This change incorporates the following CLs from the Widevine
cdm repository:
Update the java request/response test app to match Drm API changes
Don't build the mock liboemcrypto.so by default
Do not build CDM tests by default
Fix Build Break in DrmEngine Unit Tests
Fix Build Break in WVDrmPlugin
Initial version of roadmap for CDM projects.
Implement License Query
Implement Generic DRM in OEMCrypto Reference Implementation
Add key_data_length field when calling OEMCrypto_LoadKeys
Policy engine unittests
Generalized DRM API for OEMCrypto
Fixes proto buf libraries build.
Add Version Number to OEMCrypto API
Test key control block duration field in OEMCrypto
Add fix for missing crypto offset.
Fixed android/media*/test builds and added proto files for Cert. provisioning
Refactor and clean up callback code in CDM.
Add "device_id" name-value pair to LicenseRequest::ClientIdentification
Separate unit and end-to-end tests from the top level makefie.
Includes changes for 'fall back to l3 oemcrypto lib' in top level makefile.
Fall Back to Level 3 if Level 1 Fails
Fix compilation error in wvcdm_unittest.
Fix Android build break due to Decrypt() signature change in cdm_engine.h.
Wire up callbacks and errors in the Steel proxy.
Fix lock assert if there is no keybox on the device.
RSA Certificate Unit Test
Change Generic_Verify signature to constant.
Change-Id: I2e42db9d0b4f8d4e833675ae81d0714509bbfd2c
1163 lines
48 KiB
C++
1163 lines
48 KiB
C++
/*******************************************************************************
|
|
*
|
|
* Copyright 2013 Google Inc. All Rights Reserved.
|
|
*
|
|
* mock implementation of OEMCrypto APIs
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include "OEMCryptoCENC.h"
|
|
|
|
#include <dlfcn.h>
|
|
#include <stdio.h>
|
|
#include <iostream>
|
|
#include <cstring>
|
|
#include <string>
|
|
|
|
#include "log.h"
|
|
#include "oemcrypto_engine_mock.h"
|
|
#include "openssl/rand.h"
|
|
#include "openssl/sha.h"
|
|
#include "wv_cdm_constants.h"
|
|
|
|
namespace wvoec_mock {
|
|
|
|
// TODO(fredgc): These are in the level 3 directory, but they are entry points for
|
|
// both level 3 and level 1. That is confusing. Fix it.
|
|
typedef OEMCryptoResult (*L1_Initialize_t)(void);
|
|
typedef OEMCryptoResult (*L1_Terminate_t)(void);
|
|
typedef OEMCryptoResult (*L1_OpenSession_t)(OEMCrypto_SESSION *session);
|
|
typedef OEMCryptoResult (*L1_CloseSession_t)(OEMCrypto_SESSION session);
|
|
typedef OEMCryptoResult (*L1_GenerateDerivedKeys_t)(OEMCrypto_SESSION session,
|
|
const uint8_t *mac_key_context,
|
|
uint32_t mac_key_context_length,
|
|
const uint8_t *enc_key_context,
|
|
uint32_t enc_key_context_length);
|
|
typedef OEMCryptoResult (*L1_GenerateNonce_t)(OEMCrypto_SESSION session,
|
|
uint32_t* nonce);
|
|
typedef OEMCryptoResult (*L1_GenerateSignature_t)(OEMCrypto_SESSION session,
|
|
const uint8_t* message,
|
|
size_t message_length,
|
|
uint8_t* signature,
|
|
size_t* signature_length);
|
|
typedef OEMCryptoResult (*L1_LoadKeys_t)(OEMCrypto_SESSION session,
|
|
const uint8_t* message,
|
|
size_t message_length,
|
|
const uint8_t* signature,
|
|
size_t signature_length,
|
|
const uint8_t* enc_mac_key_iv,
|
|
const uint8_t* enc_mac_key,
|
|
size_t num_keys,
|
|
const OEMCrypto_KeyObject* key_array);
|
|
typedef OEMCryptoResult (*L1_RefreshKeys_t)(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);
|
|
typedef OEMCryptoResult (*L1_SelectKey_t)(const OEMCrypto_SESSION session,
|
|
const uint8_t* key_id,
|
|
size_t key_id_length);
|
|
typedef OEMCryptoResult (*L1_DecryptCTR_t)(OEMCrypto_SESSION session,
|
|
const uint8_t *data_addr,
|
|
size_t data_length,
|
|
bool is_encrypted,
|
|
const uint8_t *iv,
|
|
size_t offset,
|
|
const OEMCrypto_DestBufferDesc* out_buffer);
|
|
typedef OEMCryptoResult (*L1_InstallKeybox_t)(const uint8_t *keybox,
|
|
size_t keyBoxLength);
|
|
typedef OEMCryptoResult (*L1_IsKeyboxValid_t)(void);
|
|
typedef OEMCryptoResult (*L1_GetDeviceID_t)(uint8_t* deviceID,
|
|
size_t *idLength);
|
|
typedef OEMCryptoResult (*L1_GetKeyData_t)(uint8_t* keyData,
|
|
size_t *keyDataLength);
|
|
typedef OEMCryptoResult (*L1_GetRandom_t)(uint8_t* randomData,
|
|
size_t dataLength);
|
|
typedef OEMCryptoResult (*L1_WrapKeybox_t)(const uint8_t *keybox,
|
|
size_t keyBoxLength,
|
|
uint8_t *wrappedKeybox,
|
|
size_t *wrappedKeyBoxLength,
|
|
const uint8_t *transportKey,
|
|
size_t transportKeyLength);
|
|
typedef OEMCryptoResult (*L1_RewrapDeviceRSAKey_t)(OEMCrypto_SESSION session,
|
|
const uint8_t* message,
|
|
size_t message_length,
|
|
const uint8_t* signature,
|
|
size_t signature_length,
|
|
const uint32_t *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);
|
|
typedef OEMCryptoResult (*L1_LoadDeviceRSAKey_t)(OEMCrypto_SESSION session,
|
|
const uint8_t* wrapped_rsa_key,
|
|
size_t wrapped_rsa_key_length);
|
|
typedef OEMCryptoResult (*L1_GenerateRSASignature_t)(OEMCrypto_SESSION session,
|
|
const uint8_t* message,
|
|
size_t message_length,
|
|
uint8_t* signature,
|
|
size_t *signature_length);
|
|
typedef OEMCryptoResult (*L1_DeriveKeysFromSessionKey_t)(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);
|
|
typedef OEMCryptoResult (*L1_Generic_Encrypt_t)(OEMCrypto_SESSION session,
|
|
const uint8_t* in_buffer,
|
|
size_t buffer_length,
|
|
const uint8_t* iv,
|
|
OEMCrypto_Algorithm algorithm,
|
|
uint8_t* out_buffer);
|
|
typedef OEMCryptoResult (*L1_Generic_Decrypt_t)(OEMCrypto_SESSION session,
|
|
const uint8_t* in_buffer,
|
|
size_t buffer_length,
|
|
const uint8_t* iv,
|
|
OEMCrypto_Algorithm algorithm,
|
|
uint8_t* out_buffer);
|
|
|
|
typedef OEMCryptoResult (*L1_Generic_Sign_t)(OEMCrypto_SESSION session,
|
|
const uint8_t* in_buffer,
|
|
size_t buffer_length,
|
|
OEMCrypto_Algorithm algorithm,
|
|
uint8_t* signature,
|
|
size_t* signature_length);
|
|
|
|
typedef OEMCryptoResult (*L1_Generic_Verify_t)(OEMCrypto_SESSION session,
|
|
const uint8_t* in_buffer,
|
|
size_t buffer_length,
|
|
OEMCrypto_Algorithm algorithm,
|
|
const uint8_t* signature,
|
|
size_t signature_length);
|
|
typedef uint8_t (*L1_APIVersion_t)();
|
|
typedef const char* (*L1_SecurityLevel_t)();
|
|
|
|
struct FunctionPointers {
|
|
void* library;
|
|
L1_Initialize_t OEMCrypto_Initialize;
|
|
L1_Terminate_t OEMCrypto_Terminate;
|
|
L1_OpenSession_t OEMCrypto_OpenSession;
|
|
L1_CloseSession_t OEMCrypto_CloseSession;
|
|
L1_GenerateDerivedKeys_t OEMCrypto_GenerateDerivedKeys;
|
|
L1_GenerateNonce_t OEMCrypto_GenerateNonce;
|
|
L1_GenerateSignature_t OEMCrypto_GenerateSignature;
|
|
L1_LoadKeys_t OEMCrypto_LoadKeys;
|
|
L1_RefreshKeys_t OEMCrypto_RefreshKeys;
|
|
L1_SelectKey_t OEMCrypto_SelectKey;
|
|
L1_DecryptCTR_t OEMCrypto_DecryptCTR;
|
|
L1_InstallKeybox_t OEMCrypto_InstallKeybox;
|
|
L1_IsKeyboxValid_t OEMCrypto_IsKeyboxValid;
|
|
L1_GetDeviceID_t OEMCrypto_GetDeviceID;
|
|
L1_GetKeyData_t OEMCrypto_GetKeyData;
|
|
L1_GetRandom_t OEMCrypto_GetRandom;
|
|
L1_WrapKeybox_t OEMCrypto_WrapKeybox;
|
|
L1_RewrapDeviceRSAKey_t OEMCrypto_RewrapDeviceRSAKey;
|
|
L1_LoadDeviceRSAKey_t OEMCrypto_LoadDeviceRSAKey;
|
|
L1_GenerateRSASignature_t OEMCrypto_GenerateRSASignature;
|
|
L1_DeriveKeysFromSessionKey_t OEMCrypto_DeriveKeysFromSessionKey;
|
|
L1_APIVersion_t OEMCrypto_APIVersion;
|
|
L1_SecurityLevel_t OEMCrypto_SecurityLevel;
|
|
L1_Generic_Encrypt_t OEMCrypto_Generic_Encrypt;
|
|
L1_Generic_Decrypt_t OEMCrypto_Generic_Decrypt;
|
|
L1_Generic_Sign_t OEMCrypto_Generic_Sign;
|
|
L1_Generic_Verify_t OEMCrypto_Generic_Verify;
|
|
};
|
|
static struct FunctionPointers level1;
|
|
|
|
#define QUOTE_DEFINE(A) #A
|
|
#define QUOTE(A) QUOTE_DEFINE(A)
|
|
#define LOOKUP(Type, Name) \
|
|
level1.Name = (Type)dlsym(level1.library, QUOTE(Name)); \
|
|
if (!level1.Name) { \
|
|
dll_valid = false; \
|
|
}
|
|
|
|
typedef struct {
|
|
uint8_t signature[wvcdm::MAC_KEY_SIZE];
|
|
uint8_t context[wvcdm::MAC_KEY_SIZE];
|
|
uint8_t iv[wvcdm::KEY_IV_SIZE];
|
|
uint8_t enc_rsa_key[];
|
|
} WrappedRSAKey;
|
|
|
|
static CryptoEngine* crypto_engine = NULL;
|
|
|
|
extern "C"
|
|
OEMCryptoResult OEMCrypto_Initialize(void) {
|
|
crypto_engine = new CryptoEngine;
|
|
if (!crypto_engine || !crypto_engine->Initialized()) {
|
|
LOGE("[OEMCrypto_Initialize(): failed]");
|
|
return OEMCrypto_ERROR_INIT_FAILED;
|
|
}
|
|
LOGD("OEMCrypto_Initialize Level 3 success. Now I will try to load Level 1");
|
|
|
|
level1.library = dlopen("liboemcrypto.so", RTLD_NOW);
|
|
if (level1.library == NULL) {
|
|
LOGW("Could not load liboemcrypto.so. Falling Back to L3.");
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
bool dll_valid = true;
|
|
LOOKUP(L1_Initialize_t, OEMCrypto_Initialize);
|
|
LOOKUP(L1_Terminate_t, OEMCrypto_Terminate);
|
|
LOOKUP(L1_OpenSession_t, OEMCrypto_OpenSession);
|
|
LOOKUP(L1_CloseSession_t, OEMCrypto_CloseSession);
|
|
LOOKUP(L1_GenerateDerivedKeys_t, OEMCrypto_GenerateDerivedKeys);
|
|
LOOKUP(L1_GenerateNonce_t, OEMCrypto_GenerateNonce);
|
|
LOOKUP(L1_GenerateSignature_t, OEMCrypto_GenerateSignature);
|
|
LOOKUP(L1_LoadKeys_t, OEMCrypto_LoadKeys);
|
|
LOOKUP(L1_RefreshKeys_t, OEMCrypto_RefreshKeys);
|
|
LOOKUP(L1_SelectKey_t, OEMCrypto_SelectKey);
|
|
LOOKUP(L1_DecryptCTR_t, OEMCrypto_DecryptCTR);
|
|
LOOKUP(L1_InstallKeybox_t, OEMCrypto_InstallKeybox);
|
|
LOOKUP(L1_IsKeyboxValid_t, OEMCrypto_IsKeyboxValid);
|
|
LOOKUP(L1_GetDeviceID_t, OEMCrypto_GetDeviceID);
|
|
LOOKUP(L1_GetKeyData_t, OEMCrypto_GetKeyData);
|
|
LOOKUP(L1_GetRandom_t, OEMCrypto_GetRandom);
|
|
LOOKUP(L1_WrapKeybox_t, OEMCrypto_WrapKeybox);
|
|
|
|
// TODO(fredgc): Move the validity check from here to below after we have
|
|
// an L1 library that matches current version.
|
|
if (!dll_valid) {
|
|
dlclose(level1.library);
|
|
level1.library = NULL;
|
|
LOGW("Could not load functions from liboemcrypto.so. Falling Back to L3.");
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
LOOKUP(L1_RewrapDeviceRSAKey_t, OEMCrypto_RewrapDeviceRSAKey);
|
|
LOOKUP(L1_LoadDeviceRSAKey_t, OEMCrypto_LoadDeviceRSAKey);
|
|
LOOKUP(L1_GenerateRSASignature_t, OEMCrypto_GenerateRSASignature);
|
|
LOOKUP(L1_DeriveKeysFromSessionKey_t, OEMCrypto_DeriveKeysFromSessionKey);
|
|
LOOKUP(L1_APIVersion_t, OEMCrypto_APIVersion);
|
|
LOOKUP(L1_SecurityLevel_t, OEMCrypto_SecurityLevel);
|
|
LOOKUP(L1_Generic_Decrypt_t, OEMCrypto_Generic_Decrypt);
|
|
LOOKUP(L1_Generic_Encrypt_t, OEMCrypto_Generic_Encrypt);
|
|
LOOKUP(L1_Generic_Sign_t, OEMCrypto_Generic_Sign);
|
|
LOOKUP(L1_Generic_Verify_t, OEMCrypto_Generic_Verify);
|
|
|
|
// TODO(fredgc): Move the validity check from above to here after we have
|
|
// a current L1 library.
|
|
|
|
OEMCryptoResult st = level1.OEMCrypto_Initialize();
|
|
if (st != OEMCrypto_SUCCESS) {
|
|
LOGW("Could not initialize liboemcrypto.so. Falling Back to L3.");
|
|
dlclose(level1.library);
|
|
level1.library = NULL;
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
if (level1.OEMCrypto_APIVersion ) {
|
|
uint32_t level1_version = level1.OEMCrypto_APIVersion();
|
|
if( level1_version > oec_latest_version ) { // Check for foward jump.
|
|
LOGW("liboemcrypto.so is version %d, not %d. Falling Back to L3.",
|
|
level1_version, oec_latest_version);
|
|
dlclose(level1.library);
|
|
level1.library = NULL;
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
}
|
|
LOGD("OEMCrypto_Initialize Level 1 success. I will use level 1.");
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
extern "C"
|
|
OEMCryptoResult OEMCrypto_Terminate(void) {
|
|
if (level1.library) {
|
|
OEMCryptoResult st = level1.OEMCrypto_Terminate();
|
|
dlclose(level1.library);
|
|
level1.library = NULL;
|
|
return st;
|
|
}
|
|
if (!crypto_engine) {
|
|
LOGE("[OEMCrypto_Terminate(): failed]");
|
|
return OEMCrypto_ERROR_TERMINATE_FAILED;
|
|
}
|
|
|
|
if (crypto_engine->Initialized()) {
|
|
crypto_engine->Terminate();
|
|
}
|
|
|
|
delete crypto_engine;
|
|
crypto_engine = NULL;
|
|
LOGD("[OEMCrypto_Terminate(): success]");
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
extern "C"
|
|
OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session) {
|
|
if (level1.library) {
|
|
return level1.OEMCrypto_OpenSession(session);
|
|
}
|
|
SessionId sid = crypto_engine->CreateSession();
|
|
*session = (OEMCrypto_SESSION)sid;
|
|
LOGD("[OEMCrypto_OpenSession(): SID=%08x]", sid);
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
extern "C"
|
|
OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session) {
|
|
if (level1.library) {
|
|
return level1.OEMCrypto_CloseSession(session);
|
|
}
|
|
if (!crypto_engine->DestroySession((SessionId)session)) {
|
|
LOGD("[OEMCrypto_CloseSession(SID=%08X): failed]", session);
|
|
return OEMCrypto_ERROR_CLOSE_SESSION_FAILED;
|
|
} else {
|
|
LOGD("[OEMCrypto_CloseSession(SID=%08X): success]", session);
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
}
|
|
|
|
extern "C"
|
|
OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session,
|
|
uint32_t* nonce) {
|
|
if (level1.library) {
|
|
return level1.OEMCrypto_GenerateNonce(session, nonce);
|
|
}
|
|
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
|
if (!session_ctx || !session_ctx->isValid()) {
|
|
LOGE("[OEMCrypto_GenerateNonce(): ERROR_NO_INVALID_SESSION]");
|
|
return OEMCrypto_ERROR_INVALID_SESSION;
|
|
}
|
|
|
|
uint32_t nonce_value;
|
|
uint8_t* nonce_string = reinterpret_cast<uint8_t*>(&nonce_value);
|
|
|
|
// Generate 4 bytes of random data
|
|
if (!RAND_bytes(nonce_string, 4)) {
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
session_ctx->AddNonce(nonce_value);
|
|
*nonce = nonce_value;
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
extern "C"
|
|
OEMCryptoResult OEMCrypto_GenerateDerivedKeys(OEMCrypto_SESSION session,
|
|
const uint8_t* mac_key_context,
|
|
uint32_t mac_key_context_length,
|
|
const uint8_t* enc_key_context,
|
|
uint32_t enc_key_context_length) {
|
|
if (level1.library) {
|
|
return level1.OEMCrypto_GenerateDerivedKeys(session, mac_key_context,
|
|
mac_key_context_length,
|
|
enc_key_context,
|
|
enc_key_context_length);
|
|
}
|
|
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
|
LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_KEYBOX_INVALID]");
|
|
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
|
}
|
|
|
|
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
|
if (!session_ctx || !session_ctx->isValid()) {
|
|
LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_NO_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(mac_ctx_str, enc_ctx_str)) {
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
extern "C"
|
|
OEMCryptoResult OEMCrypto_GenerateSignature(OEMCrypto_SESSION session,
|
|
const uint8_t* message,
|
|
size_t message_length,
|
|
uint8_t* signature,
|
|
size_t* signature_length) {
|
|
if (level1.library) {
|
|
return level1.OEMCrypto_GenerateSignature( session, message, message_length,
|
|
signature, signature_length);
|
|
}
|
|
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
|
LOGE("[OEMCrypto_GenerateSignature(): ERROR_KEYBOX_INVALID]");
|
|
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
|
}
|
|
|
|
if (*signature_length < SHA256_DIGEST_LENGTH) {
|
|
*signature_length = SHA256_DIGEST_LENGTH;
|
|
return OEMCrypto_ERROR_SHORT_BUFFER;
|
|
}
|
|
|
|
if (message == NULL || message_length == 0 ||
|
|
signature == NULL || signature_length == 0) {
|
|
LOGE("[OEMCrypto_GenerateSignature(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
|
}
|
|
|
|
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
|
if (!session_ctx || !session_ctx->isValid()) {
|
|
LOGE("[OEMCrypto_GenerateSignature(): ERROR_NO_INVALID_SESSION]");
|
|
return OEMCrypto_ERROR_INVALID_SESSION;
|
|
}
|
|
|
|
if (session_ctx->GenerateSignature(message,
|
|
message_length,
|
|
signature,
|
|
signature_length)) {
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;;
|
|
}
|
|
|
|
bool RangeCheck(const uint8_t* message,
|
|
uint32_t message_length,
|
|
const uint8_t* field,
|
|
uint32_t field_length,
|
|
bool allow_null) {
|
|
if (field == NULL) return allow_null;
|
|
if (field < message) return false;
|
|
if (field + field_length > message + message_length) return false;
|
|
return true;
|
|
}
|
|
|
|
extern "C"
|
|
OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
|
const uint8_t* message,
|
|
size_t message_length,
|
|
const uint8_t* signature,
|
|
size_t signature_length,
|
|
const uint8_t* enc_mac_key_iv,
|
|
const uint8_t* enc_mac_key,
|
|
size_t num_keys,
|
|
const OEMCrypto_KeyObject* key_array) {
|
|
if (level1.library) {
|
|
return level1.OEMCrypto_LoadKeys(session, message, message_length, signature,
|
|
signature_length, enc_mac_key_iv, enc_mac_key,
|
|
num_keys, key_array);
|
|
}
|
|
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
|
LOGE("[OEMCrypto_LoadKeys(): ERROR_KEYBOX_INVALID]");
|
|
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
|
}
|
|
|
|
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
|
if (!session_ctx || !session_ctx->isValid()) {
|
|
LOGE("[OEMCrypto_LoadKeys(): ERROR_NO_INVALID_SESSION]");
|
|
return OEMCrypto_ERROR_INVALID_SESSION;
|
|
}
|
|
|
|
if (message == NULL || message_length == 0 ||
|
|
signature == NULL || signature_length == 0 ||
|
|
key_array == NULL || num_keys == 0) {
|
|
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
|
}
|
|
|
|
// Range check
|
|
if (!RangeCheck(message, message_length, enc_mac_key,
|
|
wvcdm::MAC_KEY_SIZE, true) ||
|
|
!RangeCheck(message, message_length, enc_mac_key_iv,
|
|
wvcdm::KEY_IV_SIZE, true)) {
|
|
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE - range check.]");
|
|
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
|
}
|
|
|
|
for (unsigned int i = 0; i < num_keys; i++) {
|
|
if (!RangeCheck(message, message_length, key_array[i].key_id,
|
|
key_array[i].key_id_length, false) ||
|
|
!RangeCheck(message, message_length, key_array[i].key_data,
|
|
wvcdm::KEY_SIZE, false) ||
|
|
!RangeCheck(message, message_length, key_array[i].key_data_iv,
|
|
wvcdm::KEY_IV_SIZE, false) ||
|
|
!RangeCheck(message, message_length, key_array[i].key_control,
|
|
wvcdm::KEY_CONTROL_SIZE, true) ||
|
|
!RangeCheck(message, message_length, key_array[i].key_control_iv,
|
|
wvcdm::KEY_IV_SIZE, true)) {
|
|
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE -range check %d]", i);
|
|
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
|
}
|
|
}
|
|
|
|
// Validate message signature
|
|
if (!session_ctx->ValidateMessage(message, message_length, signature, signature_length)) {
|
|
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
|
}
|
|
|
|
session_ctx->StartTimer();
|
|
|
|
// Decrypt and install keys in key object
|
|
// Each key will have a key control block. They will all have the same nonce.
|
|
std::vector<uint8_t> key_id;
|
|
std::vector<uint8_t> enc_key_data;
|
|
std::vector<uint8_t> key_data_iv;
|
|
std::vector<uint8_t> key_control;
|
|
std::vector<uint8_t> key_control_iv;
|
|
for (unsigned int i = 0; i < num_keys; i++) {
|
|
key_id.assign(key_array[i].key_id,
|
|
key_array[i].key_id + key_array[i].key_id_length);
|
|
enc_key_data.assign(key_array[i].key_data,
|
|
key_array[i].key_data + wvcdm::KEY_SIZE);
|
|
key_data_iv.assign(key_array[i].key_data_iv,
|
|
key_array[i].key_data_iv + wvcdm::KEY_IV_SIZE);
|
|
if (key_array[i].key_control == NULL) {
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
key_control.assign(key_array[i].key_control,
|
|
key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE);
|
|
key_control_iv.assign(key_array[i].key_control_iv,
|
|
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
|
|
|
|
if (!session_ctx->InstallKey(key_id, enc_key_data, key_data_iv, key_control,
|
|
key_control_iv)) {
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
}
|
|
|
|
// All keys processed. Flush nonce table
|
|
session_ctx->FlushNonces();
|
|
|
|
// enc_mac_key can be NULL if license renewal is not supported
|
|
if (enc_mac_key == NULL) return OEMCrypto_SUCCESS;
|
|
|
|
// V2 license protocol: update mac key after processing license response
|
|
const std::vector<uint8_t> enc_mac_key_str = std::vector<uint8_t>(
|
|
enc_mac_key, enc_mac_key + wvcdm::MAC_KEY_SIZE);
|
|
const std::vector<uint8_t> enc_mac_key_iv_str = std::vector<uint8_t>(
|
|
enc_mac_key_iv, enc_mac_key_iv + wvcdm::KEY_IV_SIZE);
|
|
|
|
if (!session_ctx->UpdateMacKey(enc_mac_key_str, enc_mac_key_iv_str)) {
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
extern "C"
|
|
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 (level1.library) {
|
|
return level1.OEMCrypto_RefreshKeys(session, message, message_length, signature,
|
|
signature_length, num_keys, key_array);
|
|
}
|
|
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
|
LOGE("[OEMCrypto_RefreshKeys(): ERROR_KEYBOX_INVALID]");
|
|
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
|
}
|
|
|
|
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
|
if (!session_ctx || !session_ctx->isValid()) {
|
|
LOGE("[OEMCrypto_RefreshKeys(): ERROR_NO_INVALID_SESSION]");
|
|
return OEMCrypto_ERROR_INVALID_SESSION;
|
|
}
|
|
|
|
if (message == NULL || message_length == 0 ||
|
|
signature == NULL || signature_length == 0) {
|
|
LOGE("[OEMCrypto_RefreshKeys(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
|
}
|
|
|
|
// Range check
|
|
for (unsigned int i = 0; i < num_keys; i++) {
|
|
if (!RangeCheck(message, message_length, key_array[i].key_id,
|
|
key_array[i].key_id_length, true) ||
|
|
!RangeCheck(message, message_length, key_array[i].key_control,
|
|
wvcdm::KEY_CONTROL_SIZE, true) ||
|
|
!RangeCheck(message, message_length, key_array[i].key_control_iv,
|
|
wvcdm::KEY_IV_SIZE, true)) {
|
|
LOGE("[OEMCrypto_RefreshKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE]");
|
|
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
|
}
|
|
}
|
|
|
|
// Validate message signature
|
|
if (!session_ctx->ValidateMessage(message, message_length,
|
|
signature, signature_length)) {
|
|
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
|
}
|
|
|
|
// Decrypt and refresh keys in key refresh object
|
|
std::vector<uint8_t> key_id;
|
|
std::vector<uint8_t> key_control;
|
|
std::vector<uint8_t> key_control_iv;
|
|
for (unsigned int i = 0; i < num_keys; i++) {
|
|
// TODO(gmorgan): key_id may be null if special control key type (TBS)
|
|
if (key_array[i].key_id != NULL) {
|
|
key_id.assign(key_array[i].key_id,
|
|
key_array[i].key_id + key_array[i].key_id_length);
|
|
} else {
|
|
key_id.clear();
|
|
}
|
|
if (key_array[i].key_control != NULL) {
|
|
key_control.assign(key_array[i].key_control,
|
|
key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE);
|
|
key_control_iv.assign(key_array[i].key_control_iv,
|
|
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
|
|
} else {
|
|
key_control.clear();
|
|
key_control_iv.clear();
|
|
}
|
|
|
|
if (!session_ctx->RefreshKey(key_id, key_control, key_control_iv)) {
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
}
|
|
session_ctx->StartTimer();
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
extern "C"
|
|
OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session,
|
|
const uint8_t* key_id,
|
|
size_t key_id_length) {
|
|
if (level1.library) {
|
|
return level1.OEMCrypto_SelectKey(session, key_id, key_id_length);
|
|
}
|
|
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
|
LOGE("[OEMCrypto_SelectKey(): ERROR_KEYBOX_INVALID]");
|
|
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
|
}
|
|
|
|
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
|
if (!session_ctx || !session_ctx->isValid()) {
|
|
LOGE("[OEMCrypto_SelectKey(): ERROR_NO_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->SelectContentKey(key_id_str)) {
|
|
LOGE("[OEMCrypto_SelectKey(): FAIL]");
|
|
return OEMCrypto_ERROR_NO_CONTENT_KEY;
|
|
}
|
|
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
extern "C"
|
|
OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
|
const uint8_t* data_addr,
|
|
size_t data_length,
|
|
bool is_encrypted,
|
|
const uint8_t* iv,
|
|
size_t offset,
|
|
const OEMCrypto_DestBufferDesc* out_buffer) {
|
|
if (level1.library) {
|
|
return level1.OEMCrypto_DecryptCTR( session, data_addr, data_length,
|
|
is_encrypted, iv, offset, out_buffer);
|
|
}
|
|
wvoec_mock::BufferType buffer_type = kBufferTypeDirect;
|
|
void* destination = NULL;
|
|
size_t max_length = 0;
|
|
switch (out_buffer->type) {
|
|
case OEMCrypto_BufferType_Clear:
|
|
buffer_type = kBufferTypeClear;
|
|
destination = out_buffer->buffer.clear.address;
|
|
max_length = out_buffer->buffer.clear.max_length;
|
|
break;
|
|
case OEMCrypto_BufferType_Secure:
|
|
buffer_type = kBufferTypeSecure;
|
|
destination = out_buffer->buffer.secure.handle;
|
|
max_length = out_buffer->buffer.secure.max_length;
|
|
break;
|
|
default:
|
|
case OEMCrypto_BufferType_Direct:
|
|
buffer_type = kBufferTypeDirect;
|
|
destination = NULL;
|
|
break;
|
|
}
|
|
|
|
if (buffer_type != kBufferTypeDirect && max_length < data_length) {
|
|
LOGE("[OEMCrypto_DecryptCTR(): OEMCrypto_ERROR_SHORT_BUFFER]");
|
|
return OEMCrypto_ERROR_SHORT_BUFFER;
|
|
}
|
|
|
|
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
|
LOGE("[OEMCrypto_DecryptCTR(): ERROR_KEYBOX_INVALID]");
|
|
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
|
}
|
|
|
|
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
|
if (!session_ctx || !session_ctx->isValid()) {
|
|
LOGE("[OEMCrypto_DecryptCTR(): ERROR_NO_INVALID_SESSION]");
|
|
return OEMCrypto_ERROR_INVALID_SESSION;
|
|
}
|
|
|
|
if (data_addr == NULL || data_length == 0 ||
|
|
iv == NULL || out_buffer == NULL) {
|
|
LOGE("[OEMCrypto_DecryptCTR(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
|
}
|
|
|
|
std::vector<uint8_t> iv_v(iv, iv + 16);
|
|
std::vector<uint8_t> content(data_addr, data_addr + data_length);
|
|
|
|
if (!crypto_engine->DecryptCTR(session_ctx, iv_v, (int)offset,
|
|
content, is_encrypted,
|
|
destination, buffer_type)) {
|
|
LOGE("[OEMCrypto_DecryptCTR(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
|
}
|
|
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
extern "C"
|
|
OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox,
|
|
size_t keyBoxLength) {
|
|
if (level1.library) {
|
|
return level1.OEMCrypto_InstallKeybox(keybox, keyBoxLength);
|
|
}
|
|
if (crypto_engine->keybox().InstallKeybox(keybox, keyBoxLength)) {
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
return OEMCrypto_ERROR_WRITE_KEYBOX;
|
|
}
|
|
|
|
extern "C"
|
|
OEMCryptoResult OEMCrypto_IsKeyboxValid(void) {
|
|
if (level1.library) {
|
|
return level1.OEMCrypto_IsKeyboxValid();
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
|
|
extern "C"
|
|
OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID,
|
|
size_t* idLength) {
|
|
if (level1.library) {
|
|
return level1.OEMCrypto_GetDeviceID(deviceID, idLength);
|
|
}
|
|
std::vector<uint8_t> dev_id_string = crypto_engine->keybox().device_id();
|
|
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;
|
|
LOGD("[OEMCrypto_GetDeviceId(): success]");
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
extern "C"
|
|
OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData,
|
|
size_t* keyDataLength) {
|
|
if (level1.library) {
|
|
return level1.OEMCrypto_GetKeyData(keyData, keyDataLength);
|
|
}
|
|
size_t length = crypto_engine->keybox().key_data_length();
|
|
if (*keyDataLength < length) {
|
|
*keyDataLength = length;
|
|
LOGE("[OEMCrypto_GetKeyData(): ERROR_SHORT_BUFFER]");
|
|
return OEMCrypto_ERROR_SHORT_BUFFER;
|
|
}
|
|
memset(keyData, 0, *keyDataLength);
|
|
memcpy(keyData, crypto_engine->keybox().key_data(), length);
|
|
*keyDataLength = length;
|
|
LOGD("[OEMCrypto_GetKeyData(): success]");
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
extern "C"
|
|
OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, size_t dataLength) {
|
|
if (level1.library) {
|
|
return level1.OEMCrypto_GetRandom(randomData, dataLength);
|
|
}
|
|
if (!randomData) {
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
if (RAND_bytes(randomData, dataLength)) {
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
|
|
extern "C"
|
|
OEMCryptoResult OEMCrypto_WrapKeybox(const uint8_t* keybox,
|
|
size_t keyBoxLength,
|
|
uint8_t* wrappedKeybox,
|
|
size_t* wrappedKeyBoxLength,
|
|
const uint8_t* transportKey,
|
|
size_t transportKeyLength) {
|
|
if (level1.library) {
|
|
return level1.OEMCrypto_WrapKeybox(keybox, keyBoxLength, wrappedKeybox,
|
|
wrappedKeyBoxLength, transportKey,
|
|
transportKeyLength);
|
|
}
|
|
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;
|
|
}
|
|
|
|
extern "C"
|
|
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* nonce,
|
|
const uint8_t* enc_rsa_key,
|
|
size_t enc_rsa_key_length,
|
|
const uint8_t* enc_rsa_key_iv,
|
|
uint8_t* wrapped_rsa_key,
|
|
size_t* wrapped_rsa_key_length) {
|
|
if (level1.library) {
|
|
if (!level1.OEMCrypto_RewrapDeviceRSAKey ) {
|
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return level1.OEMCrypto_RewrapDeviceRSAKey( session, message, message_length,
|
|
signature, signature_length, nonce,
|
|
enc_rsa_key, enc_rsa_key_length,
|
|
enc_rsa_key_iv, wrapped_rsa_key,
|
|
wrapped_rsa_key_length);
|
|
}
|
|
if (wrapped_rsa_key_length == NULL) {
|
|
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_LoadDeviceRSAKey below.
|
|
size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey);
|
|
|
|
if (wrapped_rsa_key == NULL || *wrapped_rsa_key_length < buffer_size) {
|
|
LOGW("[OEMCrypto_RewrapDeviceRSAKey(): Wrapped Keybox Short Buffer]");
|
|
*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 (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
|
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_KEYBOX_INVALID]");
|
|
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
|
}
|
|
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
|
if (!session_ctx || !session_ctx->isValid()) {
|
|
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_NO_INVALID_SESSION]");
|
|
return OEMCrypto_ERROR_INVALID_SESSION;
|
|
}
|
|
if (message == NULL || message_length == 0 || signature == NULL
|
|
|| signature_length == 0 || nonce == NULL || enc_rsa_key == NULL) {
|
|
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
|
}
|
|
|
|
// Range check
|
|
if (!RangeCheck(message, message_length, reinterpret_cast<const uint8_t*>(nonce),
|
|
sizeof(uint32_t), true) ||
|
|
!RangeCheck(message, message_length, enc_rsa_key, enc_rsa_key_length,
|
|
true) ||
|
|
!RangeCheck(message, message_length, enc_rsa_key_iv, wvcdm::KEY_IV_SIZE,
|
|
true)) {
|
|
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): - range check.]");
|
|
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
|
}
|
|
|
|
|
|
// Validate nonce
|
|
if (!session_ctx->CheckNonce(*nonce)) {
|
|
return OEMCrypto_ERROR_INVALID_NONCE;
|
|
}
|
|
session_ctx->FlushNonces();
|
|
|
|
// Decrypt key and verify signature.
|
|
if (!session_ctx->LoadRSAKey(enc_rsa_key, enc_rsa_key_length,
|
|
enc_rsa_key_iv, message, message_length,
|
|
signature, signature_length)) {
|
|
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
|
// 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> mac_ctx_str(wrapped->context,
|
|
wrapped->context + sizeof(wrapped->context));
|
|
// Generate mac and encryption keys for encrypting the signature.
|
|
if (!session_ctx->DeriveKeys(mac_ctx_str, mac_ctx_str)) {
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
|
|
// Encrypt rsa key with keybox.
|
|
if (!session_ctx->EncryptRSAKey(wrapped->enc_rsa_key,
|
|
enc_rsa_key_length,
|
|
wrapped->iv)) {
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
|
|
size_t sig_length = sizeof(wrapped->signature);
|
|
if (!session_ctx->GenerateSignature(wrapped->context, // start signing here.
|
|
buffer_size - sizeof(wrapped->signature),
|
|
wrapped->signature,
|
|
&sig_length)) {
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
extern "C"
|
|
OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session,
|
|
const uint8_t* wrapped_rsa_key,
|
|
size_t wrapped_rsa_key_length) {
|
|
if (level1.library) {
|
|
if (!level1.OEMCrypto_LoadDeviceRSAKey ) {
|
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return level1.OEMCrypto_LoadDeviceRSAKey( session, wrapped_rsa_key,
|
|
wrapped_rsa_key_length);
|
|
}
|
|
const WrappedRSAKey* wrapped
|
|
= reinterpret_cast<const WrappedRSAKey*>(wrapped_rsa_key);
|
|
if (wrapped_rsa_key == NULL) {
|
|
LOGE("[OEMCrypto_LoadDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
|
}
|
|
|
|
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
|
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_KEYBOX_INVALID]");
|
|
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
|
}
|
|
|
|
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
|
if (!session_ctx || !session_ctx->isValid()) {
|
|
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_NO_INVALID_SESSION]");
|
|
return OEMCrypto_ERROR_INVALID_SESSION;
|
|
}
|
|
const std::vector<uint8_t> mac_ctx_str(wrapped->context,
|
|
wrapped->context + sizeof(wrapped->context));
|
|
// Generate mac and encryption keys for encrypting the signature.
|
|
if (!session_ctx->DeriveKeys(mac_ctx_str, mac_ctx_str)) {
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
// Decrypt key and verify signature.
|
|
if (!session_ctx->LoadRSAKey(wrapped->enc_rsa_key,
|
|
wrapped_rsa_key_length - sizeof(WrappedRSAKey),
|
|
wrapped->iv,
|
|
wrapped->context,
|
|
wrapped_rsa_key_length - sizeof(wrapped->signature),
|
|
wrapped->signature,
|
|
sizeof(wrapped->signature))) {
|
|
return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
|
}
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
extern "C"
|
|
OEMCryptoResult OEMCrypto_GenerateRSASignature(OEMCrypto_SESSION session,
|
|
const uint8_t* message,
|
|
size_t message_length,
|
|
uint8_t* signature,
|
|
size_t* signature_length) {
|
|
if (level1.library) {
|
|
if (!level1.OEMCrypto_GenerateRSASignature ) {
|
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return level1.OEMCrypto_GenerateRSASignature(session, message, message_length,
|
|
signature, signature_length);
|
|
}
|
|
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
|
LOGE("[OEMCrypto_GenerateRSASignature(): ERROR_KEYBOX_INVALID]");
|
|
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
|
}
|
|
|
|
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 || !session_ctx->isValid()) {
|
|
LOGE("[OEMCrypto_GenerateRSASignature(): ERROR_NO_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 == NULL || message_length == 0 ||
|
|
signature == NULL || signature_length == 0) {
|
|
LOGE("[OEMCrypto_GenerateRSASignature(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
|
}
|
|
|
|
if (session_ctx->GenerateRSASignature(message,
|
|
message_length,
|
|
signature,
|
|
signature_length)) {
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;;
|
|
}
|
|
|
|
extern "C"
|
|
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 (level1.library) {
|
|
if (!level1.OEMCrypto_DeriveKeysFromSessionKey ) {
|
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return level1.OEMCrypto_DeriveKeysFromSessionKey(session, enc_session_key,
|
|
enc_session_key_length,
|
|
mac_key_context,
|
|
mac_key_context_length,
|
|
enc_key_context,
|
|
enc_key_context_length);
|
|
}
|
|
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
|
LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_KEYBOX_INVALID]");
|
|
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
|
}
|
|
|
|
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
|
if (!session_ctx || !session_ctx->isValid()) {
|
|
LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_NO_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
|
|
if (!session_ctx->RSADeriveKeys(ssn_key_str, mac_ctx_str, enc_ctx_str)) {
|
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
}
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
extern "C"
|
|
uint32_t OEMCrypto_APIVersion() {
|
|
if (level1.library) {
|
|
if (!level1.OEMCrypto_APIVersion ) {
|
|
return 5;
|
|
}
|
|
return level1.OEMCrypto_APIVersion();
|
|
}
|
|
return oec_latest_version;
|
|
}
|
|
|
|
extern "C"
|
|
const char* OEMCrypto_SecurityLevel() {
|
|
if (level1.library) {
|
|
if (!level1.OEMCrypto_SecurityLevel ) {
|
|
return "Unknown";
|
|
}
|
|
return level1.OEMCrypto_SecurityLevel();
|
|
}
|
|
return "L3";
|
|
}
|
|
|
|
extern "C"
|
|
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 (level1.library) {
|
|
if (!level1.OEMCrypto_Generic_Encrypt ) {
|
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return level1.OEMCrypto_Generic_Encrypt(session, in_buffer, buffer_length,
|
|
iv, algorithm, out_buffer);
|
|
}
|
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
extern "C"
|
|
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 (level1.library) {
|
|
if (!level1.OEMCrypto_Generic_Decrypt ) {
|
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return level1.OEMCrypto_Generic_Decrypt(session, in_buffer, buffer_length,
|
|
iv, algorithm, out_buffer);
|
|
}
|
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
extern "C"
|
|
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 (level1.library) {
|
|
if (!level1.OEMCrypto_Generic_Sign ) {
|
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return level1.OEMCrypto_Generic_Sign(session, in_buffer, buffer_length,
|
|
algorithm, signature,
|
|
signature_length);
|
|
}
|
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
extern "C"
|
|
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 (level1.library) {
|
|
if (!level1.OEMCrypto_Generic_Verify ) {
|
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return level1.OEMCrypto_Generic_Verify(session, in_buffer, buffer_length,
|
|
algorithm, signature,
|
|
signature_length);
|
|
}
|
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
}; // namespace wvoec_mock
|