1806 lines
70 KiB
C++
1806 lines
70 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};
|
|
|
|
// 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();
|
|
*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;
|
|
}
|
|
|
|
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
|
|
if (!session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), mac_ctx_str,
|
|
enc_ctx_str)) {
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
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)) {
|
|
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=%d", 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=%d", 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 (unsigned int 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 %d]", 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
|
|
|
|
// 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];
|
|
const size_t length =
|
|
subsample.num_bytes_clear + subsample.num_bytes_encrypted;
|
|
if (crypto_engine->max_subsample_size() > 0 &&
|
|
length > crypto_engine->max_subsample_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 keyBoxLength) {
|
|
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;
|
|
}
|
|
if (crypto_engine->InstallKeybox(keybox, keyBoxLength)) {
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
return OEMCrypto_ERROR_WRITE_KEYBOX;
|
|
}
|
|
|
|
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;
|
|
}
|
|
crypto_engine->UseTestKeybox(buffer, length);
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
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:
|
|
switch (crypto_engine->ValidateKeybox()) {
|
|
case NO_ERROR:
|
|
return OEMCrypto_SUCCESS;
|
|
case BAD_CRC:
|
|
return OEMCrypto_ERROR_BAD_CRC;
|
|
case BAD_MAGIC:
|
|
return OEMCrypto_ERROR_BAD_MAGIC;
|
|
default:
|
|
case OTHER_ERROR:
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
break;
|
|
case OEMCrypto_OEMCertificate:
|
|
// TODO(fredgc): verify that the certificate exists and is valid.
|
|
return OEMCrypto_SUCCESS;
|
|
break;
|
|
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* deviceID,
|
|
size_t* idLength) {
|
|
if (crypto_engine == nullptr) {
|
|
LOGE("OEMCrypto_GetDeviceID: OEMCrypto Not Initialized.");
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
const std::vector<uint8_t>& dev_id_string = crypto_engine->DeviceRootId();
|
|
if (dev_id_string.empty()) {
|
|
LOGE("[OEMCrypto_GetDeviceId(): Keybox Invalid]");
|
|
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
|
}
|
|
|
|
size_t dev_id_len = dev_id_string.size();
|
|
if (*idLength < dev_id_len) {
|
|
*idLength = dev_id_len;
|
|
LOGE("[OEMCrypto_GetDeviceId(): ERROR_SHORT_BUFFER]");
|
|
return OEMCrypto_ERROR_SHORT_BUFFER;
|
|
}
|
|
memset(deviceID, 0, *idLength);
|
|
memcpy(deviceID, &dev_id_string[0], dev_id_len);
|
|
*idLength = dev_id_len;
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData,
|
|
size_t* keyDataLength) {
|
|
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;
|
|
}
|
|
size_t length = crypto_engine->DeviceRootTokenLength();
|
|
if (keyDataLength == nullptr) {
|
|
LOGE("[OEMCrypto_GetKeyData(): null pointer. ERROR_UNKNOWN_FAILURE]");
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
if (*keyDataLength < length) {
|
|
*keyDataLength = length;
|
|
LOGE("[OEMCrypto_GetKeyData(): ERROR_SHORT_BUFFER]");
|
|
return OEMCrypto_ERROR_SHORT_BUFFER;
|
|
}
|
|
if (keyData == nullptr) {
|
|
LOGE("[OEMCrypto_GetKeyData(): null pointer. ERROR_UNKNOWN_FAILURE]");
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
memset(keyData, 0, *keyDataLength);
|
|
memcpy(keyData, crypto_engine->DeviceRootToken(), length);
|
|
*keyDataLength = length;
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
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)) {
|
|
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;
|
|
}
|
|
// 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 = enc_rsa_key_length + sizeof(WrappedRSAKey);
|
|
|
|
if (wrapped_rsa_key == nullptr || *wrapped_rsa_key_length < buffer_size) {
|
|
*wrapped_rsa_key_length = buffer_size;
|
|
return OEMCrypto_ERROR_SHORT_BUFFER;
|
|
}
|
|
*wrapped_rsa_key_length = buffer_size; // Tell caller how much space we used.
|
|
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;
|
|
}
|
|
|
|
if (!session_ctx->InstallRSAEncryptedKey(encrypted_message_key,
|
|
encrypted_message_key_length)) {
|
|
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[0])) {
|
|
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->LoadRSAKey(&pkcs8_rsa_key[0], rsa_key_length)) {
|
|
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): Failed to LoadRSAKey.");
|
|
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))) {
|
|
LOGE("[_RewrapDeviceRSAKey30(): RAND_bytes failed.");
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) {
|
|
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.
|
|
if (!session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), context,
|
|
context)) {
|
|
LOGE("[_RewrapDeviceRSAKey30(): DeriveKeys failed.");
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
|
|
// Encrypt rsa key with keybox.
|
|
if (!session_ctx->EncryptRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length,
|
|
wrapped->iv, wrapped->enc_rsa_key)) {
|
|
LOGE("[_RewrapDeviceRSAKey30(): EncrypteRSAKey failed.");
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
// The wrapped keybox must be signed with the same key we verify with. I'll
|
|
// pick the server key, so I don't have to modify LoadRSAKey.
|
|
unsigned int sig_length = sizeof(wrapped->signature);
|
|
if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0],
|
|
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;
|
|
}
|
|
// 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 = enc_rsa_key_length + sizeof(WrappedRSAKey);
|
|
|
|
if (wrapped_rsa_key == nullptr || *wrapped_rsa_key_length < buffer_size) {
|
|
*wrapped_rsa_key_length = buffer_size;
|
|
return OEMCrypto_ERROR_SHORT_BUFFER;
|
|
}
|
|
*wrapped_rsa_key_length = buffer_size; // Tell caller how much space we used.
|
|
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[0])) {
|
|
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->LoadRSAKey(&pkcs8_rsa_key[0], 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))) {
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) {
|
|
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.
|
|
if (!session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), context,
|
|
context)) {
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
|
|
// Encrypt rsa key with keybox.
|
|
if (!session_ctx->EncryptRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length,
|
|
wrapped->iv, wrapped->enc_rsa_key)) {
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
// The wrapped keybox must be signed with the same key we verify with. I'll
|
|
// pick the server key, so I don't have to modify LoadRSAKey.
|
|
unsigned int sig_length = sizeof(wrapped->signature);
|
|
if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0],
|
|
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;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
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.
|
|
if (!session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), context,
|
|
context)) {
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
// 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[0])) {
|
|
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->LoadRSAKey(&pkcs8_rsa_key[0], 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;
|
|
}
|
|
if (crypto_engine->LoadTestRsaKey()) return OEMCrypto_SUCCESS;
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
size_t required_size = session_ctx->RSASignatureSize();
|
|
if (*signature_length < required_size) {
|
|
*signature_length = required_size;
|
|
return OEMCrypto_ERROR_SHORT_BUFFER;
|
|
}
|
|
|
|
if (message == nullptr || message_length == 0 || signature == nullptr ||
|
|
signature_length == 0) {
|
|
LOGE("[OEMCrypto_GenerateRSASignature(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
|
}
|
|
|
|
OEMCryptoResult sts = session_ctx->GenerateRSASignature(
|
|
message, message_length, signature, signature_length, padding_scheme);
|
|
return sts;
|
|
}
|
|
|
|
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_GenerateDerivedKeys(): ERROR_KEYBOX_INVALID]");
|
|
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
if (session_ctx->allowed_schemes() != kSign_RSASSA_PSS) {
|
|
LOGE("[OEMCrypto_GenerateDerivedKeys(): x509 key used to derive keys]");
|
|
return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
|
}
|
|
|
|
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
|
|
if (!session_ctx->RSADeriveKeys(ssn_key_str, mac_ctx_str, enc_ctx_str)) {
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
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;
|
|
}
|
|
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;
|
|
}
|
|
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;
|
|
}
|
|
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) {
|
|
LOGE("[OEMCrypto_Generic_Verify(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
|
}
|
|
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
|