Files
android/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp
Alex Dale fe28d4cafc [DO NOT MERGE] Revert "Restructed reference root of trust (3/3 OEM Cert)"
This reverts commit 9f7e2c4413.

Reason for revert: Feature missed deadline

Bug: 135283522
Change-Id: I63eb0431762fd13c64bef926fb1e64b6edacb156
2021-05-17 19:08:53 +00:00

1770 lines
69 KiB
C++

// 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.
//
// Reference implementation of OEMCrypto APIs
//
#include "OEMCryptoCENC.h"
#include <assert.h>
#include <openssl/cmac.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <chrono>
#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include "file_store.h"
#include "log.h"
#include "odk.h"
#include "oemcrypto_engine_ref.h"
#include "oemcrypto_session.h"
#include "oemcrypto_usage_table_ref.h"
#include "string_conversions.h"
#if defined(_WIN32)
# define OEMCRYPTO_API extern "C" __declspec(dllexport)
#else // defined(_WIN32)
# define OEMCRYPTO_API extern "C" __attribute__((visibility("default")))
#endif // defined(_WIN32)
namespace {
const uint8_t kBakedInCertificateMagicBytes[] = {0xDE, 0xAD, 0xBE, 0xEF};
// Maximum context key length used for performance reasons, not mandated by
// specification.
const size_t kMaxContextKeyLength = 1024 * 1024;
// Maximum buffer length used by reference implementation for performance
// reasons. This is not mandated by specification.
const size_t kMaxInputMessageBuferLength = 1024 * 1024;
// Maximum signature length used by reference implementation for performance
// reasons. This is not mandated by specification.
const size_t kMaxInputSignatureLength = 10 * 1024;
// Return uint32 referenced through a potentially unaligned pointer.
// If the pointer is nullptr, return 0.
uint32_t unaligned_dereference_uint32(const void* unaligned_ptr) {
if (unaligned_ptr == nullptr) return 0;
uint32_t value;
const uint8_t* src = reinterpret_cast<const uint8_t*>(unaligned_ptr);
uint8_t* dest = reinterpret_cast<uint8_t*>(&value);
for (unsigned long i = 0; i < sizeof(value); i++) {
dest[i] = src[i];
}
return value;
}
} // namespace
namespace wvoec_ref {
static std::unique_ptr<CryptoEngine> crypto_engine;
typedef struct {
uint8_t signature[wvoec::MAC_KEY_SIZE];
uint8_t context[wvoec::MAC_KEY_SIZE];
uint8_t iv[wvoec::KEY_IV_SIZE];
uint8_t enc_rsa_key[];
} WrappedRSAKey;
OEMCRYPTO_API OEMCryptoResult OEMCrypto_Initialize(void) {
if (crypto_engine != nullptr) {
LOGE("------------------------- Calling Initialize without Terminate\n");
crypto_engine.reset();
}
// NOTE: This requires a compatible Filesystem implementation.
// NOTE: Ownership of the FileSystem object is transferred to CryptoEngine
std::unique_ptr<wvcdm::FileSystem> fs(new wvcdm::FileSystem());
crypto_engine.reset(CryptoEngine::MakeCryptoEngine(std::move(fs)));
if (crypto_engine == nullptr || !crypto_engine->Initialize()) {
LOGE("[OEMCrypto_Initialize(): failed]");
return OEMCrypto_ERROR_INIT_FAILED;
}
return OEMCrypto_SUCCESS;
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_SetSandbox(
const uint8_t* /*sandbox_id*/, size_t /*sandbox_id_length*/) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_Terminate(void) {
if (crypto_engine == nullptr) {
LOGE("[OEMCrypto_Terminate(): not initialized]");
return OEMCrypto_ERROR_TERMINATE_FAILED;
}
crypto_engine->Terminate();
crypto_engine.reset();
return OEMCrypto_SUCCESS;
}
OEMCRYPTO_API OEMCryptoResult
OEMCrypto_OpenSession(OEMCrypto_SESSION* session) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_OpenSession: OEMCrypto not initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (crypto_engine->GetNumberOfOpenSessions() >=
crypto_engine->GetMaxNumberOfSessions()) {
LOGE("[OEMCrypto_OpenSession(): failed due to too many sessions]");
return OEMCrypto_ERROR_TOO_MANY_SESSIONS;
}
SessionId sid = crypto_engine->OpenSession();
if (sid == 0) {
LOGE("OEMCrypto_OpenSession: invalid session id returned.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
*session = (OEMCrypto_SESSION)sid;
return OEMCrypto_SUCCESS;
}
OEMCRYPTO_API OEMCryptoResult
OEMCrypto_CloseSession(OEMCrypto_SESSION session) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_CloseSession: OEMCrypto not initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->DestroySession((SessionId)session)) {
return OEMCrypto_ERROR_CLOSE_SESSION_FAILED;
} else {
return OEMCrypto_SUCCESS;
}
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateDerivedKeys(
OEMCrypto_SESSION session, 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 (crypto_engine == nullptr) {
LOGE("OEMCrypto_GenerateDerivedKeys: OEMCrypto not initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
if (mac_key_context_length > kMaxContextKeyLength ||
enc_key_context_length > kMaxContextKeyLength) {
LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_BUFFER_TOO_LARGE]");
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
const std::vector<uint8_t> mac_ctx_str(
mac_key_context, mac_key_context + mac_key_context_length);
const std::vector<uint8_t> enc_ctx_str(
enc_key_context, enc_key_context + enc_key_context_length);
// Generate mac and encryption keys for current session context
return session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), mac_ctx_str,
enc_ctx_str);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session,
uint32_t* nonce) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_GenerateNonce: OEMCrypto not initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_GenerateNonce(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
// Prevent nonce flood.
static std::chrono::steady_clock clock;
const auto now = clock.now().time_since_epoch();
static auto last_nonce_time = now;
// For testing, we set nonce_flood_count to 1. Since count is initialized to
// 1, the very first nonce after initialization is counted as a flood.
static int nonce_count = 1;
if (now - last_nonce_time < std::chrono::seconds(1)) {
nonce_count++;
if (nonce_count > crypto_engine->nonce_flood_count()) {
LOGE("[OEMCrypto_GenerateNonce(): Nonce Flood detected]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
} else {
nonce_count = 1;
last_nonce_time = now;
}
uint32_t nonce_value = 0;
uint8_t* nonce_string = reinterpret_cast<uint8_t*>(&nonce_value);
while (nonce_value == 0 || crypto_engine->NonceCollision(nonce_value)) {
// Generate 4 bytes of random data
if (RAND_bytes(nonce_string, 4) != 1) {
LOGE("[OEMCrypto_GenerateNonce(): Random bytes failure]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
if (!session_ctx->set_nonce(nonce_value)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
*nonce = nonce_value;
return OEMCrypto_SUCCESS;
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_PrepAndSignLicenseRequest(
OEMCrypto_SESSION session, uint8_t* message, size_t message_length,
size_t* core_message_length, uint8_t* signature, size_t* signature_length) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("OEMCrypto_ERROR_INVALID_SESSION");
return OEMCrypto_ERROR_INVALID_SESSION;
}
return session_ctx->PrepAndSignLicenseRequest(message, message_length,
core_message_length, signature,
signature_length);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_PrepAndSignRenewalRequest(
OEMCrypto_SESSION session, uint8_t* message, size_t message_length,
size_t* core_message_length, uint8_t* signature, size_t* signature_length) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("OEMCrypto_ERROR_INVALID_SESSION");
return OEMCrypto_ERROR_INVALID_SESSION;
}
return session_ctx->PrepAndSignRenewalRequest(message, message_length,
core_message_length, signature,
signature_length);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_PrepAndSignProvisioningRequest(
OEMCrypto_SESSION session, uint8_t* message, size_t message_length,
size_t* core_message_length, uint8_t* signature, size_t* signature_length) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("OEMCrypto_ERROR_INVALID_SESSION");
return OEMCrypto_ERROR_INVALID_SESSION;
}
return session_ctx->PrepAndSignProvisioningRequest(
message, message_length, core_message_length, signature,
signature_length);
}
bool RangeCheck(const uint8_t* message, uint32_t message_length,
const uint8_t* field, uint32_t field_length, bool allow_null) {
if (field == nullptr) return allow_null;
if (field < message) return false;
if (field + field_length > message + message_length) return false;
return true;
}
bool RangeCheck(uint32_t message_length, const OEMCrypto_Substring& substring,
bool allow_null) {
if (!substring.length) return allow_null;
if (substring.offset > message_length) return false;
if (substring.offset + substring.length > message_length) return false;
return true;
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadLicense(OEMCrypto_SESSION session,
const uint8_t* message,
size_t message_length,
size_t core_message_length,
const uint8_t* signature,
size_t signature_length) {
if (crypto_engine == nullptr) {
LOGE("not initialized");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (message == nullptr || message_length == 0 || signature == nullptr ||
signature_length == 0) {
LOGE("OEMCrypto_ERROR_INVALID_CONTEXT");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("ERROR_KEYBOX_INVALID");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("ERROR_INVALID_SESSION sid=%u", session);
return OEMCrypto_ERROR_INVALID_SESSION;
}
return session_ctx->LoadLicense(message, message_length, core_message_length,
signature, signature_length);
}
OEMCRYPTO_API 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 num_keys, const OEMCrypto_KeyObject* key_array,
OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data,
OEMCrypto_LicenseType license_type) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_LoadKeys: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("ERROR_KEYBOX_INVALID");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("ERROR_INVALID_SESSION sid=%u", session);
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (message == nullptr || message_length == 0 || signature == nullptr ||
signature_length == 0 || key_array == nullptr || num_keys == 0) {
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Range check
if (!RangeCheck(message_length, enc_mac_keys_iv, true) ||
!RangeCheck(message_length, enc_mac_keys, true) ||
!RangeCheck(message_length, pst, true) ||
!RangeCheck(message_length, srm_restriction_data, true)) {
LOGE(
"[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - "
"range check.]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
for (size_t i = 0; i < num_keys; i++) {
if (!RangeCheck(message_length, key_array[i].key_id, false) ||
!RangeCheck(message_length, key_array[i].key_data, false) ||
!RangeCheck(message_length, key_array[i].key_data_iv, false) ||
!RangeCheck(message_length, key_array[i].key_control, false) ||
!RangeCheck(message_length, key_array[i].key_control_iv, false)) {
LOGE(
"[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - range "
"check %zu]",
i);
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
}
if (enc_mac_keys.offset >= wvoec::KEY_IV_SIZE && enc_mac_keys.length > 0) {
if (enc_mac_keys_iv.offset + wvoec::KEY_IV_SIZE == enc_mac_keys.offset) {
LOGE(
"[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - "
"range check iv]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
} else {
if (CRYPTO_memcmp(message + enc_mac_keys.offset - wvoec::KEY_IV_SIZE,
message + enc_mac_keys_iv.offset,
wvoec::KEY_IV_SIZE) == 0) {
LOGE(
"[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - "
"suspicious iv]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
}
}
return session_ctx->LoadKeys(message, message_length, signature,
signature_length, enc_mac_keys_iv, enc_mac_keys,
num_keys, key_array, pst, srm_restriction_data,
license_type);
}
OEMCRYPTO_API 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 (key_array_length == 0) {
LOGE("[OEMCrypto_LoadEntitledContentKeys(): key_array is empty.");
return OEMCrypto_SUCCESS;
}
if (key_array == nullptr) {
LOGE("[OEMCrypto_LoadEntitledContentKeys(): missing key_array.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_LoadEntitledContentKeys: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_LoadEntitledContentKeys(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
for (size_t i = 0; i < key_array_length; i++) {
if (!RangeCheck(message_length, key_array[i].entitlement_key_id, false) ||
!RangeCheck(message_length, key_array[i].content_key_id, false) ||
!RangeCheck(message_length, key_array[i].content_key_data_iv, false) ||
!RangeCheck(message_length, key_array[i].content_key_data, false)) {
LOGE(
"[OEMCrypto_LoadEntitledContentKeys(): "
"OEMCrypto_ERROR_INVALID_CONTEXT -range "
"check %zu]",
i);
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
}
return session_ctx->LoadEntitledContentKeys(message, message_length,
key_array_length, key_array);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadRenewal(OEMCrypto_SESSION session,
const uint8_t* message,
size_t message_length,
size_t core_message_length,
const uint8_t* signature,
size_t signature_length) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("ERROR_KEYBOX_INVALID");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("ERROR_INVALID_SESSION");
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (message == nullptr || message_length == 0 || signature == nullptr ||
signature_length == 0) {
LOGE("ERROR_INVALID_CONTEXT");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
return session_ctx->LoadRenewal(message, message_length, core_message_length,
signature, signature_length);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_RefreshKeys(
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
const uint8_t* signature, size_t signature_length, size_t num_keys,
const OEMCrypto_KeyRefreshObject* key_array) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("ERROR_KEYBOX_INVALID");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("ERROR_INVALID_SESSION");
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (message == nullptr || message_length == 0 || signature == nullptr ||
signature_length == 0 || num_keys == 0) {
LOGE("ERROR_INVALID_CONTEXT");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// We only use the first key object to update the entire license. Since we
// know num_keys > 0 after the last if statement, we can assume index is not
// out of bounds.
constexpr size_t kIndex = 0;
// Range check.
if (!RangeCheck(message_length, key_array[kIndex].key_id, true) ||
!RangeCheck(message_length, key_array[kIndex].key_control, false) ||
!RangeCheck(message_length, key_array[kIndex].key_control_iv, true)) {
LOGE("Range Check %zu", kIndex);
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Validate message signature
if (!session_ctx->ValidateMessage(message, message_length, signature,
signature_length)) {
LOGE("Signature was invalid");
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
// Decrypt and refresh keys in key refresh object
OEMCryptoResult status = OEMCrypto_SUCCESS;
std::vector<uint8_t> key_id;
std::vector<uint8_t> key_control;
std::vector<uint8_t> key_control_iv;
if (key_array[kIndex].key_id.length != 0) {
key_id.assign(message + key_array[kIndex].key_id.offset,
message + key_array[kIndex].key_id.offset +
key_array[kIndex].key_id.length);
key_control.assign(message + key_array[kIndex].key_control.offset,
message + key_array[kIndex].key_control.offset +
wvoec::KEY_CONTROL_SIZE);
if (key_array[kIndex].key_control_iv.length == 0) {
key_control_iv.clear();
} else {
key_control_iv.assign(message + key_array[kIndex].key_control_iv.offset,
message + key_array[kIndex].key_control_iv.offset +
wvoec::KEY_IV_SIZE);
}
} else {
// key_id could be null if special control key type
// key_control is not encrypted in this case
key_id.clear();
key_control_iv.clear();
key_control.assign(message + key_array[kIndex].key_control.offset,
message + key_array[kIndex].key_control.offset +
wvoec::KEY_CONTROL_SIZE);
}
status = session_ctx->RefreshKey(key_id, key_control, key_control_iv);
if (status != OEMCrypto_SUCCESS) {
return status;
}
return OEMCrypto_SUCCESS;
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_QueryKeyControl(
OEMCrypto_SESSION session, const uint8_t* key_id, size_t key_id_length,
uint8_t* key_control_block, size_t* key_control_block_length) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_QueryKeyControl: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
uint32_t* block = reinterpret_cast<uint32_t*>(key_control_block);
if ((key_control_block_length == nullptr) ||
(*key_control_block_length < wvoec::KEY_CONTROL_SIZE)) {
LOGE("[OEMCrypto_QueryKeyControl(): OEMCrypto_ERROR_SHORT_BUFFER]");
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*key_control_block_length = wvoec::KEY_CONTROL_SIZE;
if (key_id == nullptr) {
LOGE(
"[OEMCrypto_QueryKeyControl(): key_id null. "
"OEMCrypto_ERROR_UNKNOWN_FAILURE]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_QueryKeyControl(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
const std::vector<uint8_t> key_id_str =
std::vector<uint8_t>(key_id, key_id + key_id_length);
if (!session_ctx->QueryKeyControlBlock(key_id_str, block)) {
LOGE("[OEMCrypto_QueryKeyControl(): FAIL]");
return OEMCrypto_ERROR_NO_CONTENT_KEY;
}
return OEMCrypto_SUCCESS;
}
OEMCRYPTO_API OEMCryptoResult
OEMCrypto_SelectKey(const OEMCrypto_SESSION session, const uint8_t* key_id,
size_t key_id_length, OEMCryptoCipherMode cipher_mode) {
#ifndef NDEBUG
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("[OEMCrypto_SelectKey(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
#endif
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_SelectKey(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
const std::vector<uint8_t> key_id_str =
std::vector<uint8_t>(key_id, key_id + key_id_length);
return session_ctx->SelectContentKey(key_id_str, cipher_mode);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_DecryptCENC(
OEMCrypto_SESSION session, const OEMCrypto_SampleDescription* samples,
size_t samples_length, const OEMCrypto_CENCEncryptPatternDesc* pattern) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_DecryptCENC: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (samples == nullptr || samples_length == 0) {
LOGE("[OEMCrypto_DecryptCENC(): No samples]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (pattern == nullptr) {
LOGE("[OEMCrypto_DecryptCENC(): No pattern]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_DecryptCENC(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
#ifndef NDEBUG
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("[OEMCrypto_DecryptCENC(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
#endif
// The maximum subsample and sample sizes we use -- if 0, we just pick a
// very large size for a validity check.
const size_t max_subsample_size = crypto_engine->max_subsample_size() > 0
? crypto_engine->max_subsample_size()
: 100 * 1024 * 1024;
const size_t max_sample_size = crypto_engine->max_subsample_size() > 0
? crypto_engine->max_subsample_size()
: 1000 * 1024 * 1024;
// Iterate through all the samples and validate them before doing any decrypt
for (size_t sample_index = 0; sample_index < samples_length; ++sample_index) {
const OEMCrypto_SampleDescription& sample = samples[sample_index];
if (sample.buffers.input_data == nullptr ||
sample.buffers.input_data_length == 0) {
LOGE("[OEMCrypto_DecryptCENC(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (crypto_engine->max_sample_size() > 0 &&
sample.buffers.input_data_length > crypto_engine->max_sample_size()) {
// For testing reasons only, pretend that this integration only supports
// the given buffer size.
LOGE("[OEMCrypto_DecryptCENC(): Sample too large]");
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
}
// Iterate through all the subsamples and sum their lengths
size_t subsample_length_tally = 0;
for (size_t subsample_index = 0; subsample_index < sample.subsamples_length;
++subsample_index) {
const OEMCrypto_SubSampleDescription& subsample =
sample.subsamples[subsample_index];
// Compute the length now, but we check for possible overflow in the next
// if statement.
const size_t length =
subsample.num_bytes_clear + subsample.num_bytes_encrypted;
if (subsample.num_bytes_clear > max_subsample_size ||
subsample.num_bytes_encrypted > max_subsample_size ||
length > max_subsample_size ||
subsample_length_tally > max_sample_size) {
// For testing reasons only, pretend that this integration only supports
// the given buffer size.
LOGE("[OEMCrypto_DecryptCENC(): Subsample too large]");
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
}
subsample_length_tally += length;
}
if (subsample_length_tally != sample.buffers.input_data_length) {
LOGE(
"[OEMCrypto_DecryptCENC(): Sample and subsample lengths do not "
"match.]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
}
return session_ctx->DecryptSamples(samples, samples_length, pattern);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_CopyBuffer(
OEMCrypto_SESSION session, const uint8_t* data_addr, size_t data_length,
const OEMCrypto_DestBufferDesc* out_buffer_descriptor,
uint8_t subsample_flags) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_CopyBuffer: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (data_addr == nullptr || out_buffer_descriptor == nullptr) {
LOGE("[OEMCrypto_CopyBuffer(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (crypto_engine->max_subsample_size() > 0 &&
data_length > crypto_engine->max_subsample_size()) {
// For testing reasons only, pretend that this integration only supports
// the minimum possible buffer size.
LOGE("[OEMCrypto_CopyBuffer(): OEMCrypto_ERROR_BUFFER_TOO_LARGE]");
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
}
OEMCryptoResult status = crypto_engine->SetDestination(
*out_buffer_descriptor, data_length, subsample_flags);
if (status != OEMCrypto_SUCCESS) return status;
if (crypto_engine->destination() != nullptr) {
memmove(crypto_engine->destination(), data_addr, data_length);
}
return crypto_engine->PushDestination(*out_buffer_descriptor,
subsample_flags);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_WrapKeyboxOrOEMCert(
const uint8_t* keybox, size_t keyBoxLength, uint8_t* wrappedKeybox,
size_t* wrappedKeyBoxLength, const uint8_t* transportKey,
size_t transportKeyLength) {
if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
if (!keybox || !wrappedKeybox || !wrappedKeyBoxLength ||
(keyBoxLength != *wrappedKeyBoxLength)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// This implementation ignores the transport key. For test keys, we
// don't need to encrypt the keybox.
memcpy(wrappedKeybox, keybox, keyBoxLength);
return OEMCrypto_SUCCESS;
}
OEMCRYPTO_API OEMCryptoResult
OEMCrypto_InstallKeyboxOrOEMCert(const uint8_t* keybox, size_t keybox_length) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_InstallKeyboxOrOEMCert: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
return crypto_engine->InstallKeybox(keybox, keybox_length);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestKeybox(const uint8_t* buffer,
size_t length) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_LoadTestKeybox: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
return crypto_engine->InstallTestKeybox(buffer, length);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_IsKeyboxOrOEMCertValid: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
switch (crypto_engine->config_provisioning_method()) {
case OEMCrypto_DrmCertificate:
return OEMCrypto_SUCCESS;
case OEMCrypto_Keybox:
return crypto_engine->IsKeyboxValid();
case OEMCrypto_OEMCertificate:
// TODO(sigquit): verify that the certificate exists and is valid.
return OEMCrypto_SUCCESS;
default:
LOGE("Invalid provisioning method: %d.",
crypto_engine->config_provisioning_method());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
OEMCRYPTO_API OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod() {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_GetProvisioningMethod: OEMCrypto Not Initialized.");
return OEMCrypto_ProvisioningError;
}
return crypto_engine->config_provisioning_method();
}
OEMCRYPTO_API OEMCryptoResult
OEMCrypto_LoadOEMPrivateKey(OEMCrypto_SESSION session) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (crypto_engine->config_provisioning_method() != OEMCrypto_OEMCertificate) {
LOGE("Unexpected provisioning method = %d.",
crypto_engine->config_provisioning_method());
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("OEMCrypto_ERROR_INVALID_SESSION");
return OEMCrypto_ERROR_INVALID_SESSION;
}
return crypto_engine->load_oem_private_key(session_ctx);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetOEMPublicCertificate(
uint8_t* public_cert, size_t* public_cert_length) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (crypto_engine->config_provisioning_method() != OEMCrypto_OEMCertificate) {
LOGE("Unexpected provisioning method = %d.",
crypto_engine->config_provisioning_method());
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
return crypto_engine->get_oem_certificate(public_cert, public_cert_length);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* device_id,
size_t* device_id_length) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_GetDeviceID: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return crypto_engine->GetDeviceRootId(device_id, device_id_length);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* key_data,
size_t* key_data_length) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_GetKeyData: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
return crypto_engine->GetRootKeyData(key_data, key_data_length);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData,
size_t dataLength) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_GetRandom: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!randomData) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (RAND_bytes(randomData, dataLength) == 1) {
return OEMCrypto_SUCCESS;
}
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// This function is no longer exported -- it is only used by LoadProvisioning.
static 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) {
uint32_t nonce = unaligned_dereference_uint32(unaligned_nonce);
if (unaligned_nonce == nullptr) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_RewrapDeviceRSAKey30: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (wrapped_rsa_key_length == nullptr) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (encrypted_message_key == nullptr || encrypted_message_key_length == 0 ||
enc_rsa_key == nullptr || enc_rsa_key_iv == nullptr ||
unaligned_nonce == nullptr) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Validate nonce
if (!session_ctx->CheckNonce(nonce)) {
return OEMCrypto_ERROR_INVALID_NONCE;
}
const std::vector<uint8_t> enc_encryption_key(
encrypted_message_key,
encrypted_message_key + encrypted_message_key_length);
if (!session_ctx->InstallRSAEncryptedKey(enc_encryption_key)) {
LOGE(
"OEMCrypto_RewrapDeviceRSAKey30: "
"Error loading encrypted_message_key.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Decrypt RSA key.
std::vector<uint8_t> pkcs8_rsa_key(enc_rsa_key_length);
if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length,
enc_rsa_key_iv, pkcs8_rsa_key.data())) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
if (!session_ctx->LoadRsaDrmKey(pkcs8_rsa_key.data(), enc_rsa_key_length)) {
LOGE("Failed to load RSA DRM key");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
// Now we generate a wrapped keybox.
WrappedRSAKey* wrapped = reinterpret_cast<WrappedRSAKey*>(wrapped_rsa_key);
// Pick a random context and IV for generating keys.
if (RAND_bytes(wrapped->context, sizeof(wrapped->context)) != 1) {
LOGE("[_RewrapDeviceRSAKey30(): RAND_bytes failed.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (RAND_bytes(wrapped->iv, sizeof(wrapped->iv)) != 1) {
LOGE("[_RewrapDeviceRSAKey30(): RAND_bytes failed.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const std::vector<uint8_t> context(
wrapped->context, wrapped->context + sizeof(wrapped->context));
// Generate mac and encryption keys for encrypting the signature.
const OEMCryptoResult derive_key_result =
session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), context, context);
if (derive_key_result != OEMCrypto_SUCCESS) {
LOGE("[_RewrapDeviceRSAKey30(): DeriveKeys failed.");
return derive_key_result;
}
// Encrypt rsa key with keybox.
if (!session_ctx->EncryptRSAKey(pkcs8_rsa_key.data(), enc_rsa_key_length,
wrapped->iv, wrapped->enc_rsa_key)) {
LOGE("[_RewrapDeviceRSAKey30(): EncrypteRSAKey failed.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey);
// The wrapped keybox must be signed with the same key we verify with.
// Reference implementation uses the server key.
unsigned int sig_length = sizeof(wrapped->signature);
if (!HMAC(EVP_sha256(), session_ctx->mac_key_server().data(),
session_ctx->mac_key_server().size(), wrapped->context,
buffer_size - sizeof(wrapped->signature), wrapped->signature,
&sig_length)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}
// This function is no longer exported -- it is only used by LoadProvisioning.
static 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) {
uint32_t nonce = unaligned_dereference_uint32(unaligned_nonce);
if (unaligned_nonce == nullptr) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_RewrapDeviceRSAKey: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
if (wrapped_rsa_key_length == nullptr) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (message == nullptr || message_length == 0 || signature == nullptr ||
signature_length == 0 || unaligned_nonce == nullptr ||
enc_rsa_key == nullptr) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// verify signature.
if (!session_ctx->ValidateMessage(message, message_length, signature,
signature_length)) {
LOGE("[RewrapDeviceRSAKey(): Could not verify signature]");
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
// Range check performed by ODK library.
// Validate nonce
if (!session_ctx->CheckNonce(nonce)) {
return OEMCrypto_ERROR_INVALID_NONCE;
}
// Decrypt RSA key and verify it.
std::vector<uint8_t> pkcs8_rsa_key(enc_rsa_key_length);
if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length,
enc_rsa_key_iv, pkcs8_rsa_key.data())) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
if (!session_ctx->LoadRsaDrmKey(pkcs8_rsa_key.data(), enc_rsa_key_length)) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
// Now we generate a wrapped keybox.
WrappedRSAKey* wrapped = reinterpret_cast<WrappedRSAKey*>(wrapped_rsa_key);
// Pick a random context and IV for generating keys.
if (RAND_bytes(wrapped->context, sizeof(wrapped->context)) != 1) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (RAND_bytes(wrapped->iv, sizeof(wrapped->iv)) != 1) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const std::vector<uint8_t> context(
wrapped->context, wrapped->context + sizeof(wrapped->context));
// Generate mac and encryption keys for encrypting the signature.
const OEMCryptoResult derive_key_result =
session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), context, context);
if (derive_key_result != OEMCrypto_SUCCESS) {
return derive_key_result;
}
// Encrypt rsa key with keybox.
if (!session_ctx->EncryptRSAKey(pkcs8_rsa_key.data(), enc_rsa_key_length,
wrapped->iv, wrapped->enc_rsa_key)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey);
// The wrapped keybox must be signed with the same key we verify with.
// Reference implementation uses the server key.
unsigned int sig_length = sizeof(wrapped->signature);
if (!HMAC(EVP_sha256(), session_ctx->mac_key_server().data(),
session_ctx->mac_key_server().size(), wrapped->context,
buffer_size - sizeof(wrapped->signature), wrapped->signature,
&sig_length)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadProvisioning(
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
size_t core_message_length, const uint8_t* signature,
size_t signature_length, uint8_t* wrapped_private_key,
size_t* wrapped_private_key_length) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto Not Initialized");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (wrapped_private_key_length == nullptr || message == nullptr ||
message_length == 0 || signature == nullptr || signature_length == 0) {
LOGE("OEMCrypto_ERROR_INVALID_CONTEXT");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("OEMCrypto_ERROR_KEYBOX_INVALID");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("OEMCrypto_ERROR_INVALID_SESSION");
return OEMCrypto_ERROR_INVALID_SESSION;
}
std::vector<uint8_t> device_id = crypto_engine->DeviceRootId();
ODK_ParsedProvisioning parsed_response;
const uint32_t nonce = session_ctx->nonce();
const OEMCryptoResult result =
ODK_ParseProvisioning(message, message_length, core_message_length,
&(session_ctx->nonce_values()), device_id.data(),
device_id.size(), &parsed_response);
if (result != OEMCrypto_SUCCESS) {
LOGE("ODK Error %d", result);
return result;
}
if (parsed_response.enc_private_key_iv.length != wvoec::KEY_IV_SIZE) {
LOGE("Encrypted private key iv has invalid length: %zu",
parsed_response.enc_private_key_iv.length);
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// For the reference 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_LoadDRMPrivateKey below.
const size_t buffer_size =
parsed_response.enc_private_key.length + sizeof(WrappedRSAKey);
if (wrapped_private_key == nullptr ||
*wrapped_private_key_length < buffer_size) {
*wrapped_private_key_length = buffer_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*wrapped_private_key_length =
buffer_size; // Tell caller how much space we used.
const uint8_t* message_body = message + core_message_length;
if (crypto_engine->config_provisioning_method() == OEMCrypto_Keybox) {
return OEMCrypto_RewrapDeviceRSAKey(
session, message, message_length, signature, signature_length, &nonce,
message_body + parsed_response.enc_private_key.offset,
parsed_response.enc_private_key.length,
message_body + parsed_response.enc_private_key_iv.offset,
wrapped_private_key, wrapped_private_key_length);
} else if (crypto_engine->config_provisioning_method() ==
OEMCrypto_OEMCertificate) {
return OEMCrypto_RewrapDeviceRSAKey30(
session, &nonce,
message_body + parsed_response.encrypted_message_key.offset,
parsed_response.encrypted_message_key.length,
message_body + parsed_response.enc_private_key.offset,
parsed_response.enc_private_key.length,
message_body + parsed_response.enc_private_key_iv.offset,
wrapped_private_key, wrapped_private_key_length);
} else {
LOGE("Invalid provisioning method: %d.",
crypto_engine->config_provisioning_method());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadDRMPrivateKey(
OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type,
const uint8_t* wrapped_rsa_key, size_t wrapped_rsa_key_length) {
if (wrapped_rsa_key == nullptr) {
LOGE("OEMCrypto_ERROR_INVALID_CONTEXT nullptr");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (crypto_engine == nullptr) {
LOGE("OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (key_type != OEMCrypto_RSA_Private_Key) {
LOGE("ECC keys not yet supported in reference code.");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
if (crypto_engine->config_provisioning_method() == OEMCrypto_DrmCertificate) {
// If we are using a baked in cert, the "wrapped RSA key" should actually be
// the magic value for baked-in certificates.
if (wrapped_rsa_key_length != sizeof(kBakedInCertificateMagicBytes) ||
memcmp(kBakedInCertificateMagicBytes, wrapped_rsa_key,
wrapped_rsa_key_length) != 0) {
LOGE("Baked in Cert has wrong size.");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
} else {
return OEMCrypto_SUCCESS;
}
}
if (wrapped_rsa_key_length < sizeof(WrappedRSAKey)) {
LOGE("RSA Key has wrong size.");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
const WrappedRSAKey* wrapped =
reinterpret_cast<const WrappedRSAKey*>(wrapped_rsa_key);
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("ERROR_KEYBOX_INVALID");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("ERROR_INVALID_SESSION");
return OEMCrypto_ERROR_INVALID_SESSION;
}
const std::vector<uint8_t> context(
wrapped->context, wrapped->context + sizeof(wrapped->context));
// Generate mac and encryption keys for encrypting the signature.
const OEMCryptoResult derive_key_result =
session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), context, context);
if (derive_key_result != OEMCrypto_SUCCESS) {
return derive_key_result;
}
// verify signature.
if (!session_ctx->ValidateMessage(
wrapped->context, wrapped_rsa_key_length - sizeof(wrapped->signature),
wrapped->signature, sizeof(wrapped->signature))) {
LOGE("Could not verify signature");
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
// Decrypt RSA key.
std::vector<uint8_t> pkcs8_rsa_key(wrapped_rsa_key_length -
sizeof(wrapped->signature));
size_t enc_rsa_key_length = wrapped_rsa_key_length - sizeof(WrappedRSAKey);
if (!session_ctx->DecryptRSAKey(wrapped->enc_rsa_key, enc_rsa_key_length,
wrapped->iv, pkcs8_rsa_key.data())) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1];
if (padding > 16) {
// Do not return an error at this point, to avoid a padding oracle attack.
padding = 0;
}
size_t rsa_key_length = enc_rsa_key_length - padding;
if (!session_ctx->LoadRsaDrmKey(pkcs8_rsa_key.data(), rsa_key_length)) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
return OEMCrypto_SUCCESS;
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestRSAKey() {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_LoadTestRSAKey: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return crypto_engine->LoadTestRsaKey();
}
OEMCRYPTO_API 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 (crypto_engine == nullptr) {
LOGE("OEMCrypto_GenerateRSASignature: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (signature_length == 0) {
LOGE("[OEMCrypto_GenerateRSASignature(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_GenerateRSASignature(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
return session_ctx->GenerateRSASignature(message, message_length, signature,
signature_length, padding_scheme);
}
OEMCRYPTO_API 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 (crypto_engine == nullptr) {
LOGE("OEMCrypto_DeriveKeysFromSessionKey: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("[OEMCrypto_DeriveKeysFromSessionKey(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
if (mac_key_context_length > kMaxContextKeyLength ||
enc_key_context_length > kMaxContextKeyLength ||
enc_session_key_length > kMaxContextKeyLength) {
LOGE("[OEMCrypto_DeriveKeysFromSessionKey(): ERROR_BUFFER_TOO_LARGE]");
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_DeriveKeysFromSessionKey(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
const std::vector<uint8_t> ssn_key_str(
enc_session_key, enc_session_key + enc_session_key_length);
const std::vector<uint8_t> mac_ctx_str(
mac_key_context, mac_key_context + mac_key_context_length);
const std::vector<uint8_t> enc_ctx_str(
enc_key_context, enc_key_context + enc_key_context_length);
// Generate mac and encryption keys for current session context
return session_ctx->RSADeriveKeys(ssn_key_str, mac_ctx_str, enc_ctx_str);
}
OEMCRYPTO_API uint32_t OEMCrypto_APIVersion() {
return CryptoEngine::kApiVersion;
}
OEMCRYPTO_API uint32_t OEMCrypto_MinorAPIVersion() {
return CryptoEngine::kMinorApiVersion;
}
OEMCRYPTO_API uint8_t OEMCrypto_Security_Patch_Level() {
uint8_t security_patch_level = crypto_engine->config_security_patch_level();
return security_patch_level;
}
OEMCRYPTO_API const char* OEMCrypto_SecurityLevel() {
const char* security_level = crypto_engine->config_security_level();
return security_level;
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetHDCPCapability(
OEMCrypto_HDCP_Capability* current, OEMCrypto_HDCP_Capability* maximum) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_GetHDCPCapability: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (current == nullptr) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
if (maximum == nullptr) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
*current = crypto_engine->config_current_hdcp_capability();
*maximum = crypto_engine->config_maximum_hdcp_capability();
return OEMCrypto_SUCCESS;
}
OEMCRYPTO_API uint32_t OEMCrypto_GetAnalogOutputFlags() {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_GetAnalogOutputFlags: OEMCrypto Not Initialized.");
return 0;
}
return crypto_engine->analog_output_flags();
}
OEMCRYPTO_API const char* OEMCrypto_BuildInformation() {
return "OEMCrypto Ref Code " __DATE__ " " __TIME__;
}
OEMCRYPTO_API uint32_t OEMCrypto_ResourceRatingTier() {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_ResourceRatingTier: OEMCrypto Not Initialized.");
return 0;
}
return crypto_engine->resource_rating();
}
OEMCRYPTO_API bool OEMCrypto_SupportsUsageTable() {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_SupportsUsageTable: OEMCrypto Not Initialized.");
return 0;
}
bool supports_usage = crypto_engine->config_supports_usage_table();
return supports_usage;
}
OEMCRYPTO_API size_t OEMCrypto_MaximumUsageTableHeaderSize() {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_MaximumUsageTableHeaderSize: OEMCrypto Not Initialized.");
return 0;
}
return crypto_engine->max_usage_table_size();
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetNumberOfOpenSessions(size_t* count) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_GetNumberOfOpenSessions: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (count == nullptr) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
*count = crypto_engine->GetNumberOfOpenSessions();
return OEMCrypto_SUCCESS;
}
OEMCRYPTO_API OEMCryptoResult
OEMCrypto_GetMaxNumberOfSessions(size_t* maximum) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_GetMaxNumberOfSessions: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (maximum == nullptr) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
*maximum = crypto_engine->GetMaxNumberOfSessions();
return OEMCrypto_SUCCESS;
}
OEMCRYPTO_API bool OEMCrypto_IsAntiRollbackHwPresent() {
bool anti_rollback_hw_present =
crypto_engine->config_is_anti_rollback_hw_present();
return anti_rollback_hw_present;
}
OEMCRYPTO_API uint32_t OEMCrypto_SupportedCertificates() {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_GetProvisioningMethod: OEMCrypto Not Initialized.");
return 0;
}
if (crypto_engine->config_provisioning_method() == OEMCrypto_DrmCertificate) {
return 0;
}
return OEMCrypto_Supports_RSA_2048bit | OEMCrypto_Supports_RSA_3072bit |
OEMCrypto_Supports_RSA_CAST;
}
OEMCRYPTO_API 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 (crypto_engine == nullptr) {
LOGE("OEMCrypto_Generic_Encrypt: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("[OEMCrypto_Generic_Encrypt(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_Generic_Encrypt(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (in_buffer == nullptr || buffer_length == 0 || iv == nullptr ||
out_buffer == nullptr) {
LOGE("[OEMCrypto_Generic_Encrypt(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (buffer_length > kMaxInputMessageBuferLength) {
LOGE("[OEMCrypto_Generic_Encrypt(): ERROR_BUFFER_TOO_LARGE]");
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
}
OEMCryptoResult sts = session_ctx->Generic_Encrypt(in_buffer, buffer_length,
iv, algorithm, out_buffer);
return sts;
}
OEMCRYPTO_API 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 (crypto_engine == nullptr) {
LOGE("OEMCrypto_Generic_Decrypt: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("[OEMCrypto_Generic_Decrypt(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_Generic_Decrypt(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (in_buffer == nullptr || buffer_length == 0 || iv == nullptr ||
out_buffer == nullptr) {
LOGE("[OEMCrypto_Generic_Decrypt(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (buffer_length > kMaxInputMessageBuferLength) {
LOGE("[OEMCrypto_Generic_Encrypt(): ERROR_BUFFER_TOO_LARGE]");
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
}
OEMCryptoResult sts = session_ctx->Generic_Decrypt(in_buffer, buffer_length,
iv, algorithm, out_buffer);
return sts;
}
OEMCRYPTO_API 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 (crypto_engine == nullptr) {
LOGE("OEMCrypto_Generic_Sign: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("[OEMCrypto_Generic_Sign(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_Generic_Sign(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (*signature_length < SHA256_DIGEST_LENGTH) {
*signature_length = SHA256_DIGEST_LENGTH;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if (in_buffer == nullptr || buffer_length == 0 || signature == nullptr) {
LOGE("[OEMCrypto_Generic_Sign(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (buffer_length > kMaxInputMessageBuferLength) {
LOGE("[OEMCrypto_Generic_Sign(): ERROR_BUFFER_TOO_LARGE]");
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
}
OEMCryptoResult sts = session_ctx->Generic_Sign(
in_buffer, buffer_length, algorithm, signature, signature_length);
return sts;
}
OEMCRYPTO_API 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 (crypto_engine == nullptr) {
LOGE("OEMCrypto_Generic_Verify: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("[OEMCrypto_Generic_Verify(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_Generic_Verify(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (signature_length != SHA256_DIGEST_LENGTH) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (in_buffer == nullptr || buffer_length == 0 || signature == nullptr ||
signature_length > kMaxInputSignatureLength) {
LOGE("[OEMCrypto_Generic_Verify(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (buffer_length > kMaxInputMessageBuferLength) {
LOGE("[OEMCrypto_Generic_Verify(): ERROR_BUFFER_TOO_LARGE]");
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
}
return session_ctx->Generic_Verify(in_buffer, buffer_length, algorithm,
signature, signature_length);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_DeactivateUsageEntry(
OEMCrypto_SESSION session, const uint8_t* pst, size_t pst_length) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_DeactivateUsageEntry: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->config_supports_usage_table()) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_DeactivateUsageEntry(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
std::vector<uint8_t> pstv(pst, pst + pst_length);
return session_ctx->DeactivateUsageEntry(pstv);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session,
const uint8_t* pst,
size_t pst_length,
uint8_t* buffer,
size_t* buffer_length) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_ReportUsage: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->config_supports_usage_table()) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
if (!buffer_length) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_ReportUsage(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
std::vector<uint8_t> pstv(pst, pst + pst_length);
OEMCryptoResult sts = session_ctx->ReportUsage(pstv, buffer, buffer_length);
return sts;
}
OEMCRYPTO_API bool OEMCrypto_IsSRMUpdateSupported() {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_IsSRMUpdateSupported: OEMCrypto Not Initialized.");
return false;
}
bool result = crypto_engine->srm_update_supported();
return result;
}
OEMCRYPTO_API OEMCryptoResult
OEMCrypto_GetCurrentSRMVersion(uint16_t* version) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_GetCurrentSRMVersion: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (crypto_engine->config_local_display_only()) {
return OEMCrypto_LOCAL_DISPLAY_ONLY;
}
OEMCryptoResult result = crypto_engine->current_srm_version(version);
return result;
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadSRM(const uint8_t* buffer,
size_t buffer_length) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_LoadSRM: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return crypto_engine->load_srm(buffer, buffer_length);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_RemoveSRM() {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_RemoveSRM: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return crypto_engine->remove_srm();
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_CreateUsageTableHeader(
uint8_t* header_buffer, size_t* header_buffer_length) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_CreateUsageTableHeader: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->config_supports_usage_table()) {
LOGE("OEMCrypto_CreateUsageTableHeader: Configured without Usage Tables.");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
return crypto_engine->usage_table().CreateUsageTableHeader(
header_buffer, header_buffer_length);
}
OEMCRYPTO_API OEMCryptoResult
OEMCrypto_LoadUsageTableHeader(const uint8_t* buffer, size_t buffer_length) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_LoadUsageTableHeader: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->config_supports_usage_table()) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
if (!buffer) {
LOGE("OEMCrypto_LoadUsageTableHeader: buffer null.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
std::vector<uint8_t> bufferv(buffer, buffer + buffer_length);
return crypto_engine->usage_table().LoadUsageTableHeader(bufferv);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_CreateNewUsageEntry(
OEMCrypto_SESSION session, uint32_t* usage_entry_number) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_CreateNewUsageEntry: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->config_supports_usage_table()) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_CreateNewUsageEntry(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (!usage_entry_number) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
OEMCryptoResult sts = session_ctx->CreateNewUsageEntry(usage_entry_number);
return sts;
}
OEMCRYPTO_API OEMCryptoResult
OEMCrypto_LoadUsageEntry(OEMCrypto_SESSION session, uint32_t index,
const uint8_t* buffer, size_t buffer_size) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_LoadUsageEntry: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->config_supports_usage_table()) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_LoadUsageEntry(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (!buffer) {
LOGE("[OEMCrypto_LoadUsageEntry(): buffer null]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
std::vector<uint8_t> bufferv(buffer, buffer + buffer_size);
return session_ctx->LoadUsageEntry(index, bufferv);
}
OEMCRYPTO_API 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 (crypto_engine == nullptr) {
LOGE("OEMCrypto_UpdateUsageEntry: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->config_supports_usage_table()) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
if (!header_buffer_length || !entry_buffer_length) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_UpdateUsageEntry(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
return session_ctx->UpdateUsageEntry(header_buffer, header_buffer_length,
entry_buffer, entry_buffer_length);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader(
uint32_t new_table_size, uint8_t* header_buffer,
size_t* header_buffer_length) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_ShrinkUsageTableHeader: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->config_supports_usage_table()) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
return crypto_engine->usage_table().ShrinkUsageTableHeader(
new_table_size, header_buffer, header_buffer_length);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_MoveEntry(OEMCrypto_SESSION session,
uint32_t new_index) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_MoveEntry: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->config_supports_usage_table()) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_MoveEntry(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
return session_ctx->MoveEntry(new_index);
}
OEMCRYPTO_API uint32_t OEMCrypto_SupportsDecryptHash() {
return OEMCrypto_CRC_Clear_Buffer;
}
OEMCRYPTO_API OEMCryptoResult
OEMCrypto_SetDecryptHash(OEMCrypto_SESSION session, uint32_t frame_number,
const uint8_t* hash, size_t hash_length) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_SetDecryptHash: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_SetDecryptHash(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
return session_ctx->SetDecryptHash(frame_number, hash, hash_length);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetHashErrorCode(
OEMCrypto_SESSION session, uint32_t* failed_frame_number) {
if (crypto_engine == nullptr) {
LOGE("OEMCrypto_GetHashErrorCode: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_GetHashErrorCode(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
return session_ctx->GetHashErrorCode(failed_frame_number);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_AllocateSecureBuffer(
OEMCrypto_SESSION session, size_t buffer_size,
OEMCrypto_DestBufferDesc* output_descriptor, int* secure_fd) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_FreeSecureBuffer(
OEMCrypto_SESSION session, OEMCrypto_DestBufferDesc* output_descriptor,
int secure_fd) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
} // namespace wvoec_ref