From 1aff209f91cc11a31397f6d30e491028b30d1254 Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Tue, 23 Apr 2013 13:21:44 -0700 Subject: [PATCH] Field provisioning for L3 OEMCrypto bug: 8621460 Merge of https://widevine-internal-review.googlesource.com/#/c/4955/ from Widevine CDM repository. Change-Id: I30cf4314283db51c8e706c026501784259c87c13 --- libwvdrmengine/Android.mk | 4 +- .../cdm/core/src/client_files.proto | 27 - libwvdrmengine/cdm/test/unit-test.mk | 3 +- libwvdrmengine/level3/Android.mk | 40 +- libwvdrmengine/level3/arm/Android.mk | 12 + libwvdrmengine/level3/arm/entry_points.cpp | 1308 ----------------- libwvdrmengine/level3/arm/libwvlevel3.a | Bin 0 -> 292248 bytes libwvdrmengine/level3/mips/Android.mk | 12 + libwvdrmengine/level3/mips/entry_points.cpp | 1308 ----------------- libwvdrmengine/level3/mips/libwvlevel3.a | Bin 0 -> 311294 bytes libwvdrmengine/level3/x86/Android.mk | 12 + libwvdrmengine/level3/x86/entry_points.cpp | 1308 ----------------- libwvdrmengine/level3/x86/libwvlevel3.a | Bin 0 -> 303754 bytes libwvdrmengine/mediacrypto/test/Android.mk | 3 +- libwvdrmengine/mediadrm/test/Android.mk | 3 +- libwvdrmengine/oemcrypto/Android.mk | 34 + .../oemcrypto/include/OEMCryptoCENC.h | 2 - libwvdrmengine/oemcrypto/include/level3.h | 160 ++ libwvdrmengine/oemcrypto/src/wrapper.cpp | 626 ++++++++ libwvdrmengine/oemcrypto/test/Android.mk | 38 +- .../oemcrypto/test/oemcrypto_keybox_test.cpp | 27 +- .../oemcrypto/test/oemcrypto_test.cpp | 16 +- 22 files changed, 912 insertions(+), 4031 deletions(-) delete mode 100644 libwvdrmengine/cdm/core/src/client_files.proto create mode 100644 libwvdrmengine/level3/arm/Android.mk delete mode 100644 libwvdrmengine/level3/arm/entry_points.cpp create mode 100644 libwvdrmengine/level3/arm/libwvlevel3.a create mode 100644 libwvdrmengine/level3/mips/Android.mk delete mode 100644 libwvdrmengine/level3/mips/entry_points.cpp create mode 100644 libwvdrmengine/level3/mips/libwvlevel3.a create mode 100644 libwvdrmengine/level3/x86/Android.mk delete mode 100644 libwvdrmengine/level3/x86/entry_points.cpp create mode 100644 libwvdrmengine/level3/x86/libwvlevel3.a create mode 100644 libwvdrmengine/oemcrypto/Android.mk create mode 100644 libwvdrmengine/oemcrypto/include/level3.h create mode 100644 libwvdrmengine/oemcrypto/src/wrapper.cpp diff --git a/libwvdrmengine/Android.mk b/libwvdrmengine/Android.mk index 0f528b63..d5762a12 100644 --- a/libwvdrmengine/Android.mk +++ b/libwvdrmengine/Android.mk @@ -59,7 +59,8 @@ LOCAL_C_INCLUDES := \ LOCAL_STATIC_LIBRARIES := \ libcdm \ - libl3crypto \ + libwvwrapper \ + libwvlevel3 \ libprotobuf-cpp-2.3.0-lite \ libwvdrmcryptoplugin \ libwvdrmdrmplugin \ @@ -87,6 +88,7 @@ include $(BUILD_SHARED_LIBRARY) include vendor/widevine/libwvdrmengine/cdm/Android.mk include vendor/widevine/libwvdrmengine/level3/Android.mk +include vendor/widevine/libwvdrmengine/oemcrypto/Android.mk include vendor/widevine/libwvdrmengine/mediacrypto/Android.mk include vendor/widevine/libwvdrmengine/mediadrm/Android.mk diff --git a/libwvdrmengine/cdm/core/src/client_files.proto b/libwvdrmengine/cdm/core/src/client_files.proto deleted file mode 100644 index 33ddb04c..00000000 --- a/libwvdrmengine/cdm/core/src/client_files.proto +++ /dev/null @@ -1,27 +0,0 @@ -// ---------------------------------------------------------------------------- -// client_files.proto -// ---------------------------------------------------------------------------- -// Copyright 2013 Google Inc. All Rights Reserved. -// -// Description: -// Format of various files stored at the device. -// -syntax = "proto2"; - -package video_widevine_client.sdk; - -// need this if we are using libprotobuf-cpp-2.3.0-lite -option optimize_for = LITE_RUNTIME; - -message DeviceCertificateFileFormat { - optional int32 version = 1; - optional bytes certificate = 2; - optional bytes wrapped_private_key = 3; -} - -message LicenseFileFormat { - optional int32 version = 1; - optional bytes key_set_id = 2; - optional bytes license_request = 3; - optional bytes license = 4; -} diff --git a/libwvdrmengine/cdm/test/unit-test.mk b/libwvdrmengine/cdm/test/unit-test.mk index e465ca7c..909b8fb1 100644 --- a/libwvdrmengine/cdm/test/unit-test.mk +++ b/libwvdrmengine/cdm/test/unit-test.mk @@ -36,7 +36,8 @@ LOCAL_STATIC_LIBRARIES := \ libgmock \ libgtest \ libgtest_main \ - libl3crypto \ + libwvwrapper \ + libwvlevel3 \ libprotobuf-cpp-2.3.0-lite LOCAL_WHOLE_STATIC_LIBRARIES := libcdm_protos diff --git a/libwvdrmengine/level3/Android.mk b/libwvdrmengine/level3/Android.mk index 3f8a09ba..d52c9716 100644 --- a/libwvdrmengine/level3/Android.mk +++ b/libwvdrmengine/level3/Android.mk @@ -1,38 +1,4 @@ -LOCAL_PATH:= $(call my-dir) +ifneq ($(filter arm x86 mips,$(TARGET_ARCH)),) +include $(call all-subdir-makefiles) +endif -include $(CLEAR_VARS) - -# TODO(fredgc): remove mock code as real code starts working. -LOCAL_SRC_FILES := \ - $(TARGET_ARCH)/entry_points.cpp \ - ../oemcrypto/mock/src/oemcrypto_engine_mock.cpp \ - ../oemcrypto/mock/src/oemcrypto_key_mock.cpp \ - ../oemcrypto/mock/src/oemcrypto_keybox_mock.cpp \ - ../oemcrypto/mock/src/lock.cpp \ - ../oemcrypto/mock/src/log.cpp \ - ../oemcrypto/mock/src/string_conversions.cpp \ - ../oemcrypto/mock/src/wvcrc.cpp \ - -# TODO(fredgc): remove mock include when real code starts working. -LOCAL_C_INCLUDES += \ - vendor/widevine/libwvdrmengine/oemcrypto/mock/src \ - bionic \ - external/openssh \ - external/openssl/include \ - external/stlport/stlport \ - vendor/widevine/libwvdrmengine/oemcrypto/include \ - $(LOCAL_PATH)/include \ - $(LOCAL_PATH)/$(TARGET_ARCH) - -LOCAL_MODULE := libl3crypto - -LOCAL_SHARED_LIBRARIES := \ - libcrypto \ - libcutils \ - libdl \ - liblog \ - libstlport \ - libutils \ - libz \ - -include $(BUILD_STATIC_LIBRARY) diff --git a/libwvdrmengine/level3/arm/Android.mk b/libwvdrmengine/level3/arm/Android.mk new file mode 100644 index 00000000..74264a75 --- /dev/null +++ b/libwvdrmengine/level3/arm/Android.mk @@ -0,0 +1,12 @@ +ifeq ($(TARGET_ARCH),arm) +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := libwvlevel3 +LOCAL_MODULE_CLASS := STATIC_LIBRARIES +LOCAL_MODULE_SUFFIX := .a +LOCAL_SRC_FILES := $(LOCAL_MODULE)$(LOCAL_MODULE_SUFFIX) +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_OWNER := widevine +include $(BUILD_PREBUILT) +endif # if arm. diff --git a/libwvdrmengine/level3/arm/entry_points.cpp b/libwvdrmengine/level3/arm/entry_points.cpp deleted file mode 100644 index 6f04a87c..00000000 --- a/libwvdrmengine/level3/arm/entry_points.cpp +++ /dev/null @@ -1,1308 +0,0 @@ -/******************************************************************************* - * - * Copyright 2013 Google Inc. All Rights Reserved. - * - * Wrapper for Level 1 OEMCrypto or Level 3 Fallback APIs - * - ******************************************************************************/ - -#include "OEMCryptoCENC.h" - -#include -#include -#include -#include -#include - -#include "log.h" -#include "oemcrypto_engine_mock.h" -#include "openssl/cmac.h" -#include "openssl/evp.h" -#include "openssl/hmac.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, - uint8_t subsample_flags); -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(&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 mac_ctx_str(mac_key_context, - mac_key_context + mac_key_context_length); - const std::vector 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->keybox().device_key().value(), - 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_keys, - 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_keys, - 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_keys, - 2*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, - key_array[i].key_data_length, 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, false) || - !RangeCheck(message, message_length, key_array[i].key_control_iv, - wvcdm::KEY_IV_SIZE, false)) { - 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. - bool status = true; - std::vector key_id; - std::vector enc_key_data; - std::vector key_data_iv; - std::vector key_control; - std::vector 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 + key_array[i].key_data_length); - 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) { - status = false; - break; - } - 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)) { - status = false; - break; - } - } - - session_ctx->FlushNonces(); - if (!status) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - - // enc_mac_key can be NULL if license renewal is not supported - if (enc_mac_keys == NULL) return OEMCrypto_SUCCESS; - - // V2.1 license protocol: update mac keys after processing license response - const std::vector enc_mac_keys_str = std::vector( - enc_mac_keys, enc_mac_keys + 2*wvcdm::MAC_KEY_SIZE); - const std::vector enc_mac_key_iv_str = std::vector( - enc_mac_key_iv, enc_mac_key_iv + wvcdm::KEY_IV_SIZE); - - if (!session_ctx->UpdateMacKeys(enc_mac_keys_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 || - num_keys == 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, false) || - !RangeCheck(message, message_length, key_array[i].key_control_iv, - wvcdm::KEY_IV_SIZE, true)) { - LOGE("[OEMCrypto_RefreshKeys(): Range Check %d]", i); - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - } - - // Validate message signature - if (!session_ctx->ValidateMessage(message, message_length, - signature, signature_length)) { - LOGE("[OEMCrypto_RefreshKeys(): signature was invalid]"); - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - - // Decrypt and refresh keys in key refresh object - bool status = true; - std::vector key_id; - std::vector key_control; - std::vector key_control_iv; - for (unsigned int i = 0; i < num_keys; i++) { - 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); - key_control.assign(key_array[i].key_control, - key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE); - if (key_array[i].key_control_iv == NULL ) { - key_control_iv.clear(); - } else { - key_control_iv.assign(key_array[i].key_control_iv, - key_array[i].key_control_iv + wvcdm::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(key_array[i].key_control, - key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE); - } - - if (!session_ctx->RefreshKey(key_id, key_control, key_control_iv)) { - LOGE("[OEMCrypto_RefreshKeys(): error in key %i]", i); - status = false; - break; - } - } - - session_ctx->FlushNonces(); - if (!status) 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 key_id_vec = std::vector(key_id, key_id + key_id_length); - if (!session_ctx->SelectContentKey(key_id_vec)) { - 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 block_offset, - const OEMCrypto_DestBufferDesc* out_buffer, - uint8_t subsample_flags) { - if (level1.library) { - return level1.OEMCrypto_DecryptCTR( session, data_addr, data_length, - is_encrypted, iv, block_offset, - out_buffer, subsample_flags); - } - wvoec_mock::BufferType buffer_type = kBufferTypeDirect; - uint8_t* 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 = ((uint8_t*)out_buffer->buffer.secure.handle - + out_buffer->buffer.secure.offset); - 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; - } - -#ifndef NDEBUG - if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_DecryptCTR(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } -#endif - - 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; - } - - if (!crypto_engine->DecryptCTR(session_ctx, iv, (int)block_offset, - data_addr, data_length, is_encrypted, - destination, buffer_type)) { - LOGE("[OEMCrypto_DecryptCTR(): OEMCrypto_ERROR_DECRYPT_FAILED]"); - return OEMCrypto_ERROR_DECRYPT_FAILED; - } - - 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 dev_id_vec = crypto_engine->keybox().device_id(); - if (dev_id_vec.empty()) { - LOGE("[OEMCrypto_GetDeviceId(): Keybox Invalid]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - - size_t dev_id_len = dev_id_vec.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_vec[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(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 RSA key. - uint8_t* pkcs8_rsa_key = new uint8_t[enc_rsa_key_length]; - OEMCryptoResult result = OEMCrypto_SUCCESS; - if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length, - enc_rsa_key_iv, pkcs8_rsa_key)) { - result = OEMCrypto_ERROR_INVALID_RSA_KEY; - } - size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1]; - if( result == OEMCrypto_SUCCESS) { - if (padding > 16) { - LOGE("[RewrapRSAKey(): Encrypted RSA has bad padding: %d]", padding); - result = OEMCrypto_ERROR_INVALID_RSA_KEY; - } - } - size_t rsa_key_length = enc_rsa_key_length - padding; - // verify signature, verify RSA key, and load it. - if( result == OEMCrypto_SUCCESS) { - if (!session_ctx->LoadRSAKey(pkcs8_rsa_key, rsa_key_length, - message, message_length, - signature, signature_length)) { - result = OEMCrypto_ERROR_SIGNATURE_FAILURE; - // return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - } - - // Now we generate a wrapped keybox. - WrappedRSAKey* wrapped = reinterpret_cast(wrapped_rsa_key); - // Pick a random context and IV for generating keys. - if( result == OEMCrypto_SUCCESS) { - if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - } - const std::vector context(wrapped->context, - wrapped->context + sizeof(wrapped->context)); - // Generate mac and encryption keys for encrypting the signature. - if( result == OEMCrypto_SUCCESS) { - if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(), - context, context)) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - } - - // Encrypt rsa key with keybox. - if( result == OEMCrypto_SUCCESS) { - if (!session_ctx->EncryptRSAKey(pkcs8_rsa_key, enc_rsa_key_length, - wrapped->iv, wrapped->enc_rsa_key)) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - } - delete[] pkcs8_rsa_key; - - // 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. - if( result == OEMCrypto_SUCCESS) { - size_t sig_length = sizeof(wrapped->signature); - if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0], - SHA256_DIGEST_LENGTH, wrapped->context, - buffer_size - sizeof(wrapped->signature), wrapped->signature, - &sig_length)) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - } - return result; -} - -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); - } - if (wrapped_rsa_key == NULL) { - LOGE("[OEMCrypto_LoadDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - const WrappedRSAKey* wrapped - = reinterpret_cast(wrapped_rsa_key); - - if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_LoadDeviceRSAKey(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (!session_ctx || !session_ctx->isValid()) { - LOGE("[OEMCrypto_LoadDeviceRSAKey(): ERROR_NO_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - const std::vector context(wrapped->context, - wrapped->context + sizeof(wrapped->context)); - // Generate mac and encryption keys for encrypting the signature. - if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(), - context, context)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - // Decrypt RSA key. - uint8_t* pkcs8_rsa_key = new uint8_t[wrapped_rsa_key_length - - sizeof(wrapped->signature)]; - size_t enc_rsa_key_length = wrapped_rsa_key_length - sizeof(WrappedRSAKey); - OEMCryptoResult result = OEMCrypto_SUCCESS; - if (!session_ctx->DecryptRSAKey(wrapped->enc_rsa_key, enc_rsa_key_length, - wrapped->iv, pkcs8_rsa_key)) { - result = OEMCrypto_ERROR_INVALID_RSA_KEY; - } - size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1]; - if( result == OEMCrypto_SUCCESS) { - if (padding > 16) { - LOGE("[LoadDeviceRSAKey(): Encrypted RSA has bad padding: %d]", padding); - result = OEMCrypto_ERROR_INVALID_RSA_KEY; - } - } - size_t rsa_key_length = enc_rsa_key_length - padding; - // verify signature. - if( result == OEMCrypto_SUCCESS) { - if (!session_ctx->LoadRSAKey(pkcs8_rsa_key, rsa_key_length, - wrapped->context, - wrapped_rsa_key_length - sizeof(wrapped->signature), - wrapped->signature, - sizeof(wrapped->signature))) { - result = OEMCrypto_ERROR_SIGNATURE_FAILURE; - // return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - } - delete[] pkcs8_rsa_key; - return result; -} - -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 ssn_key_vec(enc_session_key, - enc_session_key + enc_session_key_length); - const std::vector mac_ctx_vec(mac_key_context, - mac_key_context + mac_key_context_length); - const std::vector enc_ctx_vec(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_vec, mac_ctx_vec, enc_ctx_vec)) { - 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); - } - if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_Generic_Enrypt(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (!session_ctx || !session_ctx->isValid()) { - LOGE("[OEMCrypto_Generic_Enrypt(): ERROR_NO_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (in_buffer == NULL || buffer_length == 0 || - iv == NULL || out_buffer == NULL) { - LOGE("[OEMCrypto_Generic_Enrypt(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!session_ctx->Generic_Encrypt(in_buffer, buffer_length, iv, algorithm, - out_buffer)) { - LOGE("[OEMCrypto_Generic_Enrypt(): OEMCrypto_ERROR_UNKNOWN_FAILURE]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -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); - } - if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_Generic_Decrypt(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (!session_ctx || !session_ctx->isValid()) { - LOGE("[OEMCrypto_Generic_Decrypt(): ERROR_NO_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (!session_ctx->Generic_Decrypt(in_buffer, buffer_length, iv, algorithm, - out_buffer)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (in_buffer == NULL || buffer_length == 0 || - iv == NULL || out_buffer == NULL) { - LOGE("[OEMCrypto_Generic_Decrypt(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - return OEMCrypto_SUCCESS; -} - -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); - } - if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_Generic_Sign(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (!session_ctx || !session_ctx->isValid()) { - LOGE("[OEMCrypto_Generic_Sign(): ERROR_NO_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 == NULL || buffer_length == 0 || signature == NULL) { - LOGE("[OEMCrypto_Generic_Sign(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!session_ctx->Generic_Sign(in_buffer, buffer_length, algorithm, - signature, signature_length)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -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); - } - if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_Generic_Verify(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (!session_ctx || !session_ctx->isValid()) { - LOGE("[OEMCrypto_Generic_Verify(): ERROR_NO_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (signature_length != SHA256_DIGEST_LENGTH) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (in_buffer == NULL || buffer_length == 0 || signature == NULL) { - LOGE("[OEMCrypto_Generic_Verify(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!session_ctx->Generic_Verify(in_buffer, buffer_length, algorithm, - signature, signature_length)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -}; // namespace wvoec_mock diff --git a/libwvdrmengine/level3/arm/libwvlevel3.a b/libwvdrmengine/level3/arm/libwvlevel3.a new file mode 100644 index 0000000000000000000000000000000000000000..18353b7ef829ca09d24f0b15ad727f368a164202 GIT binary patch literal 292248 zcmeFa4SZcioj!hUZrY}yEomvxH|kB=LK@nVo1}Sx3eC$sZAjXNB!z<2dvB7P-V14R zP0}`n0_8=l3RdN1xth;7+{qO#tXI{>k zb8>GI5Yf;7^P5j5bLPx5&-eSCnKO6JIWuz#*TnlflNaY-5c0Zkd1YnQ>Tqd!WhhiC zlFa|1P|fPHGMOWmZ&}u_E$iI$U)Fzc*s|UV|J5~?^=AD`w_4UOQ5=6|KJf0P*8lZ? zS{dYg_*>SW#s8nQm6Of?YM+(!+oj|B;Phfk__@zn!H%U?@Uuf!@W&^u+?g*~xlK!> zS8Z$?Xef*9wB%8kM?IaLrC}MA$)H9A;Zhk?$Uvrr%Vlh}3@T+%B?HAGA*B*hD$`0O zOR3CIS}ilEK*}qV^2#JjnUq&1$;xE*GRavcS;|07gTgh@4blF1@3urV)teej#d}iM zCL%3Ooo%I2iKs7Qw6&=%-q;yYr^3EdmC>Q9nyN}&Iyx$f=&Fr6TB^!!FdXho#`~j# z{qfY`09Y$~62037lO&}8g-1|R-JuHHJr`bGx;oO5yjrL-Sds2e?F^Si+Xnknz1yN4 z@qt8Rr%*K_OzTR-dwTjhtI~Z(?XLI>6#q>^12f14)hp9K~Ns6}?I?OH@<<<}nR%Z)!(Pd6g`Tx9Xy8b1t6C z6P;*U^5RM2;z>p#x4!WDw(3Q%H ztFCSEEn}QyiC%4%U`-XSMxkM)Q-W2KD#7t+M2Sfnx3bt&wbj0}Ud^j@Q)s+e7vt3t zr$J(-s>MgQGaAsUHS zCB(w<#4h!lq^`g!U7OL=AW9sag?n*lsY`FQv0+BiX??lKU*A%)ZtLmmi1##hM9`aV zh;}79`xDy}y@QjgQZyJJLu=n4f9iV@-QzH{wv~IX4j&78G0D=O+LnCNH2A4+O~A5v zZ)YOfjox*FmP(~iA=&DrysG9}Z=LwGHpFEwJD=rmM|0!&GSxef=pU~nn{Yk1t>d5g zwSD_8hH$ymExMyO_1+x`{zz2+rFCFmmg#~+5!K@|a#S31-Ntt%x;=eQc=fhuXaDZ> zU|$pi>{PF(KMYqyF%(Vj#t(LCC&v94q3p!iq(%LriA%Js+=~%|(_Qg?45>We@kc`b zky5zS9hFB~cB;{@?jdoL<^3rMuZ~7{WYtuaLb$Y*H!=0e1V+ysAHtNY#n{a)CjL$$ zR@PA=hmd->I0msg(N!%;%A&rpoZ{%{>~M#ss+(6yT{SiCVBDKjy1I*ZPRXk~Fr>J; zrKzl9Q)ENEte}R(z+l~u?(RfCjyjXx5hAI>*K8K5wzBHSTG zK~fe-bwzi#7ebd}5&n zTp2rB{QOMzwq@)9l{YcYNXIq2t2A65uGpN$J$RyF2Zm6ozFt`CYb;}06HF2HIW{4j zrG1oPh%PQ5-Mfv+%3-rHP92jTZ*!}`H9&Sj(tr)|PV_(nnVLUtj57X&kCCG93efYo z_XUWUH#YLtkY((-GpIumk1cqf<(&b;H+yIB_G)RiTDPFtQuHP1J1Z}zw!xl3eIwmr z_CW2?_EHpPrKo|iw-j%$amHr4e;O=xn{_KyjRxos@dV17wG#cMA#GgM+frmNW@ty(6A=|J|;mZDmd|Zbt zMk6147xMq7`xsiM?_=J?jm4O1__JR3lf2oei?&_LKcf=eTcNjC;|w<-b$^X|vA@l9 zQ-Y$j(c$7E)M~#~kHS(zctTMl%EH?XR@i)cF{YYWnJ!Qd;KCJE;@2=^YE@;K7*+T? z8~li=-?1@--Q87qRxQW1S91to>5hrpXm0OGi5~IR$bY%{UWbq|T;7%#wEO$E%lCSjD%D%E zyl~|GgP&brTKbM`GB+-GcV!N&)LRQblhNH!e7JNVF<9T%JJ{dXgY3Scy<4dQJMpc+ z8@i1ti~gzaaJ>4B9e`5nEH{MN?®7_-F(22$I4IoN8%O<5$evz>h_OSh~Pk45<~ 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⁣~^ z*M6Hb!z!9$=Zt)0>yzz)vakPk#x(1K(U(^I%d2~=B_VqX;!{RvloB5}cwT(@yhOY( zwj^a0U6l@{rlt#1O^cSqv2#2e_l&3fP`scp7H5tnDSLxeWN%!MzP{mxhAAT<`xB#9 z0aJ2T7u#X`YEj35($`O1yy5x=S!%`e4%NN;csvzZcy8*!x||cAURY2T7+I3Mcj4W2 ztADWE_FEB86{V~ttqZ2YhJW1phxS1E@dZ}#f4+47CadJ}V^d+@)KmD$TykSWaO8z| z<s<{_@`}u$GU$wCrF0`G$~fEt~P%S<_~W&T0`h-gjR7^?BX#qS(Tbg&PY~H#7_^ z`o?dq8S~d$ONJV9N8T~-d-DS2HxBJef8)0^a;%d7cqx>!3NKhvyZPKydAcaIdH%Ba z=^F|*(%#$=TAQ<)yr#7w`}GstYrg;;%pCatK-uwaWD-6GUk!gDJRQrlrpYR-K`X~M z8*0BN+WFq1nTOcYH;9%#?NC^hW4Lj~LHT_Fd>P>Aj89OmmE`{wjV0K3KWGO+jI9|7 z6z(lrV$T%c37DcvbnnW%<4YQ?(2RS}S9|nZOV1lAwR0YsTVyR|zP)zn=tA{Hh}T}p zd2HsPm5-Fz)`7qQrWV?Bi*f{GiCt>16xV%@U3|E}>7T5Tz|v^~vEiNz@wKFnsw-n7 zzYcPfb?oQTWa~ME_<6H#hQAtKm&N0k%-nlkQ?a<-pF}xOvt0Z9v88^6w$$QmZ+U%^C|O=}8p}j^$+ng^G7}}t5+g#M zlME{lE>G@LR$L&iZ;qAdI2_voU&jdC@MEj?_V=wCz|P$9p58vIH!-*>**7rQ8{eL= zO2cL46{{<&s%zpMot9^3Zk*^!bZ^5K%&zI#-rJXcZ~wsHj-9)Pc3)dtSKkn^*R5~7 zw5fT+#!W4kwYIfyzWjl?`QfMNI{s-�bQ(jq)??g(7 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 literal 0 HcmV?d00001 diff --git a/libwvdrmengine/level3/mips/Android.mk b/libwvdrmengine/level3/mips/Android.mk new file mode 100644 index 00000000..b1311058 --- /dev/null +++ b/libwvdrmengine/level3/mips/Android.mk @@ -0,0 +1,12 @@ +ifeq ($(TARGET_ARCH),mips) +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := libwvlevel3 +LOCAL_MODULE_CLASS := STATIC_LIBRARIES +LOCAL_MODULE_SUFFIX := .a +LOCAL_SRC_FILES := $(LOCAL_MODULE)$(LOCAL_MODULE_SUFFIX) +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_OWNER := widevine +include $(BUILD_PREBUILT) +endif # if mips. diff --git a/libwvdrmengine/level3/mips/entry_points.cpp b/libwvdrmengine/level3/mips/entry_points.cpp deleted file mode 100644 index 6f04a87c..00000000 --- a/libwvdrmengine/level3/mips/entry_points.cpp +++ /dev/null @@ -1,1308 +0,0 @@ -/******************************************************************************* - * - * Copyright 2013 Google Inc. All Rights Reserved. - * - * Wrapper for Level 1 OEMCrypto or Level 3 Fallback APIs - * - ******************************************************************************/ - -#include "OEMCryptoCENC.h" - -#include -#include -#include -#include -#include - -#include "log.h" -#include "oemcrypto_engine_mock.h" -#include "openssl/cmac.h" -#include "openssl/evp.h" -#include "openssl/hmac.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, - uint8_t subsample_flags); -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(&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 mac_ctx_str(mac_key_context, - mac_key_context + mac_key_context_length); - const std::vector 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->keybox().device_key().value(), - 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_keys, - 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_keys, - 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_keys, - 2*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, - key_array[i].key_data_length, 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, false) || - !RangeCheck(message, message_length, key_array[i].key_control_iv, - wvcdm::KEY_IV_SIZE, false)) { - 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. - bool status = true; - std::vector key_id; - std::vector enc_key_data; - std::vector key_data_iv; - std::vector key_control; - std::vector 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 + key_array[i].key_data_length); - 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) { - status = false; - break; - } - 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)) { - status = false; - break; - } - } - - session_ctx->FlushNonces(); - if (!status) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - - // enc_mac_key can be NULL if license renewal is not supported - if (enc_mac_keys == NULL) return OEMCrypto_SUCCESS; - - // V2.1 license protocol: update mac keys after processing license response - const std::vector enc_mac_keys_str = std::vector( - enc_mac_keys, enc_mac_keys + 2*wvcdm::MAC_KEY_SIZE); - const std::vector enc_mac_key_iv_str = std::vector( - enc_mac_key_iv, enc_mac_key_iv + wvcdm::KEY_IV_SIZE); - - if (!session_ctx->UpdateMacKeys(enc_mac_keys_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 || - num_keys == 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, false) || - !RangeCheck(message, message_length, key_array[i].key_control_iv, - wvcdm::KEY_IV_SIZE, true)) { - LOGE("[OEMCrypto_RefreshKeys(): Range Check %d]", i); - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - } - - // Validate message signature - if (!session_ctx->ValidateMessage(message, message_length, - signature, signature_length)) { - LOGE("[OEMCrypto_RefreshKeys(): signature was invalid]"); - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - - // Decrypt and refresh keys in key refresh object - bool status = true; - std::vector key_id; - std::vector key_control; - std::vector key_control_iv; - for (unsigned int i = 0; i < num_keys; i++) { - 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); - key_control.assign(key_array[i].key_control, - key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE); - if (key_array[i].key_control_iv == NULL ) { - key_control_iv.clear(); - } else { - key_control_iv.assign(key_array[i].key_control_iv, - key_array[i].key_control_iv + wvcdm::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(key_array[i].key_control, - key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE); - } - - if (!session_ctx->RefreshKey(key_id, key_control, key_control_iv)) { - LOGE("[OEMCrypto_RefreshKeys(): error in key %i]", i); - status = false; - break; - } - } - - session_ctx->FlushNonces(); - if (!status) 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 key_id_vec = std::vector(key_id, key_id + key_id_length); - if (!session_ctx->SelectContentKey(key_id_vec)) { - 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 block_offset, - const OEMCrypto_DestBufferDesc* out_buffer, - uint8_t subsample_flags) { - if (level1.library) { - return level1.OEMCrypto_DecryptCTR( session, data_addr, data_length, - is_encrypted, iv, block_offset, - out_buffer, subsample_flags); - } - wvoec_mock::BufferType buffer_type = kBufferTypeDirect; - uint8_t* 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 = ((uint8_t*)out_buffer->buffer.secure.handle - + out_buffer->buffer.secure.offset); - 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; - } - -#ifndef NDEBUG - if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_DecryptCTR(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } -#endif - - 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; - } - - if (!crypto_engine->DecryptCTR(session_ctx, iv, (int)block_offset, - data_addr, data_length, is_encrypted, - destination, buffer_type)) { - LOGE("[OEMCrypto_DecryptCTR(): OEMCrypto_ERROR_DECRYPT_FAILED]"); - return OEMCrypto_ERROR_DECRYPT_FAILED; - } - - 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 dev_id_vec = crypto_engine->keybox().device_id(); - if (dev_id_vec.empty()) { - LOGE("[OEMCrypto_GetDeviceId(): Keybox Invalid]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - - size_t dev_id_len = dev_id_vec.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_vec[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(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 RSA key. - uint8_t* pkcs8_rsa_key = new uint8_t[enc_rsa_key_length]; - OEMCryptoResult result = OEMCrypto_SUCCESS; - if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length, - enc_rsa_key_iv, pkcs8_rsa_key)) { - result = OEMCrypto_ERROR_INVALID_RSA_KEY; - } - size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1]; - if( result == OEMCrypto_SUCCESS) { - if (padding > 16) { - LOGE("[RewrapRSAKey(): Encrypted RSA has bad padding: %d]", padding); - result = OEMCrypto_ERROR_INVALID_RSA_KEY; - } - } - size_t rsa_key_length = enc_rsa_key_length - padding; - // verify signature, verify RSA key, and load it. - if( result == OEMCrypto_SUCCESS) { - if (!session_ctx->LoadRSAKey(pkcs8_rsa_key, rsa_key_length, - message, message_length, - signature, signature_length)) { - result = OEMCrypto_ERROR_SIGNATURE_FAILURE; - // return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - } - - // Now we generate a wrapped keybox. - WrappedRSAKey* wrapped = reinterpret_cast(wrapped_rsa_key); - // Pick a random context and IV for generating keys. - if( result == OEMCrypto_SUCCESS) { - if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - } - const std::vector context(wrapped->context, - wrapped->context + sizeof(wrapped->context)); - // Generate mac and encryption keys for encrypting the signature. - if( result == OEMCrypto_SUCCESS) { - if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(), - context, context)) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - } - - // Encrypt rsa key with keybox. - if( result == OEMCrypto_SUCCESS) { - if (!session_ctx->EncryptRSAKey(pkcs8_rsa_key, enc_rsa_key_length, - wrapped->iv, wrapped->enc_rsa_key)) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - } - delete[] pkcs8_rsa_key; - - // 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. - if( result == OEMCrypto_SUCCESS) { - size_t sig_length = sizeof(wrapped->signature); - if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0], - SHA256_DIGEST_LENGTH, wrapped->context, - buffer_size - sizeof(wrapped->signature), wrapped->signature, - &sig_length)) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - } - return result; -} - -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); - } - if (wrapped_rsa_key == NULL) { - LOGE("[OEMCrypto_LoadDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - const WrappedRSAKey* wrapped - = reinterpret_cast(wrapped_rsa_key); - - if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_LoadDeviceRSAKey(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (!session_ctx || !session_ctx->isValid()) { - LOGE("[OEMCrypto_LoadDeviceRSAKey(): ERROR_NO_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - const std::vector context(wrapped->context, - wrapped->context + sizeof(wrapped->context)); - // Generate mac and encryption keys for encrypting the signature. - if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(), - context, context)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - // Decrypt RSA key. - uint8_t* pkcs8_rsa_key = new uint8_t[wrapped_rsa_key_length - - sizeof(wrapped->signature)]; - size_t enc_rsa_key_length = wrapped_rsa_key_length - sizeof(WrappedRSAKey); - OEMCryptoResult result = OEMCrypto_SUCCESS; - if (!session_ctx->DecryptRSAKey(wrapped->enc_rsa_key, enc_rsa_key_length, - wrapped->iv, pkcs8_rsa_key)) { - result = OEMCrypto_ERROR_INVALID_RSA_KEY; - } - size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1]; - if( result == OEMCrypto_SUCCESS) { - if (padding > 16) { - LOGE("[LoadDeviceRSAKey(): Encrypted RSA has bad padding: %d]", padding); - result = OEMCrypto_ERROR_INVALID_RSA_KEY; - } - } - size_t rsa_key_length = enc_rsa_key_length - padding; - // verify signature. - if( result == OEMCrypto_SUCCESS) { - if (!session_ctx->LoadRSAKey(pkcs8_rsa_key, rsa_key_length, - wrapped->context, - wrapped_rsa_key_length - sizeof(wrapped->signature), - wrapped->signature, - sizeof(wrapped->signature))) { - result = OEMCrypto_ERROR_SIGNATURE_FAILURE; - // return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - } - delete[] pkcs8_rsa_key; - return result; -} - -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 ssn_key_vec(enc_session_key, - enc_session_key + enc_session_key_length); - const std::vector mac_ctx_vec(mac_key_context, - mac_key_context + mac_key_context_length); - const std::vector enc_ctx_vec(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_vec, mac_ctx_vec, enc_ctx_vec)) { - 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); - } - if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_Generic_Enrypt(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (!session_ctx || !session_ctx->isValid()) { - LOGE("[OEMCrypto_Generic_Enrypt(): ERROR_NO_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (in_buffer == NULL || buffer_length == 0 || - iv == NULL || out_buffer == NULL) { - LOGE("[OEMCrypto_Generic_Enrypt(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!session_ctx->Generic_Encrypt(in_buffer, buffer_length, iv, algorithm, - out_buffer)) { - LOGE("[OEMCrypto_Generic_Enrypt(): OEMCrypto_ERROR_UNKNOWN_FAILURE]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -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); - } - if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_Generic_Decrypt(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (!session_ctx || !session_ctx->isValid()) { - LOGE("[OEMCrypto_Generic_Decrypt(): ERROR_NO_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (!session_ctx->Generic_Decrypt(in_buffer, buffer_length, iv, algorithm, - out_buffer)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (in_buffer == NULL || buffer_length == 0 || - iv == NULL || out_buffer == NULL) { - LOGE("[OEMCrypto_Generic_Decrypt(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - return OEMCrypto_SUCCESS; -} - -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); - } - if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_Generic_Sign(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (!session_ctx || !session_ctx->isValid()) { - LOGE("[OEMCrypto_Generic_Sign(): ERROR_NO_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 == NULL || buffer_length == 0 || signature == NULL) { - LOGE("[OEMCrypto_Generic_Sign(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!session_ctx->Generic_Sign(in_buffer, buffer_length, algorithm, - signature, signature_length)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -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); - } - if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_Generic_Verify(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (!session_ctx || !session_ctx->isValid()) { - LOGE("[OEMCrypto_Generic_Verify(): ERROR_NO_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (signature_length != SHA256_DIGEST_LENGTH) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (in_buffer == NULL || buffer_length == 0 || signature == NULL) { - LOGE("[OEMCrypto_Generic_Verify(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!session_ctx->Generic_Verify(in_buffer, buffer_length, algorithm, - signature, signature_length)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -}; // namespace wvoec_mock diff --git a/libwvdrmengine/level3/mips/libwvlevel3.a b/libwvdrmengine/level3/mips/libwvlevel3.a new file mode 100644 index 0000000000000000000000000000000000000000..77330e067db88fdd35d9d4234e3df876e312e635 GIT binary patch literal 311294 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 J-9Ve~{{!sTNXh^J literal 0 HcmV?d00001 diff --git a/libwvdrmengine/level3/x86/Android.mk b/libwvdrmengine/level3/x86/Android.mk new file mode 100644 index 00000000..0f2a7792 --- /dev/null +++ b/libwvdrmengine/level3/x86/Android.mk @@ -0,0 +1,12 @@ +ifeq ($(TARGET_ARCH),x86) +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := libwvlevel3 +LOCAL_MODULE_CLASS := STATIC_LIBRARIES +LOCAL_MODULE_SUFFIX := .a +LOCAL_SRC_FILES := $(LOCAL_MODULE)$(LOCAL_MODULE_SUFFIX) +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_OWNER := widevine +include $(BUILD_PREBUILT) +endif # if x86. diff --git a/libwvdrmengine/level3/x86/entry_points.cpp b/libwvdrmengine/level3/x86/entry_points.cpp deleted file mode 100644 index 6f04a87c..00000000 --- a/libwvdrmengine/level3/x86/entry_points.cpp +++ /dev/null @@ -1,1308 +0,0 @@ -/******************************************************************************* - * - * Copyright 2013 Google Inc. All Rights Reserved. - * - * Wrapper for Level 1 OEMCrypto or Level 3 Fallback APIs - * - ******************************************************************************/ - -#include "OEMCryptoCENC.h" - -#include -#include -#include -#include -#include - -#include "log.h" -#include "oemcrypto_engine_mock.h" -#include "openssl/cmac.h" -#include "openssl/evp.h" -#include "openssl/hmac.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, - uint8_t subsample_flags); -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(&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 mac_ctx_str(mac_key_context, - mac_key_context + mac_key_context_length); - const std::vector 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->keybox().device_key().value(), - 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_keys, - 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_keys, - 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_keys, - 2*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, - key_array[i].key_data_length, 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, false) || - !RangeCheck(message, message_length, key_array[i].key_control_iv, - wvcdm::KEY_IV_SIZE, false)) { - 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. - bool status = true; - std::vector key_id; - std::vector enc_key_data; - std::vector key_data_iv; - std::vector key_control; - std::vector 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 + key_array[i].key_data_length); - 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) { - status = false; - break; - } - 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)) { - status = false; - break; - } - } - - session_ctx->FlushNonces(); - if (!status) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - - // enc_mac_key can be NULL if license renewal is not supported - if (enc_mac_keys == NULL) return OEMCrypto_SUCCESS; - - // V2.1 license protocol: update mac keys after processing license response - const std::vector enc_mac_keys_str = std::vector( - enc_mac_keys, enc_mac_keys + 2*wvcdm::MAC_KEY_SIZE); - const std::vector enc_mac_key_iv_str = std::vector( - enc_mac_key_iv, enc_mac_key_iv + wvcdm::KEY_IV_SIZE); - - if (!session_ctx->UpdateMacKeys(enc_mac_keys_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 || - num_keys == 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, false) || - !RangeCheck(message, message_length, key_array[i].key_control_iv, - wvcdm::KEY_IV_SIZE, true)) { - LOGE("[OEMCrypto_RefreshKeys(): Range Check %d]", i); - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - } - - // Validate message signature - if (!session_ctx->ValidateMessage(message, message_length, - signature, signature_length)) { - LOGE("[OEMCrypto_RefreshKeys(): signature was invalid]"); - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - - // Decrypt and refresh keys in key refresh object - bool status = true; - std::vector key_id; - std::vector key_control; - std::vector key_control_iv; - for (unsigned int i = 0; i < num_keys; i++) { - 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); - key_control.assign(key_array[i].key_control, - key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE); - if (key_array[i].key_control_iv == NULL ) { - key_control_iv.clear(); - } else { - key_control_iv.assign(key_array[i].key_control_iv, - key_array[i].key_control_iv + wvcdm::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(key_array[i].key_control, - key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE); - } - - if (!session_ctx->RefreshKey(key_id, key_control, key_control_iv)) { - LOGE("[OEMCrypto_RefreshKeys(): error in key %i]", i); - status = false; - break; - } - } - - session_ctx->FlushNonces(); - if (!status) 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 key_id_vec = std::vector(key_id, key_id + key_id_length); - if (!session_ctx->SelectContentKey(key_id_vec)) { - 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 block_offset, - const OEMCrypto_DestBufferDesc* out_buffer, - uint8_t subsample_flags) { - if (level1.library) { - return level1.OEMCrypto_DecryptCTR( session, data_addr, data_length, - is_encrypted, iv, block_offset, - out_buffer, subsample_flags); - } - wvoec_mock::BufferType buffer_type = kBufferTypeDirect; - uint8_t* 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 = ((uint8_t*)out_buffer->buffer.secure.handle - + out_buffer->buffer.secure.offset); - 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; - } - -#ifndef NDEBUG - if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_DecryptCTR(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } -#endif - - 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; - } - - if (!crypto_engine->DecryptCTR(session_ctx, iv, (int)block_offset, - data_addr, data_length, is_encrypted, - destination, buffer_type)) { - LOGE("[OEMCrypto_DecryptCTR(): OEMCrypto_ERROR_DECRYPT_FAILED]"); - return OEMCrypto_ERROR_DECRYPT_FAILED; - } - - 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 dev_id_vec = crypto_engine->keybox().device_id(); - if (dev_id_vec.empty()) { - LOGE("[OEMCrypto_GetDeviceId(): Keybox Invalid]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - - size_t dev_id_len = dev_id_vec.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_vec[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(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 RSA key. - uint8_t* pkcs8_rsa_key = new uint8_t[enc_rsa_key_length]; - OEMCryptoResult result = OEMCrypto_SUCCESS; - if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length, - enc_rsa_key_iv, pkcs8_rsa_key)) { - result = OEMCrypto_ERROR_INVALID_RSA_KEY; - } - size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1]; - if( result == OEMCrypto_SUCCESS) { - if (padding > 16) { - LOGE("[RewrapRSAKey(): Encrypted RSA has bad padding: %d]", padding); - result = OEMCrypto_ERROR_INVALID_RSA_KEY; - } - } - size_t rsa_key_length = enc_rsa_key_length - padding; - // verify signature, verify RSA key, and load it. - if( result == OEMCrypto_SUCCESS) { - if (!session_ctx->LoadRSAKey(pkcs8_rsa_key, rsa_key_length, - message, message_length, - signature, signature_length)) { - result = OEMCrypto_ERROR_SIGNATURE_FAILURE; - // return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - } - - // Now we generate a wrapped keybox. - WrappedRSAKey* wrapped = reinterpret_cast(wrapped_rsa_key); - // Pick a random context and IV for generating keys. - if( result == OEMCrypto_SUCCESS) { - if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - } - const std::vector context(wrapped->context, - wrapped->context + sizeof(wrapped->context)); - // Generate mac and encryption keys for encrypting the signature. - if( result == OEMCrypto_SUCCESS) { - if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(), - context, context)) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - } - - // Encrypt rsa key with keybox. - if( result == OEMCrypto_SUCCESS) { - if (!session_ctx->EncryptRSAKey(pkcs8_rsa_key, enc_rsa_key_length, - wrapped->iv, wrapped->enc_rsa_key)) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - } - delete[] pkcs8_rsa_key; - - // 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. - if( result == OEMCrypto_SUCCESS) { - size_t sig_length = sizeof(wrapped->signature); - if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0], - SHA256_DIGEST_LENGTH, wrapped->context, - buffer_size - sizeof(wrapped->signature), wrapped->signature, - &sig_length)) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - } - return result; -} - -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); - } - if (wrapped_rsa_key == NULL) { - LOGE("[OEMCrypto_LoadDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - const WrappedRSAKey* wrapped - = reinterpret_cast(wrapped_rsa_key); - - if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_LoadDeviceRSAKey(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (!session_ctx || !session_ctx->isValid()) { - LOGE("[OEMCrypto_LoadDeviceRSAKey(): ERROR_NO_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - const std::vector context(wrapped->context, - wrapped->context + sizeof(wrapped->context)); - // Generate mac and encryption keys for encrypting the signature. - if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(), - context, context)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - // Decrypt RSA key. - uint8_t* pkcs8_rsa_key = new uint8_t[wrapped_rsa_key_length - - sizeof(wrapped->signature)]; - size_t enc_rsa_key_length = wrapped_rsa_key_length - sizeof(WrappedRSAKey); - OEMCryptoResult result = OEMCrypto_SUCCESS; - if (!session_ctx->DecryptRSAKey(wrapped->enc_rsa_key, enc_rsa_key_length, - wrapped->iv, pkcs8_rsa_key)) { - result = OEMCrypto_ERROR_INVALID_RSA_KEY; - } - size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1]; - if( result == OEMCrypto_SUCCESS) { - if (padding > 16) { - LOGE("[LoadDeviceRSAKey(): Encrypted RSA has bad padding: %d]", padding); - result = OEMCrypto_ERROR_INVALID_RSA_KEY; - } - } - size_t rsa_key_length = enc_rsa_key_length - padding; - // verify signature. - if( result == OEMCrypto_SUCCESS) { - if (!session_ctx->LoadRSAKey(pkcs8_rsa_key, rsa_key_length, - wrapped->context, - wrapped_rsa_key_length - sizeof(wrapped->signature), - wrapped->signature, - sizeof(wrapped->signature))) { - result = OEMCrypto_ERROR_SIGNATURE_FAILURE; - // return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - } - delete[] pkcs8_rsa_key; - return result; -} - -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 ssn_key_vec(enc_session_key, - enc_session_key + enc_session_key_length); - const std::vector mac_ctx_vec(mac_key_context, - mac_key_context + mac_key_context_length); - const std::vector enc_ctx_vec(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_vec, mac_ctx_vec, enc_ctx_vec)) { - 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); - } - if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_Generic_Enrypt(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (!session_ctx || !session_ctx->isValid()) { - LOGE("[OEMCrypto_Generic_Enrypt(): ERROR_NO_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (in_buffer == NULL || buffer_length == 0 || - iv == NULL || out_buffer == NULL) { - LOGE("[OEMCrypto_Generic_Enrypt(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!session_ctx->Generic_Encrypt(in_buffer, buffer_length, iv, algorithm, - out_buffer)) { - LOGE("[OEMCrypto_Generic_Enrypt(): OEMCrypto_ERROR_UNKNOWN_FAILURE]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -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); - } - if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_Generic_Decrypt(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (!session_ctx || !session_ctx->isValid()) { - LOGE("[OEMCrypto_Generic_Decrypt(): ERROR_NO_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (!session_ctx->Generic_Decrypt(in_buffer, buffer_length, iv, algorithm, - out_buffer)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (in_buffer == NULL || buffer_length == 0 || - iv == NULL || out_buffer == NULL) { - LOGE("[OEMCrypto_Generic_Decrypt(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - return OEMCrypto_SUCCESS; -} - -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); - } - if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_Generic_Sign(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (!session_ctx || !session_ctx->isValid()) { - LOGE("[OEMCrypto_Generic_Sign(): ERROR_NO_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 == NULL || buffer_length == 0 || signature == NULL) { - LOGE("[OEMCrypto_Generic_Sign(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!session_ctx->Generic_Sign(in_buffer, buffer_length, algorithm, - signature, signature_length)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -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); - } - if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_Generic_Verify(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (!session_ctx || !session_ctx->isValid()) { - LOGE("[OEMCrypto_Generic_Verify(): ERROR_NO_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (signature_length != SHA256_DIGEST_LENGTH) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (in_buffer == NULL || buffer_length == 0 || signature == NULL) { - LOGE("[OEMCrypto_Generic_Verify(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!session_ctx->Generic_Verify(in_buffer, buffer_length, algorithm, - signature, signature_length)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -}; // namespace wvoec_mock diff --git a/libwvdrmengine/level3/x86/libwvlevel3.a b/libwvdrmengine/level3/x86/libwvlevel3.a new file mode 100644 index 0000000000000000000000000000000000000000..3ef2a30a4698adf21348a40a8de95b9cb02cd44f GIT binary patch literal 303754 zcmeFa3w&I~bw7T!yEZFZXoV5rBuZJ#669cPtt3lYY!b=R$`)SRizM3^OxAj=Y}v9T zRx8V<4j3fazF9=vge0V;ElFrY8uDwJQVI!a`~Vwh07D+ognvsLntBmQ386q}0>AHf z9=o$wE87r~et!M@$6n1nXU?2CbLPzB&g)*Vv?I~A#oyN!zIVT0eZ;c< z7yewA{H66<{jUCmc@wF8#Y@tL4JaJzM<}3Cqpj15b#br?A-) zzi#;5&9T0&u8N=)i|wqdS-3f#j16|hl3RxRw=L}4X^Fr}>4k(BtdL%{^ki7DN47(skR%n7q(X*ONG=sJLPed7pgfsgrA)6%m6BuBi;D^$>lN>&dhdUpgXV{OSqZ~x|4XU9;yrAtH!2Sc${ zvF>vymZOMT|Jlc`ml0%KeszVivr{HS3x}3P+V$emm7;+(UsIHUAck2XJ#&>lN zFdxip&Ek%p=`zc*keMZw86hjbh%Yibjk0tiNUO6e)E!2#4Q;hHC*tw`*kDJu!PQU_ zxf)6$i1?LNp=uRBD?ISEb(K}f_15TCgB$7VLLD%REe>==U8qVbZY78m@4BwKZt##S z417)H;;HyxB?~ORqqi##Wr9~{Jl+%Q>FA1Eu&VADK?|kU)76>Jh=g9Lm!7)HT6hB; zyRN64$U<8%hX1|!VhPhTVpYbgs|}SYUILpf9s`?4A-SQQp{m-9LFEPoJK`f@p~l~B z?Q4^@wl3D%8B4-MTDAhy7atmG*&1e8M{lBK<<_X7g-|VQD!jTa7OaT1#rxu2$>313 zrL8U|k-^xij=}asM{jbdU1HG!h|oGT0r3PHg>aOyGfBq!2fEQBFhE(8p$b`3M8z?& zO5eXn>Dhqw_7BAq$?3&MO{usgNrxEx)QqvlLN7M|K{F)+QdoPIb{<)!H#NWDedbFTP5CMRDyI$ zbrslb4??!Viq?+)&GE)9ar9Jd)6h(8MeAbPVs}NbDpkuBkH+u~Sn6bj2tL`AAzT!)&YTUM2E6;`ph zo89r2t(|R^v8~aSmDOv)s~V*mo8m*sWy3u^@dTc_bWfEVzY>j@h_BmYRT`94iriD( zSuu^skUFoxb)7XeQgM(eFGWRFRb7UHlINwW?5viZ%Cy2Qj(2DIdq^E>#2&W zv#V2eT~k!j9SUWK2!=j`RZVeW!mVu$?5u?CRK_xc1cMYjtAm}g=#c+uNb0J4dPHwa zBdnT6OYxpssqMV^udeBa@i2a6EEvifM?>G{fkba|%l2uKM#|`n-+8=Huv$tpO=8p7 zadk(PR7T!t`7I<^CF|d+jxK0>Xc{BUtCdhkT}MvqlePC?H*}ug9=k)ex$Q@=V)X!; z!}gBOzBoBJxjMq9ur|XNH}?$>snO`~rRT?ZeVu58 z7Y1Q%XpLxe{OS5TrC*%d5UMc~ZXELa&CzL&O_s&luHb*xh5z9)INk9IL~fSjm1T}jhU%|rkpr?R+SXlgp8j9; zXC2)Y9n&-w=+ET;ylqBzM^$IWwqew??dVFgy+SLrrgJOmRBn6h8VH?+263OIY<fXIJ|4-86;}k&NI9ek@A|wDI(Pk#goW0 zUK}vZo|8D!W#Uneqy0=$HFu^2W)~7L=)h3}b z0|TWSd=oX5st1^$l!}jbIEWU)q9^ zfz8oGF9&5DId)w?{p*j6U)xdH8QT)yNmCg*C2?nEhbDGfts&A1u>Oo4(S zxqjmJZ<^K7-<=rf?T&2|(}N2K7R~BmlM)+D4D9F~!mA`v1M%%S@58ycABc32~h@^7budA;&-k*$BOu+=FU@E6zs-|G7i2=jJuGruJ3Z5zX&6T3y;!v=* zW^qLYG8?R@sHvtO0xa~gY1WP5NOM6!0Tzs;E3n*F7P72CzreN;HT-L`y;)0tZ?YFn`1SGf`Iq^7I(qx!-PeM|q-l>Qw)ggnLqp&BBlv{o}-a6P?&nXK8akZQ14!mG* z43yZr19MOO`t7&hzUhbyVX1GCz)l8AQ?=u-B}?q;fC$z8F;C!b5J=on+ap7R2ghHt zYm;ZEz%a$QV2T9Fj`SRu7$rkQqh~h-JR<7-tiqGWiBs`+%G)#JuLnMDjzH&T6VX;I~~23?97Z2osm? zo$?cWJOR61X=G`^`wo)p==0|Zw!bYuJp7r|!MLTX=; zn}jgJ9w{&7p}h6*f9Lja%K8mK{0@5!09P(?)ZcGckD&AKqrLT`X_alJYHvlegGRU< z?dDRnn~`i2R3^*;Et?-<0fd!<$pTe>A&|3vMSxpz(|^2;`U;iiQ*qr*KUJZ!!tD-} zL7pNS2J$Id#K}*dtbGtRk?uuz;izw?qhHk)F=;=O6zQ?WVPi85zmog8r)d1?q}MK$ z0;&kp(z9m){RdJ_fxzhDGITj!Jo?%7I9P~wP5+sO-?aS!G7%U(ScZIL@}pI#v!q!I z-^u^}GN7pm$U2v@Lby!#IQj;9gVE>93{H4_LB}bFA(a~a*Z9*Y#ks?!FqKl6itKtP z?)?xG2JA;i{z57eSTO!*@;Ul6r>~z83MQTqnn?z{rgnk{C(%PVvZh(ciJ8}^!vZDKW#!`uaM=RuQ7UW`~UmBF!lq&9f?#~*h_%X zw0t49BG@y6Y2x->gK;a`*RiVsdyq!r-By%u$wNsEw&HznL<1_0Ued)hWk)Y(G6aLp zj;?J}Lqz=(xu>B53Wrqa7E&gocAWyf{02WwXPJMYT4x14)8tk@;%Tn zy3++CmrmfXNoXG?U5eOsr3J^4lsz+@#8^tbUuHN;!pR@#vZC*(4=0cxe`;B2=yCHVL961O5Yi2kH$@$8+!-61E9n*}rCPu%GkyD0h^!6NRPY$#t2a4uE zbvckf2lD1XFGJXDde7!S2Xi3KIAkdg*RKt=32U10WBXWp>=d!>NYk6biW&ZNztJlu=S1+u!N)>&<^{rOHZg0T{iaehE zs56{9}?XXH0y^*19ubuOy#=; zDKvn1`RuD@Qk>s^gS2p;=N}cPA}fol-WdsGj8_5O(7n@mGzq!~_(!EzZ=||-! z=)4%bH%fI&``M&u7n!uzN($Q79u>aK3?G!?w3$0q_?2dOR&Oygt?w$@B_?gJr0@gx zk_s2&SlH>RQTLU5U8`r&mRBHiEZ-70BU{#^{FA4grYH_%)b|P%?{xLew05gF@6?v= zRq@`5O_U(LmsGqWJkt?pp}x_bD?OouQib~hae3;-3a9aajQNSY%Xnk>wvlA|7q( zRTb}5Jj2eTD@JGR^|bACuNZf^uAcR(#=c+gsyjPFcZ3wcz;TG%->WGze#5MYGh!fJr=K0&ik z90v+I5tU9v$brDgqg)%V*p0@h{D9rFOw-o&Rz>(jX z_-TH-@NDusjsP)E2A)py8^*KAZ==D_hcM0W6L>cHvCq2+IPEmQy+D}!b{qMn{c3)H zf@hN-`z$fWQ4BS|&pG(rYw$bU;78jw`9)FC`S{)K;P;Zj?;L~Qw;lXm2EPY@(@x7r zoSEN1Q?`81LzvF*6L>b|`#LrVd_^;ZulYTOXOrJXgWvlQruqE~o=tw6V3am++G&12 z2Eycbo57E5h35A%o=tu)gWqw@48G>~5}r+d-!=Gs5Mi1hw@{h<4kD5mA1R)i-)|iJ zJYmc711IV+e9do;gI@{O-^BX@Xy`P*V$hlL1q^-{fKKzf(7~@B{8;z3)BMhN@M|*o zT?k^$uiC-y0Qiab5yepRUB7F5N!ni+h}?_Ncx`?rmt`>8>PU{TMGIr*XS*6(X1*Zhuv&a}VVAfL9E#h}yj zac+RTXEHL}AozVjK8nAZ-}fE-?lJOP3rfu|?cnDJgM9q{-NEk#gI~zt_ojp2@oD(I z=HOShJX^l3Pg=g&uH5|YL1&duzB52)>aX44ce%l@O!I?JS1||gl=4yh)%u(3;CBo7 z)q{fd_oMh}`9e;9==}1vr;8o@z6*YS#jnBO_lKGvaCCdX&ktQ`r{x=Q@Oz2!fsXQ_ z>&(daZ3n+QOOa>bwA1_^aPV8uBIlvV4^=tC@83ZOQ_qb5j>DL#3+?ptzdHDNR%XY$ z5H-W^zd*3soW`--&7DI~R1Oy_6dK@R;HE zAwvV5=DOeZB}%|(Uo%0VmO`dA1XQ} zo}l}_p+H?8BcL<$TZT-QfCk4FA^^o48j zybV9{W4@TC5#2h7M*LTXAetY@rgd)XjGQocPEN>wwj&&!fZ^Q2BC-f~&Kn!!bHti; zZi^$%taDqr%6D5F@nxM`yxo~FM_gIww$9H2cye18IN%E%@I?;zVh23m0bk;PQ5c4E z=ZwghK6|{Zb6Zte08egy-IR`in2YqbFm zWFmR3s{l6{@U?(<8*nG!`wf`w+p7lL2e=$Mlg?{h2Y90a?*M$jfZ6UnWWaj>XB#B1 zwU=_Ju2(u^PxL9kI}P}Dz+X4uKLdQifbRl~|H@Tce+7W;n{?II*8y`)M8o$1 zF4rJt*dGL(twq(=VZd2^Ra=h$zSf|B0`Q0de;@FE1O5@8rB0%eZLKjN(nlTemDYTfzj1`j zL4QYpX&$1Re!do10T*03g^k-Xrj__M^!q2fj;|TwI1wSC-pJ)Ap zBm6A|)5hnZ|D9nJIrZDDU|WQLz*^-9-=<*N^c?GhR>Bef4Fz-TJ_r5v1CH=#6ud}; zUts;SBm7qiUM9jXw9Fw3<(sR9FdS>mu`aUCH-;3JOk76tc<@cCBM z5x!o*kBab1tdBXuZ&k3=&!yI99N~YfU|D{PtZzEPpHr~Zf6)4gBfQXygyA?go`dm3 ziGnc<2E5ohPr;;_<6321s^Bk(@LH?d2&X>!a>7H_kR$x7IpIsJZ#cr!IpLREoHx^s z{4Xw)5c{Bc7@u6GU}72G;DEav@IFWUKUOg9XC6))KJB2#`PO&0u97+S8>yhwt~PoFesk_K}GSkv4b zX;~dM2`Ym*61KO78&&5wW`FpJXmN zV{8aw@>e8|tHnr&yG`>DI_?f5Auc%0L->xabs?LYylmdt9V_G`Zdje71LN`+65$%x zJTkwdTi?Kjm&uxJR8bh0c9O`UA4R0Esw9OFIsc8F3>F1$1REE9GPuTSZCKqD>)e%$ za6X!$6&D8wakpqpJn?FtR?*af|9f>2@s#AM za_%e+M|W)Hc#^Y`u0Bi5GS0#a+WP>zF_7o1ooB!jvu~b3wXSfTC1zth3Cm*S!pkh{ zdeRM@KA%>`!;3_xipRHWrq3ZT)5nsBNS|-To*i=9Bwsl9sCagsA{@d+N%w~`y+TBS z=tAD<(iMCWZwu)@F7sE2DZ@{^lXy3(c(~{MbmQ$Of4tECG5kU-;{4TVrUw;Ro>7@j zVZDsc@;Fugu424#RgMj(F2{|ehhFZYzfaEJ6fU!@!-P+gUK7LZ>E*eI;i>7v>li*U zefV;Qe{yR0eB%E|+7s<(E@0YM5AmO#O0Vrsm;ddg`;07y!bb5afRpA^#}j(}oYE`e zL1m{EPuLq?a7kYXrJb(b>?Hp`QRNRirTwrx3gEl2DT}Yd%=ek_3&W?*H>$ejxzn<4 zCVjJIeTwi&%2(%G#QUO(heCNr@nBRUy%p~;-e0PCE!lX?r`euywZLd5jNLiEy9< ze6NDPso=v3eni2?75qa5bN-b4Ur_K%3VubwZz`CE$Mm>fL3**b2G8dz*bO>YA86py zF3)CsOmVUuV7yD=d%h~?qYERL>ri+UvB0+xUM1(FNgr2ubX8U%COCG{2mU67N7G^z zuCXjsWr6=wh5s_)sAc_)!atz!M+jeOS&u9H4;21i2&0hF3jYg*|8K$&Y6j9|x@Y1? z`OhQVZdn&7{CtJ4BD~hJE?4-l!mlB`&ayTre22nwt*3CkWeqF*#}$4bVHnFFDg5UZ z{!4^6;9DIE|91-i9l}>*zm38_rSLx{e2ry^JrsEUnZmzLJlcx_7(DY;2%q^noA5@< z`k=yJr0`IKRe(+#q?YS^LU@MJ`{BDlvw}VfA63Y5d9Vka{tU~ay}4#u*01TKvErU6 zmltzv^kF1-(Vt~m&(WWa`7iKt6=A)M{+X85O~2T(#_0P%Prn4~1N6_rIvIUb(o&@D zg0V&DmtuX6{yA9pp?@yu=%0r?LN?c2^cVEshw%e_RPO!sKY(=!`eiuhL;r(VXF?ua ze*ilA$aj)H^l&GA-Iv zu=?Z4gAL%J9k~*u&l8u+`N26%M~jlt5&axUfJ5#zINUEt2SI+5v;7LUR+aK z2b<7t?fTr4ns)`-d7}1j8J@Z=a1h=^U*K|_i7k^wGqF4Hv56f8DVI1Aj1$0P0oE&V zIF_hvDY%Z|Ag3Q;_5yi!)_311AnWyGs2|q;rogrLe*_P{@p05M`%v)dLuuFDu3!E| za<=d9&+W0#`zFcmE=Zo?yU%m(e$ROmVGGAcH>!&{CLX*P!Itm765oB^iPBH?9D30^ z|Ec5Yg2xWNIKzJG(7(={{}ck}Kjym+|J#eM-Cr_MUl4kE_;Eul@CzJm3T)(!UDf#2 z$uqt<{9->j|3B?Fc;5LOoOkx^Lo-CHtefS_v9AH{86xKrhQXfKeU$5z*}Fm~wW$yM??}}FPzhUaLjx{R^i=&O%p;~X-r7O4_z&= zZ!EEIEIoRLHTgcC+dhiUD774A2-88T`%6ZbmlROEiHNw_%7ZvwU7bhYc-uEt32OmC zU2332SmpZC(3`%o2O&-BjQJ;U^~>;A=l@{zH*fjI?gwuCXTI>m1t(CDA~L()(8Ioc zUt!Qe6ht{5SReuVzVU})bE)N};649gM7{MsU?+-r{R#`ZwC4bgt-fGMQ=oMJtcliw z;s12^!GyvhR_IvLkMb)^ou^CBw{Iib_?!|%k~Sni0|g$imzSph8#?Cs@;4y+!IJb+ zb)KE~%-BV;I3eCrP`!OW|L8JC!3D^}jX*q?Lu3dpr2ga;pu@TQK)Q?Emv)v-$0p1>qQY9wH8tLvh*fs?-aaz@*Ht4|7f!y8huz7Q3OTA%f}+H zVO-*)>$uSJGb%xZhn`H0l=#Ltq(Sk#%;LFs{u85bp?IDGZu~W0_-Mh)x_F)jDsn=Wxp^r-61Nky2Ntk=Sk3pJizX`c#PBar za0`ykWE>PuISMC`^36YV)35d*qHo`mYPuG)XIRNXtndA`e`NFxl*KG) zV*KDY@z?T&j~5&sJzOyQ=G(q;7Kj%Ao5K85du2b2oGvX$Lw#ivs|r{sBPH{XqC9Us z2V5qKD(n{#7Rc0>fT}MO$;H;h>Vl&)7fF-K7K~AAzKvv|B~dV$_Lc1x3uO&zk3CSD zZbcRjKmj6C=`Z2HxV)z!qh4K%RB@&#s}L)6+_&#TQ0e&7!&MJ3&)UL*KTB6q)uNxu zux1st-$ac$T#`PDWaLE=NM@;T-%GR%Q@IbPe?oGzV}Ri4Wn?>Sr9JSGV8*R|z>nuC zo$zhoq54~NdG_n6djfkPXv$@e1-K0;c<`5BMNix$I+>+X1u)HDE6LIELRDAk9E>0I zjd9S8k}pD5y?c-(d=ImZwiW1dZTsZ}Y~3lrm}Ol_-YED*aM>B+tLrGUiHX>_MH08^ zh2BhFf;+h`hVq-{Kc#CLUpYigD-EFIm#O*gW3wek8n=jCrOpjK2G%k8I z(f+7rNfZpT0Lit50IVPgUyMTGWAH2OR{8bxQD6&%pisxH%sa$g0AkNZ25P&Os#}1z zP2CUYMZBzfCdLBKNnX^12hlOG7ipnG7rxMLj#iOP&`CVv=%&&>d_RQ1Woy2%BeWuE zbZkq>Sl;-l6r27c2!tLWXRZR%td>0oWcg(-;Q)&wQDU;Rn9h{aO0S}kK?gE~A~Fle zF6*7v)F*!ks$)VnjvtSW;w8l5DDv1S$?>_e&YokVMR@G8(tib75fPwtC`g*TeMjIW zAnbbsFT)cg>H>%^+`S9Ik(ug ziJfk}L^FygzOm1cp}4_rN(Gf7sv$JXH1tMhnAoHT8Y9aojxM&;Z9*%lnW4kJ@#A2f zlIl-M^{1q^p-k!)CG=}}>V6*0V)9$EzmrOs&aMzo>mE9kv_eAP_|+)&^blJ;*>C37 zTo$ciV_V;WjeR7?#?<>@3C7aqm44_o1F)aD(lDew9m6X>Y)tM%JJu|W{a7}i;dDCB=9estBCPsz(;P4Oo8zq-HzcfRDXXrA4KD9__Z_e@5HW~U5$ z+=Ioxb~P36al4+(BTDmZHh+3Q@HOPKym*gmH7|SEw9kDdE_?WP@vjRI-{tyZ=GF%e zp7ow#j+E7XHhbM|`&_Oax%b|Tu}Oowi+{8pKQ68lSw7p$ENx3N(3QTvwLx!LDZbd$RdB0nlj}YmrFPKgjD!*kqO{o5= z=`_LW`=%mPTvowLDlkK2eyBA!ke_|+`~4o~$JAra$q@FqY<1@0$H^B|G4XTKvCe3^ ziwru(qxpz-7(VNU>Bx_+96!>z3BXN9$8`>-qvVWT4t|>73@|hK-3j4E`w1F4&94AN zCckIFZwtc7uM|JcFW}&}hie81*G}{EJNVV3@>~TX@;etl&2O3F=XOaB0rJ1G-HjMZ>VW6`e}fBHe>zpq$RfUBH>;_6YK^0yNCW z`S@wQU@0flw&2n7!$`hi@Y9dC14sz;v^P zp0k))qA$5TgP3J4z%!QFl$#|^=lL~g&9Z9n++e^<@Qh_f z9N62W4usF}-#FkRZEz}_>)6_np6#c0gfSJJafDYn;J5?6#R2mirFM*ep9w?e#}%yQ z=Q=PQ`@A`*FaK@Q1JAW)I`(06ki&BoOdR?1jJd z1Lpd)cI5vx1+$NwgMWt{;g2Yoecl|@@BdH1cM14hi)YWZBfmn`hOwPHi#dZhK z!)Q6y4KLoo&*O13cy_D0+$~O=*a0rKjc0eM%MI#c7rET9uD7boEvT9IhCKIPb>c&3 z)9ejzU#DIz)K1o##T`BRQ+4{KBl}Im%sWWzYPCaLznO?v3~@79*S1*KmTj@k!ySok zgQ*}eck1#!b!^fkG00A}eN*q~6{@6=5U#Q+R4qPJCwFc-cX#I5Zh3l}K*g?iUUH_g z!ViAMgnnm7>bkZ zG`G~_gKmTPaQv>==6KR-ThZXyT|CgS>w11^FDkwy~x z5F2G3qRMx=9`QB7+#vlzm(>Tdre5PDPNmh^6%yaH9NKE}&8`h!Cy&eJebyOP9T&zM z95>DS5bGEE5WGxX2;WmK`#pxAt-{%NGW^3ToMV5_CGt)P(y{j-ACBh=(P^@ccH>VA z>F|QoMi}w85ME?i1Mo>#f;P-kVOf{KFT@alZK@}TJ*)JQ2^L`grkUn@PT6 z4-eA+Iq{1vi*1(&9Ww7xb>T$|O{B=5mg^j*hw(1QRZIsWTZL#edf|I6v#bS*|0eoK zpL>qTkLSlp|4;NW5aWHWq<@?~=k^kv^2V zl0Niy9ewEOUi!$_A^OPIKhj6OUVvYS@wM19hWyW>yvWxdz-Rgk2!p0Z`Sr?Qsr>cu znXfY`56TxsB=U6ueC7jHMZ~`rKKWfoANje7euLU8jr9JH3cnvd(>tvE?<)Tp<)11Y zR56iGE9t?vN5O+C{`JZqQ~oEF?}cA5U%porpm8W6e1&}PEWm)6?Lk2^{?Lbw`{8q( zQcoXsV-x)u@;#J$;a(tohOCd=1IPNvJ#hQ!&zAL{d*BuY>-?rW)n2lix|#|}f9kzt zyVXk~iXW~V|1PqSyr_Hh&&Q9xAHT01{BhSOKK0>ed`I@2J9N>|-Ls2}eZE;m#o9l! zc-EPG);^-BWhXJ(N!>&QJ`{ju3$fAc2*7u`7tOi%MedzaJJ{|C90W_OxI9G9HL=!X zKl3_ozY^<^ShuSo0L2QP4?Xc^YUrl;@_>n$r#~J;% zf}|T8XSia-`F}s+rkYFTvXN)v<4eU_#L@7D*0C^E=t_+R9)XWdPLZBNk9ZF~QbNxT z*G+`Q0vK&Z&;EmziJ*xP>aieeSZER4GMgF4Lg!P|*1!u|srs?f>9Tvk* zVCBo7;s(gKqeWu}hq-mB95B{3@gx)_!n}&6MAIVf+>fyqWF1i7hZgzyv$jtCEXQgYzXMXfWBs@55&1hS@CW48z;i7%v%o~$=+ULzpvkX>7)wtG zS!&l|wTc^g{3-Cm?j`lLHtbQE*z$&bZ1SFM*ddt}4o{Tte$)*MVmUtyH@Z7ecOxVy zA2|zrbH4xwMN}Z6>e0iVukU&7aDn}dZ~P$G=qkvXX&+L%5r=o(T`(M{3LZc+YKFly7G^i^0W#oi@P@qUkQ@>6PyqwnvF?=I-EeY}gz@{R2T&E$`<#|3z?P0y#c z=|#E93O)Jmn~7Z)750;(M+-)e&Dh`Ix&KDQOa~ASpZa=8WCHqHfHIJ~9o0H~A3h{V zL4OXVp_p=Wd3gR|mCL8Gx8po$lpjH>KuJ}jr0T$U=@ERZG|XBgs)CKRNbKkn`L_>2 z;blFC9`zo26xn{%E7Y)LVh=>}H65P(8_Gr}>85;3b|!1W=o{yc{K2uAe$eaO zI=>OC8)EWAV<_{8U7x9_$38C=_1fz_sc4bC-kXY+*z1c@(NcSTNh&(mUSFDumQB=q z?Dca~^=0<*GMNs(V8>ysuoqz}C~C6|lK8Su6ZRgV^l3%k5iRV)XgJG&0uRQ`U1m2l zUpD%10NYMy+Uxk?pqyQ@1;^}{?HfG#tn08SKr)`jW!9J9viaqu1KVMY2E-i0spJrkwUo=j+)Kyl6F~1SrI(0cbuO!(+>C zZZ`uBr|Ix2oRjVzz`7kGIol^XzNg}~FykJ=3nt$&sTU5x$dBox zD7VS)IWY4BM}EX>e!X}$`5gx=+FJN@nqM5xCcj^U-%jAjk8PIb$I-dTuO14@m*0J$ zGx>2%Pv@8K^qSwD4t|@!uMs%yw0wtwFw^Dzc%toAgqlvw8|ldKZ$Y|#_{;}sbh^*u znfx$SC)`I7fY#fNXxU9_;1bR_ycYukh*Uq%rH96+nRJ+rlI4!8tE!TEUaaNPV0;)hVjSy zs_APtMqv!6!#F?3XC4%AGrt$&r|pGrP^dZ?w*_-lrJ6ag znzflGi66vV?LkDm7|&oW_%UBh)8w}s6Q1Eb{6IFXd++b#H8oE8SOc@}x4(~$#>g4uWRKFe(irZ>ms7xTdyMSlAgz`kh?dYn6TAbf^@!vTNO z0YB`3A9KJ@IpAj%Ox|aq<^MNFIM*4pBMsYQ?RcK~Vg<|mo@v!MU>?|@Ys7C3?u))w z!R)iR#?5sa?Z|((g4wssfxUiO!R#C6pftX$;Ix3xvv@XKJH|h%V7Aq~&+?xY%(iw8 zT2S7juN~<*->)6vAYl6ZQ6EbH`wdvGJ7*W_ZA%`it~^)iA? z7%v#vd#}K02rIw2!P)l@13%@h17TC{C7N;#QmkudM{IC75s&TY#mBm^)3!4n?}_zv zbj7W1tXRhg!klDZh7KLW0BaT+4~_-hs6;eJGz(%3Ogvjq;xB~nxj?OpBAjDUhI6dp zM&KVYJRslaJr~LSi1eFa?;do1SJFqP#rntf;UxUR`IhxJgg>m-!Qh_-0k~dv9(?lM z2H&+{dU@FgQeONQ@~ni4;xVd>z&?=|e6I8?1sqQ0rY_%6eWfPpx-_q?`rt{lK&B z<9i#|yV~iy7yHZgFXt=k2t&oB0?X70_vITUmUM-{p%t6MJONo z5LVQ?ZSh?T2NsFtty8Uo1uN^SPj?+`BhsK_9ysd5ZNwH)v^lze+VkXt*X%gsgO9&* z)(`JFH1tnj+IQjB^M>}W{7K;Ap4(c+zbohJ#5%#mO^m?FvFw*~F+=A3a<0@PNuA%$ zrJhk7!f`E_j<^c(WQ;X`t8)OdNt^adb!e2|>o3*O{?1Z)pr_ySX@@9gF+Sv&6DB5f zuSYCP0h^9Abf}tw4yGntJ^uQ|ll-Hf7XqX$Yr0K%Hl60@d@tVwBCUVYvkd5}@Z%U( zJKlTEI?H^(%roQWCOp%I^n1b%JTsr#F^p~#etg#Ddo!MOT6h#;4DVIX#L<09dYQkP z-^YRBGpeF+x8ZNSd=!6mentCY;Q3usrptVw8fNmrGSj-lqxF6K_VGbEovxWCgZQ1< z=i#FX%ghImKXqsFyAA0!1E-zlr{R3QJBI`L%@BDetslRFDdD;%lY;cQsZ729U293x z(}J>Y>i0ipW!@NQGjkvh+k5TipuyASOPnZQ?Ab#%%%Meiv1r^d!jJ=vcQ8m&Wevk( z4rih8Sbp3e;fK%mnDvb9@S>_(*&M3Br))n%)xk}^f1dKu?Fu})9pPiS_Ff!1#2MD5AWw}2Ho-F&L_Q5do^7oM9w$~gH;xmn z?83(n;*=%l8n6+7Qxhq5(D^cibExbaE@u^C5mc`9sw5{< zSii*jKQl{*N9I;NGOy~9`K3#rfz>sUkc9bHtebJYY|5EWE*H+7X!cCpP-Zt5+07;D znCDR(`aISw6`@bd@4XAG^um-#L9dv!yAuvexF|GOGV}_}Z~Wl!tD&co-cX_hYvjv+6?!sxZfc}dA7F>v z3+$K08U5gElj)p$l_I@e@&2KB`>w&b747TT)zH^BFcR;!qVdE~?@&^Mt?~Z&hz3-g zrs0J6yl!iJdj~#o+rL>b=)~UCsUaeMM_*e!u_K;Xo9MIF#J4vlb`2&6+Tue)_$F^l zx78N!8cy^kcSYhm;(eA}kZ5VL+I9^klPlp9 zMQ7NL&;JdV!);zkle`>v3yoX_wVsWQ17cSM4hjpF6Q$+$x{{+V3wF2^C0P%yO;{LT zfy5)~taj$qdv>eAx>D=_D4YD6sGpbbfv_n51tXVYadrU=F+(W#Bfv@)*y~CQjw301 zW;&_%5lkhV`~mZ=-IRS&?O1DGRvJ2dt{8IZ$;D#C|B7y2pfshNjl>8IxSHTe$OHBZG-|GI>~@L5rU98^X)>-hYJCSGq%KYE zEE<11d8x3&)bb)U84yF7c4~wN=h=a=BUan8#$OwLR>T|h>JVEQ!1!y)nQZDOzYK!8 zsk{V*Aefup0s{ukg6U}%q=S;Ce0rMl^qc7I!6z_1O(4xHJ3!-~p2nZPMbeZ_Pg9m& zD{0#E(jZsuzVY)xg37a0w6suJetU@09!4Mbqy|f&%xfT9bcSg5^{y8njLrm&P&9Q# z>G-3#s%06kZ_1Vr2<_2DkSz+maz#C&3x)SJ6e)j@3Et$ zD9^wV_v%m!+=o>6OhOcw`v}PO0mPQvF`Lmw(59mUP>zJV@W}_bl-#Q|Myc;`FBcs z$B_n7U$P3(|52ppwO1E0y&s`Kdk)yOa<7^_>=ie&q!I}9;;(37R}0Cv3dzr=p0D#P zSq)Cbc;;rUAKF(G*;jfd&YCDr|5ET19njBwW9&WOMUi@!B)q=yOKEE;0DGA?eF2_X zo&qdN&jART>!1^;E?vP|as{)5zfjyv3vDePxmTl%4R} z>pT=Wlxba2`ezioxg>Ok@8$x?m7Xtx zCt1vS+UI*={acW&?v$0<>J6Rnja`K*fm;N-ePbVke)rVD1h8Fi$uf^`>4|=B( zq}vDID-vo7Y=ZcF!OUzhMz#Gl6uk+4MBUIQ#~;xmsUp0`_-?*|dSOv4qp0soe*&T^ zJ!a%h&e5_?3R!Vc+|OnH`HGJVB*$JrER>pW{B^REB{x1Po?)IS3Ew_0c~Km@#32;& zP>OtsX&1;}gnW3}`wC(`>dliEQB-v(Am8`_nqND3yBxg59fXMz+`~84&Gcy+^OtNv zzMlcO;~!IlsO>O1X8PR8Go(GC98jT#Uzdf-PjN2UTH+h!dDijQaHrzfmq4ydBK=3m zrP3?L0mB!SN7hS`b)f?0gawmP zjj?x}MVs~`68Y0M{vNr}5+PE683nTvtxquPPJfxHM2pftR(AuUa@fBbd(_56$4`+7 zVdZ-_kchG6ZsBeoDbSp4vAI86PvVnW_z z33QMs3B5Hk36l^0Z1N>L4Qb2A9`%j?IVeJJ`EKTnhf+bgU6STKg_sUnvb-o+n7$Gv zfqHux`o|^L7bRZ{tuOM0-^9yiAiWfM%ZSTa7j;LU9>jLjTHlZOIc?0J0wLNMw5v3X zj2(#j2m=P2^7N0HJCq3SOB`EB7MHP^TIN|2MKje&7RxYy0L7Ifu$Myu&3-c&+(liu`?!2N(xFW*mUn$K^3B}C{$9;GJH zrsm|4`E$0h%;P*1jxYspvT$-(+E0OM3SLXQq%_eHxb={Rm%c*=v7F-^}aBckGDZnEb>#^^A zE&Vh=&FV2cLmgQ+b^Q7e3lhHd!}CioAiZ+wEs$P?^f+4p%BA#<*4J612kY$S zdb_#lSn~?va7?N>3W>|qxshX@14OGcQooqE(sOLD-v41APqla_&(z!Hg^%{Bcu8-` z$Yv^x9liz{;U!P8=1X3h-9u0L&erJlfMIW}=0-dP;{~u-_i!#Fs`b zwNHq5S0!JnrD!rm36+EX(V)J{9AHT4Pwm3s#5Z;y?O(Jbh3T(JyLZVZ>-EqfbYs4; zJE3fQxhHj{*N%Ea4Z!fqaCFAwufdMIXp#Y949Hpa5pQZ&k-f8sf0uhgt1zhf3li`0 zgw}xa3#43LgxiCGv3Ghf4D$HyJ8M5KriO{`FR&lMNXWx+gEx6jXc)0;5d-7qv-xsS zjDb3GP{cd9Iexvu8~R0Z7smC;1xOF`AccEAiYQIY5i_S?4_NS30-A9#TL=UNw z<*6I8Y4O}^>V~W=ybhKZBVXZ}yqT{Vi6W+ZgV(;kNJi7?-XPQcBg)Qnp{xl!+apDM zDM)w_bMmt?U3-<49$*8%t7xKt#qc(ZLF7OvoM)2pRuNha9=G7xzM%*T4TNU-#x^hr zb)V1Y;28yBzr{jGkD<0IyRp|4rG4N}t|)Xd;owQmK&zRI9zCM~$x@r^sSx~C!EWm2 zN*r;Kh0eP;2!b_6(7rM59Yn$&<{NCO&Rx_c0pERd_MgRvqpku`F>w46Z-7i41kN%d zT9i|0t(6=WRM&gZQ78Msl%Omp*art-kE6XxKg_lZ^X>?oytU^5l!Us5#;b>T4y5F{ zM>}k#JAty7d(&6L#~ZLW{b3?-q3{kibR*t$KmAqK@ZZA7X`6utd~m`xLDt&{UVsyN1295;ArVC!io z_?syXn9Mp+9IQnLX|4cS9DKpQo3JPjsWMm@4g@8N(u-(UsOWETs3lgZs5CWx4W?F$ zaf`}zxm}t57S;1{EBz<%M|Txj6Sc#$CL2{hT$x(Ok?ZS7DFE70(%#@r52!f5q<_6P zJxPDWdmvp%ql2#brUwH?l&BynO0Q=Kl3BwL*e^O9dlrmWnC_z-zr3D)1>G64m3345 zoA0AY>(TZ#*>B7c-3^*p%yr6%k>%cr^>|f5=F04+hG$Qnj{|jL-KHpnCOWfD^H_3b zsJFzo{ISquzOnVJuAD8su9VF+M%j`VP=Lkr_-hat6KbnTx}57kAGV*8>p;`+pC$RT zS6l*NlA(#^B@nY{VtEnmc4D~~9^Yb&6{}2{3 zG2TY}Rs)~D762s9{bEOV;5l^*Y%*}ZP)QPHA+BlG0@wnBm_lU}qa1on7skQHbYYQ` zgms@JZ1+jRZaYcXJtql!=pg@hTkGWabFF69ll+LF9nLGLMQeDT@>1fa*%A35^Ug6Jou9s@br%Y3`w}<(}&JHz)i*96H#0# z;koaTiMl!^_Ic^G2@hrjabHlfi~a2RWskb+3W_7Ji8dtZyy1BTY@AKz0_qO#Cm#H9 z@M$V8qxy1ghHgSU>b_gWyL|ext9ReU>#3b7H_WEp-lgJKsQ7z%zxAklO>u?0%!RwG zkH{m#VvpBxMazAGbbKx4JSJU{^xlj6oTuM{o^y~CyUi4(_{4UlJ|Jowjy1wTJ^g{! zTsrlk<&z`^X6ozNQ*M?v&apZ_yqm+YEm=L7=-q+O>tfFcHjKou`z7Ae)z;C{6%GeO zIp4jFb>b?uZI1j^2gMfrWN%jtn_QCkE?DpNV%tlsqrW@W9mn?n;jSchu*52QdlwFN zB$5mH`E=eBtu>@%sEf6B#;|cE-m(>#KJ0sG*&1e8M{lBK<<=-KtWz4|SC7Nt)orn0 zMXW8}7w<|2hmtLAbuo#=w)l?0_C!Z-a;RNmkslFShYZCN$YMCk*qJ2dw}qMaaIS3G zG+Dahw8j6F>@194>_ti>rx(6;C9>JJod0w4@q5&9uu4i98}9GDZa6NAsaBV5tTze$ z<1RUtM_VHbOo*H-Y_8G)sqf4?Ee53zliA!i(Am+~(iyG<7{_Bre^)%#Gmtn{Nw>CD z#oDU*{}joqkJx7m9ybi)bj9F8eZ(d`yH<9_dY{Mdc)=iHypzCzP&JqaEAG)=et zByrlMD&wOo7yOuB2YzNgxba<# zdx59Z{I12bxo_VSmV55Wk9(#mANk#cpUIEws4IZePV?hFdy`)^_;I3{{CxOneqX_} z$&cSG6=Q1P=`_E;z_ZCOV({Z0e9e!`7AC(EC|r!efv3~_9>cTAuN(aQz)`-l@zeac z9h&?q@uT}3_;IaHJBIPcGd}e7d4@e;@Tw+)uhV@C&t|$~NVgt1rpx`{I^FY~{AQ@} zJ!t4OzYl=U(Kl}Yx(87RVyrL8GIWbTXQq2E(!CQjO!s2^bh=kL`0;?982f{UPN&=M;Md+F&#sZ* zeEc-O&*K5A&9svh7sxQ6gd-i@XB_+%tjzW^mmpm8`wAY+{MLgXOh4nae1GBKS8edS z)Zq6Ypkw<5bqlv*8u|F%W$JIK!EX^_B3QJizr=%(PnBB){4(!8pkWxD4?^>~LO?jD z2s$l0Q4Hg6uA(E3ZVTv4M;f{XicTdf=y*r1c9f5<9CT(rnvjnJz_Z*qR?zui8*D_k zHeQ4~PZ3u;oi2TyCc}24BRg;g?v2Is8vMwQ`C^(TzoI3m3x*(?AIPS4`OYDk#BR}3 zW-)Hj)0r?!I_umyC-f*Edy1@^`mF)Bz**-;3##Sz3qn5 zc@OeE2K+W)%BbV>{^i{U%*{L927D`Ej`cMC-vXu`Y4}Hg*)M4LEx@!14dXH6_$>$1 zP5t(O-wZ~1&2zv3Yo0PPrcsb%=`7z5Iq2E)Wt|%>SBr|zHqRwmGBf;AYo`ilRdD6p zJVgFM>&vE*<23R;fH~fh?i}lH0KZRz2)_?7s+Mx+Slbbyun+J*8}KG+A3H17f6f1Aa-tuY!IaM%-^Z!e?R}s~zP%(*ZAXz-{SX8NC2FpK>xo{WxN{qANGG3O$`y%4FY zzH)82bwg}jLu73@))sDD+uG8;Ar=X*3rAw=*jt!aZz%f8&`IbcRi{r{dHSS5lQftk zz?$afNXzQ5Nl+Qgk+8ir+_0);^>ULWSZk6rH$>WUI0S3V;P%$FxuHscmEjGswhe9V z;Z?DgrX21DK~s2LOJmqUP^ok-IOJ&DWK&fkr6ARs@T$hv4bk>BD518tmNl!L9P6^Q zt>M+-^$ihFwyq1e#@4pt?LAw5RVwS`8jUn;Sk}Ri)Iy zC=ujlbzArpF)FJZ;=~#vku~eXIcln0oF$5eTiaUN+VhfC8e|aoR5V(`_6<={Z077D zXQML{qv4R8YK`^c`W*GSnA4n+%ppIGIY;xWHb4h}zlTNWtb7@ijZ|E3z z2g#4#G=$q?xSt2h7F|4i8^gsY7I9sjU9ot-zzLW%3Kldcy@kkF)oJAFkjw%e?CS8H%vk4SNV-`l~`%#ezy?kCFLG?Z0{Sb@r3oi$qL7ujXz5fR z6+)t?z6|MV@i`!2LqUfPspXJ&w(ONJ(Y&83(qCBmJubSO&cfD|Le!s&GK#4wYdzwV zQCZNi3r+NU%-=g*{1Rm)mNqkMe80nG#do#jHKjN*?YU_9)WYn0w#1b$Ikm8r6VzQ1 ztkMOnT9)AA&AKUy_ix5^0%0-d?25{F?parI%!l{VR{757X_NQac-k%NM+z^#ld~3E zY%pFVo+q(f>*PBt`EW*rd>Y_;u2OS48|1xL9=wQdB>tMI^qgP!d~7N{py)YFC;!>- z$)9gho(}mg>*<^tZ!yEWEo&3~xMh6;e&GVk`Yhodd=-NJX6!YgzlHDSl0S#T9$&yU%}-HUZ~(21us=_lY*~MFjOt#Lsf#`CIv%80rx97 zso>oTzFEP{7t=qW;M*1aXA1sH1#`}Z^4_c9Zz}k(f*(=vaRvWS!F<;y{}&Yel7e4R z@S6(8jnWL{oA@)Cf5?9xVKfpKDExeduOf^|cHW6W zdftCZ`Za{>ENg?pb6t;k&f^whGMVr3r2n|W?<0H}?sZi7&nrC3r*H|rTcz-Sr|>)= zTZqQ$QH6g>;dwrz5JvUy3jZ^Of1U70Fn5YHnJ#~n=WITI6n8@_+(ilxHCP2ORzwr` z847s5W%&uC&?EFc_)Y_T82JJEu>G&ohwZ;iAB{BI3Eqpig8nQyCyr}%Ew&FXzqBvc z1z6`mx~_R>=jmUF`inI9owY6WKZL!C^dS%DJzbFF1pP};&lcDEO?RsMz-sHN>MBHp zQ{M;n{BdLg4rT&ZZjD-dgg)i~g81SK#`HO7L_ezhcIC6LAfA0GeRP|`XJ0{hm-7D* zK0k6fG}Px8AD8rBda3`SzG2}FSv#=ZY9L`<(;S`^q-N0O{*GMK>H+N9vBK-3vFOUiwz|qF-qHPuIEeb= z-Tu{UBawyHHOq0$QUW{8+IlzlGf}*s`QtkW@xIZWCv?m9jxIkx0m{&vTb;s*#6aRQ zfByhE#JUFhlZk=8g_c13hX?U(2fT0jyVV6w3$6dnw?Lt=m2;lwxGT_&4c4izGFW~r z3ZE^)9d5S(p8PP*$KseKP8x8pzBp)rhazs{#(_)^jutYSz{_JA2koQ7kK>Xy#s(jJ zKdcD1u-ySjoT(E;jFNRz?q~Wm!%{ewCq8v24$^oWvNk;;S*mtVPnt4af`XQBta*0v6&1MAVkOgR@ocT)HyPh?&ObU znn>><=%$*7Wb%BEX#O+&3K5RbJ)GQr)7yIx2gGF~S3=F1gD5yM1E}B;+(}Z8Q&M)= ziz~PA2|M1Nm(*uai|TA#-?1^zx2=?1>O`Y`X!38UpWwmZqmy6beGm3A=b4O$Qd@Yc zX)Z28X-}1eUK#O*e(t;Zixe(>NhB~g!~>={NaMS?A592^ivmv(5802*KVct+s!9u9 z#8=EpE&Id`9|UQs{hB&o;=8YSzjva(Aas0~hbBuyeK?V_#*_R24)l~US2!Al$GJR0 zBXzvS<3?Jb0eKmCiC}y#3?e~R z?`C!dU>}|TO2LarqICX?xNHL{7o;I>nKiN2x^dRzSvU^Evy%(=yG9QegdQ7yg_15& zlAcfTh!AGalRibt8kT#Qa~y>#E%+~cz{7CCM&!ph?~{=h>4YBl?Y)LI4njfXMRsWb zWxpsB<&6_p<8WO110WISl751;^jMVXl3GjOV{0Y=`mGAq`|Fn!b~#@TjY3=)dd}$#dqvO!NA`#JvxEomG|Z zeNJ+O05KICGg99C?gNMTEi#yx-scbIx;~oTNB+-p@Us zrq8pVXYIAuUVE*z*IxV2<4}9FVx`csO?6o!hft7(-^;TiQWpFNNNI!IkMeb(1shah z6*~5|h6BxyjJ&l})Y7)>|N7j42XfHG&LepiRjP-{jhw~R{Cavm3Y5s^k18BLkY2$y zDfVSm8#{2=>^I|lh}TD-gzM z$ENO3riKG1N9ORAzh~rBdb4BaNC^P*Fy+z)#{#0RxG-tC)YF14!e9M6Bova+j(ju`y;sulM8`RBIEYuZ<>?&?{5#nPoqR;v#A_p|4lUj1mD3}Y-k zslmQ&sqG_M>7=*eW#Gq0c;$G0QEJ2WX`GNvn~2!j3=5|5%JEgc#P-eU!IV}nbJC*c zbV1z>=laqEtJf@&4`O_nV(gn%n-Cvn!htt3vaL@ZiTLKAq6JxhY$L}z8W&}oCqf(< zRNZFH$NBpG@@yQiN%NZBBS0zLEL^X62 z&$A#E22B+fO<^W;k@oxT1VH8cmM_S;a%&1Jk%E09axMEOa6boDz>K~t2QEroVrngI z-?;Uf;Za&5*XD?QZ26Y!lq3I8V~H!VNLwySy?Je1LTaR^G(E;`HEt|Hc`XSTSV@sL? zQB!?eyrf8f3+Zr*VBk#!Rdxi%slwpE#;eubA>Ap&m9Gnb+KH|t|HT5GPY_%Uw_IeAAFbm<}n+oU{JGUi@J_CWlg*+nOtU)NZDpH zkXH5z;oZ207N#rdyMCMDw%VNoZY5jA@?0Gram@hJH+1Dz4yqlzCPlT?w)q<7XtllA zHrj$gq6I6)6W3?FIi}>wnI+e>e$CSs%JZi97=nM(d<^9|VW$)3Z7AQ2{13rM*m7+U z=6?jnc@nM%Ezkwe6w!)Rb%+& z_}Mdau4%Q-(Ui|KYpsjGpP<$uean|oAT~vCMmSRxN4vTyA5IDJZuP+Sk-p*I+Hw}i zTX7ugz&nf;r3c}g*{L;yIJ>FE#{V__fz6e-*1w(IEna5o+|)?lmMaHR8`ZJczJK`^ zHhc{Y!9+>Mx<#wCuH>Q=JvWrmL!0msHoXwe^cYd7)bh0=J#6dLgMeq-o07T^-)GCW zX8E#}i@J!%`O!z}+)%Ad5A>#KD1vJmi(((M+c3q8fh}pOquRhAc$T`RFAX!dS;vmP zPfW`Rv9^@T=UTa{%lnw>eTu^5d_{tN`TleDz^0LbZG+@^b1a-C?`qTXm#F2Z^C(h| zb2xEiRLA#k{7Unw&&u}q=WqYtXUqR4x7@tshQI~J>pFXqjoD#QH zD+J3&2#)KajtbtAXkL&#nQ+^qJV~F*M-zU-P2#4H+EX%IfGrpHXgHAlpS%|eWyrpx z`SIk$4MfEG41&m^)Ms>YG}vOH_-8zH=dg3=Wpg}zCnNDYh^?dy<(VV)!so}cCvgNy zCE(^G3_9(GI7aOuVm^%!oI5>^PeqV9Ij)taoI%*0AvVJU@+#(T`N0`uN61~Dym#Ex z>hJUhh%#M;Hq%(mu)ZC*YHhp;s(_^9rqLhCgb;#0}^U#A0uB=?QxC? z+C_$vqPH)_&{|I}8Dl5`K-%e1ZKK?4j z*W{>D{DU*_0Wcf^pMW8$;9R-*gAmhHdyEr`-udBO(3afuBt^P9Szi7$^ZI;!y4^EQ znEhck2S%@*seN_a(i}o4Fs5eyP<8#yuUY)RrW6G};2BXP%P)mgs)L_$x{r=?F~Q8~ z0uwyq-s>aiFkb}mO^yzTq5d|SrlXFphD{V&2V>e`ih^WKwXbBaAdFj9d$jpra!)r^ zG!RP?nFnj1Yz~sUpNFdWYnh<-mGnC^Mg&Y;*l++ub)30JyswGC>P~{5kYD?}Ew{{o z#Eil^!7x#(J>Yr`AC0+ZM9L#655 zB;TN}>8peP1y?M7-?sh)xT+7&Je5hMOadTVd`iQL9PE0Ju}~%fciS~&YDGzVU7S*YL#D+i1VBH{M8JO_X=CH8J*TW%~VNP4UsG>|iVBBaXfPMrN=z zea*t5ueS0!x$Fht02=*AGL4>%?004<{mA&&_Nfqlnene3<#MF$YntkoiRyx%b2F6< zPnbi%C=YpwwTZ)Hj~y_M!% z>8(^bs-nt4t0;$7QBM7La(Q4Tlv7`^dIv&tvA}^<@>SRK`JbNw8Vb501irUxvn01Z?Z>Ish<;CWsCXJ@WkkuAswlTY> zilS>tE#zER!#>2MK6#5y77jjYFH?jU&fV^9ig37gZ!{lFzhzfE zo_;a&YH)_v$wGe*7fudZNFU`sWX+tV^9A9CG~D@t&h_K`y1T27kuzI@xXUy2KHqiO ziAunwdl@};z2L%=u3M5h$%t1Gm+$LViB9bDVSmPrx5@N~&eK%)U&Cp~i)P^HJV==O zjIpc5goHsZjFBX=!!h(e1x9dVx7jY?jv5rRl2Wpp_>1;{vX(dgr7GG0xRzp=a zlT0n#*Xf?_p-jRHk{n08MoD$`L6*uY72ieiawRp3Xc+0yjvc4$9|I!LQm*bbLWuy> zm{R1>k~w>l&y+dTaA53JGB!gbdQdHQY^Su3UUEK;#Lchn0#$O)lo0aXRK2kpEY@KJ zZ7R4->KA3-q?utim6)0@e~rE(V{%#_3=~#d@RDYjSHEvAr3ODo&@+B=7ghw{DO#Kv zc-Z3VOnc5$-pup(wmf}Afa;q%W}KBZ)$E55m|F)?Vsf>v!NtXhF=SX;zG5x{b-(HB z5uR0nx8a(@;=8LGxxnRCt7BO4COvn?rvvX1JC|Ld^HQ@VP|+>4=vFyUBzu+Q+V8F` zb~EWAcO7=uw7c$b*PXg@ZZ3<9Xy&>slZGcH$7@I$`ZI^^1-BIs8T^%khm`W{63JqM zSz707d(o0oJj9wMBz8S)B+q(Cbm$J6vC-JUIFHTnh-*Tx$(=cj3$Y%9S`T8iLQDK* zQ#w6M9g5PV#^E4fMoQmLjvpcutzA z$6lwQA7dF@^9#wvPnm}PJdZ`l|6N0ikwqF>D*?g{eVEp3t36I{;|Ircd_#M)^#To5 z*w7ZYYv}ZRV;!9aP1@x|Dq0;4+;U*a2_3jFO&%IvvhUwWp9LjN^O0FMNZ*AT7=g>t zp|6De5zPZVI}r4A^V9IZH#z=ZJ;Q9&K3#iE3RFQsnP1NDsP4`@^zu=j>}dm6^DCL- z$x9B#A4=XbNsCV$fX7X=sCeC|Yx;aY{9B*gvt2^bLF*b%%!#}#i1e2$9iS9U%GKR` zm=m~ZLcS<~l+y^LGWsU|I0wS$TW|B>bc$6YE!DLz7(G>w z2e@GnvZkC*^M5z^`^`|%H`x`cuyiwT@kMA8&$=n97cBbJfWif>xSE61*qoq3Df-kv zneoeAURG!{=V05a(}D%P@E3tiPSmPwzkaAeollxU>^x}PnL7;kTQ+~5zOL#)2Q-`m zx@$U6w*#WKPAKHN71Y#6*wlq&j@ua9&T`uBODr2ApsIt@Sr<1(J{_*Fi}D+u1}jjp zS;h;&x&FOpY_OOo_yf7LPH7IOhiv-IX~g(H>q82t2-dpG1aaEbv^?paPY+@PIX{5E zJnhXKseQWnmE`VbtWYTmnR!JpHmE>*X&jU1FYtsN+R_Rbw8^H{zM3(@m=`GCRP%X8 zeHlgKS`g3q1auj`VC)HCg-mfU%qzaz!r7%paas&t^NLijbnt0D{Se}-Eqb~h1ZR0T zgv^+`T>LL5_D^U4bQA3_`h>J)DzET*oq895i?5ER$M9|2=;@SFx{AvynR@qo0m z#lcT3U#*8t4lL$1F9Ra02rW6BlqIY|zh0W}Z|x9YniY8)N{&lwp=Y@E5mvq7wJRR1 zbC)u&&c{S#j$*y>S(AH~(hyfeK?2lh1qx`D$ zy&xz~NqG{*PE+xt+|?N^lHGM&)3dk&>O;*(XqJPSs_NQTq)>)~xoSGrfoBld;o65_ z^jXei?T~>Kqr>f}LZxv*A4dqX7O?i1BTxs47y`Z0Gyzn&E;abnanpX*j>4Qm z7QzRpt`7bXs5hhcl}JM_fQsleK*2Q8QLI&Hek$-EN9Av&@^t^w7 z`kShSTx9{r)rQ@e(GJk{a^D}kB=um5KqX~pDp>=HF|3>{m&WV}{t}B37Ws`Y%_8!@ z%gbqYEhjOuYqoxk##cuOf+Z-Oq$2ny_(OqmpY%afLj%xtaXuFm{1B*{UssbtBg`A1 zj?PmtfGkL!&a`}mz+1qyG$qng)6;sU=^&tDOarhZ{ym%*6qurS0JAf=4a2~TRz^zQ zV+Rt=htgZ2v=-*XetOlsi__(3wR-=NM z$7+9_yH>nWOg6MbwRQ&V(={zC+Gp8!T2!g@IDz&u4B(X#-Cz zSc=SLBH|mgAOjiN)VC$xA-BQz1naeU1o;yTis@@p9qf@E9|LbJGm{eEh9XQWFvc+7 zW6m55{)qB%9uAu3ZAx2j*S3@|s}+iRB?8&iQY87Kt?;9f#;bh}@3|X6s85ccZvz(U zB^qnBHr)!nU$kvoJ9sNlreCXP*)x4W`U1~Gh8?y<2~)m(vX`f_J2XXM8>jZT&CS|) z%KRg+&6mq$*s72I8SlyBNrUI6xvrUmtt!}8v@ujs$7Q-;RkW4b=_7IVSw731*2uIH zVh}GXI%q3;uasNt;C1amcnNPzKr7F%k;-77l>4<^YM&t~_p`{r%$AX_GSWY#D}gof z(~zxb%`Tdoy}Y{i5Q;R%2f{L7BS&u7VW@}B`09Dd4 z2oa6xD&;ek6n}jrTLmmm@MT{^NR?&C_Ky`X!xGULe~#~d>bsn`qbsJ1MB-?Q535(4 z?%xo3FHb0Q;Stx@pS%9z;);FIQK?@Zi&W z?0q_YDjK%re$n_`fAyELJFC-_xg)N4&Cbk|bV()%So<1x#$D%X#=pt&U(?Px>8rt| zv(i^Xd5~ehG!L%1u(&3Eu=#1JA}!yTKEp_0C@c_vj%eU6=mMlZ{%eXbL+#A-+!^1w z_GRu`0f;5XwNE7%bf#GCIEK?I){9Y1{7~~Rz@?egR*G}GYdi!33|_lM2tjSj#t>C~ zk{WwrP%zQ?8&Jy8($~i7xT@nAHfF>Z!*mFK+wV}rj@n1O&iuYAAz3ZgP{{H?QK`8t zTJ_NMu9wFCU7wJ77uZ_;b|iI;`N0?}>Hr!&z?ESDXzR`#vs)NUd*>M)e3k|d``!BL zrP5Ji%(Nu)lU0^uQ=fMJn@fj^F#cJ?6HLNr4n0OwQr!Q3}7~o=5 zH4DPrh=$k*KvOm=EX09RdcL16HY_!G73Q{Po+MeVr}5g?2=)F9I9k42@LYS{wO`ld zcn6(kP5{xl?~>8$9BlN`ActbT6F|8c{WAz)4cXyzuMxmO6=4L>#FLExnuv08{6XMy z0w|X%U#u^3y%Rv=rWX@Hv`f-8lr!}*UQ{e>74 zHpjG&gX+&i?TbKVj^*aM)TlP}@)ZVZgkFBb10&FWJZ|JV-+sZuh+L~nMy{t-*idcS zAZSJMJfF-otn|PeLVX;Lw2|wsh+IEOZ|2AO@cnRG^}1Mu?K~bkSc4>K2DmA^xh{Ko zP3Cz5F2|F%d>p3{Pv@27c&S8coB>+n3=mBOAvoIx~ETHo}5*XAI7bC2rUE zde^DRtays%<#m}yfN8A#Y5Hs`VX+Mvy9HpL^(N-iZmM~CO?DAcCXAC0B(|$UVcR9l zBJ*;^4m&c}*JLi2tJXxdDygvNBl4PEqz|&TTB$TKW2mQ;}A{Ei>AHNfY;+ z`k<3*V-FCU0(;>4NM}AwYncD|;M)=Q{aOl}7u6-lpV1&r_G@Wf@Pph4A!K)~tund& zeCTg$e}YefIIdyX_*`l7qB`_7IGx-0Q9b+%w3LUzpK?XI3d4bDfhpXKb0muE%~HUQ z;43(aRDNBi+*BUj!VfT@!4wAN*i^eetskGNug~IBB{{>HYXbCUO4-WM<@2X?WCunUO7ND~%&jkOwp*M$r`#cMaoWBT*eXIqq+1%;GaI8lA*Et z4zM3uO_DO~QDV|8d5m9SLyt&U9I}(E&Q)_QWkWgbsc2;-gG?Q~A#9mXnw6->*5)_2v4V8QwLKouYL^&_*QpaEIIypbiZ%~8(0sGuAkN@ z)=x7?rp{q}9_n@=wA=^o!g}I3nR#&Zar&ckDQVL_*6kX3O^(kaJ!>g7T0i#Nm!l6x z&!pdwA@2;kG?_L_it;w!*(GQ5JM$K$h|TY8K9;ljEqR--ZZ2$>Lz0!Vfo~Q+iwJSH zBn|(>l_t!Uv%M-@M(}O}9}fDx18QyYYvO(>QuPM7HC0ofm4?zvMXO!M1wqe@6ZSS``Bv=|FcwAZsvSNL0#Y#G!!r= z#bdc7P$O5wd{0}rL1#GU!k7ofo;gz=KtG6m$yAx5&1;nv+|5JpCl#_h*lX;QY71aK z$6Yd0UVos^1UAA}?!Nb_A`mg9h1C8B>oxw+kfPn3$Aph*kcNc0DXqDcHsnHmJMuBw zFiitZ9@8u|ZXMX_Y1~HI!46XPk+A~=TIJZ9-O;F(&x-SAmzB?7R;CsEXU>39LA0r_ z?0achZ9Kg=yEQfO^W?{jbfG29-z>;$>LO9P5al2P==`T@(-jO8HGqLwxqsw_i?>(!cW;xps| zIQM(A?a2s@;o*O2dwu~T-gJ9rm(|?0D}DK0mB|T-qifi2>sF^Jv6AAm-229TmiyT_ zuh_+`<5tst=gr&#W?ZXH4KtMTRtN}Qkc!RH{!j3J=JuE0Ia}`ALhVm!Z?gSAF}?lw zBPOkAU_biYf&t3!B(pj_cJW!;Q-u))1z}oI*fzAP9TDnyfSdKqoVW9^i@1WqYrPow zCbf>!-T{OYFg8)jTnqx&Dmq!@#OfQQot-&gG)}p z(f6I;eJSrF?bVsrSL2Y((%KKIy-v!0N*X#X6w-?p+cCNghpb0uE2YL<%ftOQHZdOx z83ASS3Wu!Fih>rWvBqiVA=-R6WVh`^fi@|@!xROk=@NF(3+^J#&_=!s-IjW=??^YY z74%l!tPtmaA13(-R;YMSjlb*qT|{C9c4RrCvLxHyIPoxOQpxc@5lZczTwcxtO&)Pu zR?96-TbD{V7q8{iuIX~}9jT_NSfRKjRKbyeI3vC(B3ep5?} zX3mUa5xh2I0|fudD{FhLm#I}XG-%DX-P6jl#e9_v=1znn4rc5}2#1M-GNeFrA69IH z#j#V;K~nn`H14YeT%&C(NgDTAC(NKla^5FN%Ds0p?_`EuscG8L$w3_FH&Z!7UF??=h8u8i85?rK*nPx@WmYA4B=Jy~S`yLP6yFfXT}@a$x#t*l5mh{{&$#+v_l9gh$*wogxL74{ z^+pb9d^@1qZ|2)g&07rVP00x@6=P*mOLDvqV=$jPaJSHuw)QRvk-f1pSR`YCy)*e! zCVxkALML*wR~1XAc?a^R$e)^?KM}l}_a;8z={p>3FsE4Q+3M>dMZ2+*B^yiT1j8bTaT78SDqlxg z^GGb1sr(L8z62*yenJu-p3~gr+AEVUzaw*FLgkkSr`WiLm+auZk@Rt!hL{=J+WL8D zK%=ynS)p^uq4{~KZflBXT>Ut^O)#X5@#R{tH0)~$c5Bv+c!Zh5vunAiyHRpfHhW`& zrEENK>)29eLEMb+RftLfd`s{rxq8%v%CPv6t3Y84^`p|oJPq!BBKTL4$NLQS)YE0= z;_QhQ`-(hYExF44GPo4fxpgVQr)+!swg{ewE-}IVu4p*0ZY>q9-ePk0JCt59XtH0K25^3(#-x&UQ+gP{#Tue({7|Cw<*@jm&pEM}1P+#Z}Em({pj?=48+CQMc`H z4?BCXO$T}BY-oO$Dh`K}wS*`4Wy%t9FbzQ)<`7Fkq%tOju6yH zCl+3O-G_1>Iczk3&9~Sq>DKA}1kar(o9hPO4!_ zbuymY&zNn}F$@du*#(01hjNB-^e5j+@g(>s^=8pQ`M1vGm1%+CTfC==!+sVudJayq z;2fN(0Q%HOzO~WDVLat=LqG0974O8w%IxB~uAZdI0Wi7bhGBc~h)n4Y8EaMF@dm~z zxo3^My4$LE35nb$yG&vyS1pm)!BsJVG}m&M*X)`a=7HjT2C0_6lpraHlNtn~5-F}@ zM^acv1Hpig-2P=HFW>d^u|ut*%r8S5`!UwVgzA%R&%yXQrXyaFTLiFBwzzAnuIck~ zi@+JfoKD%3a#D;VV#mH<&_1C?c+nI;L@BMt^|jLy+~%R;2Pb~cgO>CrO`ChCj~MRw z_b3TGO%o3%$4|y5q19SzA2Rxw-1Amh80n$uu*pS4~}o#}2e+%$jJ}VOEg1 z1<6dAFib2r3z8v6s0^zv7v-5}peQkRK!Z;coR`3Ob_;-2$2GoWza4%;=TmI@*4$Wd zK9-)h1=S3GA-O|%;ALY<^o`g8Cz&(=at`BrV+?FNjUCj~Om2dJOm>7X8F9^?Z?51e zaC>rsA8Gv(@Gfp;bs<;3Z@rJQgCB|*$0sC!bqkcHno8P+z3{3qE5J_9ynFFBi*t$n_;ApqpfpHwkE)a7XENI4QMG@> zr0_Q_RE>YcnDmb&_=u~2G$%QJo_#dOKdMTOKLVxu{CXYf)(xEHGWt7HA5(uBvg{}f ztTyUnsyy-1%db3&NUjbNTr z1oPX#JjVz@4(XF1tpg+93BlseGc3KFEh27L#<|ExPVxjg1J*jTJI7aIN?2=hSl6qN+>0$@VNEwt0XIBBvOJo@esnyB|)2N;>dSId( z$%&1iqxZC5!tgJH>(E~apIbmUJ9k2aKR%uCxzh__0fbBe4r)+t4On#n&guf3##<;P zJSUBwHf-c6;HwV)6>|rTsT@8vSt^8Ydv}Bhsbci$;4Sc_f=_|Z7ZNPcQ)g!O1>cl) z@h&0jL;FK-(VwX=8Z(glZ(a1`D97+qQufmm^?Y`MMk~u!g7A&ie1!s|kY3>&?)!g7 zNa$T#X<76AiKE$7l?0IAm*tZjW(aIGF!QOhBg+Vm0sN`*Bg@pGX#rCuD{1h9{P!u| zXj_cS7s=y>ia(o#Uhy@pO>8D`l z+!XnZpBr$&pi``jXZV5WF%=iXJmdOE)rRVwa!rbJZUrIz9t4&VInoAG4tTMB# zDzk1*b~M3(IL%L`tJpyp>E}0w37j~8> z$2ZGPI*80VImz^nRNY3s-P2-!U^^Izxi(>TW^LM+ zT|sY=K3!CoQ#ROxZkll4!nM@+HaJ>9uq&@DyQN(FQMZ&&E3ZS{gvulP3N^@RS!QLq z%KP64JnMq$gPp?9^I#h{*%4lr@jpyDDYMd0ewCqIUuWaon}sXE^c!K~Ye-LJE-lYo zo|rs+vLg7E#phHgIF+RQYzDO2{;hBJ{pUpLT{)53e%1d!;#9V*~z!Cp0KFczcR7# z+Ol+2=JIlm+88OztW8Y5W3nMQPZ%yQoBHW&e3?PflH*S!JUPxJ_k2ULM6 zDnodxjn8OdKTT~oM-(uswiREqs`eL<-nKApChFmx+Oi{BT;?Dj?1Fb8K^py^xUPJ? zOs78!*)n?D(U*fuksRzPwOB{PP=hX={tUiWaV)u1kF@TiU6te7<)zRt2vS;U$V17` z<9?WSB4?L&=cJNLxD)qQQGzKgIo_|{(~1H;rs)#t(T$=Vj8Z{02c* zoPgV%u7`ncCs$j_vu9+N2vJVdZmg<3LN5imJZ*!}_FAqwbw~V5E|Uh@CZZgtdkcA6 zz_jGV3l!<;QVWf~J;sfdG6W6Mv&daV)P4K4;~@@|DKXV8r-TATrBggS9|3J(8Sg zlVx-H>I1DTG3{Z-+lv`EB*)*SzRayS^I*{x-hI6BG zb(?pTrB4fV^qvXZm2k@N!o}F#AP&R#O%iIddi(;lr$2r*_$4>Q7<29Bc+DfNBPb6( z5Bh!3(xtG9;?OxwvF1b^7qBuTi@+wll!{V*J-;YbRIQ z+fzkCj0N$v%N&*gnO?u~l%&a4W3sJ!$n!L+Jb*|)tWmNi!I(Ck8>3*Q>16qyUa%B_ zk(#TYZCFp>_wjB?uIoIh#<vV?`a38J& zHv*nH60GG62*)AB%Xku4+z-+I$b*?sLLxe+PQ#upmAqXtS)biv?AP-MM?2!wF1brC zJ%Wry?K>}{_I+vj)HjT*X+3s_q)oN}73oY)C>quLy!oBz(jL_L$w*yJB2Jo;k zU=g(%|0}g+zT)K6f*?(8o6a>Per3TfYacr$p8!_6e9=6l%Yyp_D~GQu#~)eF8=69F(siSf|*{|uuvDlC*M-|)fDqzTsa zl?9I(xOlcbv2c;>-VMJ+H6~#X?fv|(!6!K^OP5VuZ|tb>H5+`l2w$Fso^?n<&Myg; zh|R0YgV%LkQ68)$&txU~8GMoxwK7L0PqH+d>LoPjozOl-mia7qRL>CQMGrmg0`G~!^u4vCU_R5GK*8$Mb(+b)!Hq; zxCZ!Mis+}MxTSSeZMmRwY39^E21C!78u0Bi*S60U;r0=S$fPdE@i*M3M%rgeo}5IZ z%6@y+hZHK+6(KMLt$K;=EH)mZX?}wq@5qd~O!HaB7q*-HQ1MS^HB9^*eW+JkaBXx~ zGYyo!Ft-Z@e*X)vBK+<*tRPl&ifRu*TKiUI=6|%!cn;*r&}*?=BOd{IO2o~_-!%2d z5AsbHKc>p?wpWngs-vLlNu6nATzf4UO^~ePRT)&8$thDW)3Z_n`Ky_30E^jf+LQ}q zFXUNnh(QUOrLW8^nrp<l#8d4Ype2cZPPWoH8KB#a*2KqS(E{Nr^H?6FQDqJrgb~@FggB#NTDVYRjg3thjPKj znA8;7?h5V96`HkQV9GqgJk|k#%*UcTvhO65>6YA@Ow>rTqsw%@x9vx%R}0UqRbsXD z+C=kFgi(&!{^}oqDO<5{C4Gt3pWzison?clIBnbxf7GD96keBGl6VK^j@qMa-s+8w z9ZzoWX?Th0k~7KKS^K!1zqCe!ObLkbRcRqqrNda-^1GD&LA93LxXDH~Zr-g&_JAPY zPr`QMRTA0Us!UDIst%b(i(cs$Ri|;oBxo68?u}(Nb_DVrUd7D(cDda@%ov4g=jXWp zEkBzVS(e@&%tPwb&v}u}91I>pg7<~e+PJvSS2d8)pg${KsZIOzz4PE!bzb{ToW-Oy z((v^)_S%t=Z$TJuPDpa=v;)n682dMEQa;yE!3NPa?Y%pO+BBfrI`}YP_-FSU-k}|= z-Tk~-nnlN5CJJD`j=->p$E&{!H<64kah2hcxSXbVzRYyDp;KUE59<7iE>EU! z5h~S%Na~oXZa*>Dr+WA%vRxuzJLwkjSy^MjOrl+Z;WM-rWPnZPgxTP9HI$Jms4^6p zX=$~$6ZNStxc61nCQH6Kp2SsY&?iCOM%!tZvc4t7_jGNxswNlp0VAJG z5PSjW=}#!F&Xkt^Ec(gngY?L6zGgh?-a{Gc@}9f7yI+%yci1 zq8`kN>_;ZvKpY6bC>}%Xdrvc0INKh7mCy0rA~#y#*-vS6r1lqez!a?|(8)AouwkwW zlN%lA>@_0-Z0?YZq=2qZpK5ER54+KXt>}JtN}RqtLAh=xj<&JLgJ9{!r2QBmw^gn& zxUEE6%gJfiU4)zlwO{|K#-f;all#r51W{^oBn&ZtOdP>$EwIs+kY4DJG3s~ML3bT; z*I{=}yXy{JGdD|J8XhL!PV;=cdY7*JiXS%2(_8I(0Z7{PqPEgkHY-MS8u*%wjVc7-o->Bq2m06bg z_1J@mZF0|R;D?f(nWs6}ij&%95#le;ShbzA6}J;a_1Td*nzZ{3o)FqSPJt9IUc17Z zAD_I5bzLv0o^}mf=E>Rz^{GFdq6;Gexcbg%Ty@Lko`CvQJwKr+&jVj5RugsL|G^QQg z>J-Nzu4P<}8)TG0KF?#Y1I2BO^IyFVa+OgaI^D>$FF|kGuovbIQV3^rWgD25&5O)_ zm5$Uok=fISR%54&pEubb?Buo7R2Z8Sfh#HX{?($M#rQ_ z`f+=wxiPn2a<`NBSKr006<542a<-t`0PC@S!gHMT-8Lya_qbb|3sYtcEW+e_?3Oqj zc^3yRXnbltgxo-a2e<|MK!Gn<>kMyxa9Asa?6L~!^CG~?qvmpX)K>XCUywW(%hOT4 z!)4f2kYQrx3`1nlsT%1#`k|Sj*`l2sfBZ$`Zw=;itePQ5@E3s6Oftf<87Z#nm^^b# zyk*>kI`SjIY3IyX0FIh@KR)t%;h@m@kW6yVDZX%L9cki6!{uq!aHAc>{C4Ff$A3i_ zSPt8i!oksUjW($j{0QkmpuPbyvEWRn6X6Cm^PN(Zf`>Oqo1zc@pxDEY{i+D$Q!2=p zzl8F0iI>1pe7Fj!wAn-TLoExR5m*=9BkC;u13TDsAN0#Si zoYBehxcQfn)e|Bz*#<(&O_4B&lj9n{lA4Q6s?nR;r>DyIQP=A1HCku(VU`JGM->l$ zmE||NIID8x>3`YGVHVJT4U5Kzhr>wGpI(}yTxhV)MW|*G#_OSY`1ljdS*jrxE5O)o z;@>95Di@_y?Z>svUE6gf#`?xCt{5nWoDXqFXO;^Cg3GiTZDwvYT_!%*HTLb?i6b=- z*UF#$9E~_K?Q=9hN{-uj*D~1!G_y!t{c@RM3RT=yssV)^kYO#Z(Lb&0SEa}&YyKXM z*9d<3h{QSKO~y5&*)VV8->yFjbTVBi4iWsL`jZ3ZqH?Cob7+70UI46Xm>i#<2yJL? zPwx2xoJ{CeOwfoVWK=_!zKf}qEKSY7P>Q>{?@{YSA=_x2IJx)^QzU!@wa)rE+R!4b25$|vq88XE3}JBj2&tsmyuTYBzskhBEkCd z3$m{Ww)Aq&E#^2onFp7&jUsyEYi!y>3V5MXGkn5r$;5| z>U+;B6!&0(l#5vDrSwUb#2`+Nzb?bWm}NeP6-=Gs;)c{Fbt1hC(f|7Nd8(XV8etF3 zcR0Ni?9#w>~h!jx~9+0=^_H4m7QVnqMGeyYGXZj`Vh_> zM5~j(E_PliCDF1fWEe+85cSl1o_3&Yom{1Ke&s<8*rkw8>AFRN$?23%@1*Q(t4M!< zI<9vLN8CjnXh`XtL*~}!Dc6W*Q|90)Xy<&(d>CXRp2ZG za3C|%NV(ONE3?xypRtMC7qD9N>RrY}^Q)|g5c7xTA!F|LWxOAX@&!ZklJ}cL)J`acA+WZUJx6Z&}4BWL^R~B3` zXy9#&dpgHm>vc7|rDd8KB0=b4a(eo=e( zC3CzjW8^OZl$#LwcMOY0z{oA@f^yrh7+W^-2Fb~fEiv89qL7oFMWq^M9;J)zNREG( zkv8j+Y3y1p;?_R>(2N_;+i+R$RH3(-i#1W|8d|cOjcxkdGF~!d#V$2kyCl=sl(S1s zC$dYXPcf}J%ltDK(WX}8FSHl6ON~^hE~4SkRaeX|waPBZ);1wn261xy-`P%yU24NF zHHPg{OA)&yE>fJ7()IV2{@LtOi|8+Eml`8f7qLq}q6KnxX^4dE(y+Uxbq(1i+JC?8 zm~!n;HM@;nN^{o+C5<$#!ZO3yB~?at$yUhJ#Mq@4-n0q^M)e|1>#<8i1_~QR)k*g9 zsti(ghy;_<*`@WoXrZhj?8DgzRyt>wY9S4zIcLE50hH8|y;i+MBN=3mI_4vd-X3W* zW$lqR6q<5mj}(+dF7Kjj=3tsnWy>RS&tg87>sY-gr?9YIbdjS#FLYQ&H#y?3C=ZFV1UM{-!yX&B?u5>M+%2^#sHbfh0Q6iVW%D}_9Y#bIPD5#R! z^5INZ5n7_0hh^CkUsHPGUa0J^4Vd*BijBRJ+&;{-<O<#TkO7qi~&*nHL&WQ1rW7Il$J7(OFJbcb zx*NnmLsf{PkBAMSvS{S$i0l`+mYZa4BqyM z@xJ|n%X#AYIHpQQQD;@xTDpW>zZhJmzAx0Dm`Kuf61)zB0sOiKty-d)?}rMh!Y_23 z2!0_NOn#G(Gqv9)I&-`)lvbxx61-D2AUs<85Dn8rt&lgic{2*>q2)>U^Ss49+x-P7 zVmShxhJkN2pW%|c@F?dfYInMpD7ByyMsp1UreU(D*t}RLKD05P|G_W+rVO)SmIGvb z?=QlbhKmQ_=@0%5UI8kT))uVL2QNLBeXZQAu{lKs$R;8V-vMcpNRyUh`Eo)x_2pc4 zaTuftpS?`Iw(Sm&wEe!FWe&wXIP|+hm9vwrA5#lP3CWcbToiuo3(CKKkF8Ua(Oqch z-oDe>EeJMW@iMS{riw0(s%Xli+sr|?uzg-tlQmb}oCNT!7nng4Qhb|1yZtOxF5{U> zJK%=*#-HQqU~mU@^{=M>En}Shf^t|VqUFPF!s-@ZPccxd6$bP@62d)0wHHfE9o$b&@_U}#osbzW%u2kmmR9>z@NhD>+Ri1}_3;nnZz_1$(E&uwNI4@_>vG5Y~8 zm`GMfjU|6hmpD;bS$z!R54j+8e&+falN|kMPCiKIO<&>6wZUL!uJ0%Vm!*&b50Hfd zMG$l34{@Oqk8;s@9~l2H^7L7fbQHHc3Lv#9eyrhP`j{3Zr$kE$52R0RKD_;d@#D?U zZLc+p$kS)@;7r1&%@2;eGrL#|Uz>QsLH0b^cCKj;OE@xCCJ}P>%<#+3vR*9zTXz3o zeBrHzjLFrNqmxX?J_AXbkZti3vRY4oAT`RgrFc1cx9OJbyljoZIf<)^{MJyOw#18> z2$QBEXPuC}7LN|B`S_&k_%su{3BQ+jMTdAi@1_X7?{(LL-k#?}?zwTn8lK=uot^~x zLYkRZpEgyR*Rn3=6RVgiRRmLWr9KiMz3ZZyGPC_=4o}Mx^?lA?*B;f>B_A*PlC`?M z=5@w>X|mXy2%9RAVhOZ4J#PFdORe^Q zG-Vq^zmA(`k`O}I$KjZnUFMVW|C=m4>(WOsnO)wa??#{==J+2M=&?dpr2#=#pxCX} zL(!(W`9cfOSqVUI@UXRvGrS)P&XVjS%o!UdtE7CB-==doQ9u?km^W%rCMUvBSV-La~$ZRy`CbX0blF6hDG5OLnD&whK)9j^+?4{-p< zd}Wgpze6fGhyVP5fxVeJLJg)HMh6!w5n-m;3>y}sjH{-dmhKI-<|>Ebdf7>$kk0g` zr<-2p-_q5M%)hODQ}b^VCrM#Yc)sSOCKgYM5m|D%{y z9NL`r(LiSl{`L7Be?LQx;3PopWJ|+;jTV`+P*(;ogyF~|$q6@Yz9tC3Tx^YmG(y*$p32a3#+2_W=A2G-B`kMPJdK<5;NFhZ6q z1xL#V(#&w&P7c3`Qj+6?P^`JJUaoK=SK4+H)bk|;i?rRr$+nsQ{SwtTL=<;vf=Xp@ zbmE_w6`TI9H-gxFAwgM-lKxOH-H;$4eFzD>KQD>!(78kFl$J?hJ5m*!ulujibCbRFf<|D2*to#Sm%K~>JB6QI!13YR7b z$~`i5mpLw>OlQ(Tocf$CH?txZ=wn3?J{eatXpvu;sexhmkZ8Cz(Yz8Iw{oAkNghwN zLOCDREBYSY>zq>>BJ;W$!K_^H@nSaPB*8DNG`iWsl}NvZ4M*wD!zafnR@_`ChM47x zQWr{xH!S;GXB*x0LS_|UqWMzjsImoX6Tcc)?7UvQR3drr8GBFH&Eb+b2Qm{oFI5w% zbO54lq{pV6ny-kZM-9{siRN|X=`A2t(zcWQb^Mpd)Q9NvE~HhTsn2ZM2b1V=*haKT z&vB^Te&5WJSg=9e&9buKce&z9lm#EqgVC7%PVx4#V2e!BirCbD%d9G&+GkhEMb|wKfmrZbqA1kEy~<3967BKUGa`A2qAle<^WeH6M>`(`UXH$Z(so+}?cG z9OG(^o600$>m(;;^`>hML}smN4r$Q=i8D!Bs(A#FzDsEm5`UG0l-(o|3qB~hLeXE> ze4~#2*Xya1?f9gDFK@BO@MTx)n#_5@H^rVCW5FMD9lO3fHhJObsZ*D@@#J~gwZ@Ks zqZ-&T!QNCBY;}2lrRxo4!IZAs%k~AQsFv_LE+Vc?kfqarln3kdhGJIf4f4y@ugs|k zuMypcH9mbgc!7=`g7d#ZUlpZXRJ3-RetD{qyiQh8s?A$}0R{#ff<3*r9Tz*mWS2WN#DPChSmx z(a~Xi!@1d3f1p`%&k~3c1Q@)Bl1RZE@10Q2@Yq$A>M4Kwbr45Dgsb1=-3XAmbr99& zR_h?-vF6u7Xvszm^tAHVX7-wqo}V@|?g_@9`LXyh@}&d?j{odhh!i-?T8Qss8DLj# zEyS5&mIPmw-SE?hO)?&S%SCD`S{G!Ke{m8mu_?|Y#N8Q}G z!TDgSt$RZIOpeU~iDzW=UHvTY+Gly!JIlKrv%K3k%RBW3GtqfqmUkv*G(+8w&5|#C zXl;})+FLLaElsn$3m=&q#W^@jK8^2ZD)07L-W43}+h1M%u}?fejSGG{SG=%CDtH~+ z=YH9_)epp$U2@4qshVXguc%EmF1RpeX0!m0->^Cs-&q!aPk93OI2LQ+*<6R_7F`!r zlueW@swm%6x~QUZcVbaR)!18BSKJdX*>Gw_)uIO~DiqHNKF6^TWs)sV%+ z;kd4K`Nv9DRis8v1>}K>#FEoG>(*jsidE}tkV=|1(rBObPk*Af~1`ssN?v|o~=eN{zg$=8aIzWB6~ zyNWz+g9ZhIw1-K*_uEUXldHx7`e~C;sH{AnR#nvB1kR-qE-gK66HhORJhi-&Na*)= z)&|6uRUC`2R82p+r*s9Cy(wQ=4Sm1sU@z3Qt)jDi>@6F1C-#(1l=M5mrKUZ8=HRkK z-@v)6)Zn~UfF%bV2h%ISDDKy_Qfw#+pXVIDnVW0 zc-MYf$(Jf_jkoc-q}$y9u5xa3`Tv7^qYJK_AzO|_(dg#=4$efc;hE8|-?dsL-PP6{ z{bqXq8~1*-fL#9iPgay6rwQes%XnPBV(%sQE$)4%uEpAHHF8^WbrF_ca$0F;NyX2o zJpkSACRPuceGcb?;$2(Cu6Wz-#Hz8kSl)f6Vy7OJ{F&n+hCz1WyDpE>1KEY$3G9N+ zvdDohhG~L5=3rmUwPA7CYGCI|_xSz0(<|_H3hzY8R)^KS;y+cPILcsw{Po zODKOmxP~3~ji` z-#GY>IQZQqR{?}&UdjJFlf6qZ)uP`5dokrSx@Y(6nW;mloPE>F>38rKJNR5VEAr*+ zbuj0+a@1CLxMwfwnYC-X6KnRAwxdSBn->Aot`9lbm4bD$oI>q;I8vD*b9PbF}ERMzWai!gDo!BJ}N1-@IFW^H_pjwq*0E^vDm;BOiw3BNYkB ze+%%(T)FqpTyAUWc@nc|pT6ug$!~ob|MB~pgpP8j`2?#lXr&L9IE!{!5kyN)D}5m0 zO<%ve=?2}c4!71n&49bN&7f-Hul){hVmbx3jr7zF9{Qp*jH*FPjOAbk2LPDcXR&A4# zob$V=NIv5O%P%=rTu)05+P0BB8FYB+T^sL~zK)gR8J5m1K}{b(O=S&bb8mC7&ODoE zce!WfB1XRj+pfPR-M4{jdcDzMUK+ona zo70>7hBn_Yu)Om!UR~GKv*trRt1nxVKCgb$){*UfBmF&_(*q-YWbaA$UAbWMwvoOC z7t|M0IK6}>O4zh{Xov!~4UD9F`bKvw=^VUj^<{&?4G(%Y^$l$s=t*BcJYaD)G=Nl$ z6q8()8|qh!%1Z_ZHeS61`mS2j&~p_H5$0!}JN@+y=QlK7F%0Vm+D0LH^VTg(R$sPq zO%E^|Hk^OK5^{zbrg0`j%@;QJlco8Bf%C~ft#UAEbLX1#drpwO@k31mOFFMQ0aX2m z`WsBuHmo_X=c>-j&TCw?WW^;T*AJ(+_OuObOD`VXv}s_3yN!bRA31I8bKffsls~VmF{=5y1eQ&lB9~$V-<30i2=8gSD zE4;c;IzoDymn$a@8#Zn@KdM^Ofcl%8KQuc~!})Ck8`Zw6*DShh;Cj!T&J#6nW5Wh3 zC~)zFz)g*tHc8)%&YXWjt`BUw(6;CaxY&3>KO!wXJg=vrIWMS-hOXQ?vN=6?%?SyE zuKxc!49yLVmev^vIHBw}_MLATSroyEWVGRYYhYINZKUZ;YE%V{tfNN~dHqc{uCAb_p4A(A(jx-{%cpl3>BgafZQGX9XDktP z-{z6!myzi7{hZ7QUHg(HSfhseo;3qQkle5>y?o8$9{aGNXGPy|*GS*y^tLYh6lR*Y z>S^hpx1pHIog<@X%hrCFs~3fhqr$8^p$>C8C;lJTN4|-58fLB#LbteQ&87NRShxSj zv^SjZ+?~-ao39-mFwJ?Pmy4VqrFL7hl!i6cD6BwX<6N-ZcuxpT#Dnu*jggv}FgQW( z>#y&d!A#ND+kYoO(cgFehMX>-1k#1h%fj{(Texb&RY>hjm?UeBOE+)npI(`nvN-x1 z8X7M&g`WWK!VAu8n7N)O$h>LOh3DsLC^zhaeD6lxRu60%8Q3=HtLQDS6E{?L^@g4+ zhqi9$8(O|$$$2CPxb4Fl_uxdINIh3$3f460-%Lb`c^9l6xMu5h1GBOZlR1(e9bS+d zVQd@S(6hYf%{kN>3iR}ijPzX}B4c33W*l-qU=g~uH;HZ&_`>MSfJmLh$W}c3uC-Cy z=lips9ZeT3xN;!fGrX}UJvh4M>IEBi#1?Gadd)QhTad0TThjvzm{U2Ix^BGMQaUi$ zvuUL7ngKgpdo%yP2cXkKfEu?dWN|Zpf5)GOp!$o#DF)%;{&^NSjb}aFH)nzC2*J%K zMmAHqim7;f_s@b)u^kWh!CCP2hv4+dubIjn3c;N}3tTz`*D?#-&Jdgy9M4qlcnI!^ z5Zu|^gFfcMim_X{5C4QuzZ(7o=fdtY!YS4&eud#4Qbzal_|7M-$LG1{D)%QLINj<` zF-%=OeY=Q3+(O#_6m!sTF@G+EWYTjvslVSKxIVdfPh_}&3f7~hY;*9pwc{LKmByE=mJ7!C7& zhf5b<-_J$hQp9e}9HWEva9Rx$F1IcjH|42Z*$Q8eM;$&dFZ;n)Ug3~AI6z`rg`%sM zmjiEi^NcLNv3m#)m$BNf7@ z`NlB5)Ld5Vcx3_3)7KiocPsdw;l1cPn?FzAXCnCSIm^v^0;8YD_vr|}A?rjRedqA!@x2_uch3ccUwP(#9^bDb_&N~C zy#NWH^v>gZA7zB;i#5k$W?s}G^!UyKF5DhJ0N*oY6uu9H@U4m9JJ#yvNF(@GMeyyP zleaH*A$*^T;FDo8bEy%0pN!yp5qz>GqE9x|*Y_(CeD!Uy*nc=&y7>D3Wdz@?@5<|M zeF)z#qWG4$IaY_$j_nj-l2 zfp0bM{m;{-!&0@$7aB{IfAb`gs&-t?~fw*I+w;`W)9gA=;`}h z1YZmI?u1d|-$fyO4@dCbd1)+W=8q%z9*p4o5r@#-35@Wy@W*S@zx^_TZ+HcB%xWO_ z^Yr~Zf^R3^Sl9=Q@M*5o<2(N?h3(tADi$;I&k=kd1g@Yx=H=;Y4dEM&;=A0e;M;Wt_JwEu=lS=m2)@Kw z@tBru2_GVnqwhm>L_E&v$MDB!508wi$G0{D*NWq5=C&QIhua>3+XbBLh5vcD+aqxI z0C&F!;_BhP9f2GExNUzA>fxS^z}*AfIUXp4@2&L9roOHXo&oN~B5Ud!|3t-bp+qt@6FTK6~gyV9-qs9C-}_Vd<5S=MDRTdzGr|Dee!2L zeecBSRrOAC^z9pn#mu}t&-C;3y$!feg0kGJiecJe4c+e&t`sK$oP4D{}#cwAACD_FZvMe9KJ77iEw=@x4QX$ zVD$6&{tUQqee0^@vAcLLe27>MpUzee*Z1fRv6z|T2Sz`SuNSy5z8`>ZFYkq~mp@&h_vaCO-S3Bg5F&gV`1AOJ2)^MlHM&I{fywk zafeT1dXMjn@cyf#GXAj-%lgjxpKc8 z!58})w$163P0j^>P&I-Yfc z&-0AOrcSypj^OJDpWq}{*YoG=JLvFvyW0yss+RkyEd9nET)j=kh9cz(PJfdQ&Vj{t z0vG;yd|z;IzUc*bAF}IzqEEj+0WQp!H1)U-BscR8la#B+>D+rBa~o@XAQt-ydHv6q ztE(?l@7DjA*u~pytmX;QDp!0`nPGfQ?B@TMDjvF@$LG_r*BIy;8blAgG z{W>G>SH~W8Pf`e82_9jB>plF<;dvbSY~=p-P+F%J?Fywo&HZ2~{Wb18L+PiuZwjSf z;a+8V{95C#@rF-dK>8SE`?U7h{xFo@LHa-_{imew3Z)+*y)Tr0k@SvG`gc&;-cb6Z zq}2+(yqic%s(kv(q;>Dp50loj=6|Ke0}Q7> zkxy_}8taXuH$>9?k@TiWdN7if2a*4k#)k3Kh#H;kPiP! zW23QoGMN0-N0yKd|4L(@jID6*?ek=8HR-(8&x@@qct0=JOMSDSrrlg7n@{I!pTO9DFkN`=p-@ zz5hJv8hB%W^J0HOdVMJUMbi61>Axa^q^li|W6<|C(voS9@0+CW4!u7}dPgXI zgmfK$9{w@zp9{VJd(x_-fBz5M-x*5Fr_aZQ=EZ(YIxj`Z*c9oDe0Dq;#cc>RxL-2% zGU?lL4${2XYoyyl=~C{8Lg`buKLCvV&5I>T`~3o{zxLwzJpoF;hxB$2PWkUue*S#^ z-_iX^`SiJ@n?h;Dg?5C}&7`XtliJ_B*hfg;6?(sfbS(7#GSWW^y}z7vN9g@J(g#B6 zkCXmVSswpJ(tbU->a&^jts(fWq^m>liaYHJr9Vl!JCweebW6@5nitzc`q9w)Nz!+O z-v0sVvQYXDNe_k6e@6Phd2-?Jmr4K6Q2HyR>reF$=Ec5B`uF<;NVJQ71>Bl`d^!y{~mYiQWFZM5_kB8uYLi(Q2`=68E8A>bu zRbK89&WpW5`q|L?H%K>y-oJ&m)|kis=EY7UeSau@I_a{UUpX)KPSWc`>3O6ZL+SUC z{%4Pl`qYyCbtwHo(mO)%io@*>r5BQZCX`-8nkg^$OU9Ow*4&x>C1Wc{Gi1)C*O1ot zdhIV6`zYzfp>z-FkA>0$q(?*Pt4Z$;rLQIZhoQ9Me192A-$+{ig)eW6^fyB33~6%` zodHP3evkBbL+}3^>F&&Up)3$LAo^d zOhFo92>nW9IYj1ZDLq{HS4s~W{*}gZhRr-KEf_hfzbzOWO?6;?yye(ziM)Q2py;p4UY{paHaA}qGUg-Z`B>%4?>EA^1 zpW&M1Dub^oRugI>;p~W{*F@4Ejih`3KlZ)^JgOpV`*zYoI>sbMWYLH%w#X782_Ym1 z4j~I$fS81!h=!1aMZ#hTtBS~`O&evDK}Sc$T@f9IVHieHSrkz}6cv|G9S6`45l3Xy zK}3cBeXGvx+`b8fr27|`p`LWkeXCBLIUctXr_*~;}HvTUK z^F0}d@mgz35urYvZ1_?e&bHypZFsm1Uu(m+3Ff!uIKyo`X>l@QUCJl%+U~U%#;N zJ1td?^31&}{I(m1FSgtZYZ|%_6U_arap?Khyqokq!!0)c+XVAlY#hFrJZp1Td%`3D z%70Vb`K>h$Bb%m{CV=ieZ1_sS35q`%hYsTbM&lIY4#E6(5Qp*fbAri3c^?J1ry0Kp zW*;&RJ;gSbCWrhTZTM0f9%{p*Y`Es#sKZ}ibAQl=pS0oCg88j74&(i8HusNgc!yxV zlj87&u@xs5VfZaE&gf-aE|~jOAz17l$u&FA3(ixHx=a`$6!_kP(NGXq+^` z{ALzs^fN9I+)3g7Mqk1F1{P-wFvbYx%tV}#YuqZht-=G1Cj@^F+y-Bqo)ZkH@@u`# zeVgDxia*bYVkW`l;MWG@+awz<63lNqaTxC|5X^5gZ7|+V;KUoua{S^j-tBF}R|w{} zk~SErMamQx%W)fg!B{Vt-zwsa5yp>#IWCFA7ldTgOVcpu(So@TFb-b?o)FBr|2WL( zZxzhB`#6kb_6p{Hx;V_JUm$aMoI8)hczC2>&V9GRczCs7?nR3;CK|@EZrlQ2t;M>b z*lty)+{SIPDjwFj)%8%J>$It*W#eQTTJa96M|Bv9l&wS(5@37@U)n+iy^|l_5DPK*PfP?2Li^ z2KBMBBz3d0G*+u;_vuzB? zlIBW6K#E(%bV<}&kc$hL^RLV+9E=<)DCjqMkX>S04R3z-pzNX8l30+PUzD9+JS0Ci zK&nKYQuA^%uI!zWIiNUeNPb2krRHZ3%;-1BmRemTIp`%9u^Cj5U5}6CE;etsu|utDMacuWlougqh%S(iH>!|Le({$p7lotufRj=7m# z_z$~7b2F3GlltG4kJ!qRo0-Oc-S{t+|I+y{NwIUMB%ZZ@#hawOB`L-vcLDqmfdoUV$$tCG-FaduUbyDI*!T8{FS zs-$s~D$-8*N>y@FmETn5D^>YQRlZWSFD0{^;_RmUc2oS_l(cTjS2rcCoATRD`AyTD zN)?mEUyb zH(mKnN>rYc5|!_yMCCmxu?w5vnhhmt^Ds9j@?A1Hvn#ec_;+v7%D-o;uKiNVU!6>@U@^YiugW^C-@p0JwtLwd!;(Z$oS ze^76jNy?o#I{&k|722I&BPbH`$R`=GOn@`_8!Cl@Crrxllu zEHyF*W@Hv;7G6<2p?sPK{jj%0Kk40*`Wf4Ska2!)Y_VYqVC#7bi%$i%e^gGKR$Ng& zVRY3Po%tvZmNY`Ph>GT3>->yCS;Zq~RFzMzldU0}t*gdjLrF$Wp+#{H5Y#d!lV zvE4ndpg_A|KP7id9xa%9c6HaKS>Rso8jhr{ql;CPCnChrV<(iW{=fjFcxu;@QAx>t z%B!-vz4cqgP~uUhH$m5#O@W)hC4rLB&i6&Zs?$f{R&ds^@sr4? zJD}-(%co~gD8+tAy^pLWnl&Zpm^O$9c;tx!NnHxct8ywQj@SEK>)L)6s4qRG72&`I z9#U|Ggp-Zt0f9-H%J%YFPDkEU9>6-WWX4P;0d|I?XyI>cpmt_$3fyWQAVOGbZ7^rv zstVk@-(c4JVq`+`$SI?YvgEOOaB zKB*WIYiyKg#cC7d4^ur*i&CBzp=xSfiq~v)M+01<8u=1?BX1_dG3<7)D~My+<6f7) zW7yeVm$zfs&tA*hG45io<&X76?<=p%Nj8($h9m64)OMV z>F8|W1;Szu7w-G7yU(NR?=kIDr>LX$m2|(O9;RA-2q|<&+jd?PvVWKN3AouDS|UU3 zTg+?QN(vn3E!z#Y+Cq?v_Hk1c=WXBVgua2{H%#G~&c%A@H z5?Vv{o(K3p+K%%8MhU29pLt!b_3SRM%S(gyltX~os)TGed4N(!-$RZ$Retphd&e;N zDIxM*z4j@5o8DjO%9njR@9Fd1obMaPmEd!Jpx0l9eaLk`+CM){(Lbkf!#|S!Lm%TC z8TmiKel_9alq~u9^^trTbO&EQQt*`tJsXsIaXk?EIcM(thhdbGZpS(b(j9ua2KgwT zeD{m{2GX54$_#V$mkP-G+grGMrx`E(~{%{yxum3>AG|Al-q>u}HUrS@gM(6zRen8=YSv zeL!7>NPl94bBnm&EB4F8ekirZfVzXeJ@Ub5iAQai4DAm62uZd|wELgAb*_V*HF3Encnn@PVl zjDxhl3UVa9Ixzi)qr3_pLHZrOb&-B=7~j(UYQ%}@g7D4+W&B!zy0C4wna>8#l)O#}H@dMUU3;thFS26OP_V9m@c!Z80vD(Lf0Qp9}k?ty9I}L+tGM!kD z%yn^2cv9u&C+ruczQ~Vs>RVzM{Ymo;V=(O@k86URsK+-5zL^w-^Y^4Xunr2;H4^JJ zNa62A+QZ*AQuzC);D3?AAJc*P-j(T4Y8ctX;O`I0x^+1z(#c+*Iv}1*k3TWqs2^)c zkqDoYqJD7M1>>7ax)bY@NTJ^r((QWv9cfeQf%x)UDeFfUP}Yx3V(2km+*v;u&O@XK zXA3F9`H~dja1SoS;o4A!vziq0w+P)wig0*fE5qqZiu#oa%J7B|BfROP;5$ePx!qYG zAg561RH2WMg6|)oVPBx#ZK7!=DDB4xtrmJ0DAVgXP=@z9?GfHb#AtW+2>zKA`4NS0 z(WLQ0`;bCku8m-Qew7q@aSs>Ug9D`CPeudI_MkT?+k^3>NRLIN;9pJ(zLy2>7J7pV z_K>@j6nuXrh1?It{(DmRb4F^)GcK7vZ;^ukYoTZ11w_nqA(;+5kCExKL-6;ckP{ZA z_2eEF>e)eXcfq4cA^$E?$XiDWdEB!>Jwy-$M$y6{HA%iQrEKpMh_ubRR+r z_nS$f_alPeAccNS%r%GPzl{{};+ncJ)cyAaN2C2+eJ@bP za{wsI|4?F-f9_SK{baGfN$j5>MgF`kbO$KQ<=MzTYyWQ=uxkv`llh8x+)F$b?{~p3 zkRr4HMe1}ID6YzXD^T{=&Ie^aEvGy9kaUW#Df6?5K3BsD&=1&kE%wjS9^u?Tiu6_G z6z)&aeVk#e6!#CseJ?5E_p?yGpIjB_CorEO=K@g1>s*A(cwGQWz4EAs%V7*BMd!u` z>KZToSomZ7Tocg#(;XODZ@4C+914b5B@aojhQ$2k~(CT-y`o+oYTQ0qXQtsKTqVApkM&q+~k56~UqM<4<$x2%uEs$YO|+ZWhX zsr$|3zee0A3IDBvt4YECFsN%X@>lFt{|EX0HSJL@_KUqc9Q=r63Mt$Ng0fr`5hMJ0 z;=Y&^<>FDHD?wdVhOvPde6N!tejm_&3i{JxABp84>pl3AiBX<<3(f^)d18LE zJhcX8c|uW9_31X!?dacuvi)62jLcxallAp9rW^F{DYT4q2ih%A7b@EvVubrJDb8{D zf)wS1~CgzAbyL4s`Q(Vew3t>y&k6{eAf&a??FEGbj`%Nb?OKF7V-7y z9|``J_y&Y2`k?5j{(Bq2$;3D6b3Y6`cMzo9E@{CF71C-_vmcWX_%2Uf%7)$Ic1K(ygnXiG0ND%6wiX%c=O!-vojVn3Y} z^>#Ta+Ru%2uQrT##r;E2_Uq9tQu>_*O8uxW>;2yt?(K&08Ysh2dfkEZvIL{*8ZNw? zJBd8@16;pFx(jA|;JOpTPew`cf|xGW9;$DdS9}|94`KBCqPtousHI+epD5Nx9oG-Y12&p1H*ZblbK8lXv`W^bCw8wkpO_l%V z`=$%+p>Gx`hrIik!lDhcXWn->v6Qh&gZI zLS#7~Li`aa3b*RNBJlADknQ;$pq!sk?>$fl%O~<(&2MbSJRLFG`$|&i^AITCD{B7e zu%18Sd*z>WPe8m_UU#6MN*eAk%1BX9xd)H&;9fe{@1Ykl^m-384CkAnn5y`h{SBr! z!~0O^*QA&nIi2xlIa3_zK2K;kRm?lQX8CSR{c%H{}y1zJ5Kag^Q+*yPVmd5;ESRD;Oj@) z#bHb%MZT*11^=_e$XB}_B@7q-@k&4J7kkdrx$ZLz z^?m~1U9`uf+b5*ZKTgU=Dri`WL+#b2o>v1iJ#VEu@S~*EgB0QOtT58%h%eizcu zwxH}Mpi5x5{!lZ|yG-n#LHu3!qu&ThyBd-hYSj4R;t()D!JVXHw*M zCMgB^pI|sd23+x{siV8SGpe-_Yo|Iz^XjLoqG<650C^F-2-^HH$ILXgF zJ>(xk3jWz*|1>GmeJv^S;|;<8EBI@{hlEC;!6EQpsuBuk0OR%5!46m;BQFbZ-h|Q z@7-aj{py?_SwVZWhkHTU9v&iw|71jj?!8IjeiJC&?;wV|n*V~F&BREbkLZr}agVt3 zjy9%C6zenGdG{J=uFz{iT@M+?Ok&8}M*11rRjJ3E?{Yni{s%GKIlo1B&TlcC--`X8 zNOz%qr2Qiphl@Si1GdX*9v=R=ADrnmNb3DWQl!g5Qt0&uQt0~+QpoF#`b__Ytk>}0 z9QkH#ciRB7-DSCSJu2@d@GTa5yjl&{V<;z}^soAf;n*unjP~_QQk2hf<}2exx*h#B z!QTiT5U$Z3ip4}9qr&j zVz_r?KEgds+UXonzV~uL*}e^@J^03o`wXE-hJb$a9AM^~+1{D$kJ*1~!+e7~`~Rfs zdtVRCixMMzo^?ywD;yN@=blc+{}ocy^Zlf74`)6hy<Z$ktS)i^b z@SY?^nYskj*}-9SBYsk^1E76Bu`i(gQ+j@p_T^%aqHegBNqL6-&0_DP{nPq91M;IQ zq2wb-!?j$0Z=}8IA0ph1w0{QgJyO`Kb{h7Gs^NN8f0w1bnooxPPqhCd+I`s3{tW!6 zKc*-R*9y$%ihX;rM-myXKk4~3@~iI-;2%u;m6(qt#jgZE${9!eXTATP_BV<>`>QSt zM%iDa{qM#85#qmKK0)mNBKDjYajix>Bld5L{l~;~l+YXm9E#%-i1q(~~&-#`&j z-wV*SG{VrwV81x*bhK}z5VD!{4E_BlEE@G2vch8YI4vv|@`%sW-=)LiFdu>f7luN1 z1!*&k|47e9y(MjKs58pLS|Cv964ny>k+#z9QP?@CpTy_tbq!(hSO-CT9{8YhSZjn! zdOprvCv_XfR?-U~5A8=-8WM9KHfu${98_XIod6(qSp72Vby!5iJfr;MQXRMiRs-^-0q~V z=}FyEyCx4;ff6&bdESH$}5 zv95hFt5co>k8}O5mNBafBg0+$Tw8r99*Bt8=ufW#?598il}YlHwKs6{5pIvtNoV9@ zrvk3hDMYFmc@-ryGI06SwDK||ue@^d*vVBU%rD2vbrXmm^Cm%DzfyuLO|Wr^0!HHU zk=icGe@R6_c_s31NM(gFxO{x3szU|1{|VPs^(!+9%1ftkYg2Cd)ba{LZ=&dzWfaVq zTva|E4~3Oe%8eXej%Z*}a(T&k203`ts0wVtFmjWO++-uSiy^ygb!y_g#WK$}U#=$w zbs!#fz>ReEcq=^ZP>d5TMb&qvFT>e>>)Zn|F$;FUZ_Mi6NbBzFzi7#nJ`l5dX4v{K zB4SqOhr15Awt91%zVw*YLr;rYJ<+-T|5~o!8SC1E=O*j_4?H(Db?tE-^cF=Z9vAE* zEIg5#=XA{z<%9d>XT+?Y5yh||=OCV=RapIETnAmR_f+MkD0Wj5V@jJ%O&qFRp(4g3 z25#iO$A{P;mI)gdsd|%z(j}!$%APK3EP5)!N$b8^H);`};=^mgI3nLYD*awY+9e?E ztm%a$OoIZw5O|iq9YNZrK%>6iCYy4c4qvvjW41AW-K#lhhVk(rhfNmE=RB07E07jFEahhYYlw6flN6ap-vahUsv^y@LW$J+FP`=-nZIs?RbNyF#Xk-TOL4QK1BAF_V1;CGxaKHS?Ku2 z`%A|PPhr*h^vdX}#-o|Xn=36jJV2wC=|8H3K|9d?ms$xkdsZ`JO6Qo>InFOj(bkMw zH2-i_3ndVOZqPDSbgG-Bk=I)kRrNM=PZhH-JF|UK?flJ$XG2GLNtjlFyh>n5rXt=~ zs0XAbq$76B&#GoB3<9|bq`DFet@}YT!I#EgMHsL$)>~y0l*_Y(4Z0Wns>8*_ST^Hf4 zbo;K0@>Y6${bIfS+xhxOrT356)VrCZ$^{=f;@3!PtjhoA$bZJpgKTy4U24gH=KAb3 zqpFEY=nhA!NdYfTRZo4rR1wXIO3#U?I>(>l0gQ}i-4dChUoB&tRry4bV;QyR#p246 z$&$p<>75$uo!X3vS>=h>86MTtyQTdvNUnJA?z!t6RXyh(h@Eyt`dd|J;hnC^8;X>a zjdrMpo5GAb%eF2bT2EanbO64hX2^&5ubxryHLH5Uv`cD=k7o34ARmj5x2Tz8D}wSi z`Lc>75AnB3)Qn$o7~(gz-p7S#6?->J-&z%q>ekX1*M7sz2WNwQ+SzP7AWla~cQmF_ zzQv+;|D}5F3cSeuTyy!&qz26nKw|D&w{=Ge@57_G?K_H_wGi0DvlbV-o3&us z-K<5>?q)5lb~kIWw!2v?fZZ*is+4&=SJkwmh`BOfvde3NI_M%XzIe|@qfcgLcXvD7 zY1iJJ(y5#Ov}ec6e8X`=gyY;Or}I|S9XI4~JVbLX|7AtH`_2tt5EeEta?{3WXCI8) z+QGUP-C&CN4|m7U4I3Qou8hR3=U~b{Jy$7P5-~4F)z<*4)1z||KSt{LfPA`qz2u3qZ77Lp1`7bLvPwRI}c;ES9VZ$U)Gp+ee znPw3Gndvu9(mJaqt=(|`PrxHu-JrJ=l#wM zBqO4H_Yt4r0oVN7@W4d>7z@Jq%I({`NJR6k5%2HbJl1K8xl^x_fuvMhYPj>4B~;p6-0 zNZ}S*`1pJzzTpG;HU|7ft|kBtA}bF&(UYo2A{QKT{sR zN2qY6O`Qa+-n(RiVS7u{1wTx+`b`=p<`RLJACdS`9>W`opH<#=VD*j$r7`6d;Mpo~ z4CFCxl*e}6ls6gAlt+6SzW;92kLo}9=)ORxnSSeFsowXBt0vqzz}9dVAzU}?C?C`9 z{&1hdGv%7{+(@6kz@{W2^pjM5U{5)<$Z@|t9~n> zpP9~Q!Oct;EL{oEkKc<`UxUJ6OnK^ir?yi6w_D`lbAeyp6uUgUa8-Xq{F?Hv1D{pD z*bZ332_D8@J~yax!0-O}^QYek%ce*9izznefHRZvMW+^Aebf(pl;_6Jl*e@%^lp}`b&*IH*qO$Z_oPi; zVuJ3gQC=JTOnH027Y%H-8~ach>1G=9d6!LI1R5M9wbIW6YRcpKEUSK8kZbnkDAUxB z`wXn<7i*E%)*_GlFIi7b{dhjPsT1Xy&q-jg%4=zn*Ulo3`#7mzIKroig*;OyV#bLk z!zRxSdE{gIA#42c9WCjA@f}FF0eP> z(@ZCZY4L72+XSA6ZOQ}N5lwi2=9GuRZZY8jDNT2llo}Hr&{Lp0Thtm8u69dUFBd8t;pSDjmOE-(##mqu%Ugmv5Z}e1vn}`~U=H_9 z_dURz8Za@}3G*Fk;!b#GSSB8b=LietcldpfVY=T2{GkQ&d;2;Iei!&j3qB0I$b#FW zFif}L;lLv-n0F)hwctMkvksWye+0~D6CVPmF|kJaKksO2BZZ1>UYKghYB<8N3UiRS zv&{)pt1_+b3C2uop+w8ayMk*>oZ8pK{+u?^h8OPC*TlC2vk$6GoLX1P_Qk~fE}vpT zoEC9Ea4!qyKFGlq`~)!jh}y)db<9&t2>;wqb%zD70bXjsTrc-$3w{}Ry#>Dx{JI5m zU&gx@{66r97R>drpIY!v;N2F?_0=pt+Qb=qfxj~$^!*;Vre6|g90dN+;_h#-l^t&R zG8-y|!E7;sU)NcGrEmz(|NlD*qAl7m{5Tu-*l@&*ak`m|E(80p47CGQ+qChqJLwn2OSg3bTSHoVKm|D)hR%0GH`jXG!=lL0uk z=F~yc=IPp}4x0WiJZQR(i7E4#-QvkpMiyHSnXZEuhYjlkfqCq(Iz?EW2&_&L*2f{! zK_5ZPCpkozk8;4YK0#P{O;XSB~+ssaEUUKKo3zzxAs3SmS^MI@a0l+MbSK zQaivCQz!Enrn2FwR{90=|0 z;WXk<9W06WCWo+L`Gy*OMHa}}Xy{~Tz}`7T)Em!`^kVp09DD1B2zQO3sC#lygYju^q#pds|Q!x@??VBev^#5%?MIBv9uyvgW#2 z&T<+dXLvwQjt40JZt|64uL!Bh2h8yp{r4q>{b*9e<5p70;hJE^=WO_6yiIwDz^?Xs z{6PKY5O*+)J3;Hxw=3;O>+u)ESxEklve$Wx>~)47yU91Ab~<;VJ@m>Vts{NoV9zzw z=g=J;RJULxp~CFV(mhph55YjVAw19rk5UJMr!^=eYsmy7*G;?A}`0^s-29);$2!hgT; zKS7*i+amz}jkHg;?Gb?eKWLA_@Fgk2{TC?p`H48iwnqT=YL5U4-v!_$e|!AMul5L_ zFz^fx+N(VRuvdEo5b1zD0vmw<1UF5rDngBhcNpM*#L}kHDq2 zJp!;-djwD@1NI2OUhNU+iTM{aJk(R|5rDngBXF5*j{xjx9BuSG9oO(H?9uI&1BE(@ z?wAa7gL01m%YPUO!z5Ct9-DBlz*=IAFIdjF&oUNahecq{kJP2l`rzJydBj){z$F^o zJMamqYOFw^M*_m&n*3g*ZL#)!V(B<6ZFifdzBTU2-MS`g-ul|n+mff{%DJ15O_0Dz`i~v z9`^jva16?I9s}lv4_**9k;`M08;Z0tD5}amm+NQ7D`(|CTsy1vEdDhb`Fe#0W#3Sb z`ya%;J*l}KWT^HZ3#+x_&T_9zkn1z_I5{O3#TZ?>sh02P=mS|CvySH2Eu-|hDPt>n z9DU7q_(1>N^2;mAOC}$UrAuKYZvv2o9CdcyJC#lxKfZiImC*^i4$3=W#nUDD++R9Q z2U|V{2gsM;(uD>XzW>j(@UyO=Sy26h7*N(5{!sN*-9r^SGyq2(|eza%$QNP9bS>+Mb zC69Vr<&Ch&<9aSr-d}C<5+ScW>`Y_E_s_7f%A0PH$L8OZ_YR(werW$`_+ItbMPRzo z?8T4Ii3Bj^0A^UkbmQ*_p&-ieTd~!ckl!BoEWsMn0shCrNd0KA4KyGgix3a$z;uqo z&x{Alyjk|}Xkh~rcqF+|qUIMh7zT|>J#Y&z_~ z2Qie^%LJgrIW~NyU{hX&VAk0-#?Y zY&5JxaY*mhmW)-Y6WHvlcS>=cZMiugWxMuCU1~H57x$ExlogMkQdK^^mT_zW#t%!PvlKW<~>YS{@Nle@3BBZ?B&@su)NR$d8bUMgInHhft*#9GZZV+ zjr&nqry>E)2X&%ovF&%F(z2A%y@j}6M0-@|OGx2~^^@*wKj~kM8CxB}9xuE)`7wZZ zQx5X87b%!VkfKu0CPhVGN{W}sI#RR)xOL0g^>x?R_f1Mm!!A#n`uo0RR1${oW4=|- zL~FyM#&%|CQDzz6CstGasOROM4j=aZ!IJ<@y{kNlAgZe?8#&p)8{V~^6gn^Wq=Bez zF{p33rx!@|4cOw*!{ck>o#%-sp6BTcg5~;AzImQ3{irun&HW{O4HcZ$)Hm;G3a-A3 z|J6<*%kBx^VkOAeBz?mak58-S)2jKjCJ36EK>Hpb8xR^drhT)nz(1LFKKRL>bQIS&a$JzMZKb`7kBmH>Q5}z8&|+GhD`(dYbXI_lcH5-g>_@ts5c3 zH^U^3LS^MT5z0JTpNQv(ET;!ClvAGxM~;|$lEH5Fbo0`Ar-qUk3Y;PQ!8=o@T>0+i*aihZ&PuFtjkUZzpxx zrR8gIz0FU9Ix5&1j*+M3e#)tnCrrY3rYW5+Mk7Y7bwrBaFe2d^QaTl8369F6DCcma`SRR_eE3Oqi~Rb-azlZXtJMY zO!;&g=m(^EH%&Xk$L7TF zrN+Eel@sROH+OeQkJDmqSp%WfIZv(M;q*;&y4GJhEh1*#C*Zp^dhRQZxqY0DODh<* z7i`$YS>?-U7PGq981G*1+m5|+zf8o0UCQhqT`>!$W7}8Ei?84OqY5(D(+*K_Pdl?F z(A+^`v=W_5X8(9v%z{hdiOPEqLUudvH{SQ4cA^8_ky!R#z%N@12M))~dlwO%zwSB2&4|g~>ew1H=R;+K4ptf- z*wIpDCT9MRKt67)PHF#s)w$dkC%a8=&GjTGl^C%E2hMDG4Zb+rZ$N$SM>S_ITVU7v z+)a-5TX8@}i=MN=5Od2%WJ9E|BUcGw04OGDNPDKcx2boU(>pXGX8!C$=p*j0UVAY- z7~WsLycj9B$onJs(~xXikn&${0*h_0ZlH3|D;M4lui-x^7U&8!7<5W_p(ht{OZ)N+ zaA|o;S-9s;dkuSgbL;o|4pqV4TZz?|7eN#i7gM`_yo`txq9o+`Vtvz{?LUA5Exo^Z zzjge=jm^8UwHZ5@xqrE;I;sPexO1>sc|X9&8FTs`DM_tL{&FXZ~UDpxElC z8PX=4gxd{eDIS}oaezit3*W3}-pzA&#H`=#oVz^+HRd!N;W!kwcs#?nHEXDYVz6O) z$`%x`9^QRYz|8n3OuIn#Hml6ScICi5%_DTWisM&1juzhv&lQZX<7>5pd$;#n9YMX1 zJLVQI{02s~84^_Tzb3v=;0nZfT|k^O8D}X8FHr|@#j99G#nvDHOA9?$G&24Jju3w& zCeN5igkEVXab#%oJe6Y$f|TfmvX_Nyk3uPRa^gxxCaBiFrm#C-@glvE1Lu349#~yS zD^OJ@Hf4D_>Twfddp??z1aA{OUC5(6SZ^;*f13wROl4ksI&R8Ae&((5xs;8H74x1p4!Ak#=?I&w~RJS$9nR**UZ6&pr^VdOY-x)%vR; z5cKDCqF?n`?v+=nH}kcC^676w`IcJsY953UWz?wbM!+7Ztj-59RZdJw?vm0qwOd+x zM(@n5?3|+x!~F9+_HkGtbmF_6hUffpPJezF_GI1?o)I0pz?l)1;qbG$II3lB) zVXtg##-`|~j8`$^|4Oto>-3Rz*!IPkjbnf+3WeFte|5{v3tL==0PJ|B|5fw{bAbPj z0#-WI=e?osqBdiwHN?l8@sCnrHbB`+ED%6~6g3e9YG@ z;bXQd6XX~a>yD1Hvr`XAyOku5EJlZf8#5=@_4T6L$m9}}p(<7PPx_51DCsvQJG(A^ z`&Gepd=N=W>NlaPa3T)p!O1+?+<$7>T&dMcN*;oqq@M?yJ#|ce)sZo#iUMXhQ-Img zVnySReJ}plXJyuz<4%?>t050fJN(GUYCv-&zD{ssIQ8*$0T1O_$HjesO~Y{M-dm{2 zHy4;qqiM*)-w>f@JQe|~Itxmp+8)r$@w1MfXQKl=8+J^SruZ>j>TiypO?fL2q1~`I zjVZ4Z7FKy&yuh@gJldP`9>+8FH03RY!vSE^nDQQmg;icVi#$|Gzr5G*93T(l3ssjz zpegSan>^m@ln6WO$8WRp(((W6EP1SoNE2k;k#3DK84bC@%~@8r~1Y zF}i8!M$=6A%=rhNzv*v7;BNBq+Yg_qJ55LMnK}{EjlXo^qaDqq%v6gZ4-NNw@Y&R_ z2l&i$0_e_o(DVb7HNGn>@x?T*Kfa8cS?1}F=kpCU0|Pc6tznYy05V}IlxT%#&Ji0jw zjE??iKAh&yKW*K_=!%D$ENY_GuGP#+n6*W7hkpLUE+3g|G2#B6ff@eU>i$t8wk`aI zQ)J;tT zrFdX*S$PSL6D%#M!pRO(d82&&YepwbBVTQC_Vu;)PhUsv&iKFG*^;>?#`dmDajjV} z%OqIM1lg#Pu@#sLD=n$8h_ZKaP_xmN;-$hCBod9;J)q(Em~{rq1L+`87aFx|K%MBE z%p^udUnuxrr15x1pbRaNW<8usLSm+s)(CwzQ2GCph(7$3IJ;caCNB3@8xj_+c9zY5QBJt{vO z%PAN9%P1H8Zc>Nd6Ugs%YlzYKA0S0!+;HP}I?ju8t=qJzrIn?YFLw3K4JM~09`oEF z=eB9sM`Z7X^%lYU=b|x{hXGbIjP7DBL%;clIVziVzT<vy-DyTO5DJCoM? z=J_ZnXy@uP{o5Lb{rRuwt#?kibdKwP z+h(5e$yDcA5x>>LDW;}BBCpXT#{=rFGMqN|2ef5R+41Id%A8xOH=(p*MM*ObFx{H0j zzwf#u|EI_1{NJv!1y@|v@x^a)_B@w5;;FyheB+ou&%31aGhGt*KDDR$Gml<UfZM7+M`wWy{~-#vZB>Y^LQ zE;{?VPph|0`S|a5jjLFfKk+ZS&Kw!`)7DWhbAL?!SLj$3-2k-?R9O^Hy!oGp2m*ZJYY#WtaZ& z^`+xhe0ST_>wXxLmwa&N!0!$f?_0ZR_t!UWNP6S4w-&sA_>H*>*1VT;-;B4vexds( z!in<2 z4cPnd5#ygZ@WG^tpWktJ+*#gp&#txSKK0e2-4AC!_UXj?%Rahx z%Y`rhee2G3&ixN<`SVvJUYk{Y*$b~NI{dfT)oWKh@$`)=9{#EOvuE%6Y1#j*Tl2*A zf1mNlrV*+4U3cRT4?cO-syolmnX=@Z=E=7{bNY9;Rb8^;=8cKh&Hw$Pg;#f~9&qIk zPe&B?TK!sH_O9Cpef!hk{vH1w)#nfEwq#y#r`@nEuWC zRNR&5Eb(0OO8J)q?mP3EqG4y>GO1O|#PJ`-ckTIL*c|sYO|EKk-s%55_mh~*AHS>H zuIKZ+{O0~MFS~X2*6!6?@Ah=xQsn;ZtFtdD+`p~;jJ8j`^5&&u*0(sX_g%QB<<~p+p7+9I`<5*&`+o9*i+_Ci zzFoh#ep%yvar=zw(VM!@-um%R^WO8Vy?5l28y|Rn#btLzJ#+Z(KgF*2W0Nzkd-@+8 zlOG?G`rX6hN3B}>(e+c-gkPQdmsP!f_>_cPad z{YK36Y{E>>tI^H`IQJzF%oY4+;|&`SY2nT|o&Bci#uQYg<1w-=sOzJt}}VW+UIZ!QM@NWK1q8 zGWiBll$X(!<>eEKODo1=)j7M)_4S#%B&Wy*kNUr-uPsL)FlL`Q2HHUd|6In9p)a`s z13!X4>e+^`f~pVg-Gq-ISKuQ^^>WW_Fe*z}RlrI!$br(;^E`{;?ziR#npGZ7x69`( z{XLY@@Es+BZIAkzDq`@d=d#1Jkl>W;x!*XZyh(01xhwGPHG$u6Qj{a?o!{=*9d4dz zZR4w6>-ikM{H&Qh-+lH7tbU%Ko-cf_KAxW0<961^)3o|fa(z4x{r<;C>f^aI#`k1> zJTsPTTW<0sy@M}wiQf0CqgEq3o<#KV5gQj4I5y+^b~|JZ5?Fr$_u+vF$f96o8Ncg0 ze)P&=-g6IyPx-6L3>;JqPJTC22_=$|9r_gX9&%{24iE}Nfjt7>-)atc_B+MGmv)9k z>%|N72El8o4t(SBfPQqEw&vN;!c>JXb4Qo8wMG^vc^L=DQnod+6s$)UqN1ZCF@>%= zY_Ye-!&KZ%1qAA?2~EYx^vy)7I~9(L<|k?nAVpb_8(FS`%MbWgMW^oE6sMz>!-kX{ z$$^mM{_#w;P{u=Ldjsm<@eKPUENdrRdwZ(fn(x1p<(+k0+Q^WU+u$@mRZ@d5ssAZy z7+gH$ofVQYed_&(4)-zi(?gj~!R0=D%do&dF!COs5ra=_f(>Oq>!DL3Y&b&1FeL?# zTqupl9(d%)8avpiIM8m5=nLqdB)54u%K#POJ0#dJ89U&mj$UzDt z1jIEzKq^A>JY2B=#F)U1>kWYz6JHj_+*%SIQ}9SuJodmN`M|C^^;&13Pv8q~)C*|4 zM$`+QdclF*c+B!H)*9WWR6)jUqr+{U548`4vT&i)JY@qPxp<^-Jf`7sJNfj;TBR1p zaxA!1 zgKwqzsfnVHPZR~0F`?{m1g}X$ngoQ#cMc<<8nWXzy=E3}Q z+Jb15Pvw9)08>>0RRJlY@};KxsNm6G=t1NF`Y!a14vFe1>0YAhLg`+j>La0Z1U{vr zu+P)|OWoUooAeYZ14wld7n{8;)svF0r@v3B`c%57MY%rR)B0IIvMVMXOV#PpTCuAn zeb?>elRng9Gq_K*J5`l5i-H{050hT$Jl*+{j;Zvxq;D#nF6o}?eiyW2SCG;~!FBqP z3bONQ<`z0+c&wd=-rIB^c(LmLnq4%}?ue7l5EVp@HncS`6*pVKhPB7R=?dQ`X~(Fc zsVwci%K9UfmS3lQNKHO9L_GP2h%8h-4ijr${(*x+G*jErOsRqe<|BUcJaJ0r$=f2F zs#pIpQ!gQ_S18S@Q_$#l>q+`{JXII|W9ou>zXVJ}N;g-p96Hi8q!j!Ah(4~o9c3uO zp1$gy>(QFBtr@K;XufID(ZhfxV3E|Rn(-f8GgNCG>;!!%OWVoYn_?fqlkTBvaDpqlp=@GK-jaOc zG;a+}!xJa>PqhZ8S_A9;qlT8`6Q>TMPMxF^md7*ACI9}*hpxvn2ZHO(g|hyIvMe0W z6b)rOj%TY9%6K$1KTez;ilo8`Fmh^W8irDHkrk458ht*lzsDks-5~f#z}4{k^dlEA zeXk$6WM3v$xMW`~kjL_JJg(3TTxGvXKXR4*8vV#s_G(z}Ulji{9sG;p)q?)p)S`G; z%G!9fOTfQ2UTqYRwehl^N~;3V>$EUx1Ed!DYlVO|Yd7iy#5Ga~focJ%$qTI+kgU_E zW^I(^w{AnWwiiZHz>UQO5OCHt~YpX;;&*XgsgLhvVA1?mN~T_ft{(@V~n zop|hZZ0q#15X^_#2bb(qI6QO7{&qZaKRs%#$}zp;9#YrQLC=Vpv)GN9*=BUOUKa9I z*6OcM%C_d~lY&S2`eZ6+evke&SG*$Z5X@d356wea@q^2OP&Q}5yp`rL2YI%^jR3CsV2grz?D`_Sv>tqM;cd%B*W>*e6p~OFEtEQUozY(unf$>xOnR zHPS!q}*D(yeMOjVe`j;H;BdgwT3wO?? z`}^6llee)4&FIa*lm@MMF3fWM$j!iOs7_rAAy?30v6`bdw|9y@C*4BGhPE#!YMXAp z+KqAE|YQlCf}}jY?N@g)t8$Rvu(Kj{hqR>{TVc9Rj~`7%8UEGWA)e#E+dMydU08T-S#+}u z+ui2+u9)GH;^XBCeyEnqqFJxXMe(2ZsUetb^E zk7f<{V)di?PdEO?3RRZ)w;6m^W6HY`mVB0A6<>vg(J9X}K&>|_t(v97Wq$DHB=SYz zXTKXN1$Xh>0(;Y#;abC_TeC5Su@#oQZ_Jd(cri>f&+uq`j)<|{H;pOJ#C1{L4P`a8 z?}7@H67Ek8?JGP$1L|X@is{an*BIXAY&GGCkr@KZ2=98b`iKi_YT!CmzhS&n{79$s zZ)~`a4PS1&2K2*dcPL&bib<(?b^D ztg82*;>^M;iYJs$Gw?We!q_U(ipgWfj#5u0Wo51m7Zfh2VDu?-hI|E+eG>1XB1PEO@%$`vm_{@Ed}^7u*8Z zx6yw`Quyy9c%Y|C zPl7)Z{EOf-QK#tt5>ogt5r_vpVp zDR7qH(SolRe7E3rfB0LQ%La}DtH2E zbM(>0e!1AcC-{Ki3*eXjvPki}LU5JfI|Q#3yhZRn!L1Mm{r4b+-B7_Z1>Y`snc!Ch z?-qP!3++FJ6#fSbt`uA?c!l8q75uZ{*p}LV0xA3t5j9hyFW|!hajL#+Q)-j~2X8@MD5E z3;s-SlM6Ke1*DLdCAe7d9Kka$)b2}2A^%T;w+a46aGXcGUqT9bd4k6YzFly2TkXDr z6!P8>yjO78#oE0!DcsWq4;MUN@RNd{Xs`KSCk6j^f}3~HIEfVc6bhaw_)fvk2;M6A zbHPSO?Y})K{O1ZDEqI~e#{_Q{{F&e;3EKY!q)cDI#e(MuzF+V3rV3@uHcD+7YcqxaBLUN--Q(Xg9KkE_+G&;2!31e*Mgg;X#eS?@Lwo+ zn&72^Hwyk#u%oNyKby1}`jdil1y2-wkKpG8x9+C-Gf2&yhiZHg7*t< z)l>UVA%*{;f@ceUMDSk)zbkmJ;4?4N{=1XH|J8yQ2!2ZN%YwfU{FC4o7(g<TuM_;4;2#8^m9OP=B88mG1y=~ZL+~SlUlP1q@aYBGe+nu54;4I4@GXKL z7W|6f?SjJ#wf`2R@ZUx7Ai>uOo-gV!YdU#P4HcU*9!iJ;D{?Ve@9Zt%Mm z8e|v;&_>XtsQ>MZ7<@^fdsBrmHXT}2puTk7yb+oh)n%Sl_{=rJcY~))e?ZNWy{c9E zOY1Aj)>r5mgALoU-ol!ltkz?As)sg%Q(AQqNdmaj)Me#`_-YFbJEyX1roWL{r73&x zktaZ6Q9DxvoxIIFAnj@?1MltNP|LgWTLpVYLq5$}gN40vvjz$G1Y4MOg~#aB3a@%7 z)kvX}sKgkjC~q(lgk1r<;B+=Kz3zrUrwwyC(Xw-)=dz&2TzIKK~8T`ls6~V*C)k?c8Q|;r1=K3;p*WV zny7>}_4aA!>*MtHN$~ZF@b*dc^@;L=y-%zctQ6POJ5(*Xp;Yf+r*|ma_0k$?I)9C3 z6@lwE^yF&Of~#WD}-)EohyO!+Z9mOQVq0{o|0o&^@^HZg?9I z%sVSIb-&^19E{GtcKRN#Iv;en!IVXRp9DP)OP{32vGqw3{e6-iN9&U$>OM&i-_iOc z*4_xZCS2Rz12Icr*F^dy=p%4E<*j?XQ|GWPn6x>W+Hk}(6y+#1?L@=dwovFETzm2B zwr$5NosVC8-0<{0{$--!)DwN!(@94@8D_|gNS+VW;Ka`8caoKLl|~ION1(G@EoaJ=Q*~ZuB@mhi)q;+0<+r=h*awnraCXZS!i@ zJ}kPeW;fRCzn+YBtl>I`qK-AXyf(7!45n^{rafqQItQb3qto|fXb&1$20~G8LsJ$S z{%#0`?u{-JjZE)g%I~RkKK4)Ep(q=t()-xc`&79;@*LffzdQem@4rU2SD~m!!L_l+ z=e_XXTlX8D-i@yNs!TRKyi;XTFAvjevFiRVQ0F?VMz#Ts&fj3ZL!1nK?h|_q&LxXn z@^VsrM+!yV4!Z3Q(RZcb-g^!28-yb58m;rG`WnJHvy<_i*zoci%zGvHI)1`@H?q#3 znv`59cQaV-nSp^k?pof}@)gDD%0ZkJBNz8q#=WU*RH zbFo^yb+MXT?Ev-Y9iZ43+RR%NU$a`RrMCzS*!!t>ZuHTs)vzpAmaDZim#b-+*ci%f zpl-Dd)PrrH-k}thi1rN&bX#IQuXm_h&y#x^Syn?)zd}=H8{RgYDzk~^p5VYW+qQ2z zr^;;YGaW)xW*gqlhN8axH?_A-%;wfEX;;5~vpgXPz*>&KdIk}(e^kVA^+?ptIj@0N}YWUD5&=%=@MZ%=SRg=jqsqBIlyz8 z13dO(RH+L*=SP1}PcciEd{W0Su;vP_hMlPu^n3I;zE>JuKYSQ-W8}?#Vsmd1M(pT3 zV(8t{hXb0ja102Xi=tQ@i`>4VSXkj0Cy%$tgJf^VW}-PB5}B=B$sp%8VT{fq#`Vw~ zlKWb4cP)MP@py;A(WzR4mcF489HirDCXCF7#(IZpp)Hg|9N$EV>f9!jCNyojFN;Zn zc0Qpe{WSX}q4I-cU551b26q zx>u%CRr&O)PIcdA)2Vdg`0?cvs*Fw(CRUYq>N9A_C6lX4O2-+UD$6T6m5;$qG9}~7 zO=aq*IG$47!(?*u9LNa#&cN?<{G9S@1IlwDo8U*ow6hxW(X_*leBlHzN8;-QH-=Lm zAC3|a2)7ro$}3QsSWS#Bpe}hPSvv&(a26-yaTFz9+kx<;7m1Bt~(+NjR`;96Oau-zHwY9iU?%>`Txy6HXatg8wiwiS)=Vll4{wK@b zQ-c^?$(q4hqfWMG~*i{qKqJx;R)KPvbo!Ji5KL2wIXBJX|bObY)6 zf~N|;SMW-~?+e~9_#6~o`d9Zj!T%t^qey`l3SK7oO~E?_hoOMc|2d@KzfABog69Zc zB6zjn_XQsm9EZw6|EZ*q*I)3pg69Z+T<|8rdjua6+!_f?|EZ*qH%xG);3a|wq0yuJ z1XA!X5WGzA>w@TX@KnL~3Vv4bn}YWWjzdMK|722xUnKZi!3za1 z6a1#&U4kP~sp-EpDg0k1_!_};1TPW1TJW2KzZD#bhKK$;kwRW?!6OCF5&XE|O@j9b zJ|ws`3Nrm)MhbZ&17ncoQk~`&4ik&J-tZLkj*J z!NUa46nwAX7X`mB_@LlubOKfUNg*#s@U?;$3Vv4b2EjW89~7+aiGu%BbgEVSNrB_e z(>R$FIA8Eo!Ak@`C-_aldj&_g7XPI1-(TmX#br^ksgBtR|;Mz_*ual1n(4lP;l!Dwf|&N=#wwFQn0%J3i6*7{EoQq65Pb2 z{kJ8B|Nern6|C;Rg8zpFZxHvLf}32V{kJBC|K5U&1Wy%wyWo|AHwoS)xJg^>zXK`4 z>n(Vc;F*H&75tpwPX!+m+~#8KKa~{v6bYUn_)fvg1ivY`Q+v&yPm1ub6@0tkhXrpC zyi;(K4w}C$Dbr8zwSsRK{J7xP1%E2|kl@xGwg29v2!EL1S%N=G(C!CG;eO5~8ec{V zTqJm=;M)a1D|nOOJ%S@UY5$!_;eU@{bsraSr_S0vpA>kM;01yo7yP>5J%XbXHNU!- z3+d5Y@Gw%~S%Q}ceopY4g7*q;lBD@Nkj6lc;8B8S3cgqHO2O|7-YYmRS^IBGituv; zj}p94@WX;P32u|3`FoQh{9%G;3BFVCO2MxS-Yd9CSM9$8Df}-;)%bBz;7x+}2#)Ng z-8+#ozJf;zo+J2i!7mElDR{r&=4sl0CsM>WUvQ=1C4!d;eqHcR!A;V&|JJ0;Kfy(U zrwYDZ@Jhj(1n&}jNU*xU3-RgRUCX{G#BUg4I1;;BVej^QV#m4-;G|c!}U;f?pTBQ*e{ZwEwoG@ZVqX zHG*deULyE8!S4v(FSw|e_CJ*r`Y#duoZycH9}*mwq4|?Z!QWr-1i=dgtNXp+9+|26 zJCKrJ@C3oP3tlOBlVEip7xDO9jXRMte*}*dJX7!kf>#UvNO0;P?Z1c={?$EOkbke>XT|+Z!FvVA4c7b}NTX3d z1>c(o9BUYE17*RX=i>A|I7w-iYjE84-Gh^qmYk?P)PE071=>IwG{G<-y9Xyr?iJy> zh#PR$FmB7SULjMBDex>$N;SR*aF!d7>WfAeZiV4&eirV*p`BCi!7-&lin0eEd8`ua z{32rdJAxKURt0YA2_oETd@c|XR0%4BBP~INOTG}KcB9o+x&|h5T~R)A65H1?m|0`m+sY@x3r1I+p7u2UPflO^ z`X@7e|3B8e<5lB>DT_W_Ni&Ew5QhqL-2}civVQr`iT4$mM{P!X_3bs5m2_CY%u0*( z%j#5jZxOD#iS^-A^Q zsOc6^`cW18_EIl{eXehp*1d}-*{ z$A8tkM`!HGaZ}Ol8BMe2q#z~ z6B6N=oe+t&@EXM=YHJw*J7m)jBw{5V*aWZ8ij5`_v3MX7$@0KTWJRKOgtTmgA|6r_TAEbL#xNhkNh&-Z<;S^L}cN=zH=C=cDbX z=^W1@w|&H8LY#gY`&e*3uiC_)(7c*Le~sAZl2}(4dz>Uu=Gfz<6zjX-xq{9`6S&6GCzJywq(I8RpiTy328kJnej&k3oHFCA@? z$Um85PWZZu)6TKWoKW2ryT6^+S#kSWy!I{bu`ga(!`JJnn0rd#{{fwfwF|sDGCuj5 zvRzxdtoO0&-*PW@+on3tMErl?RP@J)|M#U@->!Q`@0+oY#S!c5^t5;QdH(d2J^Z{M zr>{ny$4Yd)mP9*8uCs{qXq@&`x5`7}AdOkg64?pL|=_93F-;w+G`MEHy z#E-71mDahi6z2ZO{jAt!jhJ5&b6>nV3cps1U1nET;q#3%*G8_Rg69GiQ#I(mgqkX&uwZ|@Ii={pG8@GR>>B718nD!pJ zJ%AT3*p@(TKRnVrdqbaHTglo>TNK^vRsH=0pUpICU-3UY`(*90Z>Zg`gHk?)6Q@3-YorEX>~D!pgYUcdQ@fyn^(;r|;}@8DalH@!rje7yRDu>bub&M( zXIB2La5sD(o`RR)b$AahSI0H~2D3`99Ug#3;8}PH-h!P5nfz-s7|g%PthfUnfG6QO zcolXUWQt$$aqnMeR@?@cWjxoKRr+_~UU(RuffwM1@IGAqjQ7vi9;?y-w*0bYmA=yy z6A!^tgfGGC@E%;L3BviCwfchx;1PHhUV(Suuv%hEns_X~Ewjq6MH8lRw^{KpJOeMn zoA4g&G`|$TUXz*mx0@CB!cOx`9B6rE^x4Ae%qo5x+yjrmQ}80Z4)4QNnn2CJ*{r^s z)Z}TrU{?GPK7cDKeYn%yQg}N&U{*W^&%;i0OX)eyErpk%omFR6+zR)>!|*h`1aH9y zaLqOEzhPGCAHdaUXSJZ6)d3H{WAHq@1_xSOnJS-NomrKy1rD^f2H{D<=izmD4-T}p z>VL+k*Jf7f^}!SHEW8SD!iR9xbKbw%to*y+VK~s*I{aB5UR6zevx?sV55i;c9J~te z!kN!_|9Z3XZ-e{c3HSqe1>S}a;o9fD|6Q|cpI&$bo`aX+ZTJAL{;ckU0#``yz6}Q8^@EGhgxfH$vZxDU}SE8-uG`UnC?eGBFTO;r+yaGE- zF2ygu?(=UjE8c}GKj*pLtd$S$f$zgp@DjWUm(_azDzoy>!kzFCJOwYo>+l|2{(0}; zU{>X8hn>cjcno$LTjDi%kN8ewOZhvEErqwf;L~#&TjmeXn-x2aEyZ^lTjH`W`1o~Z z%^&WAhv8{>0p5W3;HoWbm%M+yS^2laz3>>kbJK^Hf62$MHLLioa2FhCcRhd?2w#Ku;7o(}uQRLqYk_;< zL3k2gfH&Yhxawu^UvIWT?Ev?|6YvbY3~#`Pa8;xCZ#MhM3l|RI+E+Y>)$ZCiKb5Dt z$@@2$6}Q7r((c+I{sHkTU-kZ3vnpRFJOod`^Y9A11D8us#`144D}Sd6Chmdn6Fv(s z!CUYFT=Sau&zhBg7u*j|z_aiwyai{n-oL`E)*_lF^R#td&4$s|X=-eG{g!ihvbN3- ze_omCrJtf#V%j=yqpkC{_OsZzSLy5IYO}oGdCi?xdRswy#MbDw7i4aDxs)7NNz0qi zy^E9Ue&Q*q9KT=-O|Fki%WhZtFwdvX?|nVF@3^Z{K|m)bTc?CysJQuOpmY3As-alL z)k6X80WT^FMY<&GPhNiX4}Hn6s;91HSJvaze3I|YpapYV*ELTOtGL)bu$1cNsITSs zzmK@@z5jK4a>wg*dm94Q?ftcale2blEnaR{N};NK8GUtqSnhCT_QN}Fm4_cfNtE56 z?^oHaEk;lN-ANAnB+7gy>pTD6p8RJreW*cV!cTz+i5@yT-g;G!#j#zp_7oi3?<$d! zE2EuP-NR*aG)UZ|nVbfRJ(Ee=P$y`RNX}zim&NT_w)PAilZUd$nCcNVdU(#&{OkED zqit^2p590H`Ud;l>v+;vw}JtxNwb!TI|#aR-hHO}JAN#E97_HE5&w@`=7UF{K;cg%@XN5w8{ zvGYr>ZqgZ_$@KXW>4W+6wI*sWM)K%8FZkzp2CvtLt6El#QHPd9Gt?u7O{QPudDF$ zXcA>krf-IC=Q!i3Ghc--dnxwG z^SZio!uecl`@H)b^nb;f8o%fNSG;gl*DkN9-3wh)PG;;BcP$sM4;Qzr$<%N7c|3_@ zP_gSdi87~E-*Jwc#jfYbWsP{QG;)4%j#v5j1n2@yf#;Gu=AHn5`KG`<0TR=A;&Vw( zxF?`dzv|A(_XHeWV|rwdzg=ItGO7n(bzagv3rfM?65t*|<1j4tM z0^!@sPWbl9=)GIxdi02H9MHWBb~Az{tml#_*bW-H#AJCTaqm(x4T!3Fmd?ve5nY|b_J5ATsWnh~Eu|H$7X<)_4)d!*cD z_h|P>Meehublgp$tY_=k^3=~;OJ!a2b*(0@L_7|~o+s1FSI7IvYlXDR9C4h+Zll3@7Du2_tzd16MbyZsZF7kR#b71T;mvp~7MdvrtI{qfn z2TJkyG~TIGS+<+3alC4@^TxPNXtm!Q?YudzeK;m1r{K;j_K5e+TjQNq^_8A?s?9HU zGxd$p_DiEx`p~FNJ2G<9IWg_kxiS77dp5D2YiG02&2gRYY8?Oit;amUee~=0+}#^4 zk?&j@eP;Bn%R1LJnz&BeH}7cs@|zWx|6|#k6<6N7_-4h`kxOq@T>JjV->P`$;#+r$ zrPJ2*Yp*q)>$IsUB&p8eV`m;9a=F^xWiMXI8(z4R(5PVy6eE@JYg*9-Ng2-Y0&!=6&;b zdTfHek!jo{I8@C4U5}wh4#Ffvi zzPk(e!b9*B`~mzB-iNEvm1{7o^0dSK@B?@bUW2#bvPz$Sty%fE!d>tXJOwYo58(s2 z;#1zg!K{8yJ3IhCfEVCZcn2=K=Kbr;%D)Bffd}D9cma0$b&Buw>s0=lPka9+vtp-T zr|>>_g78^*6&^u%Zq}^gufRKS8M<D^iXgKN;SYeL7a1MY(-;CXl*-i9;RefjIms{Czm zH#`ha!i(?*dYCwhvx+|mPr>;*b-RRDzU1TAnN|5);coaoJOi)58}I>KdDHu6%_{$P zcmN)OXWE9{7)4x;x4PWy96AeDSd9w;%fp_3TxaMUao;6z`-86Uro`mP%Rd@@| zG-@Cdwp+lOaf_u+MBEkC#$9)>63MR)@~gu9x(|BzYbHw7=jn{e4ze0Y^v<(Gv! z;UV||ya0FIQT(eHE@=AA)7^W`%jhA#_sXl;?CsYYzkFNYzVh0aU%8!qt+BCDpBo#q zw`7}MZ9=H;$+~-Q+*4+HscG~|On2`I&q;q@;s<*C_xrld!%p8Fe-gNz*$e$tnG?^9 zKA{vzlHGHNf?$ySS9L?So#{N`;kYNBj1K&Qo8RPrOr#}&>U#g4 z6~|7V+8u@V*=pQhS3CK+I4-Wm%PmS;#dl>sUhQ6@FQ~dxSmj6cn_uTY;q{%rC*v_X zSau7SE*4zZeXn-&t^`#ic4hiqCe+n>T}BrIq`hJ~SjTi#ObW~HbhSHL3+t-r_Fdii z>e9UD)07C7r74{+1zCRzhFqYR6!fRy`;TBKssw)A6~ABjYv4>vqbK)6t5myCb8OtF zSZ046)z?*|BZbPIKV^rTJM!;G3HpeAul-l5tNiIY{dx{x=2EJocx4U7_S28~WX5aw zHYvq^bUt2fem{9`Exe`*-#3z|=VbbI`0O1^Alth`6nM1?(mB`~Lg?=5UtjW}G_`VUR%*F1-&?{CXL@u4ExNs2qBDI1*o@JowZGGX?&DHWan zuoEARP6J#gJ$%ZX`v^bh#Ov4L^NZZC^_wG?wcy(8(KdX{`KzO54BGJ6`73KifBs5q z#cS3&y2bUL8tA5U>D|ul>u%?^+Art)mHL`*z@LosSK<3Z636Sv{UYLA8N19b-|%&n z%GgP(jx^rS*9pOS$zZMX=y}Ox`eKm&)1N;(Q++YTF%WNV3qQxi?oVfJ+?LeZBAxzF z>^^*^=B7C7;!;|Nod2(w`u~ba92?@z1;t&b#9n`vLZ2PwIc)Q)n zric9bQ)306-<1A&nsnAuvFD_S$NW;9`(u|m;+QR^^=IU=M(jtC^NX|2Evf&}!XMY- z9V5ceV{zKBl;^Kx${xObr>GWTptcU zCnZt#VvoDX^Jt3WJbE1^u7CVbUz3bXA^qbYeXUsf$2~o_Z=dTQt0^v-tdCxjLUOvn z8AsA=m33_eOLoY;B=vMm|M=1`O8;0|N0PF<@NvB@J;{S!_^RF?(>qh9KYG2~`gHoo zUs1duFY~iB?ENjQjC=i};^n?9j=jF8w|yqt3%{gz?^*z_;P-x4{E6U8*+1`kI{o7x zD!un|{DORQ^R(bU`nOM~fBfItN?ZTf`bd%VkKLF}Q~&t))UKx2^~Yw_=YI(QJ^W+X z=^iWmwmOBy|AtxdZ^OS2{}0&d9xHqwu2$!@_zh;|-wyY~58yd?4c>ywE_(l3v+{3+ zd*Ly78eW1o;W7;p%fH&J{9E7yxLO0@e?1O4JIeP{jyX7!$g=ipU%3(hF6#ji1|@9x5#a3Q_p z4Z;tJU#SC!`8S!>cOCE`JOMkMV}-B4+k|J(E3P-I@HW`#9E{F2l~YOa5Z|v4d@LQ(kGrFe1-TM@YCuOKR|zY0X^b1cn{8?FIl0_u8}2fz`l-6^>nm$k+zAiC58wrO72bi%KIi@G%*ww7?tus4Nq7O?fcN04 zTJK+PR{gIH?tw?(X?Pi~eZj}SYgYO9z$5T9>~w?`{t(_Lyy6Sqzsan^J7A|HEN-at z;q7L{{qO^L4qk(|;6NX^`bF>GVpjg$@O^j^UVzu&Jvej2``4M3e+%3L--l=6o-g|N z_suH)47>tw!{zlpyvD5Ry9IVS!s7d|(-9Ug!Ry4|gPo4B!m}^=^xDjd`(URdES`mz z2;YMD;i{Y7zrn2Hcfh@{(-GG1nTD4M-+&L{Mbi zSK&?A=?*J@r#oDsdF5rFUXNMv2s{NZ!t3xpT+!&`H<|sU)`4&@JOal>~w_1PDfbj%@OW&gvGmXoq z`M1H{@Gv|LFT)$~A-wRq_kU2jBcgB-(Xhdy9@Wg_u*N15#E6J;Ho>`KWkRyak|G!uOFTud>&qhx8cms zd;c1<^1loBz$5S!ya;c=hj3+!_ir+*{M+Ducmnq3 z3Gc(zZ+QPrv-&+{Z+fmaD{g^1-~spnyZ}Fh58$p}@cu()RlX^B3EqUuzUsrP%qqVu z+zAiC58wrO72bi%zUKYw%qqWTxCb8PXHwSJM%lj(lc3&egM{yGNx6 zY`c11_sVyTk1F3ujyQ73Y-<8*^4RqRFPP3F*= zEYJ#WbV;48$LZoK{xPj%7eD+xd#O}Y{`FcXqm54Fwei+V)U%ElYhB zyWc2{WbXM1-}ihU&+qpk`g~$#4?n$}p0b~^Yc0Og+%7qD2H^- zOOe~Hl#b&O%X&TzOJ%L|sCHzby>D9VJVyWXXe8dd7A$w33zj>Dg(Gj}>wjuor81XB z?B_|W5#r4w;ny{B>bDffbuwiRU(ZSOjbzFme*GAykCak>j#t+3^_oPVh*#$D{W!h8 z5Wap>DXWfINwjNPV?Bwomr|cB<$8`?_7YoPr81r){y&)hI4bUZ8M`m0SkK9nJ$!v9 z(MOUgd-!$0=_z|U^&a^cSJLO{PTBc^wC0So@{Mzz@#u;*I+RD(w;pZN$LLTVo%T8L zc_DV%C;an5bR91Lc_C+OK8mxhIiLT-&;N1i`zLzdk2tTTQlGA@#cli8W39yg-%4VQ z7kRv#fxehT{l@N-5$idLvd8Ni;m3XwWiI9VPNwYX)O+N#29wO{}Bb4?C4#U+?mugV!%C@^!ZRO&K3zO2mH+zUQEddATLOz8)JhP3*?-{g#bY&P@ym~Lus%{GO%69^)70en zE!BtZN%{k`+Eeu3;r|W)BYa7XXyHzqL-F5$f7z_~ci>yXKZO4R-hdC`N;SLrHZE!z40?)xtOGELqnj|c~)6x(R z!4qc1^RUy>5bwd2>ZTT+HEa37eef7O53j+2hDJu+(){bp%D)xvgU8@`cp2V;58xUN zLi2AitMq!{L3k3Lhu7g9xIzQk{QI8u{$pmvPU}MHt-u?EAHbEG0Nw95tN88k06YTE z!Yl9&d@LS55SY~fx;}@XdiTQ<@I1T@@4ywBxGa9HS*3Ru z?t+KmX?Pia2=BucnoP~V$*j`rfCu3*cn)5Lci{>&E1Jy8zZG^`7vf=fhVVsr6W)U> zKjr=F&8j@@a4$RtPs2;_CR}#S`&XNle+%3JJFN?qXAGVvd@Fu(uS6BP^4Q7>} z)7p@KFFZ#09J~f^!DXNE{=;<2@k;&@I1T*@4@BQy?=vQ`R~BxpYvRAR^@4j`{4)h zEW845!ezDIzt*hP2iye@!Bg-Oya|_m-uqXXwfcbD;Q@FIo`-v1@bL?2W^53CXjZ?s z@(VtGpqbGI_nTGt1pEQK3h%<1I`3a^R`FZlZg?1;ffwOTcn_|8(fik%wfcs8;W2m` zUV=B_vK!vN)~wYx+yxK8Q}7b}5I%q_zUciM%{p%U<&F>&z@jaSANNJlUb$T0T05Hu+!d9 j_!_)Rc&5SoJM9gHJM9gn-*4ZG2hHl(r(tw#5BdKGdv8nn literal 0 HcmV?d00001 diff --git a/libwvdrmengine/mediacrypto/test/Android.mk b/libwvdrmengine/mediacrypto/test/Android.mk index 67f52799..edca99f8 100644 --- a/libwvdrmengine/mediacrypto/test/Android.mk +++ b/libwvdrmengine/mediacrypto/test/Android.mk @@ -20,7 +20,8 @@ LOCAL_STATIC_LIBRARIES := \ libgmock \ libgmock_main \ libgtest \ - libl3crypto \ + libwvwrapper \ + libwvlevel3 \ libprotobuf-cpp-2.3.0-lite \ libwvdrmcryptoplugin \ diff --git a/libwvdrmengine/mediadrm/test/Android.mk b/libwvdrmengine/mediadrm/test/Android.mk index 59a74b5c..07b3dda5 100644 --- a/libwvdrmengine/mediadrm/test/Android.mk +++ b/libwvdrmengine/mediadrm/test/Android.mk @@ -21,7 +21,8 @@ LOCAL_STATIC_LIBRARIES := \ libgmock \ libgmock_main \ libgtest \ - libl3crypto \ + libwvwrapper \ + libwvlevel3 \ libprotobuf-cpp-2.3.0-lite \ libwvdrmdrmplugin \ diff --git a/libwvdrmengine/oemcrypto/Android.mk b/libwvdrmengine/oemcrypto/Android.mk new file mode 100644 index 00000000..0c4f26e3 --- /dev/null +++ b/libwvdrmengine/oemcrypto/Android.mk @@ -0,0 +1,34 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_C_INCLUDES := \ + vendor/widevine/libwvdrmengine/cdm/core/include \ + bionic \ + external/openssh \ + external/openssl/include \ + external/openssl/include/openssl \ + external/stlport/stlport \ + vendor/widevine/libwvdrmengine/oemcrypto/include \ + +LOCAL_SHARED_LIBRARIES := \ + libcrypto \ + libcutils \ + libdl \ + liblog \ + libstlport \ + libutils \ + libz \ + +LOCAL_STATIC_LIBRARIES := \ + libwvlevel3 \ + +LOCAL_MODULE := libwvwrapper + +# TODO(fredgc): remove mock reference when library is complete. +REL_MOCK_SOURCE := ../oemcrypto/mock/src + +LOCAL_SRC_FILES := \ + src/wrapper.cpp \ + +include $(BUILD_STATIC_LIBRARY) diff --git a/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h b/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h index db08880d..f964987c 100644 --- a/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h +++ b/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h @@ -1024,8 +1024,6 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session, * OEMCrypto_SUCCESS success * OEMCrypto_ERROR_INVALID_SESSION * OEMCrypto_ERROR_SHORT_BUFFER if the signature buffer is too small. - * OEMCrypto_ERROR_CLOSE_SESSION_FAILED illegal/unrecognized handle or the - * security engine is not properly initialized. * * Version: * This method changed in API version 6. diff --git a/libwvdrmengine/oemcrypto/include/level3.h b/libwvdrmengine/oemcrypto/include/level3.h new file mode 100644 index 00000000..0e2b4f43 --- /dev/null +++ b/libwvdrmengine/oemcrypto/include/level3.h @@ -0,0 +1,160 @@ +/********************************************************************* + * OEMCryptoCENC.h + * + * (c) Copyright 2013 Google, Inc. + * + * Reference APIs needed to support Widevine's crypto algorithms. + *********************************************************************/ + +#ifndef LEVEL3_OEMCRYPTO_H_ +#define LEVEL3_OEMCRYPTO_H_ + +#include +#include + +#include "OEMCryptoCENC.h" + +namespace wvoec_level3 { + +#define Level3_Initialize _lcc01 +#define Level3_Terminate _lcc02 +#define Level3_InstallKeybox _lcc03 +#define Level3_GetKeyData _lcc04 +#define Level3_IsKeyboxValid _lcc05 +#define Level3_GetRandom _lcc06 +#define Level3_GetDeviceID _lcc07 +#define Level3_WrapKeybox _lcc08 +#define Level3_OpenSession _lcc09 +#define Level3_CloseSession _lcc10 +#define Level3_DecryptCTR _lcc11 +#define Level3_GenerateDerivedKeys _lcc12 +#define Level3_GenerateSignature _lcc13 +#define Level3_GenerateNonce _lcc14 +#define Level3_LoadKeys _lcc15 +#define Level3_RefreshKeys _lcc16 +#define Level3_SelectKey _lcc17 +#define Level3_RewrapDeviceRSAKey _lcc18 +#define Level3_LoadDeviceRSAKey _lcc19 +#define Level3_GenerateRSASignature _lcc20 +#define Level3_DeriveKeysFromSessionKey _lcc21 +#define Level3_APIVersion _lcc22 +#define Level3_SecurityLevel _lcc23 +#define Level3_Generic_Encrypt _lcc24 +#define Level3_Generic_Decrypt _lcc25 +#define Level3_Generic_Sign _lcc26 +#define Level3_Generic_Verify _lcc27 + +extern "C" { + +OEMCryptoResult Level3_Initialize(void); +OEMCryptoResult Level3_Terminate(void); +OEMCryptoResult Level3_OpenSession(OEMCrypto_SESSION *session); +OEMCryptoResult Level3_CloseSession(OEMCrypto_SESSION session); +OEMCryptoResult Level3_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); +OEMCryptoResult Level3_GenerateNonce(OEMCrypto_SESSION session, + uint32_t* nonce); +OEMCryptoResult Level3_GenerateSignature(OEMCrypto_SESSION session, + const uint8_t* message, + size_t message_length, + uint8_t* signature, + size_t* signature_length); +OEMCryptoResult Level3_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); +OEMCryptoResult Level3_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); +OEMCryptoResult Level3_SelectKey(const OEMCrypto_SESSION session, + const uint8_t* key_id, + size_t key_id_length); +OEMCryptoResult Level3_DecryptCTR(OEMCrypto_SESSION session, + const uint8_t *data_addr, + size_t data_length, + bool is_encrypted, + const uint8_t *iv, + size_t block_offset, + const OEMCrypto_DestBufferDesc* out_buffer, + uint8_t subsample_flags); +OEMCryptoResult Level3_InstallKeybox(const uint8_t *keybox, + size_t keyBoxLength); +OEMCryptoResult Level3_IsKeyboxValid(void); +OEMCryptoResult Level3_GetDeviceID(uint8_t* deviceID, + size_t *idLength); +OEMCryptoResult Level3_GetKeyData(uint8_t* keyData, + size_t *keyDataLength); +OEMCryptoResult Level3_GetRandom(uint8_t* randomData, + size_t dataLength); +OEMCryptoResult Level3_WrapKeybox(const uint8_t *keybox, + size_t keyBoxLength, + uint8_t *wrappedKeybox, + size_t *wrappedKeyBoxLength, + const uint8_t *transportKey, + size_t transportKeyLength); +OEMCryptoResult Level3_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); +OEMCryptoResult Level3_LoadDeviceRSAKey(OEMCrypto_SESSION session, + const uint8_t* wrapped_rsa_key, + size_t wrapped_rsa_key_length); +OEMCryptoResult Level3_GenerateRSASignature(OEMCrypto_SESSION session, + const uint8_t* message, + size_t message_length, + uint8_t* signature, + size_t *signature_length); +OEMCryptoResult Level3_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); +OEMCryptoResult Level3_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); +OEMCryptoResult Level3_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); +OEMCryptoResult Level3_Generic_Sign(OEMCrypto_SESSION session, + const uint8_t* in_buffer, + size_t buffer_length, + OEMCrypto_Algorithm algorithm, + uint8_t* signature, + size_t* signature_length); +OEMCryptoResult Level3_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); +}; + +} +#endif // LEVEL3_OEMCRYPTO_H_ diff --git a/libwvdrmengine/oemcrypto/src/wrapper.cpp b/libwvdrmengine/oemcrypto/src/wrapper.cpp new file mode 100644 index 00000000..49fac8a2 --- /dev/null +++ b/libwvdrmengine/oemcrypto/src/wrapper.cpp @@ -0,0 +1,626 @@ +/******************************************************************************* + * + * Copyright 2013 Google Inc. All Rights Reserved. + * + * mock implementation of OEMCrypto APIs + * + ******************************************************************************/ + +#include "OEMCryptoCENC.h" + +#include +#include +#include +#include +#include + +#include "level3.h" +#include "log.h" + +using namespace wvoec_level3; + +namespace { +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, + uint8_t subsample_flags); +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; \ + } + +extern "C" +OEMCryptoResult OEMCrypto_Initialize(void) { + // LOGD("First, 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. %s", dlerror()); + return Level3_Initialize(); + } + 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 Level3_Initialize(); + } + 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 Level3_Initialize(); + } + 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 Level3_Initialize(); + } + } + 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; + } + return Level3_Terminate(); +} + +extern "C" +OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session) { + if (level1.library) { + return level1.OEMCrypto_OpenSession(session); + } + return Level3_OpenSession(session); +} + +extern "C" +OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session) { + if (level1.library) { + return level1.OEMCrypto_CloseSession(session); + } + return Level3_CloseSession(session); +} + +extern "C" +OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, + uint32_t* nonce) { + if (level1.library) { + return level1.OEMCrypto_GenerateNonce(session, nonce); + } + return Level3_GenerateNonce(session, nonce); +} + +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); + } + return Level3_GenerateDerivedKeys(session, mac_key_context, + mac_key_context_length, + enc_key_context, + enc_key_context_length); +} + +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); + } + return Level3_GenerateSignature(session, message, message_length, + signature, signature_length); +} + + +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); + } + return Level3_LoadKeys(session, message, message_length, signature, + signature_length, enc_mac_key_iv, enc_mac_key, + num_keys, key_array); +} + +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); + } + return Level3_RefreshKeys(session, message, message_length, signature, + signature_length, num_keys, key_array); +} + +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); + } + return Level3_SelectKey(session, key_id, key_id_length); +} + +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, + uint8_t subsample_flags) { + if (level1.library) { + return level1.OEMCrypto_DecryptCTR(session, data_addr, data_length, + is_encrypted, iv, offset, out_buffer, + subsample_flags); + } + return Level3_DecryptCTR(session, data_addr, data_length, + is_encrypted, iv, offset, out_buffer, subsample_flags); +} + +extern "C" +OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox, + size_t keyBoxLength) { + if (level1.library) { + return level1.OEMCrypto_InstallKeybox(keybox, keyBoxLength); + } + return Level3_InstallKeybox(keybox, keyBoxLength); +} + +extern "C" +OEMCryptoResult OEMCrypto_IsKeyboxValid(void) { + if (level1.library) { + return level1.OEMCrypto_IsKeyboxValid(); + } + return Level3_IsKeyboxValid(); +} + +extern "C" +OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, + size_t* idLength) { + if (level1.library) { + return level1.OEMCrypto_GetDeviceID(deviceID, idLength); + } + return Level3_GetDeviceID(deviceID, idLength); +} + +extern "C" +OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, + size_t* keyDataLength) { + if (level1.library) { + return level1.OEMCrypto_GetKeyData(keyData, keyDataLength); + } + return Level3_GetKeyData(keyData, keyDataLength); +} + +extern "C" +OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, size_t dataLength) { + if (level1.library) { + return level1.OEMCrypto_GetRandom(randomData, dataLength); + } + return Level3_GetRandom(randomData, dataLength); +} + +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); + } + return Level3_WrapKeybox(keybox, keyBoxLength, wrappedKeybox, + wrappedKeyBoxLength, transportKey, + transportKeyLength); +} + +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); + } + return Level3_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); +} + +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); + } + return Level3_LoadDeviceRSAKey(session, wrapped_rsa_key, + wrapped_rsa_key_length); +} + +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); + } + return Level3_GenerateRSASignature(session, message, message_length, + signature, signature_length); +} + +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); + } + return Level3_DeriveKeysFromSessionKey(session, enc_session_key, + enc_session_key_length, + mac_key_context, + mac_key_context_length, + enc_key_context, + enc_key_context_length); +} + +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 Level3_Generic_Encrypt(session, in_buffer, buffer_length, + iv, algorithm, out_buffer); +} + +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 Level3_Generic_Decrypt(session, in_buffer, buffer_length, + iv, algorithm, out_buffer); +} + +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 Level3_Generic_Sign(session, in_buffer, buffer_length, + algorithm, signature, + signature_length); +} + +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 Level3_Generic_Verify(session, in_buffer, buffer_length, + algorithm, signature, + signature_length); +} + +}; // namespace wvoec_mock diff --git a/libwvdrmengine/oemcrypto/test/Android.mk b/libwvdrmengine/oemcrypto/test/Android.mk index 9ddd4cf7..bd378587 100644 --- a/libwvdrmengine/oemcrypto/test/Android.mk +++ b/libwvdrmengine/oemcrypto/test/Android.mk @@ -4,8 +4,8 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - oemcrypto_test.cpp \ - oemcrypto_keybox_test.cpp + oemcrypto_test.cpp \ + oemcrypto_keybox_test.cpp LOCAL_MODULE_TAGS := tests @@ -13,26 +13,28 @@ LOCAL_MODULE_TAGS := tests LOCAL_CFLAGS += -DCAN_INSTALL_KEYBOX LOCAL_C_INCLUDES += \ - bionic \ - external/gtest/include \ - external/openssl/include \ - external/stlport/stlport \ - $(LOCAL_PATH)/../include \ - $(LOCAL_PATH)/../mock/src \ + bionic \ + external/gtest/include \ + external/openssl/include \ + external/stlport/stlport \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../mock/src \ +# TODO(fredgc): fix order dependencies on libwvlevel3 and libwvwrapper. LOCAL_STATIC_LIBRARIES := \ - libgtest \ - libgtest_main \ - libl3crypto \ + libgtest \ + libgtest_main \ + libwvwrapper \ + libwvlevel3 \ LOCAL_SHARED_LIBRARIES := \ - libcrypto \ - libcutils \ - libdl \ - liblog \ - libstlport \ - libutils \ - libz \ + libcrypto \ + libcutils \ + libdl \ + liblog \ + libstlport \ + libutils \ + libz \ LOCAL_MODULE:=oemcrypto_test diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_keybox_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_keybox_test.cpp index e0db67bd..06d345d3 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_keybox_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_keybox_test.cpp @@ -92,11 +92,11 @@ class OEMCryptoKeyboxTest : public ::testing::Test { protected: virtual void SetUp() { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()) - << "OEMCrypto_Initialize failed."; } - void install_keybox(wvoec_mock::WidevineKeybox& keybox) { + void install_keybox(wvoec_mock::WidevineKeybox& keybox, bool good) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()) + << "OEMCrypto_Initialize failed."; OEMCryptoResult sts; uint8_t wrapped[sizeof(wvoec_mock::WidevineKeybox)]; size_t length = sizeof(wvoec_mock::WidevineKeybox); @@ -107,18 +107,23 @@ class OEMCryptoKeyboxTest : public ::testing::Test { NULL, 0); ASSERT_EQ(OEMCrypto_SUCCESS, sts); sts = OEMCrypto_InstallKeybox(wrapped, sizeof(keybox)); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); + if( good ) { + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + } else { + // Can return error now, or return error on IsKeyboxValid. + } } virtual void TearDown() { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Terminate()) - << "OEMCrypto_Terminate failed."; + OEMCrypto_Terminate(); } public: }; TEST_F(OEMCryptoKeyboxTest, DefaultKeybox) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()) + << "OEMCrypto_Initialize failed."; OEMCryptoResult sts; sts = OEMCrypto_IsKeyboxValid(); ASSERT_EQ(OEMCrypto_SUCCESS, sts); @@ -127,12 +132,12 @@ TEST_F(OEMCryptoKeyboxTest, DefaultKeybox) { TEST_F(OEMCryptoKeyboxTest, GoodKeybox) { wvoec_mock::WidevineKeybox keybox = kValidKeybox02; OEMCryptoResult sts; - install_keybox(keybox); + install_keybox(keybox, true); sts = OEMCrypto_IsKeyboxValid(); ASSERT_EQ(OEMCrypto_SUCCESS, sts); keybox = kValidKeybox03; - install_keybox(keybox); + install_keybox(keybox, true); sts = OEMCrypto_IsKeyboxValid(); ASSERT_EQ(OEMCrypto_SUCCESS, sts); } @@ -141,7 +146,7 @@ TEST_F(OEMCryptoKeyboxTest, BadCRCKeybox) { wvoec_mock::WidevineKeybox keybox = kValidKeybox02; keybox.crc_[1] = 42; OEMCryptoResult sts; - install_keybox(keybox); + install_keybox(keybox, false); sts = OEMCrypto_IsKeyboxValid(); ASSERT_EQ(OEMCrypto_ERROR_BAD_CRC, sts); } @@ -150,7 +155,7 @@ TEST_F(OEMCryptoKeyboxTest, BadMagicKeybox) { wvoec_mock::WidevineKeybox keybox = kValidKeybox02; keybox.magic_[1] = 42; OEMCryptoResult sts; - install_keybox(keybox); + install_keybox(keybox, false); sts = OEMCrypto_IsKeyboxValid(); ASSERT_EQ(OEMCrypto_ERROR_BAD_MAGIC, sts); } @@ -160,7 +165,7 @@ TEST_F(OEMCryptoKeyboxTest, BadDataKeybox) { wvoec_mock::WidevineKeybox keybox = kValidKeybox02; keybox.data_[1] = 42; OEMCryptoResult sts; - install_keybox(keybox); + install_keybox(keybox, false); sts = OEMCrypto_IsKeyboxValid(); ASSERT_EQ(OEMCrypto_ERROR_BAD_CRC, sts); } diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp index f2e99e87..b43ea2ab 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp @@ -1682,9 +1682,16 @@ TEST_F(OEMCryptoClientTest, GenerateDerivedKeys) { testTearDown(); } +// Define CAN_INSTALL_KEYBOX if you are compiling with the reference +// implementation of OEMCrypto, or if your version of OEMCrypto supports +// OEMCrypto_InstallKeybox and OEwith a clear keybox. +// The Below tests are based on a specific keybox which is installed for testing. +#if defined(CAN_INSTALL_KEYBOX) + TEST_F(OEMCryptoClientTest, GenerateSignature) { - Session& s = createSession("ONE"); testSetUp(); + InstallKeybox(kDefaultKeybox); + Session& s = createSession("ONE"); s.open(); s.GenerateDerivedKeys(); @@ -1715,19 +1722,12 @@ TEST_F(OEMCryptoClientTest, GenerateSignature) { ASSERT_EQ(0, memcmp(&expected_signature[0], signature, expected_signature.size())); - s.close(); ASSERT_TRUE(s.successStatus()); ASSERT_FALSE(s.isOpen()); testTearDown(); } -// Define CAN_INSTALL_KEYBOX if you are compiling with the reference -// implementation of OEMCrypto, or if your version of OEMCrypto supports -// OEMCrypto_InstallKeybox and OEwith a clear keybox. -// The Below tests are based on a specific keybox which is installed for testing. -#if defined(CAN_INSTALL_KEYBOX) - TEST_F(OEMCryptoClientTest, LoadKeyNoNonce) { testSetUp(); InstallKeybox(kDefaultKeybox);