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(); +}