From 6d5be4fddfd284c465596c7485832a93b07f9a0b Mon Sep 17 00:00:00 2001 From: Fred Gylys-Colwell Date: Tue, 7 Apr 2015 15:21:58 -0700 Subject: [PATCH] Enable OEMCrypto Unit Tests This is a merge from the widevine repository of http://go/wvgerrit/13923 Switch openssl to use the EVP interface for aes-ctr-128 http://go/wvgerrit/13979 Add Test Certificate to OEMCrypto Mock http://go/wvgerrit/13978 Add Test Keybox to Level 3 OEMCrypto http://go/wvgerrit/13873 Enable OEMCrypto Unit Tests This CL adds a main program to oemcrypto_test.cpp, which filters out tests that are not supported on the specified platform. It also adds LoadTestKeybox to the mock. This allows oemcrypto unit tests to be run on devices that have production keybox. It also allows the same set of unit tests to work on Android and on non-Android platforms. b/18962381 Use test certificate (partial fix) b/19867990 Separate cast receiver tests Change-Id: If89c31530103ed85aa37d7379bd5b4dc2a927f38 --- libwvdrmengine/cdm/core/include/properties.h | 7 - .../core/src/oemcrypto_adapter_dynamic.cpp | 37 + libwvdrmengine/cdm/core/src/properties.cpp | 2 - .../cdm/include/properties_configuration.h | 3 - .../oemcrypto/include/OEMCryptoCENC.h | 31 + libwvdrmengine/oemcrypto/include/level3.h | 2 + .../oemcrypto_engine_device_properties.cpp | 5 + .../oemcrypto_engine_device_properties_L1.cpp | 5 + ...emcrypto_engine_device_properties_cert.cpp | 56 + .../mock/src/oemcrypto_engine_mock.cpp | 297 +- .../mock/src/oemcrypto_engine_mock.h | 14 +- .../mock/src/oemcrypto_keybox_mock.cpp | 41 + .../mock/src/oemcrypto_keybox_mock.h | 5 + .../mock/src/oemcrypto_keybox_testkey.cpp | 32 +- .../oemcrypto/mock/src/oemcrypto_mock.cpp | 75 +- .../mock/src/oemcrypto_usage_table_mock.cpp | 4 +- libwvdrmengine/oemcrypto/test/common.mk | 1 + .../oemcrypto/test/oemcrypto_test.cpp | 2740 +++++++++-------- .../oemcrypto/test/oemcrypto_test.h | 41 + .../oemcrypto/test/oemcrypto_test_android.cpp | 1 - .../oemcrypto/test/oemcrypto_test_main.cpp | 43 + 21 files changed, 2059 insertions(+), 1383 deletions(-) create mode 100644 libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_cert.cpp create mode 100644 libwvdrmengine/oemcrypto/test/oemcrypto_test.h create mode 100644 libwvdrmengine/oemcrypto/test/oemcrypto_test_main.cpp diff --git a/libwvdrmengine/cdm/core/include/properties.h b/libwvdrmengine/cdm/core/include/properties.h index f618f209..5141041f 100644 --- a/libwvdrmengine/cdm/core/include/properties.h +++ b/libwvdrmengine/cdm/core/include/properties.h @@ -37,9 +37,6 @@ class Properties { static inline bool oem_crypto_use_userspace_buffers() { return oem_crypto_use_userspace_buffers_; } - static inline bool oem_crypto_require_usage_tables() { - return oem_crypto_require_usage_tables_; - } static inline bool use_certificates_as_identification() { return use_certificates_as_identification_; } @@ -83,9 +80,6 @@ class Properties { static void set_oem_crypto_use_userspace_buffers(bool flag) { oem_crypto_use_userspace_buffers_ = flag; } - static void set_oem_crypto_require_usage_tables(bool flag) { - oem_crypto_require_usage_tables_ = flag; - } static void set_use_certificates_as_identification(bool flag) { use_certificates_as_identification_ = flag; } @@ -107,7 +101,6 @@ class Properties { static bool oem_crypto_use_secure_buffers_; static bool oem_crypto_use_fifo_; static bool oem_crypto_use_userspace_buffers_; - static bool oem_crypto_require_usage_tables_; static bool use_certificates_as_identification_; static bool security_level_path_backward_compatibility_support_; static scoped_ptr session_property_set_; diff --git a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp index e54c508f..57fe7c2b 100644 --- a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp +++ b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp @@ -98,6 +98,7 @@ typedef OEMCryptoResult (*L1_RewrapDeviceRSAKey_t)( typedef OEMCryptoResult (*L1_LoadDeviceRSAKey_t)(OEMCrypto_SESSION session, const uint8_t* wrapped_rsa_key, size_t wrapped_rsa_key_length); +typedef OEMCryptoResult (*L1_LoadTestRSAKey_t)(); typedef OEMCryptoResult (*L1_GenerateRSASignature_t)( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length, @@ -178,6 +179,7 @@ struct FunctionPointers { L1_GetRandom_t GetRandom; L1_RewrapDeviceRSAKey_t RewrapDeviceRSAKey; L1_LoadDeviceRSAKey_t LoadDeviceRSAKey; + L1_LoadTestRSAKey_t LoadTestRSAKey; L1_GenerateRSASignature_t GenerateRSASignature; L1_DeriveKeysFromSessionKey_t DeriveKeysFromSessionKey; L1_APIVersion_t APIVersion; @@ -317,6 +319,8 @@ class Adapter { if (level1_.version == 9) { LOOKUP(GetHDCPCapability_V9, OEMCrypto_GetHDCPCapability_V9); } else { + LOOKUP(LoadTestKeybox, OEMCrypto_LoadTestKeybox); + LOOKUP(LoadTestRSAKey, OEMCrypto_LoadTestRSAKey); LOOKUP(QueryKeyControl, OEMCrypto_QueryKeyControl); LOOKUP(CopyBuffer, OEMCrypto_CopyBuffer); LOOKUP(GetHDCPCapability, OEMCrypto_GetHDCPCapability); @@ -329,6 +333,22 @@ class Adapter { if (OEMCrypto_SUCCESS == level1_.IsKeyboxValid()) { return true; } + uint8_t buffer[1]; + size_t buffer_size = 0; + if (OEMCrypto_ERROR_NOT_IMPLEMENTED == level1_.GetKeyData(buffer, + &buffer_size)){ + // If GetKeyData is not implemented, then the device should only use a + // baked in certificate as identification. We will assume that a device + // with a bad keybox returns a different error code. + if (!wvcdm::Properties::use_certificates_as_identification()) { + // If OEMCrypto does not support a keybox, but the CDM code expects + // one, things will not work well at all. This is not a fatal error + // because we still want to test OEMCrypto in that configuration. + LOGE("OEMCrypto uses cert as identification, but cdm does not!"); + LOGE("This will not work on a production device."); + } + return true; + } wvcdm::File file; std::string filename; if (!wvcdm::Properties::GetFactoryKeyboxPath(&filename)) { @@ -377,6 +397,7 @@ class Adapter { level3_.GetRandom = Level3_GetRandom; level3_.RewrapDeviceRSAKey = Level3_RewrapDeviceRSAKey; level3_.LoadDeviceRSAKey = Level3_LoadDeviceRSAKey; + level3_.LoadTestRSAKey = Level3_LoadTestRSAKey; level3_.GenerateRSASignature = Level3_GenerateRSASignature; level3_.DeriveKeysFromSessionKey = Level3_DeriveKeysFromSessionKey; level3_.APIVersion = Level3_APIVersion; @@ -746,6 +767,14 @@ extern "C" OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox, return OEMCrypto_InstallKeybox(keybox, keyBoxLength, kLevelDefault); } +extern "C" OEMCryptoResult OEMCrypto_LoadTestKeybox() { + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + const FunctionPointers* fcn = kAdapter->get(kLevelDefault); + if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION; + if (fcn->version < 10) return OEMCrypto_ERROR_NOT_IMPLEMENTED; + return fcn->LoadTestKeybox(); +} + extern "C" OEMCryptoResult OEMCrypto_IsKeyboxValid() { return OEMCrypto_IsKeyboxValid(kLevelDefault); } @@ -793,6 +822,14 @@ extern "C" OEMCryptoResult OEMCrypto_LoadDeviceRSAKey( wrapped_rsa_key_length); } +extern "C" OEMCryptoResult OEMCrypto_LoadTestRSAKey() { + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + const FunctionPointers* fcn = kAdapter->get(kLevelDefault); + if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION; + if (fcn->version < 10) return OEMCrypto_ERROR_NOT_IMPLEMENTED; + return fcn->LoadTestRSAKey(); +} + extern "C" OEMCryptoResult OEMCrypto_GenerateRSASignature( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length, diff --git a/libwvdrmengine/cdm/core/src/properties.cpp b/libwvdrmengine/cdm/core/src/properties.cpp index 3269423c..fb0d4309 100644 --- a/libwvdrmengine/cdm/core/src/properties.cpp +++ b/libwvdrmengine/cdm/core/src/properties.cpp @@ -12,7 +12,6 @@ namespace wvcdm { bool Properties::oem_crypto_use_secure_buffers_; bool Properties::oem_crypto_use_fifo_; bool Properties::oem_crypto_use_userspace_buffers_; -bool Properties::oem_crypto_require_usage_tables_; bool Properties::use_certificates_as_identification_; bool Properties::security_level_path_backward_compatibility_support_; scoped_ptr Properties::session_property_set_; @@ -21,7 +20,6 @@ void Properties::Init() { oem_crypto_use_secure_buffers_ = kPropertyOemCryptoUseSecureBuffers; oem_crypto_use_fifo_ = kPropertyOemCryptoUseFifo; oem_crypto_use_userspace_buffers_ = kPropertyOemCryptoUseUserSpaceBuffers; - oem_crypto_require_usage_tables_ = kPropertyOemCryptoRequireUsageTable; use_certificates_as_identification_ = kPropertyUseCertificatesAsIdentification; security_level_path_backward_compatibility_support_ = diff --git a/libwvdrmengine/cdm/include/properties_configuration.h b/libwvdrmengine/cdm/include/properties_configuration.h index e8e79641..a49376ea 100644 --- a/libwvdrmengine/cdm/include/properties_configuration.h +++ b/libwvdrmengine/cdm/include/properties_configuration.h @@ -15,9 +15,6 @@ const bool kPropertyOemCryptoUseSecureBuffers = true; const bool kPropertyOemCryptoUseFifo = false; const bool kPropertyOemCryptoUseUserSpaceBuffers = false; -// If true, the unit tests require OEMCrypto to support usage tables. -const bool kPropertyOemCryptoRequireUsageTable = true; - // If false, keyboxes will be used as client identification // and passed as the token in the license request const bool kPropertyUseCertificatesAsIdentification = true; diff --git a/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h b/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h index 3a268acb..b92797dc 100644 --- a/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h +++ b/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h @@ -294,6 +294,7 @@ typedef enum OEMCrypto_HDCP_Capability { #define OEMCrypto_LoadTestKeybox _oecc42 #define OEMCrypto_ForceDeleteUsageEntry _oecc43 #define OEMCrypto_GetHDCPCapability _oecc44 +#define OEMCrypto_LoadTestRSAKey _oecc45 /* @@ -1471,6 +1472,36 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session, const uint8_t* wrapped_rsa_key, size_t wrapped_rsa_key_length); +/* + * OEMCrypto_LoadTestRSAKey + * + * Description: + + * Temporarily use the standard test RSA key. This function is only required + * for platforms that do not use a keybox, but have an RSA certificate baked + * in. This allows a standard suite of unit tests to be run on a production + * device without permanently changing the certificate. This RSA key will + * persist until the next call to OEMCrypto_Terminate or + * OEMCrypto_Initialize. + * + * The test RSA key can be found in the reference implementation. + * + * Parameters + * none + * + * Returns + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * + * Threading + * This function is not called simultaneously with any other functions. + * It will be called just after OEMCrypto_Initialize(). + * + * Version + * This method is added in API version 10. + */ +OEMCryptoResult OEMCrypto_LoadTestRSAKey(); + /* * OEMCrypto_GenerateRSASignature * diff --git a/libwvdrmengine/oemcrypto/include/level3.h b/libwvdrmengine/oemcrypto/include/level3.h index 37e8bc8f..1f105ba1 100644 --- a/libwvdrmengine/oemcrypto/include/level3.h +++ b/libwvdrmengine/oemcrypto/include/level3.h @@ -57,6 +57,7 @@ namespace wvoec3 { #define Level3_QueryKeyControl _lcc41 #define Level3_LoadTestKeybox _lcc42 #define Level3_ForceDeleteUsageEntry _lcc43 +#define Level3_LoadTestRSAKey _lcc45 extern "C" { @@ -144,6 +145,7 @@ OEMCryptoResult Level3_RewrapDeviceRSAKey(OEMCrypto_SESSION session, OEMCryptoResult Level3_LoadDeviceRSAKey(OEMCrypto_SESSION session, const uint8_t* wrapped_rsa_key, size_t wrapped_rsa_key_length); +OEMCryptoResult Level3_LoadTestRSAKey(); OEMCryptoResult Level3_GenerateRSASignature(OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties.cpp index a2707578..a8e17218 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties.cpp @@ -33,6 +33,11 @@ bool CryptoEngine::supports_storage() { return true; } +// Returns true if the client uses a keybox as the root of trust. +bool CryptoEngine::supports_keybox() { + return true; +} + // Returns false for mock library to indicate the client does not support // anti-rollback hardware. bool CryptoEngine::is_anti_rollback_hw_present() { diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_L1.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_L1.cpp index f68dba88..29cd0a95 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_L1.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_L1.cpp @@ -35,6 +35,11 @@ bool CryptoEngine::supports_storage() { return true; } +// Returns true if the client uses a keybox as the root of trust. +bool CryptoEngine::supports_keybox() { + return true; +} + // Returns true to indicate the client does support anti-rollback hardware. bool CryptoEngine::is_anti_rollback_hw_present() { return true; diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_cert.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_cert.cpp new file mode 100644 index 00000000..c0535d13 --- /dev/null +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_cert.cpp @@ -0,0 +1,56 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Mock implementation of OEMCrypto APIs +// +// This file contains oemcrypto engine properties that would be for a +// level 2 device that does not have persistant storage or a keybox. +// Note: this is for illustration only. Production devices are rarely level 2. +#include "oemcrypto_engine_mock.h" + +namespace wvoec_mock { + +// If local_display() returns true, we pretend we are using a built-in display, +// instead of HDMI or WiFi output. +bool CryptoEngine::local_display() { + return true; +} + +// A closed platform is permitted to use clear buffers. +bool CryptoEngine::closed_platform() { + return false; +} + +// Returns the HDCP version currently in use. +OEMCrypto_HDCP_Capability CryptoEngine::current_hdcp_capability() { + return local_display() ? HDCP_NO_DIGITAL_OUTPUT : HDCP_V1; +} + +// Returns the max HDCP version supported. +OEMCrypto_HDCP_Capability CryptoEngine::maximum_hdcp_capability() { + return HDCP_NO_DIGITAL_OUTPUT; +} + +// Returns true if the client supports persistent storage of +// offline usage table information. +bool CryptoEngine::supports_storage() { + return false; +} + +// Returns true if the client uses a keybox as the root of trust. +bool CryptoEngine::supports_keybox() { + return false; +} + +// Returns true to indicate the client does support anti-rollback hardware. +bool CryptoEngine::is_anti_rollback_hw_present() { + return false; +} + +// Returns "L3" for a software only library. L1 is for hardware protected keys +// and data paths. L2 is for hardware protected keys but no data path +// protection. +const char* CryptoEngine::security_level() { + return "L2"; +} + +} // namespace wvoec_mock diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp index c47ec44a..7e07d06b 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp @@ -45,6 +45,162 @@ void dump_openssl_error() { err, ERR_error_string(err, buffer)); } } +// A 2048 bit RSA key in PKCS#8 PrivateKeyInfo format +// This is the RSA Test Key. +static const uint8_t kTestRSAPKCS8PrivateKeyInfo2_2048[] = { + 0x30, 0x82, 0x04, 0xbc, 0x02, 0x01, 0x00, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x04, 0xa6, 0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, + 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa7, 0x00, + 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, + 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, + 0x94, 0x58, 0xdd, 0xde, 0xa7, 0x1f, 0x3c, 0x2c, + 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, + 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, + 0x2a, 0xaa, 0x9d, 0xb4, 0x4e, 0xfa, 0xa7, 0x6a, + 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, + 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, + 0x28, 0xda, 0x3f, 0xce, 0x31, 0x7b, 0xfd, 0x06, + 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, + 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, + 0x29, 0xf2, 0x73, 0x9e, 0x39, 0xd8, 0xf6, 0x6f, + 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, + 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, + 0xcd, 0x9a, 0x13, 0x8b, 0x54, 0x73, 0x54, 0x25, + 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, + 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, + 0x98, 0x56, 0x57, 0x54, 0x71, 0xcd, 0x12, 0x7f, + 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, + 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, + 0xc9, 0x83, 0x06, 0x51, 0x5a, 0x88, 0x65, 0x13, + 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, + 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, + 0x2d, 0x5f, 0xf8, 0x12, 0x7f, 0xa2, 0xfc, 0xbb, + 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, + 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, + 0x82, 0x46, 0x0b, 0x3a, 0x77, 0x8f, 0xc0, 0x72, + 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, + 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, + 0xd3, 0x5b, 0x3d, 0xdb, 0x9c, 0x5e, 0x1b, 0x7b, + 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, + 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, + 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x00, 0x5e, + 0x79, 0x65, 0x49, 0xa5, 0x76, 0x79, 0xf9, 0x05, + 0x45, 0x0f, 0xf4, 0x03, 0xbd, 0xa4, 0x7d, 0x29, + 0xd5, 0xde, 0x33, 0x63, 0xd8, 0xb8, 0xac, 0x97, + 0xeb, 0x3f, 0x5e, 0x55, 0xe8, 0x7d, 0xf3, 0xe7, + 0x3b, 0x5c, 0x2d, 0x54, 0x67, 0x36, 0xd6, 0x1d, + 0x46, 0xf5, 0xca, 0x2d, 0x8b, 0x3a, 0x7e, 0xdc, + 0x45, 0x38, 0x79, 0x7e, 0x65, 0x71, 0x5f, 0x1c, + 0x5e, 0x79, 0xb1, 0x40, 0xcd, 0xfe, 0xc5, 0xe1, + 0xc1, 0x6b, 0x78, 0x04, 0x4e, 0x8e, 0x79, 0xf9, + 0x0a, 0xfc, 0x79, 0xb1, 0x5e, 0xb3, 0x60, 0xe3, + 0x68, 0x7b, 0xc6, 0xef, 0xcb, 0x71, 0x4c, 0xba, + 0xa7, 0x79, 0x5c, 0x7a, 0x81, 0xd1, 0x71, 0xe7, + 0x00, 0x21, 0x13, 0xe2, 0x55, 0x69, 0x0e, 0x75, + 0xbe, 0x09, 0xc3, 0x4f, 0xa9, 0xc9, 0x68, 0x22, + 0x0e, 0x97, 0x8d, 0x89, 0x6e, 0xf1, 0xe8, 0x88, + 0x7a, 0xd1, 0xd9, 0x09, 0x5d, 0xd3, 0x28, 0x78, + 0x25, 0x0b, 0x1c, 0x47, 0x73, 0x25, 0xcc, 0x21, + 0xb6, 0xda, 0xc6, 0x24, 0x5a, 0xd0, 0x37, 0x14, + 0x46, 0xc7, 0x94, 0x69, 0xe4, 0x43, 0x6f, 0x47, + 0xde, 0x00, 0x33, 0x4d, 0x8f, 0x95, 0x72, 0xfa, + 0x68, 0x71, 0x17, 0x66, 0x12, 0x1a, 0x87, 0x27, + 0xf7, 0xef, 0x7e, 0xe0, 0x35, 0x58, 0xf2, 0x4d, + 0x6f, 0x35, 0x01, 0xaa, 0x96, 0xe2, 0x3d, 0x51, + 0x13, 0x86, 0x9c, 0x79, 0xd0, 0xb7, 0xb6, 0x64, + 0xe8, 0x86, 0x65, 0x50, 0xbf, 0xcc, 0x27, 0x53, + 0x1f, 0x51, 0xd4, 0xca, 0xbe, 0xf5, 0xdd, 0x77, + 0x70, 0x98, 0x0f, 0xee, 0xa8, 0x96, 0x07, 0x5f, + 0x45, 0x6a, 0x7a, 0x0d, 0x03, 0x9c, 0x4f, 0x29, + 0xf6, 0x06, 0xf3, 0x5d, 0x58, 0x6c, 0x47, 0xd0, + 0x96, 0xa9, 0x03, 0x17, 0xbb, 0x4e, 0xc9, 0x21, + 0xe0, 0xac, 0xcd, 0x78, 0x78, 0xb2, 0xfe, 0x81, + 0xb2, 0x51, 0x53, 0xa6, 0x1f, 0x98, 0x45, 0x02, + 0x81, 0x81, 0x00, 0xcf, 0x73, 0x8c, 0xbe, 0x6d, + 0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75, + 0x78, 0xcc, 0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9, + 0x64, 0x60, 0x8c, 0x43, 0xeb, 0x85, 0xab, 0x04, + 0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda, + 0x84, 0x68, 0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4, + 0xde, 0x51, 0x4b, 0xb6, 0x51, 0x86, 0x7b, 0xd0, + 0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f, + 0x3a, 0x83, 0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13, + 0x93, 0xd7, 0x9c, 0x27, 0x80, 0xb7, 0x1e, 0x64, + 0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8, + 0x18, 0x6c, 0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96, + 0x90, 0x8f, 0xa2, 0x16, 0x22, 0x6a, 0xcc, 0x48, + 0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44, + 0x3c, 0x2d, 0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27, + 0x33, 0x85, 0x26, 0x60, 0x48, 0x16, 0xcb, 0xef, + 0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce, + 0x15, 0x43, 0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87, + 0xc3, 0x41, 0x45, 0x97, 0xb1, 0x49, 0xc2, 0x19, + 0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28, + 0xcb, 0x43, 0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb, + 0xbb, 0xdb, 0xfd, 0x11, 0x9d, 0x17, 0x68, 0x78, + 0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3, + 0xa7, 0x5b, 0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54, + 0x91, 0x99, 0xe5, 0x91, 0x32, 0x2d, 0xeb, 0x3f, + 0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41, + 0xc1, 0xee, 0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42, + 0x58, 0xf4, 0xd0, 0xb2, 0x74, 0x1d, 0x8e, 0x87, + 0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd, + 0x0d, 0x6c, 0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53, + 0xda, 0xfb, 0xed, 0x83, 0x51, 0x67, 0xa9, 0x55, + 0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17, + 0x53, 0xa8, 0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02, + 0x81, 0x80, 0x67, 0x9c, 0x32, 0x83, 0x39, 0x57, + 0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0, + 0x0a, 0x2d, 0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97, + 0xf3, 0x90, 0x9a, 0xab, 0x9b, 0x0b, 0x1b, 0x43, + 0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c, + 0xeb, 0xdb, 0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80, + 0xb8, 0xe1, 0xb3, 0xa1, 0x6c, 0x25, 0x92, 0xe4, + 0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f, + 0x37, 0x43, 0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81, + 0x20, 0x82, 0xa1, 0x48, 0x2c, 0x2d, 0x45, 0xdc, + 0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41, + 0xf9, 0xca, 0x58, 0xce, 0x4a, 0x66, 0x53, 0x54, + 0xc8, 0x28, 0x10, 0x1e, 0x08, 0x71, 0x16, 0xd8, + 0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5, + 0xb1, 0x31, 0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf, + 0x35, 0x95, 0x41, 0x29, 0x40, 0x19, 0x83, 0x35, + 0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b, + 0xcc, 0x3b, 0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae, + 0x50, 0x76, 0x63, 0x94, 0x49, 0x4c, 0xad, 0x10, + 0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8, + 0x6a, 0xab, 0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b, + 0x8a, 0xa2, 0xb9, 0x8f, 0xce, 0xec, 0x5e, 0x61, + 0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a, + 0x5f, 0xdf, 0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69, + 0xe4, 0x8b, 0x01, 0x06, 0x59, 0x22, 0xfa, 0x34, + 0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a, + 0x77, 0xe6, 0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26, + 0x6c, 0xfa, 0x2b, 0xd9, 0x83, 0x5a, 0x2d, 0x0c, + 0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a, + 0xd9, 0xbe, 0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3, + 0x66, 0xff, 0x1c, 0x1b, 0xc8, 0x96, 0x76, 0xe8, + 0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8, + 0xac, 0x21, 0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80, + 0x2c, 0x7c, 0xad, 0x1e, 0x75, 0xf6, 0x69, 0x1d, + 0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65, + 0x28, 0x66, 0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57, + 0xae, 0xb7, 0x65, 0x2c, 0x52, 0xf9, 0xe4, 0xc7, + 0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33, + 0x70, 0xcf, 0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50, + 0x75, 0x61, 0x96, 0x86, 0x4b, 0xb6, 0x2b, 0xad, + 0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35, + 0x50, 0xcb, 0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a, + 0xd3, 0x29, 0x23, 0x02, 0x60, 0xf7, 0xab, 0x30, + 0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4, + 0xa2, 0x0d, 0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18, + 0xf4, 0xd4, 0x52, 0x95, 0x00, 0xae, 0x84, 0x6b, + 0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde, + 0x72, 0x2c, 0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, + 0x56, 0xfe, 0x39, 0x28, 0x33, 0xe0, 0xdb, 0x03 +}; } // namespace namespace wvoec_mock { @@ -85,6 +241,10 @@ void SessionKeyTable::UpdateDuration(const KeyControlBlock& control) { SessionContext::~SessionContext() { if (usage_entry_) usage_entry_->set_session(NULL); + if (rsa_key_ && rsa_key_ != ce_->rsa_key()) { + RSA_free(rsa_key_); + rsa_key_ = NULL; + } } // Internal utility function to derive key using CMAC-128 @@ -999,7 +1159,8 @@ bool SessionContext::IsUsageEntryValid() { void SessionContext::ReleaseUsageEntry() { usage_entry_ = NULL; } CryptoEngine::CryptoEngine() - : current_session_(NULL), usage_table_(new UsageTable(this)) { + : current_session_(NULL), use_test_keybox_(false), + usage_table_(new UsageTable(this)), rsa_key_(NULL) { ERR_load_crypto_strings(); } @@ -1012,13 +1173,73 @@ CryptoEngine::~CryptoEngine() { void CryptoEngine::Terminate() { } -KeyboxError CryptoEngine::ValidateKeybox() { return keybox_.Validate(); } +KeyboxError CryptoEngine::ValidateKeybox() { return keybox().Validate(); } + +bool CryptoEngine::LoadTestRSAKey() { + if (rsa_key_) { + RSA_free(rsa_key_); + rsa_key_ = NULL; + } + uint8_t *pkcs8_rsa_key + = const_cast(kTestRSAPKCS8PrivateKeyInfo2_2048); + size_t rsa_key_length = sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048); + BIO *bio = BIO_new_mem_buf(pkcs8_rsa_key, rsa_key_length); + if ( bio == NULL ) { + LOGE("[LoadTestRSAKey(): Could not allocate bio buffer]"); + return false; + } + bool success = true; + PKCS8_PRIV_KEY_INFO *pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL); + if (pkcs8_pki == NULL) { + LOGE("d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL."); + success = false; + } + EVP_PKEY *evp = NULL; + if (success) { + evp = EVP_PKCS82PKEY(pkcs8_pki); + if (evp == NULL) { + LOGE("EVP_PKCS82PKEY returned NULL."); + success = false; + } + } + if (success) { + rsa_key_ = EVP_PKEY_get1_RSA(evp); + if (rsa_key_ == NULL) { + LOGE("PrivateKeyInfo did not contain an RSA key."); + success = false; + } + } + if (evp != NULL) { + EVP_PKEY_free(evp); + } + if (pkcs8_pki != NULL) { + PKCS8_PRIV_KEY_INFO_free(pkcs8_pki); + } + BIO_free(bio); + if (!success) { + return false; + } + switch (RSA_check_key(rsa_key_)) { + case 1: // valid. + return true; + case 0: // not valid. + LOGE("[LoadTestRSAKey(): rsa key not valid]"); + dump_openssl_error(); + return false; + default: // -1 == check failed. + LOGE("[LoadTestRSAKey(): error checking rsa key]"); + dump_openssl_error(); + return false; + } + + +} SessionId CryptoEngine::CreateSession() { wvcdm::AutoLock lock(session_table_lock_); static int unique_id = 1; SessionId sid = (SessionId)++unique_id; - SessionContext* sctx = new SessionContext(this, sid); + SessionContext* sctx = new SessionContext(this, sid, this->rsa_key_); sessions_[sid] = sctx; return sid; } @@ -1124,11 +1345,6 @@ OEMCryptoResult SessionContext::DecryptCTR( return OEMCrypto_ERROR_DECRYPT_FAILED; } const uint8_t* key_u8 = &content_key[0]; - AES_KEY aes_key; - if (AES_set_encrypt_key(key_u8, AES_BLOCK_SIZE * 8, &aes_key) != 0) { - LOGE("[DecryptCTR(): FAILURE]"); - return OEMCrypto_ERROR_DECRYPT_FAILED; - } if (buffer_type == OEMCrypto_BufferType_Direct) { // For reference implementation, we quietly drop the decrypted direct video. @@ -1144,23 +1360,78 @@ OEMCryptoResult SessionContext::DecryptCTR( uint8_t aes_iv[AES_BLOCK_SIZE]; memcpy(aes_iv, &iv[0], AES_BLOCK_SIZE); - // Encrypt the IV. - uint8_t ecount_buf[AES_BLOCK_SIZE]; - // The CENC spec specifies we increment only the low 64 bits of the IV // counter, and leave the high 64 bits alone. This is different from the // OpenSSL implementation, which increments the entire 128 bit iv. That is // why we implement the CTR loop ourselves. size_t l = 0; - while (l < cipher_data_length) { + if (block_offset > 0 && l < cipher_data_length) { + + // Encrypt the IV. + uint8_t ecount_buf[AES_BLOCK_SIZE]; + + AES_KEY aes_key; + if (AES_set_encrypt_key(key_u8, AES_BLOCK_SIZE * 8, &aes_key) != 0) { + LOGE("[DecryptCTR(): FAILURE]"); + return OEMCrypto_ERROR_DECRYPT_FAILED; + } AES_encrypt(aes_iv, ecount_buf, &aes_key); for (int n = block_offset; n < AES_BLOCK_SIZE && l < cipher_data_length; - ++n, ++l) { + ++n, ++l) { clear_data[l] = cipher_data[l] ^ ecount_buf[n]; } ctr128_inc64(aes_iv); block_offset = 0; } + + uint64_t remaining = cipher_data_length - l; + int out_len = 0; + + while (remaining) { + EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init(&ctx); + EVP_CIPHER_CTX_set_padding(&ctx, 0); + if (!EVP_DecryptInit_ex(&ctx, EVP_aes_128_ctr(), NULL, key_u8, aes_iv)) { + LOGE("[DecryptCTR(): EVP_INIT ERROR]"); + return OEMCrypto_ERROR_DECRYPT_FAILED; + } + + // Test the MSB of the counter portion of the initialization vector. If the + // value is 0xFF the counter is near wrapping. In this case we calculate + // the number of bytes we can safely decrypt before the counter wraps. + uint64_t decrypt_length = 0; + if (aes_iv[8] == 0xFF) { + uint64_t bytes_before_iv_wrap = (~wvcdm::ntohll64( + *reinterpret_cast(&aes_iv[8])) + 1) * AES_BLOCK_SIZE; + decrypt_length = + bytes_before_iv_wrap < remaining ? bytes_before_iv_wrap : remaining; + } else { + decrypt_length = remaining; + } + + if (!EVP_DecryptUpdate(&ctx, &clear_data[l], &out_len, &cipher_data[l], + decrypt_length)) { + LOGE("[DecryptCTR(): EVP_UPDATE_ERROR]"); + return OEMCrypto_ERROR_DECRYPT_FAILED; + } + l += decrypt_length; + remaining = cipher_data_length - l; + + int final; + if (!EVP_DecryptFinal_ex(&ctx, &clear_data[cipher_data_length - remaining], + &final)) { + LOGE("[DecryptCTR(): EVP_FINAL_ERROR]"); + return OEMCrypto_ERROR_DECRYPT_FAILED; + } + EVP_CIPHER_CTX_cleanup(&ctx); + + // If remaining is not zero, reset the iv before the second pass. + if (remaining) { + memcpy(aes_iv, &iv[0], AES_BLOCK_SIZE); + memset(&aes_iv[8], 0, AES_BLOCK_SIZE / 2); + } + } + return OEMCrypto_SUCCESS; } diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.h b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.h index 77df84f0..225f246d 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.h +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.h @@ -76,12 +76,12 @@ class SessionContext { SessionContext() {} public: - explicit SessionContext(CryptoEngine* ce, SessionId sid) + explicit SessionContext(CryptoEngine* ce, SessionId sid, RSA* rsa_key) : valid_(true), ce_(ce), id_(sid), current_content_key_(NULL), - rsa_key_(NULL), + rsa_key_(rsa_key), allowed_schemes_(kSign_RSASSA_PSS), usage_entry_(NULL) {} ~SessionContext(); @@ -225,7 +225,11 @@ class CryptoEngine { void Terminate(); KeyboxError ValidateKeybox(); - WvKeybox& keybox() { return keybox_; } + WvKeybox& keybox() { return use_test_keybox_ ? test_keybox_ : keybox_; } + WvKeybox& real_keybox() { return keybox_; } + void UseTestKeybox() { use_test_keybox_ = true; } + RSA* rsa_key() { return rsa_key_; } + bool LoadTestRSAKey(); SessionId CreateSession(); @@ -252,6 +256,7 @@ class CryptoEngine { bool local_display(); bool closed_platform(); bool supports_storage(); + bool supports_keybox(); bool is_anti_rollback_hw_present(); const char* security_level(); @@ -259,8 +264,11 @@ class CryptoEngine { SessionContext* current_session_; ActiveSessions sessions_; WvKeybox keybox_; + WvTestKeybox test_keybox_; wvcdm::Lock session_table_lock_; UsageTable* usage_table_; + bool use_test_keybox_; + RSA* rsa_key_; // If no keybox, this is baked in certificate. CORE_DISALLOW_COPY_AND_ASSIGN(CryptoEngine); }; diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_keybox_mock.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_keybox_mock.cpp index 52ab15c9..e149b4c8 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_keybox_mock.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_keybox_mock.cpp @@ -14,6 +14,42 @@ namespace wvoec_mock { +namespace { + +const WidevineKeybox kTestKeybox = { + // Sample keybox used for test vectors + { + // deviceID + 0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x30, // TestKey01 + 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ + }, { + // key + 0xfb, 0xda, 0x04, 0x89, 0xa1, 0x58, 0x16, 0x0e, + 0xa4, 0x02, 0xe9, 0x29, 0xe3, 0xb6, 0x8f, 0x04, + }, { + // data + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x19, + 0x07, 0xd9, 0xff, 0xde, 0x13, 0xaa, 0x95, 0xc1, + 0x22, 0x67, 0x80, 0x53, 0x36, 0x21, 0x36, 0xbd, + 0xf8, 0x40, 0x8f, 0x82, 0x76, 0xe4, 0xc2, 0xd8, + 0x7e, 0xc5, 0x2b, 0x61, 0xaa, 0x1b, 0x9f, 0x64, + 0x6e, 0x58, 0x73, 0x49, 0x30, 0xac, 0xeb, 0xe8, + 0x99, 0xb3, 0xe4, 0x64, 0x18, 0x9a, 0x14, 0xa8, + 0x72, 0x02, 0xfb, 0x02, 0x57, 0x4e, 0x70, 0x64, + 0x0b, 0xd2, 0x2e, 0xf4, 0x4b, 0x2d, 0x7e, 0x39, + }, { + // magic + 0x6b, 0x62, 0x6f, 0x78, + }, { + // Crc + 0x0a, 0x7a, 0x2c, 0x35, + } +}; + +} // namespace + WvKeybox::WvKeybox() { valid_ = Prepare(); } @@ -66,4 +102,9 @@ bool WvKeybox::InstallKeybox(const uint8_t* buffer, size_t keyBoxLength) { return true; } +WvTestKeybox::WvTestKeybox() { + InstallKeybox(reinterpret_cast(&kTestKeybox), + sizeof(kTestKeybox)); +} + } // namespace wvoec_mock diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_keybox_mock.h b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_keybox_mock.h index b56e15cc..f351b76d 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_keybox_mock.h +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_keybox_mock.h @@ -41,6 +41,11 @@ class WvKeybox { uint8_t crc_[4]; }; +class WvTestKeybox : public WvKeybox { + public: + WvTestKeybox(); +}; + } // namespace wvoec_mock #endif // OEMCRYPTO_KEYBOX_MOCK_H_ diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_keybox_testkey.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_keybox_testkey.cpp index e5baa1eb..71f2a15b 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_keybox_testkey.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_keybox_testkey.cpp @@ -9,35 +9,37 @@ namespace wvoec_mock { namespace { +// Note: this is a valid keybox, but it is not accepted by production servers. +// However, it is different from the one used for most of the unit tests. const WidevineKeybox kKeybox = { // Sample keybox used for test vectors { // deviceID - 0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x30, // TestKey01 - 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ + 0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x30, // TestKey02 + 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ }, { // key - 0xfb, 0xda, 0x04, 0x89, 0xa1, 0x58, 0x16, 0x0e, - 0xa4, 0x02, 0xe9, 0x29, 0xe3, 0xb6, 0x8f, 0x04, + 0x76, 0x5d, 0xce, 0x01, 0x04, 0x89, 0xb3, 0xd0, + 0xdf, 0xce, 0x54, 0x8a, 0x49, 0xda, 0xdc, 0xb6, }, { // data 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x19, - 0x07, 0xd9, 0xff, 0xde, 0x13, 0xaa, 0x95, 0xc1, - 0x22, 0x67, 0x80, 0x53, 0x36, 0x21, 0x36, 0xbd, - 0xf8, 0x40, 0x8f, 0x82, 0x76, 0xe4, 0xc2, 0xd8, - 0x7e, 0xc5, 0x2b, 0x61, 0xaa, 0x1b, 0x9f, 0x64, - 0x6e, 0x58, 0x73, 0x49, 0x30, 0xac, 0xeb, 0xe8, - 0x99, 0xb3, 0xe4, 0x64, 0x18, 0x9a, 0x14, 0xa8, - 0x72, 0x02, 0xfb, 0x02, 0x57, 0x4e, 0x70, 0x64, - 0x0b, 0xd2, 0x2e, 0xf4, 0x4b, 0x2d, 0x7e, 0x39, + 0x92, 0x27, 0x0b, 0x1f, 0x1a, 0xd5, 0xc6, 0x93, + 0x19, 0x3f, 0xaa, 0x74, 0x1f, 0xdd, 0x5f, 0xb4, + 0xe9, 0x40, 0x2f, 0x34, 0xa4, 0x92, 0xf4, 0xae, + 0x9a, 0x52, 0x39, 0xbc, 0xb7, 0x24, 0x38, 0x13, + 0xab, 0xf4, 0x92, 0x96, 0xc4, 0x81, 0x60, 0x33, + 0xd8, 0xb8, 0x09, 0xc7, 0x55, 0x0e, 0x12, 0xfa, + 0xa8, 0x98, 0x62, 0x8a, 0xec, 0xea, 0x74, 0x8a, + 0x4b, 0xfa, 0x5a, 0x9e, 0xb6, 0x49, 0x0d, 0x80, }, { // magic 0x6b, 0x62, 0x6f, 0x78, }, { // Crc - 0x0a, 0x7a, 0x2c, 0x35, + 0x2a, 0x3b, 0x3e, 0xe4, } }; diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp index 7ca9e8b3..da06aa2d 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp @@ -127,6 +127,9 @@ OEMCryptoResult OEMCrypto_GenerateDerivedKeys(OEMCrypto_SESSION session, (size_t)enc_key_context_length); } } + if (!crypto_engine->supports_keybox()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } if (NO_ERROR != crypto_engine->ValidateKeybox()) { LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_KEYBOX_INVALID]"); return OEMCrypto_ERROR_KEYBOX_INVALID; @@ -219,11 +222,6 @@ OEMCryptoResult OEMCrypto_GenerateSignature( } } - 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; @@ -631,6 +629,9 @@ OEMCryptoResult OEMCrypto_WrapKeybox(const uint8_t* keybox, if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) { LOGI("-- OEMCryptoResult OEMCrypto_WrapKeybox(const uint8_t *keybox,\n"); } + if (!crypto_engine->supports_keybox()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } if (!keybox || !wrappedKeybox || !wrappedKeyBoxLength || (keyBoxLength != *wrappedKeyBoxLength)) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -647,17 +648,35 @@ OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox, if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) { LOGI("-- OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t *keybox,\n"); } + if (!crypto_engine->supports_keybox()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } if (crypto_engine->keybox().InstallKeybox(keybox, keyBoxLength)) { return OEMCrypto_SUCCESS; } return OEMCrypto_ERROR_WRITE_KEYBOX; } +extern "C" +OEMCryptoResult OEMCrypto_LoadTestKeybox() { + if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) { + LOGI("-- OEMCryptoResult OEMCrypto_LoadTestKeybox()\n"); + } + if (!crypto_engine->supports_keybox()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + crypto_engine->UseTestKeybox(); + return OEMCrypto_SUCCESS; +} + extern "C" OEMCryptoResult OEMCrypto_IsKeyboxValid(void) { if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) { LOGI("-- OEMCryptoResult OEMCrypto_IsKeyboxValid(void) {\n"); } + if (!crypto_engine->supports_keybox()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } switch(crypto_engine->ValidateKeybox()) { case NO_ERROR: return OEMCrypto_SUCCESS; case BAD_CRC: return OEMCrypto_ERROR_BAD_CRC; @@ -673,6 +692,8 @@ OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) { LOGI("-- OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID,\n"); } + // Devices that do not support a keybox should use some other method to + // store the device id. std::vector dev_id_string = crypto_engine->keybox().device_id(); if (dev_id_string.empty()) { LOGE("[OEMCrypto_GetDeviceId(): Keybox Invalid]"); @@ -700,12 +721,23 @@ OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) { LOGI("-- OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData,\n"); } + if (!crypto_engine->supports_keybox()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } size_t length = crypto_engine->keybox().key_data_length(); + if (keyDataLength == NULL) { + LOGE("[OEMCrypto_GetKeyData(): null pointer. ERROR_UNKNOWN_FAILURE]"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } if (*keyDataLength < length) { *keyDataLength = length; LOGE("[OEMCrypto_GetKeyData(): ERROR_SHORT_BUFFER]"); return OEMCrypto_ERROR_SHORT_BUFFER; } + if (keyData == NULL) { + LOGE("[OEMCrypto_GetKeyData(): null pointer. ERROR_UNKNOWN_FAILURE]"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } memset(keyData, 0, *keyDataLength); memcpy(keyData, crypto_engine->keybox().key_data(), length); *keyDataLength = length; @@ -754,6 +786,9 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session, dump_hex("enc_rsa_key_iv", enc_rsa_key_iv, wvcdm::KEY_IV_SIZE); } } + if (!crypto_engine->supports_keybox()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } if (wrapped_rsa_key_length == NULL) { LOGE("[OEMCrypto_RewrapDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]"); return OEMCrypto_ERROR_INVALID_CONTEXT; @@ -890,6 +925,9 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session, LOGE("[OEMCrypto_LoadDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]"); return OEMCrypto_ERROR_INVALID_CONTEXT; } + if (!crypto_engine->supports_keybox()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } const WrappedRSAKey* wrapped = reinterpret_cast(wrapped_rsa_key); if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) { @@ -949,6 +987,15 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session, return result; } +extern "C" +OEMCryptoResult OEMCrypto_LoadTestRSAKey() { + if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) { + LOGI("-- OEMCryptoResult OEMCrypto_LoadTestRSAKey()\n"); + } + if (crypto_engine->LoadTestRSAKey()) return OEMCrypto_SUCCESS; + return OEMCrypto_ERROR_UNKNOWN_FAILURE; +} + extern "C" OEMCryptoResult OEMCrypto_GenerateRSASignature( OEMCrypto_SESSION session, @@ -1298,6 +1345,9 @@ OEMCryptoResult OEMCrypto_UpdateUsageTable() { if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) { LOGI("-- OEMCryptoResult OEMCrypto_UpdateUsageTable();\n"); } + if (!crypto_engine->supports_storage()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } return crypto_engine->usage_table()->UpdateTable(); } @@ -1310,6 +1360,9 @@ OEMCryptoResult OEMCrypto_DeactivateUsageEntry(const uint8_t *pst, dump_hex("pst", pst, pst_length); } } + if (!crypto_engine->supports_storage()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } std::vector pstv(pst, pst + pst_length); return crypto_engine->usage_table()->DeactivateEntry(pstv); } @@ -1326,6 +1379,9 @@ OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session, dump_hex("pst", pst, pst_length); } } + if (!crypto_engine->supports_storage()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } SessionContext* session_ctx = crypto_engine->FindSession(session); if (!session_ctx || !session_ctx->isValid()) { LOGE("[OEMCrypto_ReportUsage(): ERROR_INVALID_SESSION]"); @@ -1365,6 +1421,9 @@ OEMCryptoResult OEMCrypto_DeleteUsageEntry(OEMCrypto_SESSION session, dump_hex("signature", signature, signature_length); } } + if (!crypto_engine->supports_storage()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } SessionContext* session_ctx = crypto_engine->FindSession(session); if (!session_ctx || !session_ctx->isValid()) { LOGE("[OEMCrypto_DeleteUsageEntry(): ERROR_INVALID_SESSION]"); @@ -1401,6 +1460,9 @@ OEMCryptoResult OEMCrypto_ForceDeleteUsageEntry(const uint8_t* pst, dump_hex("pst", pst, pst_length); } } + if (!crypto_engine->supports_storage()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } std::vector pstv(pst, pst + pst_length); if (crypto_engine->usage_table()->DeleteEntry(pstv)) { return OEMCrypto_SUCCESS; @@ -1413,6 +1475,9 @@ OEMCryptoResult OEMCrypto_DeleteUsageTable() { if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) { LOGI("-- OEMCryptoResult OEMCrypto_DeleteUsageTable()\n"); } + if (!crypto_engine->supports_storage()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } crypto_engine->usage_table()->Clear(); return OEMCrypto_SUCCESS; } diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_usage_table_mock.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_usage_table_mock.cpp index 3376af67..31313ffa 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_usage_table_mock.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_usage_table_mock.cpp @@ -179,7 +179,7 @@ UsageTable::UsageTable(CryptoEngine *ce) { file.Close(); // First, verify the signature of the usage table file. - std::vector &key = ce_->keybox().device_key(); + std::vector &key = ce_->real_keybox().device_key(); uint8_t computed_signature[SHA256_DIGEST_LENGTH]; unsigned int sig_length = sizeof(computed_signature); if (!HMAC(EVP_sha256(), &key[0], key.size(), @@ -275,7 +275,7 @@ bool UsageTable::SaveToFile() { // This should be encrypted and signed with a device specific key. // For the reference implementation, I'm just going to use the keybox key. - std::vector &key = ce_->keybox().device_key(); + std::vector &key = ce_->real_keybox().device_key(); // Encrypt the table. RAND_bytes(encrypted_table->iv, wvcdm::KEY_IV_SIZE); diff --git a/libwvdrmengine/oemcrypto/test/common.mk b/libwvdrmengine/oemcrypto/test/common.mk index 7e979da0..1d5b0902 100644 --- a/libwvdrmengine/oemcrypto/test/common.mk +++ b/libwvdrmengine/oemcrypto/test/common.mk @@ -3,6 +3,7 @@ LOCAL_PATH:= $(call my-dir) LOCAL_SRC_FILES:= \ oemcrypto_test.cpp \ oemcrypto_test_android.cpp \ + oemcrypto_test_main.cpp \ LOCAL_C_INCLUDES += \ external/gtest/include \ diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp index c9c22422..28c5d24d 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp @@ -27,6 +27,7 @@ #include "log.h" #include "oemcrypto_key_mock.h" +#include "oemcrypto_test.h" #include "OEMCryptoCENC.h" #include "properties.h" #include "string_conversions.h" @@ -94,7 +95,7 @@ struct PaddedPSTReport { // These are test keyboxes. They will not be accepted by production systems. // By using known keyboxes for these tests, the results for a given set of // inputs to a test are predictable and can be compared to the actual results. -const wvoec_mock::WidevineKeybox kDefaultKeybox = { +const wvoec_mock::WidevineKeybox kTestKeybox = { // Sample keybox used for test vectors { // deviceID @@ -579,6 +580,127 @@ static const uint8_t kTestRSAPublicKey3_2048[] = { 0xa7, 0xdd, 0x49, 0x98, 0x7b, 0x6f, 0xdd, 0x69, 0x6d, 0x02, 0x03, 0x01, 0x00, 0x01 }; +DeviceFeatures global_features; + +void DeviceFeatures::Initialize(bool is_cast_receiver, bool force_load_test_keybox) { + cast_receiver = is_cast_receiver; + uses_keybox = false; + uses_certificate = false; + loads_certificate = false; + generic_crypto = false; + usage_table = false; + api_version = 0; + derive_key_method = NO_METHOD; + if (OEMCrypto_SUCCESS != OEMCrypto_Initialize()) { + printf("OEMCrypto_Initialze failed. All tests will fail.\n"); + return; + } + uint32_t nonce = 0; + uint8_t buffer[1]; + size_t size = 0; + uses_keybox = + (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_GetKeyData(buffer, &size)); + printf("uses_keybox = %s.\n", uses_keybox ? "true" : "false"); + loads_certificate = uses_keybox && + (OEMCrypto_ERROR_NOT_IMPLEMENTED != + OEMCrypto_RewrapDeviceRSAKey(0, buffer, 0, buffer, 0, &nonce, + buffer, 0, buffer, + buffer, &size)); + printf("loads_certificate = %s.\n", loads_certificate ? "true" : "false"); + uses_certificate = + (OEMCrypto_ERROR_NOT_IMPLEMENTED + != OEMCrypto_GenerateRSASignature(0, buffer, 0, buffer, &size, + kSign_RSASSA_PSS)); + printf("uses_certificate = %s.\n", uses_certificate ? "true" : "false"); + generic_crypto = + (OEMCrypto_ERROR_NOT_IMPLEMENTED != + OEMCrypto_Generic_Encrypt(0, buffer, 0, buffer, + OEMCrypto_AES_CBC_128_NO_PADDING, buffer)); + printf("generic_crypto = %s.\n", generic_crypto ? "true" : "false"); + api_version = OEMCrypto_APIVersion(); + printf("api_version = %d.\n", api_version); + usage_table = OEMCrypto_SupportsUsageTable(); + printf("usage_table = %s.\n", usage_table ? "true" : "false"); + if (force_load_test_keybox) { + derive_key_method = FORCE_TEST_KEYBOX; + } else { + PickDerivedKey(); + } + printf("cast_receiver = %s.\n", cast_receiver ? "true" : "false"); + switch(derive_key_method) { + case NO_METHOD: + printf("NO_METHOD: Cannot derive known session keys.\n"); + break; + case LOAD_TEST_KEYBOX: + printf("LOAD_TEST_KEYBOX: Call LoadTestKeybox before deriving keys.\n"); + break; + case LOAD_TEST_RSA_KEY: + printf("LOAD_TEST_RSA_KEY: Call LoadTestRSAKey before deriving keys.\n"); + break; + case EXISTING_TEST_KEYBOX: + printf("EXISTING_TEST_KEYBOX: Keybox is already the test keybox.\n"); + break; + case FORCE_TEST_KEYBOX: + printf("FORCE_TEST_KEYBOX: User requested calling InstallKeybox.\n"); + break; + } + OEMCrypto_Terminate(); +} + +std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) { + std::string filter = initial_filter; + if (!uses_keybox) FilterOut(&filter, "*KeyboxTest*"); + if (derive_key_method + != FORCE_TEST_KEYBOX) FilterOut(&filter, "*ForceKeybox*"); + if (!uses_certificate) FilterOut(&filter, "*Certificate*"); + if (!loads_certificate) FilterOut(&filter, "*LoadsCertificate*"); + if (!generic_crypto) FilterOut(&filter, "*GenericCrypto*"); + if (!cast_receiver) FilterOut(&filter, "*CastReceiver*"); + if (!usage_table) FilterOut(&filter, "*UsageTable*"); + return filter; +} + +void DeviceFeatures::PickDerivedKey() { + if (uses_keybox) { + // If device uses a keybox, try to load the test keybox. + if(OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestKeybox()) { + derive_key_method = LOAD_TEST_KEYBOX; + } else if(IsTestKeyboxInstalled()) { + derive_key_method = EXISTING_TEST_KEYBOX; + } + } else if(OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) { + derive_key_method = LOAD_TEST_RSA_KEY; + } +} + +bool DeviceFeatures::IsTestKeyboxInstalled() { + uint8_t key_data[256]; + size_t key_data_len = sizeof(key_data); + if (OEMCrypto_GetKeyData(key_data, &key_data_len) != OEMCrypto_SUCCESS) + return false; + if (key_data_len != sizeof(kTestKeybox.data_)) return false; + if (memcmp(key_data, kTestKeybox.data_, key_data_len)) return false; + uint8_t dev_id[128] = {0}; + size_t dev_id_len = 128; + if (OEMCrypto_GetDeviceID(dev_id, &dev_id_len) != OEMCrypto_SUCCESS) + return false; + // We use strncmp instead of memcmp because we don't really care about the + // multiple '\0' characters at the end of the device id. + return 0 == + strncmp(reinterpret_cast(dev_id), + reinterpret_cast(kTestKeybox.device_id_), + sizeof(kTestKeybox.device_id_)); +} + +void DeviceFeatures::FilterOut(std::string* current_filter, + const std::string& new_filter) { + if (current_filter->find('-') == std::string::npos) { + *current_filter += "-" + new_filter; + } else { + *current_filter += ":" + new_filter; + } +} + static void dump_openssl_error() { while (unsigned long err = ERR_get_error()) { char buffer[120]; @@ -665,7 +787,7 @@ class Session { "180120002a0c31383836373837343035000000000080"); } - void GenerateDerivedKeys() { + void GenerateDerivedKeysFromKeybox() { GenerateNonce(&nonce_); vector mac_context; vector enc_context; @@ -684,6 +806,39 @@ class Session { enc_key_ = wvcdm::a2b_hex("D0BFC35DA9E33436E81C4229E78CB9F4"); } + void GenerateDerivedKeysFromSessionKey() { // Uses test certificate. + GenerateNonce(&nonce_); + vector enc_session_key; + PreparePublicKey(); + ASSERT_TRUE(GenerateRSASessionKey(&enc_session_key)); + vector mac_context; + vector enc_context; + FillDefaultContext(&mac_context, &enc_context); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_DeriveKeysFromSessionKey( + session_id(), &enc_session_key[0], enc_session_key.size(), + &mac_context[0], mac_context.size(), &enc_context[0], + enc_context.size())); + + // Expected MAC and ENC keys generated from context strings + // with RSA certificate "installed". + mac_key_server_ = wvcdm::a2b_hex( + "1E451E59CB663DA1646194DD28880788ED8ED2EFF913CBD6A0D535D1D5A90381"); + mac_key_client_ = wvcdm::a2b_hex( + "F9AAE74690909F2207B53B13307FCA096CA8C49CC6DFE3659873CB952889A74B"); + enc_key_ = wvcdm::a2b_hex("CB477D09014D72C9B8DCE76C33EA43B3"); + + } + + void GenerateTestSessionKeys() { + if (global_features.derive_key_method + == DeviceFeatures::LOAD_TEST_RSA_KEY) { + GenerateDerivedKeysFromSessionKey(); + } else { + GenerateDerivedKeysFromKeybox(); + } + } + void LoadTestKeys(const std::string& pst = "", bool new_mac_keys = true) { uint8_t* pst_ptr = NULL; if (pst.length() > 0) { @@ -1190,26 +1345,7 @@ class Session { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadDeviceRSAKey(session_id(), &wrapped_rsa_key[0], wrapped_rsa_key.size())); - GenerateNonce(&nonce_); - vector enc_session_key; - PreparePublicKey(); - ASSERT_TRUE(GenerateRSASessionKey(&enc_session_key)); - vector mac_context; - vector enc_context; - FillDefaultContext(&mac_context, &enc_context); - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_DeriveKeysFromSessionKey( - session_id(), &enc_session_key[0], enc_session_key.size(), - &mac_context[0], mac_context.size(), &enc_context[0], - enc_context.size())); - - // Expected MAC and ENC keys generated from context strings - // with RSA certificate "installed". - mac_key_server_ = wvcdm::a2b_hex( - "1E451E59CB663DA1646194DD28880788ED8ED2EFF913CBD6A0D535D1D5A90381"); - mac_key_client_ = wvcdm::a2b_hex( - "F9AAE74690909F2207B53B13307FCA096CA8C49CC6DFE3659873CB952889A74B"); - enc_key_ = wvcdm::a2b_hex("CB477D09014D72C9B8DCE76C33EA43B3"); + GenerateDerivedKeysFromSessionKey(); } void DisallowDeriveKeys() { @@ -1321,20 +1457,6 @@ class OEMCryptoClientTest : public ::testing::Test { ::testing::Test::TearDown(); } - void CreateWrappedRSAKey(vector* wrapped_key, - uint32_t allowed_schemes, bool force, - const uint8_t* rsa_key = NULL, - size_t rsa_key_length = 0) { - Session s; - s.open(); - s.GenerateDerivedKeys(); - struct RSAPrivateKeyMessage encrypted; - std::vector signature; - s.MakeRSACertificate(&encrypted, &signature, allowed_schemes, rsa_key, - rsa_key_length); - s.RewrapRSAKey(encrypted, signature, wrapped_key, force); - } - const uint8_t* find(const vector& message, const vector& substring) { vector::const_iterator pos = search( @@ -1347,8 +1469,8 @@ class OEMCryptoClientTest : public ::testing::Test { }; // -// Keybox Tests -// These two tests are first, becuase it might give an idea why other +// General tests. +// This test is first, becuase it might give an idea why other // tests are failing when the device has the wrong keybox installed. TEST_F(OEMCryptoClientTest, VersionNumber) { const char* level = OEMCrypto_SecurityLevel(); @@ -1357,28 +1479,13 @@ TEST_F(OEMCryptoClientTest, VersionNumber) { cout << " OEMCrypto Security Level is " << level << endl; uint32_t version = OEMCrypto_APIVersion(); cout << " OEMCrypto API version is " << version << endl; - ASSERT_LE(8u, version); - ASSERT_GE(10u, version); -} - -TEST_F(OEMCryptoClientTest, NormalGetKeyData) { - OEMCryptoResult sts; - uint8_t key_data[256]; - size_t key_data_len = sizeof(key_data); - sts = OEMCrypto_GetKeyData(key_data, &key_data_len); - - uint32_t* data = reinterpret_cast(key_data); - printf(" NormalGetKeyData: system_id = %d = 0x%04X, version=%d\n", - htonl(data[1]), htonl(data[1]), htonl(data[0])); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - - uint32_t system_id = htonl(data[1]); - if (system_id == 0x1019) { - cout << "========================================================================\n" - << "= If you run this as \"oemcrypto_test --gtest_also_run_disabled_tests\", =\n" - << "= then a test keybox will be installed, and all tests will be run. =\n" - << "========================================================================\n"; + if (OEMCrypto_SupportsUsageTable()) { + cout << " OEMCrypto supports usage tables." << endl; + } else { + cout << " OEMCrypto does not support usage tables." << endl; } + ASSERT_GE(version, 8u); + ASSERT_LE(version, 10u); } const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value) { @@ -1418,10 +1525,6 @@ TEST_F(OEMCryptoClientTest, CheckMaxNumberOfOEMCryptoSessions) { printf(" Max Number of Sessions: %zu.\n", maximum); } -TEST_F(OEMCryptoClientTest, KeyboxValid) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid()); -} - TEST_F(OEMCryptoClientTest, NormalGetDeviceId) { OEMCryptoResult sts; uint8_t dev_id[128] = {0}; @@ -1453,10 +1556,6 @@ TEST_F(OEMCryptoClientTest, GetDeviceIdShortBuffer) { ASSERT_TRUE(dev_id_len > req_len); } -TEST_F(OEMCryptoClientTest, DefaultKeybox) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid()); -} - // // initialization tests // @@ -1654,12 +1753,6 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood3) { EXPECT_EQ(0, error_counter); } -TEST_F(OEMCryptoClientTest, GenerateDerivedKeys) { - Session s; - s.open(); - s.GenerateDerivedKeys(); -} - TEST_F(OEMCryptoClientTest, ClearCopyTest) { const int kDataSize = 256; uint8_t input_buffer[kDataSize]; @@ -1695,56 +1788,78 @@ TEST_F(OEMCryptoClientTest, ClearCopyTest) { | OEMCrypto_LastSubsample)); } +class OEMCryptoKeyboxTest : public OEMCryptoClientTest {}; + +TEST_F(OEMCryptoKeyboxTest, NormalGetKeyData) { + OEMCryptoResult sts; + uint8_t key_data[256]; + size_t key_data_len = sizeof(key_data); + sts = OEMCrypto_GetKeyData(key_data, &key_data_len); + + uint32_t* data = reinterpret_cast(key_data); + printf(" NormalGetKeyData: system_id = %d = 0x%04X, version=%d\n", + htonl(data[1]), htonl(data[1]), htonl(data[0])); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); +} + +TEST_F(OEMCryptoKeyboxTest, ProductionKeyboxValid) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid()); +} + +TEST_F(OEMCryptoKeyboxTest, GenerateDerivedKeysFromKeybox) { + Session s; + s.open(); + s.GenerateDerivedKeysFromKeybox(); +} + // // AddKey Tests // -// These tests will install a test keybox. This may be a problem -// on a production device, so they are disabled by default. -// Run this program with the command line argument: -// "--gtest_also_run_disabled_tests" -// to enable all of these tests. - -class DISABLED_TestKeybox : public OEMCryptoClientTest { +// These tests will use either a test keybox or a test certificate to derive +// session keys. +class OEMCryptoSessionTests : public OEMCryptoClientTest { protected: + OEMCryptoSessionTests() {} + virtual void SetUp() { OEMCryptoClientTest::SetUp(); - InstallKeybox(kDefaultKeybox, true); - OEMCrypto_DeleteUsageTable(); + EnsureTestKeys(); + if (global_features.usage_table) OEMCrypto_DeleteUsageTable(); + } + + void EnsureTestKeys() { + switch(global_features.derive_key_method) { + case DeviceFeatures::LOAD_TEST_KEYBOX: + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestKeybox()); + break; + case DeviceFeatures::LOAD_TEST_RSA_KEY: + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestRSAKey()); + break; + case DeviceFeatures::EXISTING_TEST_KEYBOX: + // already has test keybox. + break; + case DeviceFeatures::FORCE_TEST_KEYBOX: + InstallKeybox(kTestKeybox, true); + break; + default: + FAIL() << "Cannot run test without test keybox or RSA key installed."; + } } virtual void TearDown() { - InstallKeybox(kDefaultKeybox, true); + // If we installed a bad keybox, end with a good one installed. + if (global_features.derive_key_method == DeviceFeatures::FORCE_TEST_KEYBOX) + InstallKeybox(kTestKeybox, true); OEMCryptoClientTest::TearDown(); } - bool IsDefaultKeyboxInstalled() { - uint8_t key_data[256]; - size_t key_data_len = sizeof(key_data); - OEMCryptoResult sts = OEMCrypto_GetKeyData(key_data, &key_data_len); - - uint32_t* data = reinterpret_cast(key_data); - uint32_t system_id = htonl(data[1]); - return sts == OEMCrypto_SUCCESS && system_id == 0x1019; - } - void InstallKeybox(const wvoec_mock::WidevineKeybox& keybox, bool good) { - OEMCryptoResult sts; uint8_t wrapped[sizeof(wvoec_mock::WidevineKeybox)]; size_t length = sizeof(wvoec_mock::WidevineKeybox); - sts = OEMCrypto_WrapKeybox(reinterpret_cast(&keybox), - sizeof(keybox), wrapped, &length, NULL, 0); - if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED && - &keybox == &kDefaultKeybox && - IsDefaultKeyboxInstalled()) { - // Allow implementations which don't support installation to continue - // so long as: - // 1) we wanted to install the default keybox AND - // 2) the default keybox is already installed. - return; - } - - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - sts = OEMCrypto_InstallKeybox(wrapped, sizeof(keybox)); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_WrapKeybox(reinterpret_cast(&keybox), + sizeof(keybox), wrapped, &length, NULL, 0)); + OEMCryptoResult sts = OEMCrypto_InstallKeybox(wrapped, sizeof(keybox)); if (good) { ASSERT_EQ(OEMCrypto_SUCCESS, sts); } else { @@ -1753,34 +1868,17 @@ class DISABLED_TestKeybox : public OEMCryptoClientTest { } }; -TEST_F(OEMCryptoClientTest, DISABLED_CheckSystemID) { - OEMCryptoResult sts; - uint8_t key_data[256]; - size_t key_data_len = sizeof(key_data); - sts = OEMCrypto_GetKeyData(key_data, &key_data_len); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); +class OEMCryptoTestKeyboxTest : public OEMCryptoSessionTests {}; - uint32_t* data = reinterpret_cast(key_data); - uint32_t system_id = htonl(data[1]); - if (system_id != 0x1019) { - cout << "================================================================\n" - << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" - << "WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING \n" - << "You have enabled the keybox tests. This code WILL INSTALL A \n" - << "TEST KEYBOX. IT WILL REPLACE THE EXISTING KEYBOX, and you will.\n" - << "NOT have access to production content. Your current keybox has \n" - << "system id " << system_id << ".\n" - << "\n" - << "Continue? [y/N]:\n"; - int answer = getchar(); - if (tolower(answer) != 'y') { - cout << "Quitting tests.\n"; - exit(1); - } - } + +TEST_F(OEMCryptoTestKeyboxTest, TestKeyboxIsValid) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid()); } -TEST_F(DISABLED_TestKeybox, GoodKeybox) { +TEST_F(OEMCryptoTestKeyboxTest, GoodForceKeybox) { + ASSERT_EQ(DeviceFeatures::FORCE_TEST_KEYBOX, + global_features.derive_key_method) + << "ForceKeybox tests will modify the installed keybox."; wvoec_mock::WidevineKeybox keybox = kValidKeybox02; OEMCryptoResult sts; InstallKeybox(keybox, true); @@ -1793,7 +1891,10 @@ TEST_F(DISABLED_TestKeybox, GoodKeybox) { ASSERT_EQ(OEMCrypto_SUCCESS, sts); } -TEST_F(DISABLED_TestKeybox, BadCRCKeybox) { +TEST_F(OEMCryptoTestKeyboxTest, BadCRCForceKeybox) { + ASSERT_EQ(DeviceFeatures::FORCE_TEST_KEYBOX, + global_features.derive_key_method) + << "ForceKeybox tests will modify the installed keybox."; wvoec_mock::WidevineKeybox keybox = kValidKeybox02; keybox.crc_[1] ^= 42; OEMCryptoResult sts; @@ -1802,7 +1903,10 @@ TEST_F(DISABLED_TestKeybox, BadCRCKeybox) { ASSERT_EQ(OEMCrypto_ERROR_BAD_CRC, sts); } -TEST_F(DISABLED_TestKeybox, BadMagicKeybox) { +TEST_F(OEMCryptoTestKeyboxTest, BadMagicForceKeybox) { + ASSERT_EQ(DeviceFeatures::FORCE_TEST_KEYBOX, + global_features.derive_key_method) + << "ForceKeybox tests will modify the installed keybox."; wvoec_mock::WidevineKeybox keybox = kValidKeybox02; keybox.magic_[1] ^= 42; OEMCryptoResult sts; @@ -1811,7 +1915,10 @@ TEST_F(DISABLED_TestKeybox, BadMagicKeybox) { ASSERT_EQ(OEMCrypto_ERROR_BAD_MAGIC, sts); } -TEST_F(DISABLED_TestKeybox, BadDataKeybox) { +TEST_F(OEMCryptoTestKeyboxTest, BadDataForceKeybox) { + ASSERT_EQ(DeviceFeatures::FORCE_TEST_KEYBOX, + global_features.derive_key_method) + << "ForceKeybox tests will modify the installed keybox."; wvoec_mock::WidevineKeybox keybox = kValidKeybox02; keybox.data_[1] ^= 42; OEMCryptoResult sts; @@ -1820,11 +1927,11 @@ TEST_F(DISABLED_TestKeybox, BadDataKeybox) { ASSERT_EQ(OEMCrypto_ERROR_BAD_CRC, sts); } -TEST_F(DISABLED_TestKeybox, GenerateSignature) { +TEST_F(OEMCryptoTestKeyboxTest, GenerateSignature) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateDerivedKeysFromKeybox(); // Dummy context for testing signature generation. vector context = wvcdm::a2b_hex( @@ -1853,28 +1960,28 @@ TEST_F(DISABLED_TestKeybox, GenerateSignature) { expected_signature.size())); } -TEST_F(DISABLED_TestKeybox, LoadKeyNoNonce) { +TEST_F(OEMCryptoSessionTests, LoadKeyNoNonce) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(kDuration, 0, 42); s.EncryptAndSign(); s.LoadTestKeys(); } -TEST_F(DISABLED_TestKeybox, LoadKeyWithNonce) { +TEST_F(OEMCryptoSessionTests, LoadKeyWithNonce) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, wvoec_mock::kControlNonceEnabled, s.get_nonce()); s.EncryptAndSign(); s.LoadTestKeys(); } -TEST_F(DISABLED_TestKeybox, LoadKeyWithNoMAC) { +TEST_F(OEMCryptoSessionTests, LoadKeyWithNoMAC) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, 0, 0); s.EncryptAndSign(); s.LoadTestKeys("", false); @@ -1908,10 +2015,10 @@ TEST_F(DISABLED_TestKeybox, LoadKeyWithNoMAC) { /* The Bad Range tests verify that OEMCrypto_LoadKeys checks the range of all the pointers. It should reject a message if the pointer does not point into the message buffer */ -TEST_F(DISABLED_TestKeybox, LoadKeyWithBadRange1) { +TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange1) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, 0, 0); s.EncryptAndSign(); vector mac_keys( @@ -1926,10 +2033,10 @@ TEST_F(DISABLED_TestKeybox, LoadKeyWithBadRange1) { ASSERT_NE(OEMCrypto_SUCCESS, sts); } -TEST_F(DISABLED_TestKeybox, LoadKeyWithBadRange2) { +TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange2) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, 0, 0); s.EncryptAndSign(); vector mac_key_iv(s.encrypted_license().mac_key_iv, @@ -1944,10 +2051,10 @@ TEST_F(DISABLED_TestKeybox, LoadKeyWithBadRange2) { ASSERT_NE(OEMCrypto_SUCCESS, sts); } -TEST_F(DISABLED_TestKeybox, LoadKeyWithBadRange3) { +TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange3) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, 0, 0); s.EncryptAndSign(); vector bad_buffer( @@ -1962,10 +2069,10 @@ TEST_F(DISABLED_TestKeybox, LoadKeyWithBadRange3) { ASSERT_NE(OEMCrypto_SUCCESS, sts); } -TEST_F(DISABLED_TestKeybox, LoadKeyWithBadRange4) { +TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange4) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, 0, 0); s.EncryptAndSign(); @@ -1981,10 +2088,10 @@ TEST_F(DISABLED_TestKeybox, LoadKeyWithBadRange4) { ASSERT_NE(OEMCrypto_SUCCESS, sts); } -TEST_F(DISABLED_TestKeybox, LoadKeyWithBadRange5) { +TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange5) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, 0, 0); s.EncryptAndSign(); vector bad_buffer(s.encrypted_license().keys[1].key_iv, @@ -1998,11 +2105,11 @@ TEST_F(DISABLED_TestKeybox, LoadKeyWithBadRange5) { ASSERT_NE(OEMCrypto_SUCCESS, sts); } -TEST_F(DISABLED_TestKeybox, LoadKeyWithBadRange6) { +TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange6) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, 0, 0); s.EncryptAndSign(); @@ -2018,11 +2125,11 @@ TEST_F(DISABLED_TestKeybox, LoadKeyWithBadRange6) { ASSERT_NE(OEMCrypto_SUCCESS, sts); } -TEST_F(DISABLED_TestKeybox, LoadKeyWithBadRange7) { +TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange7) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, 0, 0); s.EncryptAndSign(); vector bad_buffer( @@ -2038,10 +2145,10 @@ TEST_F(DISABLED_TestKeybox, LoadKeyWithBadRange7) { ASSERT_NE(OEMCrypto_SUCCESS, sts); } -TEST_F(DISABLED_TestKeybox, LoadKeyWithBadNonce) { +TEST_F(OEMCryptoSessionTests, LoadKeyWithBadNonce) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, wvoec_mock::kControlNonceEnabled, 42); // bad nonce. s.EncryptAndSign(); OEMCryptoResult sts = OEMCrypto_LoadKeys( @@ -2052,10 +2159,10 @@ TEST_F(DISABLED_TestKeybox, LoadKeyWithBadNonce) { ASSERT_NE(OEMCrypto_SUCCESS, sts); } -TEST_F(DISABLED_TestKeybox, LoadKeyWithRepeatNonce) { +TEST_F(OEMCryptoSessionTests, LoadKeyWithRepeatNonce) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); uint32_t nonce = s.get_nonce(); s.FillSimpleMessage(0, wvoec_mock::kControlNonceEnabled, nonce); s.EncryptAndSign(); @@ -2063,7 +2170,7 @@ TEST_F(DISABLED_TestKeybox, LoadKeyWithRepeatNonce) { s.close(); s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, wvoec_mock::kControlNonceEnabled, nonce); // same old nonce. s.EncryptAndSign(); @@ -2075,11 +2182,11 @@ TEST_F(DISABLED_TestKeybox, LoadKeyWithRepeatNonce) { ASSERT_NE(OEMCrypto_SUCCESS, sts); } -TEST_F(DISABLED_TestKeybox, LoadKeyWithBadVerification) { +TEST_F(OEMCryptoSessionTests, LoadKeyWithBadVerification) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, 0, 0); s.license().keys[1].control.verification[2] = 'Z'; s.EncryptAndSign(); @@ -2091,10 +2198,10 @@ TEST_F(DISABLED_TestKeybox, LoadKeyWithBadVerification) { ASSERT_NE(OEMCrypto_SUCCESS, sts); } -TEST_F(DISABLED_TestKeybox, LoadKeysBadSignature) { +TEST_F(OEMCryptoSessionTests, LoadKeysBadSignature) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, 0, 0); s.EncryptAndSign(); s.signature()[0] ^= 42; // Bad signature. @@ -2105,10 +2212,10 @@ TEST_F(DISABLED_TestKeybox, LoadKeysBadSignature) { ASSERT_NE(OEMCrypto_SUCCESS, sts); } -TEST_F(DISABLED_TestKeybox, LoadKeysWithNoDerivedKeys) { +TEST_F(OEMCryptoSessionTests, LoadKeysWithNoDerivedKeys) { Session s; s.open(); - // s.GenerateDerivedKeys(); + // s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, 0, 0); s.EncryptAndSign(); OEMCryptoResult sts = OEMCrypto_LoadKeys( @@ -2118,10 +2225,10 @@ TEST_F(DISABLED_TestKeybox, LoadKeysWithNoDerivedKeys) { ASSERT_NE(OEMCrypto_SUCCESS, sts); } -TEST_F(DISABLED_TestKeybox, QueryKeyControl) { +TEST_F(OEMCryptoSessionTests, QueryKeyControl) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, wvoec_mock::kControlNonceEnabled, s.get_nonce()); s.EncryptAndSign(); s.LoadTestKeys(); @@ -2144,10 +2251,10 @@ TEST_F(DISABLED_TestKeybox, QueryKeyControl) { strlen(key_id), reinterpret_cast(&block), &size)); } -TEST_F(DISABLED_TestKeybox, AntiRollbackHardwareRequired) { +TEST_F(OEMCryptoSessionTests, AntiRollbackHardwareRequired) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, wvoec_mock::kControlRequireAntiRollbackHardware, 0); s.EncryptAndSign(); OEMCryptoResult sts = OEMCrypto_LoadKeys( @@ -2161,7 +2268,7 @@ TEST_F(DISABLED_TestKeybox, AntiRollbackHardwareRequired) { } } -class DISABLED_DecryptWithHDCP : public DISABLED_TestKeybox, +class OEMCryptoDecryptWithHDCP : public OEMCryptoSessionTests, public WithParamInterface { public: void DecryptWithHDCP(OEMCrypto_HDCP_Capability version) { @@ -2171,7 +2278,7 @@ class DISABLED_DecryptWithHDCP : public DISABLED_TestKeybox, ASSERT_EQ(OEMCrypto_SUCCESS, sts); Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, (version << wvoec_mock::kControlHDCPVersionShift) | wvoec_mock::kControlObserveHDCP | wvoec_mock::kControlHDCPRequired, @@ -2187,21 +2294,21 @@ class DISABLED_DecryptWithHDCP : public DISABLED_TestKeybox, } }; -TEST_P(DISABLED_DecryptWithHDCP, Decrypt) { +TEST_P(OEMCryptoDecryptWithHDCP, Decrypt) { // Test parameterized by HDCP version. DecryptWithHDCP(static_cast(GetParam())); } -INSTANTIATE_TEST_CASE_P(TestHDCP, DISABLED_DecryptWithHDCP, Range(1, 5)); +INSTANTIATE_TEST_CASE_P(TestHDCP, OEMCryptoDecryptWithHDCP, Range(1, 5)); // // Load, Refresh Keys Test // -class DISABLED_RefreshKeyTest - : public DISABLED_TestKeybox, +class OEMCryptoRefreshKeyTest + : public OEMCryptoSessionTests, public WithParamInterface > { public: virtual void SetUp() { - DISABLED_TestKeybox::SetUp(); + OEMCryptoSessionTests::SetUp(); new_mac_keys_ = GetParam().first; // Whether to put new mac keys in LoadKeys. num_keys_ = static_cast(GetParam().second); // # keys in refresh. @@ -2212,10 +2319,10 @@ class DISABLED_RefreshKeyTest size_t num_keys_; }; -TEST_P(DISABLED_RefreshKeyTest, RefreshWithNonce) { +TEST_P(OEMCryptoRefreshKeyTest, RefreshWithNonce) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(kDuration, wvoec_mock::kControlNonceEnabled, s.get_nonce()); s.EncryptAndSign(); @@ -2225,10 +2332,10 @@ TEST_P(DISABLED_RefreshKeyTest, RefreshWithNonce) { s.RefreshTestKeys(num_keys_, wvoec_mock::kControlNonceEnabled, nonce, true); } -TEST_P(DISABLED_RefreshKeyTest, RefreshNoNonce) { +TEST_P(OEMCryptoRefreshKeyTest, RefreshNoNonce) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(kDuration, 0, 0); s.EncryptAndSign(); s.LoadTestKeys("", new_mac_keys_); @@ -2237,10 +2344,10 @@ TEST_P(DISABLED_RefreshKeyTest, RefreshNoNonce) { s.RefreshTestKeys(num_keys_, 0, 0, true); } -TEST_P(DISABLED_RefreshKeyTest, RefreshOldNonce) { +TEST_P(OEMCryptoRefreshKeyTest, RefreshOldNonce) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(kDuration, wvoec_mock::kControlNonceEnabled, s.get_nonce()); s.EncryptAndSign(); @@ -2249,10 +2356,10 @@ TEST_P(DISABLED_RefreshKeyTest, RefreshOldNonce) { s.RefreshTestKeys(num_keys_, wvoec_mock::kControlNonceEnabled, nonce, false); } -TEST_P(DISABLED_RefreshKeyTest, RefreshBadNonce) { +TEST_P(OEMCryptoRefreshKeyTest, RefreshBadNonce) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(kDuration, wvoec_mock::kControlNonceEnabled, s.get_nonce()); s.EncryptAndSign(); @@ -2264,48 +2371,48 @@ TEST_P(DISABLED_RefreshKeyTest, RefreshBadNonce) { } // Of only one key control block in the refesh, we update all the keys. -INSTANTIATE_TEST_CASE_P(TestRefreshAllKeys, DISABLED_RefreshKeyTest, +INSTANTIATE_TEST_CASE_P(TestRefreshAllKeys, OEMCryptoRefreshKeyTest, Values(std::make_pair(true, 1), std::make_pair(false, 1))); // If multiple key control blocks, we update each key separately. -INSTANTIATE_TEST_CASE_P(TestRefreshEachKeys, DISABLED_RefreshKeyTest, +INSTANTIATE_TEST_CASE_P(TestRefreshEachKeys, OEMCryptoRefreshKeyTest, Values(std::make_pair(true, kNumKeys), std::make_pair(false, kNumKeys))); // // Decrypt Tests // -TEST_F(DISABLED_TestKeybox, Decrypt) { +TEST_F(OEMCryptoSessionTests, Decrypt) { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(kDuration, 0, 0); s.EncryptAndSign(); s.LoadTestKeys(); s.TestDecryptCTR(); } -TEST_F(DISABLED_TestKeybox, DecryptZeroDuration) { +TEST_F(OEMCryptoSessionTests, DecryptZeroDuration) { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, 0, 0); s.EncryptAndSign(); s.LoadTestKeys(); s.TestDecryptCTR(); } -TEST_F(DISABLED_TestKeybox, DecryptWithOffset) { +TEST_F(OEMCryptoSessionTests, DecryptWithOffset) { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(kDuration, 0, 0); s.EncryptAndSign(); s.LoadTestKeys(); @@ -2394,12 +2501,12 @@ vector EncryptCTR(const vector& key, return out; } -TEST_F(DISABLED_TestKeybox, DecryptWithNearWrap) { +TEST_F(OEMCryptoSessionTests, DecryptWithNearWrap) { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(kDuration, 0, 0); s.EncryptAndSign(); s.LoadTestKeys(); @@ -2444,12 +2551,12 @@ TEST_F(DISABLED_TestKeybox, DecryptWithNearWrap) { unencryptedData.size())); } -TEST_F(DISABLED_TestKeybox, DecryptUnencrypted) { +TEST_F(OEMCryptoSessionTests, DecryptUnencrypted) { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(kDuration, 0, 0); s.EncryptAndSign(); s.LoadTestKeys(); @@ -2490,7 +2597,7 @@ TEST_F(DISABLED_TestKeybox, DecryptUnencrypted) { unencryptedData.size())); } -TEST_F(DISABLED_TestKeybox, DecryptUnencryptedNoKey) { +TEST_F(OEMCryptoSessionTests, DecryptUnencryptedNoKey) { OEMCryptoResult sts; Session s; s.open(); @@ -2528,24 +2635,23 @@ TEST_F(DISABLED_TestKeybox, DecryptUnencryptedNoKey) { unencryptedData.size())); } -TEST_F(DISABLED_TestKeybox, DecryptSecureToClear) { +TEST_F(OEMCryptoSessionTests, DecryptSecureToClear) { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(kDuration, wvoec_mock::kControlObserveDataPath | - wvoec_mock::kControlDataPathSecure, - 0); + wvoec_mock::kControlDataPathSecure, 0); s.EncryptAndSign(); s.LoadTestKeys(); s.TestDecryptCTR(true, OEMCrypto_ERROR_UNKNOWN_FAILURE); } -TEST_F(DISABLED_TestKeybox, KeyDuration) { +TEST_F(OEMCryptoSessionTests, KeyDuration) { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(kDuration, wvoec_mock::kControlNonceEnabled, s.get_nonce()); s.EncryptAndSign(); @@ -2560,10 +2666,35 @@ TEST_F(DISABLED_TestKeybox, KeyDuration) { // // Certificate Root of Trust Tests // -TEST_F(DISABLED_TestKeybox, CertificateProvision) { +class OEMCryptoLoadsCertificate : public OEMCryptoTestKeyboxTest { + protected: + void CreateWrappedRSAKey(vector* wrapped_key, + uint32_t allowed_schemes, bool force, + const uint8_t* rsa_key = NULL, + size_t rsa_key_length = 0) { + Session s; + s.open(); + s.GenerateDerivedKeysFromKeybox(); + struct RSAPrivateKeyMessage encrypted; + std::vector signature; + s.MakeRSACertificate(&encrypted, &signature, allowed_schemes, rsa_key, + rsa_key_length); + s.RewrapRSAKey(encrypted, signature, wrapped_key, force); + } +}; + +TEST_F(OEMCryptoLoadsCertificate, LoadRSASessionKey) { + std::vector wrapped_rsa_key; + CreateWrappedRSAKey(&wrapped_rsa_key, kSign_RSASSA_PSS, true); Session s; s.open(); - s.GenerateDerivedKeys(); + s.InstallRSASessionTestKey(wrapped_rsa_key); +} + +TEST_F(OEMCryptoLoadsCertificate, CertificateProvision) { + Session s; + s.open(); + s.GenerateDerivedKeysFromKeybox(); struct RSAPrivateKeyMessage encrypted; std::vector signature; s.MakeRSACertificate(&encrypted, &signature, kSign_RSASSA_PSS); @@ -2572,14 +2703,14 @@ TEST_F(DISABLED_TestKeybox, CertificateProvision) { vector clear_key(kTestRSAPKCS8PrivateKeyInfo2_2048, kTestRSAPKCS8PrivateKeyInfo2_2048 + - sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048)); + sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048)); ASSERT_EQ(NULL, find(wrapped_key, clear_key)); } -TEST_F(DISABLED_TestKeybox, CertificateProvisionBadRange1) { +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange1) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateDerivedKeysFromKeybox(); struct RSAPrivateKeyMessage encrypted; std::vector signature; s.MakeRSACertificate(&encrypted, &signature, kSign_RSASSA_PSS); @@ -2603,10 +2734,10 @@ TEST_F(DISABLED_TestKeybox, CertificateProvisionBadRange1) { encrypted.rsa_key_iv, &(wrapped_key.front()), &wrapped_key_length)); } -TEST_F(DISABLED_TestKeybox, CertificateProvisionBadRange2) { +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange2) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateDerivedKeysFromKeybox(); struct RSAPrivateKeyMessage encrypted; std::vector signature; s.MakeRSACertificate(&encrypted, &signature, kSign_RSASSA_PSS); @@ -2632,10 +2763,10 @@ TEST_F(DISABLED_TestKeybox, CertificateProvisionBadRange2) { &(wrapped_key.front()), &wrapped_key_length)); } -TEST_F(DISABLED_TestKeybox, CertificateProvisionBadRange3) { +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange3) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateDerivedKeysFromKeybox(); struct RSAPrivateKeyMessage encrypted; std::vector signature; s.MakeRSACertificate(&encrypted, &signature, kSign_RSASSA_PSS); @@ -2662,10 +2793,10 @@ TEST_F(DISABLED_TestKeybox, CertificateProvisionBadRange3) { &(wrapped_key.front()), &wrapped_key_length)); } -TEST_F(DISABLED_TestKeybox, CertificateProvisionBadSignature) { +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadSignature) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateDerivedKeysFromKeybox(); struct RSAPrivateKeyMessage encrypted; std::vector signature; s.MakeRSACertificate(&encrypted, &signature, kSign_RSASSA_PSS); @@ -2690,10 +2821,10 @@ TEST_F(DISABLED_TestKeybox, CertificateProvisionBadSignature) { &(wrapped_key.front()), &wrapped_key_length)); } -TEST_F(DISABLED_TestKeybox, CertificateProvisionBadNonce) { +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadNonce) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateDerivedKeysFromKeybox(); struct RSAPrivateKeyMessage encrypted; std::vector signature; s.MakeRSACertificate(&encrypted, &signature, kSign_RSASSA_PSS); @@ -2718,10 +2849,10 @@ TEST_F(DISABLED_TestKeybox, CertificateProvisionBadNonce) { &(wrapped_key.front()), &wrapped_key_length)); } -TEST_F(DISABLED_TestKeybox, CertificateProvisionBadRSAKey) { +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRSAKey) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateDerivedKeysFromKeybox(); struct RSAPrivateKeyMessage encrypted; std::vector signature; s.MakeRSACertificate(&encrypted, &signature, kSign_RSASSA_PSS); @@ -2746,7 +2877,7 @@ TEST_F(DISABLED_TestKeybox, CertificateProvisionBadRSAKey) { &(wrapped_key.front()), &wrapped_key_length)); } -TEST_F(DISABLED_TestKeybox, LoadWrappedRSAKey) { +TEST_F(OEMCryptoLoadsCertificate, LoadWrappedRSAKey) { OEMCryptoResult sts; std::vector wrapped_rsa_key; CreateWrappedRSAKey(&wrapped_rsa_key, kSign_RSASSA_PSS, true); @@ -2758,68 +2889,75 @@ TEST_F(DISABLED_TestKeybox, LoadWrappedRSAKey) { ASSERT_EQ(OEMCrypto_SUCCESS, sts); } -TEST_F(DISABLED_TestKeybox, RSASignature) { - OEMCryptoResult sts; - std::vector wrapped_rsa_key; - CreateWrappedRSAKey(&wrapped_rsa_key, kSign_RSASSA_PSS, true); - - Session s; - s.open(); - sts = OEMCrypto_LoadDeviceRSAKey(s.session_id(), &wrapped_rsa_key[0], - wrapped_rsa_key.size()); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - - // Sign a Message - vector licenseRequest(500); - OEMCrypto_GetRandom(&licenseRequest[0], licenseRequest.size()); - size_t signature_length = 0; - - uint8_t signature[500]; - - sts = OEMCrypto_GenerateRSASignature(s.session_id(), &licenseRequest[0], - licenseRequest.size(), signature, - &signature_length, kSign_RSASSA_PSS); - - ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); - ASSERT_NE(static_cast(0), signature_length); - ASSERT_GE(sizeof(signature), signature_length); - - sts = OEMCrypto_GenerateRSASignature(s.session_id(), &licenseRequest[0], - licenseRequest.size(), signature, - &signature_length, kSign_RSASSA_PSS); - - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - // In the real world, the signature above would just have been used to contact - // the license server to get this response. - s.PreparePublicKey(); - s.VerifyRSASignature(&licenseRequest[0], licenseRequest.size(), signature, - signature_length, kSign_RSASSA_PSS); -} - -TEST_F(DISABLED_TestKeybox, LoadRSASessionKey) { +// This tests that a device with a keybox can also decrypt with a cert. +// Decrypt for devices that only use a cert are tested in the session tests. +TEST_F(OEMCryptoLoadsCertificate, CertificateDecrypt) { std::vector wrapped_rsa_key; CreateWrappedRSAKey(&wrapped_rsa_key, kSign_RSASSA_PSS, true); Session s; s.open(); s.InstallRSASessionTestKey(wrapped_rsa_key); -} - -TEST_F(DISABLED_TestKeybox, CertificateDecrypt) { - OEMCryptoResult sts; - std::vector wrapped_rsa_key; - CreateWrappedRSAKey(&wrapped_rsa_key, kSign_RSASSA_PSS, true); - Session s; - s.open(); - - s.InstallRSASessionTestKey(wrapped_rsa_key); s.FillSimpleMessage(kDuration, 0, 0); s.EncryptAndSign(); s.LoadTestKeys(); s.TestDecryptCTR(); } -// This test attempts to use alternate algorithms for main device certs. -class DISABLED_AlternateRSAAlgorithms : public DISABLED_TestKeybox { +class OEMCryptoUsesCertificate : public OEMCryptoLoadsCertificate { + protected: + virtual void SetUp() { + OEMCryptoLoadsCertificate::SetUp(); + session_.open(); + if (global_features.derive_key_method + != DeviceFeatures::LOAD_TEST_RSA_KEY) { + std::vector wrapped_rsa_key; + CreateWrappedRSAKey(&wrapped_rsa_key, kSign_RSASSA_PSS, true); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_LoadDeviceRSAKey(session_.session_id(), + &wrapped_rsa_key[0], + wrapped_rsa_key.size())); + } + } + + virtual void TearDown() { + session_.close(); + OEMCryptoLoadsCertificate::TearDown(); + } + + Session session_; +}; + +TEST_F(OEMCryptoUsesCertificate, RSASignature) { + OEMCryptoResult sts; + // Sign a Message + vector licenseRequest(500); + OEMCrypto_GetRandom(&licenseRequest[0], licenseRequest.size()); + size_t signature_length = 0; + uint8_t signature[500]; + + sts = OEMCrypto_GenerateRSASignature(session_.session_id(), + &licenseRequest[0], + licenseRequest.size(), signature, + &signature_length, kSign_RSASSA_PSS); + + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); + ASSERT_NE(static_cast(0), signature_length); + ASSERT_GE(sizeof(signature), signature_length); + + sts = OEMCrypto_GenerateRSASignature(session_.session_id(), &licenseRequest[0], + licenseRequest.size(), signature, + &signature_length, kSign_RSASSA_PSS); + + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + // In the real world, the signature above would just have been used to contact + // the license server to get this response. + session_.PreparePublicKey(); + session_.VerifyRSASignature(&licenseRequest[0], licenseRequest.size(), signature, + signature_length, kSign_RSASSA_PSS); +} + +// This test attempts to use alternate algorithms for loaded device certs. +class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { protected: void DisallowForbiddenPadding(RSA_Padding_Scheme scheme, size_t size) { OEMCryptoResult sts; @@ -2907,31 +3045,28 @@ class DISABLED_AlternateRSAAlgorithms : public DISABLED_TestKeybox { bool key_loaded_; }; -TEST_F(DISABLED_AlternateRSAAlgorithms, DisallowForbiddenPadding) { +TEST_F(OEMCryptoLoadsCertificateAlternates, DisallowForbiddenPadding) { LoadWithAllowedSchemes(kSign_RSASSA_PSS, true); // Use default padding scheme DisallowForbiddenPadding(kSign_PKCS1_Block1, 50); } -TEST_F(DISABLED_AlternateRSAAlgorithms, TestSignaturePKCS1) { +// TODO(fredgc): Clean this up a bit. Still need to test signature algorithms +// if uses_certificate but not loads_certificate. +TEST_F(OEMCryptoLoadsCertificateAlternates, TestSignaturePKCS1) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); + if (global_features.cast_receiver) ASSERT_TRUE(key_loaded_); if (key_loaded_) { - cout << "===============================================================\n" - << "== This device does load x509 Certs, I'll test them. ===\n" - << "===============================================================\n"; DisallowForbiddenPadding(kSign_RSASSA_PSS, 83); DisallowDeriveKeys(); TestSignature(kSign_PKCS1_Block1, 83); TestSignature(kSign_PKCS1_Block1, 50); DisallowForbiddenPadding(kSign_PKCS1_Block1, 84); // too big. - } else { - cout << "===============================================================\n" - << "== This device does not load x509 Certs! ===\n" - << "===============================================================\n"; } } -TEST_F(DISABLED_AlternateRSAAlgorithms, TestSignatureBoth) { +TEST_F(OEMCryptoLoadsCertificateAlternates, TestSignatureBoth) { LoadWithAllowedSchemes(kSign_RSASSA_PSS | kSign_PKCS1_Block1, false); + if (global_features.cast_receiver) ASSERT_TRUE(key_loaded_); if (key_loaded_) { DisallowDeriveKeys(); TestSignature(kSign_RSASSA_PSS, 200); @@ -2942,7 +3077,7 @@ TEST_F(DISABLED_AlternateRSAAlgorithms, TestSignatureBoth) { } // This tests attempts to use alternate algorithms for main device certs. -class DISABLED_AlternateRSAKey : public DISABLED_TestKeybox { +class OEMCryptoCastReceiverTest : public OEMCryptoLoadsCertificate { protected: vector encode(uint8_t type, const vector& substring) { vector result; @@ -3197,6 +3332,7 @@ class DISABLED_AlternateRSAKey : public DISABLED_TestKeybox { CreateWrappedRSAKey(&wrapped_rsa_key_, schemes, force, &encoded_key_[0], encoded_key_.size()); key_loaded_ = (wrapped_rsa_key_.size() > 0); + ASSERT_TRUE(key_loaded_); } std::vector encoded_key_; @@ -3205,7 +3341,7 @@ class DISABLED_AlternateRSAKey : public DISABLED_TestKeybox { }; // # PKCS#1 v1.5 Signature Example 15.1 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_1) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_1) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3245,7 +3381,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_1) { } } // # PKCS#1 v1.5 Signature Example 15.2 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_2) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_2) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3281,7 +3417,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_2) { } // # PKCS#1 v1.5 Signature Example 15.3 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_3) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_3) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3323,7 +3459,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_3) { }; // # PKCS#1 v1.5 Signature Example 15.4 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_4) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_4) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3353,7 +3489,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_4) { } // # PKCS#1 v1.5 Signature Example 15.5 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_5) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_5) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex("bda3a1c79059eae598308d3df609"); @@ -3379,7 +3515,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_5) { } // # PKCS#1 v1.5 Signature Example 15.6 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_6) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_6) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3412,7 +3548,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_6) { } // # PKCS#1 v1.5 Signature Example 15.7 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_7) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_7) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3446,7 +3582,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_7) { } // # PKCS#1 v1.5 Signature Example 15.8 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_8) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_8) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3486,7 +3622,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_8) { } // # PKCS#1 v1.5 Signature Example 15.9 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_9) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_9) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3524,7 +3660,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_9) { } // # PKCS#1 v1.5 Signature Example 15.10 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_10) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_10) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3555,7 +3691,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_10) { } // # PKCS#1 v1.5 Signature Example 15.11 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_11) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_11) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3590,7 +3726,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_11) { } // # PKCS#1 v1.5 Signature Example 15.12 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_12) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_12) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3632,7 +3768,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_12) { } // # PKCS#1 v1.5 Signature Example 15.13 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_13) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_13) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3662,7 +3798,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_13) { } // # PKCS#1 v1.5 Signature Example 15.14 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_14) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_14) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3699,7 +3835,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_14) { } // # PKCS#1 v1.5 Signature Example 15.15 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_15) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_15) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3739,7 +3875,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_15) { } // # PKCS#1 v1.5 Signature Example 15.16 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_16) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_16) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3781,7 +3917,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_16) { } // # PKCS#1 v1.5 Signature Example 15.17 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_17) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_17) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3811,7 +3947,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_17) { } // # PKCS#1 v1.5 Signature Example 15.18 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_18) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_18) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3842,7 +3978,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_18) { } // # PKCS#1 v1.5 Signature Example 15.19 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_19) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_19) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3880,7 +4016,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_19) { } // # PKCS#1 v1.5 Signature Example 15.20 -TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_20) { +TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_20) { LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); if (key_loaded_) { vector message = wvcdm::a2b_hex( @@ -3917,7 +4053,7 @@ TEST_F(DISABLED_AlternateRSAKey, TestSignaturePKCS1_15_20) { } } -class DISABLED_GenericDRMTest : public DISABLED_TestKeybox { +class GenericCryptoTest : public OEMCryptoSessionTests { protected: static const size_t kBufferSize = 160; // multiple of encryption block size. uint8_t clear_buffer_[kBufferSize]; @@ -3972,7 +4108,7 @@ class DISABLED_GenericDRMTest : public DISABLED_TestKeybox { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); MakeFourKeys(&s); s.EncryptAndSign(); s.LoadTestKeys(); @@ -3993,7 +4129,7 @@ class DISABLED_GenericDRMTest : public DISABLED_TestKeybox { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); MakeFourKeys(&s); s.EncryptAndSign(); s.LoadTestKeys(); @@ -4013,7 +4149,7 @@ class DISABLED_GenericDRMTest : public DISABLED_TestKeybox { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); MakeFourKeys(&s); s.EncryptAndSign(); s.LoadTestKeys(); @@ -4036,7 +4172,7 @@ class DISABLED_GenericDRMTest : public DISABLED_TestKeybox { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); MakeFourKeys(&s); s.EncryptAndSign(); s.LoadTestKeys(); @@ -4055,20 +4191,20 @@ class DISABLED_GenericDRMTest : public DISABLED_TestKeybox { } }; -TEST_F(DISABLED_GenericDRMTest, GenericKeyLoad) { +TEST_F(GenericCryptoTest, GenericKeyLoad) { Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); MakeFourKeys(&s); s.EncryptAndSign(); s.LoadTestKeys(); } -TEST_F(DISABLED_GenericDRMTest, GenericKeyEncrypt) { +TEST_F(GenericCryptoTest, GenericKeyEncrypt) { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); MakeFourKeys(&s); s.EncryptAndSign(); s.LoadTestKeys(); @@ -4086,7 +4222,7 @@ TEST_F(DISABLED_GenericDRMTest, GenericKeyEncrypt) { ASSERT_EQ(0, memcmp(encrypted, expected_encrypted, kBufferSize)); } -TEST_F(DISABLED_GenericDRMTest, GenericKeyBadEncrypt) { +TEST_F(GenericCryptoTest, GenericKeyBadEncrypt) { BadEncrypt(0, OEMCrypto_HMAC_SHA256, kBufferSize); BadEncrypt(0, OEMCrypto_AES_CBC_128_NO_PADDING, kBufferSize - 10); BadEncrypt(1, OEMCrypto_AES_CBC_128_NO_PADDING, kBufferSize); @@ -4094,11 +4230,11 @@ TEST_F(DISABLED_GenericDRMTest, GenericKeyBadEncrypt) { BadEncrypt(3, OEMCrypto_AES_CBC_128_NO_PADDING, kBufferSize); } -TEST_F(DISABLED_GenericDRMTest, GenericKeyDecrypt) { +TEST_F(GenericCryptoTest, GenericKeyDecrypt) { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); MakeFourKeys(&s); s.EncryptAndSign(); s.LoadTestKeys(); @@ -4115,11 +4251,11 @@ TEST_F(DISABLED_GenericDRMTest, GenericKeyDecrypt) { ASSERT_EQ(0, memcmp(clear_buffer_, resultant, kBufferSize)); } -TEST_F(DISABLED_GenericDRMTest, GenericSecureToClear) { +TEST_F(GenericCryptoTest, GenericSecureToClear) { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); MakeFourKeys(&s); s.license().keys[1].control.control_bits |= htonl( wvoec_mock::kControlObserveDataPath | wvoec_mock::kControlDataPathSecure); @@ -4138,7 +4274,7 @@ TEST_F(DISABLED_GenericDRMTest, GenericSecureToClear) { ASSERT_NE(0, memcmp(clear_buffer_, resultant, kBufferSize)); } -TEST_F(DISABLED_GenericDRMTest, GenericKeyBadDecrypt) { +TEST_F(GenericCryptoTest, GenericKeyBadDecrypt) { BadDecrypt(1, OEMCrypto_HMAC_SHA256, kBufferSize); BadDecrypt(1, OEMCrypto_AES_CBC_128_NO_PADDING, kBufferSize - 10); BadDecrypt(0, OEMCrypto_AES_CBC_128_NO_PADDING, kBufferSize); @@ -4146,11 +4282,11 @@ TEST_F(DISABLED_GenericDRMTest, GenericKeyBadDecrypt) { BadDecrypt(3, OEMCrypto_AES_CBC_128_NO_PADDING, kBufferSize); } -TEST_F(DISABLED_GenericDRMTest, GenericKeySign) { +TEST_F(GenericCryptoTest, GenericKeySign) { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); MakeFourKeys(&s); s.EncryptAndSign(); s.LoadTestKeys(); @@ -4175,18 +4311,18 @@ TEST_F(DISABLED_GenericDRMTest, GenericKeySign) { ASSERT_EQ(0, memcmp(signature, expected_signature, SHA256_DIGEST_LENGTH)); } -TEST_F(DISABLED_GenericDRMTest, GenericKeyBadSign) { +TEST_F(GenericCryptoTest, GenericKeyBadSign) { BadSign(0, OEMCrypto_HMAC_SHA256); // Can't sign with encrypt key. BadSign(1, OEMCrypto_HMAC_SHA256); // Can't sign with decrypt key. BadSign(3, OEMCrypto_HMAC_SHA256); // Can't sign with verify key. BadSign(2, OEMCrypto_AES_CBC_128_NO_PADDING); // Bad signing algorithm. } -TEST_F(DISABLED_GenericDRMTest, GenericKeyVerify) { +TEST_F(GenericCryptoTest, GenericKeyVerify) { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); MakeFourKeys(&s); s.EncryptAndSign(); s.LoadTestKeys(); @@ -4203,7 +4339,7 @@ TEST_F(DISABLED_GenericDRMTest, GenericKeyVerify) { ASSERT_EQ(OEMCrypto_SUCCESS, sts); } -TEST_F(DISABLED_GenericDRMTest, GenericKeyBadVerify) { +TEST_F(GenericCryptoTest, GenericKeyBadVerify) { BadVerify(0, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH, false); BadVerify(1, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH, false); BadVerify(2, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH, false); @@ -4213,11 +4349,11 @@ TEST_F(DISABLED_GenericDRMTest, GenericKeyBadVerify) { BadVerify(3, OEMCrypto_AES_CBC_128_NO_PADDING, SHA256_DIGEST_LENGTH, false); } -TEST_F(DISABLED_GenericDRMTest, KeyDurationEncrypt) { +TEST_F(GenericCryptoTest, KeyDurationEncrypt) { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); MakeFourKeys(&s, kDuration); s.EncryptAndSign(); s.LoadTestKeys(); @@ -4249,11 +4385,11 @@ TEST_F(DISABLED_GenericDRMTest, KeyDurationEncrypt) { ASSERT_NE(0, memcmp(encrypted, expected_encrypted, kBufferSize)); } -TEST_F(DISABLED_GenericDRMTest, KeyDurationDecrypt) { +TEST_F(GenericCryptoTest, KeyDurationDecrypt) { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); MakeFourKeys(&s, kDuration); s.EncryptAndSign(); s.LoadTestKeys(); @@ -4283,11 +4419,11 @@ TEST_F(DISABLED_GenericDRMTest, KeyDurationDecrypt) { ASSERT_NE(0, memcmp(clear_buffer_, resultant, kBufferSize)); } -TEST_F(DISABLED_GenericDRMTest, KeyDurationSign) { +TEST_F(GenericCryptoTest, KeyDurationSign) { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); MakeFourKeys(&s, kDuration); s.EncryptAndSign(); s.LoadTestKeys(); @@ -4321,11 +4457,11 @@ TEST_F(DISABLED_GenericDRMTest, KeyDurationSign) { ASSERT_NE(0, memcmp(signature, expected_signature, SHA256_DIGEST_LENGTH)); } -TEST_F(DISABLED_GenericDRMTest, KeyDurationVerify) { +TEST_F(GenericCryptoTest, KeyDurationVerify) { OEMCryptoResult sts; Session s; s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); MakeFourKeys(&s, kDuration); s.EncryptAndSign(); s.LoadTestKeys(); @@ -4353,44 +4489,15 @@ TEST_F(DISABLED_GenericDRMTest, KeyDurationVerify) { ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, sts); } -TEST_F(OEMCryptoClientTest, SupportsUsageTable) { - if (OEMCrypto_SupportsUsageTable()) { - EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - cout << " OEMCrypto supports usage tables." << endl; - } else { - cout << " OEMCrypto does not support usage tables." << endl; - EXPECT_FALSE(wvcdm::Properties::oem_crypto_require_usage_tables()); - } +TEST_F(OEMCryptoClientTest, UpdateUsageTableTest) { + EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); } -TEST_F(OEMCryptoClientTest, PSTReportSizes) { - if (OEMCrypto_SupportsUsageTable()) { - OEMCrypto_PST_Report report; - uint8_t* location = reinterpret_cast(&report); - EXPECT_EQ(48u, sizeof(report)); - uint8_t *field; - field = reinterpret_cast(&report.status); - EXPECT_EQ(20, field - location); - field = reinterpret_cast(&report.clock_security_level); - EXPECT_EQ(21, field - location); - field = reinterpret_cast(&report.pst_length); - EXPECT_EQ(22, field - location); - field = reinterpret_cast(&report.seconds_since_license_received); - EXPECT_EQ(24, field - location); - field = reinterpret_cast(&report.seconds_since_first_decrypt); - EXPECT_EQ(32, field - location); - field = reinterpret_cast(&report.seconds_since_last_decrypt); - EXPECT_EQ(40, field - location); - field = reinterpret_cast(&report.pst); - EXPECT_EQ(48, field - location); - } -} - -class DISABLED_UsageTableTest : public DISABLED_GenericDRMTest, - public WithParamInterface { +class UsageTableTest : public GenericCryptoTest, + public WithParamInterface { public: virtual void SetUp() { - DISABLED_GenericDRMTest::SetUp(); + GenericCryptoTest::SetUp(); new_mac_keys_ = GetParam(); } @@ -4402,7 +4509,7 @@ class DISABLED_UsageTableTest : public DISABLED_GenericDRMTest, void LoadOfflineLicense(Session& s, const std::string& pst) { s.open(); - s.GenerateDerivedKeys(); + s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, wvoec_mock::kControlNonceOrEntry, s.get_nonce(), pst); s.EncryptAndSign(); s.LoadTestKeys(pst, new_mac_keys_); @@ -4435,1020 +4542,989 @@ class DISABLED_UsageTableTest : public DISABLED_GenericDRMTest, bool new_mac_keys_; }; -TEST_P(DISABLED_UsageTableTest, OnlineLicense) { - if (OEMCrypto_SupportsUsageTable()) { - std::string pst = "my_pst"; - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - s.open(); - s.GenerateDerivedKeys(); - s.FillSimpleMessage( - 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, - s.get_nonce(), pst); - s.EncryptAndSign(); - s.LoadTestKeys(pst, new_mac_keys_); - - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - s.GenerateReport(pst); - s.GenerateReport(pst); // test repeated report generation - s.GenerateReport(pst); - s.GenerateReport(pst); - EXPECT_EQ(kUnused, s.pst_report()->status); - EXPECT_ALMOST( - 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); - s.TestDecryptCTR(); - s.GenerateReport(pst); - EXPECT_EQ(kActive, s.pst_report()->status); - EXPECT_ALMOST( - 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); - EXPECT_ALMOST(0, - wvcdm::htonll64(s.pst_report()->seconds_since_first_decrypt)); - EXPECT_ALMOST(0, - wvcdm::htonll64(s.pst_report()->seconds_since_last_decrypt)); - DeactivatePST(pst); - s.GenerateReport(pst); - EXPECT_EQ(kInactive, s.pst_report()->status); - EXPECT_ALMOST( - 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); - s.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE); - } +TEST_P(UsageTableTest, PSTReportSizes) { + OEMCrypto_PST_Report report; + uint8_t* location = reinterpret_cast(&report); + EXPECT_EQ(48u, sizeof(report)); + uint8_t *field; + field = reinterpret_cast(&report.status); + EXPECT_EQ(20, field - location); + field = reinterpret_cast(&report.clock_security_level); + EXPECT_EQ(21, field - location); + field = reinterpret_cast(&report.pst_length); + EXPECT_EQ(22, field - location); + field = reinterpret_cast(&report.seconds_since_license_received); + EXPECT_EQ(24, field - location); + field = reinterpret_cast(&report.seconds_since_first_decrypt); + EXPECT_EQ(32, field - location); + field = reinterpret_cast(&report.seconds_since_last_decrypt); + EXPECT_EQ(40, field - location); + field = reinterpret_cast(&report.pst); + EXPECT_EQ(48, field - location); } -TEST_P(DISABLED_UsageTableTest, RepeatOnlineLicense) { - if (OEMCrypto_SupportsUsageTable()) { - std::string pst = "my_pst"; - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - s.open(); - s.GenerateDerivedKeys(); - s.FillSimpleMessage( - 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, - s.get_nonce(), pst); - s.EncryptAndSign(); - s.LoadTestKeys(pst, new_mac_keys_); +TEST_P(UsageTableTest, OnlineLicense) { + std::string pst = "my_pst"; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + s.FillSimpleMessage( + 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, + s.get_nonce(), pst); + s.EncryptAndSign(); + s.LoadTestKeys(pst, new_mac_keys_); - s.close(); - Session s2; - s2.open(); - s2.GenerateDerivedKeys(); - uint8_t* pst_ptr = s.encrypted_license().pst; - // Trying to reuse a PST is bad. We use session ID for s2, everything else - // reused from s. - ASSERT_NE(OEMCrypto_SUCCESS, - OEMCrypto_LoadKeys(s2.session_id(), s.message_ptr(), - sizeof(MessageData), &s.signature()[0], - s.signature().size(), - s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, kNumKeys, - s.key_array(), pst_ptr, pst.length())); - s2.close(); - } + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + s.GenerateReport(pst); + s.GenerateReport(pst); // test repeated report generation + s.GenerateReport(pst); + s.GenerateReport(pst); + EXPECT_EQ(kUnused, s.pst_report()->status); + EXPECT_ALMOST( + 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); + s.TestDecryptCTR(); + s.GenerateReport(pst); + EXPECT_EQ(kActive, s.pst_report()->status); + EXPECT_ALMOST( + 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); + EXPECT_ALMOST(0, + wvcdm::htonll64(s.pst_report()->seconds_since_first_decrypt)); + EXPECT_ALMOST(0, + wvcdm::htonll64(s.pst_report()->seconds_since_last_decrypt)); + DeactivatePST(pst); + s.GenerateReport(pst); + EXPECT_EQ(kInactive, s.pst_report()->status); + EXPECT_ALMOST( + 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); + s.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE); +} + +TEST_P(UsageTableTest, RepeatOnlineLicense) { + std::string pst = "my_pst"; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + s.FillSimpleMessage( + 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, + s.get_nonce(), pst); + s.EncryptAndSign(); + s.LoadTestKeys(pst, new_mac_keys_); + + s.close(); + Session s2; + s2.open(); + s2.GenerateTestSessionKeys(); + uint8_t* pst_ptr = s.encrypted_license().pst; + // Trying to reuse a PST is bad. We use session ID for s2, everything else + // reused from s. + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_LoadKeys(s2.session_id(), s.message_ptr(), + sizeof(MessageData), &s.signature()[0], + s.signature().size(), + s.encrypted_license().mac_key_iv, + s.encrypted_license().mac_keys, kNumKeys, + s.key_array(), pst_ptr, pst.length())); + s2.close(); } // A license with non-zero replay control bits needs a valid pst.. -TEST_P(DISABLED_UsageTableTest, OnlineEmptyPST) { - if (OEMCrypto_SupportsUsageTable()) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - s.open(); - s.GenerateDerivedKeys(); - s.FillSimpleMessage( +TEST_P(UsageTableTest, OnlineEmptyPST) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + s.FillSimpleMessage( + 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, + s.get_nonce()); + s.EncryptAndSign(); + OEMCryptoResult sts = OEMCrypto_LoadKeys( + s.session_id(), s.message_ptr(), sizeof(MessageData), &s.signature()[0], + s.signature().size(), s.encrypted_license().mac_key_iv, + s.encrypted_license().mac_keys, kNumKeys, s.key_array(), + NULL, 0); + ASSERT_NE(OEMCrypto_SUCCESS, sts); + s.close(); +} + +TEST_P(UsageTableTest, EmptyTable) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + std::string pst = "no_pst"; + s.FillSimpleMessage( + 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, + s.get_nonce(), pst); + s.EncryptAndSign(); + s.LoadTestKeys(pst, new_mac_keys_); + s.GenerateReport(pst); + s.close(); + OEMCrypto_DeleteUsageTable(); + Session s2; + s2.open(); + s2.GenerateReport(pst, false); + s2.close(); +} + +TEST_P(UsageTableTest, FiftyEntries) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s1; + s1.open(); + s1.GenerateTestSessionKeys(); + std::string pst1 = "pst saved"; + s1.FillSimpleMessage( + 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, + s1.get_nonce(), pst1); + s1.EncryptAndSign(); + s1.LoadTestKeys(pst1, new_mac_keys_); + sleep(kShortSleep); + + const size_t ENTRY_COUNT = 49;// API says should hold at least 50 entries. + Session sessions[ENTRY_COUNT]; + for (size_t i=0; i < ENTRY_COUNT; i++) { + sessions[i].open(); + sessions[i].GenerateTestSessionKeys(); + std::string pst = "pst "; + char c = 'A' + i; + pst = pst + c; + sessions[i].FillSimpleMessage( 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, - s.get_nonce()); - s.EncryptAndSign(); - OEMCryptoResult sts = OEMCrypto_LoadKeys( - s.session_id(), s.message_ptr(), sizeof(MessageData), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, kNumKeys, s.key_array(), - NULL, 0); - ASSERT_NE(OEMCrypto_SUCCESS, sts); - s.close(); + sessions[i].get_nonce(), pst); + sessions[i].EncryptAndSign(); + sessions[i].LoadTestKeys(pst, new_mac_keys_); + sessions[i].GenerateReport(pst); + sessions[i].close(); } -} - -TEST_P(DISABLED_UsageTableTest, EmptyTable) { - if (OEMCrypto_SupportsUsageTable()) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + for (size_t i=0; istatus); - s.close(); - } - sleep(kShortSleep); - // If I add too many entries, it can delete the older ones first, except - // it shouldn't delete the one attached to an open session. (s1) - for (size_t i=0; i < ENTRY_COUNT; i++) { - sessions[i].open(); - sessions[i].GenerateDerivedKeys(); - std::string pst = "newer pst "; - char c = 'A' + i; - pst = pst + c; - sessions[i].FillSimpleMessage( - 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, - sessions[i].get_nonce(), pst); - sessions[i].EncryptAndSign(); - sessions[i].LoadTestKeys(pst, new_mac_keys_); - sessions[i].GenerateReport(pst); - sessions[i].close(); - } - for (int i=0; i<49; i++) { - Session s; - s.open(); - std::string pst = "newer pst "; - char c = 'A' + i; - pst = pst + c; - s.GenerateReport(pst, true, &sessions[i]); - EXPECT_EQ(kUnused, s.pst_report()->status); - s.close(); - } - s1.close(); - s1.open(); // Make sure s1's entry is still in the table. - s1.GenerateReport(pst1); - EXPECT_EQ(kUnused, s1.pst_report()->status); - s1.close(); - } -} - -TEST_P(DISABLED_UsageTableTest, DeleteUnusedEntry) { - if (OEMCrypto_SupportsUsageTable()) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - s.open(); - s.GenerateDerivedKeys(); - std::string pst = "my pst"; - s.FillSimpleMessage( - 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, - s.get_nonce(), pst); - s.EncryptAndSign(); - s.LoadTestKeys(pst, new_mac_keys_); - s.GenerateReport(pst); - s.close(); - - // New session should be able to generate report and copy mac keys. - Session s2; - s2.open(); - s2.GenerateReport(pst, true, &s); - EXPECT_EQ(kUnused, s2.pst_report()->status); - s2.DeleteEntry(pst); - s2.close(); - - // Now that session is deleted, we can't generate a report for it. - Session s3; - s3.open(); - s3.GenerateReport(pst, false); - s3.close(); - } -} - -TEST_P(DISABLED_UsageTableTest, DeleteActiveEntry) { - if (OEMCrypto_SupportsUsageTable()) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - s.open(); - s.GenerateDerivedKeys(); - std::string pst = "my pst"; - s.FillSimpleMessage( - 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, - s.get_nonce(), pst); - s.EncryptAndSign(); - s.LoadTestKeys(pst, new_mac_keys_); - s.TestDecryptCTR(); - s.GenerateReport(pst); - s.close(); - - // New session should be able to generate report and copy mac keys. - Session s2; - s2.open(); - s2.GenerateReport(pst, true, &s); - EXPECT_EQ(kActive, s2.pst_report()->status); - s2.DeleteEntry(pst); - s2.close(); - - // Now that session is deleted, we can't generate a report for it. - Session s3; - s3.open(); - s3.GenerateReport(pst, false); - s3.close(); - } -} - -TEST_P(DISABLED_UsageTableTest, ForceDeleteActiveEntry) { - if (OEMCrypto_SupportsUsageTable()) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - s.open(); - s.GenerateDerivedKeys(); - std::string pst = "my pst"; - s.FillSimpleMessage( - 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, - s.get_nonce(), pst); - s.EncryptAndSign(); - s.LoadTestKeys(pst, new_mac_keys_); - s.TestDecryptCTR(); - s.GenerateReport(pst); - s.close(); - - s.ForceDeleteEntry(pst); - - // Now that session is deleted, we can't generate a report for it. - Session s3; - s3.open(); - s3.GenerateReport(pst, false); - s3.close(); - } -} - -TEST_P(DISABLED_UsageTableTest, DeleteInactiveEntry) { - if (OEMCrypto_SupportsUsageTable()) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - s.open(); - s.GenerateDerivedKeys(); - std::string pst = "my pst"; - s.FillSimpleMessage( - 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, - s.get_nonce(), pst); - s.EncryptAndSign(); - s.LoadTestKeys(pst, new_mac_keys_); - s.GenerateReport(pst); - s.TestDecryptCTR(); - DeactivatePST(pst); - s.close(); - - // New session should be able to generate report and copy mac keys. - Session s2; - s2.open(); - s2.GenerateReport(pst, true, &s); - EXPECT_EQ(kInactive, s2.pst_report()->status); - s2.DeleteEntry(pst); - s2.close(); - - // Now that session is deleted, we can't generate a report for it. - Session s3; - s3.open(); - s3.GenerateReport(pst, false); - s3.close(); - } -} - -TEST_P(DISABLED_UsageTableTest, DeleteEntryBadSignature) { - if (OEMCrypto_SupportsUsageTable()) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - s.open(); - s.GenerateDerivedKeys(); - std::string pst = "my pst"; - s.FillSimpleMessage( - 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, - s.get_nonce(), pst); - s.EncryptAndSign(); - s.LoadTestKeys(pst, new_mac_keys_); - s.GenerateReport(pst); - s.close(); - - // New session should be able to generate report and copy mac keys. - Session s2; - s2.open(); - s2.GenerateReport(pst, true, &s); - uint8_t* pst_ptr = s2.encrypted_license().pst; - memcpy(pst_ptr, pst.c_str(), min(sizeof(s2.license().pst), pst.length())); - std::vector signature(SHA256_DIGEST_LENGTH); - // Cannot delete without correct signature. - // ServerSignMessage(s2.encrypted_license(), &signature); - ASSERT_NE(OEMCrypto_SUCCESS, - OEMCrypto_DeleteUsageEntry(s2.session_id(), pst_ptr, pst.length(), - s2.message_ptr(), sizeof(MessageData), - &signature[0], signature.size())); - s2.close(); - - // The session is not deleted, we can still generate a report for it. - Session s3; - s3.open(); - s3.GenerateReport(pst, true, &s); - EXPECT_EQ(kUnused, s3.pst_report()->status); - s3.close(); - } -} - -TEST_P(DISABLED_UsageTableTest, DeleteEntryWrongSession) { - if (OEMCrypto_SupportsUsageTable()) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - s.open(); - s.GenerateDerivedKeys(); - std::string pst = "my pst"; - s.FillSimpleMessage( - 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, - s.get_nonce(), pst); - s.EncryptAndSign(); - s.LoadTestKeys(pst, new_mac_keys_); - s.GenerateReport(pst); - s.close(); - - // New session should not be able to delete without using GenerateReport - // to load mac keys. - Session s2; - s2.open(); - // s2.GenerateReport(pst, true, &s); - uint8_t* pst_ptr = s2.encrypted_license().pst; - memcpy(pst_ptr, pst.c_str(), min(sizeof(s2.license().pst), pst.length())); - std::vector signature(SHA256_DIGEST_LENGTH); - s2.ServerSignMessage(s2.encrypted_license(), &signature); - ASSERT_NE(OEMCrypto_SUCCESS, - OEMCrypto_DeleteUsageEntry(s2.session_id(), pst_ptr, pst.length(), - s2.message_ptr(), sizeof(MessageData), - &signature[0], signature.size())); - s2.close(); - - // The session is not deleted, we can still generate a report for it. - Session s3; - s3.open(); - s3.GenerateReport(pst, true, &s); - EXPECT_EQ(kUnused, s3.pst_report()->status); - s3.close(); - } -} - -TEST_P(DISABLED_UsageTableTest, DeleteEntryBadRange) { - if (OEMCrypto_SupportsUsageTable()) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - s.open(); - s.GenerateDerivedKeys(); - std::string pst = "my pst"; - s.FillSimpleMessage( - 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, - s.get_nonce(), pst); - s.EncryptAndSign(); - s.LoadTestKeys(pst, new_mac_keys_); - s.GenerateReport(pst); - s.close(); - - // New session should not be able to delete if pst doesn't point into - // message. - Session s2; - s2.open(); - s2.GenerateReport(pst, true, &s); - uint8_t* pst_ptr = s2.license().pst; - memcpy(pst_ptr, pst.c_str(), min(sizeof(s2.license().pst), pst.length())); - std::vector signature(SHA256_DIGEST_LENGTH); - s2.ServerSignMessage(s2.encrypted_license(), &signature); - ASSERT_NE(OEMCrypto_SUCCESS, - OEMCrypto_DeleteUsageEntry(s2.session_id(), pst_ptr, pst.length(), - s2.message_ptr(), sizeof(MessageData), - &signature[0], signature.size())); - s2.close(); - - // The session is not deleted, we can still generate a report for it. - Session s3; - s3.open(); - s3.GenerateReport(pst, true, &s); - EXPECT_EQ(kUnused, s3.pst_report()->status); - s3.close(); - } -} - -TEST_P(DISABLED_UsageTableTest, DeactivateBadPST) { - if (OEMCrypto_SupportsUsageTable()) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - std::string pst = "nonexistant pst"; - OEMCryptoResult sts = OEMCrypto_DeactivateUsageEntry( - reinterpret_cast(pst.c_str()), pst.length()); - EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts); - std::string null_pst = ""; - sts = OEMCrypto_DeactivateUsageEntry( - reinterpret_cast(null_pst.c_str()), null_pst.length()); - EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts); - } -} - -TEST_P(DISABLED_UsageTableTest, GenericEncrypt) { - if (OEMCrypto_SupportsUsageTable()) { - std::string pst = "A PST"; - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - s.open(); - s.GenerateDerivedKeys(); - uint32_t nonce = s.get_nonce(); - MakeFourKeys(&s, 0, wvoec_mock::kControlNonceEnabled | - wvoec_mock::kControlNonceRequired, - nonce, pst); - s.EncryptAndSign(); - s.LoadTestKeys(pst, new_mac_keys_); - OEMCryptoResult sts; - unsigned int key_index = 0; - uint8_t expected_encrypted[kBufferSize]; - EncryptBuffer(&s, key_index, clear_buffer_, expected_encrypted); - sts = OEMCrypto_SelectKey( - s.session_id(), s.license().keys[key_index].key_id, kTestKeyIdLength); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - uint8_t encrypted[kBufferSize]; - sts = OEMCrypto_Generic_Encrypt(s.session_id(), clear_buffer_, kBufferSize, - iv_, OEMCrypto_AES_CBC_128_NO_PADDING, - encrypted); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - EXPECT_EQ(0, memcmp(encrypted, expected_encrypted, kBufferSize)); - s.GenerateReport(pst); - EXPECT_EQ(kActive, s.pst_report()->status); - EXPECT_ALMOST( - 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); - EXPECT_ALMOST(0, - wvcdm::htonll64(s.pst_report()->seconds_since_first_decrypt)); - EXPECT_ALMOST(0, - wvcdm::htonll64(s.pst_report()->seconds_since_last_decrypt)); - DeactivatePST(pst); - s.GenerateReport(pst); - EXPECT_EQ(kInactive, s.pst_report()->status); - EXPECT_ALMOST( - 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); - memset(encrypted, 0, kBufferSize); - sts = OEMCrypto_Generic_Encrypt(s.session_id(), clear_buffer_, kBufferSize, - iv_, OEMCrypto_AES_CBC_128_NO_PADDING, - encrypted); - ASSERT_NE(OEMCrypto_SUCCESS, sts); - EXPECT_NE(0, memcmp(encrypted, expected_encrypted, kBufferSize)); - } -} - -TEST_P(DISABLED_UsageTableTest, GenericDecrypt) { - if (OEMCrypto_SupportsUsageTable()) { - std::string pst = "my_pst"; - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - s.open(); - s.GenerateDerivedKeys(); - uint32_t nonce = s.get_nonce(); - MakeFourKeys(&s, 0, wvoec_mock::kControlNonceEnabled | - wvoec_mock::kControlNonceRequired, - nonce, pst); - s.EncryptAndSign(); - s.LoadTestKeys(pst, new_mac_keys_); - OEMCryptoResult sts; - unsigned int key_index = 1; - uint8_t encrypted[kBufferSize]; - EncryptBuffer(&s, key_index, clear_buffer_, encrypted); - sts = OEMCrypto_SelectKey( - s.session_id(), s.license().keys[key_index].key_id, kTestKeyIdLength); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - uint8_t resultant[kBufferSize]; - sts = - OEMCrypto_Generic_Decrypt(s.session_id(), encrypted, kBufferSize, iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, resultant); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - EXPECT_EQ(0, memcmp(clear_buffer_, resultant, kBufferSize)); - s.GenerateReport(pst); - EXPECT_EQ(kActive, s.pst_report()->status); - EXPECT_ALMOST( - 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); - EXPECT_ALMOST(0, - wvcdm::htonll64(s.pst_report()->seconds_since_first_decrypt)); - EXPECT_ALMOST(0, - wvcdm::htonll64(s.pst_report()->seconds_since_last_decrypt)); - DeactivatePST(pst); - s.GenerateReport(pst); - EXPECT_EQ(kInactive, s.pst_report()->status); - EXPECT_ALMOST( - 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); - memset(resultant, 0, kBufferSize); - sts = - OEMCrypto_Generic_Decrypt(s.session_id(), encrypted, kBufferSize, iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, resultant); - ASSERT_NE(OEMCrypto_SUCCESS, sts); - EXPECT_NE(0, memcmp(clear_buffer_, resultant, kBufferSize)); - } -} - -TEST_P(DISABLED_UsageTableTest, GenericSign) { - if (OEMCrypto_SupportsUsageTable()) { - std::string pst = "my_pst"; - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - s.open(); - s.GenerateDerivedKeys(); - uint32_t nonce = s.get_nonce(); - MakeFourKeys(&s, 0, wvoec_mock::kControlNonceEnabled | - wvoec_mock::kControlNonceRequired, - nonce, pst); - s.EncryptAndSign(); - s.LoadTestKeys(pst, new_mac_keys_); - - OEMCryptoResult sts; - unsigned int key_index = 2; - uint8_t expected_signature[SHA256_DIGEST_LENGTH]; - SignBuffer(&s, key_index, clear_buffer_, expected_signature); - - sts = OEMCrypto_SelectKey( - s.session_id(), s.license().keys[key_index].key_id, kTestKeyIdLength); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - size_t gen_signature_length = 0; - sts = OEMCrypto_Generic_Sign(s.session_id(), clear_buffer_, kBufferSize, - OEMCrypto_HMAC_SHA256, NULL, - &gen_signature_length); - ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); - ASSERT_EQ(static_cast(SHA256_DIGEST_LENGTH), gen_signature_length); - uint8_t signature[SHA256_DIGEST_LENGTH]; - sts = OEMCrypto_Generic_Sign(s.session_id(), clear_buffer_, kBufferSize, - OEMCrypto_HMAC_SHA256, signature, - &gen_signature_length); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - ASSERT_EQ(0, memcmp(signature, expected_signature, SHA256_DIGEST_LENGTH)); - - s.GenerateReport(pst); - EXPECT_EQ(kActive, s.pst_report()->status); - EXPECT_ALMOST( - 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); - EXPECT_ALMOST(0, - wvcdm::htonll64(s.pst_report()->seconds_since_first_decrypt)); - EXPECT_ALMOST(0, - wvcdm::htonll64(s.pst_report()->seconds_since_last_decrypt)); - DeactivatePST(pst); - s.GenerateReport(pst); - EXPECT_EQ(kInactive, s.pst_report()->status); - EXPECT_ALMOST( - 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); - - memset(signature, 0, SHA256_DIGEST_LENGTH); - gen_signature_length = SHA256_DIGEST_LENGTH; - sts = OEMCrypto_Generic_Sign(s.session_id(), clear_buffer_, kBufferSize, - OEMCrypto_HMAC_SHA256, signature, - &gen_signature_length); - ASSERT_NE(OEMCrypto_SUCCESS, sts); - ASSERT_NE(0, memcmp(signature, expected_signature, SHA256_DIGEST_LENGTH)); - } -} - -TEST_P(DISABLED_UsageTableTest, GenericVerify) { - if (OEMCrypto_SupportsUsageTable()) { - std::string pst = "my_pst"; - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - s.open(); - s.GenerateDerivedKeys(); - uint32_t nonce = s.get_nonce(); - MakeFourKeys(&s, 0, wvoec_mock::kControlNonceEnabled | - wvoec_mock::kControlNonceRequired, - nonce, pst); - s.EncryptAndSign(); - s.LoadTestKeys(pst, new_mac_keys_); - - OEMCryptoResult sts; - unsigned int key_index = 3; - uint8_t signature[SHA256_DIGEST_LENGTH]; - SignBuffer(&s, key_index, clear_buffer_, signature); - - sts = OEMCrypto_SelectKey( - s.session_id(), s.license().keys[key_index].key_id, kTestKeyIdLength); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - sts = OEMCrypto_Generic_Verify(s.session_id(), clear_buffer_, kBufferSize, - OEMCrypto_HMAC_SHA256, signature, - SHA256_DIGEST_LENGTH); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - - s.GenerateReport(pst); - EXPECT_EQ(kActive, s.pst_report()->status); - EXPECT_ALMOST( - 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); - EXPECT_ALMOST(0, - wvcdm::htonll64(s.pst_report()->seconds_since_first_decrypt)); - EXPECT_ALMOST(0, - wvcdm::htonll64(s.pst_report()->seconds_since_last_decrypt)); - DeactivatePST(pst); - s.GenerateReport(pst); - EXPECT_EQ(kInactive, s.pst_report()->status); - EXPECT_ALMOST( - 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); - - sts = OEMCrypto_Generic_Verify(s.session_id(), clear_buffer_, kBufferSize, - OEMCrypto_HMAC_SHA256, signature, - SHA256_DIGEST_LENGTH); - ASSERT_NE(OEMCrypto_SUCCESS, sts); - } -} - -TEST_P(DISABLED_UsageTableTest, OfflineLicense) { - if (OEMCrypto_SupportsUsageTable()) { - std::string pst = "my_pst"; - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - LoadOfflineLicense(s, pst); - } -} - -TEST_P(DISABLED_UsageTableTest, ReloadOfflineLicense) { - if (OEMCrypto_SupportsUsageTable()) { - std::string pst = "my_pst"; - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - LoadOfflineLicense(s, pst); - - s.open(); // Offline license can be reused. - s.GenerateDerivedKeys(); - // We will reuse the encrypted and signed message, so we don't call - // FillSimpleMessage again. - s.LoadTestKeys(pst, new_mac_keys_); - s.GenerateReport(pst); - s.GenerateReport(pst); + std::string pst = "pst "; + char c = 'A' + i; + pst = pst + c; + s.GenerateReport(pst, true, &sessions[i]); EXPECT_EQ(kUnused, s.pst_report()->status); - EXPECT_ALMOST( - 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); - s.TestDecryptCTR(); - s.GenerateReport(pst); - EXPECT_EQ(kActive, s.pst_report()->status); - EXPECT_ALMOST( - 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); - EXPECT_ALMOST(0, - wvcdm::htonll64(s.pst_report()->seconds_since_first_decrypt)); - EXPECT_ALMOST(0, - wvcdm::htonll64(s.pst_report()->seconds_since_last_decrypt)); s.close(); } + sleep(kShortSleep); + // If I add too many entries, it can delete the older ones first, except + // it shouldn't delete the one attached to an open session. (s1) + for (size_t i=0; i < ENTRY_COUNT; i++) { + sessions[i].open(); + sessions[i].GenerateTestSessionKeys(); + std::string pst = "newer pst "; + char c = 'A' + i; + pst = pst + c; + sessions[i].FillSimpleMessage( + 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, + sessions[i].get_nonce(), pst); + sessions[i].EncryptAndSign(); + sessions[i].LoadTestKeys(pst, new_mac_keys_); + sessions[i].GenerateReport(pst); + sessions[i].close(); + } + for (int i=0; i<49; i++) { + Session s; + s.open(); + std::string pst = "newer pst "; + char c = 'A' + i; + pst = pst + c; + s.GenerateReport(pst, true, &sessions[i]); + EXPECT_EQ(kUnused, s.pst_report()->status); + s.close(); + } + s1.close(); + s1.open(); // Make sure s1's entry is still in the table. + s1.GenerateReport(pst1); + EXPECT_EQ(kUnused, s1.pst_report()->status); + s1.close(); } -TEST_P(DISABLED_UsageTableTest, BadReloadOfflineLicense) { - if (OEMCrypto_SupportsUsageTable()) { - std::string pst = "my_pst"; - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - LoadOfflineLicense(s, pst); +TEST_P(UsageTableTest, DeleteUnusedEntry) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + std::string pst = "my pst"; + s.FillSimpleMessage( + 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, + s.get_nonce(), pst); + s.EncryptAndSign(); + s.LoadTestKeys(pst, new_mac_keys_); + s.GenerateReport(pst); + s.close(); - // Offline license with new mac keys should fail. - Session s2; - s2.open(); - s2.GenerateDerivedKeys(); - s2.FillSimpleMessage(0, wvoec_mock::kControlNonceOrEntry, - s2.get_nonce(), pst); - s2.EncryptAndSign(); - uint8_t* pst_ptr = s2.encrypted_license().pst; - ASSERT_NE(OEMCrypto_SUCCESS, - OEMCrypto_LoadKeys(s2.session_id(), s2.message_ptr(), - sizeof(MessageData), &s2.signature()[0], - s2.signature().size(), - s2.encrypted_license().mac_key_iv, - s2.encrypted_license().mac_keys, kNumKeys, - s2.key_array(), pst_ptr, pst.length())); - s2.close(); + // New session should be able to generate report and copy mac keys. + Session s2; + s2.open(); + s2.GenerateReport(pst, true, &s); + EXPECT_EQ(kUnused, s2.pst_report()->status); + s2.DeleteEntry(pst); + s2.close(); - // Offline license with same mac keys should still be OK. - s.open(); - s.GenerateDerivedKeys(); - s.LoadTestKeys(pst, new_mac_keys_); - s.GenerateReport(pst); - EXPECT_EQ(kUnused, s.pst_report()->status); - } + // Now that session is deleted, we can't generate a report for it. + Session s3; + s3.open(); + s3.GenerateReport(pst, false); + s3.close(); +} + +TEST_P(UsageTableTest, DeleteActiveEntry) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + std::string pst = "my pst"; + s.FillSimpleMessage( + 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, + s.get_nonce(), pst); + s.EncryptAndSign(); + s.LoadTestKeys(pst, new_mac_keys_); + s.TestDecryptCTR(); + s.GenerateReport(pst); + s.close(); + + // New session should be able to generate report and copy mac keys. + Session s2; + s2.open(); + s2.GenerateReport(pst, true, &s); + EXPECT_EQ(kActive, s2.pst_report()->status); + s2.DeleteEntry(pst); + s2.close(); + + // Now that session is deleted, we can't generate a report for it. + Session s3; + s3.open(); + s3.GenerateReport(pst, false); + s3.close(); +} + +TEST_P(UsageTableTest, ForceDeleteActiveEntry) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + std::string pst = "my pst"; + s.FillSimpleMessage( + 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, + s.get_nonce(), pst); + s.EncryptAndSign(); + s.LoadTestKeys(pst, new_mac_keys_); + s.TestDecryptCTR(); + s.GenerateReport(pst); + s.close(); + + s.ForceDeleteEntry(pst); + + // Now that session is deleted, we can't generate a report for it. + Session s3; + s3.open(); + s3.GenerateReport(pst, false); + s3.close(); +} + +TEST_P(UsageTableTest, DeleteInactiveEntry) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + std::string pst = "my pst"; + s.FillSimpleMessage( + 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, + s.get_nonce(), pst); + s.EncryptAndSign(); + s.LoadTestKeys(pst, new_mac_keys_); + s.GenerateReport(pst); + s.TestDecryptCTR(); + DeactivatePST(pst); + s.close(); + + // New session should be able to generate report and copy mac keys. + Session s2; + s2.open(); + s2.GenerateReport(pst, true, &s); + EXPECT_EQ(kInactive, s2.pst_report()->status); + s2.DeleteEntry(pst); + s2.close(); + + // Now that session is deleted, we can't generate a report for it. + Session s3; + s3.open(); + s3.GenerateReport(pst, false); + s3.close(); +} + +TEST_P(UsageTableTest, DeleteEntryBadSignature) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + std::string pst = "my pst"; + s.FillSimpleMessage( + 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, + s.get_nonce(), pst); + s.EncryptAndSign(); + s.LoadTestKeys(pst, new_mac_keys_); + s.GenerateReport(pst); + s.close(); + + // New session should be able to generate report and copy mac keys. + Session s2; + s2.open(); + s2.GenerateReport(pst, true, &s); + uint8_t* pst_ptr = s2.encrypted_license().pst; + memcpy(pst_ptr, pst.c_str(), min(sizeof(s2.license().pst), pst.length())); + std::vector signature(SHA256_DIGEST_LENGTH); + // Cannot delete without correct signature. + // ServerSignMessage(s2.encrypted_license(), &signature); + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_DeleteUsageEntry(s2.session_id(), pst_ptr, pst.length(), + s2.message_ptr(), sizeof(MessageData), + &signature[0], signature.size())); + s2.close(); + + // The session is not deleted, we can still generate a report for it. + Session s3; + s3.open(); + s3.GenerateReport(pst, true, &s); + EXPECT_EQ(kUnused, s3.pst_report()->status); + s3.close(); +} + +TEST_P(UsageTableTest, DeleteEntryWrongSession) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + std::string pst = "my pst"; + s.FillSimpleMessage( + 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, + s.get_nonce(), pst); + s.EncryptAndSign(); + s.LoadTestKeys(pst, new_mac_keys_); + s.GenerateReport(pst); + s.close(); + + // New session should not be able to delete without using GenerateReport + // to load mac keys. + Session s2; + s2.open(); + // s2.GenerateReport(pst, true, &s); + uint8_t* pst_ptr = s2.encrypted_license().pst; + memcpy(pst_ptr, pst.c_str(), min(sizeof(s2.license().pst), pst.length())); + std::vector signature(SHA256_DIGEST_LENGTH); + s2.ServerSignMessage(s2.encrypted_license(), &signature); + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_DeleteUsageEntry(s2.session_id(), pst_ptr, pst.length(), + s2.message_ptr(), sizeof(MessageData), + &signature[0], signature.size())); + s2.close(); + + // The session is not deleted, we can still generate a report for it. + Session s3; + s3.open(); + s3.GenerateReport(pst, true, &s); + EXPECT_EQ(kUnused, s3.pst_report()->status); + s3.close(); +} + +TEST_P(UsageTableTest, DeleteEntryBadRange) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + std::string pst = "my pst"; + s.FillSimpleMessage( + 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, + s.get_nonce(), pst); + s.EncryptAndSign(); + s.LoadTestKeys(pst, new_mac_keys_); + s.GenerateReport(pst); + s.close(); + + // New session should not be able to delete if pst doesn't point into + // message. + Session s2; + s2.open(); + s2.GenerateReport(pst, true, &s); + uint8_t* pst_ptr = s2.license().pst; + memcpy(pst_ptr, pst.c_str(), min(sizeof(s2.license().pst), pst.length())); + std::vector signature(SHA256_DIGEST_LENGTH); + s2.ServerSignMessage(s2.encrypted_license(), &signature); + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_DeleteUsageEntry(s2.session_id(), pst_ptr, pst.length(), + s2.message_ptr(), sizeof(MessageData), + &signature[0], signature.size())); + s2.close(); + + // The session is not deleted, we can still generate a report for it. + Session s3; + s3.open(); + s3.GenerateReport(pst, true, &s); + EXPECT_EQ(kUnused, s3.pst_report()->status); + s3.close(); +} + +TEST_P(UsageTableTest, DeactivateBadPST) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + std::string pst = "nonexistant pst"; + OEMCryptoResult sts = OEMCrypto_DeactivateUsageEntry( + reinterpret_cast(pst.c_str()), pst.length()); + EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts); + std::string null_pst = ""; + sts = OEMCrypto_DeactivateUsageEntry( + reinterpret_cast(null_pst.c_str()), null_pst.length()); + EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts); +} + +TEST_P(UsageTableTest, GenericCryptoEncrypt) { + std::string pst = "A PST"; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + uint32_t nonce = s.get_nonce(); + MakeFourKeys(&s, 0, wvoec_mock::kControlNonceEnabled | + wvoec_mock::kControlNonceRequired, + nonce, pst); + s.EncryptAndSign(); + s.LoadTestKeys(pst, new_mac_keys_); + OEMCryptoResult sts; + unsigned int key_index = 0; + uint8_t expected_encrypted[kBufferSize]; + EncryptBuffer(&s, key_index, clear_buffer_, expected_encrypted); + sts = OEMCrypto_SelectKey( + s.session_id(), s.license().keys[key_index].key_id, kTestKeyIdLength); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + uint8_t encrypted[kBufferSize]; + sts = OEMCrypto_Generic_Encrypt(s.session_id(), clear_buffer_, kBufferSize, + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, + encrypted); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + EXPECT_EQ(0, memcmp(encrypted, expected_encrypted, kBufferSize)); + s.GenerateReport(pst); + EXPECT_EQ(kActive, s.pst_report()->status); + EXPECT_ALMOST( + 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); + EXPECT_ALMOST(0, + wvcdm::htonll64(s.pst_report()->seconds_since_first_decrypt)); + EXPECT_ALMOST(0, + wvcdm::htonll64(s.pst_report()->seconds_since_last_decrypt)); + DeactivatePST(pst); + s.GenerateReport(pst); + EXPECT_EQ(kInactive, s.pst_report()->status); + EXPECT_ALMOST( + 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); + memset(encrypted, 0, kBufferSize); + sts = OEMCrypto_Generic_Encrypt(s.session_id(), clear_buffer_, kBufferSize, + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, + encrypted); + ASSERT_NE(OEMCrypto_SUCCESS, sts); + EXPECT_NE(0, memcmp(encrypted, expected_encrypted, kBufferSize)); +} + +TEST_P(UsageTableTest, GenericCryptoDecrypt) { + std::string pst = "my_pst"; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + uint32_t nonce = s.get_nonce(); + MakeFourKeys(&s, 0, wvoec_mock::kControlNonceEnabled | + wvoec_mock::kControlNonceRequired, + nonce, pst); + s.EncryptAndSign(); + s.LoadTestKeys(pst, new_mac_keys_); + OEMCryptoResult sts; + unsigned int key_index = 1; + uint8_t encrypted[kBufferSize]; + EncryptBuffer(&s, key_index, clear_buffer_, encrypted); + sts = OEMCrypto_SelectKey( + s.session_id(), s.license().keys[key_index].key_id, kTestKeyIdLength); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + uint8_t resultant[kBufferSize]; + sts = + OEMCrypto_Generic_Decrypt(s.session_id(), encrypted, kBufferSize, iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, resultant); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + EXPECT_EQ(0, memcmp(clear_buffer_, resultant, kBufferSize)); + s.GenerateReport(pst); + EXPECT_EQ(kActive, s.pst_report()->status); + EXPECT_ALMOST( + 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); + EXPECT_ALMOST(0, + wvcdm::htonll64(s.pst_report()->seconds_since_first_decrypt)); + EXPECT_ALMOST(0, + wvcdm::htonll64(s.pst_report()->seconds_since_last_decrypt)); + DeactivatePST(pst); + s.GenerateReport(pst); + EXPECT_EQ(kInactive, s.pst_report()->status); + EXPECT_ALMOST( + 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); + memset(resultant, 0, kBufferSize); + sts = + OEMCrypto_Generic_Decrypt(s.session_id(), encrypted, kBufferSize, iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, resultant); + ASSERT_NE(OEMCrypto_SUCCESS, sts); + EXPECT_NE(0, memcmp(clear_buffer_, resultant, kBufferSize)); +} + +TEST_P(UsageTableTest, GenericCryptoSign) { + std::string pst = "my_pst"; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + uint32_t nonce = s.get_nonce(); + MakeFourKeys(&s, 0, wvoec_mock::kControlNonceEnabled | + wvoec_mock::kControlNonceRequired, + nonce, pst); + s.EncryptAndSign(); + s.LoadTestKeys(pst, new_mac_keys_); + + OEMCryptoResult sts; + unsigned int key_index = 2; + uint8_t expected_signature[SHA256_DIGEST_LENGTH]; + SignBuffer(&s, key_index, clear_buffer_, expected_signature); + + sts = OEMCrypto_SelectKey( + s.session_id(), s.license().keys[key_index].key_id, kTestKeyIdLength); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + size_t gen_signature_length = 0; + sts = OEMCrypto_Generic_Sign(s.session_id(), clear_buffer_, kBufferSize, + OEMCrypto_HMAC_SHA256, NULL, + &gen_signature_length); + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); + ASSERT_EQ(static_cast(SHA256_DIGEST_LENGTH), gen_signature_length); + uint8_t signature[SHA256_DIGEST_LENGTH]; + sts = OEMCrypto_Generic_Sign(s.session_id(), clear_buffer_, kBufferSize, + OEMCrypto_HMAC_SHA256, signature, + &gen_signature_length); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + ASSERT_EQ(0, memcmp(signature, expected_signature, SHA256_DIGEST_LENGTH)); + + s.GenerateReport(pst); + EXPECT_EQ(kActive, s.pst_report()->status); + EXPECT_ALMOST( + 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); + EXPECT_ALMOST(0, + wvcdm::htonll64(s.pst_report()->seconds_since_first_decrypt)); + EXPECT_ALMOST(0, + wvcdm::htonll64(s.pst_report()->seconds_since_last_decrypt)); + DeactivatePST(pst); + s.GenerateReport(pst); + EXPECT_EQ(kInactive, s.pst_report()->status); + EXPECT_ALMOST( + 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); + + memset(signature, 0, SHA256_DIGEST_LENGTH); + gen_signature_length = SHA256_DIGEST_LENGTH; + sts = OEMCrypto_Generic_Sign(s.session_id(), clear_buffer_, kBufferSize, + OEMCrypto_HMAC_SHA256, signature, + &gen_signature_length); + ASSERT_NE(OEMCrypto_SUCCESS, sts); + ASSERT_NE(0, memcmp(signature, expected_signature, SHA256_DIGEST_LENGTH)); +} + +TEST_P(UsageTableTest, GenericCryptoVerify) { + std::string pst = "my_pst"; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + uint32_t nonce = s.get_nonce(); + MakeFourKeys(&s, 0, wvoec_mock::kControlNonceEnabled | + wvoec_mock::kControlNonceRequired, + nonce, pst); + s.EncryptAndSign(); + s.LoadTestKeys(pst, new_mac_keys_); + + OEMCryptoResult sts; + unsigned int key_index = 3; + uint8_t signature[SHA256_DIGEST_LENGTH]; + SignBuffer(&s, key_index, clear_buffer_, signature); + + sts = OEMCrypto_SelectKey( + s.session_id(), s.license().keys[key_index].key_id, kTestKeyIdLength); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + sts = OEMCrypto_Generic_Verify(s.session_id(), clear_buffer_, kBufferSize, + OEMCrypto_HMAC_SHA256, signature, + SHA256_DIGEST_LENGTH); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + + s.GenerateReport(pst); + EXPECT_EQ(kActive, s.pst_report()->status); + EXPECT_ALMOST( + 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); + EXPECT_ALMOST(0, + wvcdm::htonll64(s.pst_report()->seconds_since_first_decrypt)); + EXPECT_ALMOST(0, + wvcdm::htonll64(s.pst_report()->seconds_since_last_decrypt)); + DeactivatePST(pst); + s.GenerateReport(pst); + EXPECT_EQ(kInactive, s.pst_report()->status); + EXPECT_ALMOST( + 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); + + sts = OEMCrypto_Generic_Verify(s.session_id(), clear_buffer_, kBufferSize, + OEMCrypto_HMAC_SHA256, signature, + SHA256_DIGEST_LENGTH); + ASSERT_NE(OEMCrypto_SUCCESS, sts); +} + +TEST_P(UsageTableTest, OfflineLicense) { + std::string pst = "my_pst"; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + LoadOfflineLicense(s, pst); +} + +TEST_P(UsageTableTest, ReloadOfflineLicense) { + std::string pst = "my_pst"; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + LoadOfflineLicense(s, pst); + + s.open(); // Offline license can be reused. + s.GenerateTestSessionKeys(); + // We will reuse the encrypted and signed message, so we don't call + // FillSimpleMessage again. + s.LoadTestKeys(pst, new_mac_keys_); + s.GenerateReport(pst); + s.GenerateReport(pst); + EXPECT_EQ(kUnused, s.pst_report()->status); + EXPECT_ALMOST( + 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); + s.TestDecryptCTR(); + s.GenerateReport(pst); + EXPECT_EQ(kActive, s.pst_report()->status); + EXPECT_ALMOST( + 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); + EXPECT_ALMOST(0, + wvcdm::htonll64(s.pst_report()->seconds_since_first_decrypt)); + EXPECT_ALMOST(0, + wvcdm::htonll64(s.pst_report()->seconds_since_last_decrypt)); + s.close(); +} + +TEST_P(UsageTableTest, BadReloadOfflineLicense) { + std::string pst = "my_pst"; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + LoadOfflineLicense(s, pst); + + // Offline license with new mac keys should fail. + Session s2; + s2.open(); + s2.GenerateTestSessionKeys(); + s2.FillSimpleMessage(0, wvoec_mock::kControlNonceOrEntry, + s2.get_nonce(), pst); + s2.EncryptAndSign(); + uint8_t* pst_ptr = s2.encrypted_license().pst; + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_LoadKeys(s2.session_id(), s2.message_ptr(), + sizeof(MessageData), &s2.signature()[0], + s2.signature().size(), + s2.encrypted_license().mac_key_iv, + s2.encrypted_license().mac_keys, kNumKeys, + s2.key_array(), pst_ptr, pst.length())); + s2.close(); + + // Offline license with same mac keys should still be OK. + s.open(); + s.GenerateTestSessionKeys(); + s.LoadTestKeys(pst, new_mac_keys_); + s.GenerateReport(pst); + EXPECT_EQ(kUnused, s.pst_report()->status); } // An offline license should not load on the first call if the nonce is bad. -TEST_P(DISABLED_UsageTableTest, OfflineBadNonce) { - if (OEMCrypto_SupportsUsageTable()) { - std::string pst = "my_pst"; - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - s.open(); - s.GenerateDerivedKeys(); - s.FillSimpleMessage( - 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceOrEntry, - 42, pst); - s.EncryptAndSign(); - uint8_t* pst_ptr = s.encrypted_license().pst; - OEMCryptoResult sts = OEMCrypto_LoadKeys( - s.session_id(), s.message_ptr(), sizeof(MessageData), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, kNumKeys, s.key_array(), - pst_ptr, pst.length()); - ASSERT_NE(OEMCrypto_SUCCESS, sts); - s.close(); - } +TEST_P(UsageTableTest, OfflineBadNonce) { + std::string pst = "my_pst"; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + s.FillSimpleMessage( + 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceOrEntry, + 42, pst); + s.EncryptAndSign(); + uint8_t* pst_ptr = s.encrypted_license().pst; + OEMCryptoResult sts = OEMCrypto_LoadKeys( + s.session_id(), s.message_ptr(), sizeof(MessageData), &s.signature()[0], + s.signature().size(), s.encrypted_license().mac_key_iv, + s.encrypted_license().mac_keys, kNumKeys, s.key_array(), + pst_ptr, pst.length()); + ASSERT_NE(OEMCrypto_SUCCESS, sts); + s.close(); } // An offline license needs a valid pst. -TEST_P(DISABLED_UsageTableTest, OfflineEmptyPST) { - if (OEMCrypto_SupportsUsageTable()) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - s.open(); - s.GenerateDerivedKeys(); - s.FillSimpleMessage( - 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceOrEntry, - s.get_nonce()); - s.EncryptAndSign(); - OEMCryptoResult sts = OEMCrypto_LoadKeys( - s.session_id(), s.message_ptr(), sizeof(MessageData), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, kNumKeys, s.key_array(), - NULL, 0); - ASSERT_NE(OEMCrypto_SUCCESS, sts); - s.close(); - } +TEST_P(UsageTableTest, OfflineEmptyPST) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + s.FillSimpleMessage( + 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceOrEntry, + s.get_nonce()); + s.EncryptAndSign(); + OEMCryptoResult sts = OEMCrypto_LoadKeys( + s.session_id(), s.message_ptr(), sizeof(MessageData), &s.signature()[0], + s.signature().size(), s.encrypted_license().mac_key_iv, + s.encrypted_license().mac_keys, kNumKeys, s.key_array(), + NULL, 0); + ASSERT_NE(OEMCrypto_SUCCESS, sts); + s.close(); } -TEST_P(DISABLED_UsageTableTest, DeactivateOfflineLicense) { - if (OEMCrypto_SupportsUsageTable()) { - std::string pst = "my_pst"; - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - LoadOfflineLicense(s, pst); +TEST_P(UsageTableTest, DeactivateOfflineLicense) { + std::string pst = "my_pst"; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + LoadOfflineLicense(s, pst); - s.open(); - s.GenerateDerivedKeys(); - s.LoadTestKeys(pst, new_mac_keys_); // Reload the license - s.TestDecryptCTR(); // Should be able to decrypt. - DeactivatePST(pst); // Then deactivate. - // After deactivate, should not be able to decrypt. - s.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE); - s.GenerateReport(pst); - EXPECT_EQ(kInactive, s.pst_report()->status); - EXPECT_ALMOST( - 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); - s.close(); + s.open(); + s.GenerateTestSessionKeys(); + s.LoadTestKeys(pst, new_mac_keys_); // Reload the license + s.TestDecryptCTR(); // Should be able to decrypt. + DeactivatePST(pst); // Then deactivate. + // After deactivate, should not be able to decrypt. + s.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE); + s.GenerateReport(pst); + EXPECT_EQ(kInactive, s.pst_report()->status); + EXPECT_ALMOST( + 0, wvcdm::htonll64(s.pst_report()->seconds_since_license_received)); + s.close(); - Session s2; - s2.open(); - s2.GenerateDerivedKeys(); - // Offile license can not be reused if it has been deactivated. - uint8_t* pst_ptr = s.encrypted_license().pst; - EXPECT_NE(OEMCrypto_SUCCESS, - OEMCrypto_LoadKeys(s2.session_id(), s.message_ptr(), - sizeof(MessageData), &s.signature()[0], - s.signature().size(), - s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, kNumKeys, - s.key_array(), pst_ptr, pst.length())); - // But we can still generate a report. - Session s3; - s3.open(); - s3.GenerateReport(pst, true, &s); - EXPECT_EQ(kInactive, s3.pst_report()->status); - } + Session s2; + s2.open(); + s2.GenerateTestSessionKeys(); + // Offile license can not be reused if it has been deactivated. + uint8_t* pst_ptr = s.encrypted_license().pst; + EXPECT_NE(OEMCrypto_SUCCESS, + OEMCrypto_LoadKeys(s2.session_id(), s.message_ptr(), + sizeof(MessageData), &s.signature()[0], + s.signature().size(), + s.encrypted_license().mac_key_iv, + s.encrypted_license().mac_keys, kNumKeys, + s.key_array(), pst_ptr, pst.length())); + // But we can still generate a report. + Session s3; + s3.open(); + s3.GenerateReport(pst, true, &s); + EXPECT_EQ(kInactive, s3.pst_report()->status); } -TEST_P(DISABLED_UsageTableTest, BadRange) { - if (OEMCrypto_SupportsUsageTable()) { - std::string pst = "my_pst"; - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - s.open(); - s.GenerateDerivedKeys(); - s.FillSimpleMessage(0, wvoec_mock::kControlNonceOrEntry, - s.get_nonce(), pst); - s.EncryptAndSign(); - uint8_t* pst_ptr = s.license().pst; // Bad: not in encrypted_license. - ASSERT_NE( - OEMCrypto_SUCCESS, - OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), sizeof(MessageData), - &s.signature()[0], s.signature().size(), - s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, kNumKeys, - s.key_array(), pst_ptr, pst.length())); - } +TEST_P(UsageTableTest, BadRange) { + std::string pst = "my_pst"; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + s.FillSimpleMessage(0, wvoec_mock::kControlNonceOrEntry, + s.get_nonce(), pst); + s.EncryptAndSign(); + uint8_t* pst_ptr = s.license().pst; // Bad: not in encrypted_license. + ASSERT_NE( + OEMCrypto_SUCCESS, + OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), sizeof(MessageData), + &s.signature()[0], s.signature().size(), + s.encrypted_license().mac_key_iv, + s.encrypted_license().mac_keys, kNumKeys, + s.key_array(), pst_ptr, pst.length())); } -TEST_P(DISABLED_UsageTableTest, TimingTest) { - if (OEMCrypto_SupportsUsageTable()) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - std::string pst1 = "my_pst_1"; - std::string pst2 = "my_pst_2"; - std::string pst3 = "my_pst_3"; - Session s1; - Session s2; - Session s3; - LoadOfflineLicense(s1, pst1); - time_t loaded1 = time(NULL); - LoadOfflineLicense(s2, pst2); - time_t loaded2 = time(NULL); - LoadOfflineLicense(s3, pst3); - time_t loaded3 = time(NULL); +TEST_P(UsageTableTest, TimingTest) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + std::string pst1 = "my_pst_1"; + std::string pst2 = "my_pst_2"; + std::string pst3 = "my_pst_3"; + Session s1; + Session s2; + Session s3; + LoadOfflineLicense(s1, pst1); + time_t loaded1 = time(NULL); + LoadOfflineLicense(s2, pst2); + time_t loaded2 = time(NULL); + LoadOfflineLicense(s3, pst3); + time_t loaded3 = time(NULL); - sleep(kLongSleep); - s1.open(); - s1.GenerateDerivedKeys(); - s1.LoadTestKeys(pst1, new_mac_keys_); - time_t first_decrypt1 = time(NULL); - s1.TestDecryptCTR(); + sleep(kLongSleep); + s1.open(); + s1.GenerateTestSessionKeys(); + s1.LoadTestKeys(pst1, new_mac_keys_); + time_t first_decrypt1 = time(NULL); + s1.TestDecryptCTR(); - s2.open(); - s2.GenerateDerivedKeys(); - s2.LoadTestKeys(pst2, new_mac_keys_); - time_t first_decrypt2 = time(NULL); - s2.TestDecryptCTR(); + s2.open(); + s2.GenerateTestSessionKeys(); + s2.LoadTestKeys(pst2, new_mac_keys_); + time_t first_decrypt2 = time(NULL); + s2.TestDecryptCTR(); - sleep(kLongSleep); - time_t second_decrypt = time(NULL); - s1.TestDecryptCTR(); - s2.TestDecryptCTR(); + sleep(kLongSleep); + time_t second_decrypt = time(NULL); + s1.TestDecryptCTR(); + s2.TestDecryptCTR(); - sleep(kLongSleep); - DeactivatePST(pst1); - s1.close(); - s2.close(); + sleep(kLongSleep); + DeactivatePST(pst1); + s1.close(); + s2.close(); - sleep(kLongSleep); - // This is as close to reboot as we can simulate in code. - OEMCrypto_Terminate(); - sleep(kShortSleep); - OEMCrypto_Initialize(); - InstallKeybox(kDefaultKeybox, true); + sleep(kLongSleep); + // This is as close to reboot as we can simulate in code. + OEMCrypto_Terminate(); + sleep(kShortSleep); + OEMCrypto_Initialize(); + EnsureTestKeys(); - // After a reboot, we should be able to reload keys, and generate reports. - sleep(kLongSleep); - time_t third_decrypt = time(NULL); - s2.open(); - s2.GenerateDerivedKeys(); - s2.LoadTestKeys(pst2, new_mac_keys_); - s2.TestDecryptCTR(); - s2.close(); + // After a reboot, we should be able to reload keys, and generate reports. + sleep(kLongSleep); + time_t third_decrypt = time(NULL); + s2.open(); + s2.GenerateTestSessionKeys(); + s2.LoadTestKeys(pst2, new_mac_keys_); + s2.TestDecryptCTR(); + s2.close(); - s1.open(); - s2.open(); - s3.open(); - sleep(kLongSleep); - time_t report_generated1 = time(NULL); - s1.GenerateReport(pst1); - time_t report_generated2 = time(NULL); - s2.GenerateReport(pst2); - time_t report_generated3 = time(NULL); - s3.GenerateReport(pst3); + s1.open(); + s2.open(); + s3.open(); + sleep(kLongSleep); + time_t report_generated1 = time(NULL); + s1.GenerateReport(pst1); + time_t report_generated2 = time(NULL); + s2.GenerateReport(pst2); + time_t report_generated3 = time(NULL); + s3.GenerateReport(pst3); - EXPECT_EQ(kInactive, s1.pst_report()->status); - EXPECT_ALMOST( - report_generated1 - loaded1, - wvcdm::htonll64(s1.pst_report()->seconds_since_license_received)); - EXPECT_ALMOST( - report_generated1 - first_decrypt1, - wvcdm::htonll64(s1.pst_report()->seconds_since_first_decrypt)); - EXPECT_ALMOST(report_generated1 - second_decrypt, - wvcdm::htonll64(s1.pst_report()->seconds_since_last_decrypt)); + EXPECT_EQ(kInactive, s1.pst_report()->status); + EXPECT_ALMOST( + report_generated1 - loaded1, + wvcdm::htonll64(s1.pst_report()->seconds_since_license_received)); + EXPECT_ALMOST( + report_generated1 - first_decrypt1, + wvcdm::htonll64(s1.pst_report()->seconds_since_first_decrypt)); + EXPECT_ALMOST(report_generated1 - second_decrypt, + wvcdm::htonll64(s1.pst_report()->seconds_since_last_decrypt)); - EXPECT_EQ(kActive, s2.pst_report()->status); - EXPECT_ALMOST( - report_generated2 - loaded2, - wvcdm::htonll64(s2.pst_report()->seconds_since_license_received)); - EXPECT_ALMOST( - report_generated2 - first_decrypt2, - wvcdm::htonll64(s2.pst_report()->seconds_since_first_decrypt)); - EXPECT_ALMOST(report_generated2 - third_decrypt, - wvcdm::htonll64(s2.pst_report()->seconds_since_last_decrypt)); + EXPECT_EQ(kActive, s2.pst_report()->status); + EXPECT_ALMOST( + report_generated2 - loaded2, + wvcdm::htonll64(s2.pst_report()->seconds_since_license_received)); + EXPECT_ALMOST( + report_generated2 - first_decrypt2, + wvcdm::htonll64(s2.pst_report()->seconds_since_first_decrypt)); + EXPECT_ALMOST(report_generated2 - third_decrypt, + wvcdm::htonll64(s2.pst_report()->seconds_since_last_decrypt)); - EXPECT_EQ(kUnused, s3.pst_report()->status); - EXPECT_ALMOST( - report_generated3 - loaded3, - wvcdm::htonll64(s3.pst_report()->seconds_since_license_received)); - // We don't expect first or last decrypt for unused report. - } + EXPECT_EQ(kUnused, s3.pst_report()->status); + EXPECT_ALMOST( + report_generated3 - loaded3, + wvcdm::htonll64(s3.pst_report()->seconds_since_license_received)); + // We don't expect first or last decrypt for unused report. } -TEST_P(DISABLED_UsageTableTest, VerifyUsageTimes) { - if (OEMCrypto_SupportsUsageTable()) { - std::string pst = "my_pst"; - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - Session s; - s.open(); - s.GenerateDerivedKeys(); - s.FillSimpleMessage( - 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, - s.get_nonce(), pst); - s.EncryptAndSign(); - s.LoadTestKeys(pst, new_mac_keys_); +TEST_P(UsageTableTest, VerifyUsageTimes) { + std::string pst = "my_pst"; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + Session s; + s.open(); + s.GenerateTestSessionKeys(); + s.FillSimpleMessage( + 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, + s.get_nonce(), pst); + s.EncryptAndSign(); + s.LoadTestKeys(pst, new_mac_keys_); - const int kLicenseReceivedTimeTolerance = kSpeedMultiplier; - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + const int kLicenseReceivedTimeTolerance = kSpeedMultiplier; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + s.GenerateReport(pst); + EXPECT_EQ(kUnused, s.pst_report()->status); + EXPECT_NEAR(wvcdm::htonll64(s.pst_report()->seconds_since_license_received), + 0, kLicenseReceivedTimeTolerance); + + const time_t kDotIntervalInSeconds = 5; + const time_t kIdleInSeconds = 20; + const time_t kPlaybackLoopInSeconds = 2 * 60; + const time_t kUsageTableTimeTolerance = 10; + + cout << "This test verifies the elapsed time reported in the usage table " + "for a 2 minute simulated playback." << endl; + cout << "The total time for this test is about " << + kPlaybackLoopInSeconds + 2 * kIdleInSeconds << " seconds." << endl; + cout << "Wait " << kIdleInSeconds << + " seconds to verify usage table time before playback." << endl; + + PrintDotsWhileSleep(kIdleInSeconds, kDotIntervalInSeconds); + + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + s.GenerateReport(pst); + EXPECT_EQ(kUnused, s.pst_report()->status); + EXPECT_NEAR(wvcdm::htonll64(s.pst_report()->seconds_since_license_received), + kIdleInSeconds, kLicenseReceivedTimeTolerance); + cout << "Start simulated playback..." << endl; + + time_t dot_time = kDotIntervalInSeconds; + time_t playback_time = 0; + time_t start_time = time(NULL); + do { + s.TestDecryptCTR(); s.GenerateReport(pst); - EXPECT_EQ(kUnused, s.pst_report()->status); - EXPECT_NEAR(wvcdm::htonll64(s.pst_report()->seconds_since_license_received), - 0, kLicenseReceivedTimeTolerance); + EXPECT_EQ(kActive, s.pst_report()->status); + playback_time = time(NULL) - start_time; + ASSERT_LE(0, playback_time); + if (playback_time >= dot_time) { + cout << "."; + cout.flush(); + dot_time += kDotIntervalInSeconds; + } + } while (playback_time < kPlaybackLoopInSeconds); + cout << "\nSimulated playback time = " << playback_time << " seconds.\n"; - const time_t kDotIntervalInSeconds = 5; - const time_t kIdleInSeconds = 20; - const time_t kPlaybackLoopInSeconds = 2 * 60; - const time_t kUsageTableTimeTolerance = 10; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + s.GenerateReport(pst); + EXPECT_NEAR(wvcdm::htonll64(s.pst_report()->seconds_since_license_received), + playback_time + kIdleInSeconds, kLicenseReceivedTimeTolerance); + EXPECT_NEAR(wvcdm::htonll64(s.pst_report()->seconds_since_first_decrypt), + playback_time, kUsageTableTimeTolerance); + EXPECT_NEAR(wvcdm::htonll64(s.pst_report()->seconds_since_last_decrypt), + 0, kUsageTableTimeTolerance); + EXPECT_NEAR( + wvcdm::htonll64(s.pst_report()->seconds_since_first_decrypt) - + wvcdm::htonll64(s.pst_report()->seconds_since_last_decrypt), + playback_time, kUsageTableTimeTolerance); - cout << "This test verifies the elapsed time reported in the usage table " - "for a 2 minute simulated playback." << endl; - cout << "The total time for this test is about " << - kPlaybackLoopInSeconds + 2 * kIdleInSeconds << " seconds." << endl; - cout << "Wait " << kIdleInSeconds << - " seconds to verify usage table time before playback." << endl; + cout << "Wait another " << kIdleInSeconds << " seconds " + "to verify usage table time since playback ended." << endl; + PrintDotsWhileSleep(kIdleInSeconds, kDotIntervalInSeconds); - PrintDotsWhileSleep(kIdleInSeconds, kDotIntervalInSeconds); + // At this point, this is what we expect: + // idle playback loop idle + // |-----|-------------------------|-----| + // |<--->| = seconds_since_last_decrypt + // |<----------------------------->| = seconds_since_first_decrypt + // |<------------------------------------| = seconds_since_license_received + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); + s.GenerateReport(pst); + EXPECT_NEAR(wvcdm::htonll64(s.pst_report()->seconds_since_license_received), + playback_time + 2 * kIdleInSeconds, + kLicenseReceivedTimeTolerance); + EXPECT_NEAR(wvcdm::htonll64(s.pst_report()->seconds_since_first_decrypt), + playback_time + kIdleInSeconds, kUsageTableTimeTolerance); + EXPECT_NEAR(wvcdm::htonll64(s.pst_report()->seconds_since_last_decrypt), + kIdleInSeconds, kUsageTableTimeTolerance); - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - s.GenerateReport(pst); - EXPECT_EQ(kUnused, s.pst_report()->status); - EXPECT_NEAR(wvcdm::htonll64(s.pst_report()->seconds_since_license_received), - kIdleInSeconds, kLicenseReceivedTimeTolerance); - cout << "Start simulated playback..." << endl; - - time_t dot_time = kDotIntervalInSeconds; - time_t playback_time = 0; - time_t start_time = time(NULL); - do { - s.TestDecryptCTR(); - s.GenerateReport(pst); - EXPECT_EQ(kActive, s.pst_report()->status); - playback_time = time(NULL) - start_time; - ASSERT_LE(0, playback_time); - if (playback_time >= dot_time) { - cout << "."; - cout.flush(); - dot_time += kDotIntervalInSeconds; - } - } while (playback_time < kPlaybackLoopInSeconds); - cout << "\nSimulated playback time = " << playback_time << " seconds.\n"; - - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - s.GenerateReport(pst); - EXPECT_NEAR(wvcdm::htonll64(s.pst_report()->seconds_since_license_received), - playback_time + kIdleInSeconds, kLicenseReceivedTimeTolerance); - EXPECT_NEAR(wvcdm::htonll64(s.pst_report()->seconds_since_first_decrypt), - playback_time, kUsageTableTimeTolerance); - EXPECT_NEAR(wvcdm::htonll64(s.pst_report()->seconds_since_last_decrypt), - 0, kUsageTableTimeTolerance); - EXPECT_NEAR( - wvcdm::htonll64(s.pst_report()->seconds_since_first_decrypt) - - wvcdm::htonll64(s.pst_report()->seconds_since_last_decrypt), - playback_time, kUsageTableTimeTolerance); - - cout << "Wait another " << kIdleInSeconds << " seconds " - "to verify usage table time since playback ended." << endl; - PrintDotsWhileSleep(kIdleInSeconds, kDotIntervalInSeconds); - - // At this point, this is what we expect: - // idle playback loop idle - // |-----|-------------------------|-----| - // |<--->| = seconds_since_last_decrypt - // |<----------------------------->| = seconds_since_first_decrypt - // |<------------------------------------| = seconds_since_license_received - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); - s.GenerateReport(pst); - EXPECT_NEAR(wvcdm::htonll64(s.pst_report()->seconds_since_license_received), - playback_time + 2 * kIdleInSeconds, - kLicenseReceivedTimeTolerance); - EXPECT_NEAR(wvcdm::htonll64(s.pst_report()->seconds_since_first_decrypt), - playback_time + kIdleInSeconds, kUsageTableTimeTolerance); - EXPECT_NEAR(wvcdm::htonll64(s.pst_report()->seconds_since_last_decrypt), - kIdleInSeconds, kUsageTableTimeTolerance); - - DeactivatePST(pst); - s.GenerateReport(pst); - EXPECT_EQ(kInactive, s.pst_report()->status); - s.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE); - } + DeactivatePST(pst); + s.GenerateReport(pst); + EXPECT_EQ(kInactive, s.pst_report()->status); + s.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE); } -INSTANTIATE_TEST_CASE_P(TestUsageTables, DISABLED_UsageTableTest, +INSTANTIATE_TEST_CASE_P(TestUsageTables, UsageTableTest, Values(true, false)); // With and without new_mac_keys. } // namespace wvoec diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test.h b/libwvdrmengine/oemcrypto/test/oemcrypto_test.h new file mode 100644 index 00000000..4a3988c7 --- /dev/null +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test.h @@ -0,0 +1,41 @@ +#ifndef CDM_OEMCRYPTO_TEST_H_ +#define CDM_OEMCRYPTO_TEST_H_ + +#include "OEMCryptoCENC.h" +#include "wv_keybox.h" + +namespace wvoec { + +class DeviceFeatures { + public: + enum DeriveMethod { // Method to use derive session keys. + NO_METHOD, // Cannot derive known session keys. + LOAD_TEST_KEYBOX, // Call LoadTestKeybox before deriving keys. + LOAD_TEST_RSA_KEY, // Call LoadTestRSAKey before deriving keys. + EXISTING_TEST_KEYBOX, // Keybox is already the test keybox. + FORCE_TEST_KEYBOX, // User requested calling InstallKeybox. + }; + + enum DeriveMethod derive_key_method; + bool uses_keybox; // Device uses a keybox to derive session keys. + bool uses_certificate; // Device uses a certificate to derive session keys. + bool loads_certificate; // Device can load a certificate from the server. + bool generic_crypto; // Device supports generic crypto. + bool cast_receiver; // Device supports alternate rsa signature padding. + bool usage_table; // Device saves usage information. + uint32_t api_version; + + void Initialize(bool is_cast_receiver, bool force_load_test_keybox); + std::string RestrictFilter(const std::string& initial_filter); + + private: + void PickDerivedKey(); + bool IsTestKeyboxInstalled(); + void FilterOut(std::string* current_filter, const std::string& new_filter); +}; + +extern DeviceFeatures global_features; + +} // namespace wvoec + +#endif // CDM_OEMCRYPTO_TEST_H_ diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test_android.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test_android.cpp index 4562e69b..af2e966d 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test_android.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test_android.cpp @@ -75,7 +75,6 @@ TEST_F(OEMCryptoAndroidLMPTest, GenericCryptoImplemented) { } TEST_F(OEMCryptoAndroidLMPTest, SupportsUsageTable) { - // TODO(fredgc): maybe remove Properties::oem_crypto_require_usage_tables? ASSERT_TRUE(OEMCrypto_SupportsUsageTable()); } diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test_main.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test_main.cpp new file mode 100644 index 00000000..a6d14959 --- /dev/null +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test_main.cpp @@ -0,0 +1,43 @@ +#include +#include + +#include "log.h" +#include "oemcrypto_test.h" +#include "OEMCryptoCENC.h" +#include "properties.h" + +static void acknowledge_cast() { + std::cout + << "==================================================================\n" + << "= This device is expected to load x509 certs as a cast receiver. =\n" + << "==================================================================\n"; +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + wvcdm::Properties::Init(); + wvcdm::g_cutoff = wvcdm::LOG_INFO; + bool is_cast_receiver = false; + bool force_load_test_keybox = false; + bool filter_tests = true; + for(int i=0; i < argc; i++) { + if (!strcmp(argv[i], "--cast")) { + acknowledge_cast(); + is_cast_receiver = true; + } + if (!strcmp(argv[i], "--force_load_test_keybox")) { + force_load_test_keybox = true; + } + if (!strcmp(argv[i], "--no_filter")) { + filter_tests = false; + } + } + wvoec::global_features.Initialize(is_cast_receiver, force_load_test_keybox); + // If the user requests --no_filter, we don't change the filter, otherwise, we + // filter out features that are not supported. + if (filter_tests) { + ::testing::GTEST_FLAG(filter) + = wvoec::global_features.RestrictFilter(::testing::GTEST_FLAG(filter)); + } + return RUN_ALL_TESTS(); +}