From eaa8984c06076c987a962f00c95f404443f8c0e4 Mon Sep 17 00:00:00 2001 From: "John W. Bruce" Date: Fri, 24 Jul 2020 12:03:58 -0700 Subject: [PATCH] First Publicly Shared Version of ODKiTEE v15 --- README.md | 31 + oemcrypto_ta/oemcrypto.c | 2031 ++++++++ oemcrypto_ta/oemcrypto_api_macros.h | 194 + oemcrypto_ta/oemcrypto_endianness.c | 26 + oemcrypto_ta/oemcrypto_endianness.h | 17 + oemcrypto_ta/oemcrypto_key.c | 146 + oemcrypto_ta/oemcrypto_key.h | 94 + oemcrypto_ta/oemcrypto_key_table.c | 143 + oemcrypto_ta/oemcrypto_key_table.h | 79 + oemcrypto_ta/oemcrypto_key_types.h | 125 + oemcrypto_ta/oemcrypto_nonce_table.c | 81 + oemcrypto_ta/oemcrypto_nonce_table.h | 41 + oemcrypto_ta/oemcrypto_overflow.c | 56 + oemcrypto_ta/oemcrypto_overflow.h | 32 + .../oemcrypto_serialized_usage_table.c | 100 + .../oemcrypto_serialized_usage_table.h | 118 + oemcrypto_ta/oemcrypto_session.c | 946 ++++ oemcrypto_ta/oemcrypto_session.h | 250 + oemcrypto_ta/oemcrypto_session_key_table.c | 59 + oemcrypto_ta/oemcrypto_session_key_table.h | 26 + oemcrypto_ta/oemcrypto_session_table.c | 106 + oemcrypto_ta/oemcrypto_session_table.h | 59 + oemcrypto_ta/oemcrypto_usage_table.c | 976 ++++ oemcrypto_ta/oemcrypto_usage_table.h | 142 + .../tee_interfaces/assert_interface.h | 19 + oemcrypto_ta/tee_interfaces/clock_interface.h | 42 + .../tee_interfaces/crypto_interface.h | 189 + .../generation_number_interface.h | 64 + .../initialize_terminate_interface.h | 18 + .../tee_interfaces/logging_interface.h | 21 + .../oemcrypto_config_interface.h | 84 + .../tee_interfaces/root_of_trust_interface.h | 114 + serialization/OEMCryptoCENC.h | 4334 +++++++++++++++++ serialization/api_support.c | 123 + serialization/api_support.h | 45 + serialization/bump_allocator.c | 61 + serialization/bump_allocator.h | 29 + serialization/generated_src/deserializer.c | 2116 ++++++++ serialization/generated_src/deserializer.h | 383 ++ serialization/generated_src/dispatcher.c | 1499 ++++++ serialization/generated_src/oemcrypto_api.c | 2473 ++++++++++ serialization/generated_src/serializer.c | 1495 ++++++ serialization/generated_src/serializer.h | 369 ++ serialization/marshaller_base.c | 95 + serialization/marshaller_base.h | 55 + serialization/message.c | 101 + serialization/message.h | 103 + serialization/serialization_base.c | 642 +++ serialization/serialization_base.h | 118 + serialization/shared_memory_allocator.c | 260 + serialization/shared_memory_allocator.h | 31 + serialization/shared_memory_interface.h | 117 + serialization/special_case_apis.c | 131 + serialization/special_cases.c | 202 + serialization/special_cases.h | 64 + serialization/transport_interface.h | 116 + 56 files changed, 21391 insertions(+) create mode 100644 README.md create mode 100644 oemcrypto_ta/oemcrypto.c create mode 100644 oemcrypto_ta/oemcrypto_api_macros.h create mode 100644 oemcrypto_ta/oemcrypto_endianness.c create mode 100644 oemcrypto_ta/oemcrypto_endianness.h create mode 100644 oemcrypto_ta/oemcrypto_key.c create mode 100644 oemcrypto_ta/oemcrypto_key.h create mode 100644 oemcrypto_ta/oemcrypto_key_table.c create mode 100644 oemcrypto_ta/oemcrypto_key_table.h create mode 100644 oemcrypto_ta/oemcrypto_key_types.h create mode 100644 oemcrypto_ta/oemcrypto_nonce_table.c create mode 100644 oemcrypto_ta/oemcrypto_nonce_table.h create mode 100644 oemcrypto_ta/oemcrypto_overflow.c create mode 100644 oemcrypto_ta/oemcrypto_overflow.h create mode 100644 oemcrypto_ta/oemcrypto_serialized_usage_table.c create mode 100644 oemcrypto_ta/oemcrypto_serialized_usage_table.h create mode 100644 oemcrypto_ta/oemcrypto_session.c create mode 100644 oemcrypto_ta/oemcrypto_session.h create mode 100644 oemcrypto_ta/oemcrypto_session_key_table.c create mode 100644 oemcrypto_ta/oemcrypto_session_key_table.h create mode 100644 oemcrypto_ta/oemcrypto_session_table.c create mode 100644 oemcrypto_ta/oemcrypto_session_table.h create mode 100644 oemcrypto_ta/oemcrypto_usage_table.c create mode 100644 oemcrypto_ta/oemcrypto_usage_table.h create mode 100644 oemcrypto_ta/tee_interfaces/assert_interface.h create mode 100644 oemcrypto_ta/tee_interfaces/clock_interface.h create mode 100644 oemcrypto_ta/tee_interfaces/crypto_interface.h create mode 100644 oemcrypto_ta/tee_interfaces/generation_number_interface.h create mode 100644 oemcrypto_ta/tee_interfaces/initialize_terminate_interface.h create mode 100644 oemcrypto_ta/tee_interfaces/logging_interface.h create mode 100644 oemcrypto_ta/tee_interfaces/oemcrypto_config_interface.h create mode 100644 oemcrypto_ta/tee_interfaces/root_of_trust_interface.h create mode 100644 serialization/OEMCryptoCENC.h create mode 100644 serialization/api_support.c create mode 100644 serialization/api_support.h create mode 100644 serialization/bump_allocator.c create mode 100644 serialization/bump_allocator.h create mode 100644 serialization/generated_src/deserializer.c create mode 100644 serialization/generated_src/deserializer.h create mode 100644 serialization/generated_src/dispatcher.c create mode 100644 serialization/generated_src/oemcrypto_api.c create mode 100644 serialization/generated_src/serializer.c create mode 100644 serialization/generated_src/serializer.h create mode 100644 serialization/marshaller_base.c create mode 100644 serialization/marshaller_base.h create mode 100644 serialization/message.c create mode 100644 serialization/message.h create mode 100644 serialization/serialization_base.c create mode 100644 serialization/serialization_base.h create mode 100644 serialization/shared_memory_allocator.c create mode 100644 serialization/shared_memory_allocator.h create mode 100644 serialization/shared_memory_interface.h create mode 100644 serialization/special_case_apis.c create mode 100644 serialization/special_cases.c create mode 100644 serialization/special_cases.h create mode 100644 serialization/transport_interface.h diff --git a/README.md b/README.md new file mode 100644 index 0000000..54d0214 --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# OEMCrypto Development Kit For Trusted Execution Environments + +ODKiTEE is the Widevine hardened reference implementation of OEMCrypto suitable +to run in a TEE. It is written in C with a thin porting interface to make it +easier to port to various trusted environments. + +## Current Status + +This very early preview release contains an early version of the ODKiTEE source +code. It contains only the following: + +1) Code for an IPC layer that implements the OEMCrypto API functions, translates + the calls into serialized objects, deserializes the objects inside the TEE, + and invokes the appropriate TA function +2) Code for a Trusted Application that implements the logic of OEMCrypto + +No build system is included. No implementation of the porting layers for working +with different TEE OSes and chip hardware is included. + +In addition, the code herein has the following known limitations: + +1) The usage table code does not yet encrypt the usage table information. +2) The code is only sporadically and opportunistically hardened. +3) Some minor functionality is still missing, though it should all be marked + with TODO comments. + +If you have received this code, Widevine is looking for your feedback! Please +let us know where it can be improved. Don't hesitate to call out things you +think we already know, particularly as regards hardening. We want to know +whether the places we see room for improvement are the same as the ones where +you do. diff --git a/oemcrypto_ta/oemcrypto.c b/oemcrypto_ta/oemcrypto.c new file mode 100644 index 0000000..a1d4d41 --- /dev/null +++ b/oemcrypto_ta/oemcrypto.c @@ -0,0 +1,2031 @@ +/* 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 "OEMCryptoCENC.h" + +#include "string.h" + +#include "assert_interface.h" +#include "clock_interface.h" +#include "initialize_terminate_interface.h" +#include "logging_interface.h" +#include "oemcrypto_api_macros.h" +#include "oemcrypto_config_interface.h" +#include "oemcrypto_endianness.h" +#include "oemcrypto_key.h" +#include "oemcrypto_key_table.h" +#include "oemcrypto_nonce_table.h" +#include "oemcrypto_overflow.h" +#include "oemcrypto_session.h" +#include "oemcrypto_session_key_table.h" +#include "oemcrypto_session_table.h" +#include "oemcrypto_usage_table.h" +#include "root_of_trust_interface.h" + +LogPriority g_cutoff = LOG_ERROR; + +typedef enum GlobalSystemState { + SYSTEM_NOT_INITIALIZED = 0xca77206, + SYSTEM_INITIALIZED = 0x57fab49 +} GlobalSystemState; +static GlobalSystemState g_odkitee_system_state = SYSTEM_NOT_INITIALIZED; + +/* Return uint32 referenced through a potentially unaligned pointer. */ +static uint32_t unaligned_dereference_uint32(const void* unaligned_ptr) { + ASSERT(unaligned_ptr != NULL, "unaligned_ptr is NULL"); + uint32_t value; + const uint8_t* src = (const uint8_t*)(unaligned_ptr); + uint8_t* dest = (uint8_t*)(&value); + memcpy(dest, src, sizeof(value)); + return value; +} + +static bool range_check_substr(uint32_t message_length, + OEMCrypto_Substring substring, bool allow_null) { + if (!substring.length) return allow_null; + if (substring.offset > message_length) return false; + size_t end_of_substring; + if (AddOverflowUX(substring.offset, substring.length, &end_of_substring)) { + return false; + } + if (end_of_substring > message_length) return false; + return true; +} + +static bool range_check(const uint8_t* message, uint32_t message_length, + const uint8_t* field, uint32_t field_length, + bool allow_null) { + if (field == NULL) return allow_null; + if (field < message) return false; + if (field + field_length > message + message_length) return false; + return true; +} + +static OEMCryptoResult set_destination( + const OEMCrypto_DestBufferDesc* out_description, uint32_t data_length, + uint8_t subsample_flags, uint8_t** destination) { + ASSERT(out_description != NULL && data_length != 0 && destination != NULL, + "Parameters are either NULL or 0"); + *destination = NULL; + uint32_t dest_length = 0; + switch (out_description->type) { + case OEMCrypto_BufferType_Clear: + *destination = out_description->buffer.clear.address; + dest_length = out_description->buffer.clear.max_length; + break; + case OEMCrypto_BufferType_Secure: + *destination = (uint8_t*)(out_description->buffer.secure.handle) + + out_description->buffer.secure.offset; + dest_length = out_description->buffer.secure.max_length - + out_description->buffer.secure.offset; + break; + case OEMCrypto_BufferType_Direct: + /* TODO(b/145244584): Add support for direct buffers. */ + return OEMCrypto_ERROR_INVALID_CONTEXT; + default: + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + uint32_t max_allowed = MaxOutputSizeForDecrypt(); + if (max_allowed != 0 && + (max_allowed < dest_length || max_allowed < data_length)) { + return OEMCrypto_ERROR_OUTPUT_TOO_LARGE; + } + + if (out_description->type != OEMCrypto_BufferType_Direct && + dest_length < data_length) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + if (*destination == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + return OEMCrypto_SUCCESS; +} + +/* Cleanup functions for various OEMCrypto calls. */ + +static OEMCryptoResult FreeMacKeys(OEMCryptoSession* session) { + ASSERT(session != NULL, "session is NULL"); + OEMCryptoResult result = FreeKey(&session->mac_key_server); + OEMCryptoResult free_key_result = FreeKey(&session->mac_key_client); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + return result; +} + +static OEMCryptoResult FreeMacAndEncryptionKeys(OEMCryptoSession* session) { + ASSERT(session != NULL, "session is NULL"); + OEMCryptoResult result = FreeMacKeys(session); + OEMCryptoResult free_key_result = FreeKey(&session->encryption_key); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + return result; +} + +static OEMCryptoResult FreeContentAndEntitlementKeys( + OEMCryptoSession* session) { + ASSERT(session != NULL, "session is NULL"); + OEMCryptoResult result = OEMCrypto_SUCCESS; + OEMCryptoResult free_key_result = result; + for (uint32_t i = 0; i < session->num_content_keys; i++) { + free_key_result = FreeKey(&session->content_keys[i]); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + } + for (uint32_t i = 0; i < session->num_entitlement_keys; i++) { + free_key_result = FreeKey(&session->entitlement_keys[i]); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + } + session->num_content_keys = 0; + session->num_entitlement_keys = 0; + return result; +} + +OEMCryptoResult OEMCrypto_SetSandbox(const uint8_t* sandbox_id, + size_t sandbox_id_length) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +OEMCryptoResult OEMCrypto_Initialize(void) { +#ifdef OEMCRYPTO_TA_TEST_ONLY + g_cutoff = LOG_DEBUG; +#else + g_cutoff = LOG_ERROR; +#endif + if (g_odkitee_system_state != SYSTEM_NOT_INITIALIZED) { + LOGE("OEMCrypto Initialize called when not in uninitialized state"); + OEMCrypto_Terminate(); + } + int tee_result = Initialize(); + if (tee_result != 0) { + LOGE("OEMCrypto failed to |Initialize| with result: %d", tee_result); + return OEMCrypto_ERROR_INIT_FAILED; + } + OEMCryptoResult result = InitializeSessionTable(); + if (result != OEMCrypto_SUCCESS) { + OEMCrypto_Terminate(); + return result; + } + result = InitializeKeyTable(); + if (result != OEMCrypto_SUCCESS) { + OEMCrypto_Terminate(); + return result; + } + result = InitializeUsageTable(); + if (result != OEMCrypto_SUCCESS) { + OEMCrypto_Terminate(); + return result; + } + g_odkitee_system_state = SYSTEM_INITIALIZED; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult OEMCrypto_Terminate(void) { + OEMCryptoResult usage_table_terminate_result = TerminateUsageTable(); + OEMCryptoResult session_terminate_result = TerminateSessionTable(); + OEMCryptoResult key_terminate_result = TerminateKeyTable(); + int tee_result = Terminate(); + g_odkitee_system_state = SYSTEM_NOT_INITIALIZED; + if (tee_result != 0) { + LOGE("OEMCrypto failed to |Terminate| with result: %d", tee_result); + return OEMCrypto_ERROR_TERMINATE_FAILED; + } + if (session_terminate_result != OEMCrypto_SUCCESS) { + return session_terminate_result; + } + if (usage_table_terminate_result != OEMCrypto_SUCCESS) { + return usage_table_terminate_result; + } + return key_terminate_result; +} + +OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoResult result = GrabSession(session); + if (result != OEMCrypto_SUCCESS) return result; + OEMCryptoSession* session_context; + result = GetSession(*session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_OPENSESSION); + if (result != OEMCrypto_SUCCESS) { + FreeSession(*session); + return result; + } + result = SetStatePostCall(session_context, API_OPENSESSION); + if (result != OEMCrypto_SUCCESS) FreeSession(*session); + return result; +} + +OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_CLOSESESSION); + if (result != OEMCrypto_SUCCESS) return result; + return FreeSession(session); +} + +OEMCryptoResult OEMCrypto_GenerateDerivedKeys(OEMCrypto_SESSION session, + const uint8_t* mac_key_context, + uint32_t mac_key_context_length, + const uint8_t* enc_key_context, + uint32_t enc_key_context_length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (GetProvisioningMethod() != OEMCrypto_Keybox) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_GENERATEDERIVEDKEYS); + if (result != OEMCrypto_SUCCESS) return result; + + if (mac_key_context == NULL || mac_key_context_length == 0 || + enc_key_context == NULL || enc_key_context_length == 0) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + result = DeriveMacAndEncryptionKeysFromKeybox( + session_context, mac_key_context, mac_key_context_length, enc_key_context, + enc_key_context_length); + if (result != OEMCrypto_SUCCESS) goto cleanup; + + result = SetStatePostCall(session_context, API_GENERATEDERIVEDKEYS); +cleanup : { + if (result != OEMCrypto_SUCCESS) { + FreeMacAndEncryptionKeys(session_context); + session_context->state = SESSION_INVALID; + } +} + return result; +} + +OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( + OEMCrypto_SESSION session, const uint8_t* enc_session_key, + size_t enc_session_key_length, const uint8_t* mac_key_context, + size_t mac_key_context_length, const uint8_t* enc_key_context, + size_t enc_key_context_length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_DERIVEKEYSFROMSESSIONKEY); + if (result != OEMCrypto_SUCCESS) return result; + + if (enc_session_key == NULL || enc_session_key_length == 0 || + mac_key_context == NULL || mac_key_context_length == 0 || + enc_key_context == NULL || enc_key_context_length == 0) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + if (session_context->drm_private_key == NULL) { + result = OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED; + goto cleanup; + } + + if (session_context->drm_private_key->allowed_schemes != kSign_RSASSA_PSS) { + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + + /* Decrypt the session key with the DRM key and then derive keys from it. + RSA decryption needs at most RSA_size to decrypt. 3072 is the largest size + DRM RSA keys we can use. */ + uint8_t session_key[KEY_SIZE_3072]; + uint32_t session_key_length = sizeof(session_key); + session_context->drm_private_key->key_operation = DRM_RSA_PRIVATE_KEY_DECRYPT; + if (!CheckKey(session_context->drm_private_key, DRM_RSA_PRIVATE_KEY, + DRM_RSA_PRIVATE_KEY_DECRYPT)) { + result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup; + } + result = + RSADecrypt(session_context->drm_private_key->key_handle, enc_session_key, + enc_session_key_length, session_key, &session_key_length); + if (result != OEMCrypto_SUCCESS) goto cleanup; + + /* Session key can only be 16 bytes. */ + if (session_key_length != KEY_SIZE_128) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + result = + CreateKey(&session_context->session_key, session_key, session_key_length, + SESSION_KEY, SESSION_KEY_DERIVE, session_key_length); + if (result != OEMCrypto_SUCCESS) goto cleanup; + + if (!CheckKey(session_context->session_key, SESSION_KEY, + SESSION_KEY_DERIVE)) { + result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup; + } + result = DeriveMacAndEncryptionKeysFromCryptoKey( + session_context, session_context->session_key, mac_key_context, + mac_key_context_length, enc_key_context, enc_key_context_length); + if (result != OEMCrypto_SUCCESS) goto cleanup; + + result = SetStatePostCall(session_context, API_DERIVEKEYSFROMSESSIONKEY); +cleanup : { + OEMCryptoResult free_key_result = FreeKey(&session_context->drm_private_key); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + free_key_result = FreeKey(&session_context->session_key); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + if (result != OEMCrypto_SUCCESS) { + FreeMacAndEncryptionKeys(session_context); + session_context->state = SESSION_INVALID; + } +} + + return result; +} + +OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, + uint32_t* nonce) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_GENERATENONCE); + if (result != OEMCrypto_SUCCESS) return result; + + /* Get the current time. */ + uint64_t now; + OEMCrypto_Clock_Security_Level clock_type; + result = GetSystemTime(&now, &clock_type); + if (result != OEMCrypto_SUCCESS) return result; + + /* last_nonce_time should only be initialized once. */ + static int64_t last_nonce_time = 0; + static int nonce_count = 0; + const int nonce_flood_count = 20; + if (last_nonce_time == now) { + nonce_count++; + if (nonce_count > nonce_flood_count) { + LOGD("Nonce flood detected: now = %lld", now); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + } else { + nonce_count = 1; + last_nonce_time = now; + } + + /* Generate a new nonce that doesn't collide with other nonces. */ + uint32_t nonce_value = 0; + uint8_t* nonce_string = (uint8_t*)(&nonce_value); + + while (nonce_value == 0 || + NonceCollision(&session_context->nonce_table, nonce_value)) { + result = RandomBytes(nonce_string, sizeof(nonce_value)); + if (result != OEMCrypto_SUCCESS) return result; + } + AddNonce(&session_context->nonce_table, nonce_value); + *nonce = nonce_value; + + return SetStatePostCall(session_context, API_GENERATENONCE); +} + +OEMCryptoResult OEMCrypto_GenerateSignature(OEMCrypto_SESSION session, + const uint8_t* message, + size_t message_length, + uint8_t* signature, + size_t* signature_length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_GENERATESIGNATURE); + if (result != OEMCrypto_SUCCESS) return result; + + if (signature_length == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + + if (*signature_length < SHA256_DIGEST_LENGTH) { + *signature_length = SHA256_DIGEST_LENGTH; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + if (message == NULL || message_length == 0 || signature == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + *signature_length = SHA256_DIGEST_LENGTH; + + if (CheckKey(session_context->mac_key_client, MAC_KEY_CLIENT, + MAC_KEY_CLIENT_SIGN)) { + result = HMAC_SHA256(session_context->mac_key_client->key_handle, message, + message_length, signature); + } else { + /* Otherwise, use the usage entry to sign a release. */ + result = SignReleaseRequest(session_context, message, message_length, + signature, signature_length); + } + if (result != OEMCrypto_SUCCESS) return result; + return SetStatePostCall(session_context, API_GENERATESIGNATURE); +} + +OEMCryptoResult OEMCrypto_LoadSRM(const uint8_t* buffer, size_t buffer_length) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +OEMCryptoResult OEMCrypto_LoadKeys( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const uint8_t* signature, size_t signature_length, + OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys, + size_t key_array_length, const OEMCrypto_KeyObject* key_array, + OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data, + OEMCrypto_LicenseType license_type) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_LOADKEYS); + if (result != OEMCrypto_SUCCESS) return result; + + if (message == NULL || message_length == 0 || signature == NULL || + signature_length == 0 || key_array_length == 0 || key_array == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + if (signature_length != SHA256_DIGEST_LENGTH) { + return OEMCrypto_ERROR_SIGNATURE_FAILURE; + } + + if (license_type != OEMCrypto_ContentLicense && + license_type != OEMCrypto_EntitlementLicense) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + if (!range_check_substr(message_length, enc_mac_keys_iv, true) || + !range_check_substr(message_length, enc_mac_keys, true) || + !range_check_substr(message_length, pst, true) || + !range_check_substr(message_length, srm_restriction_data, true)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + for (uint32_t i = 0; i < key_array_length; i++) { + if (!range_check_substr(message_length, key_array[i].key_id, false) || + !range_check_substr(message_length, key_array[i].key_data, false) || + !range_check_substr(message_length, key_array[i].key_data_iv, false) || + !range_check_substr(message_length, key_array[i].key_control, false) || + !range_check_substr(message_length, key_array[i].key_control_iv, + false) || + key_array[i].key_id.length > KEY_ID_MAX_SIZE || + key_array[i].key_data_iv.length != KEY_IV_SIZE || + key_array[i].key_control.length < KEY_CONTROL_SIZE || + key_array[i].key_control_iv.length != KEY_IV_SIZE) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + } + + /* If set, enc_mac_keys and enc_mac_keys_iv must be the right sizes. */ + if ((enc_mac_keys_iv.length > 0 && enc_mac_keys_iv.length != KEY_IV_SIZE) || + (enc_mac_keys.length > 0 && enc_mac_keys.length != 2 * MAC_KEY_SIZE)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + /* Check to see if iv is not right before mac keys and that the bytes before + the mac keys aren't the same as the iv. */ + if (enc_mac_keys.offset >= KEY_IV_SIZE && enc_mac_keys.length > 0) { + if (enc_mac_keys_iv.offset + KEY_IV_SIZE == enc_mac_keys.offset) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } else if (enc_mac_keys.offset >= KEY_IV_SIZE) { + /* Compare bytes before enc_mac_keys only if offset is large enough. */ + if (memcmp(message + enc_mac_keys.offset - KEY_IV_SIZE, + message + enc_mac_keys_iv.offset, KEY_IV_SIZE) == 0) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + } + } + + /* If we've already loaded in a license and it isn't the current license type, + fail. */ + if (session_context->state == SESSION_KEYS_LOADED && + session_context->license_type != license_type) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + result = VerifySignatureWithMacKeyServer(session_context, message, + message_length, signature); + if (result != OEMCrypto_SUCCESS) return result; + + session_context->license_type = license_type; + session_context->refresh_valid = + range_check_substr(message_length, enc_mac_keys, false) && + range_check_substr(message_length, enc_mac_keys_iv, false); + + session_context->valid_srm_version = false; + if (srm_restriction_data.length != 0) { + const char srm_verification[] = "HDCPDATA"; + if (memcmp(message + srm_restriction_data.offset, srm_verification, + sizeof(srm_verification))) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + uint32_t minimum_version = NetworkToHostU32( + *(const uint32_t*)(message + srm_restriction_data.offset + + sizeof(srm_verification))); + uint32_t current_version = 0; + result = GetCurrentSRMVersion(¤t_version); + if (result != OEMCrypto_SUCCESS) { + LOGE("Unable to fetch SRM data with error: %d", result); + } else if (current_version < minimum_version) { + LOGE("SRM Version is too small %d, required: %d", current_version, + minimum_version); + } else { + session_context->valid_srm_version = true; + } + } + + result = StartTimer(session_context); + if (result != OEMCrypto_SUCCESS) goto cleanup; + + /* Decrypt and install keys in key object. Each key will have a key control + block. They will all have the same nonce. */ + session_context->num_content_keys = 0; + session_context->num_entitlement_keys = 0; + for (uint32_t i = 0; i < key_array_length; i++) { + result = InstallKey( + session_context, message + key_array[i].key_id.offset, + key_array[i].key_id.length, message + key_array[i].key_data.offset, + key_array[i].key_data.length, message + key_array[i].key_data_iv.offset, + message + key_array[i].key_control.offset, + message + key_array[i].key_control_iv.offset); + if (result != OEMCrypto_SUCCESS) break; + if (session_context->license_type == OEMCrypto_ContentLicense) { + session_context->num_content_keys++; + } else { + session_context->num_entitlement_keys++; + } + } + FlushNonces(&session_context->nonce_table); + if (result != OEMCrypto_SUCCESS) goto cleanup; + if (session_context->refresh_valid) { + result = UpdateMacKeys(session_context, message + enc_mac_keys.offset, + message + enc_mac_keys_iv.offset); + if (result != OEMCrypto_SUCCESS) goto cleanup; + } + + /* If we have loaded a usage entry, or we should have loaded an entry, check + * it. */ + if (session_context->usage_entry_status != SESSION_HAS_NO_ENTRY || + pst.length > 0) { + if (pst.length == 0) { + result = OEMCrypto_ERROR_INVALID_CONTEXT; + goto cleanup; + } + switch (session_context->usage_entry_status) { + case SESSION_HAS_NO_ENTRY: + default: + /* PST specified, but no usage entry loaded. */ + result = OEMCrypto_ERROR_INVALID_CONTEXT; + goto cleanup; + break; + case SESSION_HAS_NEW_ENTRY: + /* This was the first time loading the license. Copy the pst and mac + * keys. */ + result = + SetUsageEntryPST(session_context, message + pst.offset, pst.length); + if (result != OEMCrypto_SUCCESS) goto cleanup; + result = SetUsageEntryMacKeys(session_context); + if (result != OEMCrypto_SUCCESS) goto cleanup; + break; + case SESSION_HAS_DEACTIVATED_ENTRY: + /* TODO(b/154764983): fix this. */ + /* This was not the first time loading the license, and it was + * deactivated. This will be treated differently in future API versions, + * but for v15, we fall through to the next case statement and allow the + * license to be loaded. */ + case SESSION_HAS_LOADED_ENTRY: + /* This was not the first time loading the license. Verify the pst and + * mac keys. */ + result = VerfiyUsageEntryPST(session_context, message + pst.offset, + pst.length); + if (result != OEMCrypto_SUCCESS) goto cleanup; + result = VerifysageEntryMacKeys(session_context); + if (result != OEMCrypto_SUCCESS) goto cleanup; + break; + } + } + + result = SetStatePostCall(session_context, API_LOADKEYS); +cleanup : { + OEMCryptoResult free_key_result = FreeKey(&session_context->encryption_key); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + if (result != OEMCrypto_SUCCESS || !session_context->refresh_valid) { + /* See b/144122560. TODO: reword this once bug is resolved. + Mac keys must be freed in every case except when the call is successful + AND we are given new mac keys. In that case, the new keys should be + preserved in the session for future RefreshKeys calls. */ + free_key_result = FreeMacKeys(session_context); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + } + if (result != OEMCrypto_SUCCESS) { + FreeContentAndEntitlementKeys(session_context); + session_context->state = SESSION_INVALID; + } +} + + return result; +} + +OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + size_t key_array_length, + const OEMCrypto_EntitledContentKeyObject* key_array) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_LOADENTITLEDCONTENTKEYS); + if (result != OEMCrypto_SUCCESS) return result; + + if (message == NULL || message_length == 0 || key_array_length == 0 || + key_array == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + if (session_context->license_type != OEMCrypto_EntitlementLicense || + session_context->num_entitlement_keys == 0) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + for (uint32_t i = 0; i < key_array_length; i++) { + if (!range_check_substr(message_length, key_array[i].entitlement_key_id, + false) || + !range_check_substr(message_length, key_array[i].content_key_id, + false) || + !range_check_substr(message_length, key_array[i].content_key_data, + false) || + !range_check_substr(message_length, key_array[i].content_key_data_iv, + false) || + key_array[i].entitlement_key_id.length > KEY_ID_MAX_SIZE || + key_array[i].content_key_id.length > KEY_ID_MAX_SIZE || + key_array[i].content_key_data.length != KEY_SIZE_128 || + key_array[i].content_key_data_iv.length != KEY_IV_SIZE) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + } + + result = OEMCrypto_SUCCESS; + for (uint32_t i = 0; i < key_array_length; i++) { + const OEMCrypto_EntitledContentKeyObject key_object = key_array[i]; + CryptoKey* entitlement_key = FindKeyFromTable( + session_context, false, message + key_object.entitlement_key_id.offset, + key_object.entitlement_key_id.length); + if (entitlement_key == NULL) return OEMCrypto_KEY_NOT_ENTITLED; + + uint32_t content_key_index = session_context->num_content_keys; + if (entitlement_key->has_entitled_content_key) { + /* Free previous content key associated with this entitlement key. */ + content_key_index = entitlement_key->entitled_content_key_index; + result = FreeKey(&session_context->content_keys[content_key_index]); + if (result != OEMCrypto_SUCCESS) goto cleanup; + } + + /* If we're not updating an existing content key and we can't add any more, + we fail. */ + bool adding_new_content_key = + content_key_index == session_context->num_content_keys; + if (adding_new_content_key && + session_context->num_content_keys == CONTENT_KEYS_PER_SESSION) { + return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES; + } + + if (!CheckKey(entitlement_key, ENTITLEMENT_KEY, ENTITLEMENT_KEY_DECRYPT)) { + result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup; + } + uint8_t raw_content_key[KEY_SIZE_128]; + result = AESCBCDecrypt(entitlement_key->key_handle, KEY_SIZE_256, + message + key_object.content_key_data.offset, + key_object.content_key_data.length, + message + key_object.content_key_data_iv.offset, + raw_content_key); + if (result != OEMCrypto_SUCCESS) goto cleanup; + + CryptoKey** content_key_ptr = + &session_context->content_keys[content_key_index]; + result = CreateKey(content_key_ptr, raw_content_key, + key_object.content_key_data.length, CONTENT_KEY, + CONTENT_KEY_DECRYPT, key_object.content_key_data.length); + if (result != OEMCrypto_SUCCESS) goto cleanup; + CryptoKey* content_key = *content_key_ptr; + + memcpy(content_key->key_id, message + key_object.content_key_id.offset, + key_object.content_key_id.length); + content_key->key_id_size = key_object.content_key_id.length; + + /* Associate the new content key with its entitlement key. */ + content_key->is_entitled_content_key = true; + content_key->entitlement_key_index = entitlement_key->session_key_index; + + /* Associate the entitlement key with this new content key. */ + entitlement_key->has_entitled_content_key = true; + entitlement_key->entitled_content_key_index = content_key_index; + + if (adding_new_content_key) session_context->num_content_keys++; + } + + result = SetStatePostCall(session_context, API_LOADENTITLEDCONTENTKEYS); +cleanup: + if (result != OEMCrypto_SUCCESS) { + FreeContentAndEntitlementKeys(session_context); + session_context->state = SESSION_INVALID; + } + return result; +} + +OEMCryptoResult OEMCrypto_RefreshKeys( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const uint8_t* signature, size_t signature_length, size_t key_array_length, + const OEMCrypto_KeyRefreshObject* key_array) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_REFRESHKEYS); + if (result != OEMCrypto_SUCCESS) return result; + + if (message == NULL || message_length == 0 || signature == NULL || + signature_length == 0 || key_array_length == 0 || key_array == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + for (uint32_t i = 0; i < key_array_length; i++) { + if (!range_check_substr(message_length, key_array[i].key_id, true) || + !range_check_substr(message_length, key_array[i].key_control, false) || + !range_check_substr(message_length, key_array[i].key_control_iv, + true) || + key_array[i].key_id.length > KEY_ID_MAX_SIZE || + key_array[i].key_control.length < KEY_CONTROL_SIZE || + (key_array[i].key_control_iv.length != 0 && + key_array[i].key_control_iv.length != KEY_IV_SIZE)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + } + + if (!session_context->refresh_valid) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + if (signature_length != SHA256_DIGEST_LENGTH) { + return OEMCrypto_ERROR_SIGNATURE_FAILURE; + } + + result = VerifySignatureWithMacKeyServer(session_context, message, + message_length, signature); + if (result != OEMCrypto_SUCCESS) return result; + + result = OEMCrypto_SUCCESS; + for (uint32_t i = 0; i < key_array_length; i++) { + uint8_t* key_id = NULL; + uint8_t* key_control_iv = NULL; + if (key_array[i].key_id.length != 0) { + key_id = (uint8_t*)message + key_array[i].key_id.offset; + } + if (key_array[i].key_control_iv.length != 0) { + key_control_iv = (uint8_t*)message + key_array[i].key_control_iv.offset; + } + result = + RefreshKey(session_context, key_id, key_array[i].key_id.length, + message + key_array[i].key_control.offset, key_control_iv); + if (result != OEMCrypto_SUCCESS) break; + } + + FlushNonces(&session_context->nonce_table); + if (result != OEMCrypto_SUCCESS) return result; + + result = StartTimer(session_context); + if (result != OEMCrypto_SUCCESS) return result; + + return SetStatePostCall(session_context, API_REFRESHKEYS); +} + +OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + uint8_t* key_control_block, + size_t* key_control_block_length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_QUERYKEYCONTROL); + if (result != OEMCrypto_SUCCESS) return result; + + if (key_control_block_length == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + + if (*key_control_block_length < KEY_CONTROL_SIZE) { + *key_control_block_length = KEY_CONTROL_SIZE; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + if (content_key_id == NULL || content_key_id_length == 0 || + key_control_block == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + *key_control_block_length = KEY_CONTROL_SIZE; + + CryptoKey* content_key = FindKeyFromTable( + session_context, true, content_key_id, content_key_id_length); + if (content_key == NULL) return OEMCrypto_ERROR_NO_CONTENT_KEY; + + KeyControlBlock control_block; + if (content_key->is_entitled_content_key) { + uint32_t entitlement_key_index = content_key->entitlement_key_index; + if (entitlement_key_index < session_context->num_entitlement_keys && + CheckKey(session_context->entitlement_keys[entitlement_key_index], + ENTITLEMENT_KEY, ENTITLEMENT_KEY_DECRYPT)) { + control_block = session_context->entitlement_keys[entitlement_key_index] + ->key_control_block; + } else { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + } else { + control_block = content_key->key_control_block; + } + + uint32_t* block = (uint32_t*)key_control_block; + block[0] = 0; /* Verification optional. */ + block[1] = HostToNetworkU32(control_block.duration); + block[2] = 0; /* Nonce optional. */ + block[3] = HostToNetworkU32(control_block.control_bits); + + return SetStatePostCall(session_context, API_QUERYKEYCONTROL); +} + +OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + OEMCryptoCipherMode cipher_mode) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_SELECTKEY); + if (result != OEMCrypto_SUCCESS) return result; + + if (content_key_id == NULL || content_key_id_length == 0 || + content_key_id_length > KEY_ID_MAX_SIZE || + (cipher_mode != OEMCrypto_CipherMode_CTR && + cipher_mode != OEMCrypto_CipherMode_CBC) || + session_context->num_content_keys == 0) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + CryptoKey* content_key = FindKeyFromTable( + session_context, true, content_key_id, content_key_id_length); + if (!content_key) return OEMCrypto_ERROR_NO_CONTENT_KEY; + KeyControlBlock key_control_block; + if (content_key->is_entitled_content_key) { + if (session_context->license_type != OEMCrypto_EntitlementLicense || + session_context->num_entitlement_keys == 0) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + CryptoKey* entitlement_key = + session_context->entitlement_keys[content_key->entitlement_key_index]; + if (!CheckKey(entitlement_key, ENTITLEMENT_KEY, ENTITLEMENT_KEY_DECRYPT)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + /* Key control block for entitled content key is controlled by its + entitlement key. */ + key_control_block = entitlement_key->key_control_block; + } else { + if (session_context->license_type != OEMCrypto_ContentLicense) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + key_control_block = content_key->key_control_block; + } + uint32_t duration = key_control_block.duration; + if (duration > 0) { + uint64_t time_elapsed = 0; + result = CurrentTimer(session_context, &time_elapsed); + if (result != OEMCrypto_SUCCESS) return result; + time_elapsed = time_elapsed / 1000; /* Duration is in seconds. */ + if (duration < time_elapsed) return OEMCrypto_ERROR_KEY_EXPIRED; + } + if (key_control_block.control_bits & CONTROL_OBSERVE_CGMS) { + result = ApplyCGMS(key_control_block.control_bits & CONTROL_CGMS_MASK); + if (result != OEMCrypto_SUCCESS) return result; + } + session_context->current_content_key_index = content_key->session_key_index; + content_key->cipher_mode = cipher_mode; + + return SetStatePostCall(session_context, API_SELECTKEY); +} + +OEMCryptoResult OEMCrypto_DecryptCENC( + OEMCrypto_SESSION session, const uint8_t* data_addr, size_t data_length, + bool is_encrypted, const uint8_t* iv, size_t block_offset, + OEMCrypto_DestBufferDesc* out_buffer, + const OEMCrypto_CENCEncryptPatternDesc* pattern, uint8_t subsample_flags) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_DECRYPTCENC); + if (result != OEMCrypto_SUCCESS && + (session_context->state == SESSION_INVALID || is_encrypted)) { + /* If the session is not invalid and the data is not encrypted, we're + allowed to copy data. */ + return result; + } + + if (data_addr == NULL || data_length == 0 || iv == NULL || + out_buffer == NULL || pattern == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + uint32_t max_buffer_size = MaxBufferSizeForDecrypt(); + if (max_buffer_size != 0 && data_length > max_buffer_size) { + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } + + uint8_t* destination; + result = + set_destination(out_buffer, data_length, subsample_flags, &destination); + if (result != OEMCrypto_SUCCESS) return result; + + if (!is_encrypted) { + memmove(destination, data_addr, data_length); + } else { + /* Use 0 as use_type since there is no key control bit indicating whether + this key can be used as for DecryptCENC. */ + result = CheckCurrentContentKeyUsage(session_context, 0, out_buffer->type); + if (result != OEMCrypto_SUCCESS) return result; + if (session_context + ->content_keys[session_context->current_content_key_index] + ->cipher_mode == OEMCrypto_CipherMode_CBC) { + if (block_offset != 0) return OEMCrypto_ERROR_INVALID_CONTEXT; + result = DecryptCBC(session_context, iv, pattern, data_addr, data_length, + destination); + if (result != OEMCrypto_SUCCESS) return result; + } else { + result = DecryptCTR(session_context, iv, block_offset, pattern, data_addr, + data_length, destination); + if (result != OEMCrypto_SUCCESS) return result; + } + } + + if (session_context->compute_hash) { + bool can_compute_hash = false; + if (session_context->current_content_key_index < + session_context->num_content_keys) { + CryptoKey* current_content_key = + session_context + ->content_keys[session_context->current_content_key_index]; + if (CheckKey(current_content_key, CONTENT_KEY, CONTENT_KEY_DECRYPT)) { + uint32_t control_bits = 0; + if (current_content_key->is_entitled_content_key && + current_content_key->entitlement_key_index < + session_context->num_entitlement_keys) { + CryptoKey* entitlement_key = + session_context->entitlement_keys[current_content_key + ->entitlement_key_index]; + if (CheckKey(entitlement_key, ENTITLEMENT_KEY, + ENTITLEMENT_KEY_DECRYPT)) { + control_bits = entitlement_key->key_control_block.control_bits; + } + } else { + control_bits = current_content_key->key_control_block.control_bits; + } + can_compute_hash = + (control_bits & CONTROL_ALLOW_HASH_VERIFICATION) != 0; + } + } + + if (!can_compute_hash) { + session_context->hash_error = OEMCrypto_ERROR_UNKNOWN_FAILURE; + session_context->compute_hash = false; + session_context->current_hash = 0; + session_context->current_frame_number = 0; + } else { + if (OEMCrypto_FirstSubsample & subsample_flags) { + result = Crc32Init(&session_context->current_hash); + if (result != OEMCrypto_SUCCESS) return result; + } + result = + Crc32Cont(destination, data_length, session_context->current_hash, + &session_context->current_hash); + if (result != OEMCrypto_SUCCESS) return result; + if (OEMCrypto_LastSubsample & subsample_flags) { + if (session_context->current_hash != session_context->given_hash) { + /* Update bad_frame_number if this is the first bad frame. */ + if (session_context->hash_error == OEMCrypto_SUCCESS) { + session_context->bad_frame_number = + session_context->current_frame_number; + session_context->hash_error = OEMCrypto_ERROR_BAD_HASH; + } + } + session_context->compute_hash = false; + } + } + } + + return SetStatePostCall(session_context, API_DECRYPTCENC); +} + +OEMCryptoResult OEMCrypto_CopyBuffer(OEMCrypto_SESSION session, + const uint8_t* data_addr, + size_t data_length, + OEMCrypto_DestBufferDesc* out_buffer, + uint8_t subsample_flags) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + /* We don't need to check the session, CopyBuffer should be allowed for all + session states since it doesn't access any state data. */ + if (data_addr == NULL || data_length == 0 || out_buffer == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + uint32_t max_buffer_size = MaxBufferSizeForDecrypt(); + if (max_buffer_size != 0 && data_length > max_buffer_size) { + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } + uint8_t* destination; + OEMCryptoResult result = + set_destination(out_buffer, data_length, subsample_flags, &destination); + if (result != OEMCrypto_SUCCESS) return result; + memmove(destination, data_addr, data_length); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult OEMCrypto_Generic_Encrypt( + OEMCrypto_SESSION session, const uint8_t* in_buffer, size_t buffer_length, + const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_GENERICENCRYPT); + + if (in_buffer == NULL || buffer_length == 0 || iv == NULL || + out_buffer == NULL || algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + if (buffer_length % AES_BLOCK_SIZE != 0) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + uint32_t max_buffer_size = MaxBufferSizeForGenericCrypto(); + if (max_buffer_size != 0 && buffer_length > max_buffer_size) { + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } + + result = CheckCurrentContentKeyUsage(session_context, CONTROL_ALLOW_ENCRYPT, + OEMCrypto_BufferType_Clear); + if (result != OEMCrypto_SUCCESS) return result; + + CryptoKey* current_content_key = + session_context->content_keys[session_context->current_content_key_index]; + if (current_content_key->key_size != KEY_SIZE_128) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + result = AESCBCEncrypt(current_content_key->key_handle, in_buffer, + buffer_length, iv, out_buffer); + if (result != OEMCrypto_SUCCESS) return result; + + return SetStatePostCall(session_context, API_GENERICENCRYPT); +} + +OEMCryptoResult OEMCrypto_Generic_Decrypt( + OEMCrypto_SESSION session, const uint8_t* in_buffer, size_t buffer_length, + const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_GENERICDECRYPT); + + if (in_buffer == NULL || buffer_length == 0 || iv == NULL || + out_buffer == NULL || algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + if (buffer_length % AES_BLOCK_SIZE != 0) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + uint32_t max_buffer_size = MaxBufferSizeForGenericCrypto(); + if (max_buffer_size != 0 && buffer_length > max_buffer_size) { + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } + + result = CheckCurrentContentKeyUsage(session_context, CONTROL_ALLOW_DECRYPT, + OEMCrypto_BufferType_Clear); + if (result != OEMCrypto_SUCCESS) return result; + + CryptoKey* current_content_key = + session_context->content_keys[session_context->current_content_key_index]; + if (current_content_key->key_size != KEY_SIZE_128) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + result = AESCBCDecrypt(current_content_key->key_handle, + current_content_key->key_size, in_buffer, + buffer_length, iv, out_buffer); + if (result != OEMCrypto_SUCCESS) return result; + + return SetStatePostCall(session_context, API_GENERICDECRYPT); +} + +OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, + const uint8_t* in_buffer, + size_t buffer_length, + OEMCrypto_Algorithm algorithm, + uint8_t* signature, + size_t* signature_length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_GENERICSIGN); + + if (signature_length == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + + if (*signature_length < SHA256_DIGEST_LENGTH) { + *signature_length = SHA256_DIGEST_LENGTH; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + if (in_buffer == NULL || buffer_length == 0 || signature == NULL || + algorithm != OEMCrypto_HMAC_SHA256) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + *signature_length = SHA256_DIGEST_LENGTH; + + uint32_t max_buffer_size = MaxBufferSizeForGenericCrypto(); + if (max_buffer_size != 0 && buffer_length > max_buffer_size) { + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } + + result = CheckCurrentContentKeyUsage(session_context, CONTROL_ALLOW_SIGN, + OEMCrypto_BufferType_Clear); + if (result != OEMCrypto_SUCCESS) return result; + + CryptoKey* current_content_key = + session_context->content_keys[session_context->current_content_key_index]; + /* Only allow 256-bit keys for signing and verifying. */ + if (current_content_key->key_size != KEY_SIZE_256) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + result = HMAC_SHA256(current_content_key->key_handle, in_buffer, + buffer_length, signature); + if (result != OEMCrypto_SUCCESS) return result; + + return SetStatePostCall(session_context, API_GENERICSIGN); +} + +OEMCryptoResult OEMCrypto_Generic_Verify(OEMCrypto_SESSION session, + const uint8_t* in_buffer, + size_t buffer_length, + OEMCrypto_Algorithm algorithm, + const uint8_t* signature, + size_t signature_length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_GENERICVERIFY); + + if (in_buffer == NULL || buffer_length == 0 || signature == NULL || + signature_length != SHA256_DIGEST_LENGTH || + algorithm != OEMCrypto_HMAC_SHA256) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + uint32_t max_buffer_size = MaxBufferSizeForGenericCrypto(); + if (max_buffer_size != 0 && buffer_length > max_buffer_size) { + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } + + result = CheckCurrentContentKeyUsage(session_context, CONTROL_ALLOW_VERIFY, + OEMCrypto_BufferType_Clear); + if (result != OEMCrypto_SUCCESS) return result; + + CryptoKey* current_content_key = + session_context->content_keys[session_context->current_content_key_index]; + /* Only allow 256-bit keys for signing and verifying. */ + if (current_content_key->key_size != KEY_SIZE_256) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + uint8_t calculated_signature[SHA256_DIGEST_LENGTH]; + result = HMAC_SHA256(current_content_key->key_handle, in_buffer, + buffer_length, calculated_signature); + if (result != OEMCrypto_SUCCESS) return result; + if (memcmp(signature, calculated_signature, SHA256_DIGEST_LENGTH) != 0) { + return OEMCrypto_ERROR_SIGNATURE_FAILURE; + } + + return SetStatePostCall(session_context, API_GENERICVERIFY); +} + +OEMCryptoResult OEMCrypto_WrapKeyboxOrOEMCert(const uint8_t* rot, + size_t rotLength, + uint8_t* wrappedRot, + size_t* wrappedRotLength, + const uint8_t* transportKey, + size_t transportKeyLength) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +OEMCryptoResult OEMCrypto_InstallKeyboxOrOEMCert(const uint8_t* rot, + size_t rotLength) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod(void) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ProvisioningError; + } + return GetProvisioningMethod(); +} + +OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (GetProvisioningMethod() == OEMCrypto_OEMCertificate) { + return ValidateOEMPrivateKey(); + } else if (GetProvisioningMethod() == OEMCrypto_Keybox) { + return ValidateKeybox(); + } else { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } +} + +OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, size_t* idLength) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (GetProvisioningMethod() != OEMCrypto_Keybox && + GetProvisioningMethod() != OEMCrypto_OEMCertificate) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + + if (idLength == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + + if (GetProvisioningMethod() == OEMCrypto_OEMCertificate) { + uint32_t id_length; + OEMCryptoResult result = GetDeviceIDForOEMCert(deviceID, &id_length); + *idLength = id_length; + return result; + } else { + if (*idLength < KEYBOX_DEVICE_ID_SIZE) { + *idLength = KEYBOX_DEVICE_ID_SIZE; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + if (deviceID == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + return GetDeviceIDFromKeybox(deviceID); + } +} + +OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, size_t* keyDataLength) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (GetProvisioningMethod() != OEMCrypto_Keybox) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + if (keyDataLength == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + if (*keyDataLength < KEYBOX_KEY_DATA_SIZE) { + *keyDataLength = KEYBOX_KEY_DATA_SIZE; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + if (keyData == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + *keyDataLength = KEYBOX_KEY_DATA_SIZE; + + return GetKeyDataFromKeybox(keyData); +} + +OEMCryptoResult OEMCrypto_LoadTestKeybox(const uint8_t* buffer, size_t length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (GetProvisioningMethod() != OEMCrypto_Keybox) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + if (buffer == NULL || length < sizeof(WidevineKeybox)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + return LoadTestKeybox(buffer); +} + +OEMCryptoResult OEMCrypto_GetOEMPublicCertificate(OEMCrypto_SESSION session, + uint8_t* public_cert, + size_t* public_cert_length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (GetProvisioningMethod() != OEMCrypto_OEMCertificate) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_GETOEMPUBLICCERTIFICATE); + if (result != OEMCrypto_SUCCESS) return result; + if (public_cert_length == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + uint32_t oem_cert_length; + result = GetOEMPublicCertificateLength(&oem_cert_length); + if (result != OEMCrypto_SUCCESS) return result; + if (oem_cert_length > *public_cert_length) { + *public_cert_length = oem_cert_length; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + if (public_cert == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + *public_cert_length = oem_cert_length; + result = GetOEMPublicCertificate(public_cert); + if (result != OEMCrypto_SUCCESS) return result; + return SetStatePostCall(session_context, API_GETOEMPUBLICCERTIFICATE); +} + +OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, size_t dataLength) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (randomData == NULL || dataLength == 0) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + return RandomBytes(randomData, dataLength); +} + +uint32_t OEMCrypto_APIVersion(void) { return 15; } + +const char* OEMCrypto_BuildInformation(void) { + return "Widevine OEMCrypto TA v15.2.0"; +} + +uint8_t OEMCrypto_Security_Patch_Level(void) { return 0; } + +const char* OEMCrypto_SecurityLevel(void) { return "L3"; } + +OEMCryptoResult OEMCrypto_GetHDCPCapability( + OEMCrypto_HDCP_Capability* current, OEMCrypto_HDCP_Capability* maximum) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (current == NULL || maximum == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + *current = CurrentHDCPCapability(); + *maximum = MaxHDCPCapability(); + return OEMCrypto_SUCCESS; +} + +bool OEMCrypto_SupportsUsageTable(void) { return true; } + +size_t OEMCrypto_MaximumUsageTableHeaderSize() { + return MAX_NUMBER_OF_USAGE_ENTRIES; +} + +/* TODO((b/154764983): Obsolete. This function will be removed in v16. */ +OEMCryptoResult OEMCrypto_UpdateUsageTable(void) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +/* TODO((b/154764983): Obsolete. This function will be removed in v16. */ +OEMCryptoResult OEMCrypto_DeleteUsageEntry( + OEMCrypto_SESSION session, const uint8_t* pst, size_t pst_length, + const uint8_t* message, size_t message_length, const uint8_t* signature, + size_t signature_length) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +/* TODO((b/154764983): Obsolete. This function will be removed in v16. */ +OEMCryptoResult OEMCrypto_ForceDeleteUsageEntry(const uint8_t* pst, + size_t pst_length) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +bool OEMCrypto_IsAntiRollbackHwPresent(void) { + return IsAntiRollbackHWPresent(); +} + +OEMCryptoResult OEMCrypto_GetNumberOfOpenSessions(size_t* count) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (count == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + uint32_t num_open_sessions = 0; + OEMCryptoResult result = NumberOfOpenSessions(&num_open_sessions); + *count = num_open_sessions; + return result; +} + +OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(size_t* max) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (max == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + *max = MaxNumberOfSessions(); + return OEMCrypto_SUCCESS; +} + +uint32_t OEMCrypto_SupportedCertificates(void) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) return 0; + return SupportedCertificates(); +} + +bool OEMCrypto_IsSRMUpdateSupported(void) { return false; } + +OEMCryptoResult OEMCrypto_GetCurrentSRMVersion(uint16_t* version) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +uint32_t OEMCrypto_GetAnalogOutputFlags(void) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) return 0; + uint32_t analog_bits = 0; + if (HasAnalogDisplay()) analog_bits |= 0x1; + if (CanDisableAnalogDisplay()) analog_bits |= 0x2; + if (SupportsCGMS_A()) analog_bits |= 0x4; + return analog_bits; +} + +uint32_t OEMCrypto_ResourceRatingTier(void) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) return 0; + return GetResourceRatingTier(); +} + +static OEMCryptoResult RewrapDeviceRSAKey(OEMCryptoSession* session, + const uint8_t* enc_rsa_key, + uint32_t enc_rsa_key_length, + const uint8_t* enc_rsa_key_iv, + uint8_t* wrapped_rsa_key) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + ASSERT(session != NULL && enc_rsa_key != NULL && enc_rsa_key_length != 0 && + enc_rsa_key_iv != NULL && wrapped_rsa_key != NULL, + "Parameters are NULL or 0"); + if (!CheckKey(session->encryption_key, ENCRYPTION_KEY, + ENCRYPTION_KEY_DECRYPT)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + /* Decrypt and deserialize the DRM private key. */ + uint8_t pkcs8_rsa_key[PKCS8_RSA_KEY_MAX_SIZE]; + OEMCryptoResult result = AESCBCDecrypt( + session->encryption_key->key_handle, session->encryption_key->key_size, + enc_rsa_key, enc_rsa_key_length, enc_rsa_key_iv, pkcs8_rsa_key); + if (result != OEMCrypto_SUCCESS) return result; + + uint32_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1]; + if (padding > 16) return OEMCrypto_ERROR_INVALID_RSA_KEY; + uint32_t rsa_key_length = 0; + if (SubOverflowU32(enc_rsa_key_length, padding, &rsa_key_length)) { + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + + /* Check that it's a valid DRM RSA key. */ + result = LoadDRMRSAKey(session, pkcs8_rsa_key, rsa_key_length); + if (result != OEMCrypto_SUCCESS) return result; + + WrappedRSAKey* wrapped = (WrappedRSAKey*)(wrapped_rsa_key); + /* Pick a random context and IV for generating keys. */ + result = RandomBytes(wrapped->context, sizeof(wrapped->context)); + if (result != OEMCrypto_SUCCESS) return result; + result = RandomBytes(wrapped->iv, sizeof(wrapped->iv)); + if (result != OEMCrypto_SUCCESS) return result; + + /* Generate mac and encryption keys based off of the device key. */ + result = DeriveMacAndEncryptionKeysFromDeviceKey( + session, wrapped->context, sizeof(wrapped->context), wrapped->context, + sizeof(wrapped->context)); + if (result != OEMCrypto_SUCCESS) return result; + + /* Encrypt the DRM key with the derived encryption key. */ + if (!CheckKey(session->encryption_key, ENCRYPTION_KEY, + ENCRYPTION_KEY_ENCRYPT)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + result = AESCBCEncrypt(session->encryption_key->key_handle, pkcs8_rsa_key, + enc_rsa_key_length, wrapped->iv, wrapped->enc_rsa_key); + if (result != OEMCrypto_SUCCESS) return result; + + /* Use the mac_key_server to compute the signature of the rest of the + WrappedRSAKey. */ + if (!CheckKey(session->mac_key_server, MAC_KEY_SERVER, + MAC_KEY_SERVER_VERIFY)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + uint32_t wrapped_buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey); + return HMAC_SHA256(session->mac_key_server->key_handle, wrapped->context, + wrapped_buffer_size - sizeof(wrapped->signature), + wrapped->signature); +} + +OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30( + OEMCrypto_SESSION session, const uint32_t* unaligned_nonce, + const uint8_t* encrypted_message_key, size_t encrypted_message_key_length, + const uint8_t* enc_rsa_key, size_t enc_rsa_key_length, + const uint8_t* enc_rsa_key_iv, uint8_t* wrapped_rsa_key, + size_t* wrapped_rsa_key_length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (GetProvisioningMethod() != OEMCrypto_OEMCertificate) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_REWRAPDEVICERSAKEY30); + if (result != OEMCrypto_SUCCESS) return result; + + if (wrapped_rsa_key_length == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + + /* For the TA implementation, the wrapped key and the encrypted key are the + same size -- just encrypted with different keys. We add 32 bytes for a + context, 32 for iv, and 32 bytes for a signature. Important: This layout + must match OEMCrypto_LoadDeviceRSAKey below. */ + uint32_t buffer_size = 0; + if (AddOverflowUX(enc_rsa_key_length, sizeof(WrappedRSAKey), &buffer_size)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + if (*wrapped_rsa_key_length < buffer_size) { + *wrapped_rsa_key_length = buffer_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *wrapped_rsa_key_length = buffer_size; + + if (unaligned_nonce == NULL || encrypted_message_key == NULL || + encrypted_message_key_length == 0 || enc_rsa_key == NULL || + enc_rsa_key_length == 0 || enc_rsa_key_iv == NULL || + wrapped_rsa_key == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + if (enc_rsa_key_length > PKCS8_RSA_KEY_MAX_SIZE) { + /* Impossible to continue. */ + result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup; + } + + uint32_t nonce = unaligned_dereference_uint32(unaligned_nonce); + /* Validate nonce. */ + if (!CheckNonce(&session_context->nonce_table, nonce)) { + return OEMCrypto_ERROR_INVALID_NONCE; + } + FlushNonces(&session_context->nonce_table); + + /* RSA decryption needs at most RSA_size to decrypt. 3072 is the largest size + OEM RSA keys we can use. */ + uint8_t message_key[KEY_SIZE_3072]; + uint32_t message_key_length = sizeof(message_key); + result = DecryptMessageWithOEMPrivateKey(encrypted_message_key, + encrypted_message_key_length, + message_key, &message_key_length); + + if (result != OEMCrypto_SUCCESS) goto cleanup; + + if (message_key_length != KEY_SIZE_128) { + /* Encryption key is expected to be an AES 128-bit key. */ + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + result = CreateKey(&session_context->encryption_key, message_key, + message_key_length, ENCRYPTION_KEY, ENCRYPTION_KEY_DECRYPT, + KEY_SIZE_128); + if (result != OEMCrypto_SUCCESS) goto cleanup; + + result = RewrapDeviceRSAKey(session_context, enc_rsa_key, enc_rsa_key_length, + enc_rsa_key_iv, wrapped_rsa_key); + if (result != OEMCrypto_SUCCESS) goto cleanup; + + result = SetStatePostCall(session_context, API_REWRAPDEVICERSAKEY30); +cleanup : { + OEMCryptoResult free_key_result = FreeKey(&session_context->drm_private_key); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + free_key_result = FreeMacAndEncryptionKeys(session_context); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + if (result != OEMCrypto_SUCCESS) { + session_context->state = SESSION_INVALID; + } +} + + return result; +} + +OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const uint8_t* signature, size_t signature_length, + const uint32_t* unaligned_nonce, const uint8_t* enc_rsa_key, + size_t enc_rsa_key_length, const uint8_t* enc_rsa_key_iv, + uint8_t* wrapped_rsa_key, size_t* wrapped_rsa_key_length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (GetProvisioningMethod() != OEMCrypto_Keybox) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_REWRAPDEVICERSAKEY); + if (result != OEMCrypto_SUCCESS) return result; + + if (wrapped_rsa_key_length == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + + /* For the TA implementation, the wrapped key and the encrypted key are the + same size -- just encrypted with different keys. We add 32 bytes for a + context, 32 for iv, and 32 bytes for a signature. Important: This layout + must match OEMCrypto_LoadDeviceRSAKey below. */ + uint32_t buffer_size = 0; + if (AddOverflowUX(enc_rsa_key_length, sizeof(WrappedRSAKey), &buffer_size)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + if (*wrapped_rsa_key_length < buffer_size) { + *wrapped_rsa_key_length = buffer_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *wrapped_rsa_key_length = buffer_size; + + if (message == NULL || message_length == 0 || signature == NULL || + signature_length != SHA256_DIGEST_LENGTH || unaligned_nonce == NULL || + enc_rsa_key == NULL || enc_rsa_key_length == 0 || + enc_rsa_key_iv == NULL || wrapped_rsa_key_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + if (enc_rsa_key_length > PKCS8_RSA_KEY_MAX_SIZE) { + /* Impossible to continue. */ + result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup; + } + + if (!range_check(message, message_length, (uint8_t*)unaligned_nonce, + sizeof(uint32_t), false) || + !range_check(message, message_length, enc_rsa_key, enc_rsa_key_length, + false) || + !range_check(message, message_length, enc_rsa_key_iv, KEY_IV_SIZE, + false)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + uint32_t nonce = unaligned_dereference_uint32(unaligned_nonce); + /* Validate nonce. */ + if (!CheckNonce(&session_context->nonce_table, nonce)) { + return OEMCrypto_ERROR_INVALID_NONCE; + } + FlushNonces(&session_context->nonce_table); + + /* Use mac_key_server from previous call to GenerateDerivedKeys to verify the + message. */ + result = VerifySignatureWithMacKeyServer(session_context, message, + message_length, signature); + if (result != OEMCrypto_SUCCESS) goto cleanup; + + if (session_context->encryption_key != NULL) + session_context->encryption_key->key_operation = ENCRYPTION_KEY_DECRYPT; + result = RewrapDeviceRSAKey(session_context, enc_rsa_key, enc_rsa_key_length, + enc_rsa_key_iv, wrapped_rsa_key); + if (result != OEMCrypto_SUCCESS) goto cleanup; + + result = SetStatePostCall(session_context, API_REWRAPDEVICERSAKEY); +cleanup : { + OEMCryptoResult free_key_result = FreeKey(&session_context->drm_private_key); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + free_key_result = FreeMacAndEncryptionKeys(session_context); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + if (result != OEMCrypto_SUCCESS) { + session_context->state = SESSION_INVALID; + } +} + + return result; +} + +OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session, + const uint8_t* wrapped_rsa_key, + size_t wrapped_rsa_key_length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_LOADDEVICERSAKEY); + if (result != OEMCrypto_SUCCESS) return result; + + if (wrapped_rsa_key == NULL || + wrapped_rsa_key_length <= sizeof(WrappedRSAKey)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + WrappedRSAKey* wrapped = (WrappedRSAKey*)(wrapped_rsa_key); + result = DeriveMacAndEncryptionKeysFromDeviceKey( + session_context, wrapped->context, sizeof(wrapped->context), + wrapped->context, sizeof(wrapped->context)); + if (result != OEMCrypto_SUCCESS) goto cleanup; + + session_context->encryption_key->key_operation = ENCRYPTION_KEY_DECRYPT; + if (!CheckKey(session_context->encryption_key, ENCRYPTION_KEY, + ENCRYPTION_KEY_DECRYPT)) { + result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup; + } + + /* Decrypt the DRM private key. */ + uint8_t pkcs8_rsa_key[PKCS8_RSA_KEY_MAX_SIZE]; + uint32_t enc_rsa_key_length = wrapped_rsa_key_length - sizeof(WrappedRSAKey); + result = AESCBCDecrypt(session_context->encryption_key->key_handle, + session_context->encryption_key->key_size, + wrapped->enc_rsa_key, enc_rsa_key_length, wrapped->iv, + pkcs8_rsa_key); + if (result != OEMCrypto_SUCCESS) goto cleanup; + uint32_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1]; + if (padding > 16) { + result = OEMCrypto_ERROR_INVALID_RSA_KEY; + goto cleanup; + } + uint32_t rsa_key_length = 0; + if (SubOverflowU32(enc_rsa_key_length, padding, &rsa_key_length)) { + result = OEMCrypto_ERROR_INVALID_RSA_KEY; + goto cleanup; + } + + result = VerifySignatureWithMacKeyServer( + session_context, wrapped->context, + wrapped_rsa_key_length - sizeof(wrapped->signature), wrapped->signature); + if (result != OEMCrypto_SUCCESS) goto cleanup; + + /* Attempt to load in the DRM private key. */ + result = LoadDRMRSAKey(session_context, pkcs8_rsa_key, rsa_key_length); + if (result != OEMCrypto_SUCCESS) goto cleanup; + session_context->drm_private_key->key_operation = DRM_RSA_PRIVATE_KEY_SIGN; + + result = SetStatePostCall(session_context, API_LOADDEVICERSAKEY); +cleanup : { + OEMCryptoResult free_key_result = FreeMacAndEncryptionKeys(session_context); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + if (result != OEMCrypto_SUCCESS) { + FreeKey(&session_context->drm_private_key); + session_context->state = SESSION_INVALID; + } +} + return result; +} + +OEMCryptoResult OEMCrypto_LoadTestRSAKey(void) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +OEMCryptoResult OEMCrypto_GenerateRSASignature( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + uint8_t* signature, size_t* signature_length, + RSA_Padding_Scheme padding_scheme) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_GENERATERSASIGNATURE); + if (result != OEMCrypto_SUCCESS) return result; + + if (message == NULL || message_length == 0 || signature_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + if (padding_scheme == kSign_PKCS1_Block1 && message_length > 83) { + return OEMCrypto_ERROR_SIGNATURE_FAILURE; + } + + if (session_context->state == SESSION_LOAD_OEM_RSA_KEY && + padding_scheme == kSign_RSASSA_PSS) { + result = SignMessageWithOEMPrivateKey(message, message_length, signature, + (uint32_t*)signature_length); + if (result != OEMCrypto_SUCCESS) return result; + } else if (session_context->state == SESSION_LOAD_DRM_RSA_KEY) { + if (!CheckKey(session_context->drm_private_key, DRM_RSA_PRIVATE_KEY, + DRM_RSA_PRIVATE_KEY_SIGN)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } else if ((session_context->drm_private_key->allowed_schemes & + padding_scheme) != padding_scheme) { + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + return RSASign(session_context->drm_private_key->key_handle, message, + message_length, signature, (uint32_t*)signature_length, + padding_scheme); + } else { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + return SetStatePostCall(session_context, API_GENERATERSASIGNATURE); +} + +OEMCryptoResult OEMCrypto_CreateUsageTableHeader(uint8_t* header_buffer, + size_t* header_buffer_length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return CreateUsageTableHeader(header_buffer, header_buffer_length); +} + +OEMCryptoResult OEMCrypto_LoadUsageTableHeader(const uint8_t* header_buffer, + size_t header_buffer_length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return LoadUsageTableHeader(header_buffer, header_buffer_length); +} + +OEMCryptoResult OEMCrypto_CreateNewUsageEntry(OEMCrypto_SESSION session, + uint32_t* usage_entry_number) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + /* TODO(b/158763087): add pre/post checks for session state. */ + result = CreateNewUsageEntry(session_context, usage_entry_number); + return result; +} + +OEMCryptoResult OEMCrypto_LoadUsageEntry(OEMCrypto_SESSION session, + uint32_t usage_entry_number, + const uint8_t* buffer, + size_t buffer_length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + /* TODO(b/158763087): add pre/post checks for session state. */ + result = LoadUsageEntry(session_context, usage_entry_number, buffer, + buffer_length); + return result; +} + +OEMCryptoResult OEMCrypto_UpdateUsageEntry(OEMCrypto_SESSION session, + uint8_t* header_buffer, + size_t* header_buffer_length, + uint8_t* entry_buffer, + size_t* entry_buffer_length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + /* TODO(b/158763087): add pre/post checks for session state. */ + result = + UpdateUsageEntry(session_context, header_buffer, header_buffer_length, + entry_buffer, entry_buffer_length); + return result; +} + +OEMCryptoResult OEMCrypto_DeactivateUsageEntry(OEMCrypto_SESSION session, + const uint8_t* pst, + size_t pst_length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + /* TODO(b/158763087): add pre/post checks for session state. */ + result = DeactivateUsageEntry(session_context, pst, pst_length); + return result; +} + +OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session, + const uint8_t* pst, size_t pst_length, + uint8_t* buffer, size_t* buffer_length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + /* TODO(b/158763087): add pre/post checks for session state. */ + result = ReportUsage(session_context, pst, pst_length, buffer, buffer_length); + return result; +} + +OEMCryptoResult OEMCrypto_MoveEntry(OEMCrypto_SESSION session, + uint32_t new_index) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + /* TODO(b/158763087): add pre/post checks for session state. */ + return MoveEntry(session_context, new_index); +} + +OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader(uint32_t new_entry_count, + uint8_t* header_buffer, + size_t* header_buffer_length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return ShrinkUsageTableHeader(new_entry_count, header_buffer, + header_buffer_length); +} + +OEMCryptoResult OEMCrypto_CopyOldUsageEntry(OEMCrypto_SESSION session, + const uint8_t* pst, + size_t pst_length) { + /* Only needed for upgrades from v12. */ + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +OEMCryptoResult OEMCrypto_DeleteOldUsageTable(void) { + /* Only needed for upgrades from v12. */ + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +OEMCryptoResult OEMCrypto_RemoveSRM(void) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +OEMCryptoResult OEMCrypto_CreateOldUsageEntry( + uint64_t time_since_license_received, uint64_t time_since_first_decrypt, + uint64_t time_since_last_decrypt, OEMCrypto_Usage_Entry_Status status, + uint8_t* server_mac_key, uint8_t* client_mac_key, const uint8_t* pst, + size_t pst_length) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +uint32_t OEMCrypto_SupportsDecryptHash(void) { + return OEMCrypto_CRC_Clear_Buffer; +} + +OEMCryptoResult OEMCrypto_SetDecryptHash(OEMCrypto_SESSION session, + uint32_t frame_number, + const uint8_t* hash, + size_t hash_length) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_SETDECRYPTHASH); + if (result != OEMCrypto_SUCCESS) return result; + + if (hash == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + if (hash_length < sizeof(uint32_t)) return OEMCrypto_ERROR_SHORT_BUFFER; + + session_context->compute_hash = true; + session_context->current_frame_number = frame_number; + /* This is safe since it's host-to-host. */ + session_context->given_hash = *(const uint32_t*)hash; + + return SetStatePostCall(session_context, API_SETDECRYPTHASH); +} + +OEMCryptoResult OEMCrypto_GetHashErrorCode(OEMCrypto_SESSION session, + uint32_t* failed_frame_number) { + if (g_odkitee_system_state != SYSTEM_INITIALIZED) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoSession* session_context; + OEMCryptoResult result = GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) return result; + result = CheckStatePreCall(session_context, API_GETHASHERRORCODE); + if (result != OEMCrypto_SUCCESS) return result; + + if (failed_frame_number == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + if (session_context->hash_error != OEMCrypto_SUCCESS) { + *failed_frame_number = session_context->bad_frame_number; + } + + result = SetStatePostCall(session_context, API_GETHASHERRORCODE); + if (result != OEMCrypto_SUCCESS) return result; + return session_context->hash_error; +} diff --git a/oemcrypto_ta/oemcrypto_api_macros.h b/oemcrypto_ta/oemcrypto_api_macros.h new file mode 100644 index 0000000..a4a6a81 --- /dev/null +++ b/oemcrypto_ta/oemcrypto_api_macros.h @@ -0,0 +1,194 @@ +/* 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. */ + +#ifndef OEMCRYPTO_TA_OEMCRYPTO_API_MACROS_H_ +#define OEMCRYPTO_TA_OEMCRYPTO_API_MACROS_H_ + +#ifdef OEMCRYPTO_TA_TEST_ONLY +/* Only used for testing. This is so the TA can directly build with the + unittests. */ +/* clang-format off */ +#define OEMCrypto_Initialize _oecc01 +#define OEMCrypto_Terminate _oecc02 +#define OEMCrypto_InstallKeybox _oecc03 +#define OEMCrypto_InstallRootKeyCertificate _oecc03 +#define OEMCrypto_InstallKeyboxOrOEMCert _oecc03 +#define OEMCrypto_GetKeyData _oecc04 +#define OEMCrypto_IsKeyboxValid _oecc05 +#define OEMCrypto_IsRootKeyCertificateValid _oecc05 +#define OEMCrypto_IsKeyboxOrOEMCertValid _oecc05 +#define OEMCrypto_GetRandom _oecc06 +#define OEMCrypto_GetDeviceID _oecc07 +#define OEMCrypto_WrapKeybox _oecc08 +#define OEMCrypto_WrapRootKeyCertificate _oecc08 +#define OEMCrypto_WrapKeyboxOrOEMCert _oecc08 +#define OEMCrypto_OpenSession _oecc09 +#define OEMCrypto_CloseSession _oecc10 +#define OEMCrypto_DecryptCTR_V10 _oecc11 +#define OEMCrypto_GenerateDerivedKeys _oecc12 +#define OEMCrypto_GenerateSignature _oecc13 +#define OEMCrypto_GenerateNonce _oecc14 +#define OEMCrypto_LoadKeys_V8 _oecc15 +#define OEMCrypto_RefreshKeys_V14 _oecc16 +#define OEMCrypto_SelectKey_V13 _oecc17 +#define OEMCrypto_RewrapDeviceRSAKey _oecc18 +#define OEMCrypto_LoadDeviceRSAKey _oecc19 +#define OEMCrypto_GenerateRSASignature_V8 _oecc20 +#define OEMCrypto_DeriveKeysFromSessionKey _oecc21 +#define OEMCrypto_APIVersion _oecc22 +#define OEMCrypto_SecurityLevel _oecc23 +#define OEMCrypto_Generic_Encrypt _oecc24 +#define OEMCrypto_Generic_Decrypt _oecc25 +#define OEMCrypto_Generic_Sign _oecc26 +#define OEMCrypto_Generic_Verify _oecc27 +#define OEMCrypto_GetHDCPCapability_V9 _oecc28 +#define OEMCrypto_SupportsUsageTable _oecc29 +#define OEMCrypto_UpdateUsageTable _oecc30 +#define OEMCrypto_DeactivateUsageEntry_V12 _oecc31 +#define OEMCrypto_ReportUsage _oecc32 +#define OEMCrypto_DeleteUsageEntry _oecc33 +#define OEMCrypto_DeleteOldUsageTable _oecc34 +#define OEMCrypto_LoadKeys_V9_or_V10 _oecc35 +#define OEMCrypto_GenerateRSASignature _oecc36 +#define OEMCrypto_GetMaxNumberOfSessions _oecc37 +#define OEMCrypto_GetNumberOfOpenSessions _oecc38 +#define OEMCrypto_IsAntiRollbackHwPresent _oecc39 +#define OEMCrypto_CopyBuffer_V14 _oecc40 +#define OEMCrypto_QueryKeyControl _oecc41 +#define OEMCrypto_LoadTestKeybox_V13 _oecc42 +#define OEMCrypto_ForceDeleteUsageEntry _oecc43 +#define OEMCrypto_GetHDCPCapability _oecc44 +#define OEMCrypto_LoadTestRSAKey _oecc45 +#define OEMCrypto_Security_Patch_Level _oecc46 +#define OEMCrypto_LoadKeys_V11_or_V12 _oecc47 +#define OEMCrypto_DecryptCENC _oecc48 +#define OEMCrypto_GetProvisioningMethod _oecc49 +#define OEMCrypto_GetOEMPublicCertificate _oecc50 +#define OEMCrypto_RewrapDeviceRSAKey30 _oecc51 +#define OEMCrypto_SupportedCertificates _oecc52 +#define OEMCrypto_IsSRMUpdateSupported _oecc53 +#define OEMCrypto_GetCurrentSRMVersion _oecc54 +#define OEMCrypto_LoadSRM _oecc55 +#define OEMCrypto_LoadKeys_V13 _oecc56 +#define OEMCrypto_RemoveSRM _oecc57 +#define OEMCrypto_CreateUsageTableHeader _oecc61 +#define OEMCrypto_LoadUsageTableHeader _oecc62 +#define OEMCrypto_CreateNewUsageEntry _oecc63 +#define OEMCrypto_LoadUsageEntry _oecc64 +#define OEMCrypto_UpdateUsageEntry _oecc65 +#define OEMCrypto_DeactivateUsageEntry _oecc66 +#define OEMCrypto_ShrinkUsageTableHeader _oecc67 +#define OEMCrypto_MoveEntry _oecc68 +#define OEMCrypto_CopyOldUsageEntry _oecc69 +#define OEMCrypto_CreateOldUsageEntry _oecc70 +#define OEMCrypto_GetAnalogOutputFlags _oecc71 +#define OEMCrypto_LoadTestKeybox _oecc78 +#define OEMCrypto_LoadEntitledContentKeys_V14 _oecc79 +#define OEMCrypto_SelectKey _oecc81 +#define OEMCrypto_LoadKeys_V14 _oecc82 +#define OEMCrypto_LoadKeys _oecc83 +#define OEMCrypto_SetSandbox _oecc84 +#define OEMCrypto_ResourceRatingTier _oecc85 +#define OEMCrypto_SupportsDecryptHash _oecc86 +#define OEMCrypto_InitializeDecryptHash _oecc87 +#define OEMCrypto_SetDecryptHash _oecc88 +#define OEMCrypto_GetHashErrorCode _oecc89 +#define OEMCrypto_BuildInformation _oecc90 +#define OEMCrypto_RefreshKeys _oecc91 +#define OEMCrypto_LoadEntitledContentKeys _oecc92 +#define OEMCrypto_CopyBuffer _oecc93 +#else +#define OEMCrypto_Initialize _oecctee01 +#define OEMCrypto_Terminate _oecctee02 +#define OEMCrypto_InstallKeybox _oecctee03 +#define OEMCrypto_InstallRootKeyCertificate _oecctee03 +#define OEMCrypto_InstallKeyboxOrOEMCert _oecctee03 +#define OEMCrypto_GetKeyData _oecctee04 +#define OEMCrypto_IsKeyboxValid _oecctee05 +#define OEMCrypto_IsRootKeyCertificateValid _oecctee05 +#define OEMCrypto_IsKeyboxOrOEMCertValid _oecctee05 +#define OEMCrypto_GetRandom _oecctee06 +#define OEMCrypto_GetDeviceID _oecctee07 +#define OEMCrypto_WrapKeybox _oecctee08 +#define OEMCrypto_WrapRootKeyCertificate _oecctee08 +#define OEMCrypto_WrapKeyboxOrOEMCert _oecctee08 +#define OEMCrypto_OpenSession _oecctee09 +#define OEMCrypto_CloseSession _oecctee10 +#define OEMCrypto_DecryptCTR_V10 _oecctee11 +#define OEMCrypto_GenerateDerivedKeys _oecctee12 +#define OEMCrypto_GenerateSignature _oecctee13 +#define OEMCrypto_GenerateNonce _oecctee14 +#define OEMCrypto_LoadKeys_V8 _oecctee15 +#define OEMCrypto_RefreshKeys_V14 _oecctee16 +#define OEMCrypto_SelectKey_V13 _oecctee17 +#define OEMCrypto_RewrapDeviceRSAKey _oecctee18 +#define OEMCrypto_LoadDeviceRSAKey _oecctee19 +#define OEMCrypto_GenerateRSASignature_V8 _oecctee20 +#define OEMCrypto_DeriveKeysFromSessionKey _oecctee21 +#define OEMCrypto_APIVersion _oecctee22 +#define OEMCrypto_SecurityLevel _oecctee23 +#define OEMCrypto_Generic_Encrypt _oecctee24 +#define OEMCrypto_Generic_Decrypt _oecctee25 +#define OEMCrypto_Generic_Sign _oecctee26 +#define OEMCrypto_Generic_Verify _oecctee27 +#define OEMCrypto_GetHDCPCapability_V9 _oecctee28 +#define OEMCrypto_SupportsUsageTable _oecctee29 +#define OEMCrypto_UpdateUsageTable _oecctee30 +#define OEMCrypto_DeactivateUsageEntry_V12 _oecctee31 +#define OEMCrypto_ReportUsage _oecctee32 +#define OEMCrypto_DeleteUsageEntry _oecctee33 +#define OEMCrypto_DeleteOldUsageTable _oecctee34 +#define OEMCrypto_LoadKeys_V9_or_V10 _oecctee35 +#define OEMCrypto_GenerateRSASignature _oecctee36 +#define OEMCrypto_GetMaxNumberOfSessions _oecctee37 +#define OEMCrypto_GetNumberOfOpenSessions _oecctee38 +#define OEMCrypto_IsAntiRollbackHwPresent _oecctee39 +#define OEMCrypto_CopyBuffer_V14 _oecctee40 +#define OEMCrypto_QueryKeyControl _oecctee41 +#define OEMCrypto_LoadTestKeybox_V13 _oecctee42 +#define OEMCrypto_ForceDeleteUsageEntry _oecctee43 +#define OEMCrypto_GetHDCPCapability _oecctee44 +#define OEMCrypto_LoadTestRSAKey _oecctee45 +#define OEMCrypto_Security_Patch_Level _oecctee46 +#define OEMCrypto_LoadKeys_V11_or_V12 _oecctee47 +#define OEMCrypto_DecryptCENC _oecctee48 +#define OEMCrypto_GetProvisioningMethod _oecctee49 +#define OEMCrypto_GetOEMPublicCertificate _oecctee50 +#define OEMCrypto_RewrapDeviceRSAKey30 _oecctee51 +#define OEMCrypto_SupportedCertificates _oecctee52 +#define OEMCrypto_IsSRMUpdateSupported _oecctee53 +#define OEMCrypto_GetCurrentSRMVersion _oecctee54 +#define OEMCrypto_LoadSRM _oecctee55 +#define OEMCrypto_LoadKeys_V13 _oecctee56 +#define OEMCrypto_RemoveSRM _oecctee57 +#define OEMCrypto_CreateUsageTableHeader _oecctee61 +#define OEMCrypto_LoadUsageTableHeader _oecctee62 +#define OEMCrypto_CreateNewUsageEntry _oecctee63 +#define OEMCrypto_LoadUsageEntry _oecctee64 +#define OEMCrypto_UpdateUsageEntry _oecctee65 +#define OEMCrypto_DeactivateUsageEntry _oecctee66 +#define OEMCrypto_ShrinkUsageTableHeader _oecctee67 +#define OEMCrypto_MoveEntry _oecctee68 +#define OEMCrypto_CopyOldUsageEntry _oecctee69 +#define OEMCrypto_CreateOldUsageEntry _oecctee70 +#define OEMCrypto_GetAnalogOutputFlags _oecctee71 +#define OEMCrypto_LoadTestKeybox _oecctee78 +#define OEMCrypto_LoadEntitledContentKeys_V14 _oecctee79 +#define OEMCrypto_SelectKey _oecctee81 +#define OEMCrypto_LoadKeys_V14 _oecctee82 +#define OEMCrypto_LoadKeys _oecctee83 +#define OEMCrypto_SetSandbox _oecctee84 +#define OEMCrypto_ResourceRatingTier _oecctee85 +#define OEMCrypto_SupportsDecryptHash _oecctee86 +#define OEMCrypto_InitializeDecryptHash _oecctee87 +#define OEMCrypto_SetDecryptHash _oecctee88 +#define OEMCrypto_GetHashErrorCode _oecctee89 +#define OEMCrypto_BuildInformation _oecctee90 +#define OEMCrypto_RefreshKeys _oecctee91 +#define OEMCrypto_LoadEntitledContentKeys _oecctee92 +#define OEMCrypto_CopyBuffer _oecctee93 +/* clang-format on */ +#endif + +#endif /* OEMCRYPTO_TA_OEMCRYPTO_API_MACROS_H_ */ diff --git a/oemcrypto_ta/oemcrypto_endianness.c b/oemcrypto_ta/oemcrypto_endianness.c new file mode 100644 index 0000000..9c71da5 --- /dev/null +++ b/oemcrypto_ta/oemcrypto_endianness.c @@ -0,0 +1,26 @@ +// Copyright 2020 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_endianness.h" + +#include +#include + +uint32_t HostToNetworkU32(uint32_t host) { + uint8_t bytes[] = { + (uint8_t)(host >> 24u), + (uint8_t)(host >> 16u), + (uint8_t)(host >> 8u), + (uint8_t)(host >> 0u), + }; + + uint32_t network; + memcpy(&network, bytes, sizeof(network)); + return network; +} + +uint32_t NetworkToHostU32(uint32_t network) { + // These functions are symmetrical on any byte-ordering used in practice. + return HostToNetworkU32(network); +} diff --git a/oemcrypto_ta/oemcrypto_endianness.h b/oemcrypto_ta/oemcrypto_endianness.h new file mode 100644 index 0000000..f8dea22 --- /dev/null +++ b/oemcrypto_ta/oemcrypto_endianness.h @@ -0,0 +1,17 @@ +// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine Master +// License Agreement. + +#ifndef OEMCRYPTO_ENDIANNESS_H_ +#define OEMCRYPTO_ENDIANNESS_H_ + +#include + +// The functions in this header convert between network and host byte order for +// various basic integer types. + +uint32_t HostToNetworkU32(uint32_t host); + +uint32_t NetworkToHostU32(uint32_t network); + +#endif // OEMCRYPTO_ENDIANNESS_H_ diff --git a/oemcrypto_ta/oemcrypto_key.c b/oemcrypto_ta/oemcrypto_key.c new file mode 100644 index 0000000..4f0b399 --- /dev/null +++ b/oemcrypto_ta/oemcrypto_key.c @@ -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; +} diff --git a/oemcrypto_ta/oemcrypto_key.h b/oemcrypto_ta/oemcrypto_key.h new file mode 100644 index 0000000..cd9aa16 --- /dev/null +++ b/oemcrypto_ta/oemcrypto_key.h @@ -0,0 +1,94 @@ +/* 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. */ + +#ifndef OEMCRYPTO_TA_OEMCRYPTO_KEY_H_ +#define OEMCRYPTO_TA_OEMCRYPTO_KEY_H_ + +#include "crypto_interface.h" +#include "oemcrypto_key_types.h" + +typedef struct KeyControlBlock { + bool valid; + char verification[4]; + uint32_t duration; + uint32_t nonce; + uint32_t control_bits; +} KeyControlBlock; + +typedef struct CryptoKey { + /* Index into the global key table. */ + uint32_t key_table_index; + uint64_t cookie; + CryptoKeyType key_type; + CryptoKeyOperation key_operation; + /* key_handle is owned by the TEE. */ + TEE_Key_Handle key_handle; + CryptoKeySize key_size; + uint32_t allowed_schemes; /* For DRM RSA keys only */ + /* For entitlement or content keys only. */ + uint8_t key_id[KEY_ID_MAX_SIZE]; + uint8_t key_id_size; + KeyControlBlock key_control_block; + /* Index into either the content or entitlement key table in the session. */ + uint32_t session_key_index; + /* For entitlement keys only. */ + uint32_t entitled_content_key_index; /* Index of entitled content key that + this entitles. */ + bool has_entitled_content_key; + /* For content keys only. */ + uint32_t entitlement_key_index; /* Index of entitlement key that entitles this + key. */ + bool is_entitled_content_key; + OEMCryptoCipherMode cipher_mode; +} CryptoKey; + +/* Initializes the data fields in the |key| and sets |key|'s key_handle to + the key handle formed from |serialized_bytes| and |size|. + Returns the result of CreateKeyHandle if it fails and OEMCrypto_SUCCESS + otherwise. + |serialized_bytes_length| must be > 0 and |key_type| must be valid. + Caller retains ownership of all pointers and they must not be NULL. */ +OEMCryptoResult InitializeCryptoKey(CryptoKey* key, + const uint8_t* serialized_bytes, + uint32_t serialized_bytes_length, + CryptoKeyType key_type, + CryptoKeyOperation key_operation, + CryptoKeySize key_size); + +/* Initializes the data fields in the |key| and sets |key|'s key_handle to + the key handle formed from |wrapped_key| and |size|. + The data in |wrapped_key| was previously computed in WrapCryptoKey. + Returns the result of CreateKeyHandle if it fails and OEMCrypto_SUCCESS + otherwise. + |serialized_bytes_length| must be > 0 and |key_type| must be valid. + Caller retains ownership of all pointers and they must not be NULL. */ +OEMCryptoResult InitializeCryptoKeyFromWrappedKey( + CryptoKey* key, const uint8_t* wrapped_key, uint32_t wrapped_key_length, + CryptoKeyType key_type, CryptoKeyOperation key_operation, + CryptoKeySize key_size); + +/* Wraps the key data into a buffer that can be saved to the file system. The + wrapping must be device unique. Caller retains ownership of |key| and + |buffer| and they must not be NULL. Caller ensures that buffer_length is at + least as big as the wrapped key size specified in + oemcrypto_config_macros.h. */ +OEMCryptoResult WrapCryptoKey(CryptoKey* key, uint8_t* buffer, + size_t buffer_length); + +/* Frees the key handle associated with this key if it exists and then clears + the key. Returns the result of freeing the key handle. + Caller retains ownership of |key| and it must not be NULL. */ +OEMCryptoResult FreeCryptoKey(CryptoKey* key); + +/* Checks to make sure that |key| isn't NULL, its cookie is valid, its key_type + matches |key_type|, and its key operation matches |key_operation|. */ +bool CheckKey(CryptoKey* key, CryptoKeyType key_type, + CryptoKeyOperation key_operation); + +/* Parses the given |kcb| into a KeyControlBlock. If the verification fails, the + key control block is marked invalid. Returns the parsed KeyControlBlock. + Caller retains ownership of all pointers and they must not be NULL. */ +KeyControlBlock ParseKeyControlBlock(const uint8_t* kcb); + +#endif /* OEMCRYPTO_TA_OEMCRYPTO_KEY_H_ */ diff --git a/oemcrypto_ta/oemcrypto_key_table.c b/oemcrypto_ta/oemcrypto_key_table.c new file mode 100644 index 0000000..0e75c59 --- /dev/null +++ b/oemcrypto_ta/oemcrypto_key_table.c @@ -0,0 +1,143 @@ +/* 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; +} diff --git a/oemcrypto_ta/oemcrypto_key_table.h b/oemcrypto_ta/oemcrypto_key_table.h new file mode 100644 index 0000000..70fa9e1 --- /dev/null +++ b/oemcrypto_ta/oemcrypto_key_table.h @@ -0,0 +1,79 @@ +/* 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. */ + +#ifndef OEMCRYPTO_TA_OEMCRYPTO_KEY_TABLE_H_ +#define OEMCRYPTO_TA_OEMCRYPTO_KEY_TABLE_H_ + +#include "oemcrypto_config_interface.h" +#include "oemcrypto_key.h" + +typedef struct KeyTable { + CryptoKey keys[MAX_NUMBER_OF_KEYS]; + uint32_t size; + uint32_t first_free_key; + uint32_t next_free_key[MAX_NUMBER_OF_KEYS]; + bool is_free[MAX_NUMBER_OF_KEYS]; +} KeyTable; + +/* Initializes the key table so the session can grab keys at a late point. + Returns OEMCrypto_ERROR_INIT_FAILED if the key table has already been + initialized and OEMCrypto_SUCCESS otherwise. */ +OEMCryptoResult InitializeKeyTable(void); + +/* Gets the max number of keys. */ +uint32_t MaxNumberOfKeys(void); + +/* Gets the number of currently used keys. Returns + OEMCrypto_ERROR_SYSTEM_INVALIDATED if the key table has not been initialized + and OEMCrypto_SUCCESS otherwise. + Caller retains ownership of |num_used_keys| and it must not be NULL. */ +OEMCryptoResult NumberOfUsedKeys(uint32_t* num_used_keys); + +/* Attempts to grab an unused entry in the key table and set *|index| to the + entry position. Returns OEMCrypto_ERROR_SYSTEM_INVALIDATED if the key table + has not been initialized and OEMCrypto_ERROR_TOO_MANY_KEYS if there are no + keys left to grab. Returns OEMCrypto_SUCCESS otherwise. + Caller retains ownership of |index| and it must not be NULL. */ +OEMCryptoResult GrabKey(uint32_t* index); + +/* Sets key to the key at |index| in the key table if it is free. Returns + OEMCrypto_ERROR_SYSTEM_INVALIDATED if the key table has not been initialized + and OEMCrypto_ERROR_INVALID_CONTEXT if the key has not been grabbed or if the + index is invalid. Returns OEMCrypto_SUCCESS otherwise. + If successful, caller gains ownership of *|key| and |key| must not be NULL. + */ +OEMCryptoResult GetKey(uint32_t index, CryptoKey** key); + +/* Grabs, gets, and initializes a CryptoKey using |serialized_bytes| and + GrabKey, GetKey, and InitializeCryptoKey and sets the result in *|key|. + If |key| points to an existing key, this method tries to free it before + continuing. If there is an error in generating the new key, this method will + free it before returning and set *|key| to NULL. + If successful, caller gains ownership of *|key| and it must not be NULL. */ +OEMCryptoResult CreateKey(CryptoKey** key, const uint8_t* serialized_bytes, + uint32_t serialized_bytes_length, + CryptoKeyType key_type, + CryptoKeyOperation key_operation, + CryptoKeySize key_size); + +/* Given a pointer to a CryptoKey*, attempts to free the CryptoKey it points to + if it exists, and then sets the pointer to the CryptoKey to NULL. + Returns OEMCrypto_ERROR_SYSTEM_INVALIDATED if the key table has not been + initialized, OEMCrypto_ERROR_INVALID_CONTEXT if the non-null CryptoKey has + not been grabbed or if its index is invalid. Returns the result of freeing + the CryptoKey otherwise. + If there is an existing error in the caller, in which case this is likely + used for cleanup, that error will be returned and the result of this shall be + ignored. + Caller retains ownership of *|key| but **|key| will be destroyed if *|key| + is not NULL. */ +OEMCryptoResult FreeKey(CryptoKey** key); + +/* Clears and cleans up the key table. The key table must be reinitialized to be + used. Returns OEMCrypto_ERROR_TERMINATE_FAILED if the table has not been + initialized or if there are any active keys still. Returns OEMCrypto_SUCCESS + otherwise. */ +OEMCryptoResult TerminateKeyTable(void); + +#endif /* OEMCRYPTO_TA_OEMCRYPTO_KEY_TABLE_H_ */ diff --git a/oemcrypto_ta/oemcrypto_key_types.h b/oemcrypto_ta/oemcrypto_key_types.h new file mode 100644 index 0000000..09703ba --- /dev/null +++ b/oemcrypto_ta/oemcrypto_key_types.h @@ -0,0 +1,125 @@ +/* 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. */ + +#ifndef OEMCRYPTO_TA_OEMCRYPTO_KEY_TYPES_H_ +#define OEMCRYPTO_TA_OEMCRYPTO_KEY_TYPES_H_ + +#include "stdint.h" + +/* The type of the cryptographic key. Both used for validation and + identification of a key blob. Note that root of trusts are not included in + the scope of this interface. They shouldn't be represented by a CryptoKey. */ +typedef enum CryptoKeyType { + UNKNOWN_KEY_TYPE = (int)0xf849b0c5, + CONTENT_KEY = (int)0x336592b0, + ENTITLEMENT_KEY = (int)0x375af9af, + DRM_RSA_PRIVATE_KEY = (int)0x2e912492, + MAC_KEY_SERVER = (int)0xa09c9790, + MAC_KEY_CLIENT = (int)0x05f09a35, + ENCRYPTION_KEY = (int)0x8976b781, + SESSION_KEY = (int)0xbc792301, +} CryptoKeyType; + +/* Dictates the current valid operation state of the key. This is to ensure that + keys are not used outside of the scope of their current operation. */ +typedef enum CryptoKeyOperation { + UNKNOWN_KEY_OPERATION = (int)0x502bc2ac, + CONTENT_KEY_DECRYPT = (int)0x8638add1, + ENTITLEMENT_KEY_DECRYPT = (int)0x2d247825, + DRM_RSA_PRIVATE_KEY_SIGN = (int)0xb058fafc, + DRM_RSA_PRIVATE_KEY_DECRYPT = (int)0xe6cf4d35, + MAC_KEY_SERVER_SIGN = (int)0x2f7e2983, + MAC_KEY_SERVER_VERIFY = (int)0x0281fd41, + MAC_KEY_CLIENT_SIGN = (int)0x28c9fef2, + ENCRYPTION_KEY_ENCRYPT = (int)0x162ae24f, + ENCRYPTION_KEY_DECRYPT = (int)0x338b8c63, + SESSION_KEY_DERIVE = (int)0xcc279cc5, +} CryptoKeyOperation; + +/* The valid possible sizes of the crypto key. */ +typedef enum CryptoKeySize { + UNKNOWN_KEY_SIZE = 0, + KEY_SIZE_128 = 16, + KEY_SIZE_160 = 20, + KEY_SIZE_256 = 32, + KEY_SIZE_384 = 48, + KEY_SIZE_512 = 64, + KEY_SIZE_1024 = 128, + KEY_SIZE_2048 = 256, + KEY_SIZE_3072 = 384, + KEY_SIZE_4096 = 512, +} CryptoKeySize; + + +/* This is the format of a Widevine keybox. */ +typedef struct WidevineKeybox { /* 128 bytes total. */ + /* C character array identifying the device. Padded with NULL to fit array. */ + uint8_t device_id[32]; + /* 128 bit AES key assigned to device. Generated by Widevine. */ + uint8_t device_key[16]; + /* Key Data. Encrypted data. */ + uint8_t data[72]; + /* Constant code used to recognize a valid keybox "kbox" = 0x6b626f78. */ + uint8_t magic[4]; + /* The CRC checksum of the first 124 bytes of the keybox. */ + uint8_t crc[4]; +} WidevineKeybox; + +/* Key Control Block Bit Masks: */ +#define CONTROL_OBSERVE_DATA_PATH (1 << 31) +#define CONTROL_OBSERVE_HDCP (1 << 30) +#define CONTROL_OBSERVE_CGMS (1 << 29) +#define CONTROL_REQUIRE_ANTI_ROLLBACK_HARDWARE (1 << 28) +#define CONTROL_ALLOW_HASH_VERIFICATION (1 << 24) +#define SHARED_LICENSE (1 << 23) +#define CONTROL_SRM_VERSION_REQUIRED (1 << 22) +#define CONTROL_DISABLE_ANALOG_OUTPUT (1 << 21) +#define CONTROL_SECURITY_PATCH_LEVEL_SHIFT 15 +#define CONTROL_SECURITY_PATCH_LEVEL_MASK \ + (0x3F << CONTROL_SECURITY_PATCH_LEVEL_SHIFT) +#define CONTROL_REPLAY_MASK (0x03 << 13) +#define CONTROL_NONCE_REQUIRED (0x01 << 13) +#define CONTROL_NONCE_OR_ENTRY (0x02 << 13) +#define CONTROL_HDCP_VERSION_SHIFT 9 +#define CONTROL_HDCP_VERSION_MASK (0x0F << CONTROL_HDCP_VERSION_SHIFT) +#define CONTROL_ALLOW_ENCRYPT (1 << 8) +#define CONTROL_ALLOW_DECRYPT (1 << 7) +#define CONTROL_ALLOW_SIGN (1 << 6) +#define CONTROL_ALLOW_VERIFY (1 << 5) +#define CONTROL_DATA_PATH_SECURE (1 << 4) +#define CONTROL_NONCE_ENABLED (1 << 3) +#define CONTROL_HDCP_REQUIRED (1 << 2) +#define CONTROL_CGMS_MASK 0x03 +#define CONTROL_CGMS_COPY_FREELY 0x00 +#define CONTROL_CGMS_COPY_ONCE 0x02 +#define CONTROL_CGMS_COPY_NEVER 0x03 + +/* Various constants and sizes */ +#define AES_BLOCK_SIZE 16 +#define KEY_CONTROL_SIZE 16 +#define KEY_ID_MAX_SIZE 16 +#define KEY_IV_SIZE 16 +#define KEY_PAD_SIZE 16 +#define KEY_SIZE 16 +#define MAC_KEY_SIZE 32 +#define KEYBOX_KEY_DATA_SIZE 72 +#define KEYBOX_DEVICE_ID_SIZE 32 +#define SRM_REQUIREMENT_SIZE 12 +#define SHA256_DIGEST_LENGTH 32 +#define SHA_DIGEST_LENGTH 20 +/* TODO(b/145026434): The value of PKCS8_RSA_KEY_MAX_SIZE is purely from testing + with openssl and is not derived from any specification. Generating 3072-bit + PKCS8 RSA keys gave me keys of a max size of 1794 bytes so I added a bit of + padding to make sure it's okay. This is NOT guaranteed to work for all DRM + keys. */ +#define PKCS8_RSA_KEY_MAX_SIZE 2000 + +typedef struct WrappedRSAKey { + uint8_t signature[MAC_KEY_SIZE]; + uint8_t context[MAC_KEY_SIZE]; + uint8_t iv[KEY_IV_SIZE]; + uint8_t enc_rsa_key[]; +} WrappedRSAKey; + +#endif /* OEMCRYPTO_TA_OEMCRYPTO_KEY_TYPES_H_ */ diff --git a/oemcrypto_ta/oemcrypto_nonce_table.c b/oemcrypto_ta/oemcrypto_nonce_table.c new file mode 100644 index 0000000..a6da22c --- /dev/null +++ b/oemcrypto_ta/oemcrypto_nonce_table.c @@ -0,0 +1,81 @@ +/* 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_nonce_table.h" + +#include "stddef.h" + +#include "assert_interface.h" + +void AddNonce(NonceTable* nonce_table, uint32_t nonce) { + ASSERT(nonce_table != NULL, "nonce_table is NULL"); + int new_slot = -1; + int oldest_slot = -1; + + /* Flush any nonce_table->nonces that have been checked but not flushed. + After flush, nonce_table->nonces will be either valid or invalid. */ + FlushNonces(nonce_table); + + for (int i = 0; i < NONCE_TABLE_SIZE; i++) { + /* Increase nonce_table->age of all valid nonce_table->nonces. */ + if (nonce_table->state[i] == NT_STATE_VALID) { + nonce_table->age[i]++; + if (oldest_slot == -1) { + oldest_slot = i; + } else { + if (nonce_table->age[i] > nonce_table->age[oldest_slot]) { + oldest_slot = i; + } + } + } else { + if (new_slot == -1) { + nonce_table->age[i] = 0; + nonce_table->nonces[i] = nonce; + nonce_table->state[i] = NT_STATE_VALID; + new_slot = i; + } + } + } + if (new_slot == -1) { + /* reuse oldest */ + ASSERT(oldest_slot != -1, "oldest_slot is -1"); + int i = oldest_slot; + nonce_table->age[i] = 0; + nonce_table->nonces[i] = nonce; + nonce_table->state[i] = NT_STATE_VALID; + } +} + +bool CheckNonce(NonceTable* nonce_table, uint32_t nonce) { + ASSERT(nonce_table != NULL, "nonce_table is NULL"); + for (int i = 0; i < NONCE_TABLE_SIZE; i++) { + if (nonce_table->state[i] != NT_STATE_INVALID) { + if (nonce_table->nonces[i] == nonce) { + nonce_table->state[i] = NT_STATE_FLUSH_PENDING; + return true; + } + } + } + return false; +} + +bool NonceCollision(NonceTable* nonce_table, uint32_t nonce) { + ASSERT(nonce_table != NULL, "nonce_table is NULL"); + for (int i = 0; i < NONCE_TABLE_SIZE; i++) { + if (nonce_table->nonces[i] == nonce && + nonce_table->state[i] != NT_STATE_INVALID) { + return true; + } + } + return false; +} + +void FlushNonces(NonceTable* nonce_table) { + ASSERT(nonce_table != NULL, "nonce_table is NULL"); + for (int i = 0; i < NONCE_TABLE_SIZE; i++) { + if (nonce_table->state[i] == NT_STATE_FLUSH_PENDING) { + nonce_table->state[i] = NT_STATE_INVALID; + } + } +} diff --git a/oemcrypto_ta/oemcrypto_nonce_table.h b/oemcrypto_ta/oemcrypto_nonce_table.h new file mode 100644 index 0000000..feea0e4 --- /dev/null +++ b/oemcrypto_ta/oemcrypto_nonce_table.h @@ -0,0 +1,41 @@ +/* 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. */ + +#ifndef OEMCRYPTO_TA_OEMCRYPTO_NONCE_TABLE_H_ +#define OEMCRYPTO_TA_OEMCRYPTO_NONCE_TABLE_H_ + +#include "stdbool.h" +#include "stdint.h" + +#define NONCE_TABLE_SIZE 4 + +typedef enum NonceTableState { + NT_STATE_INVALID = 0x73624fe4, + NT_STATE_VALID = 0x7fb3983a, + NT_STATE_FLUSH_PENDING = 0x1b9654ae, +} NonceTableState; + +typedef struct NonceTable { + NonceTableState state[NONCE_TABLE_SIZE]; + uint32_t age[NONCE_TABLE_SIZE]; + uint32_t nonces[NONCE_TABLE_SIZE]; +} NonceTable; + +/* Adds |nonce| to the |nonce_table|. Flushes any nonces that have already been + checked and then either adds it to the nonce table or replaces the oldest + valid nonce in the table. */ +void AddNonce(NonceTable* nonce_table, uint32_t nonce); + +/* Checks the |nonce| exists in the |nonce_table|. Marks the nonce as ready to + be flushed if it exists. + Returns false if it does not exist in the table. */ +bool CheckNonce(NonceTable* nonce_table, uint32_t nonce); + +/* Verify that the nonce is not the same as any in |nonce_table|. */ +bool NonceCollision(NonceTable* nonce_table, uint32_t nonce); + +/* Flush any nonces that have been checked in |nonce_table|. */ +void FlushNonces(NonceTable* nonce_table); + +#endif // OEMCRYPTO_TA_OEMCRYPTO_NONCE_TABLE_H_ diff --git a/oemcrypto_ta/oemcrypto_overflow.c b/oemcrypto_ta/oemcrypto_overflow.c new file mode 100644 index 0000000..851269f --- /dev/null +++ b/oemcrypto_ta/oemcrypto_overflow.c @@ -0,0 +1,56 @@ +/* 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 "stddef.h" +#include "stdint.h" + +int SubOverflowIX(int a, int b, int* c) { + if (a >= b) { + if (c) { + *c = a - b; + } + return 0; + } + return 1; +} + +int SubOverflowU32(uint32_t a, uint32_t b, uint32_t* c) { + if (a >= b) { + if (c) { + *c = a - b; + } + return 0; + } + return 1; +} + +int SubOverflowU64(uint64_t a, uint64_t b, uint64_t* c) { + if (a >= b) { + if (c) { + *c = a - b; + } + return 0; + } + return 1; +} + +int AddOverflowUX(size_t a, size_t b, size_t* c) { + if (SIZE_MAX - a >= b) { + if (c) { + *c = a + b; + } + return 0; + } + return 1; +} + +int SubOverflowUX(size_t a, size_t b, size_t* c) { + if (a >= b) { + if (c) { + *c = a - b; + } + return 0; + } + return 1; +} diff --git a/oemcrypto_ta/oemcrypto_overflow.h b/oemcrypto_ta/oemcrypto_overflow.h new file mode 100644 index 0000000..285e3ea --- /dev/null +++ b/oemcrypto_ta/oemcrypto_overflow.h @@ -0,0 +1,32 @@ +/* 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. */ + +#ifndef OEMCRYPTO_TA_OEMCRYPTO_OVERFLOW_H_ +#define OEMCRYPTO_TA_OEMCRYPTO_OVERFLOW_H_ + +/* Defines operators that check for overflow in arithmetic. + Uses the standards GNU builtins if defined and custom overflow functions + otherwise. */ + +/* TODO(b/145244569): Unify this with the interface for the odk. */ + +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif +#if (defined(__GNUC__) && __GNUC__ >= 5) || \ + __has_builtin(__builtin_add_overflow) +# define SubOverflowIX __builtin_sub_overflow +# define SubOverflowU32 __builtin_sub_overflow +# define SubOverflowU64 __builtin_sub_overflow +# define AddOverflowUX __builtin_add_overflow +# define SubOverflowUX __builtin_sub_overflow +#else +int SubOverflowIX(int a, int b, int* c); +int SubOverflowU32(uint32_t a, uint32_t b, uint32_t* c); +int SubOverflowU64(uint64_t a, uint64_t b, uint64_t* c); +int AddOverflowUX(size_t a, size_t b, size_t* c); +int SubOverflowUX(size_t a, size_t b, size_t* c); +#endif + +#endif /* OEMCRYPTO_TA_OEMCRYPTO_OVERFLOW_H_ */ diff --git a/oemcrypto_ta/oemcrypto_serialized_usage_table.c b/oemcrypto_ta/oemcrypto_serialized_usage_table.c new file mode 100644 index 0000000..43e41d0 --- /dev/null +++ b/oemcrypto_ta/oemcrypto_serialized_usage_table.c @@ -0,0 +1,100 @@ +/* Copyright 2020 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_serialized_usage_table.h" + +#include "stddef.h" +#include "string.h" + +#include "assert_interface.h" +#include "oemcrypto_usage_table.h" + +/* Porting layer includes: */ +#include "assert_interface.h" + +/* The buffer size we need to reserve for a signed header with the given number + of entries. + TODO(b/158720996): use serialization and allow variable sized headers. This + code currently uses memcpy to serialize data. That works as long as we do not + try to change message format or want to change the header size. + */ +size_t SignedHeaderSize(int table_size) { + return sizeof(SignedSavedUsageHeader); +} + +size_t SignedEntrySize() { return sizeof(SignedSavedUsageEntry); } + +OEMCryptoResult PackSignedUsageHeader(uint8_t* buffer, size_t buffer_size, + const SignedSavedUsageHeader* header) { + if (buffer_size < sizeof(SignedSavedUsageHeader)) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + memcpy(buffer, header, sizeof(SignedSavedUsageHeader)); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult PackUsageHeader(uint8_t* buffer, size_t buffer_size, + const SavedUsageHeader* header) { + if (buffer_size < sizeof(SavedUsageHeader)) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + memcpy(buffer, header, sizeof(SavedUsageHeader)); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult PackSignedUsageEntry(uint8_t* buffer, size_t buffer_size, + const SignedSavedUsageEntry* entry) { + if (buffer_size < sizeof(SignedSavedUsageEntry)) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + memcpy(buffer, entry, sizeof(SignedSavedUsageEntry)); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult PackUsageEntry(uint8_t* buffer, size_t buffer_size, + const SavedUsageEntry* entry) { + if (buffer_size < sizeof(SavedUsageEntry)) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + memcpy(buffer, entry, sizeof(SavedUsageEntry)); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult UnpackSignedUsageHeader(const uint8_t* buffer, + size_t buffer_size, + SignedSavedUsageHeader* header) { + if (buffer_size < sizeof(SignedSavedUsageHeader)) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + memcpy(header, buffer, sizeof(SignedSavedUsageHeader)); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult UnpackUsageHeader(const uint8_t* buffer, size_t buffer_size, + SavedUsageHeader* header) { + if (buffer_size < sizeof(SavedUsageHeader)) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + memcpy(header, buffer, sizeof(SavedUsageHeader)); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult UnpackSignedUsageEntry(const uint8_t* buffer, + size_t buffer_size, + SignedSavedUsageEntry* entry) { + if (buffer_size < sizeof(SignedSavedUsageEntry)) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + memcpy(entry, buffer, sizeof(SignedSavedUsageEntry)); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult UnpackUsageEntry(const uint8_t* buffer, size_t buffer_size, + SavedUsageEntry* entry) { + if (buffer_size < sizeof(SavedUsageEntry)) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + memcpy(entry, buffer, sizeof(SavedUsageEntry)); + return OEMCrypto_SUCCESS; +} diff --git a/oemcrypto_ta/oemcrypto_serialized_usage_table.h b/oemcrypto_ta/oemcrypto_serialized_usage_table.h new file mode 100644 index 0000000..e52805e --- /dev/null +++ b/oemcrypto_ta/oemcrypto_serialized_usage_table.h @@ -0,0 +1,118 @@ +/* Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine Master + License Agreement. */ + +#ifndef OEMCRYPTO_TA_OEMCRYPTO_SERIALIZED_USAGE_TABLE_H_ +#define OEMCRYPTO_TA_OEMCRYPTO_SERIALIZED_USAGE_TABLE_H_ + +#include "OEMCryptoCENC.h" + +#include "oemcrypto_config_macros.h" +#include "oemcrypto_key_types.h" + +/* File types. */ +#define USAGE_TABLE_HEADER 0x68656164 +#define USAGE_TABLE_ENTRY 0x656e7472 +#define SIGNED_USAGE_TABLE_HEADER 0x48454144 +#define SIGNED_USAGE_TABLE_ENTRY 0x456e7472 + +#define MAX_PST_LENGTH 255 + +/* This can be changed to allow for newer code to load older files. */ +#define CURRENT_FILE_FORMAT_VERSION 1 + +/* This is the usage header, as saved to the file system, before encryption. */ +typedef struct SavedUsageHeader { + uint32_t file_type; /* This should always be USAGE_TABLE_HEADER */ + uint32_t format_version; /* For future backwards compatibility. */ + uint64_t master_generation_number; + uint32_t table_size; /* Number of entries in the table. */ + /* These are the generation numbers of each entry. */ + uint64_t generation_numbers[MAX_NUMBER_OF_USAGE_ENTRIES]; +} SavedUsageHeader; + +/* This is all of the data we wish to save as part of a usage table entry, + * before encryption. */ +typedef struct SavedUsageEntry { + uint32_t file_type; /* This should always be USAGE_TABLE_ENTRY. */ + uint32_t format_version; /* For future backwards compatibility. */ + uint32_t index; /* Index into usage header. */ + uint64_t generation_number; /* Used to prevent rollback. */ + int64_t time_of_license_received; /* Time in seconds on system clock. */ + int64_t time_of_first_decrypt; /* Time in seconds on system clock. */ + int64_t time_of_last_decrypt; /* Time in seconds on system clock.. */ + /* Status of the entry or license, as documented in OEMCrypto spec. */ + enum OEMCrypto_Usage_Entry_Status status; + /* Server Mac key wrapped for this device. */ + uint8_t mac_key_server[WRAPPED_MAC_KEY_SIZE]; + /* Client Mac key wrapped for this device. */ + uint8_t mac_key_client[WRAPPED_MAC_KEY_SIZE]; + /* Provider session token for this license. */ + uint8_t pst[MAX_PST_LENGTH + 1]; /* add 1 for padding. */ + uint8_t pst_length; +} SavedUsageEntry; + +/* TODO(b/158720996): This should be updated when we switch to using odkitee + * serialization. */ +/* In order to encrypt the data, we'll copy it to a slightly larger buffer + * that is a whole multiple of an AES block. */ +#define PADDED_HEADER_BUFFER_SIZE (16 * (1 + sizeof(SavedUsageHeader) / 16)) +#define PADDED_ENTRY_BUFFER_SIZE (16 * (1 + sizeof(SavedUsageEntry) / 16)) + +/* This is the usage header, as saved to the file system, after encryption and + * signing. */ +typedef struct SignedSavedUsageHeader { + uint32_t file_type; /* This should always be SIGNED_USAGE_TABLE_HEADER */ + /* Used for future backwards compatibility. */ + uint32_t format_version; + /* The size of the saved buffer. At most PADDED_HEADER_BUFFER_SIZE. Must be + * a multiple of 16, one AES block size. */ + uint32_t buffer_size; + /* Signature of the buffer using a device unique key. */ + uint8_t signature[SHA256_DIGEST_LENGTH]; + /* An encrypted SavedUsageHeader. */ + uint8_t buffer[PADDED_HEADER_BUFFER_SIZE]; +} SignedSavedUsageHeader; + +/* This is a usage table entry, as saved to the file system, after encryption + * and signing. */ +typedef struct SignedSavedUsageEntry { + uint32_t file_type; /* This should always be SIGNED_USAGE_TABLE_ENTRY */ + /* Used for future backwards compatibility. */ + uint32_t format_version; + /* The size of the saved buffer. At most PADDED_HEADER_BUFFER_SIZE. Must be + * a multiple of 16, one AES block size. */ + uint32_t buffer_size; + uint8_t signature[SHA256_DIGEST_LENGTH]; + /* Signature of the buffer using a device unique key. */ + uint8_t buffer[PADDED_ENTRY_BUFFER_SIZE]; /* An encrypted SavedUsageEntry */ +} SignedSavedUsageEntry; + +/* TODO(b/158720996): use serialization to turn these structures into messages + * for saving. */ +/* Size of a serialized SignedSavedUsageHeader with the specified table size. */ +size_t SignedHeaderSize(int table_size); +/* Size of a serialized SignedSavedUsageEntry. */ +size_t SignedEntrySize(void); + +OEMCryptoResult PackSignedUsageHeader(uint8_t* buffer, size_t buffer_size, + const SignedSavedUsageHeader* header); +OEMCryptoResult PackUsageHeader(uint8_t* buffer, size_t buffer_size, + const SavedUsageHeader* header); +OEMCryptoResult PackSignedUsageEntry(uint8_t* buffer, size_t buffer_size, + const SignedSavedUsageEntry* entry); +OEMCryptoResult PackUsageEntry(uint8_t* buffer, size_t buffer_size, + const SavedUsageEntry* entry); + +OEMCryptoResult UnpackSignedUsageHeader(const uint8_t* buffer, + size_t buffer_size, + SignedSavedUsageHeader* header); +OEMCryptoResult UnpackUsageHeader(const uint8_t* buffer, size_t buffer_size, + SavedUsageHeader* header); +OEMCryptoResult UnpackSignedUsageEntry(const uint8_t* buffer, + size_t buffer_size, + SignedSavedUsageEntry* entry); +OEMCryptoResult UnpackUsageEntry(const uint8_t* buffer, size_t buffer_size, + SavedUsageEntry* entry); + +#endif // OEMCRYPTO_TA_OEMCRYPTO_SERIALIZED_USAGE_TABLE_H_ diff --git a/oemcrypto_ta/oemcrypto_session.c b/oemcrypto_ta/oemcrypto_session.c new file mode 100644 index 0000000..f24a3b9 --- /dev/null +++ b/oemcrypto_ta/oemcrypto_session.c @@ -0,0 +1,946 @@ +/* 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_session.h" + +#include "string.h" + +#include "assert_interface.h" +#include "clock_interface.h" +#include "oemcrypto_endianness.h" +#include "logging_interface.h" +#include "oemcrypto_key_table.h" +#include "oemcrypto_nonce_table.h" +#include "oemcrypto_overflow.h" +#include "oemcrypto_session_key_table.h" +#include "oemcrypto_usage_table.h" +#include "root_of_trust_interface.h" + +static void clear_nonce_table(OEMCryptoSession* session) { + for (int i = 0; i < NONCE_TABLE_SIZE; i++) { + session->nonce_table.age[i] = 0; + session->nonce_table.nonces[i] = 0; + session->nonce_table.state[i] = NT_STATE_INVALID; + } +} + +OEMCryptoResult InitializeSession(OEMCryptoSession* session, uint32_t index) { + ASSERT(session != NULL, "session is NULL"); + session->session_id = index; + session->state = SESSION_INVALID; + clear_nonce_table(session); + session->drm_private_key = NULL; + session->mac_key_client = NULL; + session->mac_key_server = NULL; + session->encryption_key = NULL; + session->session_key = NULL; + session->refresh_valid = false; + session->license_type = OEMCrypto_ContentLicense; + session->current_content_key_index = CONTENT_KEYS_PER_SESSION; + for (int i = 0; i < CONTENT_KEYS_PER_SESSION; i++) { + session->content_keys[i] = NULL; + } + session->num_content_keys = 0; + for (int i = 0; i < ENTITLEMENT_KEYS_PER_SESSION; i++) { + session->entitlement_keys[i] = NULL; + } + session->num_entitlement_keys = 0; + session->valid_srm_version = false; + session->timer_start = 0; + session->compute_hash = false; + session->current_hash = 0; + session->given_hash = 0; + session->current_frame_number = 0; + session->bad_frame_number = 0; + session->hash_error = OEMCrypto_SUCCESS; + session->usage_entry_status = SESSION_HAS_NO_ENTRY; + session->usage_entry_number = MAX_NUMBER_OF_USAGE_ENTRIES; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult TerminateSession(OEMCryptoSession* session) { + ASSERT(session != NULL, "session is NULL"); + OEMCryptoResult result = OEMCrypto_SUCCESS; + + result = FreeKey(&session->drm_private_key); + + OEMCryptoResult free_key_result = FreeKey(&session->mac_key_client); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + + free_key_result = FreeKey(&session->mac_key_server); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + + free_key_result = FreeKey(&session->encryption_key); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + + free_key_result = FreeKey(&session->session_key); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + + for (uint32_t i = 0; i < session->num_content_keys; i++) { + free_key_result = FreeKey(&session->content_keys[i]); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + } + + for (uint32_t i = 0; i < session->num_entitlement_keys; i++) { + free_key_result = FreeKey(&session->entitlement_keys[i]); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + } + + clear_nonce_table(session); + + if (session->usage_entry_status != SESSION_HAS_NO_ENTRY) { + ReleaseEntry(session, session->usage_entry_number); + } + + memset(session, 0, sizeof(OEMCryptoSession)); + return result; +} + +OEMCryptoResult CheckStatePreCall(OEMCryptoSession* session, + OEMCryptoSessionAPI api) { + ASSERT(session != NULL, "session is NULL"); + switch (api) { + case API_OPENSESSION: + switch (session->state) { + case SESSION_INVALID: + return OEMCrypto_SUCCESS; + default: + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + case API_CLOSESESSION: + return OEMCrypto_SUCCESS; + case API_GETOEMPUBLICCERTIFICATE: + switch (session->state) { + case (SESSION_OPENED): + case (SESSION_LOAD_OEM_RSA_KEY): + return OEMCrypto_SUCCESS; + default: + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + case API_GENERATEDERIVEDKEYS: + switch (session->state) { + case (SESSION_OPENED): + return OEMCrypto_SUCCESS; + default: + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + case API_GENERATENONCE: + switch (session->state) { + case (SESSION_OPENED): + case (SESSION_DERIVED_KEYS): + case (SESSION_DERIVED_KEYS_FROM_SESSION_KEY): + case (SESSION_KEYS_LOADED): + case (SESSION_DECRYPT_KEY_SELECTED): + case (SESSION_LOAD_OEM_RSA_KEY): + case (SESSION_LOAD_DRM_RSA_KEY): + return OEMCrypto_SUCCESS; + default: + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + case API_GENERATERSASIGNATURE: + switch (session->state) { + case (SESSION_LOAD_OEM_RSA_KEY): + case (SESSION_LOAD_DRM_RSA_KEY): + return OEMCrypto_SUCCESS; + default: + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + case API_REWRAPDEVICERSAKEY: + switch (session->state) { + case (SESSION_DERIVED_KEYS): + return OEMCrypto_SUCCESS; + default: + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + case API_REWRAPDEVICERSAKEY30: + switch (session->state) { + case (SESSION_LOAD_OEM_RSA_KEY): + return OEMCrypto_SUCCESS; + default: + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + case API_LOADDEVICERSAKEY: + switch (session->state) { + case (SESSION_LOAD_OEM_RSA_KEY): + case (SESSION_OPENED): + return OEMCrypto_SUCCESS; + default: + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + case API_DERIVEKEYSFROMSESSIONKEY: + switch (session->state) { + case (SESSION_LOAD_DRM_RSA_KEY): + return OEMCrypto_SUCCESS; + default: + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + case API_LOADKEYS: + switch (session->state) { + case (SESSION_DERIVED_KEYS_FROM_SESSION_KEY): + case (SESSION_KEYS_LOADED): + case (SESSION_DECRYPT_KEY_SELECTED): + return OEMCrypto_SUCCESS; + default: + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + case API_REFRESHKEYS: + switch (session->state) { + case (SESSION_KEYS_LOADED): + case (SESSION_DECRYPT_KEY_SELECTED): + return OEMCrypto_SUCCESS; + default: + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + case API_GENERATESIGNATURE: + switch (session->state) { + case (SESSION_DERIVED_KEYS): + case (SESSION_DERIVED_KEYS_FROM_SESSION_KEY): + case (SESSION_KEYS_LOADED): + case (SESSION_DECRYPT_KEY_SELECTED): + /* The next two are needed for license release in v15. */ + case (SESSION_OPENED): + case (SESSION_LOAD_DRM_RSA_KEY): + return OEMCrypto_SUCCESS; + default: + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + case API_SELECTKEY: + case API_LOADENTITLEDCONTENTKEYS: + case API_QUERYKEYCONTROL: + switch (session->state) { + case (SESSION_KEYS_LOADED): + case (SESSION_DECRYPT_KEY_SELECTED): + return OEMCrypto_SUCCESS; + default: + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + case API_DECRYPTCENC: + case API_GENERICENCRYPT: + case API_GENERICDECRYPT: + case API_GENERICSIGN: + case API_GENERICVERIFY: + case API_GETHASHERRORCODE: + switch (session->state) { + case (SESSION_DECRYPT_KEY_SELECTED): + return OEMCrypto_SUCCESS; + default: + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + case API_SETDECRYPTHASH: + switch (session->state) { + case (SESSION_INVALID): + return OEMCrypto_ERROR_INVALID_CONTEXT; + default: + return OEMCrypto_SUCCESS; + } + default: + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } +} + +OEMCryptoResult SetStatePostCall(OEMCryptoSession* session, + OEMCryptoSessionAPI api) { + ASSERT(session != NULL, "session is NULL"); + switch (api) { + case API_OPENSESSION: + session->state = SESSION_OPENED; + break; + case API_GETOEMPUBLICCERTIFICATE: + session->state = SESSION_LOAD_OEM_RSA_KEY; + break; + case API_GENERATEDERIVEDKEYS: + session->state = SESSION_DERIVED_KEYS; + break; + case API_GENERATENONCE: + case API_GENERATERSASIGNATURE: + case API_REWRAPDEVICERSAKEY: + case API_REWRAPDEVICERSAKEY30: + case API_GENERATESIGNATURE: + case API_REFRESHKEYS: + case API_LOADENTITLEDCONTENTKEYS: + case API_GENERICENCRYPT: + case API_GENERICDECRYPT: + case API_GENERICSIGN: + case API_GENERICVERIFY: + case API_SETDECRYPTHASH: + case API_GETHASHERRORCODE: + case API_QUERYKEYCONTROL: + /* State does not change. */ + break; + case API_LOADDEVICERSAKEY: + session->state = SESSION_LOAD_DRM_RSA_KEY; + break; + case API_DERIVEKEYSFROMSESSIONKEY: + session->state = SESSION_DERIVED_KEYS_FROM_SESSION_KEY; + break; + case API_LOADKEYS: + session->state = SESSION_KEYS_LOADED; + break; + case API_SELECTKEY: + case API_DECRYPTCENC: + session->state = SESSION_DECRYPT_KEY_SELECTED; + break; + default: + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult StartTimer(OEMCryptoSession* session) { + ASSERT(session != NULL, "session is NULL"); + OEMCrypto_Clock_Security_Level clock_type; + return GetSystemTime(&session->timer_start, &clock_type); +} + +OEMCryptoResult CurrentTimer(const OEMCryptoSession* session, uint64_t* diff) { + ASSERT(session != NULL, "session is NULL"); + ASSERT(diff != NULL, "diff is NULL"); + uint64_t current_time; + OEMCrypto_Clock_Security_Level clock_type; + OEMCryptoResult result = GetSystemTime(¤t_time, &clock_type); + if (result != OEMCrypto_SUCCESS) return result; + if (SubOverflowU64(current_time, session->timer_start, diff)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult LoadDRMRSAKey(OEMCryptoSession* session, + const uint8_t* pkcs8_rsa_key, + uint32_t rsa_key_length) { + ASSERT(session != NULL, "session is NULL"); + ASSERT(pkcs8_rsa_key != NULL, "pkcs8_rsa_key is NULL"); + ASSERT(rsa_key_length != 0, "rsa_key_length is 0"); + if (rsa_key_length < 8) return OEMCrypto_ERROR_INVALID_RSA_KEY; + /* Determine the padding scheme allowed. */ + uint32_t allowed_schemes; + if ((memcmp(pkcs8_rsa_key, "SIGN", 4) == 0)) { + uint32_t schemes_n; + memcpy((uint8_t*)&schemes_n, pkcs8_rsa_key + 4, sizeof(uint32_t)); + allowed_schemes = HostToNetworkU32(schemes_n); + pkcs8_rsa_key += 8; + rsa_key_length -= 8; + } else { + allowed_schemes = kSign_RSASSA_PSS; + } + + if ((GetRSAPaddingSchemes() & allowed_schemes) != allowed_schemes) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + + /* Verify that the key is valid. */ + OEMCryptoResult result = + CreateKey(&session->drm_private_key, pkcs8_rsa_key, rsa_key_length, + DRM_RSA_PRIVATE_KEY, UNKNOWN_KEY_OPERATION, UNKNOWN_KEY_SIZE); + if (result != OEMCrypto_SUCCESS) return result; + session->drm_private_key->allowed_schemes = allowed_schemes; + return OEMCrypto_SUCCESS; +} + +typedef enum DeriveKeyType { + GENERIC_DERIVE_KEY_TYPE = 0x24514123, + KEYBOX_DERIVE_KEY_TYPE = 0x0be5a960, + DEVICE_KEY_DERIVE_KEY_TYPE = 0x4933dcdd, +} DeriveKeyType; + +static OEMCryptoResult DeriveKey(const CryptoKey* master_key, uint8_t counter, + const uint8_t* context, + uint32_t context_length, uint8_t* out, + DeriveKeyType derive_key_type) { + switch (derive_key_type) { + case GENERIC_DERIVE_KEY_TYPE: + return DeriveKeyFromKeyHandle(master_key->key_handle, counter, context, + context_length, out); + case DEVICE_KEY_DERIVE_KEY_TYPE: + return DeriveKeyFromDeviceKey(counter, context, context_length, out); + case KEYBOX_DERIVE_KEY_TYPE: + return DeriveKeyFromKeybox(counter, context, context_length, out); + default: + /* Unimplemented or invalid. */ + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +} + +static OEMCryptoResult DeriveMacAndEncryptionKeys( + OEMCryptoSession* session, const CryptoKey* master_key, + const uint8_t* mac_key_context, uint32_t mac_key_context_length, + const uint8_t* enc_key_context, uint32_t enc_key_context_length, + DeriveKeyType derive_key_type) { + ASSERT( + session != NULL && mac_key_context != NULL && + mac_key_context_length != 0 && enc_key_context != NULL && + enc_key_context_length != 0 && + !(master_key == NULL && derive_key_type == GENERIC_DERIVE_KEY_TYPE), + "Parameters are NULL or 0"); + + /* Generate derived keys for mac keys. */ + uint8_t mac_key_server[MAC_KEY_SIZE]; + uint8_t mac_key_client[MAC_KEY_SIZE]; + + OEMCryptoResult result = + DeriveKey(master_key, 1, mac_key_context, mac_key_context_length, + mac_key_server, derive_key_type); + if (result != OEMCrypto_SUCCESS) return result; + result = DeriveKey(master_key, 2, mac_key_context, mac_key_context_length, + mac_key_server + KEY_SIZE_128, derive_key_type); + if (result != OEMCrypto_SUCCESS) return result; + + result = DeriveKey(master_key, 3, mac_key_context, mac_key_context_length, + mac_key_client, derive_key_type); + if (result != OEMCrypto_SUCCESS) return result; + result = DeriveKey(master_key, 4, mac_key_context, mac_key_context_length, + mac_key_client + KEY_SIZE_128, derive_key_type); + if (result != OEMCrypto_SUCCESS) return result; + + /* Generate derived key for encryption key. */ + uint8_t encryption_key[KEY_SIZE_128]; + result = DeriveKey(master_key, 1, enc_key_context, enc_key_context_length, + encryption_key, derive_key_type); + if (result != OEMCrypto_SUCCESS) return result; + + result = CreateKey(&session->mac_key_server, mac_key_server, MAC_KEY_SIZE, + MAC_KEY_SERVER, MAC_KEY_SERVER_VERIFY, MAC_KEY_SIZE); + if (result != OEMCrypto_SUCCESS) return result; + result = CreateKey(&session->mac_key_client, mac_key_client, MAC_KEY_SIZE, + MAC_KEY_CLIENT, MAC_KEY_CLIENT_SIGN, MAC_KEY_SIZE); + if (result != OEMCrypto_SUCCESS) { + FreeKey(&session->mac_key_server); + return result; + } + result = CreateKey(&session->encryption_key, encryption_key, KEY_SIZE_128, + ENCRYPTION_KEY, ENCRYPTION_KEY_ENCRYPT, KEY_SIZE_128); + if (result != OEMCrypto_SUCCESS) { + FreeKey(&session->mac_key_server); + FreeKey(&session->mac_key_client); + } + return result; +} + +OEMCryptoResult DeriveMacAndEncryptionKeysFromCryptoKey( + OEMCryptoSession* session, const CryptoKey* master_key, + const uint8_t* mac_key_context, uint32_t mac_key_context_length, + const uint8_t* enc_key_context, uint32_t enc_key_context_length) { + return DeriveMacAndEncryptionKeys( + session, master_key, mac_key_context, mac_key_context_length, + enc_key_context, enc_key_context_length, GENERIC_DERIVE_KEY_TYPE); +} + +OEMCryptoResult DeriveMacAndEncryptionKeysFromDeviceKey( + OEMCryptoSession* session, const uint8_t* mac_key_context, + uint32_t mac_key_context_length, const uint8_t* enc_key_context, + uint32_t enc_key_context_length) { + return DeriveMacAndEncryptionKeys( + session, NULL, mac_key_context, mac_key_context_length, enc_key_context, + enc_key_context_length, DEVICE_KEY_DERIVE_KEY_TYPE); +} + +OEMCryptoResult DeriveMacAndEncryptionKeysFromKeybox( + OEMCryptoSession* session, const uint8_t* mac_key_context, + uint32_t mac_key_context_length, const uint8_t* enc_key_context, + uint32_t enc_key_context_length) { + if (GetProvisioningMethod() != OEMCrypto_Keybox) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + OEMCryptoResult result = ValidateKeybox(); + if (result != OEMCrypto_SUCCESS) return result; + return DeriveMacAndEncryptionKeys( + session, NULL, mac_key_context, mac_key_context_length, enc_key_context, + enc_key_context_length, KEYBOX_DERIVE_KEY_TYPE); +} + +OEMCryptoResult VerifySignatureWithMacKeyServer(OEMCryptoSession* session, + const uint8_t* message, + uint32_t message_length, + const uint8_t* signature) { + ASSERT(session != NULL && message != NULL && message_length != 0 && + signature != NULL, + "Parameters are NULL or 0"); + if (!CheckKey(session->mac_key_server, MAC_KEY_SERVER, + MAC_KEY_SERVER_VERIFY)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + uint8_t computed_signature[SHA256_DIGEST_LENGTH]; + OEMCryptoResult result = + HMAC_SHA256(session->mac_key_server->key_handle, message, message_length, + computed_signature); + if (result != OEMCrypto_SUCCESS) return result; + if (memcmp(signature, computed_signature, SHA256_DIGEST_LENGTH) != 0) { + return OEMCrypto_ERROR_SIGNATURE_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +static OEMCryptoResult CheckStatusOnline(OEMCryptoSession* session, + uint32_t nonce, uint32_t control) { + if (!session) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (!(control & CONTROL_NONCE_ENABLED)) { + /* TODO(b/154764983): fix this. */ + /* Server error. Continue, and assume nonce required. */ + LOGE("Server error: nonce not enabled."); + } + if (!CheckNonce(&session->nonce_table, nonce)) { + return OEMCrypto_ERROR_INVALID_NONCE; + } + switch (session->usage_entry_status) { + default: /* Invalid status. */ + case SESSION_HAS_NO_ENTRY: + return OEMCrypto_ERROR_INVALID_CONTEXT; + case SESSION_HAS_LOADED_ENTRY: + /* Cannot reload usage entry for online license. */ + return OEMCrypto_ERROR_INVALID_CONTEXT; + case SESSION_HAS_NEW_ENTRY: + return OEMCrypto_SUCCESS; + } +} + +static OEMCryptoResult CheckStatusOffline(OEMCryptoSession* session, + uint32_t nonce, uint32_t control) { + if (!session) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (!(control & CONTROL_NONCE_ENABLED)) { + /* TODO(b/154764983): fix this. */ + /* Server error. Continue, and assume nonce required. */ + LOGE("Server error: nonce not enabled."); + } + switch (session->usage_entry_status) { + default: /* Invalid status. */ + case SESSION_HAS_NO_ENTRY: + return OEMCrypto_ERROR_INVALID_CONTEXT; + case SESSION_HAS_LOADED_ENTRY: + /* We do not check the nonce. Instead, LoadKeys will verify the pst and + * mac keys match. */ + return OEMCrypto_SUCCESS; + case SESSION_HAS_NEW_ENTRY: + if (!CheckNonce(&session->nonce_table, nonce)) { + return OEMCrypto_ERROR_INVALID_NONCE; + } + return OEMCrypto_SUCCESS; + } +} + +static OEMCryptoResult check_nonce_or_entry(OEMCryptoSession* session, + KeyControlBlock key_control_block) { + /* Note: we only check the nonce if the bit is enabled. */ + uint8_t replay_bit = + (uint8_t)(key_control_block.control_bits & CONTROL_REPLAY_MASK); + switch (replay_bits) { + case CONTROL_NONCE_REQUIRED: + /* Online license. Nonce always required. */ + return CheckStatusOnline(session, key_control_block.nonce, + key_control_block.control_bits); + break; + case CONTROL_NONCE_OR_ENTRY: + /* Offline license. Nonce required on first load. */ + return CheckStatusOffline(session, key_control_block.nonce, + key_control_block.control_bits); + break; + default: + if ((key_control_block.control_bits & CONTROL_NONCE_ENABLED) && + !CheckNonce(&session->nonce_table, key_control_block.nonce)) { + return OEMCrypto_ERROR_INVALID_NONCE; + } + return OEMCrypto_SUCCESS; + } +} + +OEMCryptoResult InstallKey(OEMCryptoSession* session, const uint8_t* key_id, + uint32_t key_id_length, const uint8_t* key_data, + uint32_t key_data_length, const uint8_t* key_data_iv, + const uint8_t* key_control, + const uint8_t* key_control_iv) { + ASSERT(session != NULL && key_id != NULL && key_id_length != 0 && + key_data != NULL && key_data_length != 0 && key_data_iv != NULL && + key_control != NULL && key_control_iv != NULL, + "Parameters are NULL or 0"); + uint8_t raw_key[KEY_SIZE_256]; + uint8_t raw_key_control[KEY_CONTROL_SIZE]; + + CryptoKey** current_key_ptr; + uint32_t current_key_index = 0; + CryptoKeyType key_type; + CryptoKeyOperation key_operation; + if (session->license_type == OEMCrypto_ContentLicense) { + if (key_data_length != KEY_SIZE_128 && key_data_length != KEY_SIZE_256) { + /* Generic crypto allows both key sizes. */ + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + current_key_index = session->num_content_keys; + if (current_key_index == CONTENT_KEYS_PER_SESSION) { + return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES; + } + current_key_ptr = &session->content_keys[current_key_index]; + key_type = CONTENT_KEY; + key_operation = CONTENT_KEY_DECRYPT; + } else { + if (key_data_length != KEY_SIZE_256) return OEMCrypto_ERROR_INVALID_CONTEXT; + current_key_index = session->num_entitlement_keys; + if (current_key_index == ENTITLEMENT_KEYS_PER_SESSION) { + return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES; + } + current_key_ptr = &session->entitlement_keys[current_key_index]; + key_type = ENTITLEMENT_KEY; + key_operation = ENTITLEMENT_KEY_DECRYPT; + } + + if (session->encryption_key != NULL) { + session->encryption_key->key_operation = ENCRYPTION_KEY_DECRYPT; + } + if (!CheckKey(session->encryption_key, ENCRYPTION_KEY, + ENCRYPTION_KEY_DECRYPT)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoResult result = AESCBCDecrypt( + session->encryption_key->key_handle, session->encryption_key->key_size, + key_data, key_data_length, key_data_iv, raw_key); + if (result != OEMCrypto_SUCCESS) return result; + + result = CreateKey(current_key_ptr, raw_key, key_data_length, key_type, + key_operation, key_data_length); + if (result != OEMCrypto_SUCCESS) return result; + + CryptoKey* current_key = *current_key_ptr; + memcpy(current_key->key_id, key_id, key_id_length); + current_key->key_id_size = key_id_length; + current_key->session_key_index = current_key_index; + + if (!CheckKey(current_key, key_type, key_operation)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + /* We use the first 16 bytes regardless of the license type to decrypt the key + control. */ + result = AESCBCDecrypt(current_key->key_handle, KEY_SIZE_128, key_control, + KEY_CONTROL_SIZE, key_control_iv, raw_key_control); + if (result != OEMCrypto_SUCCESS) goto cleanup; + + current_key->key_control_block = ParseKeyControlBlock(raw_key_control); + if (!(current_key->key_control_block.valid)) { + result = OEMCrypto_ERROR_INVALID_CONTEXT; + goto cleanup; + } + if ((current_key->key_control_block.control_bits & + CONTROL_REQUIRE_ANTI_ROLLBACK_HARDWARE) && + !IsAntiRollbackHWPresent()) { + result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup; + } + uint8_t minimum_patch_level = (current_key->key_control_block.control_bits & + CONTROL_SECURITY_PATCH_LEVEL_MASK) >> + CONTROL_SECURITY_PATCH_LEVEL_SHIFT; + if (minimum_patch_level > OEMCrypto_Security_Patch_Level()) { + result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup; + } + result = check_nonce_or_entry(session, current_key->key_control_block); + if (result != OEMCrypto_SUCCESS) goto cleanup; + if (current_key->key_control_block.control_bits & + CONTROL_SRM_VERSION_REQUIRED) { + if (!session->valid_srm_version) { + /* Require local display only. */ + current_key->key_control_block.control_bits |= CONTROL_HDCP_VERSION_MASK; + } + } + if (session->license_type == OEMCrypto_ContentLicense) { + current_key->is_entitled_content_key = false; + } else { + /* Entitlement keys will have entitled content keys loaded in later. */ + current_key->has_entitled_content_key = false; + } + +cleanup: + if (result != OEMCrypto_SUCCESS) FreeKey(current_key_ptr); + return result; +} + +OEMCryptoResult UpdateMacKeys(OEMCryptoSession* session, + const uint8_t* enc_mac_keys, + const uint8_t* mac_keys_iv) { + ASSERT(session != NULL && enc_mac_keys != NULL && mac_keys_iv != NULL, + "Parameters are NULL"); + uint8_t raw_mac_keys[2 * MAC_KEY_SIZE]; + if (!CheckKey(session->encryption_key, ENCRYPTION_KEY, + ENCRYPTION_KEY_DECRYPT)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoResult result = AESCBCDecrypt( + session->encryption_key->key_handle, session->encryption_key->key_size, + enc_mac_keys, 2 * MAC_KEY_SIZE, mac_keys_iv, raw_mac_keys); + if (result != OEMCrypto_SUCCESS) return result; + OEMCryptoResult free_mac_key_server_result = + FreeKey(&session->mac_key_server); + OEMCryptoResult free_mac_key_client_result = + FreeKey(&session->mac_key_client); + if (free_mac_key_server_result != OEMCrypto_SUCCESS) { + return free_mac_key_server_result; + } + if (free_mac_key_client_result != OEMCrypto_SUCCESS) { + return free_mac_key_client_result; + } + result = CreateKey(&session->mac_key_server, raw_mac_keys, MAC_KEY_SIZE, + MAC_KEY_SERVER, MAC_KEY_SERVER_VERIFY, MAC_KEY_SIZE); + if (result != OEMCrypto_SUCCESS) return result; + result = CreateKey(&session->mac_key_client, raw_mac_keys + MAC_KEY_SIZE, + MAC_KEY_SIZE, MAC_KEY_CLIENT, MAC_KEY_CLIENT_SIGN, + MAC_KEY_SIZE); + if (result != OEMCrypto_SUCCESS) FreeKey(&session->mac_key_server); + return result; +} + +OEMCryptoResult RefreshKey(OEMCryptoSession* session, const uint8_t* key_id, + uint32_t key_id_length, const uint8_t* key_control, + const uint8_t* key_control_iv) { + ASSERT(session != NULL && key_control != NULL, + "session or key_control is NULL"); + + KeyControlBlock key_control_block; + + if (key_id == NULL) { + key_control_block = ParseKeyControlBlock(key_control); + if (!key_control_block.valid) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if ((key_control_block.control_bits & CONTROL_NONCE_ENABLED) && + !CheckNonce(&session->nonce_table, key_control_block.nonce)) { + return OEMCrypto_ERROR_INVALID_NONCE; + } + UpdateDurationForAllKeys(session, key_control_block); + return OEMCrypto_SUCCESS; + } + + bool is_content_key = session->license_type == OEMCrypto_ContentLicense; + CryptoKey* key = + FindKeyFromTable(session, is_content_key, key_id, key_id_length); + + if (key == NULL) return OEMCrypto_ERROR_NO_CONTENT_KEY; + + uint8_t raw_key_control[KEY_CONTROL_SIZE]; + if (key_control_iv != NULL) { + CryptoKeyType key_type = UNKNOWN_KEY_TYPE; + CryptoKeyOperation key_operation = UNKNOWN_KEY_OPERATION; + if (is_content_key) { + key_type = CONTENT_KEY; + key_operation = CONTENT_KEY_DECRYPT; + } else { + key_type = ENTITLEMENT_KEY; + key_operation = ENTITLEMENT_KEY_DECRYPT; + } + if (!CheckKey(key, key_type, key_operation)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + /* Decrypt using only the first 128 bits of the key. */ + OEMCryptoResult result = + AESCBCDecrypt(key->key_handle, KEY_SIZE_128, key_control, + KEY_CONTROL_SIZE, key_control_iv, raw_key_control); + if (result != OEMCrypto_SUCCESS) return result; + } else { + memcpy(raw_key_control, key_control, KEY_CONTROL_SIZE); + } + + key_control_block = ParseKeyControlBlock(raw_key_control); + + if (!key_control_block.valid) return OEMCrypto_ERROR_INVALID_CONTEXT; + if ((key_control_block.control_bits & CONTROL_NONCE_ENABLED) && + !CheckNonce(&session->nonce_table, key_control_block.nonce)) { + return OEMCrypto_ERROR_INVALID_NONCE; + } + + key->key_control_block.duration = key_control_block.duration; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult CheckCurrentContentKeyUsage(const OEMCryptoSession* session, + uint32_t use_type, + OEMCryptoBufferType buffer_type) { + ASSERT(session != NULL && (buffer_type == OEMCrypto_BufferType_Clear || + buffer_type == OEMCrypto_BufferType_Secure), + "session is NULL or invalid buffer_type"); + if (session->current_content_key_index >= session->num_content_keys) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + CryptoKey* current_content_key = + session->content_keys[session->current_content_key_index]; + if (!CheckKey(current_content_key, CONTENT_KEY, CONTENT_KEY_DECRYPT)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + KeyControlBlock control = current_content_key->key_control_block; + if (current_content_key->is_entitled_content_key) { + if (current_content_key->entitlement_key_index >= + session->num_entitlement_keys) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + CryptoKey* entitlement_key = + session->entitlement_keys[current_content_key->entitlement_key_index]; + if (!CheckKey(entitlement_key, ENTITLEMENT_KEY, ENTITLEMENT_KEY_DECRYPT)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + control = entitlement_key->key_control_block; + } + if (use_type && (!(control.control_bits & use_type))) { + /* Could not use this key for the given use type. */ + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + OEMCryptoResult result; + if (control.control_bits & CONTROL_DATA_PATH_SECURE) { + if (!IsClosedPlatform() && buffer_type == OEMCrypto_BufferType_Clear) { + return OEMCrypto_ERROR_DECRYPT_FAILED; + } + } + switch (session->usage_entry_status) { + case SESSION_HAS_NO_ENTRY: + /* No entry, don't do anything. */ + break; + case SESSION_HAS_DEACTIVATED_ENTRY: + return OEMCrypto_ERROR_KEY_EXPIRED; + case SESSION_HAS_NEW_ENTRY: + case SESSION_HAS_LOADED_ENTRY: + /* TODO: this is not very efficient to call on every decrypt. This will be + * more optimized when we mix with the ODK library. */ + result = UpdateLastPlaybackTime(session); + if (result != OEMCrypto_SUCCESS) return result; + break; + default: + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (control.duration > 0) { + uint64_t time_elapsed = 0; + result = CurrentTimer(session, &time_elapsed); + if (result != OEMCrypto_SUCCESS) return result; + if (control.duration < time_elapsed) { + return OEMCrypto_ERROR_KEY_EXPIRED; + } + } + OEMCrypto_HDCP_Capability capability = CurrentHDCPCapability(); + if (capability != HDCP_NO_DIGITAL_OUTPUT && + (control.control_bits & CONTROL_HDCP_REQUIRED)) { + /* Check to see if HDCP requirements are satisfied. */ + uint8_t required_hdcp = + (control.control_bits & CONTROL_HDCP_VERSION_MASK) >> + CONTROL_HDCP_VERSION_SHIFT; + if (required_hdcp > capability || capability == HDCP_NONE) { + return OEMCrypto_ERROR_INSUFFICIENT_HDCP; + } + } + /* We can't control analog output if the output is clear. Similarly, if + analog is not disabled, we should fail. */ + if (control.control_bits & CONTROL_DISABLE_ANALOG_OUTPUT) { + if (buffer_type == OEMCrypto_BufferType_Clear || + (IsAnalogDisplayActive() && !DisableAnalogDisplay())) { + return OEMCrypto_ERROR_ANALOG_OUTPUT; + } + } + /* If CGMS-A is active, we must turn off analog output. */ + if (control.control_bits & CONTROL_CGMS_MASK) { + if (buffer_type == OEMCrypto_BufferType_Clear) { + /* Similar to the above, we can't control CGMS if output is clear. */ + return OEMCrypto_ERROR_ANALOG_OUTPUT; + } + if (!IsCGMS_AActive() && IsAnalogDisplayActive() && + !DisableAnalogDisplay()) { + /* CGMS must be active if analog output is active. */ + return OEMCrypto_ERROR_ANALOG_OUTPUT; + } + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult DecryptCBC(const OEMCryptoSession* session, + const uint8_t* initial_iv, + const OEMCrypto_CENCEncryptPatternDesc* pattern, + const uint8_t* cipher_data, + uint32_t cipher_data_length, uint8_t* clear_data) { + ASSERT(session != NULL && initial_iv != NULL && pattern != NULL && + cipher_data != NULL && cipher_data_length != 0 && + clear_data != NULL, + "Parameters are NULL or 0"); + if (session->current_content_key_index >= session->num_content_keys) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + CryptoKey* current_content_key = + session->content_keys[session->current_content_key_index]; + if (!CheckKey(current_content_key, CONTENT_KEY, CONTENT_KEY_DECRYPT)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + uint8_t iv[AES_BLOCK_SIZE]; + uint8_t next_iv[AES_BLOCK_SIZE]; + memcpy(iv, &initial_iv[0], AES_BLOCK_SIZE); + + uint32_t l = 0; + uint32_t pattern_offset = pattern->offset; + while (l < cipher_data_length) { + uint32_t size = cipher_data_length - l; + if (size > AES_BLOCK_SIZE) size = AES_BLOCK_SIZE; + uint32_t pattern_length = pattern->encrypt + pattern->skip; + bool skip_block = + (pattern_offset >= pattern->encrypt) && (pattern_length > 0); + if (pattern_length > 0) { + pattern_offset = (pattern_offset + 1) % pattern_length; + } + if (skip_block || (size < AES_BLOCK_SIZE)) { + memmove(&clear_data[l], &cipher_data[l], size); + } else { + uint8_t aes_output[AES_BLOCK_SIZE]; + /* Save the iv for the next block, in case cipher_data is in the same + buffer as clear_data. */ + memcpy(next_iv, &cipher_data[l], AES_BLOCK_SIZE); + OEMCryptoResult result = AESDecrypt(current_content_key->key_handle, + &cipher_data[l], aes_output); + if (result != OEMCrypto_SUCCESS) return result; + for (uint32_t n = 0; n < AES_BLOCK_SIZE; n++) { + clear_data[l + n] = aes_output[n] ^ iv[n]; + } + memcpy(iv, next_iv, AES_BLOCK_SIZE); + } + l += size; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult DecryptCTR(const OEMCryptoSession* session, + const uint8_t* initial_iv, uint32_t block_offset, + const OEMCrypto_CENCEncryptPatternDesc* pattern, + const uint8_t* cipher_data, + uint32_t cipher_data_length, uint8_t* clear_data) { + ASSERT(session != NULL && initial_iv != NULL && pattern != NULL && + cipher_data != NULL && cipher_data_length != 0 && + clear_data != NULL, + "Parameters are NULL or 0"); + if (session->current_content_key_index >= session->num_content_keys) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + CryptoKey* current_content_key = + session->content_keys[session->current_content_key_index]; + if (!CheckKey(current_content_key, CONTENT_KEY, CONTENT_KEY_DECRYPT)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + uint8_t iv[AES_BLOCK_SIZE]; + memcpy(iv, &initial_iv[0], AES_BLOCK_SIZE); + + uint32_t l = 0; + uint32_t pattern_offset = pattern->offset; + while (l < cipher_data_length) { + uint32_t size = cipher_data_length - l; + if (size > AES_BLOCK_SIZE - block_offset) + size = AES_BLOCK_SIZE - block_offset; + uint32_t pattern_length = pattern->encrypt + pattern->skip; + bool skip_block = + (pattern_offset >= pattern->encrypt) && (pattern_length > 0); + if (pattern_length > 0) { + pattern_offset = (pattern_offset + 1) % pattern_length; + } + if (skip_block) { + memmove(&clear_data[l], &cipher_data[l], size); + } else { + uint8_t aes_output[AES_BLOCK_SIZE]; + AESEncrypt(current_content_key->key_handle, iv, aes_output); + for (uint32_t n = 0; n < size; n++) { + clear_data[l + n] = aes_output[n + block_offset] ^ cipher_data[l + n]; + } + /* Increment the lower 8 bytes of the iv only. */ + for (int n = 15; n > 7; n--) { + if (++iv[n] != 0) break; + }; + } + l += size; + block_offset = 0; + } + return OEMCrypto_SUCCESS; +} diff --git a/oemcrypto_ta/oemcrypto_session.h b/oemcrypto_ta/oemcrypto_session.h new file mode 100644 index 0000000..80c00f6 --- /dev/null +++ b/oemcrypto_ta/oemcrypto_session.h @@ -0,0 +1,250 @@ +/* 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. */ + +#ifndef OEMCRYPTO_TA_OEMCRYPTO_SESSION_H_ +#define OEMCRYPTO_TA_OEMCRYPTO_SESSION_H_ + +#include "OEMCryptoCENC.h" +#include "oemcrypto_config_interface.h" +#include "oemcrypto_key.h" +#include "oemcrypto_nonce_table.h" + +/* The different states in which an OEMCrypto session can be in. */ +typedef enum OEMCryptoSessionState { + SESSION_OPENED = (int)0xc159acf3, + SESSION_INVALID = (int)0x23a27071, + SESSION_LOAD_OEM_RSA_KEY = (int)0x9d7cae94, + SESSION_LOAD_DRM_RSA_KEY = (int)0xbc17f592, + SESSION_DERIVED_KEYS = (int)0x6f73d57c, + SESSION_DERIVED_KEYS_FROM_SESSION_KEY = (int)0xb852a5ef, + SESSION_KEYS_LOADED = (int)0xce93bdc3, + SESSION_DECRYPT_KEY_SELECTED = (int)0x9877e0a6, +} OEMCryptoSessionState; + +/* The API being executed for the current session. */ +typedef enum OEMCryptoSessionAPI { + API_OPENSESSION = (int)0x45956770, + API_CLOSESESSION = (int)0xa84dc5a7, + API_GETOEMPUBLICCERTIFICATE = (int)0xe6cf7c3e, + API_GENERATENONCE = (int)0xb9f80df2, + API_GENERATERSASIGNATURE = (int)0x450c7dd0, + API_REWRAPDEVICERSAKEY30 = (int)0x76b99787, + API_LOADDEVICERSAKEY = (int)0xb0143a2e, + API_DERIVEKEYSFROMSESSIONKEY = (int)0xf29462c0, + API_LOADKEYS = (int)0x55c0291c, + API_REFRESHKEYS = (int)0xc3f785fe, + API_GENERATESIGNATURE = (int)0x0c4352f4, + API_LOADENTITLEDCONTENTKEYS = (int)0x498bc417, + API_SELECTKEY = (int)0xef2e58fb, + API_DECRYPTCENC = (int)0xf5ad6301, + API_GENERICENCRYPT = (int)0x3bd1f139, + API_GENERICDECRYPT = (int)0xcfc2970a, + API_GENERICSIGN = (int)0xb721196a, + API_GENERICVERIFY = (int)0xe09fa38b, + API_SETDECRYPTHASH = (int)0x427f7e9b, + API_GETHASHERRORCODE = (int)0xde3477cc, + API_QUERYKEYCONTROL = (int)0x7ab3659c, + API_GENERATEDERIVEDKEYS = (int)0x59b1e187, + API_REWRAPDEVICERSAKEY = (int)0x800fef5d, +} OEMCryptoSessionAPI; + +typedef enum UsageEntryStatus { + SESSION_HAS_NO_ENTRY = (int)0xacbad562, + SESSION_HAS_NEW_ENTRY = (int)0x4545babc, + SESSION_HAS_LOADED_ENTRY = (int)0x766bca12, + SESSION_HAS_DEACTIVATED_ENTRY = (int)0xdacba37, +} UsageEntryStatus; + +typedef struct OEMCryptoSession { + OEMCrypto_SESSION session_id; + OEMCryptoSessionState state; + NonceTable nonce_table; + CryptoKey* drm_private_key; + CryptoKey* mac_key_server; + CryptoKey* mac_key_client; + CryptoKey* encryption_key; + CryptoKey* session_key; + bool refresh_valid; + OEMCrypto_LicenseType license_type; + uint32_t current_content_key_index; + CryptoKey* content_keys[CONTENT_KEYS_PER_SESSION]; + uint32_t num_content_keys; + CryptoKey* entitlement_keys[ENTITLEMENT_KEYS_PER_SESSION]; + uint32_t num_entitlement_keys; + bool valid_srm_version; + uint64_t timer_start; + /* These are used when doing full decrypt path testing. */ + bool compute_hash; /* True if the current frame needs a hash. */ + uint32_t current_hash; /* Running CRC hash of frame. */ + uint32_t given_hash; /* True CRC hash of frame. */ + uint32_t current_frame_number; /* Current frame for CRC hash. */ + uint32_t bad_frame_number; /* Frame number with bad hash. */ + OEMCryptoResult hash_error; /* Error code for first bad frame. */ + UsageEntryStatus usage_entry_status; + uint32_t usage_entry_number; + /* If |recent_decrypt| is true, then a usage report cannot be generated + * without first updating the usage entry. It should be set to true whenever a + * key is used. */ + bool recent_decrypt; +} OEMCryptoSession; + +/* Initializes session context. + Returns OEMCrypto_SUCCESS. + Caller retains ownership of |session| and it must not be NULL. */ +OEMCryptoResult InitializeSession(OEMCryptoSession* session, uint32_t index); + +/* Cleans up a session declaration by freeing any used keys and clearing any + state so the session could be reused in a future OpenSession call. + Returns the result of freeing the keys in the session. + Caller retains ownership of |session| and it must not be NULL. */ +OEMCryptoResult TerminateSession(OEMCryptoSession* session); + +/* Asserts that the session state in |session| is set to the appropriate value + that is needed to execute |api|. + Returns OEMCrypto_ERROR_UNKNOWN_FAILURE on failure, and OEMCrypto_SUCCESS on + success. + Caller retains ownership of |session| and it must not be NULL. */ +OEMCryptoResult CheckStatePreCall(OEMCryptoSession* session, + OEMCryptoSessionAPI api); + +/* Sets the session state in |session| to the appropriate state for having just + executed |api|. + Returns OEMCrypto_ERROR_UNKNOWN_FAILURE on failure, and OEMCrypto_SUCCESS on + success. + Caller retains ownership of |session| and it must not be NULL. */ +OEMCryptoResult SetStatePostCall(OEMCryptoSession* session, + OEMCryptoSessionAPI api); + +/* Initializes the timer_start field in the |session| to the current online + time. + Returns the result of getting the online time. + Caller retains ownership of |session| and it must not be NULL. */ +OEMCryptoResult StartTimer(OEMCryptoSession* session); + +/* Calculates the diff of the timer_start field in |session| and the current + online time and places it in |diff|. + Returns the result of getting the online time or subtracting the times. + Caller retains ownership of all pointers and they must not be NULL. */ +OEMCryptoResult CurrentTimer(const OEMCryptoSession* session, uint64_t* diff); + +/* Attempts to deserialize the DRM RSA key and load it into |session|'s + drm_private_key field. Returns the result of creating the private key. + |rsa_key_length| must be > 0. + Caller retains ownership of all pointers and they must not be NULL. */ +OEMCryptoResult LoadDRMRSAKey(OEMCryptoSession* session, + const uint8_t* pkcs8_rsa_key, + uint32_t rsa_key_length); + +/* Derives mac and encryption keys from the specific key. Uses AES-128-CMAC + and |mac_ and enc_key_contexts| to derive and create a mac_key_server, + mac_key_client, and encryption_key for the |session|. + Returns the result of the derivation if it fails or the result of key + creation. + All lengths must be > 0. + Caller retains ownership of all pointers and they must not be NULL. */ +OEMCryptoResult DeriveMacAndEncryptionKeysFromCryptoKey( + OEMCryptoSession* session, const CryptoKey* master_key, + const uint8_t* mac_key_context, uint32_t mac_key_context_length, + const uint8_t* enc_key_context, uint32_t enc_key_context_length); + +OEMCryptoResult DeriveMacAndEncryptionKeysFromDeviceKey( + OEMCryptoSession* session, const uint8_t* mac_key_context, + uint32_t mac_key_context_length, const uint8_t* enc_key_context, + uint32_t enc_key_context_length); + +OEMCryptoResult DeriveMacAndEncryptionKeysFromKeybox( + OEMCryptoSession* session, const uint8_t* mac_key_context, + uint32_t mac_key_context_length, const uint8_t* enc_key_context, + uint32_t enc_key_context_length); + +/* Verifies |signature| of |message| with the mac_key_server stored in + |session|. Returns OEMCrypto_ERROR_UNKNOWN_FAILURE if the mac_key_server is + invalid, the result of signature calculation if it fails, + OEMCrypto_ERROR_SIGNATURE_FAILURE if the calculated and provided signatures + don't match, and OEMCrypto_SUCCESS otherwise. + |message_length| must be > 0. + Caller retains ownership of all pointers and they must not be NULL. */ +OEMCryptoResult VerifySignatureWithMacKeyServer(OEMCryptoSession* session, + const uint8_t* message, + uint32_t message_length, + const uint8_t* signature); + +/* Installs the key using the given data into the |session| depending on the + license_type. Decrypts the |key_data| using the encryption_key in the session + and then uses the first 128 bits of the decrypted key to decrypt + |key_control|. Returns OEMCrypto_ERROR_INSUFFICIENT_RESOURCES if the session + cannot hold any more keys, OEMCrypto_ERROR_INVALID_CONTEXT if the key control + block is invalid, OEMCrypto_ERROR_INVALID_NONCE if nonce is required and the + provided nonce is not in the session's nonce table, + OEMCrypto_ERROR_UNKNOWN FAILURE for all other failures, and OEMCrypto_SUCCESS + otherwise. + All lengths must be > 0. + Caller retains ownership of all pointers and they must not be NULL. */ +OEMCryptoResult InstallKey(OEMCryptoSession* session, const uint8_t* key_id, + uint32_t key_id_length, const uint8_t* key_data, + uint32_t key_data_length, const uint8_t* key_data_iv, + const uint8_t* key_control, + const uint8_t* key_control_iv); + +/* Updates the mac_key_server and mac_key_client in |session|. Decrypts + |enc_mac_keys| using the encryption_key and splits them into the two mac + keys. Returns OEMCrypto_ERROR_UNKNOWN_FAILURE if the encryption_key is not + valid and the result of creating the mac keys otherwise. + Caller retains ownership of all pointers and they must not be NULL. */ +OEMCryptoResult UpdateMacKeys(OEMCryptoSession* session, + const uint8_t* enc_mac_keys, + const uint8_t* mac_keys_iv); + +/* Given a |session| and either a raw or encrypted |key_control|, refreshes + either the key with the matching |key_id| or all keys of the current license + type. If |key_id| or |key_control_iv| are NULL, the key control is assumed to + be unencrypted. If |key_id| is NULL, all keys of the current license type + will have their durations updated. + Returns OEMCrypto_ERROR_INVALID_CONTEXT if the key control is invalid, + OEMCrypto_ERROR_INVALID_NONCE if there's no matching nonce, + OEMCrypto_ERROR_NO_CONTENT_KEY if there is no key with the same key id, + OEMCrypto_ERROR_UNKNOWN_FAILURE for all other failures, and OEMCrypto_SUCCESS + otheriwse. + Caller retains ownership of all pointers, and |session| and |key_control| + must not be NULL. */ +OEMCryptoResult RefreshKey(OEMCryptoSession* session, const uint8_t* key_id, + uint32_t key_id_length, const uint8_t* key_control, + const uint8_t* key_control_iv); + +/* Checks whether the current content key selected in the |session| can be used + in the operation given by |use_type| and with the given |buffer_type|. + Returns OEMCrypto_ERROR_UNKNOWN_FAILURE if there is no valid current content + key, OEMCrypto_ERROR_INVALID_CONTEXT if if |use_type| is not allowed by the + key control block or if the replay mask is set in the key control block, + OEMCrypto_DECRYPT_FAILED if the |buffer_type| is not allowed on the device, + OEMCrypto_ERROR_KEY_EXPIRED if the duration in the key control block has + passed, OEMCrypto_ERROR_INSUFFICIENT_HDCP if the HDCP requirements are not + met, OEMCrypto_ERROR_ANALOG_OUTPUT if the analog display requirements are not + met, and OEMCrypto_SUCCESS otherwise. + |buffer_type| is disallowed to be OEMCrypto_BufferType_Direct. + Caller retains ownership of |session| and it must not be NULL. */ +OEMCryptoResult CheckCurrentContentKeyUsage(const OEMCryptoSession* session, + uint32_t use_type, + OEMCryptoBufferType buffer_type); + +/* Decrypts the |cipher_data_length| bytes of given |cipher_data| and places it + in |clear_data| using the |session|'s current content key, |initial_iv|, + |pattern|, and potentially a |block_offset|. + Returns OEMCrypto_ERROR_UNKNOWN_FAILURE if the current content key is + invalid, the result of AESDecrypt or AESEncrypt if the fail, and + OEMCrypto_SUCCESS otherwise. + Lengths must not be 0. + Caller retains ownership of all parameters and they must not be NULL. */ +OEMCryptoResult DecryptCBC(const OEMCryptoSession* session, + const uint8_t* initial_iv, + const OEMCrypto_CENCEncryptPatternDesc* pattern, + const uint8_t* cipher_data, + uint32_t cipher_data_length, uint8_t* clear_data); +OEMCryptoResult DecryptCTR(const OEMCryptoSession* session, + const uint8_t* initial_iv, uint32_t block_offset, + const OEMCrypto_CENCEncryptPatternDesc* pattern, + const uint8_t* cipher_data, + uint32_t cipher_data_length, uint8_t* clear_data); + +#endif /* OEMCRYPTO_TA_OEMCRYPTO_SESSION_H_ */ diff --git a/oemcrypto_ta/oemcrypto_session_key_table.c b/oemcrypto_ta/oemcrypto_session_key_table.c new file mode 100644 index 0000000..cf282e4 --- /dev/null +++ b/oemcrypto_ta/oemcrypto_session_key_table.c @@ -0,0 +1,59 @@ +/* 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_session_key_table.h" + +#include "string.h" + +#include "assert_interface.h" + +static CryptoKey** get_key_table(OEMCryptoSession* session, + OEMCrypto_LicenseType license_type, + uint32_t* num_keys) { + ASSERT(session != NULL && num_keys != NULL, "Parameters are NULL"); + ASSERT(license_type == OEMCrypto_ContentLicense || + license_type == OEMCrypto_EntitlementLicense, + "session has invalid license type"); + if (license_type == OEMCrypto_ContentLicense) { + *num_keys = session->num_content_keys; + return session->content_keys; + } else { + *num_keys = session->num_entitlement_keys; + return session->entitlement_keys; + } +} + +CryptoKey* FindKeyFromTable(OEMCryptoSession* session, bool is_content_key, + const uint8_t* key_id, uint32_t key_id_length) { + ASSERT(session != NULL && key_id != NULL && key_id_length != 0, + "Parameters are NULL or 0"); + uint32_t num_keys; + ASSERT( + session->license_type == OEMCrypto_EntitlementLicense || is_content_key, + "Cannot get entitlement key for content license"); + OEMCrypto_LicenseType license_type = + is_content_key ? OEMCrypto_ContentLicense : OEMCrypto_EntitlementLicense; + CryptoKey** key_table = get_key_table(session, license_type, &num_keys); + for (uint32_t i = 0; i < num_keys; i++) { + CryptoKey* key = key_table[i]; + ASSERT(key != NULL, "key at index %d is NULL", i); + if (key_id_length == key->key_id_size && + memcmp(key->key_id, key_id, key_id_length) == 0) { + return key; + } + } + return NULL; +} + +void UpdateDurationForAllKeys(OEMCryptoSession* session, + KeyControlBlock key_control_block) { + ASSERT(session != NULL, "session is NULL"); + uint32_t num_keys; + CryptoKey** key_table = + get_key_table(session, session->license_type, &num_keys); + for (uint32_t i = 0; i < num_keys; i++) { + ASSERT(key_table[i] != NULL, "key at index %d is NULL", i); + key_table[i]->key_control_block.duration = key_control_block.duration; + } +} diff --git a/oemcrypto_ta/oemcrypto_session_key_table.h b/oemcrypto_ta/oemcrypto_session_key_table.h new file mode 100644 index 0000000..d7c08d1 --- /dev/null +++ b/oemcrypto_ta/oemcrypto_session_key_table.h @@ -0,0 +1,26 @@ +/* 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. */ + +#ifndef OEMCRYPTO_TA_OEMCRYPTO_SESSION_KEY_TABLE_H_ +#define OEMCRYPTO_TA_OEMCRYPTO_SESSION_KEY_TABLE_H_ + +#include "oemcrypto_key.h" +#include "oemcrypto_session.h" + +/* Finds the key from the key table corresponding to the given |is_content_key| + with the given |key_id| and |key_id_length|. + Returns either the key if there is a match or NULL otherwise. + |key_id_length| must be > 0 and |is_content_key| can only be false if the + session has an OEMCrypto_EntitlementLicense. + Caller retains ownership of all parameters and they must not be NULL. */ +CryptoKey* FindKeyFromTable(OEMCryptoSession* session, bool is_content_key, + const uint8_t* key_id, uint32_t key_id_length); + +/* For the given |session|'s license_type, updates the associated keys to the + duration in the |key_control_block|. + Caller retains ownership of all pointers and they must not be NULL. */ +void UpdateDurationForAllKeys(OEMCryptoSession* session, + KeyControlBlock key_control_block); + +#endif /* OEMCRYPTO_TA_OEMCRYPTO_SESSION_KEY_TABLE_H_ */ diff --git a/oemcrypto_ta/oemcrypto_session_table.c b/oemcrypto_ta/oemcrypto_session_table.c new file mode 100644 index 0000000..57d85e9 --- /dev/null +++ b/oemcrypto_ta/oemcrypto_session_table.c @@ -0,0 +1,106 @@ +/* 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_session_table.h" + +#include "stdint.h" +#include "string.h" + +#include "assert_interface.h" +#include "logging_interface.h" +#include "oemcrypto_key.h" + +static SessionTable session_table; +static uint32_t open_session_count = 0; +static bool session_table_initialized = false; + +OEMCryptoResult InitializeSessionTable(void) { + ASSERT(MAX_NUMBER_OF_SESSIONS > 0, "MAX_NUMBER_OF_SESSIONS must be > 0"); + ASSERT(MAX_NUMBER_OF_SESSIONS <= UINT32_MAX - 1, + "MAX_NUMBER_OF_SESSIONS is too large"); + if (session_table_initialized) { + return OEMCrypto_ERROR_INIT_FAILED; + } + session_table.first_free_session = 0; + for (uint32_t i = 0; i < MAX_NUMBER_OF_SESSIONS; i++) { + session_table.next_free_session[i] = i + 1; + session_table.is_free[i] = true; + memset(&session_table.sessions[i], 0, sizeof(OEMCryptoSession)); + } + session_table_initialized = true; + open_session_count = 0; + return OEMCrypto_SUCCESS; +} + +uint32_t MaxNumberOfSessions(void) { return MAX_NUMBER_OF_SESSIONS; } + +OEMCryptoResult NumberOfOpenSessions(uint32_t* num_open_sessions) { + ASSERT(num_open_sessions != NULL, "num_open_sessions is NULL"); + if (!session_table_initialized) { + return OEMCrypto_ERROR_SYSTEM_INVALIDATED; + } + *num_open_sessions = open_session_count; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult GrabSession(uint32_t* index) { + ASSERT(index != NULL, "index is NULL"); + if (!session_table_initialized) { + return OEMCrypto_ERROR_SYSTEM_INVALIDATED; + } + if (session_table.first_free_session == MAX_NUMBER_OF_SESSIONS) { + return OEMCrypto_ERROR_TOO_MANY_SESSIONS; + } + *index = session_table.first_free_session; + session_table.first_free_session = session_table.next_free_session[*index]; + session_table.is_free[*index] = false; + open_session_count++; + return InitializeSession(&session_table.sessions[*index], *index); +} + +OEMCryptoResult GetSession(uint32_t index, OEMCryptoSession** session) { + ASSERT(session != NULL, "session is NULL"); + if (!session_table_initialized) { + return OEMCrypto_ERROR_SYSTEM_INVALIDATED; + } + if (index >= MAX_NUMBER_OF_SESSIONS || session_table.is_free[index]) { + return OEMCrypto_ERROR_INVALID_SESSION; + } + *session = &session_table.sessions[index]; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult FreeSession(uint32_t index) { + if (!session_table_initialized) { + return OEMCrypto_ERROR_SYSTEM_INVALIDATED; + } + if (index >= MAX_NUMBER_OF_SESSIONS || session_table.is_free[index]) { + return OEMCrypto_ERROR_INVALID_SESSION; + } + session_table.next_free_session[index] = session_table.first_free_session; + session_table.is_free[index] = true; + session_table.first_free_session = index; + open_session_count--; + return TerminateSession(&session_table.sessions[index]); +} + +OEMCryptoResult TerminateSessionTable(void) { + if (!session_table_initialized) { + return OEMCrypto_ERROR_TERMINATE_FAILED; + } + OEMCryptoResult result = OEMCrypto_SUCCESS; + for (int i = 0; i < MAX_NUMBER_OF_SESSIONS; i++) { + if (!session_table.is_free[i]) { + result = OEMCrypto_ERROR_TERMINATE_FAILED; + /* Attempt to free the session. */ + OEMCryptoResult free_result = FreeSession(i); + if (free_result != OEMCrypto_SUCCESS) { + LOGE("Could not free session %d with error: %d", i, free_result); + } + } + } + session_table_initialized = false; + open_session_count = 0; + return result; +} diff --git a/oemcrypto_ta/oemcrypto_session_table.h b/oemcrypto_ta/oemcrypto_session_table.h new file mode 100644 index 0000000..77584cf --- /dev/null +++ b/oemcrypto_ta/oemcrypto_session_table.h @@ -0,0 +1,59 @@ +/* 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. */ + +#ifndef OEMCRYPTO_TA_OEMCRYPTO_SESSION_TABLE_H_ +#define OEMCRYPTO_TA_OEMCRYPTO_SESSION_TABLE_H_ + +#include "OEMCryptoCENC.h" +#include "oemcrypto_config_interface.h" +#include "oemcrypto_session.h" + +typedef struct SessionTable { + OEMCryptoSession sessions[MAX_NUMBER_OF_SESSIONS]; + uint32_t first_free_session; + uint32_t next_free_session[MAX_NUMBER_OF_SESSIONS]; + bool is_free[MAX_NUMBER_OF_SESSIONS]; +} SessionTable; + +/* Initializes the session table for future OpenSession calls. Returns + OEMCrypto_ERROR_INIT_FAILED if the session table has already been initialized + and OEMCrypto_SUCCESS otherwise. */ +OEMCryptoResult InitializeSessionTable(void); + +/* Gets the max number of sessions. */ +uint32_t MaxNumberOfSessions(void); + +/* Gets the number of open sessions. Returns OEMCrypto_ERROR_SYSTEM_INVALIDATED + if the session table has not been initialized and OEMCrypto_SUCCESS + otherwise. + Caller retains ownership of |num_open_sessions| and it must not be NULL. */ +OEMCryptoResult NumberOfOpenSessions(uint32_t* num_open_sessions); + +/* Attempts to grab an open entry in the session table and set |index| to the + entry position. Returns OEMCrypto_ERROR_SYSTEM_INVALIDATED if the session + table has not been initialized and OEMCrypto_ERROR_TOO_MANY_SESSIONS if there + are no sessions left to grab. Returns OEMCrypto_SUCCESS otherwise. + Caller retains ownership of |index| and it must not be NULL. */ +OEMCryptoResult GrabSession(uint32_t* index); + +/* Sets session to the session at |index| in the session table if it is free. + Returns OEMCrypto_ERROR_SYSTEM_INVALIDATED if the session table has not been + initialized and OEMCrypto_ERROR_INVALID_SESSION if the session has not been + grabbed or if the index is invalid. Returns OEMCrypto_SUCCESS otherwise. + Caller retains ownership of |session| and it must not be NULL. */ +OEMCryptoResult GetSession(uint32_t index, OEMCryptoSession** session); + +/* Given a non-free session |index|, attempts to free it so it can be reused. + Returns OEMCrypto_ERROR_SYSTEM_INVALIDATED if the session table has not been + initialized and OEMCrypto_ERROR_INVALID_SESSION if the session has not been + grabbed or if the index is invalid. Returns OEMCrypto_SUCCESS otherwise. */ +OEMCryptoResult FreeSession(uint32_t index); + +/* Clears and cleans up the session table. The session table must be + reinitialized to be used. Returns OEMCrypto_ERROR_TERMINATE_FAILED if the + table has not been initialized or if there are any active sessions still. + Returns OEMCrypto_SUCCESS otherwise. */ +OEMCryptoResult TerminateSessionTable(void); + +#endif /* OEMCRYPTO_TA_OEMCRYPTO_SESSION_TABLE_H_ */ diff --git a/oemcrypto_ta/oemcrypto_usage_table.c b/oemcrypto_ta/oemcrypto_usage_table.c new file mode 100644 index 0000000..4472bf9 --- /dev/null +++ b/oemcrypto_ta/oemcrypto_usage_table.c @@ -0,0 +1,976 @@ +/* Copyright 2020 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_usage_table.h" + +#include "stddef.h" +#include "string.h" + +#include "OEMCryptoCENC.h" +#include "assert_interface.h" +#include "clock_interface.h" +#include "crypto_interface.h" +#include "logging_interface.h" +#include "oemcrypto_serialized_usage_table.h" +#include "oemcrypto_session.h" + +/* Porting layer includes: */ +#include "assert_interface.h" +#include "generation_number_interface.h" + +/** + The usage table consists of a short array of active entries, and a large + array of possible entries. The usage table header is stored in the large + array. The large array stores the generation number for each entry and an + index into the short array if the entry is active. The short array holds + entries that have been loaded and are connected to a session. +*/ + +/* Global usage table states. Used to tell if we need to load the usage table or + * not. */ +typedef enum UsageTableState { + /* Initial state. */ + USAGE_TABLE_NOT_INITIALIZED = (int)0xC887d04, + /* Error state. Actually, anything but the other states are considered + * errors, but we can explicitly set the state to this value. */ + USAGE_TABLE_ERROR_STATE = (int)0xd06ca1, + /* After the usage table has been initialized to an empty table. The usage + * table cannot be used in this state because the generation number is not yet + * valid. */ + USAGE_TABLE_INITIALIZED_BUT_NOT_LOADED_STATE = (int)0x1776dcfa, + /* After the usage table has been loaded or created with + * OEMCrypto_LoadUsageTableHeader or OEMCrypto_CreateUsageTableHeader. The key + * distinction between this state and the previous one is that the generation + * number is valid in this state. The usage table might be empty in this + * state, but it is ready to have new entries created. */ + USAGE_TABLE_ACTIVE_STATE = (int)0x7331face, +} UsageTableState; + +/* Indicates if a usage entry is active or not. */ +typedef enum UsageEntryState { + USAGE_ENTRY_ACTIVE = (int)0x42fab1c, + USAGE_ENTRY_NOT_ACTIVE = (int)0x39abcab4, +} UsageEntryState; + +/* Data storage for a usage entry in memory. It has the data for a usage entry + * that is saved to the filesystem, and also all of the transient state, such as + * the current session it's tied to and the current status. */ +typedef struct ResidentUsageEntry { + /* The part of the usage entry that is saved to the file system. */ + SavedUsageEntry data; + OEMCrypto_SESSION session_id; /* Which session this entry is actively in. */ + UsageEntryState state; /* Whether this entry is active or not. */ + bool forbid_report; + bool recent_decrypt; + int next_free_active_entry; /* A linked list of unused active entries. */ +} ResidentUsageEntry; + +/* A data structure holding the current, active usage table -- that means it has + * a header and all of the resident entries. */ +typedef struct ActiveUsageTable { + /* The master generation number. */ + uint64_t master_generation_number; + /* This number of active usage entries. */ + uint32_t active_table_size; + /* The head of the free list for active entries. */ + uint32_t first_free_active_entry; + /* Storage for the active entries. */ + ResidentUsageEntry entries[MAX_NUMBER_OF_ACTIVE_USAGE_ENTRIES]; + uint32_t table_size; /* Number of entries in the table. */ + /* These are the generation numbers of each entry. */ + uint64_t generation_numbers[MAX_NUMBER_OF_USAGE_ENTRIES]; + /* Map from usage header index into array of active entries. This is updated + * when an entry is loaded or created and then again when it is released. */ + struct { + UsageEntryState state; + uint32_t active_entry_index; + } active_entry_map[MAX_NUMBER_OF_USAGE_ENTRIES]; +} ActiveUsageTable; + +/* A file local variable indicating whether the usage table has been initialized + * or not. */ +static UsageTableState g_usage_table_state = USAGE_TABLE_NOT_INITIALIZED; +/* The file local variable holding the current active usage table. This is only + * valid if |g_usage_table_state| is USAGE_TABLE_ACTIVE. */ +static ActiveUsageTable g_usage_table; + +/* TODO(b/158771223): figure out a way to avoid __attribute__(packed). */ +typedef struct { + uint8_t signature[20]; // -- HMAC SHA1 of the rest of the report. + uint8_t status; // current status of entry. (OEMCrypto_Usage_Entry_Status) + uint8_t clock_security_level; + uint8_t pst_length; + uint8_t padding; // make int64's word aligned. + int64_t seconds_since_license_received; // now - time_of_license_received + int64_t seconds_since_first_decrypt; // now - time_of_first_decrypt + int64_t seconds_since_last_decrypt; // now - time_of_last_decrypt + uint8_t pst[]; +} __attribute__((packed)) OEMCrypto_PST_Report; + +/* TODO(b/158131747): add htonll64 to common hton functions. */ +int64_t htonll64(int64_t x) { + uint8_t* bytes = (uint8_t*)(&x); + uint64_t y = 0; + for (int i = 0; i < 8; i++) { + y = (y << 8) | bytes[i]; + } + return (int64_t)y; +} + +static void ClearTable(void) { + g_usage_table.active_table_size = 0; + g_usage_table.first_free_active_entry = 0; + for (int i = 0; i < MAX_NUMBER_OF_ACTIVE_USAGE_ENTRIES; i++) { + memset(&g_usage_table.entries[i].data, 0, sizeof(SavedUsageEntry)); + g_usage_table.entries[i].session_id = MAX_NUMBER_OF_SESSIONS; + g_usage_table.entries[i].state = USAGE_ENTRY_NOT_ACTIVE; + g_usage_table.entries[i].forbid_report = true; + g_usage_table.entries[i].recent_decrypt = false; + g_usage_table.entries[i].next_free_active_entry = i + 1; + } + g_usage_table.table_size = 0; + memset(&g_usage_table.generation_numbers, 0, + sizeof(g_usage_table.generation_numbers)); + for (int i = 0; i < MAX_NUMBER_OF_USAGE_ENTRIES; i++) { + g_usage_table.active_entry_map[i].state = USAGE_ENTRY_NOT_ACTIVE; + g_usage_table.active_entry_map[i].active_entry_index = + MAX_NUMBER_OF_ACTIVE_USAGE_ENTRIES; + } +} + +/* This serializes, encrypts, and signs the current header into the given + * buffer. It is an error if the buffer is not big enough. The header fields + * and the master generation number in the current header will be updated. */ +static OEMCryptoResult EncryptAndSignHeader(uint8_t* header_buffer, + size_t header_buffer_length) { + if (!header_buffer) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (header_buffer_length < SignedHeaderSize(g_usage_table.table_size)) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + SavedUsageHeader header = { + .file_type = USAGE_TABLE_HEADER, + .format_version = CURRENT_FILE_FORMAT_VERSION, + .master_generation_number = g_usage_table.master_generation_number, + .table_size = g_usage_table.table_size, + }; + memcpy(header.generation_numbers, g_usage_table.generation_numbers, + header.table_size * sizeof(uint64_t)); + SignedSavedUsageHeader signed_header = { + .file_type = SIGNED_USAGE_TABLE_HEADER, + .format_version = CURRENT_FILE_FORMAT_VERSION, + .buffer_size = PADDED_HEADER_BUFFER_SIZE, + .buffer = {0}, + }; + uint8_t temp_buffer[PADDED_HEADER_BUFFER_SIZE]; + OEMCryptoResult result = + PackUsageHeader(temp_buffer, PADDED_HEADER_BUFFER_SIZE, &header); + if (result != OEMCrypto_SUCCESS) return result; + /* TODO(b/158766099): encrypt header. */ + memcpy(signed_header.buffer, temp_buffer, PADDED_HEADER_BUFFER_SIZE); + /* TODO(b/158766099): sign header. */ + memset(signed_header.signature, 0x42, SHA256_DIGEST_LENGTH); + result = PackSignedUsageHeader(header_buffer, header_buffer_length, + &signed_header); + return result; +} + +/* This decrypts and deserializes usage table header from the given buffer. The + * signature of the buffer is verified. The generation number is verified by the + * calling function. It is an error if the buffer is not big enough. */ +static OEMCryptoResult DecryptAndVerifyHeader(const uint8_t* header_buffer, + size_t header_buffer_length, + SavedUsageHeader* header) { + if (!header_buffer || !header) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + /* TODO(b/158720996): We can't really check the buffer size because we do not + * yet know the table size. This should be done in the Unpack* functions. */ + if (header_buffer_length < SignedHeaderSize(0)) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + SignedSavedUsageHeader signed_header; + OEMCryptoResult result = UnpackSignedUsageHeader( + header_buffer, header_buffer_length, &signed_header); + if (result != OEMCrypto_SUCCESS) return result; + if (signed_header.file_type != SIGNED_USAGE_TABLE_HEADER) { + /* We were given the wrong file. */ + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (signed_header.format_version != CURRENT_FILE_FORMAT_VERSION) { + /* In the future, we might handle backwards compatible versions. */ + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (signed_header.buffer_size != PADDED_HEADER_BUFFER_SIZE) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + /* TODO(b/158766099): verify signature. */ + /* TODO(b/158766099): decrypt header. */ + uint8_t temp_buffer[PADDED_HEADER_BUFFER_SIZE]; + memcpy(&temp_buffer, signed_header.buffer, sizeof(SavedUsageHeader)); + result = UnpackUsageHeader(temp_buffer, PADDED_HEADER_BUFFER_SIZE, header); + if (result != OEMCrypto_SUCCESS) return result; + if (header->file_type != USAGE_TABLE_HEADER) { + /* We were given the wrong file. */ + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (header->format_version != CURRENT_FILE_FORMAT_VERSION) { + /* In the future, we might handle backwards compatible versions. */ + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +/* This serializes, encrypts, and signs the specified entry into the given + * buffer. It is an error if the buffer is not big enough. The header fields in + * the entry will be updated, but the generation number will not. */ +static OEMCryptoResult EncryptAndSignEntry(SavedUsageEntry* entry, + uint8_t* entry_buffer, + size_t entry_buffer_length) { + if (!entry_buffer || !entry) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (entry_buffer_length < SignedEntrySize()) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + entry->file_type = USAGE_TABLE_ENTRY; + entry->format_version = CURRENT_FILE_FORMAT_VERSION; + + SignedSavedUsageEntry signed_entry; + signed_entry.file_type = SIGNED_USAGE_TABLE_ENTRY; + signed_entry.format_version = CURRENT_FILE_FORMAT_VERSION; + signed_entry.buffer_size = PADDED_ENTRY_BUFFER_SIZE; + memset(signed_entry.buffer, 0, sizeof(signed_entry.buffer)); + uint8_t temp_buffer[PADDED_ENTRY_BUFFER_SIZE]; + OEMCryptoResult result = + PackUsageEntry(temp_buffer, PADDED_ENTRY_BUFFER_SIZE, entry); + if (result != OEMCrypto_SUCCESS) return result; + /* TODO: encrypt entry with device specific key. */ + memcpy(signed_entry.buffer, temp_buffer, PADDED_ENTRY_BUFFER_SIZE); + /* TODO: sign entry with device specific key. */ + memset(signed_entry.signature, 0x42, SHA256_DIGEST_LENGTH); + result = + PackSignedUsageEntry(entry_buffer, entry_buffer_length, &signed_entry); + return result; +} + +/* This decrypts and deserializes a usage table entry from the given buffer. The + * signature of the buffer is verified. The generation number is verified by the + * calling function. If the buffer is not big enough the error + * OEMCrypto_ERROR_SHORT_BUFFER is returned. */ +static OEMCryptoResult DecryptAndVerifyEntry(const uint8_t* entry_buffer, + size_t entry_buffer_length, + SavedUsageEntry* entry) { + if (!entry_buffer || !entry) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (entry_buffer_length < SignedEntrySize()) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + SignedSavedUsageEntry signed_entry; + OEMCryptoResult result = + UnpackSignedUsageEntry(entry_buffer, entry_buffer_length, &signed_entry); + if (result != OEMCrypto_SUCCESS) return result; + if (signed_entry.file_type != SIGNED_USAGE_TABLE_ENTRY) { + /* We were given the wrong file. */ + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (signed_entry.format_version != CURRENT_FILE_FORMAT_VERSION) { + /* In the future, we might handle backwards compatible versions. */ + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (signed_entry.buffer_size != PADDED_ENTRY_BUFFER_SIZE) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + /* TODO: verify signature with device specific key. */ + /* TODO: decrypt entry with device specific key. */ + uint8_t temp_buffer[PADDED_ENTRY_BUFFER_SIZE]; + memcpy(&temp_buffer, signed_entry.buffer, signed_entry.buffer_size); + result = UnpackUsageEntry(temp_buffer, signed_entry.buffer_size, entry); + if (result != OEMCrypto_SUCCESS) return result; + if (entry->file_type != USAGE_TABLE_ENTRY) { + /* We were given the wrong file. */ + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (entry->format_version != CURRENT_FILE_FORMAT_VERSION) { + /* In the future, we might handle backwards compatible versions. */ + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +static OEMCryptoResult RollGenerationNumber(ResidentUsageEntry* entry) { + if (!entry || entry->data.index >= MAX_NUMBER_OF_USAGE_ENTRIES) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + uint64_t new_generation_number = g_usage_table.master_generation_number + 1; + if (!TEE_SaveGenerationNumber(new_generation_number)) { + g_usage_table_state = USAGE_TABLE_ERROR_STATE; + return OEMCrypto_ERROR_SYSTEM_INVALIDATED; + } + g_usage_table.master_generation_number = new_generation_number; + entry->data.generation_number++; + g_usage_table.generation_numbers[entry->data.index] = + entry->data.generation_number; + return OEMCrypto_SUCCESS; +} + +// Clear out memory for the usage table. +OEMCryptoResult InitializeUsageTable(void) { + if (!TEE_PrepareGenerationNumber()) { + LOGE("Could not load generation number."); + return OEMCrypto_ERROR_INIT_FAILED; + } + ClearTable(); + g_usage_table_state = USAGE_TABLE_INITIALIZED_BUT_NOT_LOADED_STATE; + return OEMCrypto_SUCCESS; +} + +// Erase data from usage table. +OEMCryptoResult TerminateUsageTable(void) { + g_usage_table_state = USAGE_TABLE_NOT_INITIALIZED; + return OEMCrypto_SUCCESS; +} + +/* Create a new usage table. */ +OEMCryptoResult CreateUsageTableHeader(uint8_t* header_buffer, + size_t* header_buffer_length) { + if (!header_buffer_length) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + size_t size = SignedHeaderSize(0); + if (*header_buffer_length < size) { + *header_buffer_length = size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + /* Clear the table before we check the state -- we want to have an empty table + * after this function whether there was an error or not. */ + ClearTable(); + *header_buffer_length = size; + if (g_usage_table_state == USAGE_TABLE_ERROR_STATE) { + /* Something went wrong. The system should give up and re-init. */ + return OEMCrypto_ERROR_SYSTEM_INVALIDATED; + } else if (g_usage_table_state == USAGE_TABLE_ACTIVE_STATE) { + /* Creating a new header when one was already active. This is OK but + * rare. The system would do this to delete all the entries -- maybe on + * reprovisioning, but there are other reasons. Howver, we want to keep the + * same generation number. So we don't try to load it. */ + } else if (g_usage_table_state == + USAGE_TABLE_INITIALIZED_BUT_NOT_LOADED_STATE) { + /* We are creating a brand new table. Try to load the generation number. */ + if (!TEE_LoadGenerationNumber(&g_usage_table.master_generation_number)) { + g_usage_table_state = USAGE_TABLE_ERROR_STATE; + return OEMCrypto_ERROR_SYSTEM_INVALIDATED; + } + } else { + /* Only other valid state is not initialized, which is not valid for this + * function. */ + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + g_usage_table_state = USAGE_TABLE_ACTIVE_STATE; + return EncryptAndSignHeader(header_buffer, *header_buffer_length); +} + +/* Load a usage table header. */ +OEMCryptoResult LoadUsageTableHeader(const uint8_t* buffer, + size_t buffer_length) { + /* Clear the table before we check the state -- we want to have an empty table + * before we load a new one, or we want an empty one if there is an error. */ + ClearTable(); + if (g_usage_table_state == USAGE_TABLE_ERROR_STATE) { + /* Something went wrong. The system should give up and re-init. */ + return OEMCrypto_ERROR_SYSTEM_INVALIDATED; + } else if (g_usage_table_state == USAGE_TABLE_ACTIVE_STATE) { + /* Loading a header when one was already active is an indication that the + * system was going to terminate, but changed its mind - e.g. because + * delayed termination was canceled. We keep the existing generation + * numbers. */ + } else if (g_usage_table_state == + USAGE_TABLE_INITIALIZED_BUT_NOT_LOADED_STATE) { + /* We are loading a brand new table. Try to load the generation number. */ + if (!TEE_LoadGenerationNumber(&g_usage_table.master_generation_number)) { + g_usage_table_state = USAGE_TABLE_ERROR_STATE; + return OEMCrypto_ERROR_SYSTEM_INVALIDATED; + } + } else { + /* Only other valid state is not initialized, which is not valid for this + * function. */ + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + SavedUsageHeader header; + OEMCryptoResult result = + DecryptAndVerifyHeader(buffer, buffer_length, &header); + if (result != OEMCrypto_SUCCESS) return result; + if (g_usage_table.master_generation_number + 1 == + header.master_generation_number || + g_usage_table.master_generation_number - 1 == + header.master_generation_number) { + /* Skew of 1 is a warning, but we continue on. */ + result = OEMCrypto_WARNING_GENERATION_SKEW; + } else if (g_usage_table.master_generation_number != + header.master_generation_number) { + /* Skew of more than 1 is an error. Clean the table and return an error. */ + ClearTable(); + /* Leave the state as active, so that the generation number is kept. It is + * not a security risk to leave an empty usage header in memory. */ + g_usage_table_state = USAGE_TABLE_ACTIVE_STATE; + return OEMCrypto_ERROR_GENERATION_SKEW; + } + g_usage_table.table_size = header.table_size; + memset(g_usage_table.generation_numbers, 0, + sizeof(g_usage_table.generation_numbers)); + memcpy(g_usage_table.generation_numbers, header.generation_numbers, + header.table_size * sizeof(uint64_t)); + g_usage_table_state = USAGE_TABLE_ACTIVE_STATE; + return result; +} + +/* Grabs a free active usage entry off of the free list of active entries. It + * updates the free list, the active_entry_map, and the session for a new + * entry. It does NOT update the entry's generation number and does NOT update + * the usage header. It does sanity checks. */ +static OEMCryptoResult GrabEntry(OEMCryptoSession* session, + uint32_t usage_entry_number, + ResidentUsageEntry** entry_ptr) { + if (!session || !entry_ptr || + usage_entry_number >= MAX_NUMBER_OF_USAGE_ENTRIES) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (g_usage_table_state != USAGE_TABLE_ACTIVE_STATE) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + /* Check that the session doesn't have entry already. */ + if (session->usage_entry_status != SESSION_HAS_NO_ENTRY) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + /* TODO(b/154764983): return OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES; */ + } + /* Check that another session is not already using this entry. */ + if (g_usage_table.active_entry_map[usage_entry_number].state != + USAGE_ENTRY_NOT_ACTIVE) { + return OEMCrypto_ERROR_INVALID_SESSION; + } + /* Check that we have some room for a new active entry. */ + if (g_usage_table.active_table_size >= MAX_NUMBER_OF_ACTIVE_USAGE_ENTRIES || + g_usage_table.first_free_active_entry >= + MAX_NUMBER_OF_ACTIVE_USAGE_ENTRIES) { + return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES; + } + /* Reserve a new entry. */ + ResidentUsageEntry* entry = + &g_usage_table.entries[g_usage_table.first_free_active_entry]; + /* Make sure the new entry is not already active. */ + if (entry->state != USAGE_ENTRY_NOT_ACTIVE || + g_usage_table.active_entry_map[usage_entry_number].state != + USAGE_ENTRY_NOT_ACTIVE) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + /* Initialize the entry. */ + memset(&entry->data, 0, sizeof(SavedUsageEntry)); + entry->session_id = session->session_id; + entry->state = USAGE_ENTRY_ACTIVE; + /* Update the active entry map. */ + g_usage_table.active_entry_map[usage_entry_number].state = USAGE_ENTRY_ACTIVE; + g_usage_table.active_entry_map[usage_entry_number].active_entry_index = + g_usage_table.first_free_active_entry; + /* Update the linked list of empty active usage entries. */ + g_usage_table.first_free_active_entry = entry->next_free_active_entry; + /* Update the session. */ + session->usage_entry_status = SESSION_HAS_NEW_ENTRY; + session->usage_entry_number = usage_entry_number; + *entry_ptr = entry; + return OEMCrypto_SUCCESS; +} + +/** Release an active entry and put it back onto the free list. This does not + * save any data. It is usually done with the session is closing or when loading + * an entry generated an error. */ +OEMCryptoResult ReleaseEntry(OEMCryptoSession* session, + uint32_t usage_entry_number) { + if (!session || usage_entry_number >= MAX_NUMBER_OF_USAGE_ENTRIES || + g_usage_table_state != USAGE_TABLE_ACTIVE_STATE || + session->usage_entry_number != usage_entry_number || + session->usage_entry_status == SESSION_HAS_NO_ENTRY) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + uint32_t active_entry_index = + g_usage_table.active_entry_map[usage_entry_number].active_entry_index; + if (active_entry_index >= MAX_NUMBER_OF_ACTIVE_USAGE_ENTRIES) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + /* Remove from session. */ + session->usage_entry_status = SESSION_HAS_NO_ENTRY; + session->usage_entry_number = MAX_NUMBER_OF_USAGE_ENTRIES; + /* Remove from active entry map. */ + g_usage_table.active_entry_map[usage_entry_number].state = + USAGE_ENTRY_NOT_ACTIVE; + g_usage_table.active_entry_map[usage_entry_number].active_entry_index = + MAX_NUMBER_OF_ACTIVE_USAGE_ENTRIES; + /* Clear the entry. */ + memset(&g_usage_table.entries[active_entry_index].session_id, 0, + sizeof(SavedUsageEntry)); + g_usage_table.entries[active_entry_index].session_id = MAX_NUMBER_OF_SESSIONS; + g_usage_table.entries[active_entry_index].state = USAGE_ENTRY_NOT_ACTIVE; + /* Add back to list of free active entries. */ + g_usage_table.entries[active_entry_index].next_free_active_entry = + g_usage_table.first_free_active_entry; + g_usage_table.first_free_active_entry = active_entry_index; + return OEMCrypto_SUCCESS; +} + +/* Find the active entry with the specified index into the usage table + * header. Return null if the entry number is bad or not active. */ +ResidentUsageEntry* GetActiveEntry(uint32_t usage_entry_number) { + if (usage_entry_number > MAX_NUMBER_OF_USAGE_ENTRIES) { + return NULL; + } + if (g_usage_table.active_entry_map[usage_entry_number].state != + USAGE_ENTRY_ACTIVE || + g_usage_table.active_entry_map[usage_entry_number].active_entry_index >= + MAX_NUMBER_OF_ACTIVE_USAGE_ENTRIES) { + return NULL; + } + uint32_t index = + g_usage_table.active_entry_map[usage_entry_number].active_entry_index; + ResidentUsageEntry* entry = &g_usage_table.entries[index]; + if (entry->state != USAGE_ENTRY_ACTIVE || + entry->data.index != usage_entry_number) { + return NULL; + } + return entry; +} + +/* Create a new usage entry and tie it to |session|. The new entry will have an + * entry number at the end of the array of all entries in the header, but it + * could be anywhere in the array of active entries. */ +OEMCryptoResult CreateNewUsageEntry(OEMCryptoSession* session, + uint32_t* usage_entry_number) { + if (!session || !usage_entry_number) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + /* Check that the header can grow. */ + if (g_usage_table.table_size >= MAX_NUMBER_OF_USAGE_ENTRIES) { + return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES; + } + uint32_t new_index = g_usage_table.table_size; + ResidentUsageEntry* entry = NULL; + OEMCryptoResult result = GrabEntry(session, new_index, &entry); + if (result != OEMCrypto_SUCCESS) return result; + g_usage_table.table_size++; + entry->data.index = new_index; + /* mark session as having new entry. */ + session->usage_entry_status = SESSION_HAS_NEW_ENTRY; + /* Update the generation numbers. Increment the master GN, and then copy to + * the entry. Also copy to the header's array of entries. */ + g_usage_table.master_generation_number++; + entry->data.generation_number = g_usage_table.master_generation_number; + g_usage_table.generation_numbers[new_index] = + g_usage_table.master_generation_number; + *usage_entry_number = new_index; + return OEMCrypto_SUCCESS; +} + +/* Load a usage entry that had been saved to the file system and tie it to + * |session|. */ +OEMCryptoResult LoadUsageEntry(OEMCryptoSession* session, + uint32_t usage_entry_number, + const uint8_t* buffer, size_t buffer_length) { + if (!session) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + ResidentUsageEntry* entry = NULL; + OEMCryptoResult result = GrabEntry(session, usage_entry_number, &entry); + if (result != OEMCrypto_SUCCESS) return result; + /* Load the entry. */ + result = DecryptAndVerifyEntry(buffer, buffer_length, &entry->data); + if (result != OEMCrypto_SUCCESS) return result; + if (entry->data.index != usage_entry_number) { + entry = NULL; + ReleaseEntry(session, usage_entry_number); + return OEMCrypto_ERROR_INVALID_SESSION; + } + /* check generation number against header's table of generation numbers. */ + uint64_t entry_gn = entry->data.generation_number; + uint64_t header_gn = g_usage_table.generation_numbers[usage_entry_number]; + if (entry_gn + 1 == header_gn || entry_gn - 1 == header_gn) { + /* Skew of 1 is a warning, but we continue on. */ + result = OEMCrypto_WARNING_GENERATION_SKEW; + } else if (entry_gn != header_gn) { + /* Skew of more than 1 is an error. Clean the table and return an error. */ + entry = NULL; + ReleaseEntry(session, usage_entry_number); + return OEMCrypto_ERROR_GENERATION_SKEW; + } + /* mark session as having loaded entry or deactivated entry. */ + if (entry->data.status == kActive || entry->data.status == kUnused) { + session->usage_entry_status = SESSION_HAS_LOADED_ENTRY; + } else { + session->usage_entry_status = SESSION_HAS_DEACTIVATED_ENTRY; + } + return result; +} + +OEMCryptoResult UpdateUsageEntry(OEMCryptoSession* session, + uint8_t* header_buffer, + size_t* header_buffer_length, + uint8_t* entry_buffer, + size_t* entry_buffer_length) { + if (!session) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (g_usage_table_state != USAGE_TABLE_ACTIVE_STATE) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!header_buffer_length || !entry_buffer_length) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + /* Check the size and let caller know if it's a short buffer. */ + size_t header_size = SignedHeaderSize(g_usage_table.table_size); + size_t entry_size = SignedEntrySize(); + if (*header_buffer_length < header_size || + *entry_buffer_length < entry_size) { + *header_buffer_length = header_size; + *entry_buffer_length = entry_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *header_buffer_length = header_size; + *entry_buffer_length = entry_size; + /* Check that the session has an entry, and it's state is valid. */ + uint32_t index = session->usage_entry_number; + ResidentUsageEntry* entry = GetActiveEntry(index); + if (!entry || + (session->usage_entry_status != SESSION_HAS_NEW_ENTRY && + session->usage_entry_status != SESSION_HAS_LOADED_ENTRY && + session->usage_entry_status != SESSION_HAS_DEACTIVATED_ENTRY)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + /* The new generation numbers. */ + RollGenerationNumber(entry); + OEMCryptoResult result = + EncryptAndSignHeader(header_buffer, *header_buffer_length); + if (result != OEMCrypto_SUCCESS) return result; + result = + EncryptAndSignEntry(&entry->data, entry_buffer, *entry_buffer_length); + if (result == OEMCrypto_SUCCESS) { + entry->forbid_report = false; + entry->recent_decrypt = false; + } + return result; +} + +OEMCryptoResult UpdateLastPlaybackTime(const OEMCryptoSession* session) { + if (g_usage_table_state != USAGE_TABLE_ACTIVE_STATE) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!session) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + ResidentUsageEntry* entry = GetActiveEntry(session->usage_entry_number); + if (!entry || (session->usage_entry_status != SESSION_HAS_NEW_ENTRY && + session->usage_entry_status != SESSION_HAS_LOADED_ENTRY)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + uint64_t now; + OEMCrypto_Clock_Security_Level clock_type; + OEMCryptoResult result = GetSystemTime(&now, &clock_type); + if (result != OEMCrypto_SUCCESS) return result; + entry->recent_decrypt = true; + entry->data.time_of_last_decrypt = now; + if (entry->data.status == kUnused) { + /* This is the first playback. */ + entry->data.status = kActive; + entry->forbid_report = true; + entry->data.time_of_first_decrypt = now; + } else if (entry->data.status != kActive) { + /* License is inactive. Playback should be forbidden. */ + return OEMCrypto_ERROR_KEY_EXPIRED; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult SetUsageEntryPST(OEMCryptoSession* session, const uint8_t* pst, + size_t pst_length) { + if (g_usage_table_state != USAGE_TABLE_ACTIVE_STATE) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!session) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + ResidentUsageEntry* entry = GetActiveEntry(session->usage_entry_number); + if (!entry || (session->usage_entry_status != SESSION_HAS_NEW_ENTRY)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!pst || pst_length == 0 || pst_length > MAX_PST_LENGTH) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + memcpy(entry->data.pst, pst, pst_length); + entry->data.pst_length = pst_length; + + /* The PST is set when the license is loaded. This will be removed in v16 when + * we use the time of license signed instead of time of license loaded. */ + uint64_t now; + OEMCrypto_Clock_Security_Level clock_type; + OEMCryptoResult result = GetSystemTime(&now, &clock_type); + if (result != OEMCrypto_SUCCESS) return result; + entry->data.time_of_license_received = now; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult VerfiyUsageEntryPST(OEMCryptoSession* session, + const uint8_t* pst, size_t pst_length) { + if (g_usage_table_state != USAGE_TABLE_ACTIVE_STATE) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!session) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + ResidentUsageEntry* entry = GetActiveEntry(session->usage_entry_number); + if (!entry || (session->usage_entry_status != SESSION_HAS_LOADED_ENTRY)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!pst || pst_length == 0 || pst_length > MAX_PST_LENGTH) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (entry->data.pst_length != pst_length || + memcmp(entry->data.pst, pst, pst_length)) { + return OEMCrypto_ERROR_WRONG_PST; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult SetUsageEntryMacKeys(const OEMCryptoSession* session) { + if (g_usage_table_state != USAGE_TABLE_ACTIVE_STATE) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!session) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + ResidentUsageEntry* entry = GetActiveEntry(session->usage_entry_number); + if (!entry || (session->usage_entry_status != SESSION_HAS_NEW_ENTRY)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoResult result; + uint8_t wrapped_server_mac[WRAPPED_MAC_KEY_SIZE]; + uint8_t wrapped_client_mac[WRAPPED_MAC_KEY_SIZE]; + memset(wrapped_server_mac, 0, WRAPPED_MAC_KEY_SIZE); + memset(wrapped_client_mac, 0, WRAPPED_MAC_KEY_SIZE); + result = WrapCryptoKey(session->mac_key_server, wrapped_server_mac, + WRAPPED_MAC_KEY_SIZE); + if (result != OEMCrypto_SUCCESS) return result; + result = WrapCryptoKey(session->mac_key_client, wrapped_client_mac, + WRAPPED_MAC_KEY_SIZE); + if (result != OEMCrypto_SUCCESS) return result; + memcpy(entry->data.mac_key_server, wrapped_server_mac, WRAPPED_MAC_KEY_SIZE); + memcpy(entry->data.mac_key_client, wrapped_client_mac, WRAPPED_MAC_KEY_SIZE); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult VerifysageEntryMacKeys(const OEMCryptoSession* session) { + if (g_usage_table_state != USAGE_TABLE_ACTIVE_STATE) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!session) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + ResidentUsageEntry* entry = GetActiveEntry(session->usage_entry_number); + if (!entry || (session->usage_entry_status != SESSION_HAS_LOADED_ENTRY)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoResult result; + uint8_t wrapped_server_mac[WRAPPED_MAC_KEY_SIZE]; + uint8_t wrapped_client_mac[WRAPPED_MAC_KEY_SIZE]; + memset(wrapped_server_mac, 0, WRAPPED_MAC_KEY_SIZE); + memset(wrapped_client_mac, 0, WRAPPED_MAC_KEY_SIZE); + result = WrapCryptoKey(session->mac_key_server, wrapped_server_mac, + WRAPPED_MAC_KEY_SIZE); + if (result != OEMCrypto_SUCCESS) return result; + result = WrapCryptoKey(session->mac_key_client, wrapped_client_mac, + WRAPPED_MAC_KEY_SIZE); + if (result != OEMCrypto_SUCCESS) return result; + if (memcmp(entry->data.mac_key_server, wrapped_server_mac, + WRAPPED_MAC_KEY_SIZE) || + memcmp(entry->data.mac_key_client, wrapped_client_mac, + WRAPPED_MAC_KEY_SIZE)) { + return OEMCrypto_ERROR_WRONG_PST; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult DeactivateUsageEntry(OEMCryptoSession* session, + const uint8_t* pst, size_t pst_length) { + if (!session) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (g_usage_table_state != USAGE_TABLE_ACTIVE_STATE) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + /* Check that the session has an entry, and it's state is valid. */ + uint32_t index = session->usage_entry_number; + ResidentUsageEntry* entry = GetActiveEntry(index); + if (!entry || + (session->usage_entry_status != SESSION_HAS_NEW_ENTRY && + session->usage_entry_status != SESSION_HAS_LOADED_ENTRY && + session->usage_entry_status != SESSION_HAS_DEACTIVATED_ENTRY)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + session->usage_entry_status = SESSION_HAS_DEACTIVATED_ENTRY; + if (entry->data.status == kUnused) { + entry->data.status = kInactiveUnused; + } else if (entry->data.status == kActive) { + entry->data.status = kInactiveUsed; + } + RollGenerationNumber(entry); + entry->forbid_report = true; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult ReportUsage(OEMCryptoSession* session, const uint8_t* pst, + size_t pst_length, uint8_t* buffer, + size_t* buffer_length) { + if (!session) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (g_usage_table_state != USAGE_TABLE_ACTIVE_STATE) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + uint32_t index = session->usage_entry_number; + ResidentUsageEntry* entry = GetActiveEntry(index); + if (!entry || + (session->usage_entry_status != SESSION_HAS_NEW_ENTRY && + session->usage_entry_status != SESSION_HAS_LOADED_ENTRY && + session->usage_entry_status != SESSION_HAS_DEACTIVATED_ENTRY)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + size_t length_needed = sizeof(OEMCrypto_PST_Report) + pst_length; + if (*buffer_length < length_needed) { + *buffer_length = length_needed; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *buffer_length = length_needed; + + if (entry->forbid_report || entry->recent_decrypt) { + return OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE; + } + if (pst_length == 0 || pst_length > MAX_PST_LENGTH || + pst_length != entry->data.pst_length) { + return OEMCrypto_ERROR_WRONG_PST; + } + if (memcmp(entry->data.pst, pst, pst_length)) { + return OEMCrypto_ERROR_WRONG_PST; + } + + uint64_t now; + OEMCrypto_Clock_Security_Level clock_type; + OEMCryptoResult result = GetSystemTime(&now, &clock_type); + if (result != OEMCrypto_SUCCESS) return result; + + OEMCrypto_PST_Report* report = (OEMCrypto_PST_Report*)buffer; + report->seconds_since_license_received = + htonll64(now - entry->data.time_of_license_received); + report->seconds_since_first_decrypt = + htonll64(now - entry->data.time_of_first_decrypt); + report->seconds_since_last_decrypt = + htonll64(now - entry->data.time_of_last_decrypt); + report->status = entry->data.status; + report->clock_security_level = clock_type; + report->pst_length = pst_length; + memcpy(report->pst, pst, pst_length); + if (CheckKey(session->mac_key_client, MAC_KEY_CLIENT, MAC_KEY_CLIENT_SIGN)) { + /* If the session has mac keys, use those. */ + result = HMAC_SHA1(session->mac_key_client->key_handle, + buffer + SHA_DIGEST_LENGTH, + length_needed - SHA_DIGEST_LENGTH, report->signature); + } else { + /* Otherwise, we use the mac key from the entry. */ + CryptoKey key; + result = InitializeCryptoKeyFromWrappedKey( + &key, entry->data.mac_key_client, WRAPPED_MAC_KEY_SIZE, MAC_KEY_CLIENT, + MAC_KEY_CLIENT_SIGN, MAC_KEY_SIZE); + if (result != OEMCrypto_SUCCESS) return result; + result = HMAC_SHA1(key.key_handle, buffer + SHA_DIGEST_LENGTH, + length_needed - SHA_DIGEST_LENGTH, report->signature); + if (OEMCrypto_SUCCESS != FreeCryptoKey(&key)) { + if (OEMCrypto_SUCCESS != result) return result; + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + } + return result; +} + +OEMCryptoResult SignReleaseRequest(OEMCryptoSession* session, + const uint8_t* message, + size_t message_length, uint8_t* signature, + size_t* signature_length) { + if (!session) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (g_usage_table_state != USAGE_TABLE_ACTIVE_STATE) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + uint32_t index = session->usage_entry_number; + ResidentUsageEntry* entry = GetActiveEntry(index); + if (!entry || + (session->usage_entry_status != SESSION_HAS_NEW_ENTRY && + session->usage_entry_status != SESSION_HAS_LOADED_ENTRY && + session->usage_entry_status != SESSION_HAS_DEACTIVATED_ENTRY)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + CryptoKey key; + OEMCryptoResult result = InitializeCryptoKeyFromWrappedKey( + &key, entry->data.mac_key_client, WRAPPED_MAC_KEY_SIZE, MAC_KEY_CLIENT, + MAC_KEY_CLIENT_SIGN, MAC_KEY_SIZE); + if (result != OEMCrypto_SUCCESS) return result; + result = HMAC_SHA256(key.key_handle, message, message_length, signature); + if (OEMCrypto_SUCCESS != FreeCryptoKey(&key)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return result; +} + +OEMCryptoResult MoveEntry(OEMCryptoSession* session, uint32_t new_index) { + if (!session) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (g_usage_table_state != USAGE_TABLE_ACTIVE_STATE) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + uint32_t index = session->usage_entry_number; + ResidentUsageEntry* entry = GetActiveEntry(index); + if (!entry || + (session->usage_entry_status != SESSION_HAS_NEW_ENTRY && + session->usage_entry_status != SESSION_HAS_LOADED_ENTRY && + session->usage_entry_status != SESSION_HAS_DEACTIVATED_ENTRY)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (g_usage_table.active_entry_map[new_index].state != + USAGE_ENTRY_NOT_ACTIVE || + g_usage_table.active_entry_map[new_index].active_entry_index != + MAX_NUMBER_OF_ACTIVE_USAGE_ENTRIES) { + return OEMCrypto_ERROR_ENTRY_IN_USE; + } + /* Copy data from index to new_index. */ + entry->data.index = new_index; + g_usage_table.active_entry_map[new_index].state = USAGE_ENTRY_ACTIVE; + g_usage_table.active_entry_map[new_index].active_entry_index = + g_usage_table.active_entry_map[index].active_entry_index; + session->usage_entry_number = new_index; + /* Update entry's generation number to be max generation number. */ + entry->data.generation_number = g_usage_table.master_generation_number; + g_usage_table.generation_numbers[new_index] = + g_usage_table.master_generation_number; + + /* Mark old index as unused. */ + g_usage_table.active_entry_map[index].state = USAGE_ENTRY_NOT_ACTIVE; + g_usage_table.active_entry_map[index].active_entry_index = + MAX_NUMBER_OF_ACTIVE_USAGE_ENTRIES; + + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult ShrinkUsageTableHeader(uint32_t new_entry_count, + uint8_t* header_buffer, + size_t* header_buffer_length) { + if (g_usage_table_state != USAGE_TABLE_ACTIVE_STATE) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (new_entry_count >= g_usage_table.table_size) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + for (uint32_t i = new_entry_count; i < g_usage_table.table_size; i++) { + if (g_usage_table.active_entry_map[i].state != USAGE_ENTRY_NOT_ACTIVE) { + return OEMCrypto_ERROR_ENTRY_IN_USE; + } + } + size_t header_size = SignedHeaderSize(new_entry_count); + if (header_size > *header_buffer_length) { + *header_buffer_length = header_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + for (uint32_t i = new_entry_count; i < g_usage_table.table_size; i++) { + g_usage_table.active_entry_map[i].state = USAGE_ENTRY_NOT_ACTIVE; + g_usage_table.active_entry_map[i].active_entry_index = + MAX_NUMBER_OF_ACTIVE_USAGE_ENTRIES; + g_usage_table.generation_numbers[i] = 0; + } + g_usage_table.table_size = new_entry_count; + return EncryptAndSignHeader(header_buffer, *header_buffer_length); +} diff --git a/oemcrypto_ta/oemcrypto_usage_table.h b/oemcrypto_ta/oemcrypto_usage_table.h new file mode 100644 index 0000000..2c320ce --- /dev/null +++ b/oemcrypto_ta/oemcrypto_usage_table.h @@ -0,0 +1,142 @@ +/* Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine Master + License Agreement. */ + +#ifndef OEMCRYPTO_TA_OEMCRYPTO_USAGE_TABLE_H_ +#define OEMCRYPTO_TA_OEMCRYPTO_USAGE_TABLE_H_ + +#include "stdbool.h" +#include "stdint.h" + +#include "OEMCryptoCENC.h" +#include "oemcrypto_config_macros.h" +#include "oemcrypto_key_types.h" +#include "oemcrypto_session.h" + +/** + * Clear out memory for the usage table. No other usage table functions may be + * called before this. */ +OEMCryptoResult InitializeUsageTable(void); + +/** + * Erase data from usage table. No other usage table functions may be called + * without calling InitializeUsageTable. */ +OEMCryptoResult TerminateUsageTable(void); + +/** Create a new empty usage table header. */ +OEMCryptoResult CreateUsageTableHeader(uint8_t* header_buffer, + size_t* header_buffer_length); + +/** Load a usage table header. */ +OEMCryptoResult LoadUsageTableHeader(const uint8_t* buffer, + size_t buffer_length); + +/** + * Create a new usage table entry and attach it to the |session|. This may + * return an error if the usage table is full, or if too many open sessions have + * active usage entries. |session| must be open and not already have an entry + * associated with it. + * Pointers must be non-null and are owned by the caller. */ +OEMCryptoResult CreateNewUsageEntry(OEMCryptoSession* session, + uint32_t* usage_entry_number); + +/** + * Load a usage table entry and attach it to the |session|. This may return an + * error if too many open sessions have active usage entries. |session| must be + * open and not already have an entry associated with it. The usage_entry_number + * must match that in the loaded entry. + * Pointers must be non-null and are owned by the caller. */ +OEMCryptoResult LoadUsageEntry(OEMCryptoSession* session, + uint32_t usage_entry_number, + const uint8_t* buffer, size_t buffer_length); + +/** + * Release the active usage entry associated with |session|. + * Pointers must be non-null and are owned by the caller. */ +OEMCryptoResult ReleaseEntry(OEMCryptoSession* session, + uint32_t usage_entry_number); + +/** + * Update all values in the usage entry associated with |session|. After + * updating values, the generation numbers are all updated and the master + * generation number is saved to persistent storage. Then the entry and the + * usage table header are saved to the specified buffer. If the buffer lengths + * are not large enough, none of the work above is completed -- instead the + * lengths are updated and OEMCrypto_ERROR_SHORT_BUFFER is returned. + * Pointers must be non-null and are owned by the caller. */ +OEMCryptoResult UpdateUsageEntry(OEMCryptoSession* session, + uint8_t* header_buffer, + size_t* header_buffer_length, + uint8_t* entry_buffer, + size_t* entry_buffer_length); + +/** + * Update the playback times in the usage entry attached to |session|. + * Pointers must be non-null and are owned by the caller. */ +OEMCryptoResult UpdateLastPlaybackTime(const OEMCryptoSession* session); + +/** + * Set the provider session token in the usage entry associated with |session|. + * This is done when a license is first loaded. + * Pointers must be non-null and are owned by the caller. */ +OEMCryptoResult SetUsageEntryPST(OEMCryptoSession* session, const uint8_t* pst, + size_t pst_length); + +/** + * Verify the provider session token in the usage entry associated with + * |session|. This is done when a license is reloaded to verify the license + * matches the usage entry. + * Pointers must be non-null and are owned by the caller. */ +OEMCryptoResult VerfiyUsageEntryPST(OEMCryptoSession* session, + const uint8_t* pst, size_t pst_length); + +/** + * Set the mac keys in the usage entry associated with |session|. + * This is done when a license is first loaded. + * Pointers must be non-null and are owned by the caller. */ +OEMCryptoResult SetUsageEntryMacKeys(const OEMCryptoSession* session); + +/** + * Verify the mac keys in the usage entry associated with + * |session|. This is done when a license is reloaded to verify the license + * matches the usage entry. + * Pointers must be non-null and are owned by the caller. */ +OEMCryptoResult VerifysageEntryMacKeys(const OEMCryptoSession* session); + +/** + * Mark the usage entry associated with |session| as deactivated. After this, + * the license may not be used to decrypt content. + * Pointers must be non-null and are owned by the caller. */ +OEMCryptoResult DeactivateUsageEntry(OEMCryptoSession* session, + const uint8_t* pst, size_t pst_length); + +/** + * Generate a usage report from the entry associated with |session|. + * Pointers must be non-null and are owned by the caller. */ +OEMCryptoResult ReportUsage(OEMCryptoSession* session, const uint8_t* pst, + size_t pst_length, uint8_t* buffer, + size_t* buffer_length); + +/** + * Sign |buffer| with the client mac key in the entry associated with |session|. + * Pointers must be non-null and are owned by the caller. */ +OEMCryptoResult SignReleaseRequest(OEMCryptoSession* session, + const uint8_t* message, + size_t message_length, uint8_t* signature, + size_t* signature_length); + +/** + * Move the usage entry associated with |session| to the new index in the usage + * table header. The generation numbers are updated as specified in the + * OEMCrypto spec. + * Pointers must be non-null and are owned by the caller. */ +OEMCryptoResult MoveEntry(OEMCryptoSession* session, uint32_t new_index); + +/** + * Shrink the usage table to the size specified. + * Pointers must be non-null and are owned by the caller. */ +OEMCryptoResult ShrinkUsageTableHeader(uint32_t new_entry_count, + uint8_t* header_buffer, + size_t* header_buffer_length); + +#endif /* OEMCRYPTO_TA_OEMCRYPTO_USAGE_TABLE_H_ */ diff --git a/oemcrypto_ta/tee_interfaces/assert_interface.h b/oemcrypto_ta/tee_interfaces/assert_interface.h new file mode 100644 index 0000000..691d35d --- /dev/null +++ b/oemcrypto_ta/tee_interfaces/assert_interface.h @@ -0,0 +1,19 @@ +/* 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. */ + +#ifndef OEMCRYPTO_TA_ASSERT_INTERFACE_H_ +#define OEMCRYPTO_TA_ASSERT_INTERFACE_H_ + +#include "logging_interface.h" + +/* Abort the program execution. */ +void Abort(void); + +#define ASSERT(expression, ...) \ + if (!(expression)) { \ + LOGE(__VA_ARGS__); \ + Abort(); \ + } + +#endif /* OEMCRYPTO_TA_ASSERT_INTERFACE_H_ */ diff --git a/oemcrypto_ta/tee_interfaces/clock_interface.h b/oemcrypto_ta/tee_interfaces/clock_interface.h new file mode 100644 index 0000000..ba41e41 --- /dev/null +++ b/oemcrypto_ta/tee_interfaces/clock_interface.h @@ -0,0 +1,42 @@ +/* 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. */ + +#ifndef OEMCRYPTO_TA_CLOCK_INTERFACE_H_ +#define OEMCRYPTO_TA_CLOCK_INTERFACE_H_ + +#include "stdint.h" + +#include "OEMCryptoCENC.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Calculates the system time at the time of call and modifies |time_in_s|. + + TODO(b/158719238): This needs some design work. We should wrap this in + something that can upgrade the clock type to being monotonic over reboot. + + TODO(b/158719238): Reword this paragraph to say what the real requirements + are: + This time does not need to be strictly increasing across + device reboots, but must be strictly increasing between calls to + OEMCrypto_Initialize and OEMCrypto_Terminate. This does not need to be time + since epoch. This does not need to start at 0 on boot. + + If clock_type is not null, set *clock_type to the type of clock, as defined + in the OEMCrypto spec. + + Returns OEMCrypto_ERROR_UNKNOWN_FAILURE on failure and OEMCrypto_SUCCESS on + success. + Returns OEMCrypto_ERROR_UNKNOWN_FAILURE if time_in_s is a null pointer. + Caller retains ownership of all pointers. */ +OEMCryptoResult GetSystemTime(uint64_t* time_in_s, + OEMCrypto_Clock_Security_Level* clock_type); + +#ifdef __cplusplus +} +#endif + +#endif /* OEMCRYPTO_TA_CLOCK_INTERFACE_H_ */ diff --git a/oemcrypto_ta/tee_interfaces/crypto_interface.h b/oemcrypto_ta/tee_interfaces/crypto_interface.h new file mode 100644 index 0000000..9d44539 --- /dev/null +++ b/oemcrypto_ta/tee_interfaces/crypto_interface.h @@ -0,0 +1,189 @@ +/* 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. */ + +#ifndef OEMCRYPTO_TA_CRYPTO_INTERFACE_H_ +#define OEMCRYPTO_TA_CRYPTO_INTERFACE_H_ + +#include "OEMCryptoCENC.h" + +#include "oemcrypto_key_types.h" + +typedef struct tee_key_handle* TEE_Key_Handle; + +/* Creates a key handle from |size| bytes of |serialized_bytes| and the + |key_type|, and places the result in |key_handle|. Returns + OEMCrypto_ERROR_INVALID_CONTEXT if any of the parameters are NULL, size is 0, + or |key_type| is UNKNOWN_KEY_TYPE, OEMCrypto_ERROR_INVALID_RSA_KEY if the + key type is DRM_PRIVATE_RSA_KEY and |serialized_bytes| is an invalid PKCS8 + RSA private key, OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other + failures, and OEMCrypto_SUCCESS otherwise. + Caller retains ownership of all parameters. */ +OEMCryptoResult CreateKeyHandle(const uint8_t* serialized_bytes, uint32_t size, + CryptoKeyType key_type, + TEE_Key_Handle* key_handle); + +/* Creates a key handle from |size| bytes of |wrapped_key| and the + |key_type|, and places the result in |key_handle|. Returns + OEMCrypto_ERROR_INVALID_CONTEXT if any of the parameters are NULL, size is 0, + or |key_type| is UNKNOWN_KEY_TYPE, OEMCrypto_ERROR_INVALID_RSA_KEY if the + key type is DRM_PRIVATE_RSA_KEY and |serialized_bytes| is an invalid PKCS8 + RSA private key, OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other + failures, and OEMCrypto_SUCCESS otherwise. + Caller retains ownership of all parameters. */ +OEMCryptoResult UnwrapIntoKeyHandle(const uint8_t* wrapped_key, uint32_t size, + CryptoKeyType key_type, + TEE_Key_Handle* key_handle); + +/* Frees |key_handle| that was constructed from a previous call to + CreateKeyHandle. Returns OEMCrypto_ERROR_INVALID_CONTEXT if |key_handle| is + NULL, OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, and + OEMCrypto_SUCCESS otherwise. + Caller retains ownership of all pointers. */ +OEMCryptoResult FreeKeyHandle(TEE_Key_Handle key_handle); + +/* Wraps the key data into a buffer that can be saved to the file system. The + wrapping must be device unique. Caller retains ownership of |key| and + |buffer| and they must not be NULL. Caller ensures that buffer_length is at + least as big as the wrapped key size specified in + oemcrypto_config_macros.h. */ +OEMCryptoResult WrapKey(uint8_t* wrapped_key, uint32_t size, + CryptoKeyType key_type, TEE_Key_Handle key_handle); + +/* AES decryption for 1 block - 16 bytes. |key| is a handle to the AES key used + for decryption. It is used to decrypt |in| and place the result in |out|. + |in| and |out| must be >= 16 bytes. + Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL or + OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, and + OEMCrypto_SUCCESS otherwise. + Caller retains ownership of all pointers. */ +OEMCryptoResult AESDecrypt(TEE_Key_Handle key, const uint8_t* in, uint8_t* out); + +/* AES encryption for 1 block - 16 bytes. |key| is a handle to the AES key used + for encryption. It is used to encrypt |in| and place the result in |out|. + |in| and |out| must be >= 16 bytes. + Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL or + OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, and + OEMCrypto_SUCCESS otherwise. + Caller retains ownership of all pointers. */ +OEMCryptoResult AESEncrypt(TEE_Key_Handle key, const uint8_t* in, uint8_t* out); + +/* Decrypts |in_length| bytes of |in| using AES CBC and |iv| and places the + result in |out|. |key| is a handle to the AES key used for decryption and + |key_length| determines the number of bytes to use from |key|. |out| must be + >= |in_length| bytes. + Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL, + |key_length| is not either 16 or 32 bytes, |key_length| is greater than the + size of |key|, |in_length| is 0 or not a multiple of the AES block size, + OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, and + OEMCrypto_SUCCESS otherwise. + Caller retains ownership of all pointers. */ +OEMCryptoResult AESCBCDecrypt(TEE_Key_Handle key, uint32_t key_length, + const uint8_t* in, uint32_t in_length, + const uint8_t* iv, uint8_t* out); + +/* Encrypts |in_length| bytes of |in| using AES CBC and |iv| and places the + result in |out|. |key| is a handle to the AES key used for encryption. |out| + must be >= |in_length| bytes. + Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL, + |in_length| is 0 or not a multiple of the AES block size, + OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, and + OEMCrypto_SUCCESS otherwise. + Caller retains ownership of all pointers. */ +OEMCryptoResult AESCBCEncrypt(TEE_Key_Handle key, const uint8_t* in, + uint32_t in_length, const uint8_t* iv, + uint8_t* out); + +/* Calculates the HMAC of |message_length| bytes of |message| using SHA256 as + the hash function and places the result in |out| and sets |out_length| to the + correct length of the HMAC. |key| is a handle to the key used in the + derivation. + |out|'s length must be >= 32 bytes. + Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL or + |message_length| is 0, OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other + failures, and OEMCrypto_SUCCESS otherwise. + Caller retains ownership of all pointers. */ +OEMCryptoResult HMAC_SHA256(TEE_Key_Handle key, const uint8_t* message, + uint32_t message_length, uint8_t* out); + +/* Calculates the HMAC of |message_length| bytes of |message| using SHA1 as the + hash function and places the result in |out|. |key| is a handle to the key + used in the derivation. + |out|'s length must be >= 20 bytes. + Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL or + |message_length| is 0, OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other + failures, and OEMCrypto_SUCCESS otherwise. + Caller retains ownership of all pointers. */ +OEMCryptoResult HMAC_SHA1(TEE_Key_Handle key, const uint8_t* message, + uint32_t message_length, uint8_t* out); + +/* Sign |message_length| bytes of |message| with the given RSA key handle using + the given |padding scheme| and place the result in |signature|. + |key| is a handle to the RSA key used for signing. + Returns OEMCrypto_ERROR_SHORT_BUFFER if |signature_length| is too small or if + |signature| is NULL, in which case it sets |signature_length| to the + appropriate length. Returns OEMCrypto_ERROR_INVALID_CONTEXT if + |message_length| is 0 or if any of the pointers except |signature| are NULL, + OEMCrypto_ERROR_INVALID_RSA_KEY if the padding_scheme provided is not + supported, OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, + and OEMCrypto_SUCCESS otherwise. + Caller retains ownership of all pointers. */ +OEMCryptoResult RSASign(TEE_Key_Handle key, const uint8_t* message, + uint32_t message_length, uint8_t* signature, + uint32_t* signature_length, + RSA_Padding_Scheme padding_scheme); + +/* Decrypts |in_length| bytes of |in| and places it in |out|. The padding scheme + shall only be PKCS1 OAEP. |key| is a handle to the RSA key used for + decryption. + Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL or + |in_length| is 0, OEMCrypto_ERROR_SHORT_BUFFER if |out_length| is too small, + in which case it sets |out_length| to the appropriate length, + OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, and + OEMCrypto_SUCCESS otherwise. + Caller retains ownership of all pointers. */ +OEMCryptoResult RSADecrypt(TEE_Key_Handle key, const uint8_t* in, + uint32_t in_length, uint8_t* out, + uint32_t* out_length); + +/* The device key is used to wrap and unwrap the DRM RSA key. It should be + separate from the key tied to the Widevine root of trust if possible. + Derives a 16 byte key from the device key and |context_length| bytes of + |context| using AES-128-CMAC. Prepends |counter| to context in the + derivation. Modifies |out| to the correct value. + |out| must be >= 16 bytes. + Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL or + |context_length| is 0, OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other + failures, and OEMCrypto_SUCCESS otherwise. + Caller retains ownership of all pointers. */ +OEMCryptoResult DeriveKeyFromDeviceKey(uint8_t counter, const uint8_t* context, + uint32_t context_length, uint8_t* out); + +/* Identical to the previous function, except that it uses |key| to derive a + key. */ +OEMCryptoResult DeriveKeyFromKeyHandle(TEE_Key_Handle key, uint8_t counter, + const uint8_t* context, + uint32_t context_length, uint8_t* out); + +/* Generates |size| random bytes and places them in |out|. Returns + OEMCrypto_ERROR_BUFFER_TOO_LARGE if |size| is too big, + OEMCrypto_ERROR_UNKNOWN_FAILURE or any other failures, and OEMCrypto_SUCCESS + otherwise. + Caller retains ownership of all pointers. */ +OEMCryptoResult RandomBytes(uint8_t* out, uint32_t size); + +/* Initializes the 32-bit |initial_hash| to the starting CRC-32 value. + Returns OEMCrypto_ERROR_INVALID_CONTEXT if |initial_hash| is NULL and + OEMCrypto_SUCCESS otherwise. + Caller retains ownership of all pointers. */ +OEMCryptoResult Crc32Init(uint32_t* initial_hash); + +/* Calculates the new crc-32 value given |in_length| bytes of |in| and the + previous CRC-32 value, |prev_crc|. Places the result in |new_crc|. + Returns OEMCrypto_ERROR_INVALID_CONTEXT if any pointers are NULL or + |in_length| is 0 and OEMCrypto_SUCCESS otherwise. + Caller retains ownership of all pointers. */ +OEMCryptoResult Crc32Cont(const uint8_t* in, uint32_t in_length, + uint32_t prev_crc, uint32_t* new_crc); + +#endif /* OEMCRYPTO_TA_CRYPTO_INTERFACE_H_ */ diff --git a/oemcrypto_ta/tee_interfaces/generation_number_interface.h b/oemcrypto_ta/tee_interfaces/generation_number_interface.h new file mode 100644 index 0000000..320a9d7 --- /dev/null +++ b/oemcrypto_ta/tee_interfaces/generation_number_interface.h @@ -0,0 +1,64 @@ +/* Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine Master + License Agreement. */ + +#ifndef OEMCRYPTO_TA_GENERATION_NUMBER_INTERFACE_H_ +#define OEMCRYPTO_TA_GENERATION_NUMBER_INTERFACE_H_ + +#include + +#include "OEMCryptoCENC.h" + +/** + * Prepare to load the generation number. If the generation number is loaded + * asynchronously, this should initialize that process so that the next call to + * TEE_LoadGenerationNumber does not block for too long. + * + * TODO(b/160022428): define and document "too long". + * + * The generation number should be stored in secure persistent storage. By + * *persistent* we mean that the generation number should not be changed by + * shutting down and later restarting the system. By *secure* we mean that the + * user should not be able to modify the generation number. In particular, the + * user should not be able to revert the generation number to a previous value. + * + * Returns true on success. On failure, initialization of the TA will fail. + */ +bool TEE_PrepareGenerationNumber(void); + +/** + * Load the usage table generation number. This is called once, on first use of + * the usage table. This is expected to block until a value is available. It is + * the porting interface's responsibility to fail if this blocks too + * long. Returns true on success. A return value of false will fail OEMCrypto + * initialization. If the generation number has never been saved before, a + * random number should be generated -- this is NOT an error. + */ +bool TEE_LoadGenerationNumber(uint64_t* value); + +/** + * Save the generation number. + * + * If the generation number is saved asynchronously, then it is OK for the first + * call to this function to begin a save process and then return true. + * Subsequent calls will verify that the previous save has completed + * successfully. If the previous save resulted in an error, then this call will + * return false. If the previous call has not completed, then this call should + * block until the previous save finishes before initializing a new save. If the + * previous call was successful, then this call will initialize a new save and + * return true. It is the porting interface's responsibility to fail if this + * blocks too long. + * + * If the generation number is saved synchronously, then this function should + * attempt to save the generation number and return true if the save was + * successful. + * + * Returns true on success. A return value of false will fail the current + * attempt to save the usage table. If a failure actually indicates that the + * previous save had failed, then the usage table will be saved with a + * generation number skew of 1. When the usage table is loaded with a generation + * skew of 1, it will result in a warning, but not a failure. + */ +bool TEE_SaveGenerationNumber(uint64_t value); + +#endif /* OEMCRYPTO_TA_GENERATION_NUMBER_INTERFACE_H_ */ diff --git a/oemcrypto_ta/tee_interfaces/initialize_terminate_interface.h b/oemcrypto_ta/tee_interfaces/initialize_terminate_interface.h new file mode 100644 index 0000000..4bed7f4 --- /dev/null +++ b/oemcrypto_ta/tee_interfaces/initialize_terminate_interface.h @@ -0,0 +1,18 @@ +/* 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. */ + +#ifndef OEMCRYPTO_TA_INITIALIZE_TERMINATE_INTERFACE_H_ +#define OEMCRYPTO_TA_INITIALIZE_TERMINATE_INTERFACE_H_ + +/* Set up for any work needed for initializing the TA-specific components of the + TEE. Returns 0 on success and any other int, which will be logged, on + failure. */ +int Initialize(void); + +/* Set up for any work needed for terminating the TA-specific components of the + TEE. Returns 0 on success and any other int, which will be logged, on + failure. */ +int Terminate(void); + +#endif /* OEMCRYPTO_TA_INITIALIZE_TERMINATE_INTERFACE_H_ */ diff --git a/oemcrypto_ta/tee_interfaces/logging_interface.h b/oemcrypto_ta/tee_interfaces/logging_interface.h new file mode 100644 index 0000000..a53d6a9 --- /dev/null +++ b/oemcrypto_ta/tee_interfaces/logging_interface.h @@ -0,0 +1,21 @@ +/* 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. */ + +#ifndef OEMCRYPTO_TA_LOGGING_INTERFACE_H_ +#define OEMCRYPTO_TA_LOGGING_INTERFACE_H_ + +typedef enum LogPriority { + LOG_ERROR = 0x1098fa73, + LOG_DEBUG = 0x2b898c5a, +} LogPriority; + +extern LogPriority g_cutoff; + +void Log(const char* file, const char* function, int line, LogPriority level, + const char* fmt, ...); + +#define LOGE(...) Log(__FILE__, __func__, __LINE__, LOG_ERROR, __VA_ARGS__) +#define LOGD(...) Log(__FILE__, __func__, __LINE__, LOG_DEBUG, __VA_ARGS__) + +#endif /* OEMCRYPTO_TA_LOGGING_INTERFACE_H_ */ diff --git a/oemcrypto_ta/tee_interfaces/oemcrypto_config_interface.h b/oemcrypto_ta/tee_interfaces/oemcrypto_config_interface.h new file mode 100644 index 0000000..272fbfd --- /dev/null +++ b/oemcrypto_ta/tee_interfaces/oemcrypto_config_interface.h @@ -0,0 +1,84 @@ +/* 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. */ + +#ifndef OEMCRYPTO_TA_OEMCRYPTO_CONFIG_INTERFACE_H_ +#define OEMCRYPTO_TA_OEMCRYPTO_CONFIG_INTERFACE_H_ + +#include "OEMCryptoCENC.h" +#include "oemcrypto_config_macros.h" + +/* Returns the provisioning method configured for this TA. */ +OEMCrypto_ProvisioningMethod GetProvisioningMethod(void); + +/* Returns the resource rating tier associated with this device. */ +uint32_t GetResourceRatingTier(void); + +/* Returns an xor of all the padding schemes allowed by this device. */ +uint32_t GetRSAPaddingSchemes(void); + +/* Gets the current supported version of SRM for the device and sets the + |srm_version|. Returns OEMCrypto_SUCCESS if it was able to be fetched, + OEMCrypto_ERROR_INVALID_CONTEXT if |srm_version| is NULL, any + OEMCrypto_ERROR_UNKNOWN_FAILURE otherwise. */ +OEMCryptoResult GetCurrentSRMVersion(uint32_t* srm_version); + +/* Returns whether the device has hardware protection preventing rollback of the + usage table. */ +bool IsAntiRollbackHWPresent(void); + +/* Returns whether or not the device was able to apply the CGMS protection for + the device. The |cgms_field| correlates to those under the Key Control Block + description in the OEMCrypto doc. If the cgms_field is invalid, return + OEMCrypto_ERROR_UNKNOWN_FAILURE. Even if this function is not called, the + device should attempt best effort for CGMS. */ +OEMCryptoResult ApplyCGMS(uint8_t cgms_field); + +/* Returns whether CGMS is enabled for analog output for this device. */ +bool IsCGMS_AActive(void); + +/* Returns whether this device is capable of supporting 2-bit CGMS-A. */ +bool SupportsCGMS_A(void); + +/* Returns whether the device is capable of analog display. */ +bool HasAnalogDisplay(void); + +/* Returns whether analog display is enabled for this display. */ +bool IsAnalogDisplayActive(void); + +/* Returns whether the analog display is capable of being disabled. If this + device doesn't have analog display, return false. */ +bool CanDisableAnalogDisplay(void); + +/* Turn off analog display and return whether it was successful. If this device + doesn't have analog display, return false. */ +bool DisableAnalogDisplay(void); + +/* Returns the max buffer size/max subsample size in bytes allowed for + DecryptCENC. If there is no restriction, returns 0. */ +uint32_t MaxBufferSizeForDecrypt(void); + +/* Returns the max output size in bytes allowed for DecryptCENC and CopyBuffer. + If there is no restriction, returns 0. */ +uint32_t MaxOutputSizeForDecrypt(void); + +/* A closed platform can use clear buffers during decryption. */ +/* TODO(b/145245387): define what constitutes a closed platform. */ +bool IsClosedPlatform(void); + +/* Returns the current and maximum HDCP capabilities of the device. Look at the + OEMCrypto integration guide for full details on what the current and maximum + capabilities entail. */ +OEMCrypto_HDCP_Capability CurrentHDCPCapability(void); +OEMCrypto_HDCP_Capability MaxHDCPCapability(void); + +/* Returns the max buffer size allowed for OEMCrypto_Generic_*. + If there is no restriction, returns 0. */ +uint32_t MaxBufferSizeForGenericCrypto(void); + +/* Returns the type of certificates this device can support. See + OEMCrypto_SupportedCertificates in the integration guide for details on + return value. */ +uint32_t SupportedCertificates(void); + +#endif /* OEMCRYPTO_TA_OEMCRYPTO_CONFIG_INTERFACE_H_ */ diff --git a/oemcrypto_ta/tee_interfaces/root_of_trust_interface.h b/oemcrypto_ta/tee_interfaces/root_of_trust_interface.h new file mode 100644 index 0000000..763181d --- /dev/null +++ b/oemcrypto_ta/tee_interfaces/root_of_trust_interface.h @@ -0,0 +1,114 @@ +/* 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. */ + +#ifndef OEMCRYPTO_TA_ROOT_OF_TRUST_INTERFACE_H_ +#define OEMCRYPTO_TA_ROOT_OF_TRUST_INTERFACE_H_ + +#include "stddef.h" +#include "stdint.h" + +#include "OEMCryptoCENC.h" + +/* Sets the length of the OEM public certificate. Returns + OEMCrypto_ERROR_INVALID_CONTEXT if |public_cert| is NULL, + OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other issues, and + OEMCrypto_SUCCESS otherwise. + Caller retains ownership of |public_cert|. */ +OEMCryptoResult GetOEMPublicCertificateLength(uint32_t* public_cert_length); + +/* Sets the OEM public certificate. Returns OEMCrypto_ERROR_INVALID_CONTEXT + if |public_cert| is NULL, OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any + other issues, and OEMCrypto_SUCCESS otherwise. + Caller retains ownership of |public_cert|. */ +OEMCryptoResult GetOEMPublicCertificate(uint8_t* public_cert); + +/* Calls to the crypto engine to sign |message_length| bytes of |message| using + padding scheme RSASSA-PSS with SHA1 and places the result in |signature| and + modifies |signature_length| to the appropriate value. + Returns OEMCrypto_ERROR_SHORT_BUFFER if |signature_length| is too small or if + |signature| is NULL, in which case it sets |signature_length| to the + appropriate length. Returns OEMCrypto_ERROR_INVALID_CONTEXT if + |message_length| is 0 or if any of the pointers except |signature| are NULL, + OEMCrypto_ERROR_INVALID_RSA_KEY if the OEM RSA key is invalid, + OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, and + OEMCrypto_SUCCESS otherwise. */ +OEMCryptoResult SignMessageWithOEMPrivateKey(const uint8_t* message, + uint32_t message_length, + uint8_t* signature, + uint32_t* signature_length); + +/* Calls to the crypto engine to decrypt |in_length| bytes of |in| and place it + in |out| using the OEM private key. The padding scheme shall only be + PKCS1-OAEP. + Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL or + |in_length| is 0, OEMCrypto_ERROR_SHORT_BUFFER if *|out_length| is too small, + in which case it sets *|out_length| to the appropriate length, + OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, and + OEMCrypto_SUCCESS otherwise. + Caller retains ownership of all pointers. */ +OEMCryptoResult DecryptMessageWithOEMPrivateKey(const uint8_t* in, + uint32_t in_length, + uint8_t* out, + uint32_t* out_length); + +/* Validates the OEM private key stored on the device. + Returns OEMCrypto_ERROR_INVALID_RSA_KEY if the key is not a valid RSA key, + OEMCrypto_ERROR_UNKNOWN_FAILURE on any other failures, and OEMCrypto_SUCCESS + otherwise. */ +OEMCryptoResult ValidateOEMPrivateKey(void); + +/* For devices that use Provisioning 3.0 and want to provide a custom device id + instead of using the OEM cert as the unique identifier. + Returns OEMCrypto_ERROR_SHORT_BUFFER if |device_id_length| is too small, + OEMCrypto_ERROR_INVALID_CONTEXT if |device_id| is NULL, + OEMCrypto_ERROR_NOT_IMPLEMENTED if the OEM cert should be used, + OEMCrypto_ERROR_UNKNOWN_FAILURE on any other failures, and OEMCrypto_SUCCESS + otherwise. + Caller retains ownership of all pointers and |device_id_length| must not be + NULL. */ +OEMCryptoResult GetDeviceIDForOEMCert(uint8_t* device_id, + uint32_t* device_id_length); + +/* Attempt to validate the current keybox loaded. + Returns OEMCrypto_ERROR_BAD_MAGIC if magic field is not "kbox", + OEMCrypto_ERROR_BAD_CRC if computed CRC is not equivalent to stored CRC, + and OEMCrypto_SUCCESS otherwise. */ +OEMCryptoResult ValidateKeybox(void); + +/* Get the 72 byte encrypted key data from the current keybox. + Returns OEMCrypto_ERROR_INVALID_CONTEXT if |key_data| is NULL and + OEMCrypto_SUCCESS otherwise. + In order to avoid buffer overflow attacks, we recommend partners to keep this + separate from the device key in the keybox, so that when this accessed, the + device key is not exposed. + |key_data| must be >= 72 bytes. */ +OEMCryptoResult GetKeyDataFromKeybox(uint8_t* key_data); + +/* Get the 32 byte device id from the current keybox. + Returns OEMCrypto_ERROR_INVALID_CONTEXT if |device_id| is NULL and + OEMCrypto_SUCCESS otherwise. + In order to avoid buffer overflow attacks, we recommend partners to keep this + separate from the device key in the keybox, so that when this accessed, the + device key is not exposed. + |device_id| must be >= 32 bytes. */ +OEMCryptoResult GetDeviceIDFromKeybox(uint8_t* device_id); + +/* Load a test keybox to be used until the next OEMCrypto_Terminate call. + Returns OEMCrypto_ERROR_INVALID_CONTEXT if |test_keybox| is NULL and + OEMCrypto_SUCCESS otherwise. + |test_keybox| must be >= 128 bytes. */ +OEMCryptoResult LoadTestKeybox(const uint8_t* test_keybox); + +/* Derives a 16 byte key from the keybox key and |context_length| bytes of + |context| using AES-128-CMAC. Prepends |counter| to context in the + derivation. Modifies |out| to the correct value. + |out| must be >= 16 bytes. + Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL or + |context_length| is 0, OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other + failures, and OEMCrypto_SUCCESS otherwise. + Caller retains ownership of all pointers. */ +OEMCryptoResult DeriveKeyFromKeybox(uint8_t counter, const uint8_t* context, + uint32_t context_length, uint8_t* out); + +#endif /* OEMCRYPTO_TA_ROOT_OF_TRUST_INTERFACE_H_ */ diff --git a/serialization/OEMCryptoCENC.h b/serialization/OEMCryptoCENC.h new file mode 100644 index 0000000..f55e2af --- /dev/null +++ b/serialization/OEMCryptoCENC.h @@ -0,0 +1,4334 @@ +// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine Master +// License Agreement. + +/********************************************************************* + * OEMCryptoCENC.h + * + * Reference APIs needed to support Widevine's crypto algorithms. + * + * See the document "WV Modular DRM Security Integration Guide for Common + * Encryption (CENC) -- version 15" for a description of this API. You + * can find this document in the widevine repository as + * docs/WidevineModularDRMSecurityIntegrationGuideforCENC_v15.pdf + * Changes between different versions of this API are documented in the files + * docs/Widevine_Modular_DRM_Version_*_Delta.pdf + * + *********************************************************************/ + +#ifndef OEMCRYPTO_CENC_H_ +#define OEMCRYPTO_CENC_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint32_t OEMCrypto_SESSION; + +typedef enum OEMCryptoResult { + OEMCrypto_SUCCESS = 0, + OEMCrypto_ERROR_INIT_FAILED = 1, + OEMCrypto_ERROR_TERMINATE_FAILED = 2, + OEMCrypto_ERROR_OPEN_FAILURE = 3, + OEMCrypto_ERROR_CLOSE_FAILURE = 4, + OEMCrypto_ERROR_ENTER_SECURE_PLAYBACK_FAILED = 5, // deprecated + OEMCrypto_ERROR_EXIT_SECURE_PLAYBACK_FAILED = 6, // deprecated + OEMCrypto_ERROR_SHORT_BUFFER = 7, + OEMCrypto_ERROR_NO_DEVICE_KEY = 8, // no keybox device key. + OEMCrypto_ERROR_NO_ASSET_KEY = 9, + OEMCrypto_ERROR_KEYBOX_INVALID = 10, + OEMCrypto_ERROR_NO_KEYDATA = 11, + OEMCrypto_ERROR_NO_CW = 12, + OEMCrypto_ERROR_DECRYPT_FAILED = 13, + OEMCrypto_ERROR_WRITE_KEYBOX = 14, + OEMCrypto_ERROR_WRAP_KEYBOX = 15, + OEMCrypto_ERROR_BAD_MAGIC = 16, + OEMCrypto_ERROR_BAD_CRC = 17, + OEMCrypto_ERROR_NO_DEVICEID = 18, + OEMCrypto_ERROR_RNG_FAILED = 19, + OEMCrypto_ERROR_RNG_NOT_SUPPORTED = 20, + OEMCrypto_ERROR_SETUP = 21, + OEMCrypto_ERROR_OPEN_SESSION_FAILED = 22, + OEMCrypto_ERROR_CLOSE_SESSION_FAILED = 23, + OEMCrypto_ERROR_INVALID_SESSION = 24, + OEMCrypto_ERROR_NOT_IMPLEMENTED = 25, + OEMCrypto_ERROR_NO_CONTENT_KEY = 26, + OEMCrypto_ERROR_CONTROL_INVALID = 27, + OEMCrypto_ERROR_UNKNOWN_FAILURE = 28, + OEMCrypto_ERROR_INVALID_CONTEXT = 29, + OEMCrypto_ERROR_SIGNATURE_FAILURE = 30, + OEMCrypto_ERROR_TOO_MANY_SESSIONS = 31, + OEMCrypto_ERROR_INVALID_NONCE = 32, + OEMCrypto_ERROR_TOO_MANY_KEYS = 33, + OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED = 34, + OEMCrypto_ERROR_INVALID_RSA_KEY = 35, + OEMCrypto_ERROR_KEY_EXPIRED = 36, + OEMCrypto_ERROR_INSUFFICIENT_RESOURCES = 37, + OEMCrypto_ERROR_INSUFFICIENT_HDCP = 38, + OEMCrypto_ERROR_BUFFER_TOO_LARGE = 39, + OEMCrypto_WARNING_GENERATION_SKEW = 40, // Warning, not an error. + OEMCrypto_ERROR_GENERATION_SKEW = 41, + OEMCrypto_LOCAL_DISPLAY_ONLY = 42, // Info, not an error. + OEMCrypto_ERROR_ANALOG_OUTPUT = 43, + OEMCrypto_ERROR_WRONG_PST = 44, + OEMCrypto_ERROR_WRONG_KEYS = 45, + OEMCrypto_ERROR_MISSING_MASTER = 46, + OEMCrypto_ERROR_LICENSE_INACTIVE = 47, + OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE = 48, + OEMCrypto_ERROR_ENTRY_IN_USE = 49, + OEMCrypto_ERROR_USAGE_TABLE_UNRECOVERABLE = 50, // Reserved. Do not use. + OEMCrypto_KEY_NOT_LOADED = 51, // obsolete. use error 26. + OEMCrypto_KEY_NOT_ENTITLED = 52, + OEMCrypto_ERROR_BAD_HASH = 53, + OEMCrypto_ERROR_OUTPUT_TOO_LARGE = 54, + OEMCrypto_ERROR_SESSION_LOST_STATE = 55, + OEMCrypto_ERROR_SYSTEM_INVALIDATED = 56, +} OEMCryptoResult; + +/* + * The memory referenced by SharedMemory* is safe to be placed in + * shared memory. The only data that should be placed into shared + * memory is the contents of input/output buffers, i.e. data that will + * not introduce security vulnerabilities if it is subject to + * modification while being accessed. + */ +typedef uint8_t SharedMemory; + +/* + * OEMCrypto_DestBufferDesc + * Describes the type and access information for the memory to receive + * decrypted data. + * + * The OEMCrypto API supports a range of client device architectures. + * Different architectures have different methods for acquiring and securing + * buffers that will hold portions of the audio or video stream after + * decryption. Three basic strategies are recognized for handling decrypted + * stream data: + * 1. Return the decrypted data in the clear into normal user memory + * (ClearBuffer). The caller uses normal memory allocation methods to + * acquire a buffer, and supplies the memory address of the buffer in the + * descriptor. + * 2. Place the decrypted data into protected memory (SecureBuffer). The + * caller uses a platform-specific method to acquire the protected buffer + * and a user-memory handle that references it. The handle is supplied + * to the decrypt call in the descriptor. If the buffer is filled with + * several OEMCrypto calls, the same handle will be used, and the offset + * will be incremented to indicate where the next write should take place. + * 3. Place the decrypted data directly into the audio or video decoder fifo + * (Direct). The caller will use platform-specific methods to initialize + * the fifo and the decoders. The decrypted stream data is not accessible + * to the caller. + * + * Specific fields are as follows: + * + * (type == OEMCrypto_BufferType_Clear) + * address - Address of start of user memory buffer. + * max_length - Size of user memory buffer. + * (type == OEMCrypto_BufferType_Secure) + * handle - handle to a platform-specific secure buffer. + * max_length - Size of platform-specific secure buffer. + * offset - offset from beginning of buffer to which OEMCrypto should write. + * (type == OEMCrypto_BufferType_Direct) + * is_video - If true, decrypted bytes are routed to the video + * decoder. If false, decrypted bytes are routed to the + * audio decoder. + */ +typedef enum OEMCryptoBufferType { + OEMCrypto_BufferType_Clear, + OEMCrypto_BufferType_Secure, + OEMCrypto_BufferType_Direct +} OEMCryptoBufferType; + +typedef struct { + OEMCryptoBufferType type; + union { + struct { // type == OEMCrypto_BufferType_Clear + SharedMemory* address; + size_t max_length; + } clear; + struct { // type == OEMCrypto_BufferType_Secure + void* handle; + size_t max_length; + size_t offset; + } secure; + struct { // type == OEMCrypto_BufferType_Direct + bool is_video; + } direct; + } buffer; +} OEMCrypto_DestBufferDesc; + +/** OEMCryptoCipherMode is used in SelectKey to prepare a key for either CTR + * decryption or CBC decryption. + */ +typedef enum OEMCryptoCipherMode { + OEMCrypto_CipherMode_CTR, + OEMCrypto_CipherMode_CBC, +} OEMCryptoCipherMode; + +/** OEMCrypto_LicenseType is used in LoadKeys to indicate if the key objects + * are for content keys, or for entitlement keys. + */ +typedef enum OEMCrypto_LicenseType { + OEMCrypto_ContentLicense = 0, + OEMCrypto_EntitlementLicense = 1 +} OEMCrypto_LicenseType; + +/* + * OEMCrypto_Substring + * + * Used to indicate a substring of a signed message in OEMCrypto_LoadKeys and + * other functions which must verify that a parameter is contained within a + * signed message. + */ +typedef struct { + size_t offset; + size_t length; +} OEMCrypto_Substring; + +/* + * OEMCrypto_KeyObject + * Points to the relevant fields for a content key. The fields are extracted + * from the License Response message offered to OEMCrypto_LoadKeys(). Each + * field points to one of the components of the key. Key data, key control, + * and both IV fields are 128 bits (16 bytes): + * key_id - the unique id of this key. + * key_id_length - the size of key_id. OEMCrypto may assume this is at + * most 16. However, OEMCrypto shall correctly handle key id lengths + * from 1 to 16 bytes. + * key_data_iv - the IV for performing AES-128-CBC decryption of the + * key_data field. + * key_data - the key data. It is encrypted (AES-128-CBC) with the + * session's derived encrypt key and the key_data_iv. + * key_control_iv - the IV for performing AES-128-CBC decryption of the + * key_control field. + * key_control - the key control block. It is encrypted (AES-128-CBC) with + * the content key from the key_data field. + * + * The memory for the OEMCrypto_KeyObject fields is allocated and freed + * by the caller of OEMCrypto_LoadKeys(). + */ +typedef struct { + OEMCrypto_Substring key_id; + OEMCrypto_Substring key_data_iv; + OEMCrypto_Substring key_data; + OEMCrypto_Substring key_control_iv; + OEMCrypto_Substring key_control; +} OEMCrypto_KeyObject; + +/* + * OEMCrypto_EntitledContentKeyObject + * Contains encrypted content key data for loading into the sessions keytable. + * The content key data is encrypted using AES-256-CBC encryption, with PKCS#7 + * padding. + * entitlement_key_id - entitlement key id to be matched to key table. + * entitlement_key_id_length - length of entitlment_key_id in bytes (1 to 16). + * content_key_id - content key id to be loaded into key table. + * content_key_id_length - length of content key id in bytes (1 to 16). + * key_data_iv - the IV for performing AES-256-CBC decryption of the key data. + * key_data - encrypted content key data. + * key_data_length - length of key_data - 16 or 32 depending on intended use. + */ +typedef struct { + OEMCrypto_Substring entitlement_key_id; + OEMCrypto_Substring content_key_id; + OEMCrypto_Substring content_key_data_iv; + OEMCrypto_Substring content_key_data; +} OEMCrypto_EntitledContentKeyObject; + +/* + * OEMCrypto_KeyRefreshObject + * Points to the relevant fields for renewing a content key. The fields are + * extracted from the License Renewal Response message offered to + * OEMCrypto_RefreshKeys(). Each field points to one of the components of + * the key. + * key_id - the unique id of this key. + * key_control_iv - the IV for performing AES-128-CBC decryption of the + * key_control field. 16 bytes. + * key_control - the key control block. It is encrypted (AES-128-CBC) with + * the content key from the key_data field. 16 bytes. + * + * The key_data is unchanged from the original OEMCrypto_LoadKeys() call. Some + * Key Control Block fields, especially those related to key lifetime, may + * change. + * + * The memory for the OEMCrypto_KeyRefreshObject fields is allocated and freed + * by the caller of OEMCrypto_RefreshKeys(). + */ +typedef struct { + OEMCrypto_Substring key_id; + OEMCrypto_Substring key_control_iv; + OEMCrypto_Substring key_control; +} OEMCrypto_KeyRefreshObject; + +/* + * OEMCrypto_Algorithm + * This is a list of valid algorithms for OEMCrypto_Generic_* functions. + * Some are valid for encryption/decryption, and some for signing/verifying. + */ +typedef enum OEMCrypto_Algorithm { + OEMCrypto_AES_CBC_128_NO_PADDING = 0, + OEMCrypto_HMAC_SHA256 = 1, +} OEMCrypto_Algorithm; + +/* + * Flags indicating data endpoints in OEMCrypto_DecryptCENC. + */ +#define OEMCrypto_FirstSubsample 1 +#define OEMCrypto_LastSubsample 2 + +/* OEMCrypto_CENCEncryptPatternDesc + * This is used in OEMCrypto_DecryptCENC to indicate the encrypt/skip pattern + * used, as specified in the CENC standard. + */ +typedef struct { + size_t encrypt; // number of 16 byte blocks to decrypt. + size_t skip; // number of 16 byte blocks to leave in clear. + size_t offset; // offset into the pattern in blocks for this call. +} OEMCrypto_CENCEncryptPatternDesc; + +/* + * OEMCrypto_Usage_Entry_Status. + * Valid values for status in the usage table. + */ +typedef enum OEMCrypto_Usage_Entry_Status { + kUnused = 0, + kActive = 1, + kInactive = 2, // Deprecated. Used kInactiveUsed or kInactiveUnused. + kInactiveUsed = 3, + kInactiveUnused = 4, +} OEMCrypto_Usage_Entry_Status; + +/* + * OEMCrypto_PST_Report is used to report an entry from the Usage Table. + * + * Platforms that have compilers that support packed structures, may use the + * following definition. Other platforms may use the header pst_report.h which + * defines a wrapper class. + * + * All fields are in network byte order. + */ +#if 0 // If your compiler supports __attribute__((packed)). +typedef struct { + uint8_t signature[20]; // -- HMAC SHA1 of the rest of the report. + uint8_t status; // current status of entry. (OEMCrypto_Usage_Entry_Status) + uint8_t clock_security_level; + uint8_t pst_length; + uint8_t padding; // make int64's word aligned. + int64_t seconds_since_license_received; // now - time_of_license_received + int64_t seconds_since_first_decrypt; // now - time_of_first_decrypt + int64_t seconds_since_last_decrypt; // now - time_of_last_decrypt + uint8_t pst[]; +} __attribute__((packed)) OEMCrypto_PST_Report; +#endif + +/* + * OEMCrypto_Clock_Security_Level. + * Valid values for clock_security_level in OEMCrypto_PST_Report. + */ +typedef enum OEMCrypto_Clock_Security_Level { + kInsecureClock = 0, + kSecureTimer = 1, + kSecureClock = 2, + kHardwareSecureClock = 3 +} OEMCrypto_Clock_Security_Level; + +typedef uint8_t RSA_Padding_Scheme; +#ifndef NO_OEMCRYPTO_VARIABLE_DEFINITIONS +// RSASSA-PSS with SHA1. +const RSA_Padding_Scheme kSign_RSASSA_PSS = 0x1; +// PKCS1 with block type 1 padding (only). +const RSA_Padding_Scheme kSign_PKCS1_Block1 = 0x2; +#else +#define kSign_RSASSA_PSS 0x1 +#define kSign_PKCS1_Block1 0x2 +#endif + +/* + * OEMCrypto_HDCP_Capability is used in the key control block to enforce HDCP + * level, and in GetHDCPCapability for reporting. + */ +typedef enum OEMCrypto_HDCP_Capability { + HDCP_NONE = 0, // No HDCP supported, no secure data path. + HDCP_V1 = 1, // HDCP version 1.0 + HDCP_V2 = 2, // HDCP version 2.0 Type 1. + HDCP_V2_1 = 3, // HDCP version 2.1 Type 1. + HDCP_V2_2 = 4, // HDCP version 2.2 Type 1. + HDCP_V2_3 = 5, // HDCP version 2.3 Type 1. + HDCP_NO_DIGITAL_OUTPUT = 0xff // No digital output. +} OEMCrypto_HDCP_Capability; + +/* Return value for OEMCrypto_GetProvisioningMethod(). */ +typedef enum OEMCrypto_ProvisioningMethod { + OEMCrypto_ProvisioningError = 0, // Device cannot be provisioned. + OEMCrypto_DrmCertificate = 1, // Device has baked in DRM certificate + // (level 3 only) + OEMCrypto_Keybox = 2, // Device has factory installed unique keybox. + OEMCrypto_OEMCertificate = 3 // Device has factory installed OEM certificate. +} OEMCrypto_ProvisioningMethod; + +/* + * Flags indicating RSA keys supported. + */ +#define OEMCrypto_Supports_RSA_2048bit 0x1 +#define OEMCrypto_Supports_RSA_3072bit 0x2 +#define OEMCrypto_Supports_RSA_CAST 0x10 + +/* + * Flags indicating full decrypt path hash supported. + */ +#ifndef NO_OEMCRYPTO_VARIABLE_DEFINITIONS +const uint32_t OEMCrypto_Hash_Not_Supported = 0; +const uint32_t OEMCrypto_CRC_Clear_Buffer = 1; +const uint32_t OEMCrypto_Partner_Defined_Hash = 2; +#else +#define OEMCrypto_Hash_Not_Supported 0 +#define OEMCrypto_CRC_Clear_Buffer 1 +#define OEMCrypto_Partner_Defined_Hash 2 +#endif + +/* + * Return values from OEMCrypto_GetAnalogOutputFlags. + */ +#define OEMCrypto_No_Analog_Output 0x0 +#define OEMCrypto_Supports_Analog_Output 0x1 +#define OEMCrypto_Can_Disable_Analog_Ouptput 0x2 +#define OEMCrypto_Supports_CGMS_A 0x4 +// Unknown_Analog_Output is used only for backwards compatibility. +#define OEMCrypto_Unknown_Analog_Output (1<<31) + +/* + * Obfuscation Renames. + */ +#define OEMCrypto_Initialize _oecc01 +#define OEMCrypto_Terminate _oecc02 +#define OEMCrypto_InstallKeybox _oecc03 +// Rename InstallKeybox to InstallKeyboxOrOEMCert. +#define OEMCrypto_InstallRootKeyCertificate _oecc03 +#define OEMCrypto_InstallKeyboxOrOEMCert _oecc03 +#define OEMCrypto_GetKeyData _oecc04 +#define OEMCrypto_IsKeyboxValid _oecc05 +// Rename IsKeyboxValid to IsKeyboxOrOEMCertValid. +#define OEMCrypto_IsRootKeyCertificateValid _oecc05 +#define OEMCrypto_IsKeyboxOrOEMCertValid _oecc05 +#define OEMCrypto_GetRandom _oecc06 +#define OEMCrypto_GetDeviceID _oecc07 +#define OEMCrypto_WrapKeybox _oecc08 +// Rename WrapKeybox to WrapKeyboxOrOEMCert +#define OEMCrypto_WrapRootKeyCertificate _oecc08 +#define OEMCrypto_WrapKeyboxOrOEMCert _oecc08 +#define OEMCrypto_OpenSession _oecc09 +#define OEMCrypto_CloseSession _oecc10 +#define OEMCrypto_DecryptCTR_V10 _oecc11 +#define OEMCrypto_GenerateDerivedKeys _oecc12 +#define OEMCrypto_GenerateSignature _oecc13 +#define OEMCrypto_GenerateNonce _oecc14 +#define OEMCrypto_LoadKeys_V8 _oecc15 +#define OEMCrypto_RefreshKeys_V14 _oecc16 +#define OEMCrypto_SelectKey_V13 _oecc17 +#define OEMCrypto_RewrapDeviceRSAKey _oecc18 +#define OEMCrypto_LoadDeviceRSAKey _oecc19 +#define OEMCrypto_GenerateRSASignature_V8 _oecc20 +#define OEMCrypto_DeriveKeysFromSessionKey _oecc21 +#define OEMCrypto_APIVersion _oecc22 +#define OEMCrypto_SecurityLevel _oecc23 +#define OEMCrypto_Generic_Encrypt _oecc24 +#define OEMCrypto_Generic_Decrypt _oecc25 +#define OEMCrypto_Generic_Sign _oecc26 +#define OEMCrypto_Generic_Verify _oecc27 +#define OEMCrypto_GetHDCPCapability_V9 _oecc28 +#define OEMCrypto_SupportsUsageTable _oecc29 +#define OEMCrypto_UpdateUsageTable _oecc30 +#define OEMCrypto_DeactivateUsageEntry_V12 _oecc31 +#define OEMCrypto_ReportUsage _oecc32 +#define OEMCrypto_DeleteUsageEntry _oecc33 +#define OEMCrypto_DeleteOldUsageTable _oecc34 +#define OEMCrypto_LoadKeys_V9_or_V10 _oecc35 +#define OEMCrypto_GenerateRSASignature _oecc36 +#define OEMCrypto_GetMaxNumberOfSessions _oecc37 +#define OEMCrypto_GetNumberOfOpenSessions _oecc38 +#define OEMCrypto_IsAntiRollbackHwPresent _oecc39 +#define OEMCrypto_CopyBuffer_V14 _oecc40 +#define OEMCrypto_QueryKeyControl _oecc41 +#define OEMCrypto_LoadTestKeybox_V13 _oecc42 +#define OEMCrypto_ForceDeleteUsageEntry _oecc43 +#define OEMCrypto_GetHDCPCapability _oecc44 +#define OEMCrypto_LoadTestRSAKey _oecc45 +#define OEMCrypto_Security_Patch_Level _oecc46 +#define OEMCrypto_LoadKeys_V11_or_V12 _oecc47 +#define OEMCrypto_DecryptCENC _oecc48 +#define OEMCrypto_GetProvisioningMethod _oecc49 +#define OEMCrypto_GetOEMPublicCertificate _oecc50 +#define OEMCrypto_RewrapDeviceRSAKey30 _oecc51 +#define OEMCrypto_SupportedCertificates _oecc52 +#define OEMCrypto_IsSRMUpdateSupported _oecc53 +#define OEMCrypto_GetCurrentSRMVersion _oecc54 +#define OEMCrypto_LoadSRM _oecc55 +#define OEMCrypto_LoadKeys_V13 _oecc56 +#define OEMCrypto_RemoveSRM _oecc57 +#define OEMCrypto_CreateUsageTableHeader _oecc61 +#define OEMCrypto_LoadUsageTableHeader _oecc62 +#define OEMCrypto_CreateNewUsageEntry _oecc63 +#define OEMCrypto_LoadUsageEntry _oecc64 +#define OEMCrypto_UpdateUsageEntry _oecc65 +#define OEMCrypto_DeactivateUsageEntry _oecc66 +#define OEMCrypto_ShrinkUsageTableHeader _oecc67 +#define OEMCrypto_MoveEntry _oecc68 +#define OEMCrypto_CopyOldUsageEntry _oecc69 +#define OEMCrypto_CreateOldUsageEntry _oecc70 +#define OEMCrypto_GetAnalogOutputFlags _oecc71 +#define OEMCrypto_LoadTestKeybox _oecc78 +#define OEMCrypto_LoadEntitledContentKeys_V14 _oecc79 +#define OEMCrypto_SelectKey _oecc81 +#define OEMCrypto_LoadKeys_V14 _oecc82 +#define OEMCrypto_LoadKeys _oecc83 +#define OEMCrypto_SetSandbox _oecc84 +#define OEMCrypto_ResourceRatingTier _oecc85 +#define OEMCrypto_SupportsDecryptHash _oecc86 +#define OEMCrypto_InitializeDecryptHash _oecc87 +#define OEMCrypto_SetDecryptHash _oecc88 +#define OEMCrypto_GetHashErrorCode _oecc89 +#define OEMCrypto_BuildInformation _oecc90 +#define OEMCrypto_RefreshKeys _oecc91 +#define OEMCrypto_LoadEntitledContentKeys _oecc92 +#define OEMCrypto_CopyBuffer _oecc93 + +/* + * OEMCrypto_SetSandbox + * + * Description: + * This tells OEMCrypto which sandbox the current process belongs to. Any + * persistent memory used to store the generation number should be associated + * with this sandbox id. OEMCrypto can assume that this sandbox will be tied + * to the current process or VM until OEMCrypto_Terminate is called. See the + * section "VM and Sandbox Support" above for more details. + * + * If OEMCrypto does not support sandboxes, it will return + * OEMCrypto_ERROR_NOT_IMPLEMENTED. On most platforms, this function will + * just return OEMCrypto_ERROR_NOT_IMPLEMENTED. If OEMCrypto supports + * sandboxes, this function returns OEMCrypto_SUCCESS on success, and + * OEMCrypto_ERROR_UNKNOWN_FAILURE on failure. + * + * The CDM layer will call OEMCrypto_SetSandbox once before + * OEMCrypto_Initialize. After this function is called and returns success, + * it will be OEMCrypto's responsibility to keep calls to usage table + * functions separate, and to accept a call to OEMCrypto_Terminate for each + * sandbox. + * + * Parameters: + * [in] sandbox_id: a short string unique to the current sandbox. + * [in] sandbox_id_length: length of sandbox_id. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_INIT_FAILED failed to initialize crypto hardware + * OEMCrypto_ERROR_NOT_IMPLEMENTED - sandbox functionality not supported + * + * Threading: + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. It is called once before + * OEMCrypto_Initialize. + * + * Version: + * This method is new in version 15 of the API. + */ +OEMCryptoResult OEMCrypto_SetSandbox(const uint8_t* sandbox_id, + size_t sandbox_id_length); + +/* + * OEMCrypto_Initialize + * + * Description: + * Initialize the crypto firmware/hardware. + * + * Parameters: + * None + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_INIT_FAILED failed to initialize crypto hardware + * + * Threading: + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. + * + * Version: + * This method is supported by all API versions. + */ +OEMCryptoResult OEMCrypto_Initialize(void); + +/* + * OEMCrypto_Terminate + * + * Description: + * Closes the crypto operation and releases all related resources. + * + * Parameters: + * None + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_TERMINATE_FAILED failed to de-initialize crypto hardware + * + * Threading: + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. No other functions will be called before the + * system is re-initialized. + * + * Version: + * This method is supported by all API versions. + */ +OEMCryptoResult OEMCrypto_Terminate(void); + +/* + * OEMCrypto_OpenSession + * + * Description: + * Open a new crypto security engine context. The security engine hardware + * and firmware shall acquire resources that are needed to support the + * session, and return a session handle that identifies that session in + * future calls. + * + * Parameters: + * [out] session: an opaque handle that the crypto firmware uses to identify + * the session. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_TOO_MANY_SESSIONS failed because too many sessions are open + * OEMCrypto_ERROR_OPEN_SESSION_FAILED there is a resource issue or the + * security engine is not properly initialized. + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Session Initialization Function" and will not be called + * simultaneously with any other function, as if the CDM holds a write lock + * on the OEMCrypto system. + * + * Version: + * This method changed in API version 5. + */ +OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session); + +/* + * OEMCrypto_CloseSession + * + * Description: + * Closes the crypto security engine session and frees any associated + * resources. If this session is associated with a Usage Entry, all resident + * memory associated with it will be freed. It is the CDM layer's + * responsibility to call OEMCrypto_UpdateUsageEntry before closing the + * session. + * + * Parameters: + * [in] session: handle for the session to be closed. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_INVALID_SESSION no open session with that id. + * OEMCrypto_ERROR_CLOSE_SESSION_FAILED illegal/unrecognized handle or the + * security engine is not properly initialized. + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Session Initialization Function" and will not be called + * simultaneously with any other function, as if the CDM holds a write lock + * on the OEMCrypto system. + * + * Version: + * This method changed in API version 13. + */ +OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session); + +/* + * OEMCrypto_GenerateDerivedKeys + * + * Description: + * Generates three secondary keys, mac_key[server], mac_key[client], and + * encrypt_key, for handling signing and content key decryption under the + * license server protocol for CENC. + * + * Refer to the Key Derivation section above for more details. This function + * computes the AES-128-CMAC of the enc_key_context and stores it in secure + * memory as the encrypt_key. It then computes four cycles of AES-128-CMAC of + * the mac_key_context and stores it in the mac_keys -- the first two cycles + * generate the mac_key[server] and the second two cycles generate the + * mac_key[client]. These two keys will be stored until the next call to + * OEMCrypto_LoadKeys(). The device key from the keybox is used as the key + * for the AES-128-CMAC. + * + * Parameters: + * [in] session: handle for the session to be used. + * [in] mac_key_context: pointer to memory containing context data for + * computing the HMAC generation key. + * [in] mac_key_context_length: length of the HMAC key context data, in bytes. + * [in] enc_key_context: pointer to memory containing context data for + * computing the encryption key. + * [in] enc_key_context_length: length of the encryption key context data, in + * bytes. + * + * Results: + * mac_key[server]: the 256 bit mac key is generated and stored in secure + * memory. + * mac_key[client]: the 256 bit mac key is generated and stored in secure + * memory. + * enc_key: the 128 bit encryption key is generated and stored in secure + * memory. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_NO_DEVICE_KEY + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_INVALID_CONTEXT + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support mac_key_context and enc_key_context sizes of at + * least 8 KiB. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffers are + * too large. + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method changed in API version 12. + */ +OEMCryptoResult OEMCrypto_GenerateDerivedKeys(OEMCrypto_SESSION session, + const SharedMemory* mac_key_context, + uint32_t mac_key_context_length, + const SharedMemory* enc_key_context, + uint32_t enc_key_context_length); + +/* + * OEMCrypto_DeriveKeysFromSessionKey + * + * Description: + * Generates three secondary keys, mac_key[server], mac_key[client] and + * encrypt_key, for handling signing and content key decryption under the + * license server protocol for CENC. + * + * This function is similar to OEMCrypto_GenerateDerivedKeys, except that it + * uses a session key to generate the secondary keys instead of the Widevine + * Keybox device key. These three keys will be stored in secure memory until + * the next call to LoadKeys. The session key is passed in encrypted by the + * device RSA public key, and must be decrypted with the RSA private key + * before use. + * + * Once the enc_key and mac_keys have been generated, all calls to LoadKeys + * and RefreshKeys proceed in the same manner for license requests using RSA + * or using a Widevine keybox token. + * + * Verification: + * If the RSA key's allowed_schemes is not kSign_RSASSA_PSS, then no keys are + * derived and the error OEMCrypto_ERROR_INVALID_RSA_KEY is returned. An RSA + * key cannot be used for both deriving session keys and also for PKCS1 + * signatures. + * + * Parameters: + * [in] session: handle for the session to be used. + * [in] enc_session_key: session key, encrypted with the public RSA key (from + * the DRM certifcate) using RSA-OAEP. + * [in] enc_session_key_length: length of session_key, in bytes. + * [in] mac_key_context: pointer to memory containing context data for + * computing the HMAC generation key. + * [in] mac_key_context_length: length of the HMAC key context data, in bytes. + * [in] enc_key_context: pointer to memory containing context data for + * computing the encryption key. + * [in] enc_key_context_length: length of the encryption key context data, in + * bytes. + * + * Results: + * mac_key[server]: the 256 bit mac key is generated and stored in secure + * memory. + * mac_key[client]: the 256 bit mac key is generated and stored in secure + * memory. + * enc_key: the 128 bit encryption key is generated and stored in secure + * memory. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_INVALID_CONTEXT + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support mac_key_context and enc_key_context sizes of at + * least 8 KiB. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffers are + * too large. + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method changed in API version 12. + */ +OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( + OEMCrypto_SESSION session, const uint8_t* enc_session_key, + size_t enc_session_key_length, const SharedMemory* mac_key_context, + size_t mac_key_context_length, const SharedMemory* enc_key_context, + size_t enc_key_context_length); + +/* + * OEMCrypto_GenerateNonce + * + * Description: + * Generates a 32-bit nonce to detect possible replay attack on the key + * control block. The nonce is stored in secure memory and will be used for + * the next call to LoadKeys. + * + * Because the nonce will be used to prevent replay attacks, it is desirable + * that a rogue application cannot rapidly call this function until a + * repeated nonce is created randomly. With this in mind, if more than 20 + * nonces are requested within one second, OEMCrypto will return an error + * after the 20th and not generate any more nonces for the rest of the + * second. After an error, if the application waits at least one second + * before requesting more nonces, then OEMCrypto will reset the error + * condition and generate valid nonces again. + * + * Parameters: + * [in] session: handle for the session to be used. + * [out] nonce: pointer to memory to receive the computed nonce. + * + * Results: + * nonce: the nonce is also stored in secure memory. At least 4 nonces should + * be stored for each session. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method changed in API version 5. + */ +OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, + uint32_t* nonce); + +/* + * OEMCrypto_GenerateSignature + * + * Description: + * Generates a HMAC-SHA256 signature using the mac_key[client] for license + * request signing under the license server protocol for CENC. + * + * The key used for signing should be the mac_key[client] that was generated + * for this session or loaded for this session by the most recent successful + * call to any one of + * + * - OEMCrypto_GenerateDerivedKeys, + * - OEMCrypto_DeriveKeysFromSessionKey, + * - OEMCrypto_LoadKeys, or + * - OEMCrypto_LoadUsageEntry. + * Refer to the Signing Messages Sent to a Server section above for more + * details. + * + * If a usage entry has been loaded, but keys have not been loaded through + * OEMCrypto_LoadKeys, then the derived mac keys and the keys in the usage + * entry may be different. In this case, the mac keys specified in the usage + * entry should be used. + * + * NOTE: if signature pointer is null and/or input signature_length set to + * zero, this function returns OEMCrypto_ERROR_SHORT_BUFFER and sets output + * signature_length to the size needed to receive the output signature. + * + * Parameters: + * [in] session: crypto session identifier. + * [in] message: pointer to memory containing message to be signed. + * [in] message_length: length of the message, in bytes. + * [out] signature: pointer to memory to received the computed signature. May + * be null (see note above). + * [in/out] signature_length: (in) length of the signature buffer, in bytes. + * (out) actual length of the signature, in bytes. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_SHORT_BUFFER if signature buffer is not large enough to + * hold the signature. + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support message sizes of at least 8 KiB. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method changed in API version 12. + */ +OEMCryptoResult OEMCrypto_GenerateSignature(OEMCrypto_SESSION session, + const SharedMemory* message, + size_t message_length, + uint8_t* signature, + size_t* signature_length); + +/* + * OEMCrypto_LoadSRM + * + * Description: + * Verify and install a new SRM file. The device shall install the new file + * only if verification passes. If verification fails, the existing SRM will + * be left in place. Verification is defined by DCP, and includes + * verification of the SRM's signature and verification that the SRM version + * number will not be decreased. See the section HDCP SRM Update above for + * more details about the SRM. This function is for devices that support HDCP + * v2.2 or higher and wish to receive 4k content. + * + * Parameters: + * [in] bufer: buffer containing the SRM + * [in] buffer_length: length of the SRM, in bytes. + * + * Returns: + * OEMCrypto_SUCCESS - if the file was valid and was installed. + * OEMCrypto_ERROR_INVALID_CONTEXT - if the SRM version is too low, or the + * file is corrupted. + * OEMCrypto_ERROR_SIGNATURE_FAILURE - If the signature is invalid. + * OEMCrypto_ERROR_BUFFER_TOO_LARGE - if the buffer is too large for the + * device. + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * The size of the buffer is determined by the HDCP specification. + * + * Threading: + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. + * + * Version: + * This method changed in API version 13. + */ +OEMCryptoResult OEMCrypto_LoadSRM(const uint8_t* buffer, size_t buffer_length); + +/* + * OEMCrypto_LoadKeys + * + * Description: + * Installs a set of keys for performing decryption in the current session. + * + * The relevant fields have been extracted from the License Response protocol + * message, but the entire message and associated signature are provided so + * the message can be verified (using HMAC-SHA256 with the derived + * mac_key[server]). If the signature verification fails, ignore all other + * arguments and return OEMCrypto_ERROR_SIGNATURE_FAILURE. Otherwise, add the + * keys to the session context. + * + * The keys will be decrypted using the current encrypt_key (AES-128-CBC) and + * the IV given in the KeyObject. Each key control block will be decrypted + * using the first 128 bits of the corresponding content key (AES-128-CBC) + * and the IV given in the KeyObject. + * + * If its length is not zero, enc_mac_keys will be used to create new + * mac_keys. After all keys have been decrypted and validated, the new + * mac_keys are decrypted with the current encrypt_key and the offered IV. + * The new mac_keys replaces the current mac_keys for future calls to + * OEMCrypto_RefreshKeys(). The first 256 bits of the mac_keys become the + * mac_key[server] and the following 256 bits of the mac_keys become the + * mac_key[client]. If enc_mac_keys is null, then there will not be a call to + * OEMCrypto_RefreshKeys for this session and the current mac_keys should + * remain unchanged. + * + * The mac_key and encrypt_key were generated and stored by the previous call + * to OEMCrypto_GenerateDerivedKeys() or + * OEMCrypto_DeriveKeysFromSessionKey(). The nonce was generated and stored + * by the previous call to OEMCrypto_GenerateNonce(). + * + * This session's elapsed time clock is started at 0. The clock will be used + * in OEMCrypto_DecryptCENC(). + * + * NOTE: The calling software must have previously established the mac_keys + * and encrypt_key with a call to OEMCrypto_GenerateDerivedKeys(), + * OEMCrypto_DeriveKeysFromSessionKey(), or a previous call to + * OEMCrypto_LoadKeys(). + * + * Refer to the Verification of Messages from a Server section above for more + * details. + * + * If the parameter license_type is OEMCrypto_ContentLicense, then the fields + * key_id and key_data in an OEMCrypto_KeyObject are loaded in to the + * content_key_id and content_key_data fields of the key table entry. In this + * case, entitlement key ids and entitlement key data is left blank. + * + * If the parameter license_type is OEMCrypto_EntitlementLicense, then the + * fields key_id and key_data in an OEMCrypto_KeyObject are loaded in to the + * entitlement_key_id and entitlement_key_data fields of the key table entry. + * In this case, content key ids and content key data will be loaded later + * with a call to OEMCrypto_LoadEntitledContentKeys(). + * + * OEMCrypto may assume that the key_id_length is at most 16. However, + * OEMCrypto shall correctly handle key id lengths from 1 to 16 bytes. + * + * OEMCrypto shall handle at least 20 keys per session. This allows a single + * license to contain separate keys for 3 key rotations (previous interval, + * current interval, next interval) times 4 content keys (audio, SD, HD, UHD) + * plus up to 8 keys for watermarks. + * + * Verification: + * The following checks should be performed. If any check fails, an error is + * returned, and none of the keys are loaded. + * + * 1. The signature of the message shall be computed, and the API shall + * verify the computed signature matches the signature passed in. If + * not, return OEMCrypto_ERROR_SIGNATURE_FAILURE. The signature + * verification shall use a constant-time algorithm (a signature + * mismatch will always take the same time as a successful comparison). + * 2. The enc_mac_keys substring must either have zero length, or satisfy + * the range check. I.e. (offset < message_length) && (offset + length + * < message_length) && (offset < offset+length),and offset+length does + * not cause an integer overflow. If it does not have zero length, then + * enc_mac_keys_iv must not have zero length, and must also satisfy the + * range check. If not, return OEMCrypto_ERROR_INVALID_CONTEXT. If the + * length is zero, then OEMCrypto may assume that the offset is also + * zero. + * 3. The API shall verify that each substring in each KeyObject points to + * a location in the message. I.e. (offset < message_length) && + * (offset + length < message_length) && (offset < offset+length) and + * offset+length does not cause an integer overflow, for each of key_id, + * key_data_iv, key_data, key_control_iv, key_control. If not, return + * OEMCrypto_ERROR_INVALID_CONTEXT. + * 4. Each key's control block, after decryption, shall have a valid + * verification field. If not, return OEMCrypto_ERROR_INVALID_CONTEXT. + * 5. If any key control block has the Nonce_Enabled bit set, that key's + * Nonce field shall match a nonce in the cache. If not, return + * OEMCrypto_ERROR_INVALID_NONCE. If there is a match, remove that + * nonce from the cache. Note that all the key control blocks in a + * particular call shall have the same nonce value. + * 6. If any key control block has the Require_AntiRollback_Hardware bit + * set, and the device does not protect the usage table from rollback, + * then do not load the keys and return OEMCrypto_ERROR_UNKNOWN_FAILURE. + * 7. If the key control block has a nonzero Replay_Control, then the + * verification described below is also performed. + * 8. If the key control block has the bit SRMVersionRequired is set, then + * the verification described below is also performed. If the SRM + * requirement is not met, then the key control block's HDCP_Version + * will be changed to 0xF - local display only. + * 9. If key_array_length == 0, then return OEMCrypto_ERROR_INVALID_CONTEXT. + * 10. If any key control block has the Shared_License bit set, and this + * call to LoadKeys is not replacing keys loaded from a previous call to + * LoadKeys, then the keys are not loaded, and the error + * OEMCrypto_ERROR_MISSING_MASTER is returned. This feature is obsolete, + * and no longer used by production license servers. OEMCrypto unit + * tests for this feature have been removed. + * 11. If this session is associated with a usage table entry, and that + * entry is marked as "inactive" (either kInactiveUsed or + * kInactiveUnused), then the keys are not loaded, and the error + * OEMCrypto_ERROR_LICENSE_INACTIVE is returned. + * Usage Table and Provider Session Token (pst) + * + * If a key control block has a nonzero value for Replay_Control, then all + * keys in this license will have the same value for Replay_Control. In this + * case, the following additional checks are performed. + * + * - The substring pst must have nonzero length and must satisfy the range + * check described above. If not, return + * OEMCrypto_ERROR_INVALID_CONTEXT. + * - The session must be associated with a usage table entry, either + * created via OEMCrypto_CreateNewUsageEntry or loaded via + * OEMCrypto_LoadUsageEntry. + * - If Replay_Control is 1 = Nonce_Required, then OEMCrypto will perform a + * nonce check as described above. OEMCrypto will verify that the + * usage entry is newly created with OEMCrypto_CreateNewUsageEntry. If + * an existing entry was reloaded, an error + * OEMCrypto_ERROR_INVALID_CONTEXT is returned and no keys are loaded. + * OEMCrypto will then copy the pst and the mac keys to the usage entry, + * and set the status to Unused. This Replay_Control prevents the + * license from being loaded more than once, and will be used for online + * streaming. + * - If Replay_Control is 2 = "Require existing Session Usage table entry + * or Nonce", then OEMCrypto will behave slightly differently on the + * first call to LoadKeys for this license. + * * If the usage entry was created with OEMCrypto_CreateNewUsageEntry + * for this session, then OEMCrypto will verify the nonce for each + * key. OEMCrypto will copy the pst and mac keys to the usage + * entry. The license received time of the entry will be updated + * to the current time, and the status will be set to Unused. + * * If the usage entry was loaded with OEMCrypto_LoadUsageEntry for + * this session, then OEMCrypto will NOT verify the nonce for each + * key. Instead, it will verify that the pst passed in matches + * that in the entry. Also, the entry's mac keys will be verified + * against the current session's mac keys. This allows an offline + * license to be reloaded but maintain continuity of the playback + * times from one session to the next. + * * If the nonce is not valid and a usage entry was not loaded, the + * return error is OEMCrypto_ERROR_INVALID_NONCE. + * * If the loaded usage entry has a pst that does not match, + * OEMCrypto returns the error OEMCrypto_ERROR_WRONG_PST. + * * If the loaded usage entry has mac keys that do not match the + * license, OEMCrypto returns the error OEMCrypto_ERROR_WRONG_KEYS. + * Note: If LoadKeys updates the mac keys, then the new updated mac keys will + * be used with the Usage Entry -- i.e. the new keys are stored in the + * usage table when creating a new entry, or the new keys are verified + * against those in the usage table if there is an existing entry. If + * LoadKeys does not update the mac keys, the existing session mac keys are + * used. + * + * Sessions that are associated with an entry will need to be able to update + * and verify the status of the entry, and the time stamps in the entry. + * + * Devices that do not support the Usage Table will return + * OEMCrypto_ERROR_INVALID_CONTEXT if the Replay_Control is nonzero. + * + * SRM Restriction Data + * + * If any key control block has the flag SRMVersionRequired set, then the + * following verification is also performed. + * + * 1. The substring srm_restriction_data must have nonzero length and must + * satisfy the range check described above. If not, return + * OEMCrypto_ERROR_INVALID_CONTEXT. + * 2. The first 8 bytes of srm_restriction_data must match the string + * "HDCPDATA". If not, return OEMCrypto_ERROR_INVALID_CONTEXT. + * 3. The next 4 bytes of srm_restriction_data will be converted from + * network byte order. If the current SRM installed on the device has a + * version number less than this, then the SRM requirement is not met. + * If the device does not support SRM files, or OEMCrypto cannot + * determine the current SRM version number, then the SRM requirement is + * not met. + * Note: if the current SRM version requirement is not met, LoadKeys will + * still succeed and the keys will be loaded. However, those keys with the + * SRMVersionRequired bit set will have their HDCP_Version increased to 0xF - + * local display only. Any future call to SelectKey for these keys while + * there is an external display will return OEMCrypto_ERROR_INSUFFICIENT_HDCP + * at that time. + * + * Parameters: + * [in] session: crypto session identifier. + * [in] message: pointer to memory containing message to be verified. + * [in] message_length: length of the message, in bytes. + * [in] signature: pointer to memory containing the signature. + * [in] signature_length: length of the signature, in bytes. + * [in] enc_mac_keys_iv: IV for decrypting new mac_key. Size is 128 bits. + * [in] enc_mac_keys: encrypted mac_keys for generating new mac_keys. Size is + * 512 bits. + * [in] key_array_length: number of keys present. + * [in] key_array: set of keys to be installed. + * [in] pst: the Provider Session Token. + * [in] srm_restriction_data: optional data specifying the minimum SRM + * version. + * [in] license_type: specifies if the license contains content keys or + * entitlement keys. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_NO_DEVICE_KEY + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_INVALID_CONTEXT + * OEMCrypto_ERROR_SIGNATURE_FAILURE + * OEMCrypto_ERROR_INVALID_NONCE + * OEMCrypto_ERROR_TOO_MANY_KEYS + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support message sizes of at least 8 KiB. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method changed in API version 14. + */ +OEMCryptoResult OEMCrypto_LoadKeys( + OEMCrypto_SESSION session, const SharedMemory* message, size_t message_length, + const SharedMemory* signature, size_t signature_length, + OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys, + size_t key_array_length, const OEMCrypto_KeyObject* key_array, + OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data, + OEMCrypto_LicenseType license_type); + +/* + * OEMCrypto_LoadEntitledContentKeys + * + * Description: + * Load content keys into a session which already has entitlement keys + * loaded. This function will only be called for a session after a call to + * OEMCrypto_LoadKeys with the parameter type license_type equal to + * OEMCrypto_EntitlementLicense. This function may be called multiple times + * for the same session. + * + * If the session does not have license_type equal to + * OEMCrypto_EntitlementLicense, return OEMCrypto_ERROR_INVALID_CONTEXT and + * perform no work. + * + * For each key object in key_array, OEMCrypto shall look up the entry in the + * key table with the corresponding entitlement_key_id. + * + * 1. If no entry is found, return OEMCrypto_KEY_NOT_ENTITLED. + * 2. If the entry already has a content_key_id and content_key_data, that + * id and data are erased. + * 3. The content_key_id from the key_array is copied to the entry's + * content_key_id. + * 4. The content_key_data decrypted using the entitlement_key_data as a + * key for AES-256-CBC with an IV of content_key_data_iv. Wrapped + * content is padded using PKCS#7 padding. Notice that the entitlement + * key will be an AES 256 bit key. The clear content key data will be + * stored in the entry's content_key_data. + * Entries in the key table that do not correspond to anything in the + * key_array are not modified or removed. + * + * For devices that use a hardware key ladder, it may be more convenient to + * store the encrypted content key data in the key table, and decrypt it when + * the function SelectKey is called. + * + * Parameters: + * [in] session: handle for the session to be used. + * [in] message: pointer to memory containing message to be verified. + * [in] message_length: length of the message, in bytes. + * [in] key_array_length: number of keys present. + * [in] key_array: set of key updates. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_INVALID_CONTEXT + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_KEY_NOT_ENTITLED + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method is new in API version 14. + */ +OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( + OEMCrypto_SESSION session, const SharedMemory* message, size_t message_length, + size_t key_array_length, const OEMCrypto_EntitledContentKeyObject* key_array); + +/* + * OEMCrypto_RefreshKeys + * + * Description: + * Updates an existing set of keys for continuing decryption in the current + * session. + * + * The relevant fields have been extracted from the Renewal Response protocol + * message, but the entire message and associated signature are provided so + * the message can be verified (using HMAC-SHA256 with the current + * mac_key[server]). If any verification step fails, an error is returned. + * Otherwise, the key table in trusted memory is updated using the + * key_control block. When updating an entry in the table, only the duration, + * nonce, and nonce_enabled fields are used. All other key control bits are + * not modified. + * + * NOTE: OEMCrypto_LoadKeys() must be called first to load the keys into the + * session. + * + * This session's elapsed time clock is reset to 0 when this function is + * called. The elapsed time clock is used in OEMCrypto_DecryptCENC() and the + * other Decryption API functions to determine if the key has expired. + * + * This function does not add keys to the key table. It is only used to + * update a key control block license duration. This function is used to + * update the duration of a key, only. It is not used to update key control + * bits. + * + * If the KeyRefreshObject's key_control_iv has zero length, then the + * key_control is not encrypted. If the key_control_iv is specified, then + * key_control is encrypted with the first 128 bits of the corresponding + * content key. + * + * If the KeyRefreshObject's key_id has zero length, then this refresh object + * should be used to update the duration of all keys for the current session. + * In this case, key_control_iv will also have zero length and the control + * block will not be encrypted. + * + * If the session's license_type is OEMCrypto_ContentLicense, and the + * KeyRefreshObject's key_id is not null, then the entry in the keytable with + * the matching content_key_id is updated. + * + * If the session's license_type is OEMCrypto_EntitlementLicense, and the + * KeyRefreshObject's key_id is not null, then the entry in the keytable with + * the matching entitlment_key_id is updated. + * + * If the key_id is not null, and no matching entry is found in the key + * table, then return OEMCrypto_ERROR_NO_CONTENT_KEY. + * + * Aside from the key's duration, no other values in the key control block + * should be updated by this function. + * + * Verification: + * The following checks should be performed. If any check fails, an error is + * returned, and none of the keys are loaded. + * 1. The signature of the message shall be computed using mac_key[server], + * and the API shall verify the computed signature matches the signature + * passed in. If not, return OEMCrypto_ERROR_SIGNATURE_FAILURE. The + * signature verification shall use a constant-time algorithm (a + * signature mismatch will always take the same time as a successful + * comparison). + * 2. The API shall verify that each substring in each KeyObject has zero + * length or satisfies the range check described in the discussion of + * OEMCrypto_LoadKeys. If not, return OEMCrypto_ERROR_INVALID_CONTEXT. + * 3. Each key's control block shall have a valid verification field. If + * not, return OEMCrypto_ERROR_INVALID_CONTEXT. + * 4. If the key control block has the Nonce_Enabled bit set, the Nonce + * field shall match one of the nonces in the cache. If not, return + * OEMCrypto_ERROR_INVALID_NONCE. If there is a match, remove that nonce + * from the cache. Note that all the key control blocks in a + * particular call shall have the same nonce value. + * 5. If a key ID is specified, and that key has not been loaded into this + * session, return OEMCrypto_ERROR_NO_CONTENT_KEY. + * + * Parameters: + * [in] session: handle for the session to be used. + * [in] message: pointer to memory containing message to be verified. + * [in] message_length: length of the message, in bytes. + * [in] signature: pointer to memory containing the signature. + * [in] signature_length: length of the signature, in bytes. + * [in] key_array_length: number of keys present. + * [in] key_array: set of key updates. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_NO_DEVICE_KEY + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_INVALID_CONTEXT + * OEMCrypto_ERROR_SIGNATURE_FAILURE + * OEMCrypto_ERROR_INVALID_NONCE + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_NO_CONTENT_KEY + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support message sizes of at least 8 KiB. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method changed in API version 12. + */ +OEMCryptoResult OEMCrypto_RefreshKeys( + OEMCrypto_SESSION session, const SharedMemory* message, size_t message_length, + const SharedMemory* signature, size_t signature_length, size_t key_array_length, + const OEMCrypto_KeyRefreshObject* key_array); + +/* + * OEMCrypto_QueryKeyControl + * + * Description: + * Returns the decrypted key control block for the given content_key_id. This + * function is for application developers to debug license server and key + * timelines. It only returns a key control block if LoadKeys was successful, + * otherwise it returns OEMCrypto_ERROR_NO_CONTENT_KEY. The developer of the + * OEMCrypto library must be careful that the keys themselves are not + * accidentally revealed. + * + * Note: returns control block in original, network byte order. If OEMCrypto + * converts fields to host byte order internally for storage, it should + * convert them back. Since OEMCrypto might not store the nonce or validation + * fields, values of 0 may be used instead. + * + * Verification: + * The following checks should be performed. + * 1. If key_id is null, return OEMCrypto_ERROR_INVALID_CONTEXT. + * 2. If key_control_block_length is null, return + * OEMCrypto_ERROR_INVALID_CONTEXT. + * 3. If *key_control_block_length is less than the length of a key control + * block, set it to the correct value, and return + * OEMCrypto_ERROR_SHORT_BUFFER. + * 4. If key_control_block is null, return OEMCrypto_ERROR_INVALID_CONTEXT. + * 5. If the specified key has not been loaded, return + * OEMCrypto_ERROR_NO_CONTENT_KEY. + * + * Parameters: + * [in] session: handle for the session to be used. + * [in] content_key_id: The unique id of the key of interest. + * [in] content_key_id_length: The length of key_id, in bytes. From 1 to 16, + * inclusive. + * [out] key_control_block: A caller-owned buffer. + * [in/out] key_control_block_length. The length of key_control_block buffer. + * + * Returns: + * OEMCrypto_SUCCESS + * OEMCrypto_ERROR_INVALID_CONTEXT + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method is new in API version 10. + */ +OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + uint8_t* key_control_block, + size_t* key_control_block_length); + +/* + * OEMCrypto_SelectKey + * + * Description: + * Select a content key and install it in the hardware key ladder for + * subsequent decryption operations (OEMCrypto_DecryptCENC()) for this + * session. The specified key must have been previously "installed" via + * OEMCrypto_LoadKeys() or OEMCrypto_RefreshKeys(). + * + * A key control block is associated with the key and the session, and is + * used to configure the session context. The Key Control data is documented + * in "Key Control Block Definition". + * + * Step 1: Lookup the content key data via the offered key_id. The key data + * includes the key value, and the key control block. + * + * Step 2: Latch the content key into the hardware key ladder. Set permission + * flags and timers based on the key's control block. + * + * Step 3: use the latched content key to decrypt (AES-128-CTR or + * AES-128-CBC) buffers passed in via OEMCrypto_DecryptCENC(). If the key is + * 256 bits it will be used for OEMCrypto_Generic_Sign or + * OEMCrypto_Generic_Verify as specified in the key control block. If the key + * will be used for OEMCrypto_Generic_Encrypt or OEMCrypto_Generic_Decrypt + * then the cipher mode will always be OEMCrypto_CipherMode_CBC. Continue to + * use this key for this session until OEMCrypto_SelectKey() is called again, + * or until OEMCrypto_CloseSession() is called. + * + * Verification: + * 1. If the key id is not found in the keytable for this session, then the + * key state is not changed and OEMCrypto shall return + * OEMCrypto_ERROR_NO_CONTENT_KEY. + * 2. If the current key's control block has a nonzero Duration field, then + * the API shall verify that the duration is greater than the session's + * elapsed time clock before the key is used. OEMCrypto may return + * OEMCrypto_ERROR_KEY_EXPIRED from OEMCrypto_SelectKey, or SelectKey + * may return success from select key and the decrypt or generic crypto + * call will return OEMCrypto_ERROR_KEY_EXPIRED. + * 3. If the key control block has the bit Disable_Analog_Output set, then + * the device should disable analog video output. If the device has + * analog video output that cannot be disabled, then the key is not + * selected, and OEMCrypto_ERROR_ANALOG_OUTPUT is returned. + * 4. If the key control block has HDCP required, and the device cannot + * enforce HDCP, then the key is not selected, and + * OEMCrypto_ERROR_INSUFFICIENT_HDCP is returned. + * 5. If the key control block has a nonzero value for HDCP_Version, and + * the device cannot enforce at least that version of HDCP, then the key + * is not selected, and OEMCrypto_ERROR_INSUFFICIENT_HDCP is returned. + * + * Parameters: + * [in] session: crypto session identifier. + * [in] content_key_id: pointer to the content Key ID. + * [in] content_key_id_length: length of the content Key ID, in bytes. From + * 1 to 16, inclusive. + * [in] cipher_mode: whether the key should be prepared for CTR mode or CBC + * mode when used in later calls to DecryptCENC. This should be ignored + * when the key is used for Generic Crypto calls. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_KEY_EXPIRED - if the key's timer has expired + * OEMCrypto_ERROR_INVALID_SESSION crypto session ID invalid or not open + * OEMCrypto_ERROR_NO_DEVICE_KEY failed to decrypt device key + * OEMCrypto_ERROR_NO_CONTENT_KEY failed to decrypt content key + * OEMCrypto_ERROR_CONTROL_INVALID invalid or unsupported control input + * OEMCrypto_ERROR_KEYBOX_INVALID cannot decrypt and read from Keybox + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_KEY_EXPIRED + * OEMCrypto_ERROR_ANALOG_OUTPUT + * OEMCrypto_ERROR_INSUFFICIENT_HDCP + * OEMCrypto_ERROR_NO_CONTENT_KEY + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method changed in API version 14. + */ +OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + OEMCryptoCipherMode cipher_mode); + +/* + * OEMCrypto_DecryptCENC + * + * Description: + * Decrypts or copies the payload in the buffer referenced by the *data_addr + * parameter into the buffer referenced by the out_buffer parameter, using + * the session context indicated by the session parameter. Decryption mode is + * AES-128-CTR or AES-128-CBC depending on the value of cipher_mode passed in + * to OEMCrypto_SelectKey. If is_encrypted is true, the content key + * associated with the session is latched in the active hardware key ladder + * and is used for the decryption operation. If is_encrypted is false, the + * data is simply copied. + * + * After decryption, the data_addr_length bytes are copied to the location + * described by out_buffer. This could be one of + * + * 1. The structure out_buffer contains a pointer to a clear text buffer. + * The OEMCrypto library shall verify that key control allows data to be + * returned in clear text. If it is not authorized, this method should + * return an error. + * 2. The structure out_buffer contains a handle to a secure buffer. + * 3. The structure out_buffer indicates that the data should be sent + * directly to the decoder and renderer. + * NOTES: + * + * For CTR mode, IV points to the counter value to be used for the initial + * encrypted block of the input buffer. The IV length is the AES block size. + * For subsequent encrypted AES blocks the IV is calculated by incrementing + * the lower 64 bits (byte 8-15) of the IV value used for the previous block. + * The counter rolls over to zero when it reaches its maximum value + * (0xFFFFFFFFFFFFFFFF). The upper 64 bits (byte 0-7) of the IV do not change. + * + * For CBC mode, IV points to the initial vector for cipher block chaining. + * Within each subsample, OEMCrypto is responsible for updating the IV as + * prescribed by CBC mode. The calling layer above is responsible for + * updating the IV from one subsample to the next if needed. + * + * This method may be called several times before the decrypted data is used. + * For this reason, the parameter subsample_flags may be used to optimize + * decryption. The first buffer in a chunk of data will have the + * OEMCrypto_FirstSubsample bit set in subsample_flags. The last buffer in a + * chunk of data will have the OEMCrypto_LastSubsample bit set in + * subsample_flags. The decrypted data will not be used until after + * OEMCrypto_LastSubsample has been set. If an implementation decrypts data + * immediately, it may ignore subsample_flags. + * + * If the destination buffer is secure, an offset may be specified. + * DecryptCENC begins storing data out_buffer->secure.offset bytes after the + * beginning of the secure buffer. + * + * If the session has an entry in the Usage Table, then OEMCrypto will update + * the time_of_last_decrypt. If the status of the entry is "unused", then + * change the status to "active" and set the time_of_first_decrypt. + * + * The decryption mode, either OEMCrypto_CipherMode_CTR or + * OEMCrypto_CipherMode_CBC, was specified in the call to + * OEMCrypto_SelectKey. The encryption pattern is specified by the fields in + * the parameter pattern. A description of partial encryption patterns can be + * found in the document Draft International Standard ISO/IEC DIS 23001-7. + * Search for the codes "cenc", "cbc1", "cens" or "cbcs". + * + * The most common mode is "cenc", which is OEMCrypto_CipherMode_CTR without + * a pattern. The entire subsample is either encrypted or clear, depending on + * the flag is_encrypted. In the structure pattern, both encrypt and skip + * will be 0. This is the only mode that allows for a nonzero block_offset. + * + * A less common mode is "cens", which is OEMCrypto_CipherMode_CTR with an + * encryption pattern. For this mode, OEMCrypto may assume that an encrypted + * subsample will have a length that is a multiple of 16, the AES block + * length. + * + * The mode "cbc1" is OEMCrypto_CipherMode_CBC without a pattern. In the + * structure pattern, both encrypt and skip will be 0. If an encrypted + * subsample has a length that is not a multiple of 16, the final partial + * block will be in the clear. + * + * The mode "cbcs" is OEMCrypto_CipherMode_CBC with an encryption pattern. + * This mode allows devices to decrypt HLS content. If an encrypted subsample + * has a length that is not a multiple of 16, the final partial block will be + * in the clear. In practice, the most common pattern is (1, 9), or 1 + * encrypted block followed by 9 clear blocks. The ISO-CENC spec implicitly + * limits both the skip and encrypt values to be 4 bits, so a value of at + * most 15. + * + * A sample may be broken up into a mix of clear and encrypted subsamples. In + * order to support the VP9 standard, the breakup of a subsample into clear + * and encrypted subsamples is not always in pairs. + * + * If OEMCrypto assembles all of the subsamples into a single buffer and then + * decrypts, it can assume that the block offset is 0. + * + * Verification: + * The following checks should be performed if is_encrypted is true. If any + * check fails, an error is returned, and no decryption is performed. + * 1. If the current key's control block has a nonzero Duration field, then + * the API shall verify that the duration is greater than the session's + * elapsed time clock. If not, return OEMCrypto_ERROR_KEY_EXPIRED. + * 2. If the current key's control block has the Data_Path_Type bit set, + * then the API shall verify that the output buffer is secure or direct. + * If not, return OEMCrypto_ERROR_DECRYPT_FAILED. + * 3. If the current key control block has the bit Disable_Analog_Output + * set, then the device should disable analog video output. If the + * device has analog video output that cannot be disabled, then + * OEMCrypto_ERROR_ANALOG_OUTPUT is returned. + * 4. If the current key's control block has the HDCP bit set, then the API + * shall verify that the buffer will be displayed locally, or output + * externally using HDCP only. If not, return + * OEMCrypto_ERROR_INSUFFICIENT_HDCP. + * 5. If the current key's control block has a nonzero value for + * HDCP_Version, then the current version of HDCP for the device and the + * display combined will be compared against the version specified in + * the control block. If the current version is not at least as high as + * that in the control block, then return + * OEMCrypto_ERROR_INSUFFICIENT_HDCP. + * 6. If the current session has an entry in the Usage Table, and the + * status of that entry is either kInactiveUsed or kInactiveUnused, then + * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. + * 7. If an Decrypt Hash has been initialized via OEMCrypto_SetDecryptHash, + * and the current key's control block does not have the + * Allow_Hash_Verification bit set, then do not compute a hash and + * return OEMCrypto_ERROR_UNKNOWN_FAILURE. + * If the flag is_encrypted is false, then no verification is performed. This + * call shall copy clear data even when there are no keys loaded, or there is + * no selected key. + * + * Parameters: + * [in] session: crypto session identifier. + * [in] data_addr: An unaligned pointer to this segment of the stream. + * [in] data_addr_length: The length of this segment of the stream, in bytes. + * [in] is_encrypted: True if the buffer described by data_addr, + * data_addr_length is encrypted. If is_encrypted is false, only the + * data_addr and data_addr_length parameters are used. The iv and offset + * arguments are ignored. + * [in] iv: The initial value block to be used for content decryption. + * This is discussed further below. + * [in] block_offset: If non-zero, the decryption block boundary is different + * from the start of the data. block_offset should be subtracted from + * data_addr to compute the starting address of the first decrypted + * block. The bytes between the decryption block start address and + * data_addr are discarded after decryption. It does not adjust the + * beginning of the source or destination data. This parameter + * satisfies 0 <= block_offset < 16. + * [in/out] out_buffer: A caller-owned descriptor that specifies the handling of + * the decrypted byte stream. See OEMCrypto_DestbufferDesc for details. + * [in] pattern: A caller-owned structure indicating the encrypt/skip pattern + * as specified in the CENC standard. + * [in] subsample_flags: bitwise flags indicating if this is the first, + * middle, or last subsample in a chunk of data. 1 = first subsample, 2 + * = last subsample, 3 = both first and last subsample, 0 = neither + * first nor last subsample. + * + * Returns: + * OEMCrypto_SUCCESS + * OEMCrypto_ERROR_NO_DEVICE_KEY + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_INVALID_CONTEXT + * OEMCrypto_ERROR_DECRYPT_FAILED + * OEMCrypto_ERROR_KEY_EXPIRED + * OEMCrypto_ERROR_INSUFFICIENT_HDCP + * OEMCrypto_ERROR_ANALOG_OUTPUT + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_OUTPUT_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support subsample sizes (i.e. data_addr_length) of at least + * 100 KiB. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. If OEMCrypto returns + * OEMCrypto_ERROR_BUFFER_TOO_LARGE, the calling function must break the + * buffer into smaller chunks. For high performance devices, OEMCrypto should + * handle larger buffers. We encourage OEMCrypto implementers not to + * artificially restrict the maximum buffer size. + * If OEMCrypto detects that the output data is too large, and breaking the + * buffer into smaller subsamples will not work, then it returns + * OEMCrypto_ERROR_OUTPUT_TOO_LARGE. This error will bubble up to the + * application, which can decide to skip the current frame of video or to + * switch to a lower resolution. + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method changed in API version 15. This method changed its name in API + * version 11. + */ +OEMCryptoResult OEMCrypto_DecryptCENC( + OEMCrypto_SESSION session, const SharedMemory* data_addr, + size_t data_addr_length, bool is_encrypted, const uint8_t* iv, + size_t block_offset, // used for CTR "cenc" mode only. + OEMCrypto_DestBufferDesc* out_buffer, + const OEMCrypto_CENCEncryptPatternDesc* pattern, uint8_t subsample_flags); + +/* + * OEMCrypto_CopyBuffer + * + * Description: + * Copies the payload in the buffer referenced by the *data_addr parameter + * into the buffer referenced by the out_buffer parameter. The data is simply + * copied. The definition of OEMCrypto_DestBufferDesc and subsample_flags are + * the same as in OEMCrypto_DecryptCENC, above. + * + * The main difference between this and DecryptCENC is that this function + * does not need an open session, and it may be called concurrently with + * other functions on a multithreaded system. In particular, an application + * will use this to copy the clear leader of a video to a secure buffer while + * the license request is being generated, sent to the server, and the + * response is being processed. This functionality is needed because an + * application may not have read or write access to a secure destination + * buffer. + * + * NOTES: + * + * This method may be called several times before the data is used. The first + * buffer in a chunk of data will have the OEMCrypto_FirstSubsample bit set + * in subsample_flags. The last buffer in a chunk of data will have the + * OEMCrypto_LastSubsample bit set in subsample_flags. The data will not be + * used until after OEMCrypto_LastSubsample has been set. If an + * implementation copies data immediately, it may ignore subsample_flags. + * + * If the destination buffer is secure, an offset may be specified. + * CopyBuffer begins storing data out_buffer->secure.offset bytes after the + * beginning of the secure buffer. + * + * Verification: + * The following checks should be performed. + * 1. If either data_addr or out_buffer is null, return + * OEMCrypto_ERROR_INVALID_CONTEXT. + * + * Parameters: + * [in] session: crypto session identifier. + * [in] data_addr: An unaligned pointer to the buffer to be copied. + * [in] data_addr_length: The length of the buffer, in bytes. + * [in/out] out_buffer: A caller-owned descriptor that specifies the handling of + * the byte stream. See OEMCrypto_DestbufferDesc for details. + * [in] subsample_flags: bitwise flags indicating if this is the first, + * middle, or last subsample in a chunk of data. 1 = first subsample, 2 + * = last subsample, 3 = both first and last subsample, 0 = neither + * first nor last subsample. + * + * Returns: + * OEMCrypto_SUCCESS + * OEMCrypto_ERROR_INVALID_CONTEXT + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_OUTPUT_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support subsample sizes (i.e. data_addr_length) up to 100 + * KiB. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. If OEMCrypto returns + * OEMCrypto_ERROR_BUFFER_TOO_LARGE, the calling function must break the + * buffer into smaller chunks. For high performance devices, OEMCrypto should + * handle larger buffers. We encourage OEMCrypto implementers not to + * artificially restrict the maximum buffer size. + * If OEMCrypto detects that the output data is too large, and breaking the + * buffer into smaller subsamples will not work, then it returns + * OEMCrypto_ERROR_OUTPUT_TOO_LARGE. This error will bubble up to the + * application, which can decide to skip the current frame of video or to + * switch to a lower resolution. + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method is changed in API version 15. + */ +OEMCryptoResult OEMCrypto_CopyBuffer(OEMCrypto_SESSION session, + const SharedMemory* data_addr, + size_t data_addr_length, + OEMCrypto_DestBufferDesc* out_buffer, + uint8_t subsample_flags); + +/* + * OEMCrypto_Generic_Encrypt + * + * Description: + * This function encrypts a generic buffer of data using the current key. + * + * If the session has an entry in the Usage Table, then OEMCrypto will update + * the time_of_last_decrypt. If the status of the entry is "unused", then + * change the status to "active" and set the time_of_first_decrypt. + * + * OEMCrypto should be able to handle buffers at least 100 KiB long. + * + * Verification: + * The following checks should be performed. If any check fails, an error is + * returned, and the data is not encrypted. + * 1. The control bit for the current key shall have the Allow_Encrypt set. + * If not, return OEMCrypto_ERROR_UNKNOWN_FAILURE. + * 2. If the current key's control block has a nonzero Duration field, then + * the API shall verify that the duration is greater than the session's + * elapsed time clock. If not, return OEMCrypto_ERROR_KEY_EXPIRED. + * 3. If the current session has an entry in the Usage Table, and the + * status of that entry is either kInactiveUsed or kInactiveUnused, then + * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. + * + * Parameters: + * [in] session: crypto session identifier. + * [in] in_buffer: pointer to memory containing data to be encrypted. + * [in] in_buffer_length: length of the buffer, in bytes. The algorithm may + * restrict in_buffer_length to be a multiple of block size. + * [in] iv: IV for encrypting data. Size is 128 bits. + * [in] algorithm: Specifies which encryption algorithm to use. Currently, + * only CBC 128 mode is allowed for encryption. + * [out] out_buffer: pointer to buffer in which encrypted data should be + * stored. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_KEY_EXPIRED + * OEMCrypto_ERROR_NO_DEVICE_KEY + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support buffers sizes of at least 100 KiB for generic + * crypto operations. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method changed in API version 12. + */ +OEMCryptoResult OEMCrypto_Generic_Encrypt( + OEMCrypto_SESSION session, const SharedMemory* in_buffer, + size_t in_buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm, + uint8_t* out_buffer); + +/* + * OEMCrypto_Generic_Decrypt + * + * Description: + * This function decrypts a generic buffer of data using the current key. + * + * If the session has an entry in the Usage Table, then OEMCrypto will update + * the time_of_last_decrypt. If the status of the entry is "unused", then + * change the status to "active" and set the time_of_first_decrypt. + * + * OEMCrypto should be able to handle buffers at least 100 KiB long. + * + * Verification: + * The following checks should be performed. If any check fails, an error is + * returned, and the data is not decrypted. + * 1. The control bit for the current key shall have the Allow_Decrypt set. + * If not, return OEMCrypto_ERROR_DECRYPT_FAILED. + * 2. If the current key's control block has the Data_Path_Type bit set, + * then return OEMCrypto_ERROR_DECRYPT_FAILED. + * 3. If the current key's control block has a nonzero Duration field, then + * the API shall verify that the duration is greater than the session's + * elapsed time clock. If not, return OEMCrypto_ERROR_KEY_EXPIRED. + * 4. If the current session has an entry in the Usage Table, and the + * status of that entry is either kInactiveUsed or kInactiveUnused, then + * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. + * + * Parameters: + * [in] session: crypto session identifier. + * [in] in_buffer: pointer to memory containing data to be encrypted. + * [in] in_buffer_length: length of the buffer, in bytes. The algorithm may + * restrict in_buffer_length to be a multiple of block size. + * [in] iv: IV for encrypting data. Size is 128 bits. + * [in] algorithm: Specifies which encryption algorithm to use. Currently, + * only CBC 128 mode is allowed for decryption. + * [out] out_buffer: pointer to buffer in which decrypted data should be + * stored. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_KEY_EXPIRED + * OEMCrypto_ERROR_DECRYPT_FAILED + * OEMCrypto_ERROR_NO_DEVICE_KEY + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support buffers sizes of at least 100 KiB for generic + * crypto operations. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method changed in API version 12. + */ +OEMCryptoResult OEMCrypto_Generic_Decrypt( + OEMCrypto_SESSION session, const SharedMemory* in_buffer, + size_t in_buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm, + uint8_t* out_buffer); + +/* + * OEMCrypto_Generic_Sign + * + * Description: + * This function signs a generic buffer of data using the current key. + * + * If the session has an entry in the Usage Table, then OEMCrypto will update + * the time_of_last_decrypt. If the status of the entry is "unused", then + * change the status to "active" and set the time_of_first_decrypt. + * + * Verification: + * The following checks should be performed. If any check fails, an error is + * returned, and the data is not signed. + * 1. The control bit for the current key shall have the Allow_Sign set. + * 2. If the current key's control block has a nonzero Duration field, then + * the API shall verify that the duration is greater than the session's + * elapsed time clock. If not, return OEMCrypto_ERROR_KEY_EXPIRED. + * 3. If the current session has an entry in the Usage Table, and the + * status of that entry is either kInactiveUsed or kInactiveUnused, then + * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. + * + * Parameters: + * [in] session: crypto session identifier. + * [in] buffer: pointer to memory containing data to be encrypted. + * [in] buffer_length: length of the buffer, in bytes. + * [in] algorithm: Specifies which algorithm to use. + * [out] signature: pointer to buffer in which signature should be stored. + * May be null on the first call in order to find required buffer size. + * [in/out] signature_length: (in) length of the signature buffer, in bytes. + * (out) actual length of the signature + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_KEY_EXPIRED + * OEMCrypto_ERROR_SHORT_BUFFER if signature buffer is not large enough to + * hold the output signature. + * OEMCrypto_ERROR_NO_DEVICE_KEY + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support buffers sizes of at least 100 KiB for generic + * crypto operations. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method changed in API version 14. + */ +OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, + const SharedMemory* buffer, + size_t buffer_length, + OEMCrypto_Algorithm algorithm, + uint8_t* signature, + size_t* signature_length); + +/* + * OEMCrypto_Generic_Verify + * + * Description: + * This function verifies the signature of a generic buffer of data using the + * current key. + * + * If the session has an entry in the Usage Table, then OEMCrypto will update + * the time_of_last_decrypt. If the status of the entry is "unused", then + * change the status to "active" and set the time_of_first_decrypt. + * + * Verification: + * The following checks should be performed. If any check fails, an error is + * returned. + * 1. The control bit for the current key shall have the Allow_Verify set. + * 2. The signature of the message shall be computed, and the API shall + * verify the computed signature matches the signature passed in. If + * not, return OEMCrypto_ERROR_SIGNATURE_FAILURE. + * 3. The signature verification shall use a constant-time algorithm (a + * signature mismatch will always take the same time as a successful + * comparison). + * 4. If the current key's control block has a nonzero Duration field, then + * the API shall verify that the duration is greater than the session's + * elapsed time clock. If not, return OEMCrypto_ERROR_KEY_EXPIRED. + * 5. If the current session has an entry in the Usage Table, and the + * status of that entry is either kInactiveUsed or kInactiveUnused, then + * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. + * + * Parameters: + * [in] session: crypto session identifier. + * [in] buffer: pointer to memory containing data to be encrypted. + * [in] buffer_length: length of the buffer, in bytes. + * [in] algorithm: Specifies which algorithm to use. + * [in] signature: pointer to buffer in which signature resides. + * [in] signature_length: length of the signature buffer, in bytes. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_KEY_EXPIRED + * OEMCrypto_ERROR_SIGNATURE_FAILURE + * OEMCrypto_ERROR_NO_DEVICE_KEY + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support buffers sizes of at least 100 KiB for generic + * crypto operations. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method changed in API version 14. + */ +OEMCryptoResult OEMCrypto_Generic_Verify(OEMCrypto_SESSION session, + const SharedMemory* buffer, + size_t buffer_length, + OEMCrypto_Algorithm algorithm, + const SharedMemory* signature, + size_t signature_length); + +/* + * OEMCrypto_UpdateUsageTable + * + * Description: + * OEMCrypto should propagate values from all open sessions to the Session Usage + * Table. If any values have changed, increment the generation number, sign, and + * save the table. During playback, this function will be called approximately + * once per minute. + * + * Devices that do not implement a Session Usage Table may return + * OEMCrypto_ERROR_NOT_IMPLEMENTED. + * + * Parameters: + * none + * + * Threading: + * This function will not be called simultaneously with any session functions. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * + * Version: + * This method changed in API version 9. + */ +OEMCryptoResult OEMCrypto_UpdateUsageTable(void); + +/* + * OEMCrypto_WrapKeyboxOrOEMCert + * + * Description: + * A device should be provisioned at the factory with either an OEM + * Certificate or a keybox. We will call this data the root of trust. During + * manufacturing, the root of trust should be encrypted with the OEM root key + * and stored on the file system in a region that will not be erased during + * factory reset. This function may be used by legacy systems that use the + * two-step WrapKeyboxOrOEMCert/InstallKeyboxOrOEMCert approach. When the + * Widevine DRM plugin initializes, it will look for a wrapped root of trust + * in the file /factory/wv.keys and install it into the security processor by + * calling OEMCrypto_InstallKeyboxOrOEMCert(). + * + * Figure 10. OEMCrypto_WrapKeyboxOrOEMCert Operation + * + * OEMCrypto_WrapKeyboxOrOEMCert() is used to generate an OEM-encrypted root + * of trust that may be passed to OEMCrypto_InstallKeyboxOrOEMCert() for + * provisioning. The root of trust may be either passed in the clear or + * previously encrypted with a transport key. If a transport key is supplied, + * the keybox is first decrypted with the transport key before being wrapped + * with the OEM root key. This function is only needed if the root of trust + * provisioning method involves saving the keybox or OEM Certificate to the + * file system. + * + * Parameters: + * [in] rot - pointer to root of trust data to encrypt -- this is either a + * keybox or an OEM Certificate private key. May be NULL on the first + * call to test size of wrapped keybox. The keybox may either be clear + * or previously encrypted. + * [in] rotLength - length the keybox data in bytes + * [out] wrappedRot – Pointer to wrapped keybox + * [out] wrappedRotLength – Pointer to the length of the wrapped rot in bytes + * [in] transportKey – Optional. AES transport key. If provided, the rot + * parameter was previously encrypted with this key. The keybox will be + * decrypted with the transport key using AES-CBC and a null IV. + * [in] transportKeyLength – Optional. Number of bytes in the transportKey, + * if used. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_WRITE_KEYBOX failed to encrypt the keybox + * OEMCrypto_ERROR_SHORT_BUFFER if keybox is provided as NULL, to determine + * the size of the wrapped keybox + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. + * + * Version: + * This method is supported in all API versions. + */ +OEMCryptoResult OEMCrypto_WrapKeyboxOrOEMCert(const uint8_t* rot, + size_t rotLength, + uint8_t* wrappedRot, + size_t* wrappedRotLength, + const uint8_t* transportKey, + size_t transportKeyLength); + +/* + * OEMCrypto_InstallKeyboxOrOEMCert + * + * Description: + * Decrypts a wrapped root of trust and installs it in the security + * processor. The root of trust is unwrapped then encrypted with the OEM root + * key. This function is called from the Widevine DRM plugin at + * initialization time if there is no valid root of trust installed. It looks + * for wrapped data in the file /factory/wv.keys and if it is present, will + * read the file and call OEMCrypto_InstallKeyboxOrOEMCert() with the + * contents of the file. This function is only needed if the factory + * provisioning method involves saving the keybox or OEM Certificate to the + * file system. + * + * Parameters: + * [in] rot - pointer to encrypted data as input + * [in] rotLength - length of the data in bytes + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_BAD_MAGIC + * OEMCrypto_ERROR_BAD_CRC + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. + * + * Version: + * This method is supported in all API versions. + */ +OEMCryptoResult OEMCrypto_InstallKeyboxOrOEMCert(const uint8_t* rot, + size_t rotLength); + +/* + * OEMCrypto_GetProvisioningMethod + * + * Description: + * This function is for OEMCrypto to tell the layer above what provisioning + * method it uses: keybox or OEM certificate. + * + * Parameters: + * none + * + * Returns: + * - DrmCertificate means the device has a DRM certificate built into the + * system. This cannot be used by level 1 devices. This provisioning + * method is deprecated and should not be used on new devices. + * OEMCertificate provisioning should be used instead. + * - Keybox means the device has a unique keybox. For level 1 devices this + * keybox must be securely installed by the device manufacturer. + * - OEMCertificate means the device has a factory installed OEM + * certificate. This is also called Provisioning 3.0. + * - ProvisioningError indicates a serious problem with the OEMCrypto + * library. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method is new API version 12. + */ +OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod(void); + +/* + * OEMCrypto_IsKeyboxOrOEMCertValid + * + * Description: + * If the device has a keybox, this validates the Widevine Keybox loaded into + * the security processor device. This method verifies two fields in the + * keybox: + * + * - Verify the MAGIC field contains a valid signature (such as, + * 'k''b''o''x'). + * - Compute the CRC using CRC-32-POSIX-1003.2 standard and compare the + * checksum to the CRC stored in the Keybox. + * The CRC is computed over the entire Keybox excluding the 4 bytes of the + * CRC (for example, Keybox[0..123]). For a description of the fields stored + * in the keybox, see Keybox Definition. + * + * If the device has an OEM Certificate, this validates the certificate + * private key. + * + * Parameters: + * none + * + * Returns: + * OEMCrypto_SUCCESS + * OEMCrypto_ERROR_BAD_MAGIC + * OEMCrypto_ERROR_BAD_CRC + * OEMCrypto_ERROR_KEYBOX_INVALID + * OEMCrypto_ERROR_INVALID_RSA_KEY + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method is supported in all API versions. + */ +OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void); + +/* + * OEMCrypto_GetDeviceID + * + * Description: + * Retrieve DeviceID from the Keybox. For devices that have an OEM + * Certificate instead of a keybox, this function may return + * OEMCrypto_ERROR_NOT_IMPLEMENTED. If the function is implemented on an OEM + * Certificate device, it should set the device ID to a device-unique string, + * such as the device serial number. The ID should be device-unique and it + * should be stable -- i.e. it should not change across a device reboot or a + * system upgrade. + * + * This function is optional but recommended for Provisioning 3.0 in API v15. + * It may be required for future version of this API. + * + * Parameters: + * [out] device_id - pointer to the buffer that receives the Device ID + * [in/out] device_id_length – on input, size of the caller's device ID + * buffer. On output, the number of bytes written into the buffer. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_SHORT_BUFFER if the buffer is too small to return device ID + * OEMCrypto_ERROR_NO_DEVICEID failed to return Device Id + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method is supported in all API versions. + */ +OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* device_id, + size_t* device_id_length); + +/* + * OEMCrypto_GetKeyData + * + * Description: + * Return the Key Data field from the Keybox. + * + * Parameters: + * [out] keyData - pointer to the buffer to hold the Key Data field from the + * Keybox + * [in/out] keyDataLength – on input, the allocated buffer size. On output, + * the number of bytes in Key Data + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_SHORT_BUFFER if the buffer is too small to return KeyData + * OEMCrypto_ERROR_NO_KEYDATA + * OEMCrypto_ERROR_NOT_IMPLEMENTED - this function is for Provisioning 2.0 + * only. + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method is supported in all API versions. + */ +OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, size_t* keyDataLength); + +/* + * OEMCrypto_LoadTestKeybox + * + * Description: + * Temporarily use the specified test keybox until the next call to + * OEMCrypto_Terminate. This allows a standard suite of unit tests to be run + * on a production device without permanently changing the keybox. Using the + * test keybox is not persistent. OEMCrypto cannot assume that this keybox is + * the same as previous keyboxes used for testing. + * + * Devices that use an OEM Certificate instead of a keybox (i.e. Provisioning + * 3.0) do not need to support this functionality, and may return + * OEMCrypto_ERROR_NOT_IMPLEMENTED. + * + * Parameters: + * [in] buffer: pointer to memory containing test keybox, in binary form. + * [in] buffer_length: length of the buffer, in bytes. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_NOT_IMPLEMENTED - this function is for Provisioning 2.0 + * only. + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. It is called after OEMCrypto_Initialize and + * after OEMCrypto_GetProvisioningMethod and only if the provisoining method + * is OEMCrypto_Keybox, + * + * Version: + * This method changed in API version 14. + */ +OEMCryptoResult OEMCrypto_LoadTestKeybox(const uint8_t* buffer, + size_t buffer_length); + +/* + * OEMCrypto_GetOEMPublicCertificate + * + * Description: + * This function should place the OEM public certificate in the buffer + * public_cert. After a call to this function, all methods using an RSA key + * should use the OEM certificate's private RSA key. See the section above + * discussing Provisioning 3.0. + * + * If the buffer is not large enough, OEMCrypto should update + * public_cert_length and return OEMCrypto_ERROR_SHORT_BUFFER. + * + * Parameters: + * - [in] session: this function affects the specified session only. + * - [out] public_cert: the buffer where the public certificate is stored. + * - [in/out] public_cert_length: on input, this is the available size of + * the buffer. On output, this is the number of bytes needed for the + * certificate. + * + * Returns: + * OEMCrypto_SUCCESS + * OEMCrypto_ERROR_NOT_IMPLEMENTED - this function is for Provisioning 3.0 + * only. + * OEMCrypto_ERROR_SHORT_BUFFER + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method is new API version 12. + */ +OEMCryptoResult OEMCrypto_GetOEMPublicCertificate(OEMCrypto_SESSION session, + uint8_t* public_cert, + size_t* public_cert_length); + +/* + * OEMCrypto_GetRandom + * + * Description: + * Returns a buffer filled with hardware-generated random bytes, if supported + * by the hardware. If the hardware feature does not exist, return + * OEMCrypto_ERROR_RNG_NOT_SUPPORTED. + * + * Parameters: + * [out] random_data - pointer to the buffer that receives random data + * [in] random_data_length - length of the random data buffer in bytes + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_RNG_FAILED failed to generate random number + * OEMCrypto_ERROR_RNG_NOT_SUPPORTED function not supported + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support dataLength sizes of at least 32 bytes for random + * number generation. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method is supported in all API versions. + */ +OEMCryptoResult OEMCrypto_GetRandom(uint8_t* random_data, + size_t random_data_length); + +/* + * OEMCrypto_APIVersion + * + * Description: + * This function returns the current API version number. The version number + * allows the calling application to avoid version mis-match errors, because + * this API is part of a shared library. + * + * There is a possibility that some API methods will be backwards compatible, + * or backwards compatible at a reduced security level. + * + * There is no plan to introduce forward-compatibility. Applications will + * reject a library with a newer version of the API. + * + * The version specified in this document is 15. Any OEM that returns this + * version number guarantees it passes all unit tests associated with this + * version. + * + * Parameters: + * none + * + * Returns: + * The supported API, as specified in the header file OEMCryptoCENC.h. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method changed in each API version. + */ +uint32_t OEMCrypto_APIVersion(void); + +/* + * OEMCrypto_BuildInformation + * + * Description: + * Report the build information of the OEMCrypto library as a short null + * terminated C string. The string should be at most 128 characters long. + * This string should be updated with each release or OEMCrypto build. + * + * Some SOC vendors deliver a binary OEMCrypto library to a device + * manufacturer. This means the OEMCrypto version may not be exactly in sync + * with the system's versions. This string can be used to help track which + * version is installed on a device. + * + * It may be used for logging or bug tracking and may be bubbled up to the + * app so that it may track metrics on errors. + * + * Since the OEMCrypto API also changes its minor version number when there + * are minor corrections, it would be useful to include the API version + * number in this string, e.g. "15.1" or "15.2" if those minor versions are + * released. + * + * Parameters: + * none + * + * Returns: + * A printable null terminated C string, suitable for a single line in a log. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method changed in each API version. + */ +const char* OEMCrypto_BuildInformation(void); + +/* + * OEMCrypto_Security_Patch_Level + * + * Description: + * This function returns the current patch level of the software running in + * the trusted environment. The patch level is defined by the OEM, and is + * only incremented when a security update has been added. + * + * See the section Security Patch Level above for more details. + * + * Parameters: + * none + * + * Returns: + * The OEM defined version number. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method was introduced in API version 11. + */ +uint8_t OEMCrypto_Security_Patch_Level(void); + +/* + * OEMCrypto_SecurityLevel + * + * Description: + * Returns a string specifying the security level of the library. + * + * Since this function is spoofable, it is not relied on for security + * purposes. It is for information only. + * + * Parameters: + * none + * + * Returns: + * A null terminated string. Useful value are "L1", "L2" and "L3". + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 6. + */ +const char* OEMCrypto_SecurityLevel(void); + +/* + * OEMCrypto_GetHDCPCapability + * + * Description: + * Returns the maximum HDCP version supported by the device, and the HDCP + * version supported by the device and any connected display. + * + * Valid values for HDCP_Capability are: + * + * The value 0xFF means the device is using a local, secure, data path + * instead of HDMI output. Notice that HDCP must use flag Type 1: all + * downstream devices will also use the same version or higher. + * + * The current HDCP should be the minimum value of any display currently + * connected through any channel, either through HDMI or a supported wireless + * format. The current value can be used by the application or server to + * decide which license can currently be used. If the key control block + * requires the current HDCP level, we expect the key to be usable. + * + * The maximum HDCP level should be the maximum value that the device can + * enforce. For example, if the device has an HDCP 1.0 port and an HDCP 2.0 + * port, and the first port can be disabled, then the maximum is HDCP 2.0. If + * the first port cannot be disabled, then the maximum is HDCP 1.0. The + * maximum value can be used by the application or server to decide if a + * license may be used in the future. For example, a device may be connected + * to an external display while an offline license is downloaded, but the + * user intends to view the content on a local display. The user will want to + * download the higher quality content. + * + * When a license requires HDCP, a device may use a wireless protocol to + * connect to a display only if that protocol supports the version of HDCP as + * required by the license. Both WirelessHD (formerly WiFi Display) and + * Miracast support HDCP. + * + * Parameters: + * [out] current - this is the current HDCP version, based on the device + * itself, and the display to which it is connected. + * [out] maximum - this is the maximum supported HDCP version for the device, + * ignoring any attached device. + * + * Returns: + * OEMCrypto_SUCCESS + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 10. + */ +OEMCryptoResult OEMCrypto_GetHDCPCapability(OEMCrypto_HDCP_Capability* current, + OEMCrypto_HDCP_Capability* maximum); + +/* + * OEMCrypto_SupportsUsageTable + * + * Description: + * This is used to determine if the device can support a usage table. Since + * this function is spoofable, it is not relied on for security purposes. It + * is for information only. The usage table is described in the section above. + * + * Parameters: + * none + * + * Returns: + * Returns true if the device can maintain a usage table. Returns false + * otherwise. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 9. + */ +bool OEMCrypto_SupportsUsageTable(void); + +/* + * OEMCrypto_IsAntiRollbackHwPresent + * + * Description: + * Indicate whether there is hardware protection to detect and/or prevent the + * rollback of the usage table. For example, if the usage table contents is + * stored entirely on a secure file system that the user cannot read or write + * to. Another example is if the usage table has a generation number and the + * generation number is stored in secure memory that is not user accessible. + * + * Parameters: + * none + * + * Returns: + * Returns true if oemcrypto uses anti-rollback hardware. Returns false + * otherwise. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method is new in API version 10. + */ +bool OEMCrypto_IsAntiRollbackHwPresent(void); + +/* + * OEMCrypto_GetNumberOfOpenSessions + * + * Description: + * Returns the current number of open sessions. The CDM and OEMCrypto + * consumers can query this value so they can use resources more effectively. + * + * Parameters: + * [out] count - this is the current number of opened sessions. + * + * Returns: + * OEMCrypto_SUCCESS + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method is new in API version 10. + */ +OEMCryptoResult OEMCrypto_GetNumberOfOpenSessions(size_t* count); + +/* + * OEMCrypto_GetMaxNumberOfSessions + * + * Description: + * Returns the maximum number of concurrent OEMCrypto sessions supported by + * the device. The CDM and OEMCrypto consumers can query this value so they + * can use resources more effectively. If the maximum number of sessions + * depends on a dynamically allocated shared resource, the returned value + * should be a best estimate of the maximum number of sessions. + * + * OEMCrypto shall support a minimum of 10 sessions. Some applications use + * multiple sessions to pre-fetch licenses, so high end devices should + * support more sessions -- we recommend a minimum of 50 sessions. + * + * Parameters: + * [out] max - this is the max number of supported sessions. + * + * Returns: + * OEMCrypto_SUCCESS + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 12. + */ +OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(size_t* max); + +/* + * OEMCrypto_SupportedCertificates + * + * Description: + * Returns the type of certificates keys that this device supports. With very + * few exceptions, all devices should support at least 2048 bit RSA keys. + * High end devices should also support 3072 bit RSA keys. Devices that are + * cast receivers should also support RSA cast receiver certificates. + * + * Beginning with OEMCrypto v14, the provisioning server may deliver to the + * device an RSA key that uses the Carmichael totient. This does not change + * the RSA algorithm -- however the product of the private and public keys is + * not necessarily the Euler number \phi (n). OEMCrypto should not reject + * such keys. + * + * Parameters: + * none + * + * Returns: + * Returns the bitwise or of the following flags. It is likely that high end + * devices will support both 2048 and 3072 bit keys while the widevine + * servers transition to new key sizes. + * - 0x1 = OEMCrypto_Supports_RSA_2048bit - the device can load a DRM + * certificate with a 2048 bit RSA key. + * - 0x2 = OEMCrypto_Supports_RSA_3072bit - the device can load a DRM + * certificate with a 3072 bit RSA key. + * - 0x10 = OEMCrypto_Supports_RSA_CAST - the device can load a CAST + * certificate. These certificate are used with + * OEMCrypto_GenerateRSASignature with padding type set to 0x2, PKCS1 + * with block type 1 padding. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 13. + */ +uint32_t OEMCrypto_SupportedCertificates(void); + +/* + * OEMCrypto_IsSRMUpdateSupported + * + * Description: + * Returns true if the device supports SRM files and the file can be updated + * via the function OEMCrypto_LoadSRM. This also returns false for devices + * that do not support an SRM file, devices that do not support HDCP, and + * devices that have no external display support. + * + * Parameters: + * none + * + * Returns: + * true - if LoadSRM is supported. + * false - otherwise. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 13. + */ +bool OEMCrypto_IsSRMUpdateSupported(void); + +/* + * OEMCrypto_GetCurrentSRMVersion + * + * Description: + * Returns the version number of the current SRM file. If the device does not + * support SRM files, this will return OEMCrypto_ERROR_NOT_IMPLEMENTED. If + * the device only supports local displays, it would return + * OEMCrypto_LOCAL_DISPLAY_ONLY. If the device has an SRM, but cannot use + * OEMCrypto to update the SRM, then this function would set version to be + * the current version number, and return OEMCrypto_SUCCESS, but it would + * return false from OEMCrypto_IsSRMUpdateSupported. + * + * Parameters: + * [out] version: current SRM version number. + * + * Returns: + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_SUCCESS + * OEMCrypto_LOCAL_DISPLAY_ONLY - to indicate version was not set, and is not + * needed. + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 13. + */ +OEMCryptoResult OEMCrypto_GetCurrentSRMVersion(uint16_t* version); + +/* + * OEMCrypto_GetAnalogOutputFlags + * + * Description: + * Returns whether the device supports analog output or not. This information + * will be sent to the license server, and may be used to determine the type + * of license allowed. This function is for reporting only. It is paired with + * the key control block flags Disable_Analog_Output and CGMS. + * + * Parameters: + * none. + * + * Returns: + * Returns a bitwise OR of the following flags. + * - 0x0 = OEMCrypto_No_Analog_Output -- the device has no analog output. + * - 0x1 = OEMCrypto_Supports_Analog_Output - the device does have analog + * output. + * - 0x2 = OEMCrypto_Can_Disable_Analog_Ouptput - the device does have + * analog output, but it will disable analog output if required by the + * key control block. + * - 0x4 = OEMCrypto_Supports_CGMS_A - the device supports signaling 2-bit + * CGMS-A, if required by the key control block + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method is new in API version 14. + */ +uint32_t OEMCrypto_GetAnalogOutputFlags(void); + +/* + * OEMCrypto_ResourceRatingTier + * + * Description: + * This function returns a positive number indicating which resource rating + * it supports. This value will bubble up to the application level as a + * property. This will allow applications to estimate what resolution and + * bandwidth the device expects to support. + * + * OEMCrypto unit tests and Android GTS tests will verify that devices do + * support the resource values specified in the table below at the tier + * claimed by the device. If a device claims to be a low end device, the + * OEMCrypto unit tests will only verify the low end performance values. + * + * OEMCrypto implementers should consider the numbers below to be minimum + * values. + * + * These performance parameters are for OEMCrypto only. In particular, + * bandwidth and codec resolution are determined by the platform. + * + * Some parameters need more explanation. The Sample size is typically the + * size of one encoded frame. Converting this to resolution depends on the + * Codec, which is not specified by OEMCrypto. Some content has the sample + * broken into several subsamples. The "number of subsamples" restriction + * requires that any content can be broken into at least that many + * subsamples. However, this number may be larger if DecryptCENC returns + * OEMCrypto_ERROR_BUFFER_TOO_LARGE. In that case, the layer above OEMCrypto + * will break the sample into subsamples of size "Decrypt Buffer Size" as + * specified in the table below. The "Decrypt Buffer Size" means the size of + * one subsample that may be passed into DecryptCENC or CopyBuffer without + * returning error OEMCrypto_ERROR_BUFFER_TOO_LARGE. + * + * The number of keys per session is an indication of how many different + * track types there can be for a piece of content. Typically, content will + * have several keys corresponding to audio and video at different + * resolutions. If the content uses key rotation, there could be three keys + * -- previous interval, current interval, and next interval -- for each + * resolution. + * + * Concurrent playback sessions versus concurrent sessions: some applications + * will preload multiple licenses before the user picks which content to + * play. Each of these licenses corresponds to an open session. Once playback + * starts, some platforms support picture-in-picture or multiple displays. + * Each of these pictures would correspond to a separate playback session + * with active decryption. + * + * Decrypted frames per second -- strictly speaking, OEMCrypto only controls + * the decryption part of playback and cannot control the decoding and + * display part. However, devices that support the higher resource tiers + * should also support a higher frame rate. Platforms may enforce these + * values. For example Android will enforce a frame rate via a GTS test. + * + * +-----------------------------------+-----------+------------+-----------+ + * |Resource Rating Tier |1 - Low |2 - Medium |3 - High | + * +-----------------------------------+-----------+------------+-----------+ + * |Sample size |1 MB |2 MB |4 MB | + * +-----------------------------------+-----------+------------+-----------+ + * |Number of Subsamples |8 |16 |32 | + * +-----------------------------------+-----------+------------+-----------+ + * |Decrypt buffer size |100 KB |500 KB |1 MB | + * +-----------------------------------+-----------+------------+-----------+ + * |Generic crypto buffer size |10 KB |100 KB |500 KB | + * +-----------------------------------+-----------+------------+-----------+ + * |Number of concurrent sessions |10 |20 |20 | + * +-----------------------------------+-----------+------------+-----------+ + * |Number of keys per session |4 |20 |20 | + * +-----------------------------------+-----------+------------+-----------+ + * |Simultaneous secure playback |1 |2 |2 | + * +-----------------------------------+-----------+------------+-----------+ + * |Decrypted Frames per Second |30 fps SD |30 fps HD |60 fps HD | + * +-----------------------------------+-----------+------------+-----------+ + * + * Parameters: + * none. + * + * Returns: + * Returns an integer indicating which resource tier the device supports. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method is new in API version 15. + */ +uint32_t OEMCrypto_ResourceRatingTier(void); + +/* + * OEMCrypto_RewrapDeviceRSAKey30 + * + * Description: + * This function is similar to RewrapDeviceRSAKey, except it uses the private + * key from an OEM certificate to decrypt the message key instead of keys + * derived from a keybox. Verifies an RSA provisioning response is valid and + * corresponds to the previous provisioning request by checking the nonce. + * The RSA private key is decrypted and stored in secure memory. The RSA key + * is then re-encrypted and signed for storage on the filesystem. We + * recommend that the OEM use an encryption key and signing key generated + * using an algorithm at least as strong as that in GenerateDerivedKeys. + * + * After decrypting enc_rsa_key, If the first four bytes of the buffer are + * the string "SIGN", then the actual RSA key begins on the 9th byte of the + * buffer. The second four bytes of the buffer is the 32 bit field + * "allowed_schemes", of type RSA_Padding_Scheme, which is used in + * OEMCrypto_GenerateRSASignature. The value of allowed_schemes must also be + * wrapped with RSA key. We recommend storing the magic string "SIGN" with + * the key to distinguish keys that have a value for allowed_schemes from + * those that should use the default allowed_schemes. Devices that do not + * support the alternative signing algorithms may refuse to load these keys + * and return an error of OEMCrypto_ERROR_NOT_IMPLEMENTED. The main use case + * for these alternative signing algorithms is to support devices that use + * X509 certificates for authentication when acting as a ChromeCast receiver. + * This is not needed for devices that wish to send data to a ChromeCast. + * + * If the first four bytes of the buffer enc_rsa_key are not the string + * "SIGN", then the default value of allowed_schemes = 1 (kSign_RSASSA_PSS) + * will be used. + * + * Verification and Algorithm: + * The following checks should be performed. If any check fails, an error is + * returned, and the key is not loaded. + * + * 1. Verify that in_wrapped_rsa_key_length is large enough to hold the + * rewrapped key, returning OEMCrypto_ERROR_SHORT_BUFFER otherwise. + * 2. Verify that the nonce matches one generated by a previous call to + * OEMCrypto_GenerateNonce(). The matching nonce shall be removed from + * the nonce table. If there is no matching nonce, return + * OEMCRYPTO_ERROR_INVALID_NONCE. Notice that the nonce may not point + * to a word aligned memory location. + * 3. Decrypt encrypted_message_key with the OEM certificate's private RSA + * key using RSA-OAEP into the buffer message_key. This message key is + * a 128 bit AES key used only in step 4. This message_key should be + * kept in secure memory and protected from the user. + * 4. Decrypt enc_rsa_key into the buffer rsa_key using the message_key, + * which was found in step 3. Use enc_rsa_key_iv as the initial vector + * for AES_128-CBC mode, with PKCS#5 padding. The rsa_key should be kept + * in secure memory and protected from the user. + * 5. If the first four bytes of the buffer rsa_key are the string "SIGN", + * then the actual RSA key begins on the 9th byte of the buffer. The + * second four bytes of the buffer is the 32 bit field + * "allowed_schemes", of type RSA_Padding_Scheme, which is used in + * OEMCrypto_GenerateRSASignature. The value of allowed_schemes must + * also be wrapped with RSA key. We recommend storing the magic string + * "SIGN" with the key to distinguish keys that have a value for + * allowed_schemes from those that should use the default + * allowed_schemes. Devices that do not support the alternative signing + * algorithms may refuse to load these keys and return an error of + * OEMCrypto_ERROR_NOT_IMPLEMENTED. The main use case for these + * alternative signing algorithms is to support devices that use X.509 + * certificates for authentication when acting as a ChromeCast receiver. + * This is not needed for devices that wish to send data to a ChromeCast. + * 6. If the first four bytes of the buffer rsa_key are not the string + * "SIGN", then the default value of allowed_schemes = 1 + * (kSign_RSASSA_PSS) will be used. + * 7. After possibly skipping past the first 8 bytes signifying the allowed + * signing algorithm, the rest of the buffer rsa_key contains an RSA + * device key in PKCS#8 binary DER encoded format. The OEMCrypto library + * shall verify that this RSA key is valid. + * 8. Re-encrypt the device RSA key with an internal key (such as the OEM + * key or Widevine Keybox key) and the generated IV using AES-128-CBC + * with PKCS#5 padding. + * 9. Copy the rewrapped key to the buffer specified by wrapped_rsa_key and + * the size of the wrapped key to wrapped_rsa_key_length. + * + * Parameters: + * [in] session: crypto session identifier. + * [in] unaligned_nonce: A pointer to the nonce provided in the provisioning + * response. (unaligned uint32_t) + * [in] encrypted_message_key : message_key encrypted by private key from + * OEM cert. + * [in] encrypted_message_key_length : length of encrypted_message_key in + * bytes. + * [in] enc_rsa_key: Encrypted device private RSA key received from the + * provisioning server. Format is PKCS#8, binary DER encoded, and + * encrypted with message_key, using AES-128-CBC with PKCS#5 padding. + * [in] enc_rsa_key_length: length of the encrypted RSA key, in bytes. + * [in] enc_rsa_key_iv: IV for decrypting RSA key. Size is 128 bits. + * [out] wrapped_rsa_key: pointer to buffer in which encrypted RSA key should + * be stored. May be null on the first call in order to find required + * buffer size. + * [in/out] wrapped_rsa_key_length: (in) length of the encrypted RSA key, in + * bytes. + * (out) actual length of the encrypted RSA key + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_NO_DEVICE_KEY + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_INVALID_RSA_KEY + * OEMCrypto_ERROR_SIGNATURE_FAILURE + * OEMCrypto_ERROR_INVALID_NONCE + * OEMCrypto_ERROR_SHORT_BUFFER + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support message sizes of at least 8 KiB. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method changed in API version 12. + */ +OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30( + OEMCrypto_SESSION session, const uint32_t* unaligned_nonce, + const SharedMemory* encrypted_message_key, size_t encrypted_message_key_length, + const SharedMemory* enc_rsa_key, size_t enc_rsa_key_length, + const uint8_t* enc_rsa_key_iv, uint8_t* wrapped_rsa_key, + size_t* wrapped_rsa_key_length); + +/* + * OEMCrypto_RewrapDeviceRSAKey + * + * Description: + * This function is similar to RewrapDeviceRSAKey30, except it uses session + * keys derived from the keybox instead of the OEM certificate. Verifies an + * RSA provisioning response is valid and corresponds to the previous + * provisioning request by checking the nonce. The RSA private key is + * decrypted and stored in secure memory. The RSA key is then re-encrypted + * and signed for storage on the filesystem. We recommend that the OEM use an + * encryption key and signing key generated using an algorithm at least as + * strong as that in GenerateDerivedKeys. + * + * After decrypting enc_rsa_key, If the first four bytes of the buffer are + * the string "SIGN", then the actual RSA key begins on the 9th byte of the + * buffer. The second four bytes of the buffer is the 32 bit field + * "allowed_schemes", of type RSA_Padding_Scheme, which is used in + * OEMCrypto_GenerateRSASignature. The value of allowed_schemes must also be + * wrapped with RSA key. We recommend storing the magic string "SIGN" with + * the key to distinguish keys that have a value for allowed_schemes from + * those that should use the default allowed_schemes. Devices that do not + * support the alternative signing algorithms may refuse to load these keys + * and return an error of OEMCrypto_ERROR_NOT_IMPLEMENTED. The main use case + * for these alternative signing algorithms is to support devices that use + * X509 certificates for authentication when acting as a ChromeCast receiver. + * This is not needed for devices that wish to send data to a ChromeCast. + * + * If the first four bytes of the buffer enc_rsa_key are not the string + * "SIGN", then the default value of allowed_schemes = 1 (kSign_RSASSA_PSS) + * will be used. + * + * Verification and Algorithm: + * The following checks should be performed. If any check fails, an error is + * returned, and the key is not loaded. + * + * 1. Check that all the pointer values passed into it are within the + * buffer specified by message and message_length. + * 2. Verify that in_wrapped_rsa_key_length is large enough to hold the + * rewrapped key, returning OEMCrypto_ERROR_SHORT_BUFFER otherwise. + * 3. Verify that the nonce matches one generated by a previous call to + * OEMCrypto_GenerateNonce(). The matching nonce shall be removed from + * the nonce table. If there is no matching nonce, return + * OEMCRYPTO_ERROR_INVALID_NONCE. + * 4. Verify the message signature, using the derived signing key + * (mac_key[server]) from a previous call to + * OEMCrypto_GenerateDerivedKeys. + * 5. Decrypt enc_rsa_key in the buffer rsa_key using the derived + * encryption key (enc_key) from a previous call to + * OEMCrypto_GenerateDerivedKeys. Use enc_rsa_key_iv as the initial + * vector for AES_128-CBC mode, with PKCS#5 padding. The rsa_key should + * be kept in secure memory and protected from the user. + * 6. If the first four bytes of the buffer rsa_key are the string "SIGN", + * then the actual RSA key begins on the 9th byte of the buffer. The + * second four bytes of the buffer is the 32 bit field + * "allowed_schemes", of type RSA_Padding_Scheme, which is used in + * OEMCrypto_GenerateRSASignature. The value of allowed_schemes must + * also be wrapped with RSA key. We recommend storing the magic string + * "SIGN" with the key to distinguish keys that have a value for + * allowed_schemes from those that should use the default + * allowed_schemes. Devices that do not support the alternative signing + * algorithms may refuse to load these keys and return an error of + * OEMCrypto_ERROR_NOT_IMPLEMENTED. The main use case for these + * alternative signing algorithms is to support devices that use X.509 + * certificates for authentication when acting as a ChromeCast receiver. + * This is not needed for devices that wish to send data to a ChromeCast. + * 7. If the first four bytes of the buffer rsa_key are not the string + * "SIGN", then the default value of allowed_schemes = 1 + * (kSign_RSASSA_PSS) will be used. + * 8. After possibly skipping past the first 8 bytes signifying the allowed + * signing algorithm, the rest of the buffer rsa_key contains an RSA + * device key in PKCS#8 binary DER encoded format. The OEMCrypto library + * shall verify that this RSA key is valid. + * 9. Re-encrypt the device RSA key with an internal key (such as the OEM + * key or Widevine Keybox key) and the generated IV using AES-128-CBC + * with PKCS#5 padding. + * 10. Copy the rewrapped key to the buffer specified by wrapped_rsa_key + * and the size of the wrapped key to wrapped_rsa_key_length. + * + * Parameters: + * [in] session: crypto session identifier. + * [in] unaligned_nonce: A pointer to the nonce provided in the provisioning + * response. (unaligned uint32_t) + * [in] message: pointer to memory containing message to be verified. + * [in] message_length: length of the message, in bytes. + * [in] signature: pointer to memory containing the HMAC-SHA256 signature for + * message, received from the provisioning server. + * [in] signature_length: length of the signature, in bytes. + * [in] nonce: A pointer to the nonce provided in the provisioning response. + * [in] enc_rsa_key: Encrypted device private RSA key received from the + * provisioning server. Format is PKCS#8, binary DER encoded, and + * encrypted with the derived encryption key, using AES-128-CBC with + * PKCS#5 padding. + * [in] enc_rsa_key_length: length of the encrypted RSA key, in bytes. + * [in] enc_rsa_key_iv: IV for decrypting RSA key. Size is 128 bits. + * [out] wrapped_rsa_key: pointer to buffer in which encrypted RSA key should + * be stored. May be null on the first call in order to find required + * buffer size. + * [in/out] wrapped_rsa_key_length: (in) length of the encrypted RSA key, in + * bytes. + * (out) actual length of the encrypted RSA key + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_NO_DEVICE_KEY + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_INVALID_RSA_KEY + * OEMCrypto_ERROR_SIGNATURE_FAILURE + * OEMCrypto_ERROR_INVALID_NONCE + * OEMCrypto_ERROR_SHORT_BUFFER + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support message sizes of at least 8 KiB. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method changed in API version 12. + */ +OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey( + OEMCrypto_SESSION session, const SharedMemory* message, size_t message_length, + const SharedMemory* signature, size_t signature_length, + const uint32_t* unaligned_nonce, const uint8_t* enc_rsa_key, + size_t enc_rsa_key_length, const uint8_t* enc_rsa_key_iv, + uint8_t* wrapped_rsa_key, size_t* wrapped_rsa_key_length); + +/* + * OEMCrypto_LoadDeviceRSAKey + * + * Description: + * Loads a wrapped RSA private key to secure memory for use by this session + * in future calls to OEMCrypto_GenerateRSASignature. The wrapped RSA key + * will be the one verified and wrapped by OEMCrypto_RewrapDeviceRSAKey. The + * RSA private key should be stored in secure memory. + * + * If the bit field "allowed_schemes" was wrapped with this RSA key, its + * value will be loaded and stored with the RSA key. If there was not bit + * field wrapped with the RSA key, the key will use a default value of 1 = + * RSASSA-PSS with SHA1. + * + * Verification: + * The following checks should be performed. If any check fails, an error is + * returned, and the RSA key is not loaded. + * 1. The wrapped key has a valid signature, as described in + * RewrapDeviceRSAKey. + * 2. The decrypted key is a valid private RSA key. + * 3. If a value for allowed_schemes is included with the key, it is a + * valid value. + * + * Parameters: + * [in] session: crypto session identifier. + * [in] wrapped_rsa_key: wrapped device RSA key stored on the device. Format + * is PKCS#8, binary DER encoded, and encrypted with a key internal to + * the OEMCrypto instance, using AES-128-CBC with PKCS#5 padding. This + * is the wrapped key generated by OEMCrypto_RewrapDeviceRSAKey. + * [in] wrapped_rsa_key_length: length of the wrapped key buffer, in bytes. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_NO_DEVICE_KEY + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_INVALID_RSA_KEY + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method changed in API version 9. + */ +OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session, + const SharedMemory* wrapped_rsa_key, + size_t wrapped_rsa_key_length); + +/* + * OEMCrypto_LoadTestRSAKey + * + * Description: + * Some platforms do not support keyboxes or OEM Certificates. On those + * platforms, there is a DRM certificate baked into the OEMCrypto library. + * This is unusual, and is only available for L3 devices. In order to debug + * and test those devices, they should be able to switch to the test DRM + * certificate. + * + * Temporarily use the standard test RSA key until the next call to + * OEMCrypto_Terminate. This allows a standard suite of unit tests to be run + * on a production device without permanently changing the key. Using the + * test key is not persistent. + * + * The test key can be found in the unit test code, oemcrypto_test.cpp, in + * PKCS8 form as the constant kTestRSAPKCS8PrivateKeyInfo2_2048. + * + * Parameters: + * none + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_NOT_IMPLEMENTED - devices that use a keybox should not + * implement this function + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. + * + * Version: + * This method is new in API version 10. + */ +OEMCryptoResult OEMCrypto_LoadTestRSAKey(void); + +/* + * OEMCrypto_GenerateRSASignature + * + * Description: + * The OEMCrypto_GenerateRSASignature method is used to sign messages using + * the device private RSA key, specifically, it is used to sign the initial + * license request. + * + * Refer to the Signing Messages Sent to a Server section above for more + * details. + * + * If this function is called after OEMCrypto_LoadDeviceRSAKey for the same + * session, then this function should use the device RSA key that was loaded. + * If this function is called after a call to + * OEMCrypto_GetOEMPublicCertificate for the same session, then this function + * should use the RSA private key associated with the OEM certificate. The + * only padding scheme that is valid for the OEM certificate is 0x1 - + * RSASSA-PSS with SHA1. Any other padding scheme must generate an error. + * + * For devices that wish to be CAST receivers, there is a new RSA padding + * scheme. The padding_scheme parameter indicates which hashing and padding + * is to be applied to the message so as to generate the encoded message (the + * modulus-sized block to which the integer conversion and RSA decryption is + * applied). The following values are defined: + * + * 0x1 - RSASSA-PSS with SHA1. + * + * 0x2 - PKCS1 with block type 1 padding (only). + * + * In the first case, a hash algorithm (SHA1) is first applied to the + * message, whose length is not otherwise restricted. In the second case, the + * "message" is already a digest, so no further hashing is applied, and the + * message_length can be no longer than 83 bytes. If the message_length is + * greater than 83 bytes OEMCrypto_ERROR_SIGNATURE_FAILURE shall be returned. + * + * The second padding scheme is for devices that use X509 certificates for + * authentication. The main example is devices that work as a Cast receiver, + * like a ChromeCast, not for devices that wish to send to the Cast device, + * such as almost all Android devices. OEMs that do not support X509 + * certificate authentication need not implement the second scheme and can + * return OEMCrypto_ERROR_NOT_IMPLEMENTED. + * + * Verification: + * The bitwise AND of the parameter padding_scheme and the RSA key's + * allowed_schemes is computed. If this value is 0, then the signature is not + * computed and the error OEMCrypto_ERROR_INVALID_RSA_KEY is returned. + * + * Parameters: + * [in] session: crypto session identifier. + * [in] message: pointer to memory containing message to be signed. + * [in] message_length: length of the message, in bytes. + * [out] signature: buffer to hold the message signature. On return, it will + * contain the message signature generated with the device private RSA + * key using RSASSA-PSS. Will be null on the first call in order to + * find required buffer size. + * [in/out] signature_length: (in) length of the signature buffer, in bytes. + * (out) actual length of the signature + * [in] padding_scheme: specify which scheme to use for the signature. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_SHORT_BUFFER if the signature buffer is too small. + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_INVALID_CONTEXT + * OEMCrypto_ERROR_INVALID_RSA_KEY + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_NOT_IMPLEMENTED - if algorithm > 0, and the device does + * not support that algorithm. + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support message sizes of at least 8 KiB. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method changed in API version 12. + */ +OEMCryptoResult OEMCrypto_GenerateRSASignature( + OEMCrypto_SESSION session, const SharedMemory* message, size_t message_length, + uint8_t* signature, size_t* signature_length, + RSA_Padding_Scheme padding_scheme); + +/* + * OEMCrypto_CreateUsageTableHeader + * + * Description: + * This creates a new Usage Table Header with no entries. If there is already + * a generation number stored in secure storage, it will be incremented by 1 + * and used as the new Master Generation Number. This will only be called if + * the CDM layer finds no existing usage table on the file system. OEMCrypto + * will encrypt and sign the new, empty, header and return it in the provided + * buffer. + * + * Devices that do not implement a Session Usage Table may return + * OEMCrypto_ERROR_NOT_IMPLEMENTED. + * + * Parameters: + * [out] header_buffer: pointer to memory where encrypted usage table header + * is written. + * [in/out] header_buffer_length: (in) length of the header_buffer, in bytes. + * (out) actual length of the header_buffer + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_SHORT_BUFFER - if header_buffer_length is too small. + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Usage Table Function" and will not be called simultaneously + * with any other function, as if the CDM holds a write lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 13. + */ +OEMCryptoResult OEMCrypto_CreateUsageTableHeader(uint8_t* header_buffer, + size_t* header_buffer_length); + +/* + * OEMCrypto_LoadUsageTableHeader + * + * Description: + * This loads the Usage Table Header. The buffer's signature is verified and + * the buffer is decrypted. OEMCrypto will verify the verification string. If + * the Master Generation Number is more than 1 off, the table is considered + * bad, the headers are NOT loaded, and the error + * OEMCrypto_ERROR_GENERATION_SKEW is returned. If the generation number is + * off by 1, the warning OEMCrypto_WARNING_GENERATION_SKEW is returned but + * the header is still loaded. This warning may be logged by the CDM layer. + * + * Parameters: + * [in] buffer: pointer to memory containing encrypted usage table header. + * [in] buffer_length: length of the buffer, in bytes. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_SHORT_BUFFER + * OEMCrypto_ERROR_NOT_IMPLEMENTED - some devices do not implement usage + * tables. + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_WARNING_GENERATION_SKEW - if the generation number is off by + * exactly 1. + * OEMCrypto_ERROR_GENERATION_SKEW - if the generation number is off by more + * than 1. + * OEMCrypto_ERROR_SIGNATURE_FAILURE - if the signature failed. + * OEMCrypto_ERROR_BAD_MAGIC - verification string does not match. + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Usage Table Function" and will not be called simultaneously + * with any other function, as if the CDM holds a write lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 13. + */ +OEMCryptoResult OEMCrypto_LoadUsageTableHeader(const uint8_t* buffer, + size_t buffer_length); + +/* + * OEMCrypto_CreateNewUsageEntry + * + * Description: + * This creates a new usage entry. The size of the header will be increased + * by 8 bytes, and secure volatile memory will be allocated for it. The new + * entry will be associated with the given session. The status of the new + * entry will be set to "unused". OEMCrypto will set *usage_entry_number to + * be the index of the new entry. The first entry created will have index 0. + * The new entry will be initialized with a generation number equal to the + * master generation number, which will also be stored in the header's new + * slot. Then the master generation number will be incremented. Since each + * entry's generation number is less than the master generation number, the + * new entry will have a generation number that is larger than all other + * entries and larger than all previously deleted entries. This helps prevent + * a rogue application from deleting an entry and then loading an old version + * of it. + * + * Parameters: + * [in] session: handle for the session to be used. + * [out] usage_entry_number: index of new usage entry. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_NOT_IMPLEMENTED - some devices do not implement usage + * tables. + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES - if there is no room in memory to + * increase the size of the usage table header. The CDM layer can + * delete some entries and then try again, or it can pass the error up + * to the application. + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Usage Table Function" and will not be called simultaneously + * with any other function, as if the CDM holds a write lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 13. + */ +OEMCryptoResult OEMCrypto_CreateNewUsageEntry(OEMCrypto_SESSION session, + uint32_t* usage_entry_number); + +/* + * OEMCrypto_LoadUsageEntry + * + * Description: + * This loads a usage table saved previously by UpdateUsageEntry. The + * signature at the beginning of the buffer is verified and the buffer will + * be decrypted. Then the verification field in the entry will be verified. + * The index in the entry must match the index passed in. The generation + * number in the entry will be compared against that in the header. If it is + * off by 1, a warning is returned, but the entry is still loaded. This + * warning may be logged by the CDM layer. If the generation number is off by + * more than 1, an error is returned and the entry is not loaded. + * + * If the entry is already loaded into another open session, then this fails + * and returns OEMCrypto_ERROR_INVALID_SESSION. + * + * Parameters: + * [in] session: handle for the session to be used. + * [in] usage_entry_number: index of existing usage entry. + * [in] buffer: pointer to memory containing encrypted usage table entry. + * [in] buffer_length: length of the buffer, in bytes. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_SHORT_BUFFER + * OEMCrypto_ERROR_NOT_IMPLEMENTED - some devices do not implement usage + * tables. + * OEMCrypto_ERROR_UNKNOWN_FAILURE - index beyond end of table. + * OEMCrypto_ERROR_INVALID_SESSION - entry associated with another session or + * the index is wrong. + * OEMCrypto_WARNING_GENERATION_SKEW - if the generation number is off by + * exactly 1. + * OEMCrypto_ERROR_GENERATION_SKEW - if the generation number is off by more + * than 1. + * OEMCrypto_ERROR_SIGNATURE_FAILURE - if the signature failed. + * OEMCrypto_ERROR_BAD_MAGIC - verification string does not match. + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Usage Table Function" and will not be called simultaneously + * with any other function, as if the CDM holds a write lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 13. + */ +OEMCryptoResult OEMCrypto_LoadUsageEntry(OEMCrypto_SESSION session, + uint32_t usage_entry_number, + const uint8_t* buffer, + size_t buffer_length); + +/* + * OEMCrypto_UpdateUsageEntry + * + * Description: + * Updates the session's usage entry and fills buffers with the encrypted and + * signed entry and usage table header. OEMCrypto will update all time and + * status values in the entry, and then increment the entry's generation + * number. The corresponding generation number in the usage table header is + * also incremented so that it matches the one in the entry. The master + * generation number in the usage table header is incremented and is copied + * to secure persistent storage. OEMCrypto will encrypt and sign the entry + * into the entry_buffer, and it will encrypt and sign the usage table header + * into the header_buffer. Some actions, such as the first decrypt and + * deactivating an entry, will also increment the entry's generation number + * as well as changing the entry's status and time fields. As in OEMCrypto + * v12, the first decryption will change the status from Inactive to Active, + * and it will set the time stamp "first decrypt". + * + * If the usage entry has the flag ForbidReport set, then the flag is + * cleared. It is the responsibility of the CDM layer to call this function + * and save the usage table before the next call to ReportUsage and before + * the CDM is terminated. Failure to do so will result in generation number + * skew, which will invalidate all of the usage table. + * + * If either entry_buffer_length is not large enough, they are set to the + * needed size, and OEMCrypto_ERROR_SHORT_BUFFER. In this case, the entry is + * not updated, ForbidReport is not cleared, generation numbers are not + * incremented, and no other work is done. + * + * Parameters: + * [in] session: handle for the session to be used. + * [out] header_buffer: pointer to memory where encrypted usage table header + * is written. + * [in/out] header_buffer_length: (in) length of the header_buffer, in bytes. + * (out) actual length of the header_buffer + * [out] entry_buffer: pointer to memory where encrypted usage table entry is + * written. + * [in/out] entry_buffer_length: (in) length of the entry_buffer, in bytes. + * (out) actual length of the entry_buffer + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_SHORT_BUFFER + * OEMCrypto_ERROR_NOT_IMPLEMENTED - some devices do not implement usage + * tables. + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Usage Table Function" and will not be called simultaneously + * with any other function, as if the CDM holds a write lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 13. + */ +OEMCryptoResult OEMCrypto_UpdateUsageEntry(OEMCrypto_SESSION session, + SharedMemory* header_buffer, + size_t* header_buffer_length, + SharedMemory* entry_buffer, + size_t* entry_buffer_length); + +/* + * OEMCrypto_DeactivateUsageEntry + * + * Description: + * This deactivates the usage entry associated with the current session. This + * means that the state of the usage entry is changed to InactiveUsed if it + * was Active, or InactiveUnused if it was Unused. This also increments the + * entry's generation number, and the header's master generation number. The + * entry's flag ForbidReport will be set. This flag prevents an application + * from generating a report of a deactivated license without first saving the + * entry. + * + * It is allowed to call this function multiple times. If the state is + * already InactiveUsed or InactiveUnused, then this function does not change + * the entry or its state. + * + * Parameters: + * [in] session: handle for the session to be used. + * [in] pst: pointer to memory containing Provider Session Token. + * [in] pst_length: length of the pst, in bytes. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_INVALID_CONTEXT - an entry was not created or loaded, or + * the pst does not match. + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support pst sizes of at least 255 bytes. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. + * + * Threading: + * This is a "Usage Table Function" and will not be called simultaneously + * with any other function, as if the CDM holds a write lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 13. + */ +OEMCryptoResult OEMCrypto_DeactivateUsageEntry(OEMCrypto_SESSION session, + const uint8_t* pst, + size_t pst_length); + +/* + * OEMCrypto_ReportUsage + * + * Description: + * All fields of OEMCrypto_PST_Report are in network byte order. + * + * If the buffer_length is not sufficient to hold a report structure, set + * buffer_length and return OEMCrypto_ERROR_SHORT_BUFFER. + * + * If the an entry was not loaded or created with + * OEMCrypto_CreateNewUsageEntry or OEMCRypto_LoadUsageEntry, or if the pst + * does not match that in the entry, return the error + * OEMCrypto_ERROR_INVALID_CONTEXT. + * + * If the usage entry's flag ForbidReport is set, indicating the entry has + * not been saved since the entry was deactivated, then the error + * OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE is returned and a report is not + * generated. Similarly, if any key in the session has been used since the + * last call to OEMCrypto_UpdateUsageEntry, then the report is not generated, + * and OEMCrypto returns the error OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE. + * + * The pst_report is filled out by subtracting the times in the Usage Entry + * from the current time on the secure clock. This is done in case the secure + * clock is not using UTC time, but is instead using something like seconds + * since clock installed. + * + * Valid values for status are: + * + * - 0 = kUnused -- the keys have not been used to decrypt. + * - 1 = kActive -- the keys have been used, and have not been deactivated. + * - 2 = kInactive - deprecated. Use kInactiveUsed or kInactiveUnused. + * - 3 = kInactiveUsed -- the keys have been marked inactive after being + * active. + * - 4 = kInactiveUnused -- they keys have been marked inactive, but were + * never active. + * The clock_security_level is reported as follows: + * + * - 0 = Insecure Clock - clock just uses system time. + * - 1 = Secure Timer - clock runs from a secure timer which is initialized + * from system time when OEMCrypto becomes active and cannot be modified + * by user software or the user while OEMCrypto is active. + * - 2 = Secure Clock - Real-time clock set from a secure source that + * cannot be modified by user software regardless of whether OEMCrypto + * is active or inactive. The clock time can only be modified by + * tampering with the security software or hardware. + * - 3 = Hardware Secure Clock - Real-time clock set from a secure source + * that cannot be modified by user software and there are security + * features that prevent the user from modifying the clock in hardware, + * such as a tamper proof battery. + * After pst_report has been filled in, the HMAC SHA1 signature is computed + * for the buffer from bytes 20 to the end of the pst field. The signature is + * computed using the mac_key[client] which is stored in the usage table. The + * HMAC SHA1 signature is used to prevent a rogue application from using + * OMECrypto_GenerateSignature to forge a Usage Report. + * + * Devices that do not implement a Session Usage Table may return + * OEMCrypto_ERROR_NOT_IMPLEMENTED. + * + * Parameters: + * [in] session: handle for the session to be used. + * [in] pst: pointer to memory containing Provider Session Token. + * [in] pst_length: length of the pst, in bytes. + * [out] buffer: pointer to buffer in which usage report should be stored. + * May be null on the first call in order to find required buffer size. + * [in/out] buffer_length: (in) length of the report buffer, in bytes. + * (out) actual length of the report + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_SHORT_BUFFER - if report buffer is not large enough to + * hold the output report. + * OEMCrypto_ERROR_INVALID_SESSION - no open session with that id. + * OEMCrypto_ERROR_INVALID_CONTEXT + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE - if no call to UpdateUsageEntry since + * last call to Deactivate or since key use. + * OEMCrypto_ERROR_WRONG_PST - report asked for wrong pst. + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support pst sizes of at least 255 bytes. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. + * + * Threading: + * This is a "Usage Table Function" and will not be called simultaneously + * with any other function, as if the CDM holds a write lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 13. + */ +OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session, + const uint8_t* pst, size_t pst_length, + uint8_t* buffer, + size_t* buffer_length); + +/* + * OEMCrypto_DeleteUsageEntry + * + * Description: + * This function verifies the signature of the given message using the sessions + * mac_key[server] and the algorithm HMAC-SHA256, and then deletes an entry from + * the session table. The session should already be associated with the given + * entry, from a previous call to OEMCrypto_ReportUsage. + * + * After performing all verification listed below, and deleting the entry from + * the Usage Table, OEMCrypto will increment Usage Table’s generation number, and + * then sign, encrypt, and save the Usage Table. + * + * The signature verification shall use a constant-time algorithm (a signature + * mismatch will always take the same time as a successful comparison). + * + * Devices that do not implement a Session Usage Table may return + * OEMCrypto_ERROR_NOT_IMPLEMENTED. + * + * Verification: + * The following checks should be performed. If any check fails, an error is + * returned. + * 1. The pointer pst is not null, and points inside the message. If not, return + * OEMCrypto_ERROR_UNKNOWN_FAILURE. + * 2. The signature of the message shall be computed, and the API shall verify + * the computed signature matches the signature passed in. The signature will be + * computed using HMAC-SHA256 and the mac_key_server. If they do not match, + * return OEMCrypto_ERROR_SIGNATURE_FAILURE. + * 3. If the session is not associated with an entry in the Usage Table, return + * OEMCrypto_ERROR_UNKNOWN_FAILURE. + * 4. If the pst passed in as a parameter does not match that in the Usage Table, + * return OEMCrypto_ERROR_UNKNOWN_FAILURE. + * + * Parameters: + * [in] session - handle for the session to be used. + * [in] pst - pointer to memory containing Provider Session Token. + * [in] pst_length - length of the pst, in bytes. + * [in] message - pointer to memory containing message to be verified. + * [in] message_length - length of the message, in bytes. + * [in] signature - pointer to memory containing the signature. + * [in] signature_length - length of the signature, in bytes. + * + * Threading: + * This function will not be called simultaneously with any session functions. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_INVALID_SESSION no open session with that id. + * OEMCrypto_ERROR_SIGNATURE_FAILURE + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * + * Version: + * This method changed in API version 9. + */ +OEMCryptoResult OEMCrypto_DeleteUsageEntry(OEMCrypto_SESSION session, + const uint8_t* pst, + size_t pst_length, + const uint8_t *message, + size_t message_length, + const uint8_t *signature, + size_t signature_length); + +/* + * OEMCrypto_ForceDeleteUsageEntry + * + * Description: + * This function deletes an entry from the session usage table. This will be + * used for stale entries without a signed request from the server. + * + * After performing all verification listed below, and deleting the entry from + * the Usage Table, OEMCrypto will increment the Usage Table’s generation number, + * and then sign, encrypt, and save the Usage Table. + * + * Devices that do not implement a Session Usage Table may return + * OEMCrypto_ERROR_NOT_IMPLEMENTED. + * + * Verification + * The following checks should be performed. If any check fails, an error is + * returned. + * 1) The pointer pst is not null. If not, return OEMCrypto_ERROR_UNKNOWN_FAILURE. + * + * Parameters + * [in] pst - pointer to memory containing Provider Session Token. + * [in] pst_length - length of the pst, in bytes. + * + * Returns + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * + * Threading + * This function will not be called simultaneously with any session functions. + * + * Version + * This method changed in API version 10. + */ +OEMCryptoResult OEMCrypto_ForceDeleteUsageEntry(const uint8_t* pst, + size_t pst_length); + +/* + * OEMCrypto_MoveEntry + * + * Description: + * Moves the entry associated with the current session from one location in + * the usage table header to another. This function is used by the CDM layer + * to defragment the usage table. This does not modify any data in the entry, + * except the index and the generation number. The index in the session's + * usage entry will be changed to new_index. The generation number in + * session's usage entry and in the header for new_index will be increased to + * the master generation number, and then the master generation number is + * incremented. If there was an existing entry at the new location, it will + * be overwritten. It is an error to call this when the entry that was at + * new_index is associated with a currently open session. In this case, the + * error code OEMCrypto_ERROR_ENTRY_IN_USE is returned. It is the CDM layer's + * responsibility to call UpdateUsageEntry after moving an entry. It is an + * error for new_index to be beyond the end of the existing usage table + * header. + * + * Devices that do not implement a Session Usage Table may return + * OEMCrypto_ERROR_NOT_IMPLEMENTED. + * + * Parameters: + * [in] session: handle for the session to be used. + * [in] new_index: new index to be used for the session's usage entry + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_ENTRY_IN_USE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Usage Table Function" and will not be called simultaneously + * with any other function, as if the CDM holds a write lock on the OEMCrypto + * system. + * + * Version: + * This method is new in API version 13. + */ +OEMCryptoResult OEMCrypto_MoveEntry(OEMCrypto_SESSION session, + uint32_t new_index); + +/* + * OEMCrypto_ShrinkUsageTableHeader + * + * Description: + * This shrinks the usage table and the header. This function is used by the + * CDM layer after it has defragmented the usage table and can delete unused + * entries. It is an error if any open session is associated with an entry + * that will be erased - the error OEMCrypto_ERROR_ENTRY_IN_USE shall be + * returned in this case. If new_table_size is larger than the current size, + * then the header is not changed and the error is returned. If the header + * has not been previously loaded, then an error is returned. OEMCrypto will + * increment the master generation number in the header and store the new + * value in secure persistent storage. Then, OEMCrypto will encrypt and sign + * the header into the provided buffer. The generation numbers of all + * remaining entries will remain unchanged. The next time + * OEMCrypto_CreateNewUsageEntry is called, the new entry will have an index + * of new_table_size. + * + * Devices that do not implement a Session Usage Table may return + * OEMCrypto_ERROR_NOT_IMPLEMENTED. + * + * If header_buffer_length is not large enough to hold the new table, it is + * set to the needed value, the generation number is not incremented, and + * OEMCrypto_ERROR_SHORT_BUFFER is returned. + * + * Parameters: + * [in] new_entry_count: number of entries in the to be in the header. + * [out] header_buffer: pointer to memory where encrypted usage table header + * is written. + * [in/out] header_buffer_length: (in) length of the header_buffer, in bytes. + * (out) actual length of the header_buffer + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_SHORT_BUFFER + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_ENTRY_IN_USE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Usage Table Function" and will not be called simultaneously + * with any other function, as if the CDM holds a write lock on the OEMCrypto + * system. + * + * Version: + * This method is new in API version 13. + */ +OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader(uint32_t new_entry_count, + uint8_t* header_buffer, + size_t* header_buffer_length); + +/* + * OEMCrypto_CopyOldUsageEntry + * + * Description: + * This function copies an entry from the old v12 table to the new table. The + * new entry will already have been loaded by CreateNewUsageEntry. If the + * device did not support pre-v13 usage tables, this may return + * OEMCrypto_ERROR_NOT_IMPLEMENTED. + * + * This is only needed for devices that are upgrading from a version of + * OEMCrypto before v13 to a recent version. Devices that have an existing + * usage table with customer's offline licenses will use this method to move + * entries from the old table to the new one. + * + * Parameters: + * [in] session: handle for the session to be used. + * [in] pst: pointer to memory containing Provider Session Token. + * [in] pst_length: length of the pst, in bytes. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Usage Table Function" and will not be called simultaneously + * with any other function, as if the CDM holds a write lock on the OEMCrypto + * system. + * + * Version: + * This method is new in API version 13. + */ +OEMCryptoResult OEMCrypto_CopyOldUsageEntry(OEMCrypto_SESSION session, + const uint8_t* pst, + size_t pst_length); + +/* + * OEMCrypto_DeleteOldUsageTable + * + * Description: + * This function will delete the old usage table, if possible, freeing any + * nonvolatile secure memory. This may return OEMCrypto_ERROR_NOT_IMPLEMENTED + * if the device did not support pre-v13 usage tables. + * + * This is only needed for devices that are upgrading from a version of + * OEMCrypto before v13 to a recent version. Devices that have an existing + * usage table with customer's offline licenses will use this method to move + * entries from the old table to the new one. + * + * Parameters: + * none + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. + * + * Version: + * This method is new in API version 13. + */ +OEMCryptoResult OEMCrypto_DeleteOldUsageTable(void); + +/* + * OEMCrypto_RemoveSRM + * + * Description: + * Delete the current SRM. Any valid SRM, regardless of version number, will + * be installable after this via OEMCrypto_LoadSRM. + * + * This function should not be implemented on production devices, and will + * only be used to verify unit tests on a test device. + * + * Parameters: + * none + * + * Returns: + * OEMCrypto_SUCCESS - if the SRM file was deleted. + * OEMCrypto_ERROR_NOT_IMPLEMENTED - always on production devices. + * + * Threading: + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. + * + * Version: + * This method is new in API version 13. + */ +OEMCryptoResult OEMCrypto_RemoveSRM(void); + +/* + * OEMCrypto_CreateOldUsageEntry + * + * Description: + * This forces the creation of an entry in the old usage table in order to + * test OEMCrypto_CopyOldUsageTable. OEMCrypto will create a new entry, set + * the status and compute the times at license receive, first decrypt and + * last decrypt. The mac keys will be copied to the entry. The mac keys are + * not encrypted, but will only correspond to a test license. + * + * Devices that do not support usage tables, or devices that will not be + * field upgraded from a version of OEMCrypto before v13 to a recent version + * may return OEMCrypto_ERROR_NOT_IMPLEMENTED. + * + * Parameters: + * TODO(fredgc): add appropriate comments for parameters + * [in] time_since_license_received: + * [in] time_since_first_decrypt: + * [in] time_since_last_decrypt: + * [in] status: + * [in] server_mac_key + * [in] client_mac_key + * [in] pst + * [in] pst_length + * + * Returns: + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_SUCCESS + * + * Threading: + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. It is only used when running unit tests. + * + * Version: + * This method is new in API version 13. + */ +OEMCryptoResult OEMCrypto_CreateOldUsageEntry(uint64_t time_since_license_received, + uint64_t time_since_first_decrypt, + uint64_t time_since_last_decrypt, + OEMCrypto_Usage_Entry_Status status, + uint8_t *server_mac_key, + uint8_t *client_mac_key, + const uint8_t* pst, + size_t pst_length); + +/* + * OEMCrypto_SupportsDecryptHash + * + * Description: + * Returns the type of hash function supported for Full Decrypt Path Testing. + * A hash type of OEMCrypto_Hash_Not_Supported = 0 means this feature is not + * supported. OEMCrypto is not required by Google to support this feature, + * but support will greatly improve automated testing. A hash type of + * OEMCrypto_CRC_Clear_Buffer = 1 means the device will be able to compute + * the CRC32 checksum of the decrypted content in the secure buffer after a + * call to OEMCrypto_DecryptCENC. Google intends to provide test applications + * on some platforms, such as Android, that will automate decryption testing + * using the CRC 32 checksum of all frames in some test content. + * + * If an SOC vendor cannot support CRC 32 checksums of decrypted output, but + * can support some other hash or checksum, then the function should return + * OEMCrypto_Partner_Defined_Hash = 2 and those partners should modify the + * test application to compute the appropriate hash. An application that + * computes the CRC 32 hashes of test content and builds a hash file in the + * correct format will be provided by Widevine. The source of this + * application will be provided so that partners may modify it to compute + * their own hash format and generate their own hashes. + * + * Returns: + * OEMCrypto_Hash_Not_Supported = 0; + * OEMCrypto_CRC_Clear_Buffer = 1; + * OEMCrypto_Partner_Defined_Hash = 2; + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method is new in API version 15. + */ +uint32_t OEMCrypto_SupportsDecryptHash(void); + +/* + * OEMCrypto_SetDecryptHash + * + * Description: + * Set the hash value for the next frame to be decrypted. This function is + * called before the first subsample is passed to OEMCrypto_DecryptCENC, when + * the subsample_flag has the bit OEMCrytpo_FirstSubsample set. The hash is + * over all of the frame or sample: encrypted and clear subsamples + * concatenated together, up to, and including the subsample with the + * subsample_flag having the bit OEMCrypto_LastSubsample set. If hashing the + * output is not supported, then this will return + * OEMCrypto_ERROR_NOT_IMPLEMENTED. If the hash is ill formed or there are + * other error conditions, this returns OEMCrypto_ERROR_UNKNOWN_FAILURE. The + * length of the hash will be at most 128 bytes. + * + * This may be called before the first call to SelectKey. In that case, this + * function cannot verify that the key control block allows hash + * verification. The function DecryptCENC should verify that the key control + * bit allows hash verification when it is called. If an attempt is made to + * compute a hash when the selected key does not have the bit + * Allow_Hash_Verification set, then a hash should not be computed, and + * OEMCrypto_GetHashErrorCode should return the error + * OEMCrypto_ERROR_UNKNOWN_FAILURE. + * + * OEMCrypto should compute the hash of the frame and then compare it with + * the correct value. If the values differ, then OEMCrypto should latch in an + * error and save the frame number of the bad hash. It is allowed for + * OEMCrypto to postpone computation of the hash until the frame is + * displayed. This might happen if the actual decryption operation is carried + * out by a later step in the video pipeline, or if you are using a partner + * specified hash of the decoded frame. For this reason, an error state must + * be saved until the call to OEMCrypto_GetHashErrorCode is made. + * + * Parameters: + * [in] session: session id for current decrypt operation + * [in] frame_number: frame number for the recent DecryptCENC sample. + * [in] hash: hash or CRC of previously decrypted frame. + * [in] hash_length: length of hash, in bytes. + * + * Returns: + * OEMCrypto_SUCCESS - if the hash was set + * OEMCrypto_ERROR_NOT_IMPLEMENTED - function not implemented + * OEMCrypto_ERROR_INVALID_SESSION - session not open + * OEMCrypto_ERROR_SHORT_BUFFER - hash_length too short for supported hash + * type + * OEMCrypto_ERROR_BUFFER_TOO_LARGE - hash_length too long for supported hash + * type + * OEMCrypto_ERROR_UNKNOWN_FAILURE - other error + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method is new in API version 15. + */ +OEMCryptoResult OEMCrypto_SetDecryptHash(OEMCrypto_SESSION session, + uint32_t frame_number, + const uint8_t* hash, + size_t hash_length); + +/* + * OEMCrypto_GetHashErrorCode + * + * Description: + * If the hash set in OEMCrypto_SetDecryptHash did not match the computed + * hash, then an error code was saved internally. This function returns that + * error and the frame number of the bad hash. This will be called + * periodically, but might not be in sync with the decrypt loop. OEMCrypto + * shall not reset the error state to "no error" once any frame has failed + * verification. It should be initialized to "no error" when the session is + * first opened. If there is more than one bad frame, it is the implementer's + * choice if it is more useful to return the number of the first bad frame, + * or the most recent bad frame. + * + * If the hash could not be computed -- either because the + * Allow_Hash_Verification was not set in the key control block, or because + * there were other issues -- this function should return + * OEMCrypto_ERROR_UNKNOWN_FAILURE. + * + * Parameters: + * [in] session: session id for operation. + * [out] failed_frame_number: frame number for sample with incorrect hash. + * + * Returns: + * OEMCrypto_SUCCESS - if all frames have had a correct hash + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_BAD_HASH - if any frame had an incorrect hash + * OEMCrypto_ERROR_UNKNOWN_FAILURE - if the hash could not be computed + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * Version: + * This method is new in API version 15. + */ +OEMCryptoResult OEMCrypto_GetHashErrorCode(OEMCrypto_SESSION session, + uint32_t* failed_frame_number); + +#ifdef __cplusplus +} +#endif + +#endif // OEMCRYPTO_CENC_H_ diff --git a/serialization/api_support.c b/serialization/api_support.c new file mode 100644 index 0000000..5477ebe --- /dev/null +++ b/serialization/api_support.c @@ -0,0 +1,123 @@ +/* + * Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine Master + * License Agreement. + */ + +/* + * Support functions for the OEMCrypto API functions, related to + * message handling + */ + +#include "OEMCryptoCENC.h" +#include "api_support.h" +#include "bump_allocator.h" +#include "message.h" +#include "shared_memory_allocator.h" +#include "shared_memory_interface.h" +#include "special_cases.h" +#include "transport_interface.h" + +/* + * If true, the system has been invalidated due to a communications + * breakdown with the TEE. This is a persistent condition and will + * cause OEMCrypto_ERROR_SYSTEM_INVALIDATED to be returned from any + * function that returns an OEMCryptoResult until the transport + * interface is reinitialized. +*/ +static bool system_invalidated; + +/* + * This is the result code to be returned from any function that + * returns OEMCryptoResult code. + */ +OEMCryptoResult api_result; + +/* + * odkitee OEMCrypto API is single threaded + */ +pthread_mutex_t api_lock; + +/* + * Called at the beginning of every API function. Checks configuration + * state and if it is okay allocates a request message. Sets + * api_result based on the status of the operations, which will be + * returned from any API function that returns an OEMCryptoResult + * code. On exit, if api_result is not OEMCrypto_SUCCESS or NULL is + * returned, then any allocated messages will have been deallocated + * prior to returning. + */ +Message *API_InitializeRequest(void) { + api_result = OEMCrypto_SUCCESS; + + SharedMemory_Reset(); + BumpAllocator_Reset(); + Message* request = ODK_Transport_AllocateMessage(); + if (request == NULL) { + api_result = OEMCrypto_ERROR_INSUFFICIENT_RESOURCES; + } else if (GetStatus(request) != MESSAGE_STATUS_OK) { + /* The transport allocator must return initialized messages */ + api_result = OEMCrypto_ERROR_SYSTEM_INVALIDATED; + } + if (api_result != OEMCrypto_SUCCESS) { + if (request != NULL) { + ODK_Transport_DeallocateMessage(request); + request = NULL; + } + } + return request; +} + +/* + * Called to send the request message to the TEE and receive the + * response. Sets api_result based on the status of the + * operations. Returns either a valid response message or NULL. If + * NULL is returned or api_result != OEMCrypto_SUCCESS then any + * allocated messages will have been deallocated prior to returning. + */ +Message *API_Transact(Message* request) { + if (api_result != OEMCrypto_SUCCESS || request == NULL) { + return NULL; + } + ODK_Transport_Status transport_status = ODK_Transport_SendMessage(request); + Message* response = NULL; + if (transport_status == ODK_TRANSPORT_STATUS_IO_ERROR) { + api_result = OEMCrypto_ERROR_SYSTEM_INVALIDATED; + } else { + transport_status = ODK_Transport_ReceiveMessage(&response); + if (transport_status == ODK_TRANSPORT_STATUS_IO_ERROR || response == NULL) { + api_result = OEMCrypto_ERROR_SYSTEM_INVALIDATED; + } else if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + } + if (api_result != OEMCrypto_SUCCESS) { + if (response) { + ODK_Transport_DeallocateMessage(response); + response = NULL; + } + } + return response; +} + +/* + * Called at the end of every API function. Sets system_invalidated if + * the local api_result indicates a failure in the current + * function. Once system_invalidated is set, it will persist until + * reset by the next OEMCrypto_Inititalize/OEMCrypto_Terminate. + */ +OEMCryptoResult API_CheckResult(OEMCryptoResult unpacked_result) { + if (api_result == OEMCrypto_ERROR_SYSTEM_INVALIDATED) { + system_invalidated = true; + } else if (api_result == OEMCrypto_SUCCESS) { + api_result = unpacked_result; + } + return api_result; +} + +/* + * Called by OEMCrypto_Terminate + */ +void API_Terminate(void) { + system_invalidated = false; +} diff --git a/serialization/api_support.h b/serialization/api_support.h new file mode 100644 index 0000000..6af58c8 --- /dev/null +++ b/serialization/api_support.h @@ -0,0 +1,45 @@ +/* + * Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine Master + * License Agreement. + */ + +/* + * Support functions for the OEMCrypto API functions, related to + * message handling + */ + +#include + +#include "OEMCryptoCENC.h" +#include "bump_allocator.h" +#include "deserializer.h" +#include "marshaller_base.h" +#include "serializer.h" +#include "shared_memory_allocator.h" +#include "shared_memory_interface.h" +#include "special_cases.h" +#include "transport_interface.h" + +#ifndef ODKITEE_API_SUPPORT_H_ +#define ODKITEE_API_SUPPORT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define OEMCRYPTO_API __attribute__((visibility("default"))) + +extern pthread_mutex_t api_lock; +extern OEMCryptoResult api_result; + +Message *API_InitializeRequest(); +Message *API_Transact(Message *request); +OEMCryptoResult API_CheckResult(OEMCryptoResult unpacked_result); +void API_Terminate(); + +#ifdef __cplusplus +} +#endif + +#endif /* ODKITEE_API_SUPOPRT_H_ */ diff --git a/serialization/bump_allocator.c b/serialization/bump_allocator.c new file mode 100644 index 0000000..f096ff8 --- /dev/null +++ b/serialization/bump_allocator.c @@ -0,0 +1,61 @@ +/* + * 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 "bump_allocator.h" + +#include +#include +#include + +#define INITIAL_ALLOCATOR_BUFFER_SIZE (8 * 1024) + +static uint8_t buffer[INITIAL_ALLOCATOR_BUFFER_SIZE]; +static uint8_t* ptr = buffer; +static size_t buffer_size = sizeof(buffer); +static size_t buffer_offset = 0; + +uint8_t* BumpAllocate(size_t nbytes) { + size_t new_offset = 0; + if(__builtin_add_overflow(buffer_offset, nbytes, &new_offset) || + (new_offset > buffer_size)) { + /* + * The bump allocator buffer should be large enough that a malloc + * is never required. But allow a malloc if the buffer overflows. + */ + fprintf(stderr, "Warning: bump allocator memory size exceeded," + " size=%zd, requested=%zd\n", buffer_size, new_offset); + size_t new_size = 2 * buffer_size; + uint8_t* new_ptr = malloc(new_size); + if (new_ptr == NULL) { + fprintf(stderr, "Fatal: bump allocator could not malloc %zd bytes\n", + new_size); + abort(); + } + memcpy(new_ptr, ptr, buffer_size); + memset(new_ptr + buffer_size, 0, buffer_size); + buffer_size = new_size; + if (ptr != buffer) { + free(ptr); + } + ptr = new_ptr; + } + uint8_t* result = ptr + buffer_offset; + memset(result, 0, nbytes); + buffer_offset = new_offset; + return result; +} + +void BumpAllocator_Reset(void) { + buffer_offset = 0; + if (ptr != buffer) { + free(ptr); + } + ptr = buffer; + buffer_size = sizeof(buffer); + memset(buffer, 0, sizeof(buffer)); +} + + diff --git a/serialization/bump_allocator.h b/serialization/bump_allocator.h new file mode 100644 index 0000000..5d58539 --- /dev/null +++ b/serialization/bump_allocator.h @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#ifndef ODKITEE_BUMP_ALLOCATOR_H_ +#define ODKITEE_BUMP_ALLOCATOR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* + * Simple bump allocator. Allocate memory chunks from a fixed region + * at consecutively increasing offsets. The memory is all released + * when BumpAllocator_Reset is called. + */ +uint8_t* BumpAllocate(size_t size); +void BumpAllocator_Reset(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif //ODKITEE_BUMP_ALLOCATOR_H_ diff --git a/serialization/generated_src/deserializer.c b/serialization/generated_src/deserializer.c new file mode 100644 index 0000000..adad72f --- /dev/null +++ b/serialization/generated_src/deserializer.c @@ -0,0 +1,2116 @@ +/* + * 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. + */ + +/* + * This code is auto-generated, do not edit + */ + +#include "deserializer.h" + +#include + +#include "marshaller_base.h" +#include "serialization_base.h" +#include "serializer.h" +#include "shared_memory_allocator.h" +#include "special_cases.h" + +bool Is_Valid_OEMCryptoResult(uint32_t value) { + switch (value) { + case 0: /* OEMCrypto_SUCCESS */ + case 1: /* OEMCrypto_ERROR_INIT_FAILED */ + case 2: /* OEMCrypto_ERROR_TERMINATE_FAILED */ + case 3: /* OEMCrypto_ERROR_OPEN_FAILURE */ + case 4: /* OEMCrypto_ERROR_CLOSE_FAILURE */ + case 5: /* OEMCrypto_ERROR_ENTER_SECURE_PLAYBACK_FAILED */ + case 6: /* OEMCrypto_ERROR_EXIT_SECURE_PLAYBACK_FAILED */ + case 7: /* OEMCrypto_ERROR_SHORT_BUFFER */ + case 8: /* OEMCrypto_ERROR_NO_DEVICE_KEY */ + case 9: /* OEMCrypto_ERROR_NO_ASSET_KEY */ + case 10: /* OEMCrypto_ERROR_KEYBOX_INVALID */ + case 11: /* OEMCrypto_ERROR_NO_KEYDATA */ + case 12: /* OEMCrypto_ERROR_NO_CW */ + case 13: /* OEMCrypto_ERROR_DECRYPT_FAILED */ + case 14: /* OEMCrypto_ERROR_WRITE_KEYBOX */ + case 15: /* OEMCrypto_ERROR_WRAP_KEYBOX */ + case 16: /* OEMCrypto_ERROR_BAD_MAGIC */ + case 17: /* OEMCrypto_ERROR_BAD_CRC */ + case 18: /* OEMCrypto_ERROR_NO_DEVICEID */ + case 19: /* OEMCrypto_ERROR_RNG_FAILED */ + case 20: /* OEMCrypto_ERROR_RNG_NOT_SUPPORTED */ + case 21: /* OEMCrypto_ERROR_SETUP */ + case 22: /* OEMCrypto_ERROR_OPEN_SESSION_FAILED */ + case 23: /* OEMCrypto_ERROR_CLOSE_SESSION_FAILED */ + case 24: /* OEMCrypto_ERROR_INVALID_SESSION */ + case 25: /* OEMCrypto_ERROR_NOT_IMPLEMENTED */ + case 26: /* OEMCrypto_ERROR_NO_CONTENT_KEY */ + case 27: /* OEMCrypto_ERROR_CONTROL_INVALID */ + case 28: /* OEMCrypto_ERROR_UNKNOWN_FAILURE */ + case 29: /* OEMCrypto_ERROR_INVALID_CONTEXT */ + case 30: /* OEMCrypto_ERROR_SIGNATURE_FAILURE */ + case 31: /* OEMCrypto_ERROR_TOO_MANY_SESSIONS */ + case 32: /* OEMCrypto_ERROR_INVALID_NONCE */ + case 33: /* OEMCrypto_ERROR_TOO_MANY_KEYS */ + case 34: /* OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED */ + case 35: /* OEMCrypto_ERROR_INVALID_RSA_KEY */ + case 36: /* OEMCrypto_ERROR_KEY_EXPIRED */ + case 37: /* OEMCrypto_ERROR_INSUFFICIENT_RESOURCES */ + case 38: /* OEMCrypto_ERROR_INSUFFICIENT_HDCP */ + case 39: /* OEMCrypto_ERROR_BUFFER_TOO_LARGE */ + case 40: /* OEMCrypto_WARNING_GENERATION_SKEW */ + case 41: /* OEMCrypto_ERROR_GENERATION_SKEW */ + case 42: /* OEMCrypto_LOCAL_DISPLAY_ONLY */ + case 43: /* OEMCrypto_ERROR_ANALOG_OUTPUT */ + case 44: /* OEMCrypto_ERROR_WRONG_PST */ + case 45: /* OEMCrypto_ERROR_WRONG_KEYS */ + case 46: /* OEMCrypto_ERROR_MISSING_MASTER */ + case 47: /* OEMCrypto_ERROR_LICENSE_INACTIVE */ + case 48: /* OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE */ + case 49: /* OEMCrypto_ERROR_ENTRY_IN_USE */ + case 50: /* OEMCrypto_ERROR_USAGE_TABLE_UNRECOVERABLE */ + case 51: /* OEMCrypto_KEY_NOT_LOADED */ + case 52: /* OEMCrypto_KEY_NOT_ENTITLED */ + case 53: /* OEMCrypto_ERROR_BAD_HASH */ + case 54: /* OEMCrypto_ERROR_OUTPUT_TOO_LARGE */ + case 55: /* OEMCrypto_ERROR_SESSION_LOST_STATE */ + case 56: /* OEMCrypto_ERROR_SYSTEM_INVALIDATED */ + return true; + default: + return false; + } +} + +bool Is_Valid_OEMCryptoBufferType(uint32_t value) { + switch (value) { + case 0: /* OEMCrypto_BufferType_Clear */ + case 1: /* OEMCrypto_BufferType_Secure */ + case 2: /* OEMCrypto_BufferType_Direct */ + return true; + default: + return false; + } +} + +bool Is_Valid_OEMCryptoCipherMode(uint32_t value) { + switch (value) { + case 0: /* OEMCrypto_CipherMode_CTR */ + case 1: /* OEMCrypto_CipherMode_CBC */ + return true; + default: + return false; + } +} + +bool Is_Valid_OEMCrypto_LicenseType(uint32_t value) { + switch (value) { + case 0: /* OEMCrypto_ContentLicense */ + case 1: /* OEMCrypto_EntitlementLicense */ + return true; + default: + return false; + } +} + +bool Is_Valid_OEMCrypto_Algorithm(uint32_t value) { + switch (value) { + case 0: /* OEMCrypto_AES_CBC_128_NO_PADDING */ + case 1: /* OEMCrypto_HMAC_SHA256 */ + return true; + default: + return false; + } +} + +bool Is_Valid_OEMCrypto_Usage_Entry_Status(uint32_t value) { + switch (value) { + case 0: /* kUnused */ + case 1: /* kActive */ + case 2: /* kInactive */ + case 3: /* kInactiveUsed */ + case 4: /* kInactiveUnused */ + return true; + default: + return false; + } +} + +bool Is_Valid_OEMCrypto_Clock_Security_Level(uint32_t value) { + switch (value) { + case 0: /* kInsecureClock */ + case 1: /* kSecureTimer */ + case 2: /* kSecureClock */ + case 3: /* kHardwareSecureClock */ + return true; + default: + return false; + } +} + +bool Is_Valid_OEMCrypto_HDCP_Capability(uint32_t value) { + switch (value) { + case 0: /* HDCP_NONE */ + case 1: /* HDCP_V1 */ + case 2: /* HDCP_V2 */ + case 3: /* HDCP_V2_1 */ + case 4: /* HDCP_V2_2 */ + case 5: /* HDCP_V2_3 */ + case 255: /* HDCP_NO_DIGITAL_OUTPUT */ + return true; + default: + return false; + } +} + +bool Is_Valid_OEMCrypto_ProvisioningMethod(uint32_t value) { + switch (value) { + case 0: /* OEMCrypto_ProvisioningError */ + case 1: /* OEMCrypto_DrmCertificate */ + case 2: /* OEMCrypto_Keybox */ + case 3: /* OEMCrypto_OEMCertificate */ + return true; + default: + return false; + } +} + +void ODK_Unpack_OEMCrypto_Substring(Message* msg, OEMCrypto_Substring* obj) { + ODK_Unpack_size_t(msg, (size_t*)&obj->offset); + ODK_Unpack_size_t(msg, (size_t*)&obj->length); +} + +void ODK_Unpack_OEMCrypto_KeyObject(Message* msg, OEMCrypto_KeyObject* obj) { + ODK_Unpack_OEMCrypto_Substring(msg, (OEMCrypto_Substring*)&obj->key_id); + ODK_Unpack_OEMCrypto_Substring(msg, (OEMCrypto_Substring*)&obj->key_data_iv); + ODK_Unpack_OEMCrypto_Substring(msg, (OEMCrypto_Substring*)&obj->key_data); + ODK_Unpack_OEMCrypto_Substring(msg, + (OEMCrypto_Substring*)&obj->key_control_iv); + ODK_Unpack_OEMCrypto_Substring(msg, (OEMCrypto_Substring*)&obj->key_control); +} + +void ODK_Unpack_OEMCrypto_EntitledContentKeyObject( + Message* msg, OEMCrypto_EntitledContentKeyObject* obj) { + ODK_Unpack_OEMCrypto_Substring( + msg, (OEMCrypto_Substring*)&obj->entitlement_key_id); + ODK_Unpack_OEMCrypto_Substring(msg, + (OEMCrypto_Substring*)&obj->content_key_id); + ODK_Unpack_OEMCrypto_Substring( + msg, (OEMCrypto_Substring*)&obj->content_key_data_iv); + ODK_Unpack_OEMCrypto_Substring(msg, + (OEMCrypto_Substring*)&obj->content_key_data); +} + +void ODK_Unpack_OEMCrypto_KeyRefreshObject(Message* msg, + OEMCrypto_KeyRefreshObject* obj) { + ODK_Unpack_OEMCrypto_Substring(msg, (OEMCrypto_Substring*)&obj->key_id); + ODK_Unpack_OEMCrypto_Substring(msg, + (OEMCrypto_Substring*)&obj->key_control_iv); + ODK_Unpack_OEMCrypto_Substring(msg, (OEMCrypto_Substring*)&obj->key_control); +} + +void ODK_Unpack_OEMCrypto_CENCEncryptPatternDesc( + Message* msg, OEMCrypto_CENCEncryptPatternDesc* obj) { + ODK_Unpack_size_t(msg, (size_t*)&obj->encrypt); + ODK_Unpack_size_t(msg, (size_t*)&obj->skip); + ODK_Unpack_size_t(msg, (size_t*)&obj->offset); +} + +void ODK_Unpack_SecurityLevel_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 23) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_SecurityLevel_Response(Message* msg, char** result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 23) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_c_str(msg, result); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_BuildInformation_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 90) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_BuildInformation_Response(Message* msg, char** result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 90) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_c_str(msg, result); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_SetSandbox_Request(Message* msg, uint8_t** sandbox_id, + size_t* sandbox_id_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 84) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, sandbox_id_length); + ODK_UnpackPointerToMemory(msg, sandbox_id); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_SetSandbox_Response(Message* msg, OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 84) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_Initialize_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 1) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_Initialize_Response(Message* msg, OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 1) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_Terminate_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 2) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_Terminate_Response(Message* msg, OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 2) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_OpenSession_Request(Message* msg, OEMCrypto_SESSION** session) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 9) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + *session = (uint32_t*)ODK_UnpackAlloc(msg, sizeof(OEMCrypto_SESSION)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_OpenSession_Response(Message* msg, OEMCryptoResult* result, + OEMCrypto_SESSION** session) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 9) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackNullable_uint32_t(msg, session); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_CloseSession_Request(Message* msg, OEMCrypto_SESSION* session) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, session); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_CloseSession_Response(Message* msg, OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GenerateDerivedKeys_Request(Message* msg, + OEMCrypto_SESSION* session, + SharedMemory** mac_key_context, + uint32_t* mac_key_context_length, + SharedMemory** enc_key_context, + uint32_t* enc_key_context_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 12) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, mac_key_context_length); + ODK_Unpack_uint32_t(msg, enc_key_context_length); + ODK_Unpack_uint32_t(msg, session); + *mac_key_context = ODK_UnpackSharedBuffer( + msg, 0, LengthFromUint32TPointer(mac_key_context_length)); + *enc_key_context = ODK_UnpackSharedBuffer( + msg, 1, LengthFromUint32TPointer(enc_key_context_length)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GenerateDerivedKeys_Response(Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 12) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_DeriveKeysFromSessionKey_Request( + Message* msg, OEMCrypto_SESSION* session, uint8_t** enc_session_key, + size_t* enc_session_key_length, SharedMemory** mac_key_context, + size_t* mac_key_context_length, SharedMemory** enc_key_context, + size_t* enc_key_context_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 21) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, enc_session_key_length); + ODK_Unpack_size_t(msg, mac_key_context_length); + ODK_Unpack_size_t(msg, enc_key_context_length); + ODK_Unpack_uint32_t(msg, session); + ODK_UnpackPointerToMemory(msg, enc_session_key); + *mac_key_context = ODK_UnpackSharedBuffer( + msg, 0, LengthFromSizeTPointer(mac_key_context_length)); + *enc_key_context = ODK_UnpackSharedBuffer( + msg, 1, LengthFromSizeTPointer(enc_key_context_length)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_DeriveKeysFromSessionKey_Response(Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 21) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GenerateNonce_Request(Message* msg, OEMCrypto_SESSION* session, + uint32_t** nonce) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 14) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, session); + *nonce = (uint32_t*)ODK_UnpackAlloc(msg, sizeof(uint32_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GenerateNonce_Response(Message* msg, OEMCryptoResult* result, + uint32_t** nonce) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 14) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackNullable_uint32_t(msg, nonce); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GenerateSignature_Request( + Message* msg, OEMCrypto_SESSION* session, SharedMemory** message, + size_t* message_length, uint8_t** signature, size_t** signature_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 13) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, message_length); + ODK_UnpackNullable_size_t(msg, signature_length); + ODK_Unpack_uint32_t(msg, session); + *message = + ODK_UnpackSharedBuffer(msg, 0, LengthFromSizeTPointer(message_length)); + *signature = (uint8_t*)ODK_UnpackAllocBuffer( + msg, LengthFromSizeTDoublePointer(signature_length), sizeof(uint8_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GenerateSignature_Response(Message* msg, + OEMCryptoResult* result, + uint8_t** signature, + size_t** signature_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 13) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, signature_length); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + ODK_UnpackPointerToMemory(msg, &p); + if (p && *signature) { + memcpy(*signature, p, + LengthAsSizeT(LengthFromSizeTDoublePointer(signature_length))); + } + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_LoadSRM_Request(Message* msg, uint8_t** buffer, + size_t* buffer_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 55) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, buffer_length); + ODK_UnpackPointerToMemory(msg, buffer); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_LoadSRM_Response(Message* msg, OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 55) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_LoadKeys_Request( + Message* msg, OEMCrypto_SESSION* session, SharedMemory** message, + size_t* message_length, SharedMemory** signature, size_t* signature_length, + OEMCrypto_Substring* enc_mac_keys_iv, OEMCrypto_Substring* enc_mac_keys, + size_t* key_array_length, OEMCrypto_KeyObject** key_array, + OEMCrypto_Substring* pst, OEMCrypto_Substring* srm_restriction_data, + OEMCrypto_LicenseType* license_type) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 83) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, message_length); + ODK_Unpack_size_t(msg, signature_length); + ODK_Unpack_size_t(msg, key_array_length); + ODK_Unpack_uint32_t(msg, session); + *message = + ODK_UnpackSharedBuffer(msg, 0, LengthFromSizeTPointer(message_length)); + *signature = + ODK_UnpackSharedBuffer(msg, 1, LengthFromSizeTPointer(signature_length)); + ODK_Unpack_OEMCrypto_Substring(msg, enc_mac_keys_iv); + ODK_Unpack_OEMCrypto_Substring(msg, enc_mac_keys); + ODK_UnpackObjArray(msg, (uint8_t**)key_array, + LengthFromSizeTPointer(key_array_length), + sizeof(OEMCrypto_KeyObject), + (ObjUnpacker)&ODK_Unpack_OEMCrypto_KeyObject); + ODK_Unpack_OEMCrypto_Substring(msg, pst); + ODK_Unpack_OEMCrypto_Substring(msg, srm_restriction_data); + ODK_Unpack_uint32_t(msg, license_type); + if (!Is_Valid_OEMCrypto_LicenseType(*license_type)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_LoadKeys_Response(Message* msg, OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 83) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_LoadEntitledContentKeys_Request( + Message* msg, OEMCrypto_SESSION* session, SharedMemory** message, + size_t* message_length, size_t* key_array_length, + OEMCrypto_EntitledContentKeyObject** key_array) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 92) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, message_length); + ODK_Unpack_size_t(msg, key_array_length); + ODK_Unpack_uint32_t(msg, session); + *message = + ODK_UnpackSharedBuffer(msg, 0, LengthFromSizeTPointer(message_length)); + ODK_UnpackObjArray( + msg, (uint8_t**)key_array, LengthFromSizeTPointer(key_array_length), + sizeof(OEMCrypto_EntitledContentKeyObject), + (ObjUnpacker)&ODK_Unpack_OEMCrypto_EntitledContentKeyObject); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_LoadEntitledContentKeys_Response(Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 92) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_RefreshKeys_Request( + Message* msg, OEMCrypto_SESSION* session, SharedMemory** message, + size_t* message_length, SharedMemory** signature, size_t* signature_length, + size_t* key_array_length, OEMCrypto_KeyRefreshObject** key_array) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 91) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, message_length); + ODK_Unpack_size_t(msg, signature_length); + ODK_Unpack_size_t(msg, key_array_length); + ODK_Unpack_uint32_t(msg, session); + *message = + ODK_UnpackSharedBuffer(msg, 0, LengthFromSizeTPointer(message_length)); + *signature = + ODK_UnpackSharedBuffer(msg, 1, LengthFromSizeTPointer(signature_length)); + ODK_UnpackObjArray(msg, (uint8_t**)key_array, + LengthFromSizeTPointer(key_array_length), + sizeof(OEMCrypto_KeyRefreshObject), + (ObjUnpacker)&ODK_Unpack_OEMCrypto_KeyRefreshObject); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_RefreshKeys_Response(Message* msg, OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 91) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_QueryKeyControl_Request(Message* msg, + OEMCrypto_SESSION* session, + uint8_t** content_key_id, + size_t* content_key_id_length, + uint8_t** key_control_block, + size_t** key_control_block_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 41) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, content_key_id_length); + ODK_UnpackNullable_size_t(msg, key_control_block_length); + ODK_Unpack_uint32_t(msg, session); + ODK_UnpackPointerToMemory(msg, content_key_id); + *key_control_block = (uint8_t*)ODK_UnpackAllocBuffer( + msg, LengthFromSizeTDoublePointer(key_control_block_length), + sizeof(uint8_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_QueryKeyControl_Response(Message* msg, OEMCryptoResult* result, + uint8_t** key_control_block, + size_t** key_control_block_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 41) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, key_control_block_length); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + ODK_UnpackPointerToMemory(msg, &p); + if (p && *key_control_block) { + memcpy(*key_control_block, p, + LengthAsSizeT( + LengthFromSizeTDoublePointer(key_control_block_length))); + } + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_SelectKey_Request(Message* msg, OEMCrypto_SESSION* session, + uint8_t** content_key_id, + size_t* content_key_id_length, + OEMCryptoCipherMode* cipher_mode) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 81) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, content_key_id_length); + ODK_Unpack_uint32_t(msg, session); + ODK_UnpackPointerToMemory(msg, content_key_id); + ODK_Unpack_uint32_t(msg, cipher_mode); + if (!Is_Valid_OEMCryptoCipherMode(*cipher_mode)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_SelectKey_Response(Message* msg, OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 81) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_DecryptCENC_Request( + Message* msg, OEMCrypto_SESSION* session, SharedMemory** data_addr, + size_t* data_addr_length, bool* is_encrypted, uint8_t* iv, + size_t* block_offset, OEMCrypto_DestBufferDesc** out_buffer, + OEMCrypto_CENCEncryptPatternDesc** pattern, uint8_t* subsample_flags) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 48) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, data_addr_length); + ODK_Unpack_uint32_t(msg, session); + *data_addr = + ODK_UnpackSharedBuffer(msg, 0, LengthFromSizeTPointer(data_addr_length)); + ODK_Unpack_bool(msg, is_encrypted); + ODK_UnpackArray(msg, &iv[0], 16); + ODK_Unpack_size_t(msg, block_offset); + ODK_UnpackNullable_OEMCrypto_DestBufferDesc(msg, out_buffer); + ODK_UnpackNullable_OEMCrypto_CENCEncryptPatternDesc(msg, pattern); + ODK_Unpack_uint8_t(msg, subsample_flags); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_DecryptCENC_Response(Message* msg, OEMCryptoResult* result, + OEMCrypto_DestBufferDesc** out_buffer) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 48) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackNullable_OEMCrypto_DestBufferDesc(msg, out_buffer); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_CopyBuffer_Request(Message* msg, OEMCrypto_SESSION* session, + SharedMemory** data_addr, + size_t* data_addr_length, + OEMCrypto_DestBufferDesc** out_buffer, + uint8_t* subsample_flags) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 93) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, data_addr_length); + ODK_Unpack_uint32_t(msg, session); + *data_addr = + ODK_UnpackSharedBuffer(msg, 0, LengthFromSizeTPointer(data_addr_length)); + ODK_UnpackNullable_OEMCrypto_DestBufferDesc(msg, out_buffer); + ODK_Unpack_uint8_t(msg, subsample_flags); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_CopyBuffer_Response(Message* msg, OEMCryptoResult* result, + OEMCrypto_DestBufferDesc** out_buffer) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 93) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackNullable_OEMCrypto_DestBufferDesc(msg, out_buffer); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_Generic_Encrypt_Request(Message* msg, + OEMCrypto_SESSION* session, + SharedMemory** in_buffer, + size_t* in_buffer_length, uint8_t* iv, + OEMCrypto_Algorithm* algorithm, + uint8_t** out_buffer) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 24) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, in_buffer_length); + ODK_Unpack_uint32_t(msg, session); + *in_buffer = + ODK_UnpackSharedBuffer(msg, 0, LengthFromSizeTPointer(in_buffer_length)); + ODK_UnpackArray(msg, &iv[0], 16); + ODK_Unpack_uint32_t(msg, algorithm); + if (!Is_Valid_OEMCrypto_Algorithm(*algorithm)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + *out_buffer = (uint8_t*)ODK_UnpackAllocBuffer( + msg, LengthFromSizeTPointer(in_buffer_length), sizeof(uint8_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_Generic_Encrypt_Response(Message* msg, OEMCryptoResult* result, + size_t* in_buffer_length, + uint8_t** out_buffer) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 24) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, in_buffer_length); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + ODK_UnpackPointerToMemory(msg, &p); + if (p && *out_buffer) { + memcpy(*out_buffer, p, + LengthAsSizeT(LengthFromSizeTPointer(in_buffer_length))); + } + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_Generic_Decrypt_Request(Message* msg, + OEMCrypto_SESSION* session, + SharedMemory** in_buffer, + size_t* in_buffer_length, uint8_t* iv, + OEMCrypto_Algorithm* algorithm, + uint8_t** out_buffer) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 25) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, in_buffer_length); + ODK_Unpack_uint32_t(msg, session); + *in_buffer = + ODK_UnpackSharedBuffer(msg, 0, LengthFromSizeTPointer(in_buffer_length)); + ODK_UnpackArray(msg, &iv[0], 16); + ODK_Unpack_uint32_t(msg, algorithm); + if (!Is_Valid_OEMCrypto_Algorithm(*algorithm)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + *out_buffer = (uint8_t*)ODK_UnpackAllocBuffer( + msg, LengthFromSizeTPointer(in_buffer_length), sizeof(uint8_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_Generic_Decrypt_Response(Message* msg, OEMCryptoResult* result, + size_t* in_buffer_length, + uint8_t** out_buffer) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 25) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, in_buffer_length); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + ODK_UnpackPointerToMemory(msg, &p); + if (p && *out_buffer) { + memcpy(*out_buffer, p, + LengthAsSizeT(LengthFromSizeTPointer(in_buffer_length))); + } + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_Generic_Sign_Request(Message* msg, OEMCrypto_SESSION* session, + SharedMemory** buffer, + size_t* buffer_length, + OEMCrypto_Algorithm* algorithm, + uint8_t** signature, + size_t** signature_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 26) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, buffer_length); + ODK_UnpackNullable_size_t(msg, signature_length); + ODK_Unpack_uint32_t(msg, session); + *buffer = + ODK_UnpackSharedBuffer(msg, 0, LengthFromSizeTPointer(buffer_length)); + ODK_Unpack_uint32_t(msg, algorithm); + if (!Is_Valid_OEMCrypto_Algorithm(*algorithm)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + *signature = (uint8_t*)ODK_UnpackAllocBuffer( + msg, LengthFromSizeTDoublePointer(signature_length), sizeof(uint8_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_Generic_Sign_Response(Message* msg, OEMCryptoResult* result, + uint8_t** signature, + size_t** signature_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 26) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, signature_length); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + ODK_UnpackPointerToMemory(msg, &p); + if (p && *signature) { + memcpy(*signature, p, + LengthAsSizeT(LengthFromSizeTDoublePointer(signature_length))); + } + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_Generic_Verify_Request(Message* msg, OEMCrypto_SESSION* session, + SharedMemory** buffer, + size_t* buffer_length, + OEMCrypto_Algorithm* algorithm, + SharedMemory** signature, + size_t* signature_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 27) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, buffer_length); + ODK_Unpack_size_t(msg, signature_length); + ODK_Unpack_uint32_t(msg, session); + *buffer = + ODK_UnpackSharedBuffer(msg, 0, LengthFromSizeTPointer(buffer_length)); + ODK_Unpack_uint32_t(msg, algorithm); + if (!Is_Valid_OEMCrypto_Algorithm(*algorithm)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + *signature = + ODK_UnpackSharedBuffer(msg, 1, LengthFromSizeTPointer(signature_length)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_Generic_Verify_Response(Message* msg, OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 27) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_UpdateUsageTable_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 30) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_UpdateUsageTable_Response(Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 30) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_WrapKeyboxOrOEMCert_Request(Message* msg, uint8_t** rot, + size_t* rotLength, + uint8_t** wrappedRot, + size_t** wrappedRotLength, + uint8_t** transportKey, + size_t* transportKeyLength) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 8) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, rotLength); + *wrappedRotLength = (size_t*)ODK_UnpackAlloc(msg, sizeof(size_t)); + ODK_Unpack_size_t(msg, transportKeyLength); + ODK_UnpackPointerToMemory(msg, rot); + *wrappedRot = (uint8_t*)ODK_UnpackAllocBuffer( + msg, LengthFromSizeTDoublePointer(wrappedRotLength), sizeof(uint8_t)); + ODK_UnpackPointerToMemory(msg, transportKey); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_WrapKeyboxOrOEMCert_Response(Message* msg, + OEMCryptoResult* result, + uint8_t** wrappedRot, + size_t** wrappedRotLength) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 8) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, wrappedRotLength); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + ODK_UnpackPointerToMemory(msg, &p); + if (p && *wrappedRot) { + memcpy(*wrappedRot, p, + LengthAsSizeT(LengthFromSizeTDoublePointer(wrappedRotLength))); + } + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_InstallKeyboxOrOEMCert_Request(Message* msg, uint8_t** rot, + size_t* rotLength) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 3) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, rotLength); + ODK_UnpackPointerToMemory(msg, rot); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_InstallKeyboxOrOEMCert_Response(Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 3) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetProvisioningMethod_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 49) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetProvisioningMethod_Response( + Message* msg, OEMCrypto_ProvisioningMethod* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 49) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCrypto_ProvisioningMethod(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_IsKeyboxOrOEMCertValid_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 5) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_IsKeyboxOrOEMCertValid_Response(Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 5) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetDeviceID_Request(Message* msg, uint8_t** device_id, + size_t** device_id_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 7) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, device_id_length); + *device_id = (uint8_t*)ODK_UnpackAllocBuffer( + msg, LengthFromSizeTDoublePointer(device_id_length), sizeof(uint8_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetDeviceID_Response(Message* msg, OEMCryptoResult* result, + uint8_t** device_id, + size_t** device_id_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 7) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, device_id_length); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + ODK_UnpackPointerToMemory(msg, &p); + if (p && *device_id) { + memcpy(*device_id, p, + LengthAsSizeT(LengthFromSizeTDoublePointer(device_id_length))); + } + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetKeyData_Request(Message* msg, uint8_t** keyData, + size_t** keyDataLength) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 4) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, keyDataLength); + *keyData = (uint8_t*)ODK_UnpackAllocBuffer( + msg, LengthFromSizeTDoublePointer(keyDataLength), sizeof(uint8_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetKeyData_Response(Message* msg, OEMCryptoResult* result, + uint8_t** keyData, size_t** keyDataLength) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 4) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, keyDataLength); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + ODK_UnpackPointerToMemory(msg, &p); + if (p && *keyData) { + memcpy(*keyData, p, + LengthAsSizeT(LengthFromSizeTDoublePointer(keyDataLength))); + } + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_LoadTestKeybox_Request(Message* msg, uint8_t** buffer, + size_t* buffer_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 78) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, buffer_length); + ODK_UnpackPointerToMemory(msg, buffer); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_LoadTestKeybox_Response(Message* msg, OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 78) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetOEMPublicCertificate_Request(Message* msg, + OEMCrypto_SESSION* session, + uint8_t** public_cert, + size_t** public_cert_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 50) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, public_cert_length); + ODK_Unpack_uint32_t(msg, session); + *public_cert = (uint8_t*)ODK_UnpackAllocBuffer( + msg, LengthFromSizeTDoublePointer(public_cert_length), sizeof(uint8_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetOEMPublicCertificate_Response(Message* msg, + OEMCryptoResult* result, + uint8_t** public_cert, + size_t** public_cert_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 50) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, public_cert_length); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + ODK_UnpackPointerToMemory(msg, &p); + if (p && *public_cert) { + memcpy(*public_cert, p, + LengthAsSizeT(LengthFromSizeTDoublePointer(public_cert_length))); + } + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetRandom_Request(Message* msg, uint8_t** random_data, + size_t* random_data_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 6) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, random_data_length); + *random_data = (uint8_t*)ODK_UnpackAllocBuffer( + msg, LengthFromSizeTPointer(random_data_length), sizeof(uint8_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetRandom_Response(Message* msg, OEMCryptoResult* result, + uint8_t** random_data, + size_t* random_data_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 6) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, random_data_length); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + ODK_UnpackPointerToMemory(msg, &p); + if (p && *random_data) { + memcpy(*random_data, p, + LengthAsSizeT(LengthFromSizeTPointer(random_data_length))); + } + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_APIVersion_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 22) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_APIVersion_Response(Message* msg, uint32_t* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 22) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_Security_Patch_Level_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 46) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_Security_Patch_Level_Response(Message* msg, uint8_t* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 46) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint8_t(msg, result); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetHDCPCapability_Request(Message* msg, + OEMCrypto_HDCP_Capability** current, + OEMCrypto_HDCP_Capability** maximum) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 44) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + *current = (uint32_t*)ODK_UnpackAlloc(msg, sizeof(OEMCrypto_HDCP_Capability)); + *maximum = (uint32_t*)ODK_UnpackAlloc(msg, sizeof(OEMCrypto_HDCP_Capability)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetHDCPCapability_Response( + Message* msg, OEMCryptoResult* result, OEMCrypto_HDCP_Capability** current, + OEMCrypto_HDCP_Capability** maximum) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 44) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackNullable_uint32_t(msg, current); + if (*current) { + if (!Is_Valid_OEMCrypto_HDCP_Capability(**current)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + } + ODK_UnpackNullable_uint32_t(msg, maximum); + if (*maximum) { + if (!Is_Valid_OEMCrypto_HDCP_Capability(**maximum)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_SupportsUsageTable_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 29) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_SupportsUsageTable_Response(Message* msg, bool* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 29) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_bool(msg, result); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_IsAntiRollbackHwPresent_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 39) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_IsAntiRollbackHwPresent_Response(Message* msg, bool* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 39) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_bool(msg, result); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetNumberOfOpenSessions_Request(Message* msg, size_t** count) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 38) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + *count = (size_t*)ODK_UnpackAlloc(msg, sizeof(size_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetNumberOfOpenSessions_Response(Message* msg, + OEMCryptoResult* result, + size_t** count) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 38) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackNullable_size_t(msg, count); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetMaxNumberOfSessions_Request(Message* msg, size_t** max) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 37) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + *max = (size_t*)ODK_UnpackAlloc(msg, sizeof(size_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetMaxNumberOfSessions_Response(Message* msg, + OEMCryptoResult* result, + size_t** max) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 37) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackNullable_size_t(msg, max); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_SupportedCertificates_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 52) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_SupportedCertificates_Response(Message* msg, uint32_t* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 52) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_IsSRMUpdateSupported_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 53) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_IsSRMUpdateSupported_Response(Message* msg, bool* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 53) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_bool(msg, result); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetCurrentSRMVersion_Request(Message* msg, uint16_t** version) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 54) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + *version = (uint16_t*)ODK_UnpackAlloc(msg, sizeof(uint16_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetCurrentSRMVersion_Response(Message* msg, + OEMCryptoResult* result, + uint16_t** version) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 54) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackNullable_uint16_t(msg, version); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetAnalogOutputFlags_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 71) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetAnalogOutputFlags_Response(Message* msg, uint32_t* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 71) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_ResourceRatingTier_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 85) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_ResourceRatingTier_Response(Message* msg, uint32_t* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 85) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_RewrapDeviceRSAKey30_Request( + Message* msg, OEMCrypto_SESSION* session, uint32_t** unaligned_nonce, + SharedMemory** encrypted_message_key, size_t* encrypted_message_key_length, + SharedMemory** enc_rsa_key, size_t* enc_rsa_key_length, + uint8_t** enc_rsa_key_iv, uint8_t** wrapped_rsa_key, + size_t** wrapped_rsa_key_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 51) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, encrypted_message_key_length); + ODK_Unpack_size_t(msg, enc_rsa_key_length); + ODK_UnpackNullable_size_t(msg, wrapped_rsa_key_length); + ODK_Unpack_uint32_t(msg, session); + ODK_UnpackNullable_uint32_t(msg, unaligned_nonce); + *encrypted_message_key = ODK_UnpackSharedBuffer( + msg, 0, LengthFromSizeTPointer(encrypted_message_key_length)); + *enc_rsa_key = ODK_UnpackSharedBuffer( + msg, 1, LengthFromSizeTPointer(enc_rsa_key_length)); + ODK_UnpackNullable_uint8_t(msg, enc_rsa_key_iv); + *wrapped_rsa_key = (uint8_t*)ODK_UnpackAllocBuffer( + msg, LengthFromSizeTDoublePointer(wrapped_rsa_key_length), + sizeof(uint8_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_RewrapDeviceRSAKey30_Response(Message* msg, + OEMCryptoResult* result, + uint8_t** wrapped_rsa_key, + size_t** wrapped_rsa_key_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 51) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, wrapped_rsa_key_length); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + ODK_UnpackPointerToMemory(msg, &p); + if (p && *wrapped_rsa_key) { + memcpy( + *wrapped_rsa_key, p, + LengthAsSizeT(LengthFromSizeTDoublePointer(wrapped_rsa_key_length))); + } + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_RewrapDeviceRSAKey_Response(Message* msg, + OEMCryptoResult* result, + uint8_t** wrapped_rsa_key, + size_t** wrapped_rsa_key_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 18) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, wrapped_rsa_key_length); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + ODK_UnpackPointerToMemory(msg, &p); + if (p && *wrapped_rsa_key) { + memcpy( + *wrapped_rsa_key, p, + LengthAsSizeT(LengthFromSizeTDoublePointer(wrapped_rsa_key_length))); + } + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_LoadDeviceRSAKey_Request(Message* msg, + OEMCrypto_SESSION* session, + SharedMemory** wrapped_rsa_key, + size_t* wrapped_rsa_key_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 19) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, wrapped_rsa_key_length); + ODK_Unpack_uint32_t(msg, session); + *wrapped_rsa_key = ODK_UnpackSharedBuffer( + msg, 0, LengthFromSizeTPointer(wrapped_rsa_key_length)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_LoadDeviceRSAKey_Response(Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 19) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_LoadTestRSAKey_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 45) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_LoadTestRSAKey_Response(Message* msg, OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 45) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GenerateRSASignature_Request( + Message* msg, OEMCrypto_SESSION* session, SharedMemory** message, + size_t* message_length, uint8_t** signature, size_t** signature_length, + RSA_Padding_Scheme* padding_scheme) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 36) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, message_length); + ODK_UnpackNullable_size_t(msg, signature_length); + ODK_Unpack_uint32_t(msg, session); + *message = + ODK_UnpackSharedBuffer(msg, 0, LengthFromSizeTPointer(message_length)); + *signature = (uint8_t*)ODK_UnpackAllocBuffer( + msg, LengthFromSizeTDoublePointer(signature_length), sizeof(uint8_t)); + ODK_Unpack_uint8_t(msg, padding_scheme); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GenerateRSASignature_Response(Message* msg, + OEMCryptoResult* result, + uint8_t** signature, + size_t** signature_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 36) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, signature_length); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + ODK_UnpackPointerToMemory(msg, &p); + if (p && *signature) { + memcpy(*signature, p, + LengthAsSizeT(LengthFromSizeTDoublePointer(signature_length))); + } + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_CreateUsageTableHeader_Request(Message* msg, + uint8_t** header_buffer, + size_t** header_buffer_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 61) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, header_buffer_length); + *header_buffer = (uint8_t*)ODK_UnpackAllocBuffer( + msg, LengthFromSizeTDoublePointer(header_buffer_length), sizeof(uint8_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_CreateUsageTableHeader_Response(Message* msg, + OEMCryptoResult* result, + uint8_t** header_buffer, + size_t** header_buffer_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 61) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, header_buffer_length); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + ODK_UnpackPointerToMemory(msg, &p); + if (p && *header_buffer) { + memcpy(*header_buffer, p, + LengthAsSizeT(LengthFromSizeTDoublePointer(header_buffer_length))); + } + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_LoadUsageTableHeader_Request(Message* msg, uint8_t** buffer, + size_t* buffer_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 62) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, buffer_length); + ODK_UnpackPointerToMemory(msg, buffer); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_LoadUsageTableHeader_Response(Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 62) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_CreateNewUsageEntry_Request(Message* msg, + OEMCrypto_SESSION* session, + uint32_t** usage_entry_number) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 63) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, session); + *usage_entry_number = (uint32_t*)ODK_UnpackAlloc(msg, sizeof(uint32_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_CreateNewUsageEntry_Response(Message* msg, + OEMCryptoResult* result, + uint32_t** usage_entry_number) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 63) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackNullable_uint32_t(msg, usage_entry_number); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_LoadUsageEntry_Request(Message* msg, OEMCrypto_SESSION* session, + uint32_t* usage_entry_number, + uint8_t** buffer, + size_t* buffer_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 64) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, buffer_length); + ODK_Unpack_uint32_t(msg, session); + ODK_Unpack_uint32_t(msg, usage_entry_number); + ODK_UnpackPointerToMemory(msg, buffer); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_LoadUsageEntry_Response(Message* msg, OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 64) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_UpdateUsageEntry_Request(Message* msg, + OEMCrypto_SESSION* session, + SharedMemory** header_buffer, + size_t** header_buffer_length, + SharedMemory** entry_buffer, + size_t** entry_buffer_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 65) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, header_buffer_length); + ODK_UnpackNullable_size_t(msg, entry_buffer_length); + ODK_Unpack_uint32_t(msg, session); + *header_buffer = ODK_UnpackSharedBuffer( + msg, 0, LengthFromSizeTDoublePointer(header_buffer_length)); + *entry_buffer = ODK_UnpackSharedBuffer( + msg, 1, LengthFromSizeTDoublePointer(entry_buffer_length)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_UpdateUsageEntry_Response(Message* msg, OEMCryptoResult* result, + SharedMemory** header_buffer, + size_t** header_buffer_length, + SharedMemory** entry_buffer, + size_t** entry_buffer_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 65) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, header_buffer_length); + ODK_UnpackNullable_size_t(msg, entry_buffer_length); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + ODK_UnpackSharedOutputBuffer( + msg, 0, header_buffer, + LengthFromSizeTDoublePointer(header_buffer_length)); + } + if (SuccessResult(*result)) { + ODK_UnpackSharedOutputBuffer( + msg, 1, entry_buffer, + LengthFromSizeTDoublePointer(entry_buffer_length)); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_DeactivateUsageEntry_Request(Message* msg, + OEMCrypto_SESSION* session, + uint8_t** pst, + size_t* pst_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 66) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, pst_length); + ODK_Unpack_uint32_t(msg, session); + ODK_UnpackPointerToMemory(msg, pst); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_DeactivateUsageEntry_Response(Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 66) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_ReportUsage_Request(Message* msg, OEMCrypto_SESSION* session, + uint8_t** pst, size_t* pst_length, + uint8_t** buffer, size_t** buffer_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 32) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, pst_length); + ODK_UnpackNullable_size_t(msg, buffer_length); + ODK_Unpack_uint32_t(msg, session); + ODK_UnpackPointerToMemory(msg, pst); + *buffer = (uint8_t*)ODK_UnpackAllocBuffer( + msg, LengthFromSizeTDoublePointer(buffer_length), sizeof(uint8_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_ReportUsage_Response(Message* msg, OEMCryptoResult* result, + uint8_t** buffer, size_t** buffer_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 32) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, buffer_length); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + ODK_UnpackPointerToMemory(msg, &p); + if (p && *buffer) { + memcpy(*buffer, p, + LengthAsSizeT(LengthFromSizeTDoublePointer(buffer_length))); + } + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_DeleteUsageEntry_Request( + Message* msg, OEMCrypto_SESSION* session, uint8_t** pst, size_t* pst_length, + uint8_t** message, size_t* message_length, uint8_t** signature, + size_t* signature_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 33) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, pst_length); + ODK_Unpack_size_t(msg, message_length); + ODK_Unpack_size_t(msg, signature_length); + ODK_Unpack_uint32_t(msg, session); + ODK_UnpackPointerToMemory(msg, pst); + ODK_UnpackPointerToMemory(msg, message); + ODK_UnpackPointerToMemory(msg, signature); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_DeleteUsageEntry_Response(Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 33) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_ForceDeleteUsageEntry_Request(Message* msg, uint8_t** pst, + size_t* pst_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 43) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, pst_length); + ODK_UnpackPointerToMemory(msg, pst); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_ForceDeleteUsageEntry_Response(Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 43) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_MoveEntry_Request(Message* msg, OEMCrypto_SESSION* session, + uint32_t* new_index) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 68) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, session); + ODK_Unpack_uint32_t(msg, new_index); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_MoveEntry_Response(Message* msg, OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 68) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_ShrinkUsageTableHeader_Request(Message* msg, + uint32_t* new_entry_count, + uint8_t** header_buffer, + size_t** header_buffer_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 67) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, header_buffer_length); + ODK_Unpack_uint32_t(msg, new_entry_count); + *header_buffer = (uint8_t*)ODK_UnpackAllocBuffer( + msg, LengthFromSizeTDoublePointer(header_buffer_length), sizeof(uint8_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_ShrinkUsageTableHeader_Response(Message* msg, + OEMCryptoResult* result, + uint8_t** header_buffer, + size_t** header_buffer_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 67) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackNullable_size_t(msg, header_buffer_length); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + ODK_UnpackPointerToMemory(msg, &p); + if (p && *header_buffer) { + memcpy(*header_buffer, p, + LengthAsSizeT(LengthFromSizeTDoublePointer(header_buffer_length))); + } + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_CopyOldUsageEntry_Request(Message* msg, + OEMCrypto_SESSION* session, + uint8_t** pst, size_t* pst_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 69) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, pst_length); + ODK_Unpack_uint32_t(msg, session); + ODK_UnpackPointerToMemory(msg, pst); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_CopyOldUsageEntry_Response(Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 69) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_DeleteOldUsageTable_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 34) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_DeleteOldUsageTable_Response(Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 34) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_RemoveSRM_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 57) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_RemoveSRM_Response(Message* msg, OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 57) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_CreateOldUsageEntry_Request( + Message* msg, uint64_t* time_since_license_received, + uint64_t* time_since_first_decrypt, uint64_t* time_since_last_decrypt, + OEMCrypto_Usage_Entry_Status* status, uint8_t* server_mac_key, + uint8_t* client_mac_key, uint8_t** pst, size_t* pst_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 70) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, pst_length); + ODK_Unpack_uint64_t(msg, time_since_license_received); + ODK_Unpack_uint64_t(msg, time_since_first_decrypt); + ODK_Unpack_uint64_t(msg, time_since_last_decrypt); + ODK_Unpack_uint32_t(msg, status); + if (!Is_Valid_OEMCrypto_Usage_Entry_Status(*status)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackArray(msg, &server_mac_key[0], 32); + ODK_UnpackArray(msg, &client_mac_key[0], 32); + ODK_UnpackPointerToMemory(msg, pst); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_CreateOldUsageEntry_Response(Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 70) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_SupportsDecryptHash_Request(Message* msg) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 86) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_SupportsDecryptHash_Response(Message* msg, uint32_t* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 86) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_SetDecryptHash_Request(Message* msg, OEMCrypto_SESSION* session, + uint32_t* frame_number, uint8_t** hash, + size_t* hash_length) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 88) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, hash_length); + ODK_Unpack_uint32_t(msg, session); + ODK_Unpack_uint32_t(msg, frame_number); + ODK_UnpackPointerToMemory(msg, hash); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_SetDecryptHash_Response(Message* msg, OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 88) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetHashErrorCode_Request(Message* msg, + OEMCrypto_SESSION* session, + uint32_t** failed_frame_number) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 89) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, session); + *failed_frame_number = (uint32_t*)ODK_UnpackAlloc(msg, sizeof(uint32_t)); + ODK_UnpackEOM(msg); +} + +void ODK_Unpack_GetHashErrorCode_Response(Message* msg, OEMCryptoResult* result, + uint32_t** failed_frame_number) { + uint32_t api_value = UINT32_MAX; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 89) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + SetStatus(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + ODK_UnpackNullable_uint32_t(msg, failed_frame_number); + ODK_UnpackEOM(msg); +} + +void ODK_UnpackNullable_c_str(Message* msg, char** value) { + if (ODK_UnpackIsNull(msg)) { + *value = NULL; + } else { + ODK_Unpack_c_str(msg, value); + } +} +void ODK_UnpackAlloc_c_str(Message* msg, char** value) { + *value = (char*)ODK_UnpackAlloc(msg, sizeof(char)); + if (*value) { + ODK_Unpack_c_str(msg, value); + } +} +void ODK_UnpackNullable_uint32_t(Message* msg, OEMCrypto_SESSION** value) { + if (ODK_UnpackIsNull(msg)) { + *value = NULL; + } else { + ODK_Unpack_uint32_t(msg, *value); + } +} +void ODK_UnpackAlloc_uint32_t(Message* msg, OEMCrypto_SESSION** value) { + *value = (OEMCrypto_SESSION*)ODK_UnpackAlloc(msg, sizeof(OEMCrypto_SESSION)); + if (*value) { + ODK_Unpack_uint32_t(msg, *value); + } +} +void ODK_UnpackNullable_size_t(Message* msg, size_t** value) { + if (ODK_UnpackIsNull(msg)) { + *value = NULL; + } else { + ODK_Unpack_size_t(msg, *value); + } +} +void ODK_UnpackNullable_OEMCrypto_DestBufferDesc( + Message* msg, OEMCrypto_DestBufferDesc** value) { + if (ODK_UnpackIsNull(msg)) { + *value = NULL; + } else { + ODK_Unpack_OEMCrypto_DestBufferDesc(msg, *value); + } +} +void ODK_UnpackNullable_OEMCrypto_CENCEncryptPatternDesc( + Message* msg, OEMCrypto_CENCEncryptPatternDesc** value) { + if (ODK_UnpackIsNull(msg)) { + *value = NULL; + } else { + ODK_Unpack_OEMCrypto_CENCEncryptPatternDesc(msg, *value); + } +} +void ODK_UnpackAlloc_size_t(Message* msg, size_t** value) { + *value = (size_t*)ODK_UnpackAlloc(msg, sizeof(size_t)); + if (*value) { + ODK_Unpack_size_t(msg, *value); + } +} +void ODK_UnpackNullable_uint16_t(Message* msg, uint16_t** value) { + if (ODK_UnpackIsNull(msg)) { + *value = NULL; + } else { + ODK_Unpack_uint16_t(msg, *value); + } +} +void ODK_UnpackAlloc_uint16_t(Message* msg, uint16_t** value) { + *value = (uint16_t*)ODK_UnpackAlloc(msg, sizeof(uint16_t)); + if (*value) { + ODK_Unpack_uint16_t(msg, *value); + } +} +void ODK_UnpackNullable_uint8_t(Message* msg, uint8_t** value) { + if (ODK_UnpackIsNull(msg)) { + *value = NULL; + } else { + ODK_Unpack_uint8_t(msg, *value); + } +} diff --git a/serialization/generated_src/deserializer.h b/serialization/generated_src/deserializer.h new file mode 100644 index 0000000..3caf94d --- /dev/null +++ b/serialization/generated_src/deserializer.h @@ -0,0 +1,383 @@ +/* + * 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. + */ + +/* + * This code is auto-generated, do not edit + */ +#ifndef ODKITEE_DESERIALIZER_H_ +#define ODKITEE_DESERIALIZER_H_ + +#include "deserializer.h" +#include "serialization_base.h" +#include "serializer.h" +#ifdef __cplusplus +extern "C" { +#endif + +bool Is_Valid_OEMCryptoResult(uint32_t value); +bool Is_Valid_OEMCryptoBufferType(uint32_t value); +bool Is_Valid_OEMCryptoCipherMode(uint32_t value); +bool Is_Valid_OEMCrypto_LicenseType(uint32_t value); +bool Is_Valid_OEMCrypto_Algorithm(uint32_t value); +bool Is_Valid_OEMCrypto_Usage_Entry_Status(uint32_t value); +bool Is_Valid_OEMCrypto_Clock_Security_Level(uint32_t value); +bool Is_Valid_OEMCrypto_HDCP_Capability(uint32_t value); +bool Is_Valid_OEMCrypto_ProvisioningMethod(uint32_t value); +void ODK_Unpack_OEMCrypto_Substring(Message* msg, OEMCrypto_Substring* obj); +void ODK_Unpack_OEMCrypto_KeyObject(Message* msg, OEMCrypto_KeyObject* obj); +void ODK_Unpack_OEMCrypto_EntitledContentKeyObject( + Message* msg, OEMCrypto_EntitledContentKeyObject* obj); +void ODK_Unpack_OEMCrypto_KeyRefreshObject(Message* msg, + OEMCrypto_KeyRefreshObject* obj); +void ODK_Unpack_OEMCrypto_CENCEncryptPatternDesc( + Message* msg, OEMCrypto_CENCEncryptPatternDesc* obj); +void ODK_Unpack_SecurityLevel_Request(Message* msg); +void ODK_Unpack_SecurityLevel_Response(Message* msg, char** result); +void ODK_Unpack_BuildInformation_Request(Message* msg); +void ODK_Unpack_BuildInformation_Response(Message* msg, char** result); +void ODK_Unpack_SetSandbox_Request(Message* msg, uint8_t** sandbox_id, + size_t* sandbox_id_length); +void ODK_Unpack_SetSandbox_Response(Message* msg, OEMCryptoResult* result); +void ODK_Unpack_Initialize_Request(Message* msg); +void ODK_Unpack_Initialize_Response(Message* msg, OEMCryptoResult* result); +void ODK_Unpack_Terminate_Request(Message* msg); +void ODK_Unpack_Terminate_Response(Message* msg, OEMCryptoResult* result); +void ODK_Unpack_OpenSession_Request(Message* msg, OEMCrypto_SESSION** session); +void ODK_Unpack_OpenSession_Response(Message* msg, OEMCryptoResult* result, + OEMCrypto_SESSION** session); +void ODK_Unpack_CloseSession_Request(Message* msg, OEMCrypto_SESSION* session); +void ODK_Unpack_CloseSession_Response(Message* msg, OEMCryptoResult* result); +void ODK_Unpack_GenerateDerivedKeys_Request(Message* msg, + OEMCrypto_SESSION* session, + SharedMemory** mac_key_context, + uint32_t* mac_key_context_length, + SharedMemory** enc_key_context, + uint32_t* enc_key_context_length); +void ODK_Unpack_GenerateDerivedKeys_Response(Message* msg, + OEMCryptoResult* result); +void ODK_Unpack_DeriveKeysFromSessionKey_Request( + Message* msg, OEMCrypto_SESSION* session, uint8_t** enc_session_key, + size_t* enc_session_key_length, SharedMemory** mac_key_context, + size_t* mac_key_context_length, SharedMemory** enc_key_context, + size_t* enc_key_context_length); +void ODK_Unpack_DeriveKeysFromSessionKey_Response(Message* msg, + OEMCryptoResult* result); +void ODK_Unpack_GenerateNonce_Request(Message* msg, OEMCrypto_SESSION* session, + uint32_t** nonce); +void ODK_Unpack_GenerateNonce_Response(Message* msg, OEMCryptoResult* result, + uint32_t** nonce); +void ODK_Unpack_GenerateSignature_Request( + Message* msg, OEMCrypto_SESSION* session, SharedMemory** message, + size_t* message_length, uint8_t** signature, size_t** signature_length); +void ODK_Unpack_GenerateSignature_Response(Message* msg, + OEMCryptoResult* result, + uint8_t** signature, + size_t** signature_length); +void ODK_Unpack_LoadSRM_Request(Message* msg, uint8_t** buffer, + size_t* buffer_length); +void ODK_Unpack_LoadSRM_Response(Message* msg, OEMCryptoResult* result); +void ODK_Unpack_LoadKeys_Request( + Message* msg, OEMCrypto_SESSION* session, SharedMemory** message, + size_t* message_length, SharedMemory** signature, size_t* signature_length, + OEMCrypto_Substring* enc_mac_keys_iv, OEMCrypto_Substring* enc_mac_keys, + size_t* key_array_length, OEMCrypto_KeyObject** key_array, + OEMCrypto_Substring* pst, OEMCrypto_Substring* srm_restriction_data, + OEMCrypto_LicenseType* license_type); +void ODK_Unpack_LoadKeys_Response(Message* msg, OEMCryptoResult* result); +void ODK_Unpack_LoadEntitledContentKeys_Request( + Message* msg, OEMCrypto_SESSION* session, SharedMemory** message, + size_t* message_length, size_t* key_array_length, + OEMCrypto_EntitledContentKeyObject** key_array); +void ODK_Unpack_LoadEntitledContentKeys_Response(Message* msg, + OEMCryptoResult* result); +void ODK_Unpack_RefreshKeys_Request( + Message* msg, OEMCrypto_SESSION* session, SharedMemory** message, + size_t* message_length, SharedMemory** signature, size_t* signature_length, + size_t* key_array_length, OEMCrypto_KeyRefreshObject** key_array); +void ODK_Unpack_RefreshKeys_Response(Message* msg, OEMCryptoResult* result); +void ODK_Unpack_QueryKeyControl_Request(Message* msg, + OEMCrypto_SESSION* session, + uint8_t** content_key_id, + size_t* content_key_id_length, + uint8_t** key_control_block, + size_t** key_control_block_length); +void ODK_Unpack_QueryKeyControl_Response(Message* msg, OEMCryptoResult* result, + uint8_t** key_control_block, + size_t** key_control_block_length); +void ODK_Unpack_SelectKey_Request(Message* msg, OEMCrypto_SESSION* session, + uint8_t** content_key_id, + size_t* content_key_id_length, + OEMCryptoCipherMode* cipher_mode); +void ODK_Unpack_SelectKey_Response(Message* msg, OEMCryptoResult* result); +void ODK_Unpack_DecryptCENC_Request( + Message* msg, OEMCrypto_SESSION* session, SharedMemory** data_addr, + size_t* data_addr_length, bool* is_encrypted, uint8_t* iv, + size_t* block_offset, OEMCrypto_DestBufferDesc** out_buffer, + OEMCrypto_CENCEncryptPatternDesc** pattern, uint8_t* subsample_flags); +void ODK_Unpack_DecryptCENC_Response(Message* msg, OEMCryptoResult* result, + OEMCrypto_DestBufferDesc** out_buffer); +void ODK_Unpack_CopyBuffer_Request(Message* msg, OEMCrypto_SESSION* session, + SharedMemory** data_addr, + size_t* data_addr_length, + OEMCrypto_DestBufferDesc** out_buffer, + uint8_t* subsample_flags); +void ODK_Unpack_CopyBuffer_Response(Message* msg, OEMCryptoResult* result, + OEMCrypto_DestBufferDesc** out_buffer); +void ODK_Unpack_Generic_Encrypt_Request(Message* msg, + OEMCrypto_SESSION* session, + SharedMemory** in_buffer, + size_t* in_buffer_length, uint8_t* iv, + OEMCrypto_Algorithm* algorithm, + uint8_t** out_buffer); +void ODK_Unpack_Generic_Encrypt_Response(Message* msg, OEMCryptoResult* result, + size_t* in_buffer_length, + uint8_t** out_buffer); +void ODK_Unpack_Generic_Decrypt_Request(Message* msg, + OEMCrypto_SESSION* session, + SharedMemory** in_buffer, + size_t* in_buffer_length, uint8_t* iv, + OEMCrypto_Algorithm* algorithm, + uint8_t** out_buffer); +void ODK_Unpack_Generic_Decrypt_Response(Message* msg, OEMCryptoResult* result, + size_t* in_buffer_length, + uint8_t** out_buffer); +void ODK_Unpack_Generic_Sign_Request(Message* msg, OEMCrypto_SESSION* session, + SharedMemory** buffer, + size_t* buffer_length, + OEMCrypto_Algorithm* algorithm, + uint8_t** signature, + size_t** signature_length); +void ODK_Unpack_Generic_Sign_Response(Message* msg, OEMCryptoResult* result, + uint8_t** signature, + size_t** signature_length); +void ODK_Unpack_Generic_Verify_Request(Message* msg, OEMCrypto_SESSION* session, + SharedMemory** buffer, + size_t* buffer_length, + OEMCrypto_Algorithm* algorithm, + SharedMemory** signature, + size_t* signature_length); +void ODK_Unpack_Generic_Verify_Response(Message* msg, OEMCryptoResult* result); +void ODK_Unpack_UpdateUsageTable_Request(Message* msg); +void ODK_Unpack_UpdateUsageTable_Response(Message* msg, + OEMCryptoResult* result); +void ODK_Unpack_WrapKeyboxOrOEMCert_Request(Message* msg, uint8_t** rot, + size_t* rotLength, + uint8_t** wrappedRot, + size_t** wrappedRotLength, + uint8_t** transportKey, + size_t* transportKeyLength); +void ODK_Unpack_WrapKeyboxOrOEMCert_Response(Message* msg, + OEMCryptoResult* result, + uint8_t** wrappedRot, + size_t** wrappedRotLength); +void ODK_Unpack_InstallKeyboxOrOEMCert_Request(Message* msg, uint8_t** rot, + size_t* rotLength); +void ODK_Unpack_InstallKeyboxOrOEMCert_Response(Message* msg, + OEMCryptoResult* result); +void ODK_Unpack_GetProvisioningMethod_Request(Message* msg); +void ODK_Unpack_GetProvisioningMethod_Response( + Message* msg, OEMCrypto_ProvisioningMethod* result); +void ODK_Unpack_IsKeyboxOrOEMCertValid_Request(Message* msg); +void ODK_Unpack_IsKeyboxOrOEMCertValid_Response(Message* msg, + OEMCryptoResult* result); +void ODK_Unpack_GetDeviceID_Request(Message* msg, uint8_t** device_id, + size_t** device_id_length); +void ODK_Unpack_GetDeviceID_Response(Message* msg, OEMCryptoResult* result, + uint8_t** device_id, + size_t** device_id_length); +void ODK_Unpack_GetKeyData_Request(Message* msg, uint8_t** keyData, + size_t** keyDataLength); +void ODK_Unpack_GetKeyData_Response(Message* msg, OEMCryptoResult* result, + uint8_t** keyData, size_t** keyDataLength); +void ODK_Unpack_LoadTestKeybox_Request(Message* msg, uint8_t** buffer, + size_t* buffer_length); +void ODK_Unpack_LoadTestKeybox_Response(Message* msg, OEMCryptoResult* result); +void ODK_Unpack_GetOEMPublicCertificate_Request(Message* msg, + OEMCrypto_SESSION* session, + uint8_t** public_cert, + size_t** public_cert_length); +void ODK_Unpack_GetOEMPublicCertificate_Response(Message* msg, + OEMCryptoResult* result, + uint8_t** public_cert, + size_t** public_cert_length); +void ODK_Unpack_GetRandom_Request(Message* msg, uint8_t** random_data, + size_t* random_data_length); +void ODK_Unpack_GetRandom_Response(Message* msg, OEMCryptoResult* result, + uint8_t** random_data, + size_t* random_data_length); +void ODK_Unpack_APIVersion_Request(Message* msg); +void ODK_Unpack_APIVersion_Response(Message* msg, uint32_t* result); +void ODK_Unpack_Security_Patch_Level_Request(Message* msg); +void ODK_Unpack_Security_Patch_Level_Response(Message* msg, uint8_t* result); +void ODK_Unpack_GetHDCPCapability_Request(Message* msg, + OEMCrypto_HDCP_Capability** current, + OEMCrypto_HDCP_Capability** maximum); +void ODK_Unpack_GetHDCPCapability_Response(Message* msg, + OEMCryptoResult* result, + OEMCrypto_HDCP_Capability** current, + OEMCrypto_HDCP_Capability** maximum); +void ODK_Unpack_SupportsUsageTable_Request(Message* msg); +void ODK_Unpack_SupportsUsageTable_Response(Message* msg, bool* result); +void ODK_Unpack_IsAntiRollbackHwPresent_Request(Message* msg); +void ODK_Unpack_IsAntiRollbackHwPresent_Response(Message* msg, bool* result); +void ODK_Unpack_GetNumberOfOpenSessions_Request(Message* msg, size_t** count); +void ODK_Unpack_GetNumberOfOpenSessions_Response(Message* msg, + OEMCryptoResult* result, + size_t** count); +void ODK_Unpack_GetMaxNumberOfSessions_Request(Message* msg, size_t** max); +void ODK_Unpack_GetMaxNumberOfSessions_Response(Message* msg, + OEMCryptoResult* result, + size_t** max); +void ODK_Unpack_SupportedCertificates_Request(Message* msg); +void ODK_Unpack_SupportedCertificates_Response(Message* msg, uint32_t* result); +void ODK_Unpack_IsSRMUpdateSupported_Request(Message* msg); +void ODK_Unpack_IsSRMUpdateSupported_Response(Message* msg, bool* result); +void ODK_Unpack_GetCurrentSRMVersion_Request(Message* msg, uint16_t** version); +void ODK_Unpack_GetCurrentSRMVersion_Response(Message* msg, + OEMCryptoResult* result, + uint16_t** version); +void ODK_Unpack_GetAnalogOutputFlags_Request(Message* msg); +void ODK_Unpack_GetAnalogOutputFlags_Response(Message* msg, uint32_t* result); +void ODK_Unpack_ResourceRatingTier_Request(Message* msg); +void ODK_Unpack_ResourceRatingTier_Response(Message* msg, uint32_t* result); +void ODK_Unpack_RewrapDeviceRSAKey30_Request( + Message* msg, OEMCrypto_SESSION* session, uint32_t** unaligned_nonce, + SharedMemory** encrypted_message_key, size_t* encrypted_message_key_length, + SharedMemory** enc_rsa_key, size_t* enc_rsa_key_length, + uint8_t** enc_rsa_key_iv, uint8_t** wrapped_rsa_key, + size_t** wrapped_rsa_key_length); +void ODK_Unpack_RewrapDeviceRSAKey30_Response(Message* msg, + OEMCryptoResult* result, + uint8_t** wrapped_rsa_key, + size_t** wrapped_rsa_key_length); +void ODK_Unpack_RewrapDeviceRSAKey_Response(Message* msg, + OEMCryptoResult* result, + uint8_t** wrapped_rsa_key, + size_t** wrapped_rsa_key_length); +void ODK_Unpack_LoadDeviceRSAKey_Request(Message* msg, + OEMCrypto_SESSION* session, + SharedMemory** wrapped_rsa_key, + size_t* wrapped_rsa_key_length); +void ODK_Unpack_LoadDeviceRSAKey_Response(Message* msg, + OEMCryptoResult* result); +void ODK_Unpack_LoadTestRSAKey_Request(Message* msg); +void ODK_Unpack_LoadTestRSAKey_Response(Message* msg, OEMCryptoResult* result); +void ODK_Unpack_GenerateRSASignature_Request( + Message* msg, OEMCrypto_SESSION* session, SharedMemory** message, + size_t* message_length, uint8_t** signature, size_t** signature_length, + RSA_Padding_Scheme* padding_scheme); +void ODK_Unpack_GenerateRSASignature_Response(Message* msg, + OEMCryptoResult* result, + uint8_t** signature, + size_t** signature_length); +void ODK_Unpack_CreateUsageTableHeader_Request(Message* msg, + uint8_t** header_buffer, + size_t** header_buffer_length); +void ODK_Unpack_CreateUsageTableHeader_Response(Message* msg, + OEMCryptoResult* result, + uint8_t** header_buffer, + size_t** header_buffer_length); +void ODK_Unpack_LoadUsageTableHeader_Request(Message* msg, uint8_t** buffer, + size_t* buffer_length); +void ODK_Unpack_LoadUsageTableHeader_Response(Message* msg, + OEMCryptoResult* result); +void ODK_Unpack_CreateNewUsageEntry_Request(Message* msg, + OEMCrypto_SESSION* session, + uint32_t** usage_entry_number); +void ODK_Unpack_CreateNewUsageEntry_Response(Message* msg, + OEMCryptoResult* result, + uint32_t** usage_entry_number); +void ODK_Unpack_LoadUsageEntry_Request(Message* msg, OEMCrypto_SESSION* session, + uint32_t* usage_entry_number, + uint8_t** buffer, size_t* buffer_length); +void ODK_Unpack_LoadUsageEntry_Response(Message* msg, OEMCryptoResult* result); +void ODK_Unpack_UpdateUsageEntry_Request(Message* msg, + OEMCrypto_SESSION* session, + SharedMemory** header_buffer, + size_t** header_buffer_length, + SharedMemory** entry_buffer, + size_t** entry_buffer_length); +void ODK_Unpack_UpdateUsageEntry_Response(Message* msg, OEMCryptoResult* result, + SharedMemory** header_buffer, + size_t** header_buffer_length, + SharedMemory** entry_buffer, + size_t** entry_buffer_length); +void ODK_Unpack_DeactivateUsageEntry_Request(Message* msg, + OEMCrypto_SESSION* session, + uint8_t** pst, size_t* pst_length); +void ODK_Unpack_DeactivateUsageEntry_Response(Message* msg, + OEMCryptoResult* result); +void ODK_Unpack_ReportUsage_Request(Message* msg, OEMCrypto_SESSION* session, + uint8_t** pst, size_t* pst_length, + uint8_t** buffer, size_t** buffer_length); +void ODK_Unpack_ReportUsage_Response(Message* msg, OEMCryptoResult* result, + uint8_t** buffer, size_t** buffer_length); +void ODK_Unpack_DeleteUsageEntry_Request( + Message* msg, OEMCrypto_SESSION* session, uint8_t** pst, size_t* pst_length, + uint8_t** message, size_t* message_length, uint8_t** signature, + size_t* signature_length); +void ODK_Unpack_DeleteUsageEntry_Response(Message* msg, + OEMCryptoResult* result); +void ODK_Unpack_ForceDeleteUsageEntry_Request(Message* msg, uint8_t** pst, + size_t* pst_length); +void ODK_Unpack_ForceDeleteUsageEntry_Response(Message* msg, + OEMCryptoResult* result); +void ODK_Unpack_MoveEntry_Request(Message* msg, OEMCrypto_SESSION* session, + uint32_t* new_index); +void ODK_Unpack_MoveEntry_Response(Message* msg, OEMCryptoResult* result); +void ODK_Unpack_ShrinkUsageTableHeader_Request(Message* msg, + uint32_t* new_entry_count, + uint8_t** header_buffer, + size_t** header_buffer_length); +void ODK_Unpack_ShrinkUsageTableHeader_Response(Message* msg, + OEMCryptoResult* result, + uint8_t** header_buffer, + size_t** header_buffer_length); +void ODK_Unpack_CopyOldUsageEntry_Request(Message* msg, + OEMCrypto_SESSION* session, + uint8_t** pst, size_t* pst_length); +void ODK_Unpack_CopyOldUsageEntry_Response(Message* msg, + OEMCryptoResult* result); +void ODK_Unpack_DeleteOldUsageTable_Request(Message* msg); +void ODK_Unpack_DeleteOldUsageTable_Response(Message* msg, + OEMCryptoResult* result); +void ODK_Unpack_RemoveSRM_Request(Message* msg); +void ODK_Unpack_RemoveSRM_Response(Message* msg, OEMCryptoResult* result); +void ODK_Unpack_CreateOldUsageEntry_Request( + Message* msg, uint64_t* time_since_license_received, + uint64_t* time_since_first_decrypt, uint64_t* time_since_last_decrypt, + OEMCrypto_Usage_Entry_Status* status, uint8_t* server_mac_key, + uint8_t* client_mac_key, uint8_t** pst, size_t* pst_length); +void ODK_Unpack_CreateOldUsageEntry_Response(Message* msg, + OEMCryptoResult* result); +void ODK_Unpack_SupportsDecryptHash_Request(Message* msg); +void ODK_Unpack_SupportsDecryptHash_Response(Message* msg, uint32_t* result); +void ODK_Unpack_SetDecryptHash_Request(Message* msg, OEMCrypto_SESSION* session, + uint32_t* frame_number, uint8_t** hash, + size_t* hash_length); +void ODK_Unpack_SetDecryptHash_Response(Message* msg, OEMCryptoResult* result); +void ODK_Unpack_GetHashErrorCode_Request(Message* msg, + OEMCrypto_SESSION* session, + uint32_t** failed_frame_number); +void ODK_Unpack_GetHashErrorCode_Response(Message* msg, OEMCryptoResult* result, + uint32_t** failed_frame_number); +void ODK_UnpackNullable_c_str(Message* msg, char** value); +void ODK_UnpackAlloc_c_str(Message* msg, char** value); +void ODK_UnpackNullable_uint32_t(Message* msg, OEMCrypto_SESSION** value); +void ODK_UnpackAlloc_uint32_t(Message* msg, OEMCrypto_SESSION** value); +void ODK_UnpackNullable_size_t(Message* msg, size_t** value); +void ODK_UnpackNullable_OEMCrypto_DestBufferDesc( + Message* msg, OEMCrypto_DestBufferDesc** value); +void ODK_UnpackNullable_OEMCrypto_CENCEncryptPatternDesc( + Message* msg, OEMCrypto_CENCEncryptPatternDesc** value); +void ODK_UnpackAlloc_size_t(Message* msg, size_t** value); +void ODK_UnpackNullable_uint16_t(Message* msg, uint16_t** value); +void ODK_UnpackAlloc_uint16_t(Message* msg, uint16_t** value); +void ODK_UnpackNullable_uint8_t(Message* msg, uint8_t** value); +#ifdef __cplusplus +} // extern "C" +#endif +#endif /* ODKITEE_DESERIALIZER_H_ */ diff --git a/serialization/generated_src/dispatcher.c b/serialization/generated_src/dispatcher.c new file mode 100644 index 0000000..c48d361 --- /dev/null +++ b/serialization/generated_src/dispatcher.c @@ -0,0 +1,1499 @@ +/* + * 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. + */ + +/* + * This code is auto-generated, do not edit + */ +#include "dispatcher.h" + +#include + +#include "OEMCryptoCENC.h" +#include "bump_allocator.h" +#include "deserializer.h" +#include "marshaller_base.h" +#include "serializer.h" +#include "shared_memory_allocator.h" +#include "shared_memory_interface.h" +#include "special_cases.h" + +void ODK_InitializeDispatcher() { + SharedMemory_Initialize(1024 * 1024 /* 1MB */); +} + +void Init_OEMCrypto_Substring(OEMCrypto_Substring* obj) { + Init_size_t((size_t*)&obj->offset); + Init_size_t((size_t*)&obj->length); +} + +void Init_OEMCrypto_KeyObject(OEMCrypto_KeyObject* obj) { + Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_id); + Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_data_iv); + Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_data); + Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_control_iv); + Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_control); +} + +void Init_OEMCrypto_EntitledContentKeyObject( + OEMCrypto_EntitledContentKeyObject* obj) { + Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->entitlement_key_id); + Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->content_key_id); + Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->content_key_data_iv); + Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->content_key_data); +} + +void Init_OEMCrypto_KeyRefreshObject(OEMCrypto_KeyRefreshObject* obj) { + Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_id); + Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_control_iv); + Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_control); +} + +void Init_OEMCrypto_CENCEncryptPatternDesc( + OEMCrypto_CENCEncryptPatternDesc* obj) { + Init_size_t((size_t*)&obj->encrypt); + Init_size_t((size_t*)&obj->skip); + Init_size_t((size_t*)&obj->offset); +} + +MessageStatus ODK_DispatchMessage(Message* request, Message* response) { + if (request == NULL || response == NULL) { + return MESSAGE_STATUS_NULL_POINTER_ERROR; + } + MessageStatus message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + message_status = GetStatus(response); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + ClearMessage(response); + uint32_t api_value; + ODK_Unpack_uint32_t(request, &api_value); + BumpAllocator_Reset(); + SharedMemory_Reset(); + ResetMessage(request); + switch (api_value) { + case 23: /* OEMCrypto_SecurityLevel */ + { + ODK_Unpack_SecurityLevel_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + const char* result; + Init_c_str((char**)&result); + result = OEMCrypto_SecurityLevel(); + ODK_Pack_SecurityLevel_Response(response, result); + break; + } + case 90: /* OEMCrypto_BuildInformation */ + { + ODK_Unpack_BuildInformation_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + const char* result; + Init_c_str((char**)&result); + result = OEMCrypto_BuildInformation(); + ODK_Pack_BuildInformation_Response(response, result); + break; + } + case 84: /* OEMCrypto_SetSandbox */ + { + size_t sandbox_id_length; + Init_size_t((size_t*)&sandbox_id_length); + uint8_t* sandbox_id; + InitPointer((uint8_t**)&sandbox_id); + ODK_Unpack_SetSandbox_Request(request, &sandbox_id, &sandbox_id_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_SetSandbox(sandbox_id, sandbox_id_length); + ODK_Pack_SetSandbox_Response(response, result); + break; + } + case 1: /* OEMCrypto_Initialize */ + { + ODK_Unpack_Initialize_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_Initialize(); + ODK_Pack_Initialize_Response(response, result); + break; + } + case 2: /* OEMCrypto_Terminate */ + { + ODK_Unpack_Terminate_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_Terminate(); + ODK_Pack_Terminate_Response(response, result); + break; + } + case 9: /* OEMCrypto_OpenSession */ + { + OEMCrypto_SESSION* session; + InitPointer((uint8_t**)&session); + ODK_Unpack_OpenSession_Request(request, &session); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_OpenSession(session); + ODK_Pack_OpenSession_Response(response, result, session); + break; + } + case 10: /* OEMCrypto_CloseSession */ + { + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + ODK_Unpack_CloseSession_Request(request, &session); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_CloseSession(session); + ODK_Pack_CloseSession_Response(response, result); + break; + } + case 12: /* OEMCrypto_GenerateDerivedKeys */ + { + uint32_t mac_key_context_length; + Init_uint32_t((uint32_t*)&mac_key_context_length); + uint32_t enc_key_context_length; + Init_uint32_t((uint32_t*)&enc_key_context_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + SharedMemory* mac_key_context; + InitPointer((uint8_t**)&mac_key_context); + SharedMemory* enc_key_context; + InitPointer((uint8_t**)&enc_key_context); + ODK_Unpack_GenerateDerivedKeys_Request( + request, &session, &mac_key_context, &mac_key_context_length, + &enc_key_context, &enc_key_context_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_GenerateDerivedKeys( + session, mac_key_context, mac_key_context_length, enc_key_context, + enc_key_context_length); + ODK_Pack_GenerateDerivedKeys_Response(response, result); + break; + } + case 21: /* OEMCrypto_DeriveKeysFromSessionKey */ + { + size_t enc_session_key_length; + Init_size_t((size_t*)&enc_session_key_length); + size_t mac_key_context_length; + Init_size_t((size_t*)&mac_key_context_length); + size_t enc_key_context_length; + Init_size_t((size_t*)&enc_key_context_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + uint8_t* enc_session_key; + InitPointer((uint8_t**)&enc_session_key); + SharedMemory* mac_key_context; + InitPointer((uint8_t**)&mac_key_context); + SharedMemory* enc_key_context; + InitPointer((uint8_t**)&enc_key_context); + ODK_Unpack_DeriveKeysFromSessionKey_Request( + request, &session, &enc_session_key, &enc_session_key_length, + &mac_key_context, &mac_key_context_length, &enc_key_context, + &enc_key_context_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_DeriveKeysFromSessionKey( + session, enc_session_key, enc_session_key_length, mac_key_context, + mac_key_context_length, enc_key_context, enc_key_context_length); + ODK_Pack_DeriveKeysFromSessionKey_Response(response, result); + break; + } + case 14: /* OEMCrypto_GenerateNonce */ + { + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + uint32_t* nonce; + InitPointer((uint8_t**)&nonce); + ODK_Unpack_GenerateNonce_Request(request, &session, &nonce); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_GenerateNonce(session, nonce); + ODK_Pack_GenerateNonce_Response(response, result, nonce); + break; + } + case 13: /* OEMCrypto_GenerateSignature */ + { + size_t message_length; + Init_size_t((size_t*)&message_length); + size_t* signature_length = (size_t*)VarAlloc(sizeof(size_t)); + Init_size_t(signature_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + SharedMemory* message; + InitPointer((uint8_t**)&message); + uint8_t* signature; + InitPointer((uint8_t**)&signature); + ODK_Unpack_GenerateSignature_Request(request, &session, &message, + &message_length, &signature, + &signature_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_GenerateSignature(session, message, message_length, + signature, signature_length); + ODK_Pack_GenerateSignature_Response(response, result, signature, + signature_length); + break; + } + case 55: /* OEMCrypto_LoadSRM */ + { + size_t buffer_length; + Init_size_t((size_t*)&buffer_length); + uint8_t* buffer; + InitPointer((uint8_t**)&buffer); + ODK_Unpack_LoadSRM_Request(request, &buffer, &buffer_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_LoadSRM(buffer, buffer_length); + ODK_Pack_LoadSRM_Response(response, result); + break; + } + case 83: /* OEMCrypto_LoadKeys */ + { + size_t message_length; + Init_size_t((size_t*)&message_length); + size_t signature_length; + Init_size_t((size_t*)&signature_length); + size_t key_array_length; + Init_size_t((size_t*)&key_array_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + SharedMemory* message; + InitPointer((uint8_t**)&message); + SharedMemory* signature; + InitPointer((uint8_t**)&signature); + OEMCrypto_Substring enc_mac_keys_iv; + Init_OEMCrypto_Substring((OEMCrypto_Substring*)&enc_mac_keys_iv); + OEMCrypto_Substring enc_mac_keys; + Init_OEMCrypto_Substring((OEMCrypto_Substring*)&enc_mac_keys); + OEMCrypto_KeyObject* key_array; + InitPointer((uint8_t**)&key_array); + OEMCrypto_Substring pst; + Init_OEMCrypto_Substring((OEMCrypto_Substring*)&pst); + OEMCrypto_Substring srm_restriction_data; + Init_OEMCrypto_Substring((OEMCrypto_Substring*)&srm_restriction_data); + OEMCrypto_LicenseType license_type; + Init_uint32_t((uint32_t*)&license_type); + ODK_Unpack_LoadKeys_Request( + request, &session, &message, &message_length, &signature, + &signature_length, &enc_mac_keys_iv, &enc_mac_keys, &key_array_length, + &key_array, &pst, &srm_restriction_data, &license_type); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_LoadKeys(session, message, message_length, signature, + signature_length, enc_mac_keys_iv, + enc_mac_keys, key_array_length, key_array, + pst, srm_restriction_data, license_type); + ODK_Pack_LoadKeys_Response(response, result); + break; + } + case 92: /* OEMCrypto_LoadEntitledContentKeys */ + { + size_t message_length; + Init_size_t((size_t*)&message_length); + size_t key_array_length; + Init_size_t((size_t*)&key_array_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + SharedMemory* message; + InitPointer((uint8_t**)&message); + OEMCrypto_EntitledContentKeyObject* key_array; + InitPointer((uint8_t**)&key_array); + ODK_Unpack_LoadEntitledContentKeys_Request(request, &session, &message, + &message_length, + &key_array_length, &key_array); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_LoadEntitledContentKeys( + session, message, message_length, key_array_length, key_array); + ODK_Pack_LoadEntitledContentKeys_Response(response, result); + break; + } + case 91: /* OEMCrypto_RefreshKeys */ + { + size_t message_length; + Init_size_t((size_t*)&message_length); + size_t signature_length; + Init_size_t((size_t*)&signature_length); + size_t key_array_length; + Init_size_t((size_t*)&key_array_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + SharedMemory* message; + InitPointer((uint8_t**)&message); + SharedMemory* signature; + InitPointer((uint8_t**)&signature); + OEMCrypto_KeyRefreshObject* key_array; + InitPointer((uint8_t**)&key_array); + ODK_Unpack_RefreshKeys_Request( + request, &session, &message, &message_length, &signature, + &signature_length, &key_array_length, &key_array); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = + OEMCrypto_RefreshKeys(session, message, message_length, signature, + signature_length, key_array_length, key_array); + ODK_Pack_RefreshKeys_Response(response, result); + break; + } + case 41: /* OEMCrypto_QueryKeyControl */ + { + size_t content_key_id_length; + Init_size_t((size_t*)&content_key_id_length); + size_t* key_control_block_length = (size_t*)VarAlloc(sizeof(size_t)); + Init_size_t(key_control_block_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + uint8_t* content_key_id; + InitPointer((uint8_t**)&content_key_id); + uint8_t* key_control_block; + InitPointer((uint8_t**)&key_control_block); + ODK_Unpack_QueryKeyControl_Request( + request, &session, &content_key_id, &content_key_id_length, + &key_control_block, &key_control_block_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_QueryKeyControl( + session, content_key_id, content_key_id_length, key_control_block, + key_control_block_length); + ODK_Pack_QueryKeyControl_Response(response, result, key_control_block, + key_control_block_length); + break; + } + case 81: /* OEMCrypto_SelectKey */ + { + size_t content_key_id_length; + Init_size_t((size_t*)&content_key_id_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + uint8_t* content_key_id; + InitPointer((uint8_t**)&content_key_id); + OEMCryptoCipherMode cipher_mode; + Init_uint32_t((uint32_t*)&cipher_mode); + ODK_Unpack_SelectKey_Request(request, &session, &content_key_id, + &content_key_id_length, &cipher_mode); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_SelectKey(session, content_key_id, + content_key_id_length, cipher_mode); + ODK_Pack_SelectKey_Response(response, result); + break; + } + case 48: /* OEMCrypto_DecryptCENC */ + { + size_t data_addr_length; + Init_size_t((size_t*)&data_addr_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + SharedMemory* data_addr; + InitPointer((uint8_t**)&data_addr); + bool is_encrypted; + Init_bool((bool*)&is_encrypted); + uint8_t iv[16]; + InitMemory(&iv[0], 16); + size_t block_offset; + Init_size_t((size_t*)&block_offset); + OEMCrypto_DestBufferDesc* out_buffer = + (OEMCrypto_DestBufferDesc*)VarAlloc(sizeof(OEMCrypto_DestBufferDesc)); + Init_OEMCrypto_DestBufferDesc(out_buffer); + OEMCrypto_CENCEncryptPatternDesc* pattern = + (OEMCrypto_CENCEncryptPatternDesc*)VarAlloc( + sizeof(OEMCrypto_CENCEncryptPatternDesc)); + Init_OEMCrypto_CENCEncryptPatternDesc( + (OEMCrypto_CENCEncryptPatternDesc*)pattern); + uint8_t subsample_flags; + Init_uint8_t((uint8_t*)&subsample_flags); + ODK_Unpack_DecryptCENC_Request( + request, &session, &data_addr, &data_addr_length, &is_encrypted, + &iv[0], &block_offset, &out_buffer, &pattern, &subsample_flags); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_DecryptCENC(session, data_addr, data_addr_length, + is_encrypted, iv, block_offset, out_buffer, + pattern, subsample_flags); + ODK_Pack_DecryptCENC_Response(response, result, out_buffer); + break; + } + case 93: /* OEMCrypto_CopyBuffer */ + { + size_t data_addr_length; + Init_size_t((size_t*)&data_addr_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + SharedMemory* data_addr; + InitPointer((uint8_t**)&data_addr); + OEMCrypto_DestBufferDesc* out_buffer = + (OEMCrypto_DestBufferDesc*)VarAlloc(sizeof(OEMCrypto_DestBufferDesc)); + Init_OEMCrypto_DestBufferDesc(out_buffer); + uint8_t subsample_flags; + Init_uint8_t((uint8_t*)&subsample_flags); + ODK_Unpack_CopyBuffer_Request(request, &session, &data_addr, + &data_addr_length, &out_buffer, + &subsample_flags); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_CopyBuffer(session, data_addr, data_addr_length, + out_buffer, subsample_flags); + ODK_Pack_CopyBuffer_Response(response, result, out_buffer); + break; + } + case 24: /* OEMCrypto_Generic_Encrypt */ + { + size_t in_buffer_length; + Init_size_t((size_t*)&in_buffer_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + SharedMemory* in_buffer; + InitPointer((uint8_t**)&in_buffer); + uint8_t iv[16]; + InitMemory(&iv[0], 16); + OEMCrypto_Algorithm algorithm; + Init_uint32_t((uint32_t*)&algorithm); + uint8_t* out_buffer; + InitPointer((uint8_t**)&out_buffer); + ODK_Unpack_Generic_Encrypt_Request(request, &session, &in_buffer, + &in_buffer_length, &iv[0], &algorithm, + &out_buffer); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_Generic_Encrypt(session, in_buffer, in_buffer_length, + iv, algorithm, out_buffer); + ODK_Pack_Generic_Encrypt_Response(response, result, in_buffer_length, + out_buffer); + break; + } + case 25: /* OEMCrypto_Generic_Decrypt */ + { + size_t in_buffer_length; + Init_size_t((size_t*)&in_buffer_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + SharedMemory* in_buffer; + InitPointer((uint8_t**)&in_buffer); + uint8_t iv[16]; + InitMemory(&iv[0], 16); + OEMCrypto_Algorithm algorithm; + Init_uint32_t((uint32_t*)&algorithm); + uint8_t* out_buffer; + InitPointer((uint8_t**)&out_buffer); + ODK_Unpack_Generic_Decrypt_Request(request, &session, &in_buffer, + &in_buffer_length, &iv[0], &algorithm, + &out_buffer); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_Generic_Decrypt(session, in_buffer, in_buffer_length, + iv, algorithm, out_buffer); + ODK_Pack_Generic_Decrypt_Response(response, result, in_buffer_length, + out_buffer); + break; + } + case 26: /* OEMCrypto_Generic_Sign */ + { + size_t buffer_length; + Init_size_t((size_t*)&buffer_length); + size_t* signature_length = (size_t*)VarAlloc(sizeof(size_t)); + Init_size_t(signature_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + SharedMemory* buffer; + InitPointer((uint8_t**)&buffer); + OEMCrypto_Algorithm algorithm; + Init_uint32_t((uint32_t*)&algorithm); + uint8_t* signature; + InitPointer((uint8_t**)&signature); + ODK_Unpack_Generic_Sign_Request(request, &session, &buffer, + &buffer_length, &algorithm, &signature, + &signature_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_Generic_Sign(session, buffer, buffer_length, algorithm, + signature, signature_length); + ODK_Pack_Generic_Sign_Response(response, result, signature, + signature_length); + break; + } + case 27: /* OEMCrypto_Generic_Verify */ + { + size_t buffer_length; + Init_size_t((size_t*)&buffer_length); + size_t signature_length; + Init_size_t((size_t*)&signature_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + SharedMemory* buffer; + InitPointer((uint8_t**)&buffer); + OEMCrypto_Algorithm algorithm; + Init_uint32_t((uint32_t*)&algorithm); + SharedMemory* signature; + InitPointer((uint8_t**)&signature); + ODK_Unpack_Generic_Verify_Request(request, &session, &buffer, + &buffer_length, &algorithm, &signature, + &signature_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_Generic_Verify(session, buffer, buffer_length, + algorithm, signature, signature_length); + ODK_Pack_Generic_Verify_Response(response, result); + break; + } + case 30: /* OEMCrypto_UpdateUsageTable */ + { + ODK_Unpack_UpdateUsageTable_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_UpdateUsageTable(); + ODK_Pack_UpdateUsageTable_Response(response, result); + break; + } + case 8: /* OEMCrypto_WrapKeyboxOrOEMCert */ + { + size_t rotLength; + Init_size_t((size_t*)&rotLength); + size_t* wrappedRotLength; + InitPointer((uint8_t**)&wrappedRotLength); + size_t transportKeyLength; + Init_size_t((size_t*)&transportKeyLength); + uint8_t* rot; + InitPointer((uint8_t**)&rot); + uint8_t* wrappedRot; + InitPointer((uint8_t**)&wrappedRot); + uint8_t* transportKey; + InitPointer((uint8_t**)&transportKey); + ODK_Unpack_WrapKeyboxOrOEMCert_Request( + request, &rot, &rotLength, &wrappedRot, &wrappedRotLength, + &transportKey, &transportKeyLength); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_WrapKeyboxOrOEMCert(rot, rotLength, wrappedRot, + wrappedRotLength, transportKey, + transportKeyLength); + ODK_Pack_WrapKeyboxOrOEMCert_Response(response, result, wrappedRot, + wrappedRotLength); + break; + } + case 3: /* OEMCrypto_InstallKeyboxOrOEMCert */ + { + size_t rotLength; + Init_size_t((size_t*)&rotLength); + uint8_t* rot; + InitPointer((uint8_t**)&rot); + ODK_Unpack_InstallKeyboxOrOEMCert_Request(request, &rot, &rotLength); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_InstallKeyboxOrOEMCert(rot, rotLength); + ODK_Pack_InstallKeyboxOrOEMCert_Response(response, result); + break; + } + case 49: /* OEMCrypto_GetProvisioningMethod */ + { + ODK_Unpack_GetProvisioningMethod_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCrypto_ProvisioningMethod result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_GetProvisioningMethod(); + ODK_Pack_GetProvisioningMethod_Response(response, result); + break; + } + case 5: /* OEMCrypto_IsKeyboxOrOEMCertValid */ + { + ODK_Unpack_IsKeyboxOrOEMCertValid_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_IsKeyboxOrOEMCertValid(); + ODK_Pack_IsKeyboxOrOEMCertValid_Response(response, result); + break; + } + case 7: /* OEMCrypto_GetDeviceID */ + { + size_t* device_id_length = (size_t*)VarAlloc(sizeof(size_t)); + Init_size_t(device_id_length); + uint8_t* device_id; + InitPointer((uint8_t**)&device_id); + ODK_Unpack_GetDeviceID_Request(request, &device_id, &device_id_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_GetDeviceID(device_id, device_id_length); + ODK_Pack_GetDeviceID_Response(response, result, device_id, + device_id_length); + break; + } + case 4: /* OEMCrypto_GetKeyData */ + { + size_t* keyDataLength = (size_t*)VarAlloc(sizeof(size_t)); + Init_size_t(keyDataLength); + uint8_t* keyData; + InitPointer((uint8_t**)&keyData); + ODK_Unpack_GetKeyData_Request(request, &keyData, &keyDataLength); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_GetKeyData(keyData, keyDataLength); + ODK_Pack_GetKeyData_Response(response, result, keyData, keyDataLength); + break; + } + case 78: /* OEMCrypto_LoadTestKeybox */ + { + size_t buffer_length; + Init_size_t((size_t*)&buffer_length); + uint8_t* buffer; + InitPointer((uint8_t**)&buffer); + ODK_Unpack_LoadTestKeybox_Request(request, &buffer, &buffer_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_LoadTestKeybox(buffer, buffer_length); + ODK_Pack_LoadTestKeybox_Response(response, result); + break; + } + case 50: /* OEMCrypto_GetOEMPublicCertificate */ + { + size_t* public_cert_length = (size_t*)VarAlloc(sizeof(size_t)); + Init_size_t(public_cert_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + uint8_t* public_cert; + InitPointer((uint8_t**)&public_cert); + ODK_Unpack_GetOEMPublicCertificate_Request( + request, &session, &public_cert, &public_cert_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_GetOEMPublicCertificate(session, public_cert, + public_cert_length); + ODK_Pack_GetOEMPublicCertificate_Response(response, result, public_cert, + public_cert_length); + break; + } + case 6: /* OEMCrypto_GetRandom */ + { + size_t random_data_length; + Init_size_t((size_t*)&random_data_length); + uint8_t* random_data; + InitPointer((uint8_t**)&random_data); + ODK_Unpack_GetRandom_Request(request, &random_data, &random_data_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_GetRandom(random_data, random_data_length); + ODK_Pack_GetRandom_Response(response, result, random_data, + random_data_length); + break; + } + case 22: /* OEMCrypto_APIVersion */ + { + ODK_Unpack_APIVersion_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + uint32_t result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_APIVersion(); + ODK_Pack_APIVersion_Response(response, result); + break; + } + case 46: /* OEMCrypto_Security_Patch_Level */ + { + ODK_Unpack_Security_Patch_Level_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + uint8_t result; + Init_uint8_t((uint8_t*)&result); + result = OEMCrypto_Security_Patch_Level(); + ODK_Pack_Security_Patch_Level_Response(response, result); + break; + } + case 44: /* OEMCrypto_GetHDCPCapability */ + { + OEMCrypto_HDCP_Capability* current; + InitPointer((uint8_t**)¤t); + OEMCrypto_HDCP_Capability* maximum; + InitPointer((uint8_t**)&maximum); + ODK_Unpack_GetHDCPCapability_Request(request, ¤t, &maximum); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_GetHDCPCapability(current, maximum); + ODK_Pack_GetHDCPCapability_Response(response, result, current, maximum); + break; + } + case 29: /* OEMCrypto_SupportsUsageTable */ + { + ODK_Unpack_SupportsUsageTable_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + bool result; + Init_bool((bool*)&result); + result = OEMCrypto_SupportsUsageTable(); + ODK_Pack_SupportsUsageTable_Response(response, result); + break; + } + case 39: /* OEMCrypto_IsAntiRollbackHwPresent */ + { + ODK_Unpack_IsAntiRollbackHwPresent_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + bool result; + Init_bool((bool*)&result); + result = OEMCrypto_IsAntiRollbackHwPresent(); + ODK_Pack_IsAntiRollbackHwPresent_Response(response, result); + break; + } + case 38: /* OEMCrypto_GetNumberOfOpenSessions */ + { + size_t* count; + InitPointer((uint8_t**)&count); + ODK_Unpack_GetNumberOfOpenSessions_Request(request, &count); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_GetNumberOfOpenSessions(count); + ODK_Pack_GetNumberOfOpenSessions_Response(response, result, count); + break; + } + case 37: /* OEMCrypto_GetMaxNumberOfSessions */ + { + size_t* max; + InitPointer((uint8_t**)&max); + ODK_Unpack_GetMaxNumberOfSessions_Request(request, &max); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_GetMaxNumberOfSessions(max); + ODK_Pack_GetMaxNumberOfSessions_Response(response, result, max); + break; + } + case 52: /* OEMCrypto_SupportedCertificates */ + { + ODK_Unpack_SupportedCertificates_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + uint32_t result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_SupportedCertificates(); + ODK_Pack_SupportedCertificates_Response(response, result); + break; + } + case 53: /* OEMCrypto_IsSRMUpdateSupported */ + { + ODK_Unpack_IsSRMUpdateSupported_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + bool result; + Init_bool((bool*)&result); + result = OEMCrypto_IsSRMUpdateSupported(); + ODK_Pack_IsSRMUpdateSupported_Response(response, result); + break; + } + case 54: /* OEMCrypto_GetCurrentSRMVersion */ + { + uint16_t* version; + InitPointer((uint8_t**)&version); + ODK_Unpack_GetCurrentSRMVersion_Request(request, &version); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_GetCurrentSRMVersion(version); + ODK_Pack_GetCurrentSRMVersion_Response(response, result, version); + break; + } + case 71: /* OEMCrypto_GetAnalogOutputFlags */ + { + ODK_Unpack_GetAnalogOutputFlags_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + uint32_t result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_GetAnalogOutputFlags(); + ODK_Pack_GetAnalogOutputFlags_Response(response, result); + break; + } + case 85: /* OEMCrypto_ResourceRatingTier */ + { + ODK_Unpack_ResourceRatingTier_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + uint32_t result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_ResourceRatingTier(); + ODK_Pack_ResourceRatingTier_Response(response, result); + break; + } + case 51: /* OEMCrypto_RewrapDeviceRSAKey30 */ + { + size_t encrypted_message_key_length; + Init_size_t((size_t*)&encrypted_message_key_length); + size_t enc_rsa_key_length; + Init_size_t((size_t*)&enc_rsa_key_length); + size_t* wrapped_rsa_key_length = (size_t*)VarAlloc(sizeof(size_t)); + Init_size_t(wrapped_rsa_key_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + uint32_t* unaligned_nonce = (uint32_t*)VarAlloc(sizeof(uint32_t)); + Init_uint32_t((uint32_t*)unaligned_nonce); + SharedMemory* encrypted_message_key; + InitPointer((uint8_t**)&encrypted_message_key); + SharedMemory* enc_rsa_key; + InitPointer((uint8_t**)&enc_rsa_key); + uint8_t* enc_rsa_key_iv = (uint8_t*)VarAlloc(sizeof(uint8_t)); + Init_uint8_t((uint8_t*)enc_rsa_key_iv); + uint8_t* wrapped_rsa_key; + InitPointer((uint8_t**)&wrapped_rsa_key); + ODK_Unpack_RewrapDeviceRSAKey30_Request( + request, &session, &unaligned_nonce, &encrypted_message_key, + &encrypted_message_key_length, &enc_rsa_key, &enc_rsa_key_length, + &enc_rsa_key_iv, &wrapped_rsa_key, &wrapped_rsa_key_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_RewrapDeviceRSAKey30( + session, unaligned_nonce, encrypted_message_key, + encrypted_message_key_length, enc_rsa_key, enc_rsa_key_length, + enc_rsa_key_iv, wrapped_rsa_key, wrapped_rsa_key_length); + ODK_Pack_RewrapDeviceRSAKey30_Response(response, result, wrapped_rsa_key, + wrapped_rsa_key_length); + break; + } + case 18: /* OEMCrypto_RewrapDeviceRSAKey */ + { + size_t message_length; + Init_size_t((size_t*)&message_length); + size_t signature_length; + Init_size_t((size_t*)&signature_length); + size_t enc_rsa_key_length; + Init_size_t((size_t*)&enc_rsa_key_length); + size_t* wrapped_rsa_key_length = (size_t*)VarAlloc(sizeof(size_t)); + Init_size_t(wrapped_rsa_key_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + SharedMemory* message; + InitPointer((uint8_t**)&message); + SharedMemory* signature; + InitPointer((uint8_t**)&signature); + uint32_t* unaligned_nonce = (uint32_t*)VarAlloc(sizeof(uint32_t)); + Init_uint32_t((uint32_t*)unaligned_nonce); + uint8_t* enc_rsa_key; + InitPointer((uint8_t**)&enc_rsa_key); + uint8_t* enc_rsa_key_iv = (uint8_t*)VarAlloc(sizeof(uint8_t)); + Init_uint8_t((uint8_t*)enc_rsa_key_iv); + uint8_t* wrapped_rsa_key; + InitPointer((uint8_t**)&wrapped_rsa_key); + ODK_Unpack_RewrapDeviceRSAKey_Request( + request, &session, &message, &message_length, &signature, + &signature_length, &unaligned_nonce, &enc_rsa_key, + &enc_rsa_key_length, &enc_rsa_key_iv, &wrapped_rsa_key, + &wrapped_rsa_key_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_RewrapDeviceRSAKey( + session, message, message_length, signature, signature_length, + unaligned_nonce, enc_rsa_key, enc_rsa_key_length, enc_rsa_key_iv, + wrapped_rsa_key, wrapped_rsa_key_length); + ODK_Pack_RewrapDeviceRSAKey_Response(response, result, wrapped_rsa_key, + wrapped_rsa_key_length); + break; + } + case 19: /* OEMCrypto_LoadDeviceRSAKey */ + { + size_t wrapped_rsa_key_length; + Init_size_t((size_t*)&wrapped_rsa_key_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + SharedMemory* wrapped_rsa_key; + InitPointer((uint8_t**)&wrapped_rsa_key); + ODK_Unpack_LoadDeviceRSAKey_Request(request, &session, &wrapped_rsa_key, + &wrapped_rsa_key_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_LoadDeviceRSAKey(session, wrapped_rsa_key, + wrapped_rsa_key_length); + ODK_Pack_LoadDeviceRSAKey_Response(response, result); + break; + } + case 45: /* OEMCrypto_LoadTestRSAKey */ + { + ODK_Unpack_LoadTestRSAKey_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_LoadTestRSAKey(); + ODK_Pack_LoadTestRSAKey_Response(response, result); + break; + } + case 36: /* OEMCrypto_GenerateRSASignature */ + { + size_t message_length; + Init_size_t((size_t*)&message_length); + size_t* signature_length = (size_t*)VarAlloc(sizeof(size_t)); + Init_size_t(signature_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + SharedMemory* message; + InitPointer((uint8_t**)&message); + uint8_t* signature; + InitPointer((uint8_t**)&signature); + RSA_Padding_Scheme padding_scheme; + Init_uint8_t((uint8_t*)&padding_scheme); + ODK_Unpack_GenerateRSASignature_Request( + request, &session, &message, &message_length, &signature, + &signature_length, &padding_scheme); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_GenerateRSASignature(session, message, message_length, + signature, signature_length, + padding_scheme); + ODK_Pack_GenerateRSASignature_Response(response, result, signature, + signature_length); + break; + } + case 61: /* OEMCrypto_CreateUsageTableHeader */ + { + size_t* header_buffer_length = (size_t*)VarAlloc(sizeof(size_t)); + Init_size_t(header_buffer_length); + uint8_t* header_buffer; + InitPointer((uint8_t**)&header_buffer); + ODK_Unpack_CreateUsageTableHeader_Request(request, &header_buffer, + &header_buffer_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = + OEMCrypto_CreateUsageTableHeader(header_buffer, header_buffer_length); + ODK_Pack_CreateUsageTableHeader_Response(response, result, header_buffer, + header_buffer_length); + break; + } + case 62: /* OEMCrypto_LoadUsageTableHeader */ + { + size_t buffer_length; + Init_size_t((size_t*)&buffer_length); + uint8_t* buffer; + InitPointer((uint8_t**)&buffer); + ODK_Unpack_LoadUsageTableHeader_Request(request, &buffer, &buffer_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_LoadUsageTableHeader(buffer, buffer_length); + ODK_Pack_LoadUsageTableHeader_Response(response, result); + break; + } + case 63: /* OEMCrypto_CreateNewUsageEntry */ + { + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + uint32_t* usage_entry_number; + InitPointer((uint8_t**)&usage_entry_number); + ODK_Unpack_CreateNewUsageEntry_Request(request, &session, + &usage_entry_number); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_CreateNewUsageEntry(session, usage_entry_number); + ODK_Pack_CreateNewUsageEntry_Response(response, result, + usage_entry_number); + break; + } + case 64: /* OEMCrypto_LoadUsageEntry */ + { + size_t buffer_length; + Init_size_t((size_t*)&buffer_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + uint32_t usage_entry_number; + Init_uint32_t((uint32_t*)&usage_entry_number); + uint8_t* buffer; + InitPointer((uint8_t**)&buffer); + ODK_Unpack_LoadUsageEntry_Request(request, &session, &usage_entry_number, + &buffer, &buffer_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_LoadUsageEntry(session, usage_entry_number, buffer, + buffer_length); + ODK_Pack_LoadUsageEntry_Response(response, result); + break; + } + case 65: /* OEMCrypto_UpdateUsageEntry */ + { + size_t* header_buffer_length = (size_t*)VarAlloc(sizeof(size_t)); + Init_size_t(header_buffer_length); + size_t* entry_buffer_length = (size_t*)VarAlloc(sizeof(size_t)); + Init_size_t(entry_buffer_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + SharedMemory* header_buffer; + InitPointer((uint8_t**)&header_buffer); + SharedMemory* entry_buffer; + InitPointer((uint8_t**)&entry_buffer); + ODK_Unpack_UpdateUsageEntry_Request(request, &session, &header_buffer, + &header_buffer_length, &entry_buffer, + &entry_buffer_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_UpdateUsageEntry(session, header_buffer, + header_buffer_length, entry_buffer, + entry_buffer_length); + ODK_Pack_UpdateUsageEntry_Response( + response, result, SharedMemory_GetAddress(0), header_buffer_length, + SharedMemory_GetAddress(1), entry_buffer_length); + break; + } + case 66: /* OEMCrypto_DeactivateUsageEntry */ + { + size_t pst_length; + Init_size_t((size_t*)&pst_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + uint8_t* pst; + InitPointer((uint8_t**)&pst); + ODK_Unpack_DeactivateUsageEntry_Request(request, &session, &pst, + &pst_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_DeactivateUsageEntry(session, pst, pst_length); + ODK_Pack_DeactivateUsageEntry_Response(response, result); + break; + } + case 32: /* OEMCrypto_ReportUsage */ + { + size_t pst_length; + Init_size_t((size_t*)&pst_length); + size_t* buffer_length = (size_t*)VarAlloc(sizeof(size_t)); + Init_size_t(buffer_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + uint8_t* pst; + InitPointer((uint8_t**)&pst); + uint8_t* buffer; + InitPointer((uint8_t**)&buffer); + ODK_Unpack_ReportUsage_Request(request, &session, &pst, &pst_length, + &buffer, &buffer_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_ReportUsage(session, pst, pst_length, buffer, + buffer_length); + ODK_Pack_ReportUsage_Response(response, result, buffer, buffer_length); + break; + } + case 33: /* OEMCrypto_DeleteUsageEntry */ + { + size_t pst_length; + Init_size_t((size_t*)&pst_length); + size_t message_length; + Init_size_t((size_t*)&message_length); + size_t signature_length; + Init_size_t((size_t*)&signature_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + uint8_t* pst; + InitPointer((uint8_t**)&pst); + uint8_t* message; + InitPointer((uint8_t**)&message); + uint8_t* signature; + InitPointer((uint8_t**)&signature); + ODK_Unpack_DeleteUsageEntry_Request(request, &session, &pst, &pst_length, + &message, &message_length, &signature, + &signature_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_DeleteUsageEntry(session, pst, pst_length, message, + message_length, signature, + signature_length); + ODK_Pack_DeleteUsageEntry_Response(response, result); + break; + } + case 43: /* OEMCrypto_ForceDeleteUsageEntry */ + { + size_t pst_length; + Init_size_t((size_t*)&pst_length); + uint8_t* pst; + InitPointer((uint8_t**)&pst); + ODK_Unpack_ForceDeleteUsageEntry_Request(request, &pst, &pst_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_ForceDeleteUsageEntry(pst, pst_length); + ODK_Pack_ForceDeleteUsageEntry_Response(response, result); + break; + } + case 68: /* OEMCrypto_MoveEntry */ + { + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + uint32_t new_index; + Init_uint32_t((uint32_t*)&new_index); + ODK_Unpack_MoveEntry_Request(request, &session, &new_index); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_MoveEntry(session, new_index); + ODK_Pack_MoveEntry_Response(response, result); + break; + } + case 67: /* OEMCrypto_ShrinkUsageTableHeader */ + { + size_t* header_buffer_length = (size_t*)VarAlloc(sizeof(size_t)); + Init_size_t(header_buffer_length); + uint32_t new_entry_count; + Init_uint32_t((uint32_t*)&new_entry_count); + uint8_t* header_buffer; + InitPointer((uint8_t**)&header_buffer); + ODK_Unpack_ShrinkUsageTableHeader_Request( + request, &new_entry_count, &header_buffer, &header_buffer_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_ShrinkUsageTableHeader(new_entry_count, header_buffer, + header_buffer_length); + ODK_Pack_ShrinkUsageTableHeader_Response(response, result, header_buffer, + header_buffer_length); + break; + } + case 69: /* OEMCrypto_CopyOldUsageEntry */ + { + size_t pst_length; + Init_size_t((size_t*)&pst_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + uint8_t* pst; + InitPointer((uint8_t**)&pst); + ODK_Unpack_CopyOldUsageEntry_Request(request, &session, &pst, + &pst_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_CopyOldUsageEntry(session, pst, pst_length); + ODK_Pack_CopyOldUsageEntry_Response(response, result); + break; + } + case 34: /* OEMCrypto_DeleteOldUsageTable */ + { + ODK_Unpack_DeleteOldUsageTable_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_DeleteOldUsageTable(); + ODK_Pack_DeleteOldUsageTable_Response(response, result); + break; + } + case 57: /* OEMCrypto_RemoveSRM */ + { + ODK_Unpack_RemoveSRM_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_RemoveSRM(); + ODK_Pack_RemoveSRM_Response(response, result); + break; + } + case 70: /* OEMCrypto_CreateOldUsageEntry */ + { + size_t pst_length; + Init_size_t((size_t*)&pst_length); + uint64_t time_since_license_received; + Init_uint64_t((uint64_t*)&time_since_license_received); + uint64_t time_since_first_decrypt; + Init_uint64_t((uint64_t*)&time_since_first_decrypt); + uint64_t time_since_last_decrypt; + Init_uint64_t((uint64_t*)&time_since_last_decrypt); + OEMCrypto_Usage_Entry_Status status; + Init_uint32_t((uint32_t*)&status); + uint8_t server_mac_key[32]; + InitMemory(&server_mac_key[0], 32); + uint8_t client_mac_key[32]; + InitMemory(&client_mac_key[0], 32); + uint8_t* pst; + InitPointer((uint8_t**)&pst); + ODK_Unpack_CreateOldUsageEntry_Request( + request, &time_since_license_received, &time_since_first_decrypt, + &time_since_last_decrypt, &status, &server_mac_key[0], + &client_mac_key[0], &pst, &pst_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_CreateOldUsageEntry( + time_since_license_received, time_since_first_decrypt, + time_since_last_decrypt, status, server_mac_key, client_mac_key, pst, + pst_length); + ODK_Pack_CreateOldUsageEntry_Response(response, result); + break; + } + case 86: /* OEMCrypto_SupportsDecryptHash */ + { + ODK_Unpack_SupportsDecryptHash_Request(request); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + uint32_t result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_SupportsDecryptHash(); + ODK_Pack_SupportsDecryptHash_Response(response, result); + break; + } + case 88: /* OEMCrypto_SetDecryptHash */ + { + size_t hash_length; + Init_size_t((size_t*)&hash_length); + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + uint32_t frame_number; + Init_uint32_t((uint32_t*)&frame_number); + uint8_t* hash; + InitPointer((uint8_t**)&hash); + ODK_Unpack_SetDecryptHash_Request(request, &session, &frame_number, &hash, + &hash_length); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = + OEMCrypto_SetDecryptHash(session, frame_number, hash, hash_length); + ODK_Pack_SetDecryptHash_Response(response, result); + break; + } + case 89: /* OEMCrypto_GetHashErrorCode */ + { + OEMCrypto_SESSION session; + Init_uint32_t((uint32_t*)&session); + uint32_t* failed_frame_number; + InitPointer((uint8_t**)&failed_frame_number); + ODK_Unpack_GetHashErrorCode_Request(request, &session, + &failed_frame_number); + message_status = GetStatus(request); + if (message_status != MESSAGE_STATUS_OK) { + return message_status; + } + OEMCryptoResult result; + Init_uint32_t((uint32_t*)&result); + result = OEMCrypto_GetHashErrorCode(session, failed_frame_number); + ODK_Pack_GetHashErrorCode_Response(response, result, failed_frame_number); + break; + } + default: + return MESSAGE_STATUS_API_VALUE_ERROR; + } + return GetStatus(response); +} diff --git a/serialization/generated_src/oemcrypto_api.c b/serialization/generated_src/oemcrypto_api.c new file mode 100644 index 0000000..c47b2e7 --- /dev/null +++ b/serialization/generated_src/oemcrypto_api.c @@ -0,0 +1,2473 @@ +/* + * This code is auto-generated, do not edit + */ + +#include + +#include "OEMCryptoCENC.h" +#include "api_support.h" +#include "bump_allocator.h" +#include "shared_memory_allocator.h" +#include "shared_memory_interface.h" +#include "special_cases.h" +#include "transport_interface.h" + +OEMCRYPTO_API const char* OEMCrypto_SecurityLevel() { + char* result = NULL; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_SecurityLevel_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_SecurityLevel_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API const char* OEMCrypto_BuildInformation() { + char* result = NULL; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_BuildInformation_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_BuildInformation_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_SetSandbox(const uint8_t* sandbox_id, + size_t sandbox_id_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_SetSandbox_Request(request, sandbox_id, sandbox_id_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_SetSandbox_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_Initialize() { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_Initialize_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_Initialize_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_Terminate() { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_Terminate_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_Terminate_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + API_Terminate(); + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_OpenSession(OEMCrypto_SESSION* session) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_OpenSession_Request(request, session); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_OpenSession_Response(response, &result, &session); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_CloseSession(OEMCrypto_SESSION session) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_CloseSession_Request(request, session); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_CloseSession_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateDerivedKeys( + OEMCrypto_SESSION session, const SharedMemory* mac_key_context, + uint32_t mac_key_context_length, const SharedMemory* enc_key_context, + uint32_t enc_key_context_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_GenerateDerivedKeys_Request(request, session, mac_key_context, + mac_key_context_length, enc_key_context, + enc_key_context_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_GenerateDerivedKeys_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( + OEMCrypto_SESSION session, const uint8_t* enc_session_key, + size_t enc_session_key_length, const SharedMemory* mac_key_context, + size_t mac_key_context_length, const SharedMemory* enc_key_context, + size_t enc_key_context_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_DeriveKeysFromSessionKey_Request( + request, session, enc_session_key, enc_session_key_length, + mac_key_context, mac_key_context_length, enc_key_context, + enc_key_context_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_DeriveKeysFromSessionKey_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, + uint32_t* nonce) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_GenerateNonce_Request(request, session, nonce); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_GenerateNonce_Response(response, &result, &nonce); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateSignature( + OEMCrypto_SESSION session, const SharedMemory* message, + size_t message_length, uint8_t* signature, size_t* signature_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_GenerateSignature_Request(request, session, message, message_length, + signature, signature_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_GenerateSignature_Response(response, &result, &signature, + &signature_length); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadSRM(const uint8_t* buffer, + size_t buffer_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_LoadSRM_Request(request, buffer, buffer_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_LoadSRM_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadKeys( + OEMCrypto_SESSION session, const SharedMemory* message, + size_t message_length, const SharedMemory* signature, + size_t signature_length, OEMCrypto_Substring enc_mac_keys_iv, + OEMCrypto_Substring enc_mac_keys, size_t key_array_length, + const OEMCrypto_KeyObject* key_array, OEMCrypto_Substring pst, + OEMCrypto_Substring srm_restriction_data, + OEMCrypto_LicenseType license_type) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_LoadKeys_Request(request, session, message, message_length, + signature, signature_length, enc_mac_keys_iv, + enc_mac_keys, key_array_length, key_array, pst, + srm_restriction_data, license_type); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_LoadKeys_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( + OEMCrypto_SESSION session, const SharedMemory* message, + size_t message_length, size_t key_array_length, + const OEMCrypto_EntitledContentKeyObject* key_array) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_LoadEntitledContentKeys_Request( + request, session, message, message_length, key_array_length, key_array); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_LoadEntitledContentKeys_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_RefreshKeys(OEMCrypto_SESSION session, const SharedMemory* message, + size_t message_length, const SharedMemory* signature, + size_t signature_length, size_t key_array_length, + const OEMCrypto_KeyRefreshObject* key_array) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_RefreshKeys_Request(request, session, message, message_length, + signature, signature_length, key_array_length, + key_array); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_RefreshKeys_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_QueryKeyControl( + OEMCrypto_SESSION session, const uint8_t* content_key_id, + size_t content_key_id_length, uint8_t* key_control_block, + size_t* key_control_block_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_QueryKeyControl_Request(request, session, content_key_id, + content_key_id_length, key_control_block, + key_control_block_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_QueryKeyControl_Response(response, &result, &key_control_block, + &key_control_block_length); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_SelectKey( + OEMCrypto_SESSION session, const uint8_t* content_key_id, + size_t content_key_id_length, OEMCryptoCipherMode cipher_mode) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_SelectKey_Request(request, session, content_key_id, + content_key_id_length, cipher_mode); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_SelectKey_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Encrypt( + OEMCrypto_SESSION session, const SharedMemory* in_buffer, + size_t in_buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm, + uint8_t* out_buffer) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_Generic_Encrypt_Request(request, session, in_buffer, + in_buffer_length, iv, algorithm, out_buffer); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_Generic_Encrypt_Response(response, &result, &in_buffer_length, + &out_buffer); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Decrypt( + OEMCrypto_SESSION session, const SharedMemory* in_buffer, + size_t in_buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm, + uint8_t* out_buffer) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_Generic_Decrypt_Request(request, session, in_buffer, + in_buffer_length, iv, algorithm, out_buffer); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_Generic_Decrypt_Response(response, &result, &in_buffer_length, + &out_buffer); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, const SharedMemory* buffer, + size_t buffer_length, OEMCrypto_Algorithm algorithm, + uint8_t* signature, size_t* signature_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_Generic_Sign_Request(request, session, buffer, buffer_length, + algorithm, signature, signature_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_Generic_Sign_Response(response, &result, &signature, + &signature_length); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Verify( + OEMCrypto_SESSION session, const SharedMemory* buffer, size_t buffer_length, + OEMCrypto_Algorithm algorithm, const SharedMemory* signature, + size_t signature_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_Generic_Verify_Request(request, session, buffer, buffer_length, + algorithm, signature, signature_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_Generic_Verify_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_UpdateUsageTable() { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_UpdateUsageTable_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_UpdateUsageTable_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_WrapKeyboxOrOEMCert( + const uint8_t* rot, size_t rotLength, uint8_t* wrappedRot, + size_t* wrappedRotLength, const uint8_t* transportKey, + size_t transportKeyLength) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_WrapKeyboxOrOEMCert_Request(request, rot, rotLength, wrappedRot, + wrappedRotLength, transportKey, + transportKeyLength); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_WrapKeyboxOrOEMCert_Response(response, &result, &wrappedRot, + &wrappedRotLength); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_InstallKeyboxOrOEMCert(const uint8_t* rot, size_t rotLength) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_InstallKeyboxOrOEMCert_Request(request, rot, rotLength); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_InstallKeyboxOrOEMCert_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod() { + OEMCrypto_ProvisioningMethod result = OEMCrypto_ProvisioningError; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_GetProvisioningMethod_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_GetProvisioningMethod_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid() { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_IsKeyboxOrOEMCertValid_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_IsKeyboxOrOEMCertValid_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* device_id, + size_t* device_id_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_GetDeviceID_Request(request, device_id, device_id_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_GetDeviceID_Response(response, &result, &device_id, + &device_id_length); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, + size_t* keyDataLength) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_GetKeyData_Request(request, keyData, keyDataLength); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_GetKeyData_Response(response, &result, &keyData, &keyDataLength); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestKeybox(const uint8_t* buffer, + size_t buffer_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_LoadTestKeybox_Request(request, buffer, buffer_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_LoadTestKeybox_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetOEMPublicCertificate( + OEMCrypto_SESSION session, uint8_t* public_cert, + size_t* public_cert_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_GetOEMPublicCertificate_Request(request, session, public_cert, + public_cert_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_GetOEMPublicCertificate_Response(response, &result, &public_cert, + &public_cert_length); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetRandom(uint8_t* random_data, + size_t random_data_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_GetRandom_Request(request, random_data, random_data_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_GetRandom_Response(response, &result, &random_data, + &random_data_length); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API uint32_t OEMCrypto_APIVersion() { + uint32_t result = 0; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_APIVersion_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_APIVersion_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API uint8_t OEMCrypto_Security_Patch_Level() { + uint8_t result = 0; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_Security_Patch_Level_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_Security_Patch_Level_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetHDCPCapability( + OEMCrypto_HDCP_Capability* current, OEMCrypto_HDCP_Capability* maximum) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_GetHDCPCapability_Request(request, current, maximum); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_GetHDCPCapability_Response(response, &result, ¤t, &maximum); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API bool OEMCrypto_SupportsUsageTable() { + bool result = false; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_SupportsUsageTable_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_SupportsUsageTable_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API bool OEMCrypto_IsAntiRollbackHwPresent() { + bool result = false; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_IsAntiRollbackHwPresent_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_IsAntiRollbackHwPresent_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetNumberOfOpenSessions(size_t* count) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_GetNumberOfOpenSessions_Request(request, count); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_GetNumberOfOpenSessions_Response(response, &result, &count); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(size_t* max) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_GetMaxNumberOfSessions_Request(request, max); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_GetMaxNumberOfSessions_Response(response, &result, &max); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API uint32_t OEMCrypto_SupportedCertificates() { + uint32_t result = 0; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_SupportedCertificates_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_SupportedCertificates_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API bool OEMCrypto_IsSRMUpdateSupported() { + bool result = false; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_IsSRMUpdateSupported_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_IsSRMUpdateSupported_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_GetCurrentSRMVersion(uint16_t* version) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_GetCurrentSRMVersion_Request(request, version); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_GetCurrentSRMVersion_Response(response, &result, &version); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API uint32_t OEMCrypto_GetAnalogOutputFlags() { + uint32_t result = 0; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_GetAnalogOutputFlags_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_GetAnalogOutputFlags_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API uint32_t OEMCrypto_ResourceRatingTier() { + uint32_t result = 0; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_ResourceRatingTier_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_ResourceRatingTier_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30( + OEMCrypto_SESSION session, const uint32_t* unaligned_nonce, + const SharedMemory* encrypted_message_key, + size_t encrypted_message_key_length, const SharedMemory* enc_rsa_key, + size_t enc_rsa_key_length, const uint8_t* enc_rsa_key_iv, + uint8_t* wrapped_rsa_key, size_t* wrapped_rsa_key_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_RewrapDeviceRSAKey30_Request( + request, session, unaligned_nonce, encrypted_message_key, + encrypted_message_key_length, enc_rsa_key, enc_rsa_key_length, + enc_rsa_key_iv, wrapped_rsa_key, wrapped_rsa_key_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_RewrapDeviceRSAKey30_Response(response, &result, &wrapped_rsa_key, + &wrapped_rsa_key_length); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey( + OEMCrypto_SESSION session, const SharedMemory* message, + size_t message_length, const SharedMemory* signature, + size_t signature_length, const uint32_t* unaligned_nonce, + const uint8_t* enc_rsa_key, size_t enc_rsa_key_length, + const uint8_t* enc_rsa_key_iv, uint8_t* wrapped_rsa_key, + size_t* wrapped_rsa_key_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_RewrapDeviceRSAKey_Request( + request, session, message, message_length, signature, signature_length, + unaligned_nonce, enc_rsa_key, enc_rsa_key_length, enc_rsa_key_iv, + wrapped_rsa_key, wrapped_rsa_key_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_RewrapDeviceRSAKey_Response(response, &result, &wrapped_rsa_key, + &wrapped_rsa_key_length); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadDeviceRSAKey( + OEMCrypto_SESSION session, const SharedMemory* wrapped_rsa_key, + size_t wrapped_rsa_key_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_LoadDeviceRSAKey_Request(request, session, wrapped_rsa_key, + wrapped_rsa_key_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_LoadDeviceRSAKey_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestRSAKey() { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_LoadTestRSAKey_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_LoadTestRSAKey_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateRSASignature( + OEMCrypto_SESSION session, const SharedMemory* message, + size_t message_length, uint8_t* signature, size_t* signature_length, + RSA_Padding_Scheme padding_scheme) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_GenerateRSASignature_Request(request, session, message, + message_length, signature, + signature_length, padding_scheme); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_GenerateRSASignature_Response(response, &result, &signature, + &signature_length); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_CreateUsageTableHeader( + uint8_t* header_buffer, size_t* header_buffer_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_CreateUsageTableHeader_Request(request, header_buffer, + header_buffer_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_CreateUsageTableHeader_Response(response, &result, &header_buffer, + &header_buffer_length); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_LoadUsageTableHeader(const uint8_t* buffer, size_t buffer_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_LoadUsageTableHeader_Request(request, buffer, buffer_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_LoadUsageTableHeader_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_CreateNewUsageEntry( + OEMCrypto_SESSION session, uint32_t* usage_entry_number) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_CreateNewUsageEntry_Request(request, session, usage_entry_number); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_CreateNewUsageEntry_Response(response, &result, + &usage_entry_number); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_LoadUsageEntry(OEMCrypto_SESSION session, uint32_t usage_entry_number, + const uint8_t* buffer, size_t buffer_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_LoadUsageEntry_Request(request, session, usage_entry_number, buffer, + buffer_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_LoadUsageEntry_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_UpdateUsageEntry( + OEMCrypto_SESSION session, SharedMemory* header_buffer, + size_t* header_buffer_length, SharedMemory* entry_buffer, + size_t* entry_buffer_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_UpdateUsageEntry_Request(request, session, header_buffer, + header_buffer_length, entry_buffer, + entry_buffer_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_UpdateUsageEntry_Response(response, &result, &header_buffer, + &header_buffer_length, &entry_buffer, + &entry_buffer_length); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_DeactivateUsageEntry( + OEMCrypto_SESSION session, const uint8_t* pst, size_t pst_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_DeactivateUsageEntry_Request(request, session, pst, pst_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_DeactivateUsageEntry_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session, + const uint8_t* pst, + size_t pst_length, + uint8_t* buffer, + size_t* buffer_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_ReportUsage_Request(request, session, pst, pst_length, buffer, + buffer_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_ReportUsage_Response(response, &result, &buffer, &buffer_length); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_DeleteUsageEntry( + OEMCrypto_SESSION session, const uint8_t* pst, size_t pst_length, + const uint8_t* message, size_t message_length, const uint8_t* signature, + size_t signature_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_DeleteUsageEntry_Request(request, session, pst, pst_length, message, + message_length, signature, + signature_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_DeleteUsageEntry_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_ForceDeleteUsageEntry(const uint8_t* pst, size_t pst_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_ForceDeleteUsageEntry_Request(request, pst, pst_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_ForceDeleteUsageEntry_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_MoveEntry(OEMCrypto_SESSION session, + uint32_t new_index) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_MoveEntry_Request(request, session, new_index); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_MoveEntry_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader( + uint32_t new_entry_count, uint8_t* header_buffer, + size_t* header_buffer_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_ShrinkUsageTableHeader_Request(request, new_entry_count, + header_buffer, header_buffer_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_ShrinkUsageTableHeader_Response(response, &result, &header_buffer, + &header_buffer_length); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_CopyOldUsageEntry( + OEMCrypto_SESSION session, const uint8_t* pst, size_t pst_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_CopyOldUsageEntry_Request(request, session, pst, pst_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_CopyOldUsageEntry_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_DeleteOldUsageTable() { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_DeleteOldUsageTable_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_DeleteOldUsageTable_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_RemoveSRM() { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_RemoveSRM_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_RemoveSRM_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_CreateOldUsageEntry( + uint64_t time_since_license_received, uint64_t time_since_first_decrypt, + uint64_t time_since_last_decrypt, OEMCrypto_Usage_Entry_Status status, + uint8_t* server_mac_key, uint8_t* client_mac_key, const uint8_t* pst, + size_t pst_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_CreateOldUsageEntry_Request( + request, time_since_license_received, time_since_first_decrypt, + time_since_last_decrypt, status, server_mac_key, client_mac_key, pst, + pst_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_CreateOldUsageEntry_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API uint32_t OEMCrypto_SupportsDecryptHash() { + uint32_t result = 0; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_SupportsDecryptHash_Request(request); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_SupportsDecryptHash_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_SetDecryptHash(OEMCrypto_SESSION session, uint32_t frame_number, + const uint8_t* hash, size_t hash_length) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_SetDecryptHash_Request(request, session, frame_number, hash, + hash_length); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_SetDecryptHash_Response(response, &result); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetHashErrorCode( + OEMCrypto_SESSION session, uint32_t* failed_frame_number) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message* request = API_InitializeRequest(); + Message* response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_GetHashErrorCode_Request(request, session, failed_frame_number); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_GetHashErrorCode_Response(response, &result, &failed_frame_number); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} diff --git a/serialization/generated_src/serializer.c b/serialization/generated_src/serializer.c new file mode 100644 index 0000000..73d4a1a --- /dev/null +++ b/serialization/generated_src/serializer.c @@ -0,0 +1,1495 @@ +/* + * 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. + */ + +/* + * This code is auto-generated, do not edit + */ + +#include "serializer.h" + +#include + +#include "deserializer.h" +#include "marshaller_base.h" +#include "serialization_base.h" +#include "shared_memory_allocator.h" +#include "special_cases.h" + +bool SuccessResult(OEMCryptoResult result) { + switch (result) { + case OEMCrypto_SUCCESS: + case OEMCrypto_WARNING_GENERATION_SKEW: + case OEMCrypto_LOCAL_DISPLAY_ONLY: + return true; + default: + return false; + } +} +void ODK_Pack_OEMCrypto_Substring(Message* msg, + OEMCrypto_Substring const* obj) { + ODK_Pack_size_t(msg, (const size_t*)&obj->offset); + ODK_Pack_size_t(msg, (const size_t*)&obj->length); +} + +void ODK_Pack_OEMCrypto_KeyObject(Message* msg, + OEMCrypto_KeyObject const* obj) { + ODK_Pack_OEMCrypto_Substring(msg, (const OEMCrypto_Substring*)&obj->key_id); + ODK_Pack_OEMCrypto_Substring(msg, + (const OEMCrypto_Substring*)&obj->key_data_iv); + ODK_Pack_OEMCrypto_Substring(msg, (const OEMCrypto_Substring*)&obj->key_data); + ODK_Pack_OEMCrypto_Substring( + msg, (const OEMCrypto_Substring*)&obj->key_control_iv); + ODK_Pack_OEMCrypto_Substring(msg, + (const OEMCrypto_Substring*)&obj->key_control); +} + +void ODK_Pack_OEMCrypto_EntitledContentKeyObject( + Message* msg, OEMCrypto_EntitledContentKeyObject const* obj) { + ODK_Pack_OEMCrypto_Substring( + msg, (const OEMCrypto_Substring*)&obj->entitlement_key_id); + ODK_Pack_OEMCrypto_Substring( + msg, (const OEMCrypto_Substring*)&obj->content_key_id); + ODK_Pack_OEMCrypto_Substring( + msg, (const OEMCrypto_Substring*)&obj->content_key_data_iv); + ODK_Pack_OEMCrypto_Substring( + msg, (const OEMCrypto_Substring*)&obj->content_key_data); +} + +void ODK_Pack_OEMCrypto_KeyRefreshObject( + Message* msg, OEMCrypto_KeyRefreshObject const* obj) { + ODK_Pack_OEMCrypto_Substring(msg, (const OEMCrypto_Substring*)&obj->key_id); + ODK_Pack_OEMCrypto_Substring( + msg, (const OEMCrypto_Substring*)&obj->key_control_iv); + ODK_Pack_OEMCrypto_Substring(msg, + (const OEMCrypto_Substring*)&obj->key_control); +} + +void ODK_Pack_OEMCrypto_CENCEncryptPatternDesc( + Message* msg, OEMCrypto_CENCEncryptPatternDesc const* obj) { + ODK_Pack_size_t(msg, (const size_t*)&obj->encrypt); + ODK_Pack_size_t(msg, (const size_t*)&obj->skip); + ODK_Pack_size_t(msg, (const size_t*)&obj->offset); +} + +void ODK_Pack_SecurityLevel_Request(Message* msg) { + uint32_t api_value = 23; /* from _oecc23 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_SecurityLevel_Response(Message* msg, const char* result) { + uint32_t api_value = 23; /* from _oecc23 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_c_str(msg, result); + ODK_PackEOM(msg); +} + +void ODK_Pack_BuildInformation_Request(Message* msg) { + uint32_t api_value = 90; /* from _oecc90 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_BuildInformation_Response(Message* msg, const char* result) { + uint32_t api_value = 90; /* from _oecc90 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_c_str(msg, result); + ODK_PackEOM(msg); +} + +void ODK_Pack_SetSandbox_Request(Message* msg, const uint8_t* sandbox_id, + size_t sandbox_id_length) { + uint32_t api_value = 84; /* from _oecc84 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &sandbox_id_length); + ODK_PackMemory(msg, sandbox_id, LengthFromSizeT(sandbox_id_length)); + ODK_PackEOM(msg); +} + +void ODK_Pack_SetSandbox_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 84; /* from _oecc84 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_Initialize_Request(Message* msg) { + uint32_t api_value = 1; /* from _oecc1 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_Initialize_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 1; /* from _oecc1 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_Terminate_Request(Message* msg) { + uint32_t api_value = 2; /* from _oecc2 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_Terminate_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 2; /* from _oecc2 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_OpenSession_Request(Message* msg, + const OEMCrypto_SESSION* session) { + uint32_t api_value = 9; /* from _oecc9 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackIsNull(msg, session); + ODK_PackEOM(msg); +} + +void ODK_Pack_OpenSession_Response(Message* msg, OEMCryptoResult result, + const OEMCrypto_SESSION* session) { + uint32_t api_value = 9; /* from _oecc9 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackNullable_uint32_t(msg, session); + ODK_PackEOM(msg); +} + +void ODK_Pack_CloseSession_Request(Message* msg, OEMCrypto_SESSION session) { + uint32_t api_value = 10; /* from _oecc10 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &session); + ODK_PackEOM(msg); +} + +void ODK_Pack_CloseSession_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 10; /* from _oecc10 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_GenerateDerivedKeys_Request(Message* msg, + OEMCrypto_SESSION session, + const SharedMemory* mac_key_context, + uint32_t mac_key_context_length, + const SharedMemory* enc_key_context, + uint32_t enc_key_context_length) { + uint32_t api_value = 12; /* from _oecc12 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &mac_key_context_length); + ODK_Pack_uint32_t(msg, &enc_key_context_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackSharedInputBuffer(msg, 0, mac_key_context, + LengthFromUint32T(mac_key_context_length)); + ODK_PackSharedInputBuffer(msg, 1, enc_key_context, + LengthFromUint32T(enc_key_context_length)); + ODK_PackEOM(msg); +} + +void ODK_Pack_GenerateDerivedKeys_Response(Message* msg, + OEMCryptoResult result) { + uint32_t api_value = 12; /* from _oecc12 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_DeriveKeysFromSessionKey_Request( + Message* msg, OEMCrypto_SESSION session, const uint8_t* enc_session_key, + size_t enc_session_key_length, const SharedMemory* mac_key_context, + size_t mac_key_context_length, const SharedMemory* enc_key_context, + size_t enc_key_context_length) { + uint32_t api_value = 21; /* from _oecc21 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &enc_session_key_length); + ODK_Pack_size_t(msg, &mac_key_context_length); + ODK_Pack_size_t(msg, &enc_key_context_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackMemory(msg, enc_session_key, LengthFromSizeT(enc_session_key_length)); + ODK_PackSharedInputBuffer(msg, 0, mac_key_context, + LengthFromSizeT(mac_key_context_length)); + ODK_PackSharedInputBuffer(msg, 1, enc_key_context, + LengthFromSizeT(enc_key_context_length)); + ODK_PackEOM(msg); +} + +void ODK_Pack_DeriveKeysFromSessionKey_Response(Message* msg, + OEMCryptoResult result) { + uint32_t api_value = 21; /* from _oecc21 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_GenerateNonce_Request(Message* msg, OEMCrypto_SESSION session, + const uint32_t* nonce) { + uint32_t api_value = 14; /* from _oecc14 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &session); + ODK_PackIsNull(msg, nonce); + ODK_PackEOM(msg); +} + +void ODK_Pack_GenerateNonce_Response(Message* msg, OEMCryptoResult result, + const uint32_t* nonce) { + uint32_t api_value = 14; /* from _oecc14 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackNullable_uint32_t(msg, nonce); + ODK_PackEOM(msg); +} + +void ODK_Pack_GenerateSignature_Request(Message* msg, OEMCrypto_SESSION session, + const SharedMemory* message, + size_t message_length, + const uint8_t* signature, + const size_t* signature_length) { + uint32_t api_value = 13; /* from _oecc13 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &message_length); + ODK_PackNullable_size_t(msg, signature_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackSharedInputBuffer(msg, 0, message, LengthFromSizeT(message_length)); + ODK_PackAlloc(msg, signature); + ODK_PackEOM(msg); +} + +void ODK_Pack_GenerateSignature_Response(Message* msg, OEMCryptoResult result, + const uint8_t* signature, + const size_t* signature_length) { + uint32_t api_value = 13; /* from _oecc13 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, signature_length); + ODK_Pack_uint32_t(msg, &result); + if (SuccessResult(result)) { + ODK_PackMemory(msg, signature, LengthFromSizeTPointer(signature_length)); + } + ODK_PackEOM(msg); +} + +void ODK_Pack_LoadSRM_Request(Message* msg, const uint8_t* buffer, + size_t buffer_length) { + uint32_t api_value = 55; /* from _oecc55 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &buffer_length); + ODK_PackMemory(msg, buffer, LengthFromSizeT(buffer_length)); + ODK_PackEOM(msg); +} + +void ODK_Pack_LoadSRM_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 55; /* from _oecc55 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_LoadKeys_Request( + Message* msg, OEMCrypto_SESSION session, const SharedMemory* message, + size_t message_length, const SharedMemory* signature, + size_t signature_length, OEMCrypto_Substring enc_mac_keys_iv, + OEMCrypto_Substring enc_mac_keys, size_t key_array_length, + const OEMCrypto_KeyObject* key_array, OEMCrypto_Substring pst, + OEMCrypto_Substring srm_restriction_data, + OEMCrypto_LicenseType license_type) { + uint32_t api_value = 83; /* from _oecc83 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &message_length); + ODK_Pack_size_t(msg, &signature_length); + ODK_Pack_size_t(msg, &key_array_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackSharedInputBuffer(msg, 0, message, LengthFromSizeT(message_length)); + ODK_PackSharedInputBuffer(msg, 1, signature, + LengthFromSizeT(signature_length)); + ODK_Pack_OEMCrypto_Substring(msg, &enc_mac_keys_iv); + ODK_Pack_OEMCrypto_Substring(msg, &enc_mac_keys); + ODK_PackObjArray(msg, (uint8_t*)key_array, LengthFromSizeT(key_array_length), + sizeof(OEMCrypto_KeyObject), + (ObjPacker)&ODK_Pack_OEMCrypto_KeyObject); + ODK_Pack_OEMCrypto_Substring(msg, &pst); + ODK_Pack_OEMCrypto_Substring(msg, &srm_restriction_data); + ODK_Pack_uint32_t(msg, &license_type); + ODK_PackEOM(msg); +} + +void ODK_Pack_LoadKeys_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 83; /* from _oecc83 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_LoadEntitledContentKeys_Request( + Message* msg, OEMCrypto_SESSION session, const SharedMemory* message, + size_t message_length, size_t key_array_length, + const OEMCrypto_EntitledContentKeyObject* key_array) { + uint32_t api_value = 92; /* from _oecc92 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &message_length); + ODK_Pack_size_t(msg, &key_array_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackSharedInputBuffer(msg, 0, message, LengthFromSizeT(message_length)); + ODK_PackObjArray(msg, (uint8_t*)key_array, LengthFromSizeT(key_array_length), + sizeof(OEMCrypto_EntitledContentKeyObject), + (ObjPacker)&ODK_Pack_OEMCrypto_EntitledContentKeyObject); + ODK_PackEOM(msg); +} + +void ODK_Pack_LoadEntitledContentKeys_Response(Message* msg, + OEMCryptoResult result) { + uint32_t api_value = 92; /* from _oecc92 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_RefreshKeys_Request(Message* msg, OEMCrypto_SESSION session, + const SharedMemory* message, + size_t message_length, + const SharedMemory* signature, + size_t signature_length, + size_t key_array_length, + const OEMCrypto_KeyRefreshObject* key_array) { + uint32_t api_value = 91; /* from _oecc91 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &message_length); + ODK_Pack_size_t(msg, &signature_length); + ODK_Pack_size_t(msg, &key_array_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackSharedInputBuffer(msg, 0, message, LengthFromSizeT(message_length)); + ODK_PackSharedInputBuffer(msg, 1, signature, + LengthFromSizeT(signature_length)); + ODK_PackObjArray(msg, (uint8_t*)key_array, LengthFromSizeT(key_array_length), + sizeof(OEMCrypto_KeyRefreshObject), + (ObjPacker)&ODK_Pack_OEMCrypto_KeyRefreshObject); + ODK_PackEOM(msg); +} + +void ODK_Pack_RefreshKeys_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 91; /* from _oecc91 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_QueryKeyControl_Request(Message* msg, OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + const uint8_t* key_control_block, + const size_t* key_control_block_length) { + uint32_t api_value = 41; /* from _oecc41 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &content_key_id_length); + ODK_PackNullable_size_t(msg, key_control_block_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackMemory(msg, content_key_id, LengthFromSizeT(content_key_id_length)); + ODK_PackAlloc(msg, key_control_block); + ODK_PackEOM(msg); +} + +void ODK_Pack_QueryKeyControl_Response(Message* msg, OEMCryptoResult result, + const uint8_t* key_control_block, + const size_t* key_control_block_length) { + uint32_t api_value = 41; /* from _oecc41 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, key_control_block_length); + ODK_Pack_uint32_t(msg, &result); + if (SuccessResult(result)) { + ODK_PackMemory(msg, key_control_block, + LengthFromSizeTPointer(key_control_block_length)); + } + ODK_PackEOM(msg); +} + +void ODK_Pack_SelectKey_Request(Message* msg, OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + OEMCryptoCipherMode cipher_mode) { + uint32_t api_value = 81; /* from _oecc81 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &content_key_id_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackMemory(msg, content_key_id, LengthFromSizeT(content_key_id_length)); + ODK_Pack_uint32_t(msg, &cipher_mode); + ODK_PackEOM(msg); +} + +void ODK_Pack_SelectKey_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 81; /* from _oecc81 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_DecryptCENC_Request( + Message* msg, OEMCrypto_SESSION session, const SharedMemory* data_addr, + size_t data_addr_length, bool is_encrypted, const uint8_t* iv, + size_t block_offset, const OEMCrypto_DestBufferDesc* out_buffer, + const OEMCrypto_CENCEncryptPatternDesc* pattern, uint8_t subsample_flags) { + uint32_t api_value = 48; /* from _oecc48 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &data_addr_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackSharedInputBuffer(msg, 0, data_addr, + LengthFromSizeT(data_addr_length)); + ODK_Pack_bool(msg, &is_encrypted); + ODK_PackArray(msg, &iv[0], 16); + ODK_Pack_size_t(msg, &block_offset); + ODK_PackNullable_OEMCrypto_DestBufferDesc(msg, out_buffer); + ODK_PackNullable_OEMCrypto_CENCEncryptPatternDesc(msg, pattern); + ODK_Pack_uint8_t(msg, &subsample_flags); + ODK_PackEOM(msg); +} + +void ODK_Pack_DecryptCENC_Response(Message* msg, OEMCryptoResult result, + const OEMCrypto_DestBufferDesc* out_buffer) { + uint32_t api_value = 48; /* from _oecc48 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackNullable_OEMCrypto_DestBufferDesc(msg, out_buffer); + ODK_PackEOM(msg); +} + +void ODK_Pack_CopyBuffer_Request(Message* msg, OEMCrypto_SESSION session, + const SharedMemory* data_addr, + size_t data_addr_length, + const OEMCrypto_DestBufferDesc* out_buffer, + uint8_t subsample_flags) { + uint32_t api_value = 93; /* from _oecc93 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &data_addr_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackSharedInputBuffer(msg, 0, data_addr, + LengthFromSizeT(data_addr_length)); + ODK_PackNullable_OEMCrypto_DestBufferDesc(msg, out_buffer); + ODK_Pack_uint8_t(msg, &subsample_flags); + ODK_PackEOM(msg); +} + +void ODK_Pack_CopyBuffer_Response(Message* msg, OEMCryptoResult result, + const OEMCrypto_DestBufferDesc* out_buffer) { + uint32_t api_value = 93; /* from _oecc93 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackNullable_OEMCrypto_DestBufferDesc(msg, out_buffer); + ODK_PackEOM(msg); +} + +void ODK_Pack_Generic_Encrypt_Request(Message* msg, OEMCrypto_SESSION session, + const SharedMemory* in_buffer, + size_t in_buffer_length, + const uint8_t* iv, + OEMCrypto_Algorithm algorithm, + const uint8_t* out_buffer) { + uint32_t api_value = 24; /* from _oecc24 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &in_buffer_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackSharedInputBuffer(msg, 0, in_buffer, + LengthFromSizeT(in_buffer_length)); + ODK_PackArray(msg, &iv[0], 16); + ODK_Pack_uint32_t(msg, &algorithm); + ODK_PackAlloc(msg, out_buffer); + ODK_PackEOM(msg); +} + +void ODK_Pack_Generic_Encrypt_Response(Message* msg, OEMCryptoResult result, + size_t in_buffer_length, + const uint8_t* out_buffer) { + uint32_t api_value = 24; /* from _oecc24 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &in_buffer_length); + ODK_Pack_uint32_t(msg, &result); + if (SuccessResult(result)) { + ODK_PackMemory(msg, out_buffer, LengthFromSizeT(in_buffer_length)); + } + ODK_PackEOM(msg); +} + +void ODK_Pack_Generic_Decrypt_Request(Message* msg, OEMCrypto_SESSION session, + const SharedMemory* in_buffer, + size_t in_buffer_length, + const uint8_t* iv, + OEMCrypto_Algorithm algorithm, + const uint8_t* out_buffer) { + uint32_t api_value = 25; /* from _oecc25 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &in_buffer_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackSharedInputBuffer(msg, 0, in_buffer, + LengthFromSizeT(in_buffer_length)); + ODK_PackArray(msg, &iv[0], 16); + ODK_Pack_uint32_t(msg, &algorithm); + ODK_PackAlloc(msg, out_buffer); + ODK_PackEOM(msg); +} + +void ODK_Pack_Generic_Decrypt_Response(Message* msg, OEMCryptoResult result, + size_t in_buffer_length, + const uint8_t* out_buffer) { + uint32_t api_value = 25; /* from _oecc25 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &in_buffer_length); + ODK_Pack_uint32_t(msg, &result); + if (SuccessResult(result)) { + ODK_PackMemory(msg, out_buffer, LengthFromSizeT(in_buffer_length)); + } + ODK_PackEOM(msg); +} + +void ODK_Pack_Generic_Sign_Request(Message* msg, OEMCrypto_SESSION session, + const SharedMemory* buffer, + size_t buffer_length, + OEMCrypto_Algorithm algorithm, + const uint8_t* signature, + const size_t* signature_length) { + uint32_t api_value = 26; /* from _oecc26 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &buffer_length); + ODK_PackNullable_size_t(msg, signature_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackSharedInputBuffer(msg, 0, buffer, LengthFromSizeT(buffer_length)); + ODK_Pack_uint32_t(msg, &algorithm); + ODK_PackAlloc(msg, signature); + ODK_PackEOM(msg); +} + +void ODK_Pack_Generic_Sign_Response(Message* msg, OEMCryptoResult result, + const uint8_t* signature, + const size_t* signature_length) { + uint32_t api_value = 26; /* from _oecc26 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, signature_length); + ODK_Pack_uint32_t(msg, &result); + if (SuccessResult(result)) { + ODK_PackMemory(msg, signature, LengthFromSizeTPointer(signature_length)); + } + ODK_PackEOM(msg); +} + +void ODK_Pack_Generic_Verify_Request(Message* msg, OEMCrypto_SESSION session, + const SharedMemory* buffer, + size_t buffer_length, + OEMCrypto_Algorithm algorithm, + const SharedMemory* signature, + size_t signature_length) { + uint32_t api_value = 27; /* from _oecc27 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &buffer_length); + ODK_Pack_size_t(msg, &signature_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackSharedInputBuffer(msg, 0, buffer, LengthFromSizeT(buffer_length)); + ODK_Pack_uint32_t(msg, &algorithm); + ODK_PackSharedInputBuffer(msg, 1, signature, + LengthFromSizeT(signature_length)); + ODK_PackEOM(msg); +} + +void ODK_Pack_Generic_Verify_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 27; /* from _oecc27 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_UpdateUsageTable_Request(Message* msg) { + uint32_t api_value = 30; /* from _oecc30 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_UpdateUsageTable_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 30; /* from _oecc30 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_WrapKeyboxOrOEMCert_Request(Message* msg, const uint8_t* rot, + size_t rotLength, + const uint8_t* wrappedRot, + const size_t* wrappedRotLength, + const uint8_t* transportKey, + size_t transportKeyLength) { + uint32_t api_value = 8; /* from _oecc8 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &rotLength); + ODK_PackIsNull(msg, wrappedRotLength); + ODK_Pack_size_t(msg, &transportKeyLength); + ODK_PackMemory(msg, rot, LengthFromSizeT(rotLength)); + ODK_PackAlloc(msg, wrappedRot); + ODK_PackMemory(msg, transportKey, LengthFromSizeT(transportKeyLength)); + ODK_PackEOM(msg); +} + +void ODK_Pack_WrapKeyboxOrOEMCert_Response(Message* msg, OEMCryptoResult result, + const uint8_t* wrappedRot, + const size_t* wrappedRotLength) { + uint32_t api_value = 8; /* from _oecc8 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, wrappedRotLength); + ODK_Pack_uint32_t(msg, &result); + if (SuccessResult(result)) { + ODK_PackMemory(msg, wrappedRot, LengthFromSizeTPointer(wrappedRotLength)); + } + ODK_PackEOM(msg); +} + +void ODK_Pack_InstallKeyboxOrOEMCert_Request(Message* msg, const uint8_t* rot, + size_t rotLength) { + uint32_t api_value = 3; /* from _oecc3 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &rotLength); + ODK_PackMemory(msg, rot, LengthFromSizeT(rotLength)); + ODK_PackEOM(msg); +} + +void ODK_Pack_InstallKeyboxOrOEMCert_Response(Message* msg, + OEMCryptoResult result) { + uint32_t api_value = 3; /* from _oecc3 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetProvisioningMethod_Request(Message* msg) { + uint32_t api_value = 49; /* from _oecc49 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetProvisioningMethod_Response( + Message* msg, OEMCrypto_ProvisioningMethod result) { + uint32_t api_value = 49; /* from _oecc49 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_IsKeyboxOrOEMCertValid_Request(Message* msg) { + uint32_t api_value = 5; /* from _oecc5 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_IsKeyboxOrOEMCertValid_Response(Message* msg, + OEMCryptoResult result) { + uint32_t api_value = 5; /* from _oecc5 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetDeviceID_Request(Message* msg, const uint8_t* device_id, + const size_t* device_id_length) { + uint32_t api_value = 7; /* from _oecc7 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, device_id_length); + ODK_PackAlloc(msg, device_id); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetDeviceID_Response(Message* msg, OEMCryptoResult result, + const uint8_t* device_id, + const size_t* device_id_length) { + uint32_t api_value = 7; /* from _oecc7 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, device_id_length); + ODK_Pack_uint32_t(msg, &result); + if (SuccessResult(result)) { + ODK_PackMemory(msg, device_id, LengthFromSizeTPointer(device_id_length)); + } + ODK_PackEOM(msg); +} + +void ODK_Pack_GetKeyData_Request(Message* msg, const uint8_t* keyData, + const size_t* keyDataLength) { + uint32_t api_value = 4; /* from _oecc4 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, keyDataLength); + ODK_PackAlloc(msg, keyData); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetKeyData_Response(Message* msg, OEMCryptoResult result, + const uint8_t* keyData, + const size_t* keyDataLength) { + uint32_t api_value = 4; /* from _oecc4 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, keyDataLength); + ODK_Pack_uint32_t(msg, &result); + if (SuccessResult(result)) { + ODK_PackMemory(msg, keyData, LengthFromSizeTPointer(keyDataLength)); + } + ODK_PackEOM(msg); +} + +void ODK_Pack_LoadTestKeybox_Request(Message* msg, const uint8_t* buffer, + size_t buffer_length) { + uint32_t api_value = 78; /* from _oecc78 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &buffer_length); + ODK_PackMemory(msg, buffer, LengthFromSizeT(buffer_length)); + ODK_PackEOM(msg); +} + +void ODK_Pack_LoadTestKeybox_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 78; /* from _oecc78 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetOEMPublicCertificate_Request( + Message* msg, OEMCrypto_SESSION session, const uint8_t* public_cert, + const size_t* public_cert_length) { + uint32_t api_value = 50; /* from _oecc50 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, public_cert_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackAlloc(msg, public_cert); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetOEMPublicCertificate_Response( + Message* msg, OEMCryptoResult result, const uint8_t* public_cert, + const size_t* public_cert_length) { + uint32_t api_value = 50; /* from _oecc50 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, public_cert_length); + ODK_Pack_uint32_t(msg, &result); + if (SuccessResult(result)) { + ODK_PackMemory(msg, public_cert, + LengthFromSizeTPointer(public_cert_length)); + } + ODK_PackEOM(msg); +} + +void ODK_Pack_GetRandom_Request(Message* msg, const uint8_t* random_data, + size_t random_data_length) { + uint32_t api_value = 6; /* from _oecc6 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &random_data_length); + ODK_PackAlloc(msg, random_data); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetRandom_Response(Message* msg, OEMCryptoResult result, + const uint8_t* random_data, + size_t random_data_length) { + uint32_t api_value = 6; /* from _oecc6 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &random_data_length); + ODK_Pack_uint32_t(msg, &result); + if (SuccessResult(result)) { + ODK_PackMemory(msg, random_data, LengthFromSizeT(random_data_length)); + } + ODK_PackEOM(msg); +} + +void ODK_Pack_APIVersion_Request(Message* msg) { + uint32_t api_value = 22; /* from _oecc22 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_APIVersion_Response(Message* msg, uint32_t result) { + uint32_t api_value = 22; /* from _oecc22 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_Security_Patch_Level_Request(Message* msg) { + uint32_t api_value = 46; /* from _oecc46 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_Security_Patch_Level_Response(Message* msg, uint8_t result) { + uint32_t api_value = 46; /* from _oecc46 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint8_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetHDCPCapability_Request( + Message* msg, const OEMCrypto_HDCP_Capability* current, + const OEMCrypto_HDCP_Capability* maximum) { + uint32_t api_value = 44; /* from _oecc44 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackIsNull(msg, current); + ODK_PackIsNull(msg, maximum); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetHDCPCapability_Response( + Message* msg, OEMCryptoResult result, + const OEMCrypto_HDCP_Capability* current, + const OEMCrypto_HDCP_Capability* maximum) { + uint32_t api_value = 44; /* from _oecc44 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackNullable_uint32_t(msg, current); + ODK_PackNullable_uint32_t(msg, maximum); + ODK_PackEOM(msg); +} + +void ODK_Pack_SupportsUsageTable_Request(Message* msg) { + uint32_t api_value = 29; /* from _oecc29 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_SupportsUsageTable_Response(Message* msg, bool result) { + uint32_t api_value = 29; /* from _oecc29 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_bool(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_IsAntiRollbackHwPresent_Request(Message* msg) { + uint32_t api_value = 39; /* from _oecc39 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_IsAntiRollbackHwPresent_Response(Message* msg, bool result) { + uint32_t api_value = 39; /* from _oecc39 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_bool(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetNumberOfOpenSessions_Request(Message* msg, + const size_t* count) { + uint32_t api_value = 38; /* from _oecc38 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackIsNull(msg, count); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetNumberOfOpenSessions_Response(Message* msg, + OEMCryptoResult result, + const size_t* count) { + uint32_t api_value = 38; /* from _oecc38 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackNullable_size_t(msg, count); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetMaxNumberOfSessions_Request(Message* msg, const size_t* max) { + uint32_t api_value = 37; /* from _oecc37 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackIsNull(msg, max); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetMaxNumberOfSessions_Response(Message* msg, + OEMCryptoResult result, + const size_t* max) { + uint32_t api_value = 37; /* from _oecc37 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackNullable_size_t(msg, max); + ODK_PackEOM(msg); +} + +void ODK_Pack_SupportedCertificates_Request(Message* msg) { + uint32_t api_value = 52; /* from _oecc52 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_SupportedCertificates_Response(Message* msg, uint32_t result) { + uint32_t api_value = 52; /* from _oecc52 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_IsSRMUpdateSupported_Request(Message* msg) { + uint32_t api_value = 53; /* from _oecc53 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_IsSRMUpdateSupported_Response(Message* msg, bool result) { + uint32_t api_value = 53; /* from _oecc53 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_bool(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetCurrentSRMVersion_Request(Message* msg, + const uint16_t* version) { + uint32_t api_value = 54; /* from _oecc54 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackIsNull(msg, version); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetCurrentSRMVersion_Response(Message* msg, + OEMCryptoResult result, + const uint16_t* version) { + uint32_t api_value = 54; /* from _oecc54 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackNullable_uint16_t(msg, version); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetAnalogOutputFlags_Request(Message* msg) { + uint32_t api_value = 71; /* from _oecc71 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetAnalogOutputFlags_Response(Message* msg, uint32_t result) { + uint32_t api_value = 71; /* from _oecc71 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_ResourceRatingTier_Request(Message* msg) { + uint32_t api_value = 85; /* from _oecc85 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_ResourceRatingTier_Response(Message* msg, uint32_t result) { + uint32_t api_value = 85; /* from _oecc85 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_RewrapDeviceRSAKey30_Request( + Message* msg, OEMCrypto_SESSION session, const uint32_t* unaligned_nonce, + const SharedMemory* encrypted_message_key, + size_t encrypted_message_key_length, const SharedMemory* enc_rsa_key, + size_t enc_rsa_key_length, const uint8_t* enc_rsa_key_iv, + const uint8_t* wrapped_rsa_key, const size_t* wrapped_rsa_key_length) { + uint32_t api_value = 51; /* from _oecc51 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &encrypted_message_key_length); + ODK_Pack_size_t(msg, &enc_rsa_key_length); + ODK_PackNullable_size_t(msg, wrapped_rsa_key_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackNullable_uint32_t(msg, unaligned_nonce); + ODK_PackSharedInputBuffer(msg, 0, encrypted_message_key, + LengthFromSizeT(encrypted_message_key_length)); + ODK_PackSharedInputBuffer(msg, 1, enc_rsa_key, + LengthFromSizeT(enc_rsa_key_length)); + ODK_PackNullable_uint8_t(msg, enc_rsa_key_iv); + ODK_PackAlloc(msg, wrapped_rsa_key); + ODK_PackEOM(msg); +} + +void ODK_Pack_RewrapDeviceRSAKey30_Response( + Message* msg, OEMCryptoResult result, const uint8_t* wrapped_rsa_key, + const size_t* wrapped_rsa_key_length) { + uint32_t api_value = 51; /* from _oecc51 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, wrapped_rsa_key_length); + ODK_Pack_uint32_t(msg, &result); + if (SuccessResult(result)) { + ODK_PackMemory(msg, wrapped_rsa_key, + LengthFromSizeTPointer(wrapped_rsa_key_length)); + } + ODK_PackEOM(msg); +} + +void ODK_Pack_RewrapDeviceRSAKey_Response( + Message* msg, OEMCryptoResult result, const uint8_t* wrapped_rsa_key, + const size_t* wrapped_rsa_key_length) { + uint32_t api_value = 18; /* from _oecc18 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, wrapped_rsa_key_length); + ODK_Pack_uint32_t(msg, &result); + if (SuccessResult(result)) { + ODK_PackMemory(msg, wrapped_rsa_key, + LengthFromSizeTPointer(wrapped_rsa_key_length)); + } + ODK_PackEOM(msg); +} + +void ODK_Pack_LoadDeviceRSAKey_Request(Message* msg, OEMCrypto_SESSION session, + const SharedMemory* wrapped_rsa_key, + size_t wrapped_rsa_key_length) { + uint32_t api_value = 19; /* from _oecc19 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &wrapped_rsa_key_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackSharedInputBuffer(msg, 0, wrapped_rsa_key, + LengthFromSizeT(wrapped_rsa_key_length)); + ODK_PackEOM(msg); +} + +void ODK_Pack_LoadDeviceRSAKey_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 19; /* from _oecc19 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_LoadTestRSAKey_Request(Message* msg) { + uint32_t api_value = 45; /* from _oecc45 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_LoadTestRSAKey_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 45; /* from _oecc45 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_GenerateRSASignature_Request( + Message* msg, OEMCrypto_SESSION session, const SharedMemory* message, + size_t message_length, const uint8_t* signature, + const size_t* signature_length, RSA_Padding_Scheme padding_scheme) { + uint32_t api_value = 36; /* from _oecc36 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &message_length); + ODK_PackNullable_size_t(msg, signature_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackSharedInputBuffer(msg, 0, message, LengthFromSizeT(message_length)); + ODK_PackAlloc(msg, signature); + ODK_Pack_uint8_t(msg, &padding_scheme); + ODK_PackEOM(msg); +} + +void ODK_Pack_GenerateRSASignature_Response(Message* msg, + OEMCryptoResult result, + const uint8_t* signature, + const size_t* signature_length) { + uint32_t api_value = 36; /* from _oecc36 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, signature_length); + ODK_Pack_uint32_t(msg, &result); + if (SuccessResult(result)) { + ODK_PackMemory(msg, signature, LengthFromSizeTPointer(signature_length)); + } + ODK_PackEOM(msg); +} + +void ODK_Pack_CreateUsageTableHeader_Request( + Message* msg, const uint8_t* header_buffer, + const size_t* header_buffer_length) { + uint32_t api_value = 61; /* from _oecc61 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, header_buffer_length); + ODK_PackAlloc(msg, header_buffer); + ODK_PackEOM(msg); +} + +void ODK_Pack_CreateUsageTableHeader_Response( + Message* msg, OEMCryptoResult result, const uint8_t* header_buffer, + const size_t* header_buffer_length) { + uint32_t api_value = 61; /* from _oecc61 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, header_buffer_length); + ODK_Pack_uint32_t(msg, &result); + if (SuccessResult(result)) { + ODK_PackMemory(msg, header_buffer, + LengthFromSizeTPointer(header_buffer_length)); + } + ODK_PackEOM(msg); +} + +void ODK_Pack_LoadUsageTableHeader_Request(Message* msg, const uint8_t* buffer, + size_t buffer_length) { + uint32_t api_value = 62; /* from _oecc62 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &buffer_length); + ODK_PackMemory(msg, buffer, LengthFromSizeT(buffer_length)); + ODK_PackEOM(msg); +} + +void ODK_Pack_LoadUsageTableHeader_Response(Message* msg, + OEMCryptoResult result) { + uint32_t api_value = 62; /* from _oecc62 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_CreateNewUsageEntry_Request(Message* msg, + OEMCrypto_SESSION session, + const uint32_t* usage_entry_number) { + uint32_t api_value = 63; /* from _oecc63 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &session); + ODK_PackIsNull(msg, usage_entry_number); + ODK_PackEOM(msg); +} + +void ODK_Pack_CreateNewUsageEntry_Response(Message* msg, OEMCryptoResult result, + const uint32_t* usage_entry_number) { + uint32_t api_value = 63; /* from _oecc63 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackNullable_uint32_t(msg, usage_entry_number); + ODK_PackEOM(msg); +} + +void ODK_Pack_LoadUsageEntry_Request(Message* msg, OEMCrypto_SESSION session, + uint32_t usage_entry_number, + const uint8_t* buffer, + size_t buffer_length) { + uint32_t api_value = 64; /* from _oecc64 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &buffer_length); + ODK_Pack_uint32_t(msg, &session); + ODK_Pack_uint32_t(msg, &usage_entry_number); + ODK_PackMemory(msg, buffer, LengthFromSizeT(buffer_length)); + ODK_PackEOM(msg); +} + +void ODK_Pack_LoadUsageEntry_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 64; /* from _oecc64 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_UpdateUsageEntry_Request(Message* msg, OEMCrypto_SESSION session, + const SharedMemory* header_buffer, + const size_t* header_buffer_length, + const SharedMemory* entry_buffer, + const size_t* entry_buffer_length) { + uint32_t api_value = 65; /* from _oecc65 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, header_buffer_length); + ODK_PackNullable_size_t(msg, entry_buffer_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackSharedOutputBuffer(msg, header_buffer, + LengthFromSizeTPointer(header_buffer_length)); + ODK_PackSharedOutputBuffer(msg, entry_buffer, + LengthFromSizeTPointer(entry_buffer_length)); + ODK_PackEOM(msg); +} + +void ODK_Pack_UpdateUsageEntry_Response(Message* msg, OEMCryptoResult result, + const SharedMemory* header_buffer, + const size_t* header_buffer_length, + const SharedMemory* entry_buffer, + const size_t* entry_buffer_length) { + uint32_t api_value = 65; /* from _oecc65 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, header_buffer_length); + ODK_PackNullable_size_t(msg, entry_buffer_length); + ODK_Pack_uint32_t(msg, &result); + if (SuccessResult(result)) { + ODK_PackSharedOutputBuffer(msg, header_buffer, + LengthFromSizeTPointer(header_buffer_length)); + } + if (SuccessResult(result)) { + ODK_PackSharedOutputBuffer(msg, entry_buffer, + LengthFromSizeTPointer(entry_buffer_length)); + } + ODK_PackEOM(msg); +} + +void ODK_Pack_DeactivateUsageEntry_Request(Message* msg, + OEMCrypto_SESSION session, + const uint8_t* pst, + size_t pst_length) { + uint32_t api_value = 66; /* from _oecc66 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &pst_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackMemory(msg, pst, LengthFromSizeT(pst_length)); + ODK_PackEOM(msg); +} + +void ODK_Pack_DeactivateUsageEntry_Response(Message* msg, + OEMCryptoResult result) { + uint32_t api_value = 66; /* from _oecc66 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_ReportUsage_Request(Message* msg, OEMCrypto_SESSION session, + const uint8_t* pst, size_t pst_length, + const uint8_t* buffer, + const size_t* buffer_length) { + uint32_t api_value = 32; /* from _oecc32 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &pst_length); + ODK_PackNullable_size_t(msg, buffer_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackMemory(msg, pst, LengthFromSizeT(pst_length)); + ODK_PackAlloc(msg, buffer); + ODK_PackEOM(msg); +} + +void ODK_Pack_ReportUsage_Response(Message* msg, OEMCryptoResult result, + const uint8_t* buffer, + const size_t* buffer_length) { + uint32_t api_value = 32; /* from _oecc32 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, buffer_length); + ODK_Pack_uint32_t(msg, &result); + if (SuccessResult(result)) { + ODK_PackMemory(msg, buffer, LengthFromSizeTPointer(buffer_length)); + } + ODK_PackEOM(msg); +} + +void ODK_Pack_DeleteUsageEntry_Request(Message* msg, OEMCrypto_SESSION session, + const uint8_t* pst, size_t pst_length, + const uint8_t* message, + size_t message_length, + const uint8_t* signature, + size_t signature_length) { + uint32_t api_value = 33; /* from _oecc33 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &pst_length); + ODK_Pack_size_t(msg, &message_length); + ODK_Pack_size_t(msg, &signature_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackMemory(msg, pst, LengthFromSizeT(pst_length)); + ODK_PackMemory(msg, message, LengthFromSizeT(message_length)); + ODK_PackMemory(msg, signature, LengthFromSizeT(signature_length)); + ODK_PackEOM(msg); +} + +void ODK_Pack_DeleteUsageEntry_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 33; /* from _oecc33 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_ForceDeleteUsageEntry_Request(Message* msg, const uint8_t* pst, + size_t pst_length) { + uint32_t api_value = 43; /* from _oecc43 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &pst_length); + ODK_PackMemory(msg, pst, LengthFromSizeT(pst_length)); + ODK_PackEOM(msg); +} + +void ODK_Pack_ForceDeleteUsageEntry_Response(Message* msg, + OEMCryptoResult result) { + uint32_t api_value = 43; /* from _oecc43 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_MoveEntry_Request(Message* msg, OEMCrypto_SESSION session, + uint32_t new_index) { + uint32_t api_value = 68; /* from _oecc68 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &session); + ODK_Pack_uint32_t(msg, &new_index); + ODK_PackEOM(msg); +} + +void ODK_Pack_MoveEntry_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 68; /* from _oecc68 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_ShrinkUsageTableHeader_Request( + Message* msg, uint32_t new_entry_count, const uint8_t* header_buffer, + const size_t* header_buffer_length) { + uint32_t api_value = 67; /* from _oecc67 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, header_buffer_length); + ODK_Pack_uint32_t(msg, &new_entry_count); + ODK_PackAlloc(msg, header_buffer); + ODK_PackEOM(msg); +} + +void ODK_Pack_ShrinkUsageTableHeader_Response( + Message* msg, OEMCryptoResult result, const uint8_t* header_buffer, + const size_t* header_buffer_length) { + uint32_t api_value = 67; /* from _oecc67 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackNullable_size_t(msg, header_buffer_length); + ODK_Pack_uint32_t(msg, &result); + if (SuccessResult(result)) { + ODK_PackMemory(msg, header_buffer, + LengthFromSizeTPointer(header_buffer_length)); + } + ODK_PackEOM(msg); +} + +void ODK_Pack_CopyOldUsageEntry_Request(Message* msg, OEMCrypto_SESSION session, + const uint8_t* pst, size_t pst_length) { + uint32_t api_value = 69; /* from _oecc69 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &pst_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackMemory(msg, pst, LengthFromSizeT(pst_length)); + ODK_PackEOM(msg); +} + +void ODK_Pack_CopyOldUsageEntry_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 69; /* from _oecc69 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_DeleteOldUsageTable_Request(Message* msg) { + uint32_t api_value = 34; /* from _oecc34 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_DeleteOldUsageTable_Response(Message* msg, + OEMCryptoResult result) { + uint32_t api_value = 34; /* from _oecc34 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_RemoveSRM_Request(Message* msg) { + uint32_t api_value = 57; /* from _oecc57 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_RemoveSRM_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 57; /* from _oecc57 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_CreateOldUsageEntry_Request( + Message* msg, uint64_t time_since_license_received, + uint64_t time_since_first_decrypt, uint64_t time_since_last_decrypt, + OEMCrypto_Usage_Entry_Status status, const uint8_t* server_mac_key, + const uint8_t* client_mac_key, const uint8_t* pst, size_t pst_length) { + uint32_t api_value = 70; /* from _oecc70 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &pst_length); + ODK_Pack_uint64_t(msg, &time_since_license_received); + ODK_Pack_uint64_t(msg, &time_since_first_decrypt); + ODK_Pack_uint64_t(msg, &time_since_last_decrypt); + ODK_Pack_uint32_t(msg, &status); + ODK_PackArray(msg, &server_mac_key[0], 32); + ODK_PackArray(msg, &client_mac_key[0], 32); + ODK_PackMemory(msg, pst, LengthFromSizeT(pst_length)); + ODK_PackEOM(msg); +} + +void ODK_Pack_CreateOldUsageEntry_Response(Message* msg, + OEMCryptoResult result) { + uint32_t api_value = 70; /* from _oecc70 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_SupportsDecryptHash_Request(Message* msg) { + uint32_t api_value = 86; /* from _oecc86 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_PackEOM(msg); +} + +void ODK_Pack_SupportsDecryptHash_Response(Message* msg, uint32_t result) { + uint32_t api_value = 86; /* from _oecc86 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_SetDecryptHash_Request(Message* msg, OEMCrypto_SESSION session, + uint32_t frame_number, const uint8_t* hash, + size_t hash_length) { + uint32_t api_value = 88; /* from _oecc88 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &hash_length); + ODK_Pack_uint32_t(msg, &session); + ODK_Pack_uint32_t(msg, &frame_number); + ODK_PackMemory(msg, hash, LengthFromSizeT(hash_length)); + ODK_PackEOM(msg); +} + +void ODK_Pack_SetDecryptHash_Response(Message* msg, OEMCryptoResult result) { + uint32_t api_value = 88; /* from _oecc88 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetHashErrorCode_Request(Message* msg, OEMCrypto_SESSION session, + const uint32_t* failed_frame_number) { + uint32_t api_value = 89; /* from _oecc89 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &session); + ODK_PackIsNull(msg, failed_frame_number); + ODK_PackEOM(msg); +} + +void ODK_Pack_GetHashErrorCode_Response(Message* msg, OEMCryptoResult result, + const uint32_t* failed_frame_number) { + uint32_t api_value = 89; /* from _oecc89 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_uint32_t(msg, &result); + ODK_PackNullable_uint32_t(msg, failed_frame_number); + ODK_PackEOM(msg); +} + +void ODK_PackNullable_c_str(Message* msg, const char* value) { + ODK_PackBoolValue(msg, value == NULL); + if (value) { + ODK_Pack_c_str(msg, value); + } +} +void ODK_PackNullable_uint32_t(Message* msg, const OEMCrypto_SESSION* value) { + ODK_PackBoolValue(msg, value == NULL); + if (value) { + ODK_Pack_uint32_t(msg, value); + } +} +void ODK_PackNullable_size_t(Message* msg, const size_t* value) { + ODK_PackBoolValue(msg, value == NULL); + if (value) { + ODK_Pack_size_t(msg, value); + } +} +void ODK_PackNullable_OEMCrypto_DestBufferDesc( + Message* msg, const OEMCrypto_DestBufferDesc* value) { + ODK_PackBoolValue(msg, value == NULL); + if (value) { + ODK_Pack_OEMCrypto_DestBufferDesc(msg, value); + } +} +void ODK_PackNullable_OEMCrypto_CENCEncryptPatternDesc( + Message* msg, const OEMCrypto_CENCEncryptPatternDesc* value) { + ODK_PackBoolValue(msg, value == NULL); + if (value) { + ODK_Pack_OEMCrypto_CENCEncryptPatternDesc(msg, value); + } +} +void ODK_PackNullable_uint16_t(Message* msg, const uint16_t* value) { + ODK_PackBoolValue(msg, value == NULL); + if (value) { + ODK_Pack_uint16_t(msg, value); + } +} +void ODK_PackNullable_uint8_t(Message* msg, const uint8_t* value) { + ODK_PackBoolValue(msg, value == NULL); + if (value) { + ODK_Pack_uint8_t(msg, value); + } +} diff --git a/serialization/generated_src/serializer.h b/serialization/generated_src/serializer.h new file mode 100644 index 0000000..ded8486 --- /dev/null +++ b/serialization/generated_src/serializer.h @@ -0,0 +1,369 @@ +/* + * 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. + */ + +/* + * This code is auto-generated, do not edit + */ +#ifndef ODKITEE_SERIALIZER_H_ +#define ODKITEE_SERIALIZER_H_ + +#include "deserializer.h" +#include "serialization_base.h" +#include "serializer.h" +#ifdef __cplusplus +extern "C" { +#endif + +bool SuccessResult(OEMCryptoResult result); +void ODK_Pack_OEMCrypto_Substring(Message* msg, OEMCrypto_Substring const* obj); +void ODK_Pack_OEMCrypto_KeyObject(Message* msg, OEMCrypto_KeyObject const* obj); +void ODK_Pack_OEMCrypto_EntitledContentKeyObject( + Message* msg, OEMCrypto_EntitledContentKeyObject const* obj); +void ODK_Pack_OEMCrypto_KeyRefreshObject(Message* msg, + OEMCrypto_KeyRefreshObject const* obj); +void ODK_Pack_OEMCrypto_CENCEncryptPatternDesc( + Message* msg, OEMCrypto_CENCEncryptPatternDesc const* obj); +void ODK_Pack_SecurityLevel_Request(Message* msg); +void ODK_Pack_SecurityLevel_Response(Message* msg, const char* result); +void ODK_Pack_BuildInformation_Request(Message* msg); +void ODK_Pack_BuildInformation_Response(Message* msg, const char* result); +void ODK_Pack_SetSandbox_Request(Message* msg, const uint8_t* sandbox_id, + size_t sandbox_id_length); +void ODK_Pack_SetSandbox_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_Initialize_Request(Message* msg); +void ODK_Pack_Initialize_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_Terminate_Request(Message* msg); +void ODK_Pack_Terminate_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_OpenSession_Request(Message* msg, + const OEMCrypto_SESSION* session); +void ODK_Pack_OpenSession_Response(Message* msg, OEMCryptoResult result, + const OEMCrypto_SESSION* session); +void ODK_Pack_CloseSession_Request(Message* msg, OEMCrypto_SESSION session); +void ODK_Pack_CloseSession_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_GenerateDerivedKeys_Request(Message* msg, + OEMCrypto_SESSION session, + const SharedMemory* mac_key_context, + uint32_t mac_key_context_length, + const SharedMemory* enc_key_context, + uint32_t enc_key_context_length); +void ODK_Pack_GenerateDerivedKeys_Response(Message* msg, + OEMCryptoResult result); +void ODK_Pack_DeriveKeysFromSessionKey_Request( + Message* msg, OEMCrypto_SESSION session, const uint8_t* enc_session_key, + size_t enc_session_key_length, const SharedMemory* mac_key_context, + size_t mac_key_context_length, const SharedMemory* enc_key_context, + size_t enc_key_context_length); +void ODK_Pack_DeriveKeysFromSessionKey_Response(Message* msg, + OEMCryptoResult result); +void ODK_Pack_GenerateNonce_Request(Message* msg, OEMCrypto_SESSION session, + const uint32_t* nonce); +void ODK_Pack_GenerateNonce_Response(Message* msg, OEMCryptoResult result, + const uint32_t* nonce); +void ODK_Pack_GenerateSignature_Request(Message* msg, OEMCrypto_SESSION session, + const SharedMemory* message, + size_t message_length, + const uint8_t* signature, + const size_t* signature_length); +void ODK_Pack_GenerateSignature_Response(Message* msg, OEMCryptoResult result, + const uint8_t* signature, + const size_t* signature_length); +void ODK_Pack_LoadSRM_Request(Message* msg, const uint8_t* buffer, + size_t buffer_length); +void ODK_Pack_LoadSRM_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_LoadKeys_Request( + Message* msg, OEMCrypto_SESSION session, const SharedMemory* message, + size_t message_length, const SharedMemory* signature, + size_t signature_length, OEMCrypto_Substring enc_mac_keys_iv, + OEMCrypto_Substring enc_mac_keys, size_t key_array_length, + const OEMCrypto_KeyObject* key_array, OEMCrypto_Substring pst, + OEMCrypto_Substring srm_restriction_data, + OEMCrypto_LicenseType license_type); +void ODK_Pack_LoadKeys_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_LoadEntitledContentKeys_Request( + Message* msg, OEMCrypto_SESSION session, const SharedMemory* message, + size_t message_length, size_t key_array_length, + const OEMCrypto_EntitledContentKeyObject* key_array); +void ODK_Pack_LoadEntitledContentKeys_Response(Message* msg, + OEMCryptoResult result); +void ODK_Pack_RefreshKeys_Request(Message* msg, OEMCrypto_SESSION session, + const SharedMemory* message, + size_t message_length, + const SharedMemory* signature, + size_t signature_length, + size_t key_array_length, + const OEMCrypto_KeyRefreshObject* key_array); +void ODK_Pack_RefreshKeys_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_QueryKeyControl_Request(Message* msg, OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + const uint8_t* key_control_block, + const size_t* key_control_block_length); +void ODK_Pack_QueryKeyControl_Response(Message* msg, OEMCryptoResult result, + const uint8_t* key_control_block, + const size_t* key_control_block_length); +void ODK_Pack_SelectKey_Request(Message* msg, OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + OEMCryptoCipherMode cipher_mode); +void ODK_Pack_SelectKey_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_DecryptCENC_Request( + Message* msg, OEMCrypto_SESSION session, const SharedMemory* data_addr, + size_t data_addr_length, bool is_encrypted, const uint8_t* iv, + size_t block_offset, const OEMCrypto_DestBufferDesc* out_buffer, + const OEMCrypto_CENCEncryptPatternDesc* pattern, uint8_t subsample_flags); +void ODK_Pack_DecryptCENC_Response(Message* msg, OEMCryptoResult result, + const OEMCrypto_DestBufferDesc* out_buffer); +void ODK_Pack_CopyBuffer_Request(Message* msg, OEMCrypto_SESSION session, + const SharedMemory* data_addr, + size_t data_addr_length, + const OEMCrypto_DestBufferDesc* out_buffer, + uint8_t subsample_flags); +void ODK_Pack_CopyBuffer_Response(Message* msg, OEMCryptoResult result, + const OEMCrypto_DestBufferDesc* out_buffer); +void ODK_Pack_Generic_Encrypt_Request(Message* msg, OEMCrypto_SESSION session, + const SharedMemory* in_buffer, + size_t in_buffer_length, + const uint8_t* iv, + OEMCrypto_Algorithm algorithm, + const uint8_t* out_buffer); +void ODK_Pack_Generic_Encrypt_Response(Message* msg, OEMCryptoResult result, + size_t in_buffer_length, + const uint8_t* out_buffer); +void ODK_Pack_Generic_Decrypt_Request(Message* msg, OEMCrypto_SESSION session, + const SharedMemory* in_buffer, + size_t in_buffer_length, + const uint8_t* iv, + OEMCrypto_Algorithm algorithm, + const uint8_t* out_buffer); +void ODK_Pack_Generic_Decrypt_Response(Message* msg, OEMCryptoResult result, + size_t in_buffer_length, + const uint8_t* out_buffer); +void ODK_Pack_Generic_Sign_Request(Message* msg, OEMCrypto_SESSION session, + const SharedMemory* buffer, + size_t buffer_length, + OEMCrypto_Algorithm algorithm, + const uint8_t* signature, + const size_t* signature_length); +void ODK_Pack_Generic_Sign_Response(Message* msg, OEMCryptoResult result, + const uint8_t* signature, + const size_t* signature_length); +void ODK_Pack_Generic_Verify_Request(Message* msg, OEMCrypto_SESSION session, + const SharedMemory* buffer, + size_t buffer_length, + OEMCrypto_Algorithm algorithm, + const SharedMemory* signature, + size_t signature_length); +void ODK_Pack_Generic_Verify_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_UpdateUsageTable_Request(Message* msg); +void ODK_Pack_UpdateUsageTable_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_WrapKeyboxOrOEMCert_Request(Message* msg, const uint8_t* rot, + size_t rotLength, + const uint8_t* wrappedRot, + const size_t* wrappedRotLength, + const uint8_t* transportKey, + size_t transportKeyLength); +void ODK_Pack_WrapKeyboxOrOEMCert_Response(Message* msg, OEMCryptoResult result, + const uint8_t* wrappedRot, + const size_t* wrappedRotLength); +void ODK_Pack_InstallKeyboxOrOEMCert_Request(Message* msg, const uint8_t* rot, + size_t rotLength); +void ODK_Pack_InstallKeyboxOrOEMCert_Response(Message* msg, + OEMCryptoResult result); +void ODK_Pack_GetProvisioningMethod_Request(Message* msg); +void ODK_Pack_GetProvisioningMethod_Response( + Message* msg, OEMCrypto_ProvisioningMethod result); +void ODK_Pack_IsKeyboxOrOEMCertValid_Request(Message* msg); +void ODK_Pack_IsKeyboxOrOEMCertValid_Response(Message* msg, + OEMCryptoResult result); +void ODK_Pack_GetDeviceID_Request(Message* msg, const uint8_t* device_id, + const size_t* device_id_length); +void ODK_Pack_GetDeviceID_Response(Message* msg, OEMCryptoResult result, + const uint8_t* device_id, + const size_t* device_id_length); +void ODK_Pack_GetKeyData_Request(Message* msg, const uint8_t* keyData, + const size_t* keyDataLength); +void ODK_Pack_GetKeyData_Response(Message* msg, OEMCryptoResult result, + const uint8_t* keyData, + const size_t* keyDataLength); +void ODK_Pack_LoadTestKeybox_Request(Message* msg, const uint8_t* buffer, + size_t buffer_length); +void ODK_Pack_LoadTestKeybox_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_GetOEMPublicCertificate_Request(Message* msg, + OEMCrypto_SESSION session, + const uint8_t* public_cert, + const size_t* public_cert_length); +void ODK_Pack_GetOEMPublicCertificate_Response( + Message* msg, OEMCryptoResult result, const uint8_t* public_cert, + const size_t* public_cert_length); +void ODK_Pack_GetRandom_Request(Message* msg, const uint8_t* random_data, + size_t random_data_length); +void ODK_Pack_GetRandom_Response(Message* msg, OEMCryptoResult result, + const uint8_t* random_data, + size_t random_data_length); +void ODK_Pack_APIVersion_Request(Message* msg); +void ODK_Pack_APIVersion_Response(Message* msg, uint32_t result); +void ODK_Pack_Security_Patch_Level_Request(Message* msg); +void ODK_Pack_Security_Patch_Level_Response(Message* msg, uint8_t result); +void ODK_Pack_GetHDCPCapability_Request( + Message* msg, const OEMCrypto_HDCP_Capability* current, + const OEMCrypto_HDCP_Capability* maximum); +void ODK_Pack_GetHDCPCapability_Response( + Message* msg, OEMCryptoResult result, + const OEMCrypto_HDCP_Capability* current, + const OEMCrypto_HDCP_Capability* maximum); +void ODK_Pack_SupportsUsageTable_Request(Message* msg); +void ODK_Pack_SupportsUsageTable_Response(Message* msg, bool result); +void ODK_Pack_IsAntiRollbackHwPresent_Request(Message* msg); +void ODK_Pack_IsAntiRollbackHwPresent_Response(Message* msg, bool result); +void ODK_Pack_GetNumberOfOpenSessions_Request(Message* msg, + const size_t* count); +void ODK_Pack_GetNumberOfOpenSessions_Response(Message* msg, + OEMCryptoResult result, + const size_t* count); +void ODK_Pack_GetMaxNumberOfSessions_Request(Message* msg, const size_t* max); +void ODK_Pack_GetMaxNumberOfSessions_Response(Message* msg, + OEMCryptoResult result, + const size_t* max); +void ODK_Pack_SupportedCertificates_Request(Message* msg); +void ODK_Pack_SupportedCertificates_Response(Message* msg, uint32_t result); +void ODK_Pack_IsSRMUpdateSupported_Request(Message* msg); +void ODK_Pack_IsSRMUpdateSupported_Response(Message* msg, bool result); +void ODK_Pack_GetCurrentSRMVersion_Request(Message* msg, + const uint16_t* version); +void ODK_Pack_GetCurrentSRMVersion_Response(Message* msg, + OEMCryptoResult result, + const uint16_t* version); +void ODK_Pack_GetAnalogOutputFlags_Request(Message* msg); +void ODK_Pack_GetAnalogOutputFlags_Response(Message* msg, uint32_t result); +void ODK_Pack_ResourceRatingTier_Request(Message* msg); +void ODK_Pack_ResourceRatingTier_Response(Message* msg, uint32_t result); +void ODK_Pack_RewrapDeviceRSAKey30_Request( + Message* msg, OEMCrypto_SESSION session, const uint32_t* unaligned_nonce, + const SharedMemory* encrypted_message_key, + size_t encrypted_message_key_length, const SharedMemory* enc_rsa_key, + size_t enc_rsa_key_length, const uint8_t* enc_rsa_key_iv, + const uint8_t* wrapped_rsa_key, const size_t* wrapped_rsa_key_length); +void ODK_Pack_RewrapDeviceRSAKey30_Response( + Message* msg, OEMCryptoResult result, const uint8_t* wrapped_rsa_key, + const size_t* wrapped_rsa_key_length); +void ODK_Pack_RewrapDeviceRSAKey_Response(Message* msg, OEMCryptoResult result, + const uint8_t* wrapped_rsa_key, + const size_t* wrapped_rsa_key_length); +void ODK_Pack_LoadDeviceRSAKey_Request(Message* msg, OEMCrypto_SESSION session, + const SharedMemory* wrapped_rsa_key, + size_t wrapped_rsa_key_length); +void ODK_Pack_LoadDeviceRSAKey_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_LoadTestRSAKey_Request(Message* msg); +void ODK_Pack_LoadTestRSAKey_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_GenerateRSASignature_Request( + Message* msg, OEMCrypto_SESSION session, const SharedMemory* message, + size_t message_length, const uint8_t* signature, + const size_t* signature_length, RSA_Padding_Scheme padding_scheme); +void ODK_Pack_GenerateRSASignature_Response(Message* msg, + OEMCryptoResult result, + const uint8_t* signature, + const size_t* signature_length); +void ODK_Pack_CreateUsageTableHeader_Request( + Message* msg, const uint8_t* header_buffer, + const size_t* header_buffer_length); +void ODK_Pack_CreateUsageTableHeader_Response( + Message* msg, OEMCryptoResult result, const uint8_t* header_buffer, + const size_t* header_buffer_length); +void ODK_Pack_LoadUsageTableHeader_Request(Message* msg, const uint8_t* buffer, + size_t buffer_length); +void ODK_Pack_LoadUsageTableHeader_Response(Message* msg, + OEMCryptoResult result); +void ODK_Pack_CreateNewUsageEntry_Request(Message* msg, + OEMCrypto_SESSION session, + const uint32_t* usage_entry_number); +void ODK_Pack_CreateNewUsageEntry_Response(Message* msg, OEMCryptoResult result, + const uint32_t* usage_entry_number); +void ODK_Pack_LoadUsageEntry_Request(Message* msg, OEMCrypto_SESSION session, + uint32_t usage_entry_number, + const uint8_t* buffer, + size_t buffer_length); +void ODK_Pack_LoadUsageEntry_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_UpdateUsageEntry_Request(Message* msg, OEMCrypto_SESSION session, + const SharedMemory* header_buffer, + const size_t* header_buffer_length, + const SharedMemory* entry_buffer, + const size_t* entry_buffer_length); +void ODK_Pack_UpdateUsageEntry_Response(Message* msg, OEMCryptoResult result, + const SharedMemory* header_buffer, + const size_t* header_buffer_length, + const SharedMemory* entry_buffer, + const size_t* entry_buffer_length); +void ODK_Pack_DeactivateUsageEntry_Request(Message* msg, + OEMCrypto_SESSION session, + const uint8_t* pst, + size_t pst_length); +void ODK_Pack_DeactivateUsageEntry_Response(Message* msg, + OEMCryptoResult result); +void ODK_Pack_ReportUsage_Request(Message* msg, OEMCrypto_SESSION session, + const uint8_t* pst, size_t pst_length, + const uint8_t* buffer, + const size_t* buffer_length); +void ODK_Pack_ReportUsage_Response(Message* msg, OEMCryptoResult result, + const uint8_t* buffer, + const size_t* buffer_length); +void ODK_Pack_DeleteUsageEntry_Request(Message* msg, OEMCrypto_SESSION session, + const uint8_t* pst, size_t pst_length, + const uint8_t* message, + size_t message_length, + const uint8_t* signature, + size_t signature_length); +void ODK_Pack_DeleteUsageEntry_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_ForceDeleteUsageEntry_Request(Message* msg, const uint8_t* pst, + size_t pst_length); +void ODK_Pack_ForceDeleteUsageEntry_Response(Message* msg, + OEMCryptoResult result); +void ODK_Pack_MoveEntry_Request(Message* msg, OEMCrypto_SESSION session, + uint32_t new_index); +void ODK_Pack_MoveEntry_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_ShrinkUsageTableHeader_Request( + Message* msg, uint32_t new_entry_count, const uint8_t* header_buffer, + const size_t* header_buffer_length); +void ODK_Pack_ShrinkUsageTableHeader_Response( + Message* msg, OEMCryptoResult result, const uint8_t* header_buffer, + const size_t* header_buffer_length); +void ODK_Pack_CopyOldUsageEntry_Request(Message* msg, OEMCrypto_SESSION session, + const uint8_t* pst, size_t pst_length); +void ODK_Pack_CopyOldUsageEntry_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_DeleteOldUsageTable_Request(Message* msg); +void ODK_Pack_DeleteOldUsageTable_Response(Message* msg, + OEMCryptoResult result); +void ODK_Pack_RemoveSRM_Request(Message* msg); +void ODK_Pack_RemoveSRM_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_CreateOldUsageEntry_Request( + Message* msg, uint64_t time_since_license_received, + uint64_t time_since_first_decrypt, uint64_t time_since_last_decrypt, + OEMCrypto_Usage_Entry_Status status, const uint8_t* server_mac_key, + const uint8_t* client_mac_key, const uint8_t* pst, size_t pst_length); +void ODK_Pack_CreateOldUsageEntry_Response(Message* msg, + OEMCryptoResult result); +void ODK_Pack_SupportsDecryptHash_Request(Message* msg); +void ODK_Pack_SupportsDecryptHash_Response(Message* msg, uint32_t result); +void ODK_Pack_SetDecryptHash_Request(Message* msg, OEMCrypto_SESSION session, + uint32_t frame_number, const uint8_t* hash, + size_t hash_length); +void ODK_Pack_SetDecryptHash_Response(Message* msg, OEMCryptoResult result); +void ODK_Pack_GetHashErrorCode_Request(Message* msg, OEMCrypto_SESSION session, + const uint32_t* failed_frame_number); +void ODK_Pack_GetHashErrorCode_Response(Message* msg, OEMCryptoResult result, + const uint32_t* failed_frame_number); +void ODK_PackNullable_c_str(Message* msg, const char* value); +void ODK_PackNullable_uint32_t(Message* msg, const OEMCrypto_SESSION* value); +void ODK_PackNullable_size_t(Message* msg, const size_t* value); +void ODK_PackNullable_OEMCrypto_DestBufferDesc( + Message* msg, const OEMCrypto_DestBufferDesc* value); +void ODK_PackNullable_OEMCrypto_CENCEncryptPatternDesc( + Message* msg, const OEMCrypto_CENCEncryptPatternDesc* value); +void ODK_PackNullable_uint16_t(Message* msg, const uint16_t* value); +void ODK_PackNullable_uint8_t(Message* msg, const uint8_t* value); +#ifdef __cplusplus +} // extern "C" +#endif +#endif /* ODKITEE_SERIALIZER_H_ */ diff --git a/serialization/marshaller_base.c b/serialization/marshaller_base.c new file mode 100644 index 0000000..9d1f1d4 --- /dev/null +++ b/serialization/marshaller_base.c @@ -0,0 +1,95 @@ +/* + * 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 "bump_allocator.h" +#include "marshaller_base.h" + +static void InitBytes(uint8_t* ptr, size_t count) { + if (ptr && count) { + memset(ptr, 0, count); + } +} + +/* + * The functions here are declared weak so they can + * be overriden by test functions that inject + * various initialized values for testing + */ + +__attribute__((weak)) void Init_bool(bool* value) { + if (value) { + *value = false; + } +} + +__attribute__((weak)) void Init_size_t(size_t* value) { + if (value) { + *value = 0; + } +} + +__attribute__((weak)) void Init_c_str(char** value) { + if (value) { + *value = NULL; + } +} + +__attribute__((weak)) void Init_uint8_t(uint8_t* value) { + if (value) { + *value = 0; + } +} + +__attribute__((weak)) void Init_uint16_t(uint16_t* value) { + if (value) { + *value = 0; + } +} + +__attribute__((weak)) void Init_uint32_t(uint32_t* value) { + if (value) { + *value = 0; + } +} + +__attribute__((weak)) void Init_uint64_t(uint64_t* value) { + if (value) { + *value = 0; + } +} + +__attribute__((weak)) void InitMemory(uint8_t* address, size_t length) +{ + if (address && length) { + InitBytes(address, length); + } +} + +__attribute__((weak)) void InitPointer(uint8_t** ptr) { + if (ptr) { + *ptr = NULL; + } +} + +/* + * Allocate memory for a variable from the bump allocator, used for + * DeclarePackVar, DeclareUnpackVar, for some pointer types + */ +__attribute__((weak)) uint8_t* VarAlloc(size_t size) { + return BumpAllocate(size); +} + +/* + * Special cases due to union & shared memory + */ +__attribute__((weak)) void Init_OEMCrypto_DestBufferDesc(OEMCrypto_DestBufferDesc* d) { + if (d) { + d->type = OEMCrypto_BufferType_Clear; + d->buffer.clear.address = NULL; + d->buffer.clear.max_length = 0; + } +} + diff --git a/serialization/marshaller_base.h b/serialization/marshaller_base.h new file mode 100644 index 0000000..7766f75 --- /dev/null +++ b/serialization/marshaller_base.h @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#ifndef ODKITEE_MARSHALLER_BASE_H_ +#define ODKITEE_MARSHALLER_BASE_H_ + +#include +#include +#include +#include + +#include "OEMCryptoCENC.h" +#include "serialization_base.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _Message Message; + +/* + * When packing a pointer to size_t, and the pointer is null, pass + * this special value of size_t instead + */ +#define SZ_NULL (size_t)~0 + +void Init_bool(bool* value); +void Init_size_t(size_t* value); +void Init_c_str(char** value); +void Init_uint8_t(uint8_t* value); +void Init_uint16_t(uint16_t* value); +void Init_uint32_t(uint32_t* value); +void Init_uint64_t(uint64_t* value); +void InitMemory(uint8_t* addr, size_t length); +void InitPointer(uint8_t** addr); + +/* + * Allocate memory for a variable from the bump allocator, used for + * DeclarePackVar, DeclareUnpackVar, for some pointer types + */ +uint8_t* VarAlloc(size_t size); + +/* + * Special cases due to union & shared memory + */ +void Init_OEMCrypto_DestBufferDesc(OEMCrypto_DestBufferDesc* desc); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // ODKITEE_MARSHALLER_BASE_H_ diff --git a/serialization/message.c b/serialization/message.c new file mode 100644 index 0000000..84a3b94 --- /dev/null +++ b/serialization/message.c @@ -0,0 +1,101 @@ +/* + * 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 "message.h" + +#include +#include +#include +#include +#include + +/* Round up address to the nearest 8 byte boundary */ +#define align_8(addr) (((uintptr_t)(addr) + 7) & ~(uintptr_t)7) + +struct _Message { + uint8_t* base; + size_t capacity; + size_t size; + size_t read_offset; + MessageStatus status; +}; + +/* + * The message structure, which is separate from the buffer, + * is initialized to reference the buffer + */ +void InitMessage(Message* message, uint8_t* buffer, size_t capacity) { + assert(message != NULL); + assert(buffer != NULL); + message->base = buffer; + message->capacity = capacity; + message->size = 0; + message->read_offset = 0; + message->status = MESSAGE_STATUS_OK; +} + +/* + * Cast pointer of Message from the input buffer. Since Message* is 8-byte + * aligned on a 64-bit system, or 4-byte aligned on a 32-bit system, the input + * buffer needs to be adjusted to 8-byte alignment before pointer casting, in + * order to avoid misaligned pointer + */ +Message* CreateMessage(uint8_t* buffer, size_t buffer_size) { + assert(buffer != NULL); + uint8_t* const buffer_aligned = (uint8_t* const)align_8(buffer); + assert(buffer_size >= sizeof(Message) + (size_t)(buffer_aligned - buffer)); + Message* const message = (Message* const)buffer_aligned; + message->base = buffer_aligned + sizeof(Message); + message->capacity = + buffer_size - sizeof(Message) - (size_t)(buffer_aligned - buffer); + message->size = 0; + message->read_offset = 0; + message->status = MESSAGE_STATUS_OK; + return message; +} + +void ClearMessage(Message* message) { + assert(message != NULL); + message->size = 0; + message->read_offset = 0; + message->status = MESSAGE_STATUS_OK; +} + +void ResetMessage(Message* message) { + assert(message != NULL); + message->read_offset = 0; + message->status = MESSAGE_STATUS_OK; +} + +uint8_t* GetBase(Message* message) { + assert(message != NULL); + return message->base; +} + +size_t GetCapacity(Message* message) { + assert(message != NULL); + return message->capacity; +} + +size_t GetSize(Message* message) { + assert(message != NULL); + return message->size; +} + +MessageStatus GetStatus(Message* message) { + assert(message != NULL); + return message->status; +} + +void SetStatus(Message* message, MessageStatus status) { + assert(message != NULL); + message->status = status; +} + +void SetSize(Message* message, size_t size) { + assert(message != NULL); + message->size = size; +} diff --git a/serialization/message.h b/serialization/message.h new file mode 100644 index 0000000..d6c6067 --- /dev/null +++ b/serialization/message.h @@ -0,0 +1,103 @@ +/* + * 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. + */ + +#ifndef ODKITEE_MESSAGE_H_ +#define ODKITEE_MESSAGE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct _Message Message; + +/* + * TODO: there is a dangerous duplication of the MessageStatus + * enum with odk/src/serialization_base.h. The two need to + * be converged. Removing the random enum values here, since + * a proper fix is outside the scope of the current CL. Opened + * b/158603784. + */ +typedef enum { + MESSAGE_STATUS_OK, + MESSAGE_STATUS_UNKNOWN_ERROR, + MESSAGE_STATUS_OVERFLOW_ERROR, + MESSAGE_STATUS_UNDERFLOW_ERROR, + MESSAGE_STATUS_PARSE_ERROR, + MESSAGE_STATUS_NULL_POINTER_ERROR, + MESSAGE_STATUS_API_VALUE_ERROR, + MESSAGE_STATUS_INVALID_TAG_ERROR, + MESSAGE_STATUS_END_OF_MESSAGE_ERROR, + MESSAGE_STATUS_INVALID_ENUM_VALUE +} MessageStatus; + +/* + * Create a message from a buffer. The message structure consumes the first + * sizeof(Message) bytes of the buffer. The caller is responsible for ensuring + * that the buffer remains allocated for the lifetime of the message. + */ +Message* CreateMessage(uint8_t* buffer, size_t buffer_size); + +/* + * Initialize a message structure to reference a separate buffer. The caller + * is responsible for ensuring that the buffer remains allocated for the + * lifetime of the message. + */ +void InitMessage(Message* message, uint8_t* buffer, size_t capacity); + +/* + * Erase the contents of the message, set it + * to an empty state. + */ +void ClearMessage(Message* message); + +/* + * Reset read pointer to the beginning of the + * message and clear status + */ +void ResetMessage(Message* message); + +/* + * The message base is the start of the payload + */ +uint8_t* GetBase(Message* message); + +/* + * Get the maximum number of bytes the message + * can hold. + */ +size_t GetCapacity(Message* message); + +/* + * Get the number of bytes currently in the + * message + */ +size_t GetSize(Message* message); + +/* + * Return the status of the message + */ +MessageStatus GetStatus(Message* message); + +/* + * Set the message status to a specific value + */ +void SetStatus(Message* message, MessageStatus status); + +/* + * Set the size of the message to a value. This + * may be needed after writing data into the payload. + */ +void SetSize(Message*message, size_t size); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // ODKITEE_MESSAGE_H_ + diff --git a/serialization/serialization_base.c b/serialization/serialization_base.c new file mode 100644 index 0000000..c1b2355 --- /dev/null +++ b/serialization/serialization_base.c @@ -0,0 +1,642 @@ +/* + * 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 "serialization_base.h" + +#include +#include +#include +#include +#include + +#include "OEMCryptoCENC.h" +#include "bump_allocator.h" +#include "marshaller_base.h" +#include "shared_memory_allocator.h" +#include "shared_memory_interface.h" + +struct _Message { + uint8_t* base; + size_t capacity; + size_t size; + size_t read_offset; + MessageStatus status; +}; + +typedef enum { + TAG_INVALID, + TAG_BOOL, + TAG_SIZE_T, + TAG_UINT8, + TAG_UINT16, + TAG_UINT32, + TAG_UINT64, + TAG_MEMORY, + TAG_SHARED_MEMORY, + TAG_EOM +} TagType; + +static bool ValidMessage(Message* message) { + if (message == NULL) { + return false; + } + if (message->status != MESSAGE_STATUS_OK) { + return false; + } + if (message->base == NULL) { + message->status = MESSAGE_STATUS_NULL_POINTER_ERROR; + return false; + } + if (message->read_offset > message->capacity || + message->size > message->capacity || + message->read_offset > message->size) { + message->status = MESSAGE_STATUS_OVERFLOW_ERROR; + return false; + } + return true; +} + +static bool NullCheck(Message* message, const void* ptr) { + if (!ptr) { + message->status = MESSAGE_STATUS_NULL_POINTER_ERROR; + return true; + } + return false; +} + +/* Callers are expected to have validated the message already */ +static void PackBytes(Message* message, const uint8_t* ptr, size_t count) { + if (!NullCheck(message, ptr)) { + if (count <= message->capacity - message->size) { + memcpy(message->base + message->size, ptr, count); + message->size += count; + } else { + message->status = MESSAGE_STATUS_OVERFLOW_ERROR; + } + } +} + +static void PackTag(Message* message, TagType tag) { + if (!ValidMessage(message)) return; + uint8_t byte = (uint8_t)tag; + PackBytes(message, &byte, sizeof(byte)); +} + +LengthType LengthFromUint32T(uint32_t length) { + LengthType length_type = {.tag = LENGTH_TYPE_UINT32_T, + .type.uint32_t_value = length}; + return length_type; +} + +LengthType LengthFromSizeT(size_t length) { + LengthType length_type = {.tag = LENGTH_TYPE_SIZE_T, + .type.size_t_value = length}; + return length_type; +} + +LengthType LengthFromUint32TPointer(const uint32_t* length) { + LengthType length_type = {.tag = LENGTH_TYPE_UINT32_T_POINTER, + .type.uint32_t_pointer = length}; + return length_type; +} + +LengthType LengthFromSizeTPointer(const size_t* length) { + LengthType length_type = {.tag = LENGTH_TYPE_SIZE_T_POINTER, + .type.size_t_pointer = length}; + return length_type; +} + +LengthType LengthFromUint32TDoublePointer(uint32_t** length) { + LengthType length_type = {.tag = LENGTH_TYPE_UINT32_T_DOUBLE_POINTER, + .type.uint32_t_double_pointer = length}; + return length_type; +} + +LengthType LengthFromSizeTDoublePointer(size_t** length) { + LengthType length_type = {.tag = LENGTH_TYPE_SIZE_T_DOUBLE_POINTER, + .type.size_t_double_pointer = length}; + return length_type; +} + +size_t LengthAsSizeT(LengthType length) { + size_t result = 0; + switch(length.tag) { + case LENGTH_TYPE_SIZE_T: + result = length.type.size_t_value; + break; + case LENGTH_TYPE_UINT32_T: + result = (size_t)length.type.uint32_t_value; + break; + case LENGTH_TYPE_SIZE_T_POINTER: + if (length.type.size_t_pointer) { + result = *length.type.size_t_pointer; + } + break; + case LENGTH_TYPE_UINT32_T_POINTER: + if (length.type.uint32_t_pointer) { + result = (size_t)*length.type.uint32_t_pointer; + } + break; + case LENGTH_TYPE_SIZE_T_DOUBLE_POINTER: + if (length.type.size_t_double_pointer && *length.type.size_t_double_pointer) { + result = **length.type.size_t_double_pointer; + } + break; + case LENGTH_TYPE_UINT32_T_DOUBLE_POINTER: + if (length.type.uint32_t_double_pointer && *length.type.uint32_t_double_pointer) { + result = (size_t)**length.type.uint32_t_double_pointer; + } + break; + } + return result; +} + +bool LengthIsNull(LengthType length) { + switch(length.tag) { + case LENGTH_TYPE_SIZE_T: + case LENGTH_TYPE_UINT32_T: + return false; + case LENGTH_TYPE_SIZE_T_POINTER: + return length.type.size_t_pointer == NULL; + case LENGTH_TYPE_UINT32_T_POINTER: + return length.type.uint32_t_pointer == NULL; + case LENGTH_TYPE_SIZE_T_DOUBLE_POINTER: + return length.type.size_t_double_pointer == NULL || + *length.type.size_t_double_pointer == NULL; + case LENGTH_TYPE_UINT32_T_DOUBLE_POINTER: + return length.type.uint32_t_double_pointer == NULL || + *length.type.uint32_t_double_pointer == NULL; + } + assert(false); + return true; +} + +void ODK_Pack_bool(Message* message, const bool* value) { + if (!ValidMessage(message)) return; + PackTag(message, TAG_BOOL); + uint8_t b = (*value) ? 1 : 0; + PackBytes(message, &b, sizeof(b)); +} + +void ODK_Pack_size_t(Message* message, const size_t* value) { + if (!ValidMessage(message)) return; + PackTag(message, TAG_SIZE_T); + uint64_t u64 = *value; + uint8_t buf[sizeof(uint64_t)]; + buf[0] = (uint8_t)u64; + buf[1] = (uint8_t)(u64 >> 8); + buf[2] = (uint8_t)(u64 >> 16); + buf[3] = (uint8_t)(u64 >> 24); + buf[4] = (uint8_t)(u64 >> 32); + buf[5] = (uint8_t)(u64 >> 40); + buf[6] = (uint8_t)(u64 >> 48); + buf[7] = (uint8_t)(u64 >> 56); + + PackBytes(message, buf, sizeof(buf)); +} + +void ODK_Pack_c_str(Message* message, const char* value) { + if (!ValidMessage(message) || NullCheck(message, value)) return; + size_t length = strlen(value) + 1; + ODK_PackMemory(message, (const uint8_t*)value, LengthFromSizeT(length)); +} + +void ODK_Pack_uint8_t(Message* message, const uint8_t* value) { + if (!ValidMessage(message)) return; + PackTag(message, TAG_UINT8); + PackBytes(message, (const uint8_t*)value, sizeof(*value)); +} + +void ODK_Pack_uint16_t(Message* message, const uint16_t* value) { + if (!ValidMessage(message)) return; + PackTag(message, TAG_UINT16); + uint8_t buf[sizeof(uint16_t)]; + buf[0] = (uint8_t)(*value); + buf[1] = (uint8_t)(*value >> 8); + + PackBytes(message, buf, sizeof(buf)); +} + +void ODK_Pack_uint32_t(Message* message, const uint32_t* value) { + if (!ValidMessage(message)) return; + PackTag(message, TAG_UINT32); + uint8_t buf[sizeof(uint32_t)]; + buf[0] = (uint8_t)(*value); + buf[1] = (uint8_t)(*value >> 8); + buf[2] = (uint8_t)(*value >> 16); + buf[3] = (uint8_t)(*value >> 24); + + PackBytes(message, buf, sizeof(buf)); +} + +void ODK_Pack_uint64_t(Message* message, const uint64_t* value) { + if (!ValidMessage(message)) return; + PackTag(message, TAG_UINT64); + uint8_t buf[sizeof(uint64_t)]; + buf[0] = (uint8_t)(*value); + buf[1] = (uint8_t)(*value >> 8); + buf[2] = (uint8_t)(*value >> 16); + buf[3] = (uint8_t)(*value >> 24); + buf[4] = (uint8_t)(*value >> 32); + buf[5] = (uint8_t)(*value >> 40); + buf[6] = (uint8_t)(*value >> 48); + buf[7] = (uint8_t)(*value >> 56); + + PackBytes(message, buf, sizeof(buf)); +} + +/* + * Convenience function used by the serializer to + * pack a bool without having to allocate a local + * variable. + */ +bool ODK_PackBoolValue(Message* message, bool value) { + ODK_Pack_bool(message, (const bool*)&value); + return value; +} + +/* + * Pack a boolean indicating if the pointer value is NULL + */ +bool ODK_PackIsNull(Message* message, const void* pointer) { + return ODK_PackBoolValue(message, pointer == NULL); +} + +/* + * Pack a boolean indicating if the address value is NULL. It's + * effectivey the same as PackIsNull but provided for symmetry with + * UnpackAlloc. + */ +void ODK_PackAlloc(Message* message, const void* addr) { + ODK_PackIsNull(message, addr); +} + +/* + * Pack a range of memory given by address and length. First pack a + * bool indicating if the address is NULL. If the address is non-null + * and length is non-null then pack the length and |length| bytes from + * memory beginning at |address|. + */ +void ODK_PackMemory(Message* message, const uint8_t* address, + LengthType length) { + if (!ValidMessage(message)) return; + PackTag(message, TAG_MEMORY); + ODK_PackBoolValue(message, address == NULL || LengthIsNull(length)); + if (address && !LengthIsNull(length)) { + size_t count = LengthAsSizeT(length); + ODK_Pack_size_t(message, &count); + if (LengthAsSizeT(length) > 0) { + PackBytes(message, address, LengthAsSizeT(length)); + } + } +} + +/* + * Pack memory representing an array of fundamental types, given by + * address and length. + */ +void ODK_PackArray(Message* message, const uint8_t* address, size_t length) { + ODK_PackMemory(message, address, LengthFromSizeT(length)); +} + +/* + * Pack a variable length array of objects at the base address given + * by |address|, with |length| elements of size |size|. The ObjPacker is + * a pack function able to pack elements of the array. + */ +void ODK_PackObjArray(Message* message, const uint8_t* objs, LengthType length, + size_t size, ObjPacker packer) { + bool is_null = objs == NULL || LengthIsNull(length); + if (!ODK_PackBoolValue(message, is_null)) { + for (size_t i = 0; i < LengthAsSizeT(length); i++) { + (*packer)(message, objs + i * size); + } + } +} + +/* + * On the REE side, if address and length are not null, map the shared + * memory segment specified by index into our address space using the + * shared memory bump allocator and pack fields into the message so + * that the receiver can map the corresponding segment if needed. Copy + * the input data into the shared segment. + * + * Parameters: + * message - The message to pack into + * index - the index that identifies which segment to map + * address - base address of the local memory buffer. If address is + * null, shared memory will not be allocated, which is indicated + * by a packed bool value so the receiver will also know not to + * allocate the segment. + * length - the length of the segment. A segment of this size will + * be mapped if length is non-null and *length is non-zero. + * otherwise the segment will not be mapped. + */ +void ODK_PackSharedInputBuffer(Message* message, uint16_t index, + const uint8_t* address, LengthType length) { + if (!ValidMessage(message)) return; + PackTag(message, TAG_SHARED_MEMORY); + ODK_PackBoolValue(message, address == NULL || LengthIsNull(length)); + if (address && !LengthIsNull(length)) { + uint8_t* shared_address = SharedMemory_Allocate(index, LengthAsSizeT(length)); + if (shared_address) { + memcpy(shared_address, address, LengthAsSizeT(length)); + } + } +} + +/* + * Pass information to the receiver indicating whether shared memory + * needs to be allocated for the buffer indicated by |address| and |length|. + * + * Parameters: + * message - The message to pack into + * address - base address of the local memory buffer. If null, a shared + * memory segment will not need to be mapped by the receiver. + * length - the length of the segment. If null, or if the length is 0, + * a shared memory segment will not need to be mapped by the receiver. + * + * Returns: + * void + */ +void ODK_PackSharedOutputBuffer(Message* message, const uint8_t* address, + LengthType length) { + if (!ValidMessage(message)) return; + PackTag(message, TAG_SHARED_MEMORY); + ODK_PackBoolValue(message, address == NULL || LengthIsNull(length)); +} + +void ODK_PackEOM(Message* message) { + if (!ValidMessage(message)) return; + PackTag(message, TAG_EOM); +} + +/**************************** Unpack Functions *******************************/ + +static void UnpackBytes(Message* message, uint8_t* ptr, size_t count) { + if (!ValidMessage(message)) return; + if (count <= message->size - message->read_offset) { + if (ptr) { + memcpy(ptr, message->base + message->read_offset, count); + } + message->read_offset += count; + } else { + message->status = MESSAGE_STATUS_UNDERFLOW_ERROR; + } +} + +static bool CheckTag(Message* message, TagType tag) { + uint8_t byte = TAG_INVALID; + UnpackBytes(message, &byte, sizeof(byte)); + if (tag != (TagType)byte) { + message->status = MESSAGE_STATUS_INVALID_TAG_ERROR; + return false; + } + return true; +} + +void ODK_Unpack_bool(Message* message, bool* value) { + if (!ValidMessage(message)) return; + if (!CheckTag(message, TAG_BOOL)) return; + uint8_t b = 0; + UnpackBytes(message, &b, sizeof(b)); + *value = b ? true : false; +} + +void ODK_Unpack_size_t(Message* message, size_t* value) { + if (!ValidMessage(message)) return; + if (!CheckTag(message, TAG_SIZE_T)) return; + uint8_t buf[sizeof(uint64_t)]; + UnpackBytes(message, buf, sizeof(buf)); + uint64_t u64 = *value; + u64 = buf[0]; + u64 |= (uint64_t)buf[1] << 8; + u64 |= (uint64_t)buf[2] << 16; + u64 |= (uint64_t)buf[3] << 24; + u64 |= (uint64_t)buf[4] << 32; + u64 |= (uint64_t)buf[5] << 40; + u64 |= (uint64_t)buf[6] << 48; + u64 |= (uint64_t)buf[7] << 56; + *value = u64; +} + +void ODK_Unpack_c_str(Message* message, char** value) { + if (!ValidMessage(message) || NullCheck(message, value)) return; + *value = NULL; + uint8_t* ptr = NULL; + ODK_UnpackPointerToMemory(message, &ptr); + if (ptr) { + /* calculate length, be careful to stay within length of message */ + size_t length = 0; + uint8_t* p = ptr; + while (*p && p < message->base + message->size) { + length++; + p++; + } + void* buffer = BumpAllocate(length + 1); + if (buffer) { + memcpy(buffer, ptr, length); + *value = buffer; + } + } +} + +void ODK_Unpack_uint8_t(Message* message, uint8_t* value) { + if (!ValidMessage(message)) return; + if (!CheckTag(message, TAG_UINT8)) return; + UnpackBytes(message, (uint8_t*)value, sizeof(*value)); +} + +void ODK_Unpack_uint16_t(Message* message, uint16_t* value) { + if (!ValidMessage(message)) return; + if (!CheckTag(message, TAG_UINT16)) return; + uint8_t buf[sizeof(uint16_t)]; + UnpackBytes(message, buf, sizeof(buf)); + *value = buf[0]; + *value |= (uint16_t)buf[1] << 8; +} + +void ODK_Unpack_uint32_t(Message* message, uint32_t* value) { + if (!ValidMessage(message)) return; + if (!CheckTag(message, TAG_UINT32)) return; + uint8_t buf[sizeof(uint32_t)]; + UnpackBytes(message, buf, sizeof(buf)); + *value = buf[0]; + *value |= (uint32_t)buf[1] << 8; + *value |= (uint32_t)buf[2] << 16; + *value |= (uint32_t)buf[3] << 24; +} + +void ODK_Unpack_uint64_t(Message* message, uint64_t* value) { + if (!ValidMessage(message)) return; + if (!CheckTag(message, TAG_UINT64)) return; + uint8_t buf[sizeof(uint64_t)]; + UnpackBytes(message, buf, sizeof(buf)); + *value = buf[0]; + *value |= (uint64_t)buf[1] << 8; + *value |= (uint64_t)buf[2] << 16; + *value |= (uint64_t)buf[3] << 24; + *value |= (uint64_t)buf[4] << 32; + *value |= (uint64_t)buf[5] << 40; + *value |= (uint64_t)buf[6] << 48; + *value |= (uint64_t)buf[7] << 56; +} + +bool ODK_UnpackBoolValue(Message* message) { + bool value = false; + ODK_Unpack_bool(message, &value); + return value; +} + +/* Return true if the pointer was packed as NULL */ +bool ODK_UnpackIsNull(Message* message) { return ODK_UnpackBoolValue(message); } + +/* + * If the pointer was packed as NULL, return NULL. Otherwise + * return the number of bytes of memory from the bump allocator + * requested by |size| + */ +uint8_t* ODK_UnpackAlloc(Message* message, size_t size) { + return ODK_UnpackIsNull(message) ? NULL : BumpAllocate(size); +} + +/* + * If the pointer was packed as NULL, return NULL. Otherwise + * return the number of bytes of memory from the bump allocator + * requested by |size| + */ +uint8_t* ODK_UnpackAllocBuffer(Message* message, LengthType length, size_t size) { + uint8_t* buffer = NULL; + if (!ODK_UnpackIsNull(message) && !LengthIsNull(length)) { + buffer = BumpAllocate(LengthAsSizeT(length) * size); + } + return buffer; +} + +/* + * If the pointer was packed as NULL, return NULL. Otherwise unpack + * the array of objects into memory allocated from the bump allocator. + */ +void ODK_UnpackObjArray(Message* message, uint8_t** address, LengthType count, + size_t size, ObjUnpacker unpacker) { + if (address) { + *address = NULL; + } + if (!ODK_UnpackIsNull(message)) { + if (address && !LengthIsNull(count)) { + *address = BumpAllocate(LengthAsSizeT(count) * size); + if (*address) { + for (size_t i = 0; i < LengthAsSizeT(count); i++) { + (*unpacker)(message, (*address) + size * i); + } + } + } + } +} + +/* + * Unpack a range of memory representing an array of fundamental types + * given a pointer to a buffer and a length. The caller is responsible + * for ensuring that the buffer is large enough to handle the number + * of bytes specified by |length|. First unpack a bool that indicates + * if the pointer to the memory is NULL and if not unpack the + * requested number of bytes into the address specified by |address|. + */ +void ODK_UnpackArray(Message* message, uint8_t* address, size_t length) { + if (!ValidMessage(message) || NullCheck(message, address)) return; + uint8_t* array = NULL; + ODK_UnpackPointerToMemory(message, &array); + if (array) { + memcpy(address, array, length); + } +} + +/* + * Unpack a pointer to memory within the received message and return + * it. First unpack a bool that indicates if the address was passed in + * as NULL. If so set *address to NULL and return. Otherwise set + * *|address| to the current message read offset and unpack the length + * of the memory range. Then increment the message read offset by that + * amount. + */ +void ODK_UnpackPointerToMemory(Message* message, uint8_t** address) { + if (!ValidMessage(message) || NullCheck(message, address)) return; + if (!CheckTag(message, TAG_MEMORY)) return; + bool is_null = true; + ODK_Unpack_bool(message, &is_null); + if (is_null) { + *address = NULL; + return; + } else { + size_t length; + ODK_Unpack_size_t(message, &length); + size_t new_offset; + if (__builtin_add_overflow(message->read_offset, length, &new_offset) || + new_offset > message->size) { + message->status = MESSAGE_STATUS_OVERFLOW_ERROR; + } else { + *address = message->base + message->read_offset; + message->read_offset = new_offset; + } + } +} + +/* + * Unpack fields from |message| and use them to map a shared memory + * segment using the shared memory bump allocator. If the packed bool + * indicates that the output buffer is non-null, allocate a shared + * memory segment identified by |index| of the size indicated by + * |length|. + * + * Parameters: + * message - the message to unpack from + * index - the index that identifies which segment to map + * length - the length of the segment + * Returns: + * The address of the mapped segment + */ +uint8_t* ODK_UnpackSharedBuffer(Message* message, uint16_t index, + LengthType length) { + if (!ValidMessage(message)) return NULL; + if (!CheckTag(message, TAG_SHARED_MEMORY)) return NULL; + if (!ODK_UnpackIsNull(message)) { + return SharedMemory_Allocate(index, LengthAsSizeT(length)); + } + return NULL; +} + +/* + * In the REE, unpack fields from |message| and use them to map a + * shared memory segment using the shared memory bump allocator. If + * the packed bool indicates that the output buffer is non-null, + * allocate a shared memory segment identified by |index| of the size + * indicated by |length|. Copy the buffer from shared memory to + * the OEMCrypto API parameter. + * + * Parameters: + * message - the message to unpack from + * address - the OEMCrypto API parameter for the output buffer + * index - the index that identifies which segment to map + * length - the length of the segment + */ +void ODK_UnpackSharedOutputBuffer(Message* message, uint16_t index, + uint8_t** address, LengthType length) { + if (address && !LengthIsNull(length)) { + uint8_t* shared_address = ODK_UnpackSharedBuffer(message, index, length); + if (*address && LengthAsSizeT(length) > 0) { + memcpy(*address, shared_address, LengthAsSizeT(length)); + } + } +} + +/* end of message */ +void ODK_UnpackEOM(Message* message) { + if (!ValidMessage(message)) return; + if (!CheckTag(message, TAG_EOM)) return; + if (message->read_offset != message->size) { + message->status = MESSAGE_STATUS_END_OF_MESSAGE_ERROR; + } +} diff --git a/serialization/serialization_base.h b/serialization/serialization_base.h new file mode 100644 index 0000000..0722718 --- /dev/null +++ b/serialization/serialization_base.h @@ -0,0 +1,118 @@ +/* + * 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. + */ + +#ifndef ODKITEE_SERIALIZATION_BASE_H_ +#define ODKITEE_SERIALIZATION_BASE_H_ + +#include +#include + +#include "OEMCryptoCENC.h" +#include "message.h" +#include "shared_memory_interface.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef char* c_str; + +/* + * In the OEMCrypto API, the lengths of variable length buffers can be + * of various types: base types of size_t or uint32_t and [in] values + * or [in/out] pointers. The LengthType struct is used to pass + * lengths in a consistent way to the primitives that take lengths as + * arguments. + */ + +typedef enum { + LENGTH_TYPE_SIZE_T, + LENGTH_TYPE_UINT32_T, + LENGTH_TYPE_SIZE_T_POINTER, + LENGTH_TYPE_UINT32_T_POINTER, + LENGTH_TYPE_SIZE_T_DOUBLE_POINTER, + LENGTH_TYPE_UINT32_T_DOUBLE_POINTER +} LengthTypeTag; + +typedef struct { + LengthTypeTag tag; + union { + size_t size_t_value; + uint32_t uint32_t_value; + const size_t* size_t_pointer; + const uint32_t* uint32_t_pointer; + size_t** size_t_double_pointer; + uint32_t** uint32_t_double_pointer; + } type; +} LengthType; + +LengthType LengthFromSizeT(size_t length); +LengthType LengthFromUint32T(uint32_t length); +LengthType LengthFromSizeTPointer(const size_t* length); +LengthType LengthFromUint32TPointer(const uint32_t* length); +LengthType LengthFromSizeTDoublePointer(size_t** length); +LengthType LengthFromUint32TDoublePointer(uint32_t** length); + +size_t LengthAsSizeT(LengthType length_type); +bool LengthIsNull(LengthType length_type); + +void ODK_Pack_bool(Message* message, const bool* value); +void ODK_Pack_size_t(Message* message, const size_t* value); +void ODK_Pack_c_str(Message* message, const char* value); +void ODK_Pack_uint8_t(Message* message, const uint8_t* value); +void ODK_Pack_uint16_t(Message* message, const uint16_t* value); +void ODK_Pack_uint32_t(Message* message, const uint32_t* value); +void ODK_Pack_uint64_t(Message* message, const uint64_t* value); +bool ODK_PackBoolValue(Message* message, bool value); +bool ODK_PackIsNull(Message* message, const void* value); +void ODK_PackAlloc(Message* message, const void* address); +void ODK_PackMemory(Message* message, const uint8_t* addr, + LengthType length); +void ODK_PackArray(Message* message, const uint8_t* addr, size_t length); + +typedef void (*ObjPacker)(Message* message, const uint8_t* obj); +void ODK_PackObjArray(Message* message, const uint8_t* address, + LengthType length, size_t size, ObjPacker packer); +void ODK_PackEOM(Message* message); /* end of message */ + + +void ODK_PackSharedInputBuffer(Message* message, uint16_t index, + const uint8_t* address, const LengthType); +void ODK_PackSharedOutputBuffer(Message* message, const uint8_t* address, + LengthType length); + +void ODK_Unpack_bool(Message* message, bool* value); +void ODK_Unpack_size_t(Message* message, size_t* value); +void ODK_Unpack_c_str(Message* message, char** value); +void ODK_Unpack_uint8_t(Message* message, uint8_t* value); +void ODK_Unpack_uint16_t(Message* message, uint16_t* value); +void ODK_Unpack_uint32_t(Message* message, uint32_t* value); +void ODK_Unpack_uint64_t(Message* message, uint64_t* value); +bool ODK_UnpackBoolValue(Message* message); +bool ODK_UnpackIsNull(Message* message); +uint8_t* ODK_UnpackAlloc(Message* message, size_t size); +uint8_t* ODK_UnpackAllocBuffer(Message* message, LengthType length, + size_t size); +void ODK_UnpackArray(Message* message, uint8_t* addr, size_t length); + +typedef void (*ObjUnpacker)(Message* message, uint8_t* obj); +void ODK_UnpackObjArray(Message* message, uint8_t** address, + LengthType length, size_t size, + ObjUnpacker unpacker); +void ODK_UnpackPointerToMemory(Message* message, uint8_t** addr); +uint8_t* ODK_UnpackSharedBuffer(Message* message, uint16_t index, + LengthType length); +void ODK_UnpackSharedInputBuffer(Message* message, uint16_t index, + uint8_t** address, LengthType length); +void ODK_UnpackSharedOutputBuffer(Message* message, uint16_t index, + uint8_t** address, LengthType length); +void ODK_UnpackEOM(Message* message); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // ODKITEE_SERIALIZATION_BASE_H_ diff --git a/serialization/shared_memory_allocator.c b/serialization/shared_memory_allocator.c new file mode 100644 index 0000000..74e62d1 --- /dev/null +++ b/serialization/shared_memory_allocator.c @@ -0,0 +1,260 @@ +/* + * Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine Master + * License Agreement. + */ + +#include + +#include "shared_memory_allocator.h" +#include "shared_memory_interface.h" +#include "oemcrypto_overflow.h" + +/* + * This file implements the allocator for shared memory. Shared memory + * is managed using two different schemes. There is a memory region, + * called the "pool" that is allocated once at initialization and kept + * open for the lifetime of OEMCrypto, and discrete allocations that + * are made on each OEMCrypto call where additional shared memory is + * required. + * + * Every shared memory allocation is identified by an index number, + * which is provided by the caller. Allowing the caller to specify the + * index allows the code generator to refer to specific regions + * explicitly, which is needed to correlate segments across + * serialization endpoints. The index numbers start from 0. Given an + * index number, the address and size of the allocation can be + * returned. The code generator requires that the allocation algorithm + * be deterministic and repeatable, i.e. that a specific sequence of + * allocations when replayed after a reset will result in the same + * shared memory regions being mapped to the same indexes. + * + * The memory pool is managed with a bump allocator. The pool is + * allocated from the porting layer's ODK_SharedMemory interface. The + * pool is divided into "segments" which are allocated consecutively + * from the pool by AllocateSegment. The allocator is reset before + * each api call, which removes all segments. + * + * Shared memory allocations that are too large to put in the pool are + * allocated directly from ODK_SharedMemory and are released at the + * end of each OEMCrypto call. A threshold is defined (e.g. pool + * size/4) that determines whether allocations are from the pool or + * from the discrete regions. + */ + +/* Region ID for the shared memory pool */ +#define SHARED_MEMORY_POOL_REGION_ID 0 + +/* The ID of the next discrete region to allocate */ +static size_t next_discrete_region_id_ = SHARED_MEMORY_POOL_REGION_ID + 1; + +/* + * Descriptor for a segment allocated from the pool. + */ +typedef struct { + uint32_t size; + uint32_t offset; +} Segment; + +/* + * Descriptor for an allocation, which may be either from the pool + * or from a discrete region. + */ +typedef enum {FREE, POOL_SEGMENT, DISCRETE_REGION} AllocationType; +typedef struct { + AllocationType type; + union { + Segment segment; + ODK_SharedHandle* handle; + } u; +} Allocation; + +/* + * Maximum number of allocations allowed. Indexes go from 0 to + * MAX_ALLOCATIONS - 1 + */ +#define MAX_ALLOCATIONS 16 +static Allocation allocations_[MAX_ALLOCATIONS]; + +/* + * Shared memory handle for the bump allocator pool + */ +static ODK_SharedHandle *pool_handle_; + +/* + * The offset from pool_address of the next segment that will be + * allocated. + */ +static size_t next_segment_offset_ = 0; + +/* + * Initial size of the memory pool + */ +static size_t pool_size_ = 0; + +/* + * Initialize shared memory state variables. Set the initial pool size + * to the specified value. + */ +void SharedMemory_Initialize(size_t pool_size) { + ODK_SharedMemory_Initialize(); + memset(&allocations_[0], 0, sizeof(allocations_)); + pool_size_ = pool_size; + pool_handle_ = NULL; + next_discrete_region_id_ = SHARED_MEMORY_POOL_REGION_ID + 1; +} + +/* + * Release all shared memory resources from the current process. + */ +void SharedMemory_Terminate(void) { + SharedMemory_Reset(); + ODK_SharedMemory_Free(pool_handle_); + pool_handle_ = NULL; + ODK_SharedMemory_Terminate(); +} + + +/* + * Allocate shared memory as a discrete region + */ +static uint8_t* AllocateAsRegion(uint16_t index, size_t size) { + ODK_SharedHandle* handle = + ODK_SharedMemory_Allocate(next_discrete_region_id_, size); + if (handle) { + Allocation* alloc = &allocations_[index]; + alloc->type = DISCRETE_REGION; + alloc->u.handle = handle; + next_discrete_region_id_++; + } + return ODK_SharedMemory_GetAddress(handle); +} + +/* + * Allocate a segment of shared memory from the pool + */ +static uint8_t* AllocateFromPool(uint16_t index, size_t size) { + if (!pool_handle_) { + pool_handle_ = ODK_SharedMemory_Allocate(SHARED_MEMORY_POOL_REGION_ID, + pool_size_); + if (!pool_handle_) { + return NULL; + } + next_segment_offset_ = 0; + } + size_t new_offset = 0; + if (AddOverflowUX(next_segment_offset_, size, &new_offset)) { + return NULL; + } + if (new_offset > ODK_SharedMemory_GetSize(pool_handle_)) { + return AllocateAsRegion(index, size); + } + uint8_t* segment_address = + ODK_SharedMemory_GetAddress(pool_handle_) + next_segment_offset_; + + Allocation* alloc = &allocations_[index]; + alloc->type = POOL_SEGMENT; + Segment* segment = &alloc->u.segment; + segment->size = size; + segment->offset = next_segment_offset_; + next_segment_offset_ = new_offset; + return segment_address; +} + +/* + * Allocate shared memory from either the pool or a discrete region. + * If the requested memory size is larger than 1/4 of the pool size, or + * if the pool is full, allocate as a discrete region. + * + * Parameters: + * index - the index number of the allocation, assigned by the caller. + * indexes start at 0. The index cannot exceed MAX_ALLOCATIONS. + * + * Returns: + * The address of the allocation or NULL if the index has already + * been allocated or allocation fails. + */ +uint8_t* SharedMemory_Allocate(uint16_t index, size_t size) { + if (index >= MAX_ALLOCATIONS || allocations_[index].type != FREE) { + return NULL; + } + if (size <= pool_size_ / 4) { + return AllocateFromPool(index, size); + } else { + return AllocateAsRegion(index, size); + } +} + +/* + * Get the size of a shared memory segment. + * + * Parameters: + * index - identifies the allocation. Valid values are + * 0..MAX_ALLOCATIONS-1 + * + * Returns: + * The size of the allocation indicated by |index| or 0 if the + * index is invalid or no matching allocation was found + */ +size_t SharedMemory_GetSize(uint16_t index) { + if (index >= MAX_ALLOCATIONS) { + return 0; + } + Allocation* alloc = &allocations_[index]; + switch (alloc->type) { + case DISCRETE_REGION: + return ODK_SharedMemory_GetSize(alloc->u.handle); + case POOL_SEGMENT: + return alloc->u.segment.size; + default: + break; + } + return 0; +} + +/* + * Get the address of a shared memory segment. + * + * Parameters: + * index - identifies the allocation. Valid values are + * 0..MAX_ALLOCATIONS-1 + * + * Returns: + * The address of the allocation indicated by |index| or NULL if the + * index is invalid or no matching allocation was found + */ +uint8_t* SharedMemory_GetAddress(uint16_t index) { + if (index >= MAX_ALLOCATIONS) { + return NULL; + } + Allocation* alloc = &allocations_[index]; + switch (alloc->type) { + case DISCRETE_REGION: + return ODK_SharedMemory_GetAddress(alloc->u.handle); + case POOL_SEGMENT: + if (!pool_handle_) { + return NULL; + } + return ODK_SharedMemory_GetAddress(pool_handle_) + + alloc->u.segment.offset; + default: + break; + } + return NULL; +} + +/* + * Set the allocator to its initial state, where there are no segments + * allocated from the pool and there are no discrete allocations. + */ +void SharedMemory_Reset(void) { + next_segment_offset_ = 0; + for (size_t i = 0; i < MAX_ALLOCATIONS; i++) { + Allocation* alloc = &allocations_[i]; + if (alloc->type == DISCRETE_REGION) { + ODK_SharedMemory_Free(alloc->u.handle); + } + } + memset(&allocations_[0], 0, sizeof(allocations_)); + next_discrete_region_id_ = SHARED_MEMORY_POOL_REGION_ID + 1; +} diff --git a/serialization/shared_memory_allocator.h b/serialization/shared_memory_allocator.h new file mode 100644 index 0000000..9c57302 --- /dev/null +++ b/serialization/shared_memory_allocator.h @@ -0,0 +1,31 @@ +/* + * Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine Master + * License Agreement. + */ + +#ifndef ODKITEE_SHARED_MEMORY_ALLOCATOR_H_ +#define ODKITEE_SHARED_MEMORY_ALLOCATOR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* + * An allocator for shared memory + */ +void SharedMemory_Initialize(size_t initial_pool_size); +uint8_t* SharedMemory_Allocate(uint16_t index, size_t size); +size_t SharedMemory_GetSize(uint16_t index); +uint8_t* SharedMemory_GetAddress(uint16_t index); +void SharedMemory_Reset(void); +void SharedMemory_Terminate(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif //ODKITEE_SHARED_MEMORY_ALLOCATOR_H_ diff --git a/serialization/shared_memory_interface.h b/serialization/shared_memory_interface.h new file mode 100644 index 0000000..d14abe0 --- /dev/null +++ b/serialization/shared_memory_interface.h @@ -0,0 +1,117 @@ +/* + * Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine Master + * License Agreement. + */ + +#ifndef ODKITEE_SHARED_MEMORY_INTERFACE_H_ +#define ODKITEE_SHARED_MEMORY_INTERFACE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* + * This is the interface to shared memory that must be implemented in + * a port for a specific trusted OS. The interface defines functions + * to allocate, access and free regions of shared memory. + * + * Shared memory regions are defined by an address and a size. Regions + * are allocated by specifying an integer |region_id| that is used to + * correlate remote and local mappings. When a region is created, the + * implementation returns an ODK_SharedHandle which is used by callers + * when accessing the region. + * + * Each shared memory implementation defines its own _ODK_SharedHandle + * struct to hold the data needed to represent a shared memory region. + */ +typedef struct _ODK_SharedHandle ODK_SharedHandle; + +/* + * Shared memory regions are identified with an id that correlates the + * remote and local mappings. + */ +typedef uint16_t ODK_SharedRegionId; + +/* + * Note that the shared memory implementation must be initialized + * prior to calling any OEMCrypto API functions because it needs to be + * available when communicating with the TEE. Typically it would be + * initialized on service startup. + */ + +/* + * Initialize the shared memory implementation, must be called prior + * to using any other ODK_SharedMemory functions. This function will + * be called by the dispatcher on the TEE side at startup. On the REE + * side it must be called by the service that is calling OEMCrypto + * because the communication with the TEE needs to be established + * before any OEMCrypto calls are made. + */ +void ODK_SharedMemory_Initialize(void); + +/* + * Terminate the shared memory implementation, releasing any resources + * in use. + */ +void ODK_SharedMemory_Terminate(void); + +/* + * Allocate a region of shared memory of |size| bytes. Regions are + * allocated based on a specified id that is used to correlate remote + * and local mappings. The shared memory region must remain mapped + * until released by ODK_SharedMemory_Free. + * + * Parameters: + * region_id - identifies the region to allocate + * size - the size of the memory region to allocate + * + * Returns: + * A pointer to an ODK_SharedHandle which refers to the allocated + * shared memory, or NULL if allocation fails. The memory for the + * handle is owned by the implementation. The handle must remain + * valid for as long as the shared memory region is allocated. + */ +ODK_SharedHandle* ODK_SharedMemory_Allocate(ODK_SharedRegionId region_id, + size_t size); + +/* + * Return the address that a shared memory handle is mapped to. + * + * Parameters: + * handle - the shared handle for which an address is requested + * + * Returns: + * The address of the shared memory region refered by |handle| + */ +uint8_t* ODK_SharedMemory_GetAddress(ODK_SharedHandle* handle); + +/* + * Return the size of a shared memory region + * + * Parameters: + * handle - the shared handle for which the region size is requested + * + * Returns: + * The size of the shared memory region refered by |handle| + */ +size_t ODK_SharedMemory_GetSize(ODK_SharedHandle* handle); + +/* + * Release a handle for a previously allocated region of shared memory. + * The memory is unmapped and any associated resources are released. + * + * Parameters: + * address - the address of the shared memory region to release + */ +void ODK_SharedMemory_Free(ODK_SharedHandle* handle); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif //ODKITEE_SHARED_MEMORY_INTERFACE_H_ diff --git a/serialization/special_case_apis.c b/serialization/special_case_apis.c new file mode 100644 index 0000000..1713027 --- /dev/null +++ b/serialization/special_case_apis.c @@ -0,0 +1,131 @@ +/* + * 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 "special_cases.h" + +#include +#include +#include +#include + +#include "api_support.h" +#include "deserializer.h" +#include "OEMCryptoCENC.h" +#include "serialization_base.h" +#include "shared_memory_allocator.h" +#include "shared_memory_interface.h" +#include "serializer.h" + +/* + * Special case API functions. DecryptCENC and CopyBuffer have the + * |out_buffer| parameter of type OEMCrypt_DestBufferDesc. If the + * destination is to non-secure memory, the output data needs to be + * copied out from shared memory to the provided destination buffer. + * The length of the data is given by the seemingly unrelated input + * parameter data_addr_length so it's difficult to auto-generate these + * functions. + * + * To update these functions when the api generator changes, remove them + * from special_case_config.cpp, build, then copy the generated code + * from oemcrypto_api.c and apply the manual edits. + */ +OEMCRYPTO_API OEMCryptoResult OEMCrypto_DecryptCENC( + OEMCrypto_SESSION session, const SharedMemory *data_addr, + size_t data_addr_length, bool is_encrypted, const uint8_t *iv, + size_t block_offset, OEMCrypto_DestBufferDesc *out_buffer, + const OEMCrypto_CENCEncryptPatternDesc *pattern, uint8_t subsample_flags) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message *request = API_InitializeRequest(); + Message *response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_DecryptCENC_Request(request, session, data_addr, data_addr_length, is_encrypted, + iv, block_offset, out_buffer, pattern, subsample_flags); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_DecryptCENC_Response(response, &result, &out_buffer); + + /* Only this block is hand coded */ + if (result == OEMCrypto_SUCCESS) { + if (out_buffer->type == OEMCrypto_BufferType_Clear) { + uint8_t* shared_address = SharedMemory_GetAddress(DEST_BUFFER_INDEX); + if (data_addr_length <= SharedMemory_GetSize(DEST_BUFFER_INDEX)) { + memcpy(out_buffer->buffer.clear.address, shared_address, data_addr_length); + } else { + result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + } + } + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + pthread_mutex_unlock(&api_lock); + return API_CheckResult(result); +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_CopyBuffer( + OEMCrypto_SESSION session, const SharedMemory *data_addr, + size_t data_addr_length, OEMCrypto_DestBufferDesc *out_buffer, + uint8_t subsample_flags) { + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + pthread_mutex_lock(&api_lock); + Message *request = API_InitializeRequest(); + Message *response = NULL; + if (!request) { + goto cleanup_and_return; + } + ODK_Pack_CopyBuffer_Request(request, session, data_addr, data_addr_length, + out_buffer, subsample_flags); + if (GetStatus(request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(request); + if (!response) { + goto cleanup_and_return; + } + ODK_Unpack_CopyBuffer_Response(response, &result, &out_buffer); + + if (GetStatus(response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + + /* Only this block is hand coded */ + if (result == OEMCrypto_SUCCESS) { + if (out_buffer->type == OEMCrypto_BufferType_Clear) { + uint8_t* shared_address = SharedMemory_GetAddress(DEST_BUFFER_INDEX); + memcpy(out_buffer->buffer.clear.address, shared_address, data_addr_length); + } + } +cleanup_and_return: + if (request) { + ODK_Transport_DeallocateMessage(request); + } + if (response) { + ODK_Transport_DeallocateMessage(response); + } + pthread_mutex_unlock(&api_lock); + return API_CheckResult(result); +} diff --git a/serialization/special_cases.c b/serialization/special_cases.c new file mode 100644 index 0000000..125ca45 --- /dev/null +++ b/serialization/special_cases.c @@ -0,0 +1,202 @@ +/* + * 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 "special_cases.h" + +#include +#include +#include +#include + +#include "deserializer.h" +#include "OEMCryptoCENC.h" +#include "serialization_base.h" +#include "shared_memory_allocator.h" +#include "shared_memory_interface.h" +#include "serializer.h" + +/* + * Special cases due to union & shared memory + */ + +/* + * Pack the destination buffer parameter to OEMCrypto_DecryptCENC and + * OEMCrypto_CopyBuffer + */ +void ODK_Pack_OEMCrypto_DestBufferDesc(Message* message, + const OEMCrypto_DestBufferDesc* obj) { + if (obj == NULL) { + SetStatus(message, MESSAGE_STATUS_NULL_POINTER_ERROR); + return; + } + ODK_Pack_uint32_t(message, (uint32_t*)&obj->type); + switch (obj->type) { + case OEMCrypto_BufferType_Clear: { + ODK_Pack_size_t(message, &obj->buffer.clear.max_length); + ODK_PackSharedOutputBuffer(message, obj->buffer.clear.address, + LengthFromSizeT(obj->buffer.clear.max_length)); + break; + } + case OEMCrypto_BufferType_Secure: + /* secure memory - pass handle, length, offset */ + ODK_Pack_uint64_t(message, (uint64_t*)&obj->buffer.secure.handle); + ODK_Pack_size_t(message, &obj->buffer.secure.max_length); + ODK_Pack_size_t(message, &obj->buffer.secure.offset); + break; + case OEMCrypto_BufferType_Direct: + ODK_Pack_bool(message, &obj->buffer.direct.is_video); + break; + } +} + +/* + * Unpack the destination buffer parameter to OEMCrypto_DecryptCENC and + * OEMCrypto_CopyBuffer + */ +void ODK_Unpack_OEMCrypto_DestBufferDesc(Message* message, + OEMCrypto_DestBufferDesc* obj) { + if (obj == NULL) { + SetStatus(message, MESSAGE_STATUS_NULL_POINTER_ERROR); + return; + } + ODK_Unpack_uint32_t(message, (uint32_t*)&obj->type); + switch (obj->type) { + case OEMCrypto_BufferType_Clear: { + ODK_Unpack_size_t(message, &obj->buffer.clear.max_length); + uint8_t* shared_address = + ODK_UnpackSharedBuffer(message, DEST_BUFFER_INDEX, + LengthFromSizeT(obj->buffer.clear.max_length)); + if (!obj->buffer.clear.address) { + // unpacking request in TEE - set the address to shared memory + obj->buffer.clear.address = shared_address; + } + break; + } + case OEMCrypto_BufferType_Secure: + /* secure memory handle - deal with later */ + ODK_Unpack_uint64_t(message, (uint64_t*)&obj->buffer.secure.handle); + ODK_Unpack_size_t(message, &obj->buffer.secure.max_length); + ODK_Unpack_size_t(message, &obj->buffer.secure.offset); + break; + case OEMCrypto_BufferType_Direct: + ODK_Unpack_bool(message, &obj->buffer.direct.is_video); + break; + } +} + +/* + * Special serialization cases due to some parameters being defined as + * pointers into other parameters. + */ + +void ODK_Pack_RewrapDeviceRSAKey_Request( + Message* msg, OEMCrypto_SESSION session, + const uint8_t* message, + size_t message_length, + const uint8_t* signature, + size_t signature_length, + const uint32_t* unaligned_nonce, + const uint8_t* enc_rsa_key, + size_t enc_rsa_key_length, + const uint8_t* enc_rsa_key_iv, + const uint8_t* wrapped_rsa_key, + const size_t* wrapped_rsa_key_length) { + uint32_t api_value = 18; /* from _oecc18 */ + ODK_Pack_uint32_t(msg, &api_value); + ODK_Pack_size_t(msg, &message_length); + ODK_Pack_size_t(msg, &signature_length); + ODK_Pack_size_t(msg, &enc_rsa_key_length); + ODK_PackNullable_size_t(msg, wrapped_rsa_key_length); + ODK_Pack_uint32_t(msg, &session); + ODK_PackSharedInputBuffer(msg, 0, message, LengthFromSizeT(message_length)); + ODK_PackSharedInputBuffer(msg, 1, signature, LengthFromSizeT(signature_length)); + + size_t unaligned_nonce_offset = 0; + if (__builtin_sub_overflow((uintptr_t)unaligned_nonce, (uintptr_t)message, + &unaligned_nonce_offset)) { + SetStatus(msg, MESSAGE_STATUS_PARSE_ERROR); + return; + } + ODK_Pack_size_t(msg, &unaligned_nonce_offset); + + size_t enc_rsa_key_offset = 0; + if (__builtin_sub_overflow((uintptr_t)enc_rsa_key, (uintptr_t)message, + &enc_rsa_key_offset)) { + SetStatus(msg, MESSAGE_STATUS_PARSE_ERROR); + return; + } + ODK_Pack_size_t(msg, &enc_rsa_key_offset); + + size_t enc_rsa_key_iv_offset = 0; + if (__builtin_sub_overflow((uintptr_t)enc_rsa_key_iv, (uintptr_t)message, + &enc_rsa_key_iv_offset)) { + SetStatus(msg, MESSAGE_STATUS_PARSE_ERROR); + return; + } + ODK_Pack_size_t(msg, &enc_rsa_key_iv_offset); + ODK_PackAlloc(msg, wrapped_rsa_key); + ODK_PackEOM(msg); +} + +void ODK_Unpack_RewrapDeviceRSAKey_Request( + Message* msg, OEMCrypto_SESSION* session, + SharedMemory** message, + size_t* message_length, + SharedMemory** signature, + size_t* signature_length, + uint32_t** unaligned_nonce, + uint8_t** enc_rsa_key, + size_t* enc_rsa_key_length, + uint8_t** enc_rsa_key_iv, + uint8_t** wrapped_rsa_key, + size_t** wrapped_rsa_key_length) { + uint32_t api_value = ~(uint32_t)0; + ODK_Unpack_uint32_t(msg, &api_value); + if (api_value != 18) SetStatus(msg, MESSAGE_STATUS_API_VALUE_ERROR); + ODK_Unpack_size_t(msg, message_length); + ODK_Unpack_size_t(msg, signature_length); + ODK_Unpack_size_t(msg, enc_rsa_key_length); + ODK_UnpackNullable_size_t(msg, wrapped_rsa_key_length); + ODK_Unpack_uint32_t(msg, session); + ODK_UnpackSharedBuffer(msg, 0, LengthFromSizeTPointer(message_length)); + ODK_UnpackSharedBuffer(msg, 1, LengthFromSizeTPointer(signature_length)); + *message = SharedMemory_GetAddress(0); + *signature = SharedMemory_GetAddress(1); + + size_t unaligned_nonce_offset = 0; + uintptr_t unaligned_nonce_ptr = 0; + ODK_Unpack_size_t(msg, &unaligned_nonce_offset); + if (__builtin_add_overflow((uintptr_t)*message, unaligned_nonce_offset, + &unaligned_nonce_ptr)) { + SetStatus(msg, MESSAGE_STATUS_PARSE_ERROR); + return; + } + *unaligned_nonce = (uint32_t*)unaligned_nonce_ptr; + + size_t enc_rsa_key_offset = 0; + uintptr_t enc_rsa_key_ptr = 0; + ODK_Unpack_size_t(msg, &enc_rsa_key_offset); + if (__builtin_add_overflow((uintptr_t)*message, enc_rsa_key_offset, + &enc_rsa_key_ptr)) { + SetStatus(msg, MESSAGE_STATUS_PARSE_ERROR); + return; + } + *enc_rsa_key = (uint8_t*)enc_rsa_key_ptr; + + size_t enc_rsa_key_iv_offset = 0; + uintptr_t enc_rsa_key_iv_ptr = 0; + ODK_Unpack_size_t(msg, &enc_rsa_key_iv_offset); + if (__builtin_add_overflow((uintptr_t)*message, enc_rsa_key_iv_offset, + &enc_rsa_key_iv_ptr)) { + SetStatus(msg, MESSAGE_STATUS_PARSE_ERROR); + return; + } + *enc_rsa_key_iv = (uint8_t*)enc_rsa_key_iv_ptr; + *wrapped_rsa_key = (uint8_t*)ODK_UnpackAllocBuffer( + msg, LengthFromSizeTDoublePointer(wrapped_rsa_key_length), + sizeof(uint8_t)); + ODK_UnpackEOM(msg); +} diff --git a/serialization/special_cases.h b/serialization/special_cases.h new file mode 100644 index 0000000..d9b08ce --- /dev/null +++ b/serialization/special_cases.h @@ -0,0 +1,64 @@ +/* + * 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. + */ + +#ifndef ODKITEE_SPECIAL_CASES_H_ +#define ODKITEE_SPECIAL_CASES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "OEMCryptoCENC.h" +#include "message.h" + +/* shared memory index used for destination buffers */ +#define DEST_BUFFER_INDEX 3 + +/* + * Special cases due to union & shared memory + */ +void ODK_Pack_OEMCrypto_DestBufferDesc(Message* msg, + const OEMCrypto_DestBufferDesc* obj); +void ODK_Unpack_OEMCrypto_DestBufferDesc(Message* msg, + OEMCrypto_DestBufferDesc* obj); + +/* + * Special cases due to parameters defined as having pointers into other parameters + */ +void ODK_Pack_RewrapDeviceRSAKey_Request( + Message* msg, OEMCrypto_SESSION session, + const uint8_t* message, + size_t message_length, + const uint8_t* signature, + size_t signature_length, + const uint32_t* unaligned_nonce, + const uint8_t* enc_rsa_key, + size_t enc_rsa_key_length, + const uint8_t* enc_rsa_key_iv, + const uint8_t* wrapped_rsa_key, + const size_t* wrapped_rsa_key_length); + +void ODK_Unpack_RewrapDeviceRSAKey_Request( + Message* msg, OEMCrypto_SESSION* session, + SharedMemory** message, + size_t* message_length, + SharedMemory** signature, + size_t* signature_length, + uint32_t** unaligned_nonce, + uint8_t** enc_rsa_key, + size_t* enc_rsa_key_length, + uint8_t** enc_rsa_key_iv, + uint8_t** wrapped_rsa_key, + size_t** wrapped_rsa_key_length); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // ODKITEE_SPECIAL_CASES_H_ diff --git a/serialization/transport_interface.h b/serialization/transport_interface.h new file mode 100644 index 0000000..0b559f3 --- /dev/null +++ b/serialization/transport_interface.h @@ -0,0 +1,116 @@ +/* + * 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. + */ + +#ifndef ODKITEE_TRANSPORT_INTERFACE_H_ +#define ODKITEE_TRANSPORT_INTERFACE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The Transport Interface is used by the oemcrypto library running + * on the REE side/HLOS. It connects liboemcrypto to the trusted + * OS's method of transporting data between the REE and the TEE. + * + * The trusted OS must provide primitives to transport data segments + * between the REE and TEE. The maximum size of the data segments may + * be fixed and predetermined by the trusted OS. However, the + * transport implementation must be able to append data segments + * sequentially to transport arbitrarily sized messages. For example + * if the maximum block size is 2 KiB and a message is serialized that + * requires 6 KiB, the transport layer must be able to extend the + * messsage to three logically consecutive 2 KiB segments during + * serialization to contain the message. Messages may be initially + * allocated at any block size. The serialization layer will call back + * into the transport layer to request that additional blocks be added + * to the message as needed. The serialization layer will attempt to + * minimize the actual size of messages by passing larger parameters + * in shared memory, if supported by the trusted OS. + * + * Functions need to be provided to allocate, extend and deallocate + * messages, and send and receive messages between the REE and the + * TEE. + */ + +typedef enum { + /* + * ODK_TRANSPORT_STATUS_OK must be returned from transport functions + * if the requested operation completed succesfully. + */ + ODK_TRANSPORT_STATUS_OK, + + /* + * ODK_TRANSPORT_STATUS_ALLOC_FAILED must be returned from + * ODK_Transport_ExtendMessage if there is insufficient memory. This + * is a fatal failure that will cause OEMCrypto to return + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES. + */ + ODK_TRANSPORT_STATUS_ALLOC_FAILED, + + /* + * ODK_TRANSPORT_STATUS_IO_ERROR must be returned from + * ODK_Transport_SendMessage or ODK_Transport_ReceiveMessage if the + * transport interface was unable to deliver or receive a message + * for any reason. The transport implementation should be designed + * to be robust against communication failures, e.g. by providing + * logic to retry delivery or other techniques if possible. The + * odkitee library does not make any attempts to improve + * communcation reliability using these techniques. + * + * This return code indicates a fatal failure of the current command + * which will result in OEMCrypto returning + * OEMCrypto_ERROR_SYSTEM_INVALIDATED. This will cause the app to be + * notified that the drm system must be reinitialized. + */ + ODK_TRANSPORT_STATUS_IO_ERROR, +} ODK_Transport_Status; + +/* + * Allocate a new message of a size that is determined by the + * transport implementation, which is most likely the maximum data + * segment transport size of the trusted OS. The message will be + * subsequently extended if it is too small for the message currently + * being serialized. Must return NULL if the transport implementation + * is unable to allocate a message of any size. Only two messages will + * be simultaneously allocated at any time. + */ +Message* ODK_Transport_AllocateMessage(void); + +/* + * Extend an existing message to a new size. The new size is the total + * required size of the message including the currently allocation + * portion. Return ODK_TRANSPORT_STATUS_ALLOC_FAILED if the transport + * interface is unable to extend the message to the new size. + */ +ODK_Transport_Status ODK_Transport_ExtendMessage(Message* message, size_t new_size); + +/* + * Request that a message be delivered from the REE to the TEE. If the + * delivery is successful ODK_TRANSPORT_STATUS_OK must be returned. + * Otherwise return ODK_TRANSPORT_STATUS_IO_ERROR. + */ +ODK_Transport_Status ODK_Transport_SendMessage(Message* message); + +/* + * Request that a message be received by the REE from the TEE. If + * the receipt is successful ODK_TRANSPORT_STATUS_OK must be returned. + * Otherwise return ODK_TRANSPORT_STATUS_IO_ERROR. + */ +ODK_Transport_Status ODK_Transport_ReceiveMessage(Message** message); + +/* + * Return a message that is not longer in use to the transport + * interface. + */ +void ODK_Transport_DeallocateMessage(Message* message); + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* ODKITEE_TRANSPORT_INTERFACE_H_ */