diff --git a/docs/Widevine_OEMCrypto_Version_Compatibility.pdf b/docs/Widevine_OEMCrypto_Version_Compatibility.pdf index 996cc62..20174fb 100644 Binary files a/docs/Widevine_OEMCrypto_Version_Compatibility.pdf and b/docs/Widevine_OEMCrypto_Version_Compatibility.pdf differ diff --git a/oemcrypto/include/OEMCryptoCENC.h b/oemcrypto/include/OEMCryptoCENC.h index f55e31e..e63c92e 100644 --- a/oemcrypto/include/OEMCryptoCENC.h +++ b/oemcrypto/include/OEMCryptoCENC.h @@ -480,8 +480,8 @@ typedef enum OEMCrypto_ProvisioningMethod { OEMCrypto_ProvisioningError = 0, // Device cannot be provisioned. OEMCrypto_DrmCertificate = 1, // Device has baked in DRM certificate // (level 3 only) - OEMCrypto_Keybox = 2, // Device has factory installed unique keybox. - OEMCrypto_OEMCertificate = 3 // Device has factory installed OEM certificate. + OEMCrypto_Keybox = 2, // Device has factory installed unique keybox. + OEMCrypto_OEMCertificate = 3 // Device has factory installed OEM certificate. } OEMCrypto_ProvisioningMethod; /** @@ -489,7 +489,7 @@ typedef enum OEMCrypto_ProvisioningMethod { */ #define OEMCrypto_Supports_RSA_2048bit 0x1 #define OEMCrypto_Supports_RSA_3072bit 0x2 -#define OEMCrypto_Supports_RSA_CAST 0x10 +#define OEMCrypto_Supports_RSA_CAST 0x10 #define OEMCrypto_Supports_ECC_secp256r1 0x100 #define OEMCrypto_Supports_ECC_secp384r1 0x200 #define OEMCrypto_Supports_ECC_secp521r1 0x400 @@ -504,12 +504,12 @@ typedef enum OEMCrypto_ProvisioningMethod { /** * Return values from OEMCrypto_GetAnalogOutputFlags. */ -#define OEMCrypto_No_Analog_Output 0x0 -#define OEMCrypto_Supports_Analog_Output 0x1 -#define OEMCrypto_Can_Disable_Analog_Ouptput 0x2 -#define OEMCrypto_Supports_CGMS_A 0x4 +#define OEMCrypto_No_Analog_Output 0x0 +#define OEMCrypto_Supports_Analog_Output 0x1 +#define OEMCrypto_Can_Disable_Analog_Ouptput 0x2 +#define OEMCrypto_Supports_CGMS_A 0x4 // Unknown_Analog_Output is used only for backwards compatibility. -#define OEMCrypto_Unknown_Analog_Output (1 << 31) +#define OEMCrypto_Unknown_Analog_Output (1<<31) /// @} @@ -622,8 +622,6 @@ typedef enum OEMCrypto_ProvisioningMethod { #define OEMCrypto_DecryptCENC _oecc105 #define OEMCrypto_LoadDRMPrivateKey _oecc107 #define OEMCrypto_MinorAPIVersion _oecc108 -#define OEMCrypto_AllocateSecureBuffer _oecc109 -#define OEMCrypto_FreeSecureBuffer _oecc110 // clang-format on /// @addtogroup initcontrol @@ -4725,25 +4723,12 @@ OEMCryptoResult OEMCrypto_FreeSecureBuffer( * current version of OEMCrypto. They are being declared here to help with * backwards compatibility. */ - -/* - * OEMCrypto_GenerateSignature - * @deprecated - * Not required for the current version of OEMCrypto. Declared here to - * help with backward compatibility. - */ OEMCryptoResult OEMCrypto_GenerateSignature(OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length); -/* - * OEMCrypto_RewrapDeviceRSAKey30 - * @deprecated - * Not required for the current version of OEMCrypto. Declared here to - * help with backward compatibility. - */ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30( OEMCrypto_SESSION session, const uint32_t* unaligned_nonce, const uint8_t* encrypted_message_key, size_t encrypted_message_key_length, @@ -4751,12 +4736,6 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30( const uint8_t* enc_rsa_key_iv, uint8_t* wrapped_rsa_key, size_t* wrapped_rsa_key_length); -/* - * OEMCrypto_RewrapDeviceRSAKey - * @deprecated - * Not required for the current version of OEMCrypto. Declared here to - * help with backward compatibility. - */ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length, @@ -4764,70 +4743,26 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey( size_t enc_rsa_key_length, const uint8_t* enc_rsa_key_iv, uint8_t* wrapped_rsa_key, size_t* wrapped_rsa_key_length); -/* - * OEMCrypto_UpdateUsageTable - * @deprecated - * Not required for the current version of OEMCrypto. Declared here to - * help with backward compatibility. - */ OEMCryptoResult OEMCrypto_UpdateUsageTable(void); -/* - * OEMCrypto_DeleteUsageEntry - * @deprecated - * Not required for the current version of OEMCrypto. Declared here to - * help with backward compatibility. - */ -OEMCryptoResult OEMCrypto_DeleteUsageEntry( - OEMCrypto_SESSION session, const uint8_t* pst, size_t pst_length, - const uint8_t* message, size_t message_length, const uint8_t* signature, - size_t signature_length); +OEMCryptoResult OEMCrypto_DeleteUsageEntry(OEMCrypto_SESSION, const uint8_t*, + size_t, const uint8_t*, size_t, + const uint8_t*, size_t); -/* - * OEMCrypto_ForceDeleteUsageEntry - * @deprecated - * Not required for the current version of OEMCrypto. Declared here to - * help with backward compatibility. - */ -OEMCryptoResult OEMCrypto_ForceDeleteUsageEntry(const uint8_t* pst, - size_t pst_length); +OEMCryptoResult OEMCrypto_ForceDeleteUsageEntry(const uint8_t*, size_t); -/* - * OEMCrypto_CopyOldUsageEntry - * @deprecated - * Not required for the current version of OEMCrypto. Declared here to - * help with backward compatibility. - */ OEMCryptoResult OEMCrypto_CopyOldUsageEntry(OEMCrypto_SESSION session, const uint8_t* pst, size_t pst_length); -/* - * OEMCrypto_DeleteOldUsageTable - * @deprecated - * Not required for the current version of OEMCrypto. Declared here to - * help with backward compatibility. - */ OEMCryptoResult OEMCrypto_DeleteOldUsageTable(void); -/* - * OEMCrypto_CreateOldUsageEntry - * @deprecated - * Not required for the current version of OEMCrypto. Declared here to - * help with backward compatibility. - */ OEMCryptoResult OEMCrypto_CreateOldUsageEntry( uint64_t time_since_license_received, uint64_t time_since_first_decrypt, uint64_t time_since_last_decrypt, OEMCrypto_Usage_Entry_Status status, uint8_t* server_mac_key, uint8_t* client_mac_key, const uint8_t* pst, size_t pst_length); -/* - * OEMCrypto_GenerateDerivedKeys_V15 - * @deprecated - * Not required for the current version of OEMCrypto. Declared here to - * help with backward compatibility. - */ OEMCryptoResult OEMCrypto_GenerateDerivedKeys_V15( OEMCrypto_SESSION session, const uint8_t* mac_key_context, uint32_t mac_key_context_length, const uint8_t* enc_key_context, @@ -4839,36 +4774,18 @@ typedef struct { size_t offset; // offset into the pattern in blocks for this call. } OEMCrypto_CENCEncryptPatternDesc_V15; -/* - * OEMCrypto_DecryptCENC_V15 - * @deprecated - * Not required for the current version of OEMCrypto. Declared here to - * help with backward compatibility. - */ OEMCryptoResult OEMCrypto_DecryptCENC_V15( - OEMCrypto_SESSION session, const uint8_t* data_addr, - size_t data_addr_length, bool is_encrypted, const uint8_t* iv, + OEMCrypto_SESSION session, const uint8_t* data_addr, size_t data_length, + bool is_encrypted, const uint8_t* iv, size_t block_offset, // used for CTR "cenc" mode only. - OEMCrypto_DestBufferDesc* out_buffer, + OEMCrypto_DestBufferDesc* out_buffer_descriptor, const OEMCrypto_CENCEncryptPatternDesc_V15* pattern, uint8_t subsample_flags); -/* - * OEMCrypto_GetOEMPublicCertificate_V15 - * @deprecated - * Not required for the current version of OEMCrypto. Declared here to - * help with backward compatibility. - */ OEMCryptoResult OEMCrypto_GetOEMPublicCertificate_V15( OEMCrypto_SESSION session, uint8_t* public_cert, size_t* public_cert_length); -/* - * OEMCrypto_LoadDeviceRSAKey - * @deprecated - * Not required for the current version of OEMCrypto. Declared here to - * help with backward compatibility. - */ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session, const uint8_t* wrapped_rsa_key, size_t wrapped_rsa_key_length); diff --git a/oemcrypto/include/level3.h b/oemcrypto/include/level3.h index 7616c14..8ae6646 100644 --- a/oemcrypto/include/level3.h +++ b/oemcrypto/include/level3.h @@ -96,7 +96,6 @@ namespace wvoec3 { #define Level3_AllocateSecureBuffer _lcc111 #define Level3_FreeSecureBuffer _lcc112 #else -#define Level3_IsInApp _oecc00 #define Level3_Initialize _oecc01 #define Level3_Terminate _oecc02 #define Level3_InstallKeyboxOrOEMCert _oecc03 @@ -169,11 +168,15 @@ namespace wvoec3 { #define Level3_DecryptCENC _oecc105 #define Level3_LoadDRMPrivateKey _oecc107 #define Level3_MinorAPIVersion _oecc108 -#define Level3_AllocateSecureBuffer _oecc111 -#define Level3_FreeSecureBuffer _oecc112 +// TODO(b/171121061): Renaming for oemcrypto_test to find the L3 implementation +// of the two functions below. This is to be fixed when +// OEMCrypto_AllocateSecureBuffer and OEMCrypto_FreeSecureBuffer are added to +// OEMCryptoCENC.h +#define Level3_AllocateSecureBuffer OEMCrypto_AllocateSecureBuffer +#define Level3_FreeSecureBuffer OEMCrypto_FreeSecureBuffer #endif -#define Level3_GetInitializationState _oecl3o01 +#define Level3_GetInitializationState _oecl3o01 // clang-format on extern "C" { diff --git a/oemcrypto/ref/oec_ref.gypi b/oemcrypto/ref/oec_ref.gypi index abc0124..f5c93b4 100644 --- a/oemcrypto/ref/oec_ref.gypi +++ b/oemcrypto/ref/oec_ref.gypi @@ -37,4 +37,12 @@ '../../util/libcrypto_dependency.gypi', '../odk/src/odk.gypi', ], + 'cflags': [ + # TODO(b/172518513): Remove this + '-Wno-error=cast-qual', + ], + 'cflags_c': [ + # TODO(b/159354894): Remove this + '-Wno-error=bad-function-cast', + ], } diff --git a/oemcrypto/ref/src/oemcrypto_engine_ref.h b/oemcrypto/ref/src/oemcrypto_engine_ref.h index 299c527..07d31cf 100644 --- a/oemcrypto/ref/src/oemcrypto_engine_ref.h +++ b/oemcrypto/ref/src/oemcrypto_engine_ref.h @@ -171,12 +171,12 @@ class CryptoEngine { // If 0 no restriction, otherwise it's the max subsample size for // DecryptCENC. This is not the same as the max sample or buffer size. - virtual size_t max_subsample_size() { return 1024 * 100; } // 100 KiB + virtual size_t max_subsample_size() { return 4 * 1024 * 1024; } // 4 MiB // If 0 no restriction, otherwise it's the max sample size for DecryptCENC. // This is the same as the max input and output buffer size for DecryptCENC // and CopyBuffer. It is not the same as the max subsample size. - virtual size_t max_sample_size() { return 1024 * 1024; } // 1 MiB + virtual size_t max_sample_size() { return 16 * 1024 * 1024; } // 16 MiB virtual bool srm_update_supported() { return false; } @@ -193,7 +193,7 @@ class CryptoEngine { return OEMCrypto_ERROR_NOT_IMPLEMENTED; } - virtual bool srm_blacklisted_device_attached() { return false; } + virtual bool srm_forbidden_device_attached() { return false; } // Rate limit for nonce generation. Default to 200 nonce/second. virtual int nonce_flood_count() { return 200; } diff --git a/oemcrypto/ref/src/oemcrypto_ref.cpp b/oemcrypto/ref/src/oemcrypto_ref.cpp index 9c038b6..8adb68e 100644 --- a/oemcrypto/ref/src/oemcrypto_ref.cpp +++ b/oemcrypto/ref/src/oemcrypto_ref.cpp @@ -32,9 +32,9 @@ #include "string_conversions.h" #if defined(_WIN32) -# define OEMCRYPTO_API extern "C" __declspec(dllexport) +# define OEMCRYPTO_API extern "C" __declspec(dllexport) #else // defined(_WIN32) -# define OEMCRYPTO_API extern "C" __attribute__((visibility("default"))) +# define OEMCRYPTO_API extern "C" __attribute__((visibility("default"))) #endif // defined(_WIN32) namespace { @@ -42,6 +42,12 @@ const uint8_t kBakedInCertificateMagicBytes[] = {0xDE, 0xAD, 0xBE, 0xEF}; // Maximum context key length used for performance reasons, not mandated by // specification. const size_t kMaxContextKeyLength = 1024 * 1024; +// Maximum buffer length used by reference implementation for performance +// reasons. This is not mandated by specification. +const size_t kMaxInputMessageBuferLength = 1024 * 1024; +// Maximum signature length used by reference implementation for performance +// reasons. This is not mandated by specification. +const size_t kMaxInputSignatureLength = 10 * 1024; // Return uint32 referenced through a potentially unaligned pointer. // If the pointer is nullptr, return 0. @@ -100,8 +106,8 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Terminate(void) { return OEMCrypto_SUCCESS; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_OpenSession( - OEMCrypto_SESSION* session) { +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_OpenSession(OEMCrypto_SESSION* session) { if (crypto_engine == nullptr) { LOGE("OEMCrypto_OpenSession: OEMCrypto not initialized."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -120,8 +126,8 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_OpenSession( return OEMCrypto_SUCCESS; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_CloseSession( - OEMCrypto_SESSION session) { +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_CloseSession(OEMCrypto_SESSION session) { if (crypto_engine == nullptr) { LOGE("OEMCrypto_CloseSession: OEMCrypto not initialized."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -209,7 +215,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, while (nonce_value == 0 || crypto_engine->NonceCollision(nonce_value)) { // Generate 4 bytes of random data - if (!RAND_bytes(nonce_string, 4)) { + if (RAND_bytes(nonce_string, 4) != 1) { LOGE("[OEMCrypto_GenerateNonce(): Random bytes failure]"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -309,7 +315,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadLicense(OEMCrypto_SESSION session, } SessionContext* session_ctx = crypto_engine->FindSession(session); if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("ERROR_INVALID_SESSION sid=%d", session); + LOGE("ERROR_INVALID_SESSION sid=%u", session); return OEMCrypto_ERROR_INVALID_SESSION; } return session_ctx->LoadLicense(message, message_length, core_message_length, @@ -333,7 +339,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadKeys( } SessionContext* session_ctx = crypto_engine->FindSession(session); if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("ERROR_INVALID_SESSION sid=%d", session); + LOGE("ERROR_INVALID_SESSION sid=%u", session); return OEMCrypto_ERROR_INVALID_SESSION; } if (message == nullptr || message_length == 0 || signature == nullptr || @@ -347,33 +353,38 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadKeys( !RangeCheck(message_length, enc_mac_keys, true) || !RangeCheck(message_length, pst, true) || !RangeCheck(message_length, srm_restriction_data, true)) { - LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - " - "range check.]"); + LOGE( + "[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - " + "range check.]"); return OEMCrypto_ERROR_INVALID_CONTEXT; } - for (unsigned int i = 0; i < num_keys; i++) { + for (size_t i = 0; i < num_keys; i++) { if (!RangeCheck(message_length, key_array[i].key_id, false) || !RangeCheck(message_length, key_array[i].key_data, false) || !RangeCheck(message_length, key_array[i].key_data_iv, false) || !RangeCheck(message_length, key_array[i].key_control, false) || !RangeCheck(message_length, key_array[i].key_control_iv, false)) { - LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - " - "range check %d]", i); + LOGE( + "[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - range " + "check %zu]", + i); return OEMCrypto_ERROR_INVALID_CONTEXT; } } if (enc_mac_keys.offset >= wvoec::KEY_IV_SIZE && enc_mac_keys.length > 0) { if (enc_mac_keys_iv.offset + wvoec::KEY_IV_SIZE == enc_mac_keys.offset) { - LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - " - "range check iv]"); + LOGE( + "[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - " + "range check iv]"); return OEMCrypto_ERROR_INVALID_CONTEXT; } else { if (CRYPTO_memcmp(message + enc_mac_keys.offset - wvoec::KEY_IV_SIZE, message + enc_mac_keys_iv.offset, wvoec::KEY_IV_SIZE) == 0) { - LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - " - "suspicious iv]"); + LOGE( + "[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - " + "suspicious iv]"); return OEMCrypto_ERROR_INVALID_CONTEXT; } } @@ -570,9 +581,9 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_QueryKeyControl( return OEMCrypto_SUCCESS; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_SelectKey( - const OEMCrypto_SESSION session, const uint8_t* key_id, - size_t key_id_length, OEMCryptoCipherMode cipher_mode) { +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_SelectKey(const OEMCrypto_SESSION session, const uint8_t* key_id, + size_t key_id_length, OEMCryptoCipherMode cipher_mode) { #ifndef NDEBUG if (!crypto_engine->ValidRootOfTrust()) { LOGE("[OEMCrypto_SelectKey(): ERROR_KEYBOX_INVALID]"); @@ -619,7 +630,14 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_DecryptCENC( return OEMCrypto_ERROR_KEYBOX_INVALID; } #endif - + // The maximum subsample and sample sizes we use -- if 0, we just pick a + // very large size for a sanity check. + const size_t max_subsample_size = crypto_engine->max_subsample_size() > 0 + ? crypto_engine->max_subsample_size() + : 100 * 1024 * 1024; + const size_t max_sample_size = crypto_engine->max_subsample_size() > 0 + ? crypto_engine->max_subsample_size() + : 1000 * 1024 * 1024; // Iterate through all the samples and validate them before doing any decrypt for (size_t sample_index = 0; sample_index < samples_length; ++sample_index) { const OEMCrypto_SampleDescription& sample = samples[sample_index]; @@ -636,17 +654,20 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_DecryptCENC( LOGE("[OEMCrypto_DecryptCENC(): Sample too large]"); return OEMCrypto_ERROR_BUFFER_TOO_LARGE; } - // Iterate through all the subsamples and sum their lengths size_t subsample_length_tally = 0; for (size_t subsample_index = 0; subsample_index < sample.subsamples_length; ++subsample_index) { const OEMCrypto_SubSampleDescription& subsample = sample.subsamples[subsample_index]; + // Compute the length now, but we check for possible overflow in the next + // if statement. const size_t length = subsample.num_bytes_clear + subsample.num_bytes_encrypted; - if (crypto_engine->max_subsample_size() > 0 && - length > crypto_engine->max_subsample_size()) { + if (subsample.num_bytes_clear > max_subsample_size || + subsample.num_bytes_encrypted > max_subsample_size || + length > max_subsample_size || + subsample_length_tally > max_sample_size) { // For testing reasons only, pretend that this integration only supports // the given buffer size. LOGE("[OEMCrypto_DecryptCENC(): Subsample too large]"); @@ -711,8 +732,8 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_WrapKeyboxOrOEMCert( return OEMCrypto_SUCCESS; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_InstallKeyboxOrOEMCert( - const uint8_t* keybox, size_t keyBoxLength) { +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_InstallKeyboxOrOEMCert(const uint8_t* keybox, size_t keyBoxLength) { if (crypto_engine == nullptr) { LOGE("OEMCrypto_InstallKeyboxOrOEMCert: OEMCrypto Not Initialized."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -876,7 +897,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, if (!randomData) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - if (RAND_bytes(randomData, dataLength)) { + if (RAND_bytes(randomData, dataLength) == 1) { return OEMCrypto_SUCCESS; } return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -944,11 +965,11 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30( // Now we generate a wrapped keybox. WrappedRSAKey* wrapped = reinterpret_cast(wrapped_rsa_key); // Pick a random context and IV for generating keys. - if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) { + if (RAND_bytes(wrapped->context, sizeof(wrapped->context)) != 1) { LOGE("[_RewrapDeviceRSAKey30(): RAND_bytes failed."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) { + if (RAND_bytes(wrapped->iv, sizeof(wrapped->iv)) != 1) { LOGE("[_RewrapDeviceRSAKey30(): RAND_bytes failed."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -1045,10 +1066,10 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey( // Now we generate a wrapped keybox. WrappedRSAKey* wrapped = reinterpret_cast(wrapped_rsa_key); // Pick a random context and IV for generating keys. - if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) { + if (RAND_bytes(wrapped->context, sizeof(wrapped->context)) != 1) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) { + if (RAND_bytes(wrapped->iv, sizeof(wrapped->iv)) != 1) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } const std::vector context( @@ -1178,6 +1199,10 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadDRMPrivateKey( return OEMCrypto_SUCCESS; } } + if (wrapped_rsa_key_length < sizeof(WrappedRSAKey)) { + LOGE("RSA Key has wrong size."); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } const WrappedRSAKey* wrapped = reinterpret_cast(wrapped_rsa_key); if (!crypto_engine->ValidRootOfTrust()) { @@ -1393,8 +1418,8 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetNumberOfOpenSessions(size_t* count) { return OEMCrypto_SUCCESS; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions( - size_t* maximum) { +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_GetMaxNumberOfSessions(size_t* maximum) { if (crypto_engine == nullptr) { LOGE("OEMCrypto_GetMaxNumberOfSessions: OEMCrypto Not Initialized."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -1444,6 +1469,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Encrypt( LOGE("[OEMCrypto_Generic_Encrypt(): OEMCrypto_ERROR_INVALID_CONTEXT]"); return OEMCrypto_ERROR_INVALID_CONTEXT; } + if (buffer_length > kMaxInputMessageBuferLength) { + LOGE("[OEMCrypto_Generic_Encrypt(): ERROR_BUFFER_TOO_LARGE]"); + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } + OEMCryptoResult sts = session_ctx->Generic_Encrypt(in_buffer, buffer_length, iv, algorithm, out_buffer); return sts; @@ -1470,15 +1500,19 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Decrypt( LOGE("[OEMCrypto_Generic_Decrypt(): OEMCrypto_ERROR_INVALID_CONTEXT]"); return OEMCrypto_ERROR_INVALID_CONTEXT; } + if (buffer_length > kMaxInputMessageBuferLength) { + LOGE("[OEMCrypto_Generic_Encrypt(): ERROR_BUFFER_TOO_LARGE]"); + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } OEMCryptoResult sts = session_ctx->Generic_Decrypt(in_buffer, buffer_length, iv, algorithm, out_buffer); return sts; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Sign( - OEMCrypto_SESSION session, const uint8_t* in_buffer, size_t buffer_length, - OEMCrypto_Algorithm algorithm, uint8_t* signature, - size_t* signature_length) { +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, const uint8_t* in_buffer, + size_t buffer_length, OEMCrypto_Algorithm algorithm, + uint8_t* signature, size_t* signature_length) { if (crypto_engine == nullptr) { LOGE("OEMCrypto_Generic_Sign: OEMCrypto Not Initialized."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -1500,15 +1534,19 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Sign( LOGE("[OEMCrypto_Generic_Sign(): OEMCrypto_ERROR_INVALID_CONTEXT]"); return OEMCrypto_ERROR_INVALID_CONTEXT; } + if (buffer_length > kMaxInputMessageBuferLength) { + LOGE("[OEMCrypto_Generic_Sign(): ERROR_BUFFER_TOO_LARGE]"); + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } OEMCryptoResult sts = session_ctx->Generic_Sign( in_buffer, buffer_length, algorithm, signature, signature_length); return sts; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Verify( - OEMCrypto_SESSION session, const uint8_t* in_buffer, size_t buffer_length, - OEMCrypto_Algorithm algorithm, const uint8_t* signature, - size_t signature_length) { +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_Generic_Verify(OEMCrypto_SESSION session, const uint8_t* in_buffer, + size_t buffer_length, OEMCrypto_Algorithm algorithm, + const uint8_t* signature, size_t signature_length) { if (crypto_engine == nullptr) { LOGE("OEMCrypto_Generic_Verify: OEMCrypto Not Initialized."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -1525,10 +1563,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Verify( if (signature_length != SHA256_DIGEST_LENGTH) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - if (in_buffer == nullptr || buffer_length == 0 || signature == nullptr) { + if (in_buffer == nullptr || buffer_length == 0 || signature == nullptr || + signature_length > kMaxInputSignatureLength) { LOGE("[OEMCrypto_Generic_Verify(): OEMCrypto_ERROR_INVALID_CONTEXT]"); return OEMCrypto_ERROR_INVALID_CONTEXT; } + if (buffer_length > kMaxInputMessageBuferLength) { + LOGE("[OEMCrypto_Generic_Verify(): ERROR_BUFFER_TOO_LARGE]"); + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } return session_ctx->Generic_Verify(in_buffer, buffer_length, algorithm, signature, signature_length); } @@ -1585,8 +1628,8 @@ OEMCRYPTO_API bool OEMCrypto_IsSRMUpdateSupported() { return result; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetCurrentSRMVersion( - uint16_t* version) { +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_GetCurrentSRMVersion(uint16_t* version) { if (crypto_engine == nullptr) { LOGE("OEMCrypto_GetCurrentSRMVersion: OEMCrypto Not Initialized."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -1629,8 +1672,8 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_CreateUsageTableHeader( header_buffer, header_buffer_length); } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadUsageTableHeader( - const uint8_t* buffer, size_t buffer_length) { +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_LoadUsageTableHeader(const uint8_t* buffer, size_t buffer_length) { if (crypto_engine == nullptr) { LOGE("OEMCrypto_LoadUsageTableHeader: OEMCrypto Not Initialized."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -1667,9 +1710,9 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_CreateNewUsageEntry( return sts; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadUsageEntry( - OEMCrypto_SESSION session, uint32_t index, const uint8_t* buffer, - size_t buffer_size) { +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_LoadUsageEntry(OEMCrypto_SESSION session, uint32_t index, + const uint8_t* buffer, size_t buffer_size) { if (crypto_engine == nullptr) { LOGE("OEMCrypto_LoadUsageEntry: OEMCrypto Not Initialized."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -1690,10 +1733,10 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadUsageEntry( return session_ctx->LoadUsageEntry(index, bufferv); } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_UpdateUsageEntry( - OEMCrypto_SESSION session, uint8_t* header_buffer, - size_t* header_buffer_length, uint8_t* entry_buffer, - size_t* entry_buffer_length) { +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_UpdateUsageEntry(OEMCrypto_SESSION session, uint8_t* header_buffer, + size_t* header_buffer_length, uint8_t* entry_buffer, + size_t* entry_buffer_length) { if (crypto_engine == nullptr) { LOGE("OEMCrypto_UpdateUsageEntry: OEMCrypto Not Initialized."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -1748,9 +1791,9 @@ OEMCRYPTO_API uint32_t OEMCrypto_SupportsDecryptHash() { return OEMCrypto_CRC_Clear_Buffer; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_SetDecryptHash( - OEMCrypto_SESSION session, uint32_t frame_number, const uint8_t* hash, - size_t hash_length) { +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_SetDecryptHash(OEMCrypto_SESSION session, uint32_t frame_number, + const uint8_t* hash, size_t hash_length) { if (crypto_engine == nullptr) { LOGE("OEMCrypto_SetDecryptHash: OEMCrypto Not Initialized."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; diff --git a/oemcrypto/ref/src/oemcrypto_session.cpp b/oemcrypto/ref/src/oemcrypto_session.cpp index cbbc6fb..1567123 100644 --- a/oemcrypto/ref/src/oemcrypto_session.cpp +++ b/oemcrypto/ref/src/oemcrypto_session.cpp @@ -303,9 +303,12 @@ bool SessionContext::RSADeriveKeys( LOGE("[RSADeriveKeys(): no RSA key set]"); return false; } - if (enc_session_key.size() != static_cast(RSA_size(rsa_key()))) { - LOGE("[RSADeriveKeys(): encrypted session key wrong size:%zu, expected %d]", - enc_session_key.size(), RSA_size(rsa_key())); + const size_t actual_key_size = static_cast(RSA_size(rsa_key())); + if (enc_session_key.size() != actual_key_size) { + LOGE( + "[RSADeriveKeys(): encrypted session key wrong size: %zu, expected " + "%zu]", + enc_session_key.size(), actual_key_size); dump_boringssl_error(); return false; } @@ -806,8 +809,8 @@ OEMCryptoResult SessionContext::LoadKeysNoSignature( LOGW("[LoadKeys: SRM Version is too small %u, required: %u", current_version, minimum_version); srm_requirements_status_ = InvalidSRMVersion; - } else if (ce_->srm_blacklisted_device_attached()) { - LOGW("[LoadKeys: SRM blacklisted device attached]"); + } else if (ce_->srm_forbidden_device_attached()) { + LOGW("[LoadKeys: SRM forbidden device attached]"); srm_requirements_status_ = InvalidSRMVersion; } else { LOGI("[LoadKeys: SRM Versions is %u, required: %u]", current_version, @@ -1193,6 +1196,36 @@ OEMCryptoResult SessionContext::CheckKeyUse(const std::string& log_string, return OEMCrypto_ERROR_DECRYPT_FAILED; } } + if (!ce_->config_local_display_only()) { + // Only look at HDCP restrictions if the display can be non-local. + if (control.control_bits() & wvoec::kControlHDCPRequired) { + uint8_t required_hdcp = + (control.control_bits() & wvoec::kControlHDCPVersionMask) >> + wvoec::kControlHDCPVersionShift; + if (ce_->srm_forbidden_device_attached()) { + required_hdcp = HDCP_NO_DIGITAL_OUTPUT; + } + // For reference implementation, we pretend we can handle the current + // HDCP version. + if (required_hdcp > ce_->config_current_hdcp_capability() || + ce_->config_current_hdcp_capability() == 0) { + return OEMCrypto_ERROR_INSUFFICIENT_HDCP; + } + } + } + // Return an error if analog displays should be disabled. + if ((control.control_bits() & wvoec::kControlDisableAnalogOutput) && + ce_->analog_display_active()) { + LOGE("[%s(): control bit says disable analog", log_string.c_str()); + return OEMCrypto_ERROR_ANALOG_OUTPUT; + } + // Check if CGMS is required. + if (control.control_bits() & wvoec::kControlCGMSMask) { + if (ce_->analog_display_active() && !ce_->cgms_a_active()) { + LOGE("[%s(): control bit says CGMS required", log_string.c_str()); + return OEMCrypto_ERROR_ANALOG_OUTPUT; + } + } if (!decrypt_started_) { // The reference implementation does not have a hardware timer. uint64_t* timer_expiration = nullptr; @@ -1207,44 +1240,6 @@ OEMCryptoResult SessionContext::CheckKeyUse(const std::string& log_string, if (result == ODK_TIMER_EXPIRED) return OEMCrypto_ERROR_KEY_EXPIRED; if (usage_entry_ != nullptr) usage_entry_->set_recent_decrypt(true); } - if (!ce_->config_local_display_only()) { - // Only look at HDCP restrictions if the display can be non-local. - if (control.control_bits() & wvoec::kControlHDCPRequired) { - uint8_t required_hdcp = - (control.control_bits() & wvoec::kControlHDCPVersionMask) >> - wvoec::kControlHDCPVersionShift; - if (ce_->srm_blacklisted_device_attached()) { - required_hdcp = HDCP_NO_DIGITAL_OUTPUT; - } - // For reference implementation, we pretend we can handle the current - // HDCP version. - if (required_hdcp > ce_->config_current_hdcp_capability() || - ce_->config_current_hdcp_capability() == 0) { - return OEMCrypto_ERROR_INSUFFICIENT_HDCP; - } - } - } - // If the output buffer is clear, then we cannot control whether the output is - // an active analog display. In that case, return an error if analog displays - // should be disabled. - if ((control.control_bits() & wvoec::kControlDisableAnalogOutput) && - (ce_->analog_display_active() || - (buffer_type == OEMCrypto_BufferType_Clear))) { - LOGE("[%s(): control bit says disable analog", log_string.c_str()); - return OEMCrypto_ERROR_ANALOG_OUTPUT; - } - // Check if CGMS is required. - if (control.control_bits() & wvoec::kControlCGMSMask) { - // We can't control CGMS for a clear buffer. - if (buffer_type == OEMCrypto_BufferType_Clear) { - LOGE("[%s(): CGMS required, but buffer is clear", log_string.c_str()); - return OEMCrypto_ERROR_ANALOG_OUTPUT; - } - if (ce_->analog_display_active() && !ce_->cgms_a_active()) { - LOGE("[%s(): control bit says CGMS required", log_string.c_str()); - return OEMCrypto_ERROR_ANALOG_OUTPUT; - } - } decrypt_started_ = true; // First playback for session. return OEMCrypto_SUCCESS; } @@ -1761,6 +1756,8 @@ OEMCryptoResult SessionContext::DecryptCTR(const uint8_t* key_u8, const uint8_t* cipher_data, size_t cipher_data_length, uint8_t* clear_data) { + if (block_offset >= AES_BLOCK_SIZE) return OEMCrypto_ERROR_INVALID_CONTEXT; + // Local copy (will be modified). // Allocated as 64-bit ints to enforce 64-bit alignment for later access as a // 64-bit value. diff --git a/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp b/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp index 69f2f46..d61ec05 100644 --- a/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp +++ b/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp @@ -209,7 +209,10 @@ OEMCryptoResult UsageTableEntry::SaveData(CryptoEngine* ce, } // Encrypt the entry. - RAND_bytes(encrypted->iv, wvoec::KEY_IV_SIZE); + if (RAND_bytes(encrypted->iv, wvoec::KEY_IV_SIZE) != 1) { + LOGE("SaveUsageEntry: Could not generate iv."); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; // working iv buffer. memcpy(iv_buffer, encrypted->iv, wvoec::KEY_IV_SIZE); AES_KEY aes_key; @@ -292,7 +295,7 @@ OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index, // Check that the index is correct. if (index != clear->data.index) { - LOGE("LoadUsageEntry: entry says index is %d, not %d", clear->data.index, + LOGE("LoadUsageEntry: entry says index is %u, not %u", clear->data.index, index); return OEMCrypto_ERROR_INVALID_SESSION; } @@ -386,7 +389,7 @@ OEMCryptoResult UsageTable::LoadUsageEntry( if (index >= generation_numbers_.size()) return OEMCrypto_ERROR_UNKNOWN_FAILURE; if (sessions_[index]) { - LOGE("LoadUsageEntry: index %d used by other session.", index); + LOGE("LoadUsageEntry: index %u used by other session.", index); return OEMCrypto_ERROR_INVALID_SESSION; } const size_t max = ce_->max_usage_table_size(); @@ -479,7 +482,10 @@ OEMCryptoResult UsageTable::SaveUsageTableHeader(uint8_t* signed_buffer, } // Encrypt the entry. - RAND_bytes(encrypted->iv, wvoec::KEY_IV_SIZE); + if (RAND_bytes(encrypted->iv, wvoec::KEY_IV_SIZE) != 1) { + LOGE("SaveUsageHeader: Could not generate iv entry."); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; // working iv buffer. memcpy(iv_buffer, encrypted->iv, wvoec::KEY_IV_SIZE); AES_KEY aes_key; @@ -667,9 +673,8 @@ bool UsageTable::LoadGenerationNumber(bool or_make_new_one) { auto file = file_system->Open(filename, wvcdm::FileSystem::kReadOnly); if (!file) { if (or_make_new_one) { - RAND_bytes(reinterpret_cast(&master_generation_number_), - sizeof(int64_t)); - return true; + return RAND_bytes(reinterpret_cast(&master_generation_number_), + sizeof(int64_t)) == 1; } LOGE("UsageTable: File open failed: %s (clearing table)", path.c_str()); master_generation_number_ = 0; diff --git a/oemcrypto/test/README.md b/oemcrypto/test/README.md new file mode 100644 index 0000000..bcae4b3 --- /dev/null +++ b/oemcrypto/test/README.md @@ -0,0 +1,73 @@ +# OEMCrypto Memory Unit Tests + +## Objective + +* Add OEMCrypto buffer overflow unit tests (indirect way of fuzzing) to verify + OEMCrypto API behavior when the parameters passed to the API are out of + range or not reasonable. The API can return an error code, but shouldn't + crash. + +* A lot of OEMCrypto APIs take buffers and their length as inputs to the APIs + and we have added unit tests with buffers of varying lengths (small + to huge) to verify API behavior which is an indirect and simplest way of + fuzz testing to detect buffer overflows. + +* Add the tests for OEMCrypto APIs with prefix `OEMCryptoMemory` in the + following format. Huge length is set at 100 MB as of now. + + ```cpp + for (size_t length=small_length; length subsamples.size()) return 0; } // Sample loop. // Allocate input/output buffers for each sample description. vector input_buffer(total_input_data_length); - RAND_bytes(input_buffer.data(), total_input_data_length); size_t input_buffer_index = 0; for (size_t i = 0; i < samples_length; i++) { sample_descriptions[i].buffers.input_data = diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp b/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp index 8eaeabf..e263c13 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp +++ b/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp @@ -5,22 +5,65 @@ # Builds under the CDM ./build.py (target platform) build system # Refer to the distribution package's README for details. { + 'target_defaults': { + 'type': 'executable', + 'includes': [ + 'oemcrypto_fuzztests.gypi', + ], + }, 'variables': { - 'oemcrypto_lib%': '', - 'openssl_config%': 'system', - 'openssl_target%': '', + # Flag to select appropriate underlying oemcrypto implementation when + # buiding fuzz binaries. + 'oemcrypto_implementation_version%': 'reference', }, 'targets': [ { - 'target_name': 'wv_ce_cdm_oemcrypto_generate_signature_fuzz_test', - 'type': 'executable', + 'target_name': 'oemcrypto_load_license_fuzz', 'sources': [ - # The test runner and the testing device certificate. - 'oemcrypto_generate_signature.cc', + 'oemcrypto_load_license_fuzz.cc', ], - 'includes': [ - 'oemcrypto_fuzztests.gypi', + }, + { + 'target_name': 'oemcrypto_load_provisioning_fuzz', + 'sources': [ + 'oemcrypto_load_provisioning_fuzz.cc', ], - }, + }, + { + 'target_name': 'oemcrypto_load_renewal_fuzz', + 'sources': [ + 'oemcrypto_load_renewal_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_license_request_fuzz', + 'sources': [ + 'oemcrypto_license_request_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_provisioning_request_fuzz', + 'sources': [ + 'oemcrypto_provisioning_request_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_renewal_request_fuzz', + 'sources': [ + 'oemcrypto_renewal_request_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_decrypt_cenc_fuzz', + 'sources': [ + 'oemcrypto_decrypt_cenc_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_load_entitled_content_keys_fuzz', + 'sources': [ + 'oemcrypto_load_entitled_content_keys_fuzz.cc', + ], + }, ], } diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi b/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi index 0363515..2b23666 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi +++ b/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi @@ -1,48 +1,101 @@ # Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary #source code may only be used and distributed under the Widevine Master License #Agreement. -# -# Include this in any custom unit test targets. -# Does not include the test runner main. + { + 'variables': { + 'boringssl_libcrypto_path%': '../../../third_party/boringssl/boringssl.gyp:crypto', + 'boringssl_libssl_path%': '../../../third_party/boringssl/boringssl.gyp:ssl', + 'oemcrypto_dir': '../..', + 'platform_specific_dir': '../../../linux/src', + 'privacy_crypto_impl%': 'boringssl', + # Flag used to generate source based code coverage reports. + 'generate_code_coverage_report%': 'false', + 'util_dir': '../../../util', + }, 'sources': [ + '../../odk/src/core_message_deserialize.cpp', + '../../odk/src/core_message_serialize.cpp', '../oec_device_features.cpp', '../oec_key_deriver.cpp', + '../oemcrypto_corpus_generator_helper.cpp', '../oec_session_util.cpp', + '../oemcrypto_corpus_generator_helper.cpp', + 'oemcrypto_fuzz_helper.cc', '../oemcrypto_session_tests_helper.cpp', - '../oemcrypto_session_tests_helper.h', - '../../../cdm/test/device_cert.cpp', - '../../../cdm/test/device_cert.h', + '<(platform_specific_dir)/file_store.cpp', + '<(platform_specific_dir)/log.cpp', + '<(util_dir)/src/platform.cpp', + '<(util_dir)/src/rw_lock.cpp', + '<(util_dir)/src/string_conversions.cpp', + '<(util_dir)/test/test_sleep.cpp', + '<(util_dir)/test/test_clock.cpp', ], 'include_dirs': [ - '../../../core/include', # log.h - '../../include', - '../../ref/src', # oemcrypto_key_ref.h - '../', - '../../../cdm/test', + '../../../third_party/fuzz', + '<(util_dir)/include', + '<(util_dir)/test', + '<(oemcrypto_dir)/include', + '<(oemcrypto_dir)/test', + '<(oemcrypto_dir)/test/fuzz_tests', + '<(oemcrypto_dir)/odk/include', + '<(oemcrypto_dir)/odk/src', + '<(oemcrypto_dir)/odkitee/oemcrypto_ta', ], - 'defines': [ - 'OEMCRYPTO_TESTS', - 'OEMCRYPTO_FUZZ_TESTS', - ], - 'libraries': [ - '../../../third_party/fuzz/platforms/x86-64/libFuzzer.a', + 'includes': [ + '../../../util/libssl_dependency.gypi', ], 'dependencies': [ - '../../../cdm/cdm.gyp:widevine_ce_cdm_shared', - '../../../third_party/gmock.gyp:gmock', '../../../third_party/gmock.gyp:gtest', + '../../../third_party/gmock.gyp:gmock', + ], + 'defines': [ + 'OEMCRYPTO_FUZZ_TESTS', ], 'conditions': [ - ['oemcrypto_lib==""', { - 'includes': [ - '../../ref/oec_ref.gypi', - ], - }, { - 'libraries': [ - '../../../third_party/fuzz/platforms/x86-64/libFuzzer.a', - '<(oemcrypto_lib)', - ], + ['generate_code_coverage_report=="false"', { + # Include flags to build fuzzer binaries for cluster fuzz. + 'cflags_cc': [ + '-std=c++11', + '-fsanitize=fuzzer,address,undefined', + # Need -g flag to include source line numbers in error stack trace. + '-g', + ], + 'ldflags': [ + '-fPIC', + '-fsanitize=fuzzer,address,undefined', + ], }], + ['generate_code_coverage_report=="true"', { + # Include flags to build fuzzer binaries to generate source based code coverage reports. + 'cflags_cc': [ + '-std=c++11', + '-fprofile-instr-generate', + '-fcoverage-mapping', + ], + 'ldflags': [ + '-fPIC', + '-fsanitize=fuzzer,address,undefined', + '-fprofile-instr-generate', + '-fcoverage-mapping', + ], + }], + ['oemcrypto_implementation_version=="reference"', { + # Include oemcrypto reference implementation code for building reference + # implementation fuzz binaries. + 'includes': [ + '../../ref/oec_ref.gypi', + ], + }], + ['oemcrypto_implementation_version=="odkitee"', { + # Include oemcrypto odkitee implementation code for building odkitee + # implementation fuzz binaries. + 'dependencies': [ + '../../odkitee/oemcrypto_ta/oemcrypto_ta.gyp:oemcrypto_ta', + ], + }], + ], # conditions + 'libraries': [ + '-lpthread', ], } diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_dispatcher_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_dispatcher_fuzz.cc new file mode 100644 index 0000000..1a3c770 --- /dev/null +++ b/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_dispatcher_fuzz.cc @@ -0,0 +1,77 @@ +#include + +#include "dispatcher.h" +#include "marshaller_base.h" +#include "transport_interface.h" + +namespace wvoec { + +void InitializeODKMessage(ODK_Message* message, uint8_t* data, size_t size) { + ODK_Message_Impl* impl = (ODK_Message_Impl*)message; + impl->base = data; + impl->size = size; + impl->capacity = size; + impl->read_offset = 0; + impl->status = MESSAGE_STATUS_OK; +} + +void OpenOEMCryptoTASession() { + ODK_Message request; + ODK_Message* response = NULL; + uint8_t response_buffer[0x1000]; + uint8_t request_body[] = { + 0x06, // TAG_UINT32 + 0x09, 0x00, 0x00, 0x00, // API value (0x09) + 0x01, // TAG_BOOL + 0x00, // value (false) + 0x0a // TAG_EOM + }; + + InitializeODKMessage(&request, request_body, sizeof(request_body)); + + ODK_DispatchMessage(&request, &response); + if (response != NULL) ODK_Transport_DeallocateMessage(response); +} + +void InitializeOEMCryptoTA() { + ODK_Message init_request; + ODK_Message* init_response = NULL; + uint8_t response_buffer[0x1000]; + uint8_t init_request_body[] = { + 0x06, // TAG_UINT32 + 0x01, 0x00, 0x00, 0x00, // API value(0x01) + 0x0a // TAG_EOM + }; + + InitializeODKMessage(&init_request, init_request_body, + sizeof(init_request_body)); + + ODK_DispatchMessage(&init_request, &init_response); + if (init_response != NULL) ODK_Transport_DeallocateMessage(init_response); +} + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { + ODK_InitializeDispatcher(); + InitializeOEMCryptoTA(); + OpenOEMCryptoTASession(); + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + ODK_Message request; + ODK_Message* response = NULL; + unsigned char response_buffer[0x1000]; + + uint8_t* input = new uint8_t[size]; + memcpy(input, data, size); + + InitializeODKMessage(&request, input, size); + + ODK_DispatchMessage(&request, &response); + if (response != NULL) ODK_Transport_DeallocateMessage(response); + + delete[] input; + return 0; +} + +} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_fuzztests.gyp b/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_fuzztests.gyp new file mode 100644 index 0000000..afb4c7e --- /dev/null +++ b/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_fuzztests.gyp @@ -0,0 +1,85 @@ +# Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine Master +# License Agreement. +{ + 'target_defaults': { + 'type': 'executable', + 'includes': [ + 'oemcrypto_fuzztests.gypi', + ], + }, + 'variables': { + # Flag to select appropriate underlying oemcrypto implementation when + # buiding fuzz binaries. + 'oemcrypto_implementation_version%': 'odkitee', + 'oemcrypto_dir': '../..', + }, + 'targets': [ + { + 'target_name': 'oemcrypto_odkitee_load_license_fuzz', + 'sources': [ + 'oemcrypto_load_license_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_odkitee_load_provisioning_fuzz', + 'sources': [ + 'oemcrypto_load_provisioning_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_odkitee_load_renewal_fuzz', + 'sources': [ + 'oemcrypto_load_renewal_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_odkitee_license_request_fuzz', + 'sources': [ + 'oemcrypto_license_request_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_odkitee_provisioning_request_fuzz', + 'sources': [ + 'oemcrypto_provisioning_request_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_odkitee_renewal_request_fuzz', + 'sources': [ + 'oemcrypto_renewal_request_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_odkitee_decrypt_cenc_fuzz', + 'sources': [ + 'oemcrypto_decrypt_cenc_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_odkitee_load_entitled_content_keys_fuzz', + 'sources': [ + 'oemcrypto_load_entitled_content_keys_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_odkitee_dispatcher_fuzz', + 'include_dirs': [ + '<(oemcrypto_dir)/odkitee/serialization/common', + '<(oemcrypto_dir)/odkitee/serialization/os_interfaces', + '<(oemcrypto_dir)/odkitee/serialization/tee', + '<(oemcrypto_dir)/odkitee/serialization/tee/include', + '<(oemcrypto_dir)/odkitee/serialization/ports/trusty/include/', + ], + 'dependencies': [ + '<(oemcrypto_dir)/odkitee/serialization/tee/tee.gyp:odkitee_tee', + ], + 'sources': [ + 'oemcrypto_odkitee_dispatcher_fuzz.cc', + '<(oemcrypto_dir)/odkitee/serialization/test/transport_interface.c', + '<(oemcrypto_dir)/odkitee/serialization/ports/trusty/serialization_adapter/shared_memory.c', + ], + }, + ], +} diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_fuzztests.gypi b/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_fuzztests.gypi new file mode 100644 index 0000000..316b051 --- /dev/null +++ b/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_fuzztests.gypi @@ -0,0 +1,42 @@ +# Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine Master +# License Agreement. + +# gypi file to be included using --includes option while building oemcrypto +# odkitee fuzz binaries. Odkitee classes needs to be instrumented with fuzzer +# but only when being built for fuzzing. Instead of directly updating +# oemcrypto_ta.gyp target, we use gypi in build_oemcrypto_fuzztests script. +{ + 'target_defaults': { + 'variables': { + # Flag used to generate source based code coverage reports. + 'generate_code_coverage_report%': 'false', + # Flag to indicate that the code is being built with libFuzzer + # instrumentation enabled. + 'enable_fuzzing_instrumentation': 'true', + }, + # Include flags to build fuzzer binaries to generate source based code coverage reports. + 'cflags': [ + '-fsanitize=fuzzer,address,undefined', + # Need -g flag to include source line numbers in error stack trace. + '-g', + ], + 'ldflags': [ + '-fPIC', + '-fsanitize=fuzzer,address,undefined', + ], + 'conditions': [ + ['generate_code_coverage_report=="true"', { + # Include flags to build fuzzer binaries to generate source based code coverage reports. + 'cflags': [ + '-fprofile-instr-generate', + '-fcoverage-mapping', + ], + 'ldflags': [ + '-fprofile-instr-generate', + '-fcoverage-mapping', + ], + }], + ], + }, +} diff --git a/oemcrypto/test/fuzz_tests/platforms/x86-64/fuzzer_settings.gypi b/oemcrypto/test/fuzz_tests/platforms/x86-64/fuzzer_settings.gypi new file mode 100644 index 0000000..718280b --- /dev/null +++ b/oemcrypto/test/fuzz_tests/platforms/x86-64/fuzzer_settings.gypi @@ -0,0 +1,78 @@ +# Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine Master +# License Agreement. +{ + # Here you can set platform-specific compiler settings. + 'target_defaults': { + # These are flags passed to the compiler for all C & C++ files. + 'cflags': [ + '-fsanitize=address', + '-fsanitize-coverage=trace-pc-guard', + '-fPIC', + ], + + # These are flags passed to the compiler for plain C only. + 'cflags_c': [ + '-fsanitize-coverage=trace-pc-guard', + '-fsanitize=address', + '-fPIC', + ], + + # These are flags passed to the compiler for C++ only. + 'cflags_cc': [ + '-fsanitize-coverage=trace-pc-guard', + '-fsanitize=address', + '-fPIC', + ], + + # These are flags passed to the linker. + 'ldflags': [ + '-fsanitize=address', + ], + + # These are macros set by the compiler. + 'defines': [ + #'EXAMPLE_MACRO_WITH_NO_VALUE', + #'EXAMPLE_KEY=EXAMPLE_VALUE', + ], + + # These are additional include paths to search for headers. + 'include_dirs': [ + ], + + 'target_conditions': [ + ['_toolset == "host"', { + # These are settings specifically for the host toolchain. + # The extra equals sign in the key name instructs gyp to replace + # the generic settings above rather than append to them. + 'cflags=': [ + '-fsanitize-coverage=trace-pc-guard', + '-fsanitize=address', + '-fPIC', + ], + + 'cflags_c=': [ + '-fsanitize-coverage=trace-pc-guard', + '-fsanitize=address', + '-fPIC', + ], + + 'cflags_cc=': [ + '-fsanitize-coverage=trace-pc-guard', + '-fsanitize=address', + '-fPIC', + ], + + 'ldflags=': [ + '-fsanitize=address', + ], + + 'defines=': [ + ], + + 'include_dirs=': [ + ], + }], # end _toolset == "host" condition + ], # end target_conditions + }, # end target_defaults +} diff --git a/oemcrypto/test/oec_session_util.cpp b/oemcrypto/test/oec_session_util.cpp index 5dd0299..0fc0f90 100644 --- a/oemcrypto/test/oec_session_util.cpp +++ b/oemcrypto/test/oec_session_util.cpp @@ -144,26 +144,28 @@ Test_PST_Report::Test_PST_Report(const std::string& pst_in, template -void RoundTrip::SignAndVerifyRequest() { +OEMCryptoResult +RoundTrip:: + SignAndCreateRequestWithCustomBufferLengths(bool verify_request) { // In the real world, a message should be signed by the client and // verified by the server. This simulates that. size_t gen_signature_length = 0; size_t core_message_length = 0; constexpr size_t small_size = 42; // arbitrary. - size_t message_size = - std::max(required_message_size_, core_message_length + small_size); - vector data(message_size, 0); - for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF; - ASSERT_EQ( - PrepAndSignRequest(session()->session_id(), data.data(), data.size(), - &core_message_length, nullptr, &gen_signature_length), - OEMCrypto_ERROR_SHORT_BUFFER); + uint32_t session_id = session()->session_id(); + GetDefaultRequestSignatureAndCoreMessageLengths( + session_id, small_size, &gen_signature_length, &core_message_length); + // Used to test request APIs with varying lengths of core message. + core_message_length = + std::max(core_message_length, required_core_message_size_); + // Used to test request APIs with varying lengths of signature. + gen_signature_length = + std::max(gen_signature_length, required_request_signature_size_); // Make the message buffer a little bigger than the core message, or the // required size, whichever is larger. - message_size = + size_t message_size = std::max(required_message_size_, core_message_length + small_size); - data.resize(message_size); + vector data(message_size); for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF; if (ShouldGenerateCorpus()) { WriteRequestApiCorpus(gen_signature_length, @@ -171,17 +173,32 @@ void RoundTrip gen_signature(gen_signature_length); - ASSERT_EQ(PrepAndSignRequest(session()->session_id(), data.data(), - data.size(), &core_message_length, - gen_signature.data(), &gen_signature_length), - OEMCrypto_SUCCESS); + OEMCryptoResult result = PrepAndSignRequest( + session()->session_id(), data.data(), data.size(), &core_message_length, + gen_signature.data(), &gen_signature_length); + // We need to fill in core request and verify signature only for calls other + // than OEMCryptoMemory buffer overflow test. Any test other than buffer + // overflow will pass true. + if (!verify_request || result != OEMCrypto_SUCCESS) return result; if (global_features.api_version >= kCoreMessagesAPI) { - ASSERT_GT(data.size(), core_message_length); std::string core_message(reinterpret_cast(data.data()), core_message_length); FillAndVerifyCoreRequest(core_message); } VerifyRequestSignature(data, gen_signature, core_message_length); + return result; +} + +template +void GetDefaultRequestSignatureAndCoreMessageLengths( + uint32_t& session_id, const size_t& small_size, + size_t* gen_signature_length, size_t* core_message_length) { + vector data(small_size); + for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF; + ASSERT_EQ( + PrepAndSignRequest(session_id, data.data(), data.size(), + core_message_length, nullptr, gen_signature_length), + OEMCrypto_ERROR_SHORT_BUFFER); } template = kCoreMessagesAPI) { ASSERT_TRUE( oemcrypto_core_message::serialize::CreateCoreProvisioningResponse( core_response_, core_request_, &serialized_core_message_)); + // Resizing for huge core message length unit tests. + serialized_core_message_.resize( + std::max(required_core_message_size_, serialized_core_message_.size())); } // Make the message buffer a just big enough, or the // required size, whichever is larger. @@ -689,6 +722,10 @@ void LicenseRoundTrip::EncryptAndSignResponse() { ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreLicenseResponse( core_response_, core_request_, request_hash_string, &serialized_core_message_)); + // Resize serialize core message to be just big enough or required core + // message size, whichever is larger. + serialized_core_message_.resize( + std::max(required_core_message_size_, serialized_core_message_.size())); } // Make the message buffer a just big enough, or the @@ -701,7 +738,6 @@ void LicenseRoundTrip::EncryptAndSignResponse() { for (size_t i = 0; i < encrypted_response_.size(); i++) { encrypted_response_[i] = i % 0x100; } - ASSERT_GE(kMaxCoreMessage, serialized_core_message_.size()); ASSERT_GE(encrypted_response_.size(), serialized_core_message_.size()); memcpy(encrypted_response_.data(), serialized_core_message_.data(), serialized_core_message_.size()); @@ -716,6 +752,11 @@ void LicenseRoundTrip::EncryptAndSignResponse() { } OEMCryptoResult LicenseRoundTrip::LoadResponse(Session* session) { + return LoadResponse(session, true); +} + +OEMCryptoResult LicenseRoundTrip::LoadResponse(Session* session, + bool verify_keys) { EXPECT_NE(session, nullptr); // Write corpus for oemcrypto_load_license_fuzz. Fuzz script expects // unecnrypted response from license server as input corpus data. @@ -762,7 +803,7 @@ OEMCryptoResult LicenseRoundTrip::LoadResponse(Session* session) { encrypted_response_.size(), serialized_core_message_.size(), response_signature_.data(), response_signature_.size()); } - if (result == OEMCrypto_SUCCESS) { + if (verify_keys && result == OEMCrypto_SUCCESS) { // Give the session object a copy of the license truth data so that it can // call SelectKey, use key control information, and so that it has key data // to verify decrypt operations. @@ -861,6 +902,18 @@ void EntitledMessage::MakeOneKey(size_t entitlement_key_index) { key_data->content_key_data_iv, sizeof(key_data->content_key_data_iv)); } +OEMCrypto_EntitledContentKeyObject* EntitledMessage::entitled_key_array() { + return entitled_key_array_; +} + +EntitledContentKeyData* EntitledMessage::entitled_key_data() { + return entitled_key_data_; +} + +size_t EntitledMessage::entitled_key_data_size() { + return sizeof(entitled_key_data_); +} + void EntitledMessage::SetEntitlementKeyId(unsigned int index, const std::string& key_id) { ASSERT_LT(index, num_keys_); @@ -884,6 +937,32 @@ OEMCrypto_Substring EntitledMessage::FindSubstring(const void* ptr, } void EntitledMessage::LoadKeys(OEMCryptoResult expected_sts) { + EncryptContentKey(); + ASSERT_EQ(expected_sts, + OEMCrypto_LoadEntitledContentKeys( + license_messages_->session()->session_id(), + reinterpret_cast(entitled_key_data_), + sizeof(entitled_key_data_), num_keys_, entitled_key_array_)); + if (expected_sts != OEMCrypto_SUCCESS) { + return; + } + VerifyEntitlementTestKeys(); +} + +OEMCryptoResult EntitledMessage::LoadKeys(const vector& message) { + return OEMCrypto_LoadEntitledContentKeys( + license_messages_->session()->session_id(), message.data(), + message.size(), num_keys_, entitled_key_array_); +} + +OEMCryptoResult EntitledMessage::LoadKeys() { + return OEMCrypto_LoadEntitledContentKeys( + license_messages_->session()->session_id(), + reinterpret_cast(entitled_key_data_), + sizeof(entitled_key_data_), num_keys_, entitled_key_array_); +} + +void EntitledMessage::EncryptContentKey() { for (size_t i = 0; i < num_keys_; ++i) { EntitledContentKeyData* key_data = &entitled_key_data_[i]; const size_t entitlement_key_index = key_data->key_index; @@ -912,15 +991,6 @@ void EntitledMessage::LoadKeys(OEMCryptoResult expected_sts) { AppendToFile(file_name, reinterpret_cast(entitled_key_array_), num_keys_); } - ASSERT_EQ(expected_sts, - OEMCrypto_LoadEntitledContentKeys( - license_messages_->session()->session_id(), - reinterpret_cast(entitled_key_data_), - sizeof(entitled_key_data_), num_keys_, entitled_key_array_)); - if (expected_sts != OEMCrypto_SUCCESS) { - return; - } - VerifyEntitlementTestKeys(); } // This function verifies that the key control block reported by OEMCrypto agree @@ -1035,6 +1105,10 @@ void RenewalRoundTrip::EncryptAndSignResponse() { } else { ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreRenewalResponse( core_request_, renewal_duration_seconds_, &serialized_core_message_)); + // Resize serialize core message to be just big enough or required core + // message size, whichever is larger. + serialized_core_message_.resize( + std::max(required_core_message_size_, serialized_core_message_.size())); } // Make the message buffer a just big enough, or the // required size, whichever is larger. @@ -1047,7 +1121,6 @@ void RenewalRoundTrip::EncryptAndSignResponse() { encrypted_response_[i] = i % 0x100; } // Concatenate the core message and the response. - ASSERT_GE(kMaxCoreMessage, serialized_core_message_.size()); ASSERT_GE(encrypted_response_.size(), serialized_core_message_.size()); memcpy(encrypted_response_.data(), serialized_core_message_.data(), serialized_core_message_.size()); diff --git a/oemcrypto/test/oec_session_util.h b/oemcrypto/test/oec_session_util.h index a3773fd..3ede5dc 100644 --- a/oemcrypto/test/oec_session_util.h +++ b/oemcrypto/test/oec_session_util.h @@ -155,12 +155,25 @@ class RoundTrip { core_response_(), response_data_(), encrypted_response_data_(), - required_message_size_(0) {} + required_message_size_(0), + required_core_message_size_(0), + required_request_signature_size_(0) {} virtual ~RoundTrip() {} // Have OEMCrypto sign a request message and then verify the signature and the // core message. - virtual void SignAndVerifyRequest(); + virtual void SignAndVerifyRequest() { + // Boolean true generates core request and verifies the request. + // Custom message sizes are 0 by default, so the behavior of following + // functions will be sign and verify request without any custom buffers + // sizes. + ASSERT_EQ(SignAndCreateRequestWithCustomBufferLengths(true), + OEMCrypto_SUCCESS); + } + // Have OEMCrypto sign and call create request APIs. Buffer parameters in API + // can be set to custom values to test with varying lengths of buffers. + virtual OEMCryptoResult SignAndCreateRequestWithCustomBufferLengths( + bool verify_request = false); // Used for OEMCrypto Fuzzing: Function to convert fuzzer data to valid // License/Provisioning/Renwal request data that can be serialized. virtual void InjectFuzzedRequestData(uint8_t* data, size_t size); @@ -189,6 +202,16 @@ class RoundTrip { // Set the size of the buffer used the encrypted license. void set_message_size(size_t size) { required_message_size_ = size; } + // Set core message size to test OEMCrypto request APIs for varying core + // message lengths. + void set_core_message_size(size_t size) { + required_core_message_size_ = size; + } + // Set signature size to test OEMCrypto request APIs for varying signature + // lengths. + void set_request_signature_size(size_t size) { + required_request_signature_size_ = size; + } std::vector& response_signature() { return response_signature_; } const std::string& serialized_core_message() const { return serialized_core_message_; @@ -217,6 +240,8 @@ class RoundTrip { // Message buffers will be at least this big. Tests for loading and signing // messages will increase all buffers to this size. size_t required_message_size_; + size_t required_core_message_size_; + size_t required_request_signature_size_; std::vector response_signature_; std::string serialized_core_message_; std::vector encrypted_response_; @@ -239,6 +264,8 @@ class ProvisioningRoundTrip virtual void PrepareSession(const wvoec::WidevineKeybox& keybox); void CreateDefaultResponse() override; void EncryptAndSignResponse() override; + void EncryptAndSignResponseWithoutUpdatingEncPrivateKeyLength(); + void SignResponse(); OEMCryptoResult LoadResponse() override { return LoadResponse(session_); } OEMCryptoResult LoadResponse(Session* session) override; void VerifyLoadFailed(); @@ -318,6 +345,7 @@ class LicenseRoundTrip void EncryptAndSignResponse() override; OEMCryptoResult LoadResponse() override { return LoadResponse(session_); } OEMCryptoResult LoadResponse(Session* session) override; + OEMCryptoResult LoadResponse(Session* session, bool verify_keys); // Reload an offline license into a different session. This derives new mac // keys and then calls LoadResponse. OEMCryptoResult ReloadResponse(Session* session); @@ -442,11 +470,19 @@ class EntitledMessage { void FillKeyArray(); void MakeOneKey(size_t entitlement_key_index); void LoadKeys(OEMCryptoResult expected_sts); + OEMCryptoResult LoadKeys(const vector& message); + OEMCryptoResult LoadKeys(); + void EncryptContentKey(); void set_num_keys(uint32_t num_keys) { num_keys_ = num_keys; } uint32_t num_keys() const { return num_keys_; } void SetEntitlementKeyId(unsigned int index, const std::string& key_id); // Verify that key control blocks of the loaded keys. void VerifyEntitlementTestKeys(); + OEMCrypto_EntitledContentKeyObject* entitled_key_array(); + // Returns entitled_key_data_ which is used as input message buffer to + // load entitled content keys API. + EntitledContentKeyData* entitled_key_data(); + size_t entitled_key_data_size(); private: // Find the offset of the give pointer, relative to |entitled_key_data_|. @@ -631,6 +667,10 @@ bool ConvertByteToValidBoolean(const bool* in); template void WriteRequestApiCorpus(size_t signature_length, size_t core_message_length, vector& data); +template +void GetDefaultRequestSignatureAndCoreMessageLengths( + uint32_t& session_id, const size_t& small_size, + size_t* gen_signature_length, size_t* core_message_length); } // namespace wvoec #endif // CDM_OEC_SESSION_UTIL_H_ diff --git a/oemcrypto/test/oemcrypto_test.cpp b/oemcrypto/test/oemcrypto_test.cpp index 8ad6e47..95c614a 100644 --- a/oemcrypto/test/oemcrypto_test.cpp +++ b/oemcrypto/test/oemcrypto_test.cpp @@ -107,6 +107,9 @@ constexpr size_t MiB = 1024 * 1024; // Huge input buffer length used for OEMCryptoMemory* tests. constexpr size_t kHugeInputBufferLength = 100 * MiB; constexpr bool kCheckStatus = true; +constexpr bool kUpdateCoreMessageSubstringValues = true; +constexpr bool kDecryptCENCSecureBuffer = true; +constexpr size_t kHugeRandomNumber = 541236; // With OEMCrypto v15 and above, we have different resource requirements // depending on the resource rating reported by OEMCrypto. This function looks // up the required value for the specified resource for the target OEMCrypto @@ -134,6 +137,11 @@ void TestHugeLengthDoesNotCrashAPI(oemcrypto_function f, !check_status); buffer_length *= 2) { sts = f(buffer_length); + if (check_status && sts != OEMCrypto_SUCCESS && + sts != OEMCrypto_ERROR_SHORT_BUFFER) { + LOGI("Test exits huge buffer loop for length:%zu, status:%d", + buffer_length, sts); + } } } @@ -167,6 +175,17 @@ const size_t kLargeMessageSize[] = { 8*KiB, 8*KiB, 16*KiB, 32*KiB}; // const size_t kAV1NumberSubsamples[] = { 72, 144, 288, 576}; // clang-format on +// Return a printable string from data. If all the characters are printable, +// then just use the string. Otherwise, convert to hex. +std::string MaybeHex(const uint8_t* data, size_t length) { + for (size_t i = 0; i < length; i++) { + if (!isprint(data[i])) return "0x" + wvcdm::HexEncode(data, length); + } + return std::string(reinterpret_cast(data), length); +} +std::string MaybeHex(const std::vector& data) { + return MaybeHex(data.data(), data.size()); +} } // namespace class OEMCryptoClientTest : public ::testing::Test, public SessionUtil { @@ -199,6 +218,17 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil { } }; +TEST_F(OEMCryptoClientTest, FreeUnallocatedSecureBufferNoFailure) { + Session s; + s.open(); + OEMCrypto_DestBufferDesc output_descriptor; + int secure_fd = kHugeRandomNumber; + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_FreeSecureBuffer(s.session_id(), &output_descriptor, + secure_fd)); + s.close(); +} + /// @addtogroup basic /// @{ @@ -209,7 +239,7 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil { */ TEST_F(OEMCryptoClientTest, VersionNumber) { const std::string log_message = - "OEMCrypto unit tests for API 16.4. Tests last updated 2020-10-07"; + "OEMCrypto unit tests for API 16.4. Tests last updated 2021-01-25"; cout << " " << log_message << "\n"; LOGI("%s", log_message.c_str()); // If any of the following fail, then it is time to update the log message @@ -249,6 +279,91 @@ TEST_F(OEMCryptoClientTest, VersionNumber) { ASSERT_LE(version, kCurrentAPI); } +TEST_F(OEMCryptoClientTest, + OEMCryptoMemoryAllocateSecureBufferForHugeBufferSize) { + Session s; + s.open(); + auto oemcrypto_function = [&s](size_t buffer_size) { + OEMCrypto_DestBufferDesc output_descriptor; + int secure_fd; + OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( + s.session_id(), buffer_size, &output_descriptor, &secure_fd); + if (sts == OEMCrypto_SUCCESS) { + OEMCrypto_FreeSecureBuffer(s.session_id(), &output_descriptor, secure_fd); + } + return sts; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); + s.close(); +} + +TEST_F(OEMCryptoClientTest, + OEMCryptoMemoryWrapKeyboxOrOEMCertForHugeKeyboxLength) { + auto oemcrypto_function = [](size_t keybox_length) { + vector keybox_buffer(keybox_length); + size_t wrapped_keybox_length = keybox_length + 50; + vector wrapped_keybox_buffer(wrapped_keybox_length); + vector transport_key_buffer(20); + memcpy(keybox_buffer.data(), &kTestKeybox, sizeof(kTestKeybox)); + return OEMCrypto_WrapKeyboxOrOEMCert( + keybox_buffer.data(), keybox_length, wrapped_keybox_buffer.data(), + &wrapped_keybox_length, transport_key_buffer.data(), + transport_key_buffer.size()); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, sizeof(kTestKeybox), + kHugeInputBufferLength, kCheckStatus); +} + +TEST_F(OEMCryptoClientTest, + OEMCryptoMemoryWrapKeyboxOrOEMCertForHugeWrappedKeyboxLength) { + auto oemcrypto_function = [](size_t buffer_length) { + size_t wrapped_keybox_length = buffer_length; + vector wrapped_keybox_buffer(wrapped_keybox_length); + vector transport_key_buffer(20); + return OEMCrypto_WrapKeyboxOrOEMCert( + reinterpret_cast(&kTestKeybox), sizeof(kTestKeybox), + wrapped_keybox_buffer.data(), &wrapped_keybox_length, + transport_key_buffer.data(), transport_key_buffer.size()); + }; + // API expects keybox length and wrapped keybox length to be equal. We would + // like to test for various values of wrapped keybox lengths, hence skipping + // status check. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_F(OEMCryptoClientTest, + OEMCryptoMemoryWrapKeyboxOrOEMCertForHugeTransportKey) { + auto oemcrypto_function = [](size_t transport_key_length) { + size_t wrapped_keybox_length = sizeof(&kTestKeybox) + 50; + vector wrapped_keybox_buffer(wrapped_keybox_length); + vector transport_key_buffer(transport_key_length); + return OEMCrypto_WrapKeyboxOrOEMCert( + reinterpret_cast(&kTestKeybox), sizeof(kTestKeybox), + wrapped_keybox_buffer.data(), &wrapped_keybox_length, + transport_key_buffer.data(), transport_key_buffer.size()); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F( + OEMCryptoClientTest, + OEMCryptoMemoryWrapKeyboxOrOEMCertForHugeKeyboxLengthStartingFromLength1) { + auto oemcrypto_function = [](size_t keybox_length) { + vector keybox_buffer(keybox_length); + size_t wrapped_keybox_length = keybox_length + 50; + vector wrapped_keybox_buffer(wrapped_keybox_length); + vector transport_key_buffer(20); + return OEMCrypto_WrapKeyboxOrOEMCert( + keybox_buffer.data(), keybox_length, wrapped_keybox_buffer.data(), + &wrapped_keybox_length, transport_key_buffer.data(), + transport_key_buffer.size()); + }; + // Cannot check status as keybox will not be valid for this test. + // We still want to test what happens if buffer lengths is less that keybox + // length. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + /** * The resource rating is a number from 1 to 4. The first three levels * were initially defined in API 15 and they were expanded in API 16. @@ -641,6 +756,7 @@ TEST_F(OEMCryptoClientTest, vector input_buffer; OEMCrypto_DestBufferDesc dest_buffer_descriptor; dest_buffer_descriptor.type = OEMCrypto_BufferType_Direct; + dest_buffer_descriptor.buffer.direct.is_video = false; auto oemcrypto_function = [&s, &dest_buffer_descriptor, &input_buffer](size_t buffer_length) { @@ -782,8 +898,6 @@ TEST_F(OEMCryptoKeyboxTest, } #endif -// This test verifies that load test key box doesn't crash for large -// buffer length. TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryLoadTestKeyBoxForHugeKeyboxBuffer) { auto f = [](size_t keybox_length) { vector keybox(keybox_length); @@ -796,14 +910,25 @@ TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryLoadTestKeyBoxForHugeKeyboxBuffer) { kCheckStatus); } +TEST_F(OEMCryptoKeyboxTest, + OEMCryptoMemoryLoadTestKeyBoxForHugeKeyboxBufferStartingFromLength1) { + auto f = [](size_t keybox_length) { + vector keybox(keybox_length); + return OEMCrypto_LoadTestKeybox(keybox.data(), keybox.size()); + }; + // We are testing for keybox lengths starting from 1 which would return error, + // hence skipping status check. + TestHugeLengthDoesNotCrashAPI(f, !kCheckStatus); +} + // This test is used to print the device ID to stdout. TEST_F(OEMCryptoKeyboxTest, NormalGetDeviceId) { OEMCryptoResult sts; uint8_t dev_id[128] = {0}; size_t dev_id_len = 128; sts = OEMCrypto_GetDeviceID(dev_id, &dev_id_len); - cout << " NormalGetDeviceId: dev_id = " << dev_id - << " len = " << dev_id_len << endl; + cout << " NormalGetDeviceId: dev_id = " + << MaybeHex(dev_id, dev_id_len) << " len = " << dev_id_len << endl; ASSERT_EQ(OEMCrypto_SUCCESS, sts); } @@ -945,7 +1070,7 @@ TEST_F(OEMCryptoProv30Test, GetDeviceId) { } ASSERT_EQ(OEMCrypto_SUCCESS, sts); dev_id.resize(dev_id_len); - cout << " NormalGetDeviceId: dev_id = " << dev_id.data() + cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id) << " len = " << dev_id_len << endl; ASSERT_EQ(OEMCrypto_SUCCESS, sts); } @@ -1052,7 +1177,7 @@ TEST_F(OEMCryptoProv30Test, OEMCryptoMemoryGetOEMPublicCertForLargeCertLength) { return OEMCrypto_GetOEMPublicCertificate(public_cert.data(), &public_cert_length); }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); } // @@ -1094,8 +1219,101 @@ class OEMCryptoSessionTests : public OEMCryptoClientTest { ASSERT_NE(OEMCrypto_SUCCESS, sts); } } + + void TestPrepareLicenseRequestForHugeBufferLengths( + const std::function f, + bool check_status) { + auto oemcrypto_function = [&](size_t message_length) { + Session s; + s.open(); + InstallTestRSAKey(&s); + s.GenerateNonce(); + LicenseRoundTrip license_messages(&s); + f(message_length, &license_messages); + OEMCryptoResult result = + license_messages.SignAndCreateRequestWithCustomBufferLengths(); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } + + OEMCryptoResult LoadLicense(Session& s, LicenseRoundTrip& license_messages) { + InstallTestRSAKey(&s); + s.GenerateNonce(); + license_messages.SignAndVerifyRequest(); + license_messages.CreateDefaultResponse(); + license_messages.EncryptAndSignResponse(); + return license_messages.LoadResponse(); + } + + void TestLoadLicenseForHugeBufferLengths( + const std::function f, bool check_status, + bool update_core_message_substring_values) { + auto oemcrypto_function = [&](size_t message_length) { + Session s; + LicenseRoundTrip license_messages(&s); + s.open(); + InstallTestRSAKey(&s); + s.GenerateNonce(); + bool verify_keys_loaded = true; + license_messages.SignAndVerifyRequest(); + license_messages.CreateDefaultResponse(); + if (update_core_message_substring_values) { + // Make the license message big enough so that updated core message + // substring offset and length values from tests are still able to read + // data from license_message buffer rather than reading some garbage + // data. + license_messages.set_message_size( + sizeof(license_messages.response_data()) + message_length); + } + f(message_length, &license_messages); + if (update_core_message_substring_values) { + // We will be updating offset for these tests, which will cause verify + // keys to fail with an assertion. Hence skipping verification. + verify_keys_loaded = false; + } + license_messages.EncryptAndSignResponse(); + OEMCryptoResult result = + license_messages.LoadResponse(&s, verify_keys_loaded); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } + + void TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + const std::function f) { + Session s; + LicenseRoundTrip license_messages(&s); + s.open(); + InstallTestRSAKey(&s); + s.GenerateNonce(); + license_messages.SignAndVerifyRequest(); + license_messages.CreateDefaultResponse(); + size_t message_length = sizeof(license_messages.response_data()); + f(message_length, &license_messages); + license_messages.EncryptAndSignResponse(); + OEMCryptoResult result = license_messages.LoadResponse(); + s.close(); + // Verifying error is not due to signature failure which can be caused due + // to test code. + ASSERT_NE(OEMCrypto_ERROR_SIGNATURE_FAILURE, result); + ASSERT_NE(OEMCrypto_SUCCESS, result); + } }; +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryCreateUsageTableHeaderForHugeHeaderBufferLength) { + auto oemcrypto_function = [](size_t buffer_length) { + size_t header_buffer_length = buffer_length; + vector usage_table_header(header_buffer_length); + return OEMCrypto_CreateUsageTableHeader(usage_table_header.data(), + &header_buffer_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + class OEMCryptoSessionTestKeyboxTest : public OEMCryptoSessionTests {}; TEST_F(OEMCryptoSessionTestKeyboxTest, TestKeyboxIsValid) { @@ -1126,6 +1344,88 @@ class OEMCryptoLicenseTestAPI16 : public OEMCryptoSessionTests { LicenseRoundTrip license_messages_; }; +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryPrepareLicenseRequestForHugeRequestMessageLength) { + TestPrepareLicenseRequestForHugeBufferLengths( + [](size_t message_size, LicenseRoundTrip* license_messages) { + license_messages->set_message_size(message_size); + }, + kCheckStatus); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryPrepareLicenseRequestForHugeCoreMessageLength) { + TestPrepareLicenseRequestForHugeBufferLengths( + [](size_t core_message_size, LicenseRoundTrip* license_messages) { + license_messages->set_core_message_size(core_message_size); + }, + kCheckStatus); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryPrepareLicenseRequestForHugeSignatureLength) { + // There is a limit of signature length that gets validated. Hence not + // checking status as we would like to test it for all possible signature + // lengths. + TestPrepareLicenseRequestForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->set_request_signature_size(length); + }, + !kCheckStatus); +} + +// This class is for testing a single license with the default API version +// of 16. Used for buffer overflow tests. +class OEMCryptoMemoryLicenseTest : public OEMCryptoLicenseTestAPI16 { + public: + OEMCryptoMemoryLicenseTest() : entitled_message_(&license_messages_) {} + + void SetUp() override { + OEMCryptoLicenseTestAPI16::SetUp(); + SetUpEntitledMessage(); + entitlement_response_length_ = entitled_message_.entitled_key_data_size(); + } + + void LoadLicense() { + ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce()); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + } + + void SetUpEntitledMessage() { + license_messages_.set_license_type(OEMCrypto_EntitlementLicense); + LoadLicense(); + entitled_message_.FillKeyArray(); + entitled_message_.EncryptContentKey(); + } + + void TearDown() override { OEMCryptoLicenseTestAPI16::TearDown(); } + + protected: + EntitledMessage entitled_message_; + size_t entitlement_response_length_; + + void TestLoadEntitlementKeysForHugeBufferLengths( + const std::function f, + bool check_status) { + size_t entitled_key_data_size = entitled_message_.entitled_key_data_size(); + vector message(entitled_key_data_size); + memcpy(message.data(), entitled_message_.entitled_key_data(), + entitled_key_data_size); + auto oemcrypto_function = [&](size_t length) { + // Make entitled message big enough so that updated substring offset and + // length fields by core message substring tests can still be able to read + // valid data from entitled message buffer rather than some garbage data. + message.resize(entitled_key_data_size + length); + f(length, &entitled_message_); + return entitled_message_.LoadKeys(message); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } +}; + // This class is used to test a license that is from a server either that is // current or one version old. class OEMCryptoLicenseTest : public OEMCryptoLicenseTestAPI16, @@ -1138,6 +1438,108 @@ class OEMCryptoLicenseTest : public OEMCryptoLicenseTestAPI16, license_messages_.set_api_version(license_api_version_); OEMCryptoLicenseTestAPI16::SetUp(); } + + void LoadLicense() { + session_.GenerateNonce(); + license_messages_.SignAndVerifyRequest(); + license_messages_.CreateDefaultResponse(); + license_messages_.EncryptAndSignResponse(); + license_messages_.LoadResponse(); + } + + void TestDecryptCENCForHugeBufferLengths( + const std::function f, + bool check_status) { + LoadLicense(); + auto oemcrypto_function = [&](size_t message_length) { + OEMCrypto_SelectKey( + session_.session_id(), session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CTR); + + size_t input_buffer_size = 1; + vector in_buffer(input_buffer_size + message_length); + vector out_buffer(in_buffer.size()); + + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + GenerateSimpleSampleDescription( + in_buffer, out_buffer, &sample_description, &subsample_description); + + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description.subsamples); + // Actual tests modifies either of these fields to match clear + encrypted + // = in_buffer.size(). + sub_samples[0].num_bytes_clear = 0; + sub_samples[0].num_bytes_encrypted = input_buffer_size; + + // Create the pattern description (always 0,0 for CTR) + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + int secure_fd = 0; + f(message_length, &sample_description); + if (sample_description.buffers.output_descriptor.type == + OEMCrypto_BufferType_Secure) { + OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( + session_.session_id(), in_buffer.size(), + &sample_description.buffers.output_descriptor, &secure_fd); + if (sts != OEMCrypto_SUCCESS) { + LOGI("Secure buffers are not supported."); + return sts; + } + } + // Try to decrypt the data + OEMCryptoResult result = OEMCrypto_DecryptCENC( + session_.session_id(), &sample_description, 1, &pattern); + if (sample_description.buffers.output_descriptor.type == + OEMCrypto_BufferType_Secure) { + OEMCrypto_FreeSecureBuffer( + session_.session_id(), + &sample_description.buffers.output_descriptor, secure_fd); + } + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } + + void TestDecryptCENCForOutOfRangeOffsetsAndLengths( + const std::function f, + bool update_secure_buffer) { + LoadLicense(); + OEMCrypto_SelectKey( + session_.session_id(), session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CTR); + + vector in_buffer(256); + vector out_buffer(in_buffer.size()); + + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description, + &subsample_description); + + // Create the pattern description (always 0,0 for CTR) + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + int secure_fd = 0; + if (update_secure_buffer) { + OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( + session_.session_id(), in_buffer.size(), + &sample_description.buffers.output_descriptor, &secure_fd); + if (sts != OEMCrypto_SUCCESS) { + LOGI("Secure buffers are not supported."); + return; + } + } + f(&sample_description); + // Try to decrypt the data + OEMCryptoResult result = OEMCrypto_DecryptCENC( + session_.session_id(), &sample_description, 1, &pattern); + if (update_secure_buffer) { + OEMCrypto_FreeSecureBuffer(session_.session_id(), + &sample_description.buffers.output_descriptor, + secure_fd); + } + ASSERT_NE(OEMCrypto_SUCCESS, result); + } }; // This class is used to test a license that is only for v15 license. @@ -1318,6 +1720,238 @@ TEST_P(OEMCryptoLicenseTest, LoadEntitlementKeysWrongEntitlementKeysAPI14) { entitled_message_1.LoadKeys(OEMCrypto_KEY_NOT_ENTITLED)); } +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryPrepareRenewalRequestForHugeBufferLength) { + RenewalRoundTrip renewal_messages(&license_messages_); + auto oemcrypto_function = [&renewal_messages](size_t buffer_length) { + renewal_messages.set_message_size(buffer_length); + return renewal_messages.SignAndCreateRequestWithCustomBufferLengths(); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryPrepareRenewalRequestForHugeSignatureLength) { + RenewalRoundTrip renewal_messages(&license_messages_); + auto oemcrypto_function = [&renewal_messages](size_t buffer_length) { + renewal_messages.set_request_signature_size(buffer_length); + return renewal_messages.SignAndCreateRequestWithCustomBufferLengths(); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryPrepareRenewalRequestForHugeCoreMessageLength) { + RenewalRoundTrip renewal_messages(&license_messages_); + auto oemcrypto_function = [&renewal_messages](size_t buffer_length) { + renewal_messages.set_core_message_size(buffer_length); + return renewal_messages.SignAndCreateRequestWithCustomBufferLengths(); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyIdLength) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t key_id_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_id.length = + key_id_length; + }, + !kCheckStatus); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyIdOffset) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t key_id_offset, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_id.offset = + key_id_offset; + }, + !kCheckStatus); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyIdLength) { + auto& content_key_id = + entitled_message_.entitled_key_array()[0].content_key_id; + content_key_id.length = + entitlement_response_length_ - content_key_id.offset + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyIdOffset) { + auto& content_key_id = + entitled_message_.entitled_key_array()[0].content_key_id; + content_key_id.offset = + entitlement_response_length_ - content_key_id.length + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringEntitlementKeyIdLength) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t key_id_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].entitlement_key_id.length = + key_id_length; + }, + !kCheckStatus); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringEntitlementKeyIdOffset) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t key_id_offset, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].entitlement_key_id.offset = + key_id_offset; + }, + !kCheckStatus); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringEntitlementKeyIdLength) { + auto& entitlement_key_id = + entitled_message_.entitled_key_array()[0].entitlement_key_id; + entitlement_key_id.length = + entitlement_response_length_ - entitlement_key_id.offset + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringEntitlementKeyIdOffset) { + auto& entitlement_key_id = + entitled_message_.entitled_key_array()[0].entitlement_key_id; + entitlement_key_id.offset = + entitlement_response_length_ - entitlement_key_id.length + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyDataIvLength) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t content_key_data_iv_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_data_iv.length = + content_key_data_iv_length; + }, + !kCheckStatus); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyDataIvOffset) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t content_key_data_iv_offset, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_data_iv.offset = + content_key_data_iv_offset; + }, + !kCheckStatus); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyDataIvLength) { + auto& content_key_data_iv = + entitled_message_.entitled_key_array()[0].content_key_data_iv; + content_key_data_iv.length = + entitlement_response_length_ - content_key_data_iv.offset + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyDataIvOffset) { + auto& content_key_data_iv = + entitled_message_.entitled_key_array()[0].content_key_data_iv; + content_key_data_iv.offset = + entitlement_response_length_ - content_key_data_iv.length + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyDataLength) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t content_key_data_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_data.length = + content_key_data_length; + }, + !kCheckStatus); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyDataOffset) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t content_key_data_offset, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_data.offset = + content_key_data_offset; + }, + !kCheckStatus); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyDataLength) { + auto& content_key_data = + entitled_message_.entitled_key_array()[0].content_key_data; + content_key_data.length = + entitlement_response_length_ - content_key_data.offset + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyDataOffset) { + auto& content_key_data = + entitled_message_.entitled_key_array()[0].content_key_data; + content_key_data.offset = + entitlement_response_length_ - content_key_data.length + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeEntitlementKeyIdLength) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t key_id_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_data()->entitlement_key_id_length = + key_id_length; + }, + !kCheckStatus); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeContentKeyIdLength) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t key_id_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_data()->content_key_id_length = + key_id_length; + }, + !kCheckStatus); +} + +// This verifies that entitled content keys API does not crash for unreasonable +// input message buffer lengths. +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeBufferLength) { + auto oemcrypto_function = [&](size_t buffer_length) { + size_t entitled_key_data_length = + entitled_message_.entitled_key_data_size(); + vector message(entitled_key_data_length); + memcpy(message.data(), entitled_message_.entitled_key_data(), + entitled_key_data_length); + message.resize(buffer_length); + return entitled_message_.LoadKeys(message); + }; + // We are not constructing a valid message for load entitled content keys. + // Hence skipping status check. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + // This tests load license with an 8k license response. TEST_P(OEMCryptoLicenseTest, LoadKeyLargeBuffer) { ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce()); @@ -1737,6 +2371,123 @@ TEST_P(OEMCryptoLicenseTest, LoadKeyNoKeyWithNonce) { ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); } +// Following two tests will test huge values for num bytes clear, num bytes +// encrypted, input data length and clear address, clear address_length. +TEST_P(OEMCryptoLicenseTest, + OEMCryptoMemoryDecryptCENCForHugeNumBytesClearAndBuffers) { + TestDecryptCENCForHugeBufferLengths( + [](size_t message_size, OEMCrypto_SampleDescription* sample_description) { + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description->subsamples); + sub_samples[0].num_bytes_clear = + sub_samples[0].num_bytes_clear + message_size; + }, + !kCheckStatus); +} + +TEST_P(OEMCryptoLicenseTest, + DecryptCENCForNumBytesClearPlusEncryptedOverflowsSize) { + LoadLicense(); + OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length, + OEMCrypto_CipherMode_CTR); + + size_t input_buffer_size = 1; + vector in_buffer(input_buffer_size); + vector out_buffer(in_buffer.size()); + + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description, + &subsample_description); + + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description.subsamples); + // If Decrypt cenc API does not check for overflow on clear + encrypted + // addition operation. This will result in 1 which will match with input data + // length, which causes validation to pass. + sub_samples[0].num_bytes_clear = 2; + sub_samples[0].num_bytes_encrypted = 0xFFFFFFFFFFFFFFFF; + + // Create the pattern description (always 0,0 for CTR) + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + // Try to decrypt the data + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, + &pattern)); +} + +TEST_P(OEMCryptoLicenseTest, + OEMCryptoMemoryDecryptCENCForHugeNumBytesEncryptedAndBuffers) { + TestDecryptCENCForHugeBufferLengths( + [](size_t message_size, OEMCrypto_SampleDescription* sample_description) { + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description->subsamples); + sub_samples[0].num_bytes_encrypted = + sub_samples[0].num_bytes_encrypted + message_size; + }, + !kCheckStatus); +} + +TEST_P(OEMCryptoLicenseTest, + OEMCryptoMemoryDecryptCENCForHugeSecureHandleLength) { + TestDecryptCENCForHugeBufferLengths( + [](size_t message_size, OEMCrypto_SampleDescription* sample_description) { + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description->subsamples); + // TestDecryptCENCForHugeBufferLengths alloctes huge secure handle + // buffer. + sample_description->buffers.output_descriptor.type = + OEMCrypto_BufferType_Secure; + sub_samples[0].num_bytes_clear = + sub_samples[0].num_bytes_clear + message_size; + }, + !kCheckStatus); +} + +TEST_P(OEMCryptoLicenseTest, + OEMCryptoMemoryDecryptCENCForOutOfRangeNumBytesClear) { + TestDecryptCENCForOutOfRangeOffsetsAndLengths( + [](OEMCrypto_SampleDescription* sample_description) { + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description->subsamples); + sub_samples[0].num_bytes_clear = sub_samples[0].num_bytes_clear + 1; + }, + !kDecryptCENCSecureBuffer); +} + +TEST_P(OEMCryptoLicenseTest, + OEMCryptoMemoryDecryptCENCForOutOfRangeNumBytesEncrypted) { + TestDecryptCENCForOutOfRangeOffsetsAndLengths( + [](OEMCrypto_SampleDescription* sample_description) { + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description->subsamples); + sub_samples[0].num_bytes_encrypted = + sub_samples[0].num_bytes_encrypted + 1; + }, + !kDecryptCENCSecureBuffer); +} + +TEST_P(OEMCryptoLicenseTest, + OEMCryptoMemoryDecryptCENCForOutOfRangeSecureBufferOffset) { + TestDecryptCENCForOutOfRangeOffsetsAndLengths( + [](OEMCrypto_SampleDescription* sample_description) { + sample_description->buffers.output_descriptor.type = + OEMCrypto_BufferType_Secure; + sample_description->buffers.output_descriptor.buffer.secure.offset = + sample_description->buffers.output_descriptor.buffer.secure + .handle_length + + 1; + }, + kDecryptCENCSecureBuffer); +} + // SelectKey should fail if we attempt to select a key that has not been loaded. // Also, the error should be NO_CONTENT_KEY. // This test should pass for v15 devices, except that the exact error code was @@ -1871,6 +2622,43 @@ TEST_P(OEMCryptoLicenseTest, RejectCbcsWithBlockOffset) { EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts); } +TEST_P(OEMCryptoLicenseTest, RejectOversizedBlockOffset) { + ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce()); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + + OEMCryptoResult sts; + sts = OEMCrypto_SelectKey( + session_.session_id(), session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CTR); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + + vector in_buffer(256); + vector out_buffer(in_buffer.size()); + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + + ASSERT_NO_FATAL_FAILURE(GenerateSimpleSampleDescription( + in_buffer, out_buffer, &sample_description, &subsample_description)); + subsample_description.block_offset = 0xFF; // Anything 16+ + + // Create a zero pattern to indicate this is 'cenc'. + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + + // Try to decrypt the data + sts = OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, + &pattern); + EXPECT_NE(OEMCrypto_SUCCESS, sts); + + // Try again with the minimum invalid value + subsample_description.block_offset = 16; + sts = OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, + &pattern); + EXPECT_NE(OEMCrypto_SUCCESS, sts); +} + // After loading keys, we should be able to query the key control block. If we // attempt to query a key that has not been loaded, the error should be // NO_CONTENT_KEY. @@ -1900,19 +2688,488 @@ TEST_P(OEMCryptoLicenseTest, QueryKeyControl) { strlen(key_id), reinterpret_cast(&block), &size)); } -// Test OEMCrypto_QueryKeyControl doesn't crash for huge key_id_length. -TEST_F(OEMCryptoLicenseTestAPI16, - OEMCryptoMemoryQueryKeyControlForHugeKeyIdLength) { - ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce()); - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeSignatureLength) { + auto oemcrypto_function = [&](size_t signature_size) { + Session s; + LicenseRoundTrip license_messages(&s); + s.open(); + InstallTestRSAKey(&s); + s.GenerateNonce(); + license_messages.SignAndVerifyRequest(); + license_messages.CreateDefaultResponse(); + license_messages.EncryptAndSignResponse(); + vector signature(signature_size); + OEMCryptoResult result = OEMCrypto_LoadLicense( + s.session_id(), license_messages.encrypted_response_buffer().data(), + license_messages.encrypted_response_buffer().size(), + license_messages.serialized_core_message().size(), signature.data(), + signature_size); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} - OEMCrypto_SESSION session_id = session_.session_id(); +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyIdLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_id.length = length; + license_messages->response_data().keys[0].key_id_length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyIdOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_id.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyIdLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_id = license_messages->core_response().key_array[0].key_id; + key_id.length = response_message_length - key_id.offset + 1; + }); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyIdOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_id = license_messages->core_response().key_array[0].key_id; + key_id.offset = response_message_length - key_id.length + 1; + }); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataIvLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_data_iv.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataIvOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_data_iv.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataIvLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_data_iv = + license_messages->core_response().key_array[0].key_data_iv; + key_data_iv.length = response_message_length - key_data_iv.offset + 1; + }); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataIvOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_data_iv = + license_messages->core_response().key_array[0].key_data_iv; + key_data_iv.offset = response_message_length - key_data_iv.length + 1; + }); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_data.length = length; + license_messages->response_data().keys[0].key_data_length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_data.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_data = + license_messages->core_response().key_array[0].key_data; + key_data.length = response_message_length - key_data.offset + 1; + }); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_data = + license_messages->core_response().key_array[0].key_data; + key_data.offset = response_message_length - key_data.length + 1; + }); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlIvLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_control_iv.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlIvOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_control_iv.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlIvLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_control_iv = + license_messages->core_response().key_array[0].key_control_iv; + key_control_iv.length = + response_message_length - key_control_iv.offset + 1; + }); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlIvOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_control_iv = + license_messages->core_response().key_array[0].key_control_iv; + key_control_iv.offset = + response_message_length - key_control_iv.length + 1; + }); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_control.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_control.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_control = + license_messages->core_response().key_array[0].key_control; + key_control.length = response_message_length - key_control.offset + 1; + }); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_control = + license_messages->core_response().key_array[0].key_control; + key_control.offset = response_message_length - key_control.length + 1; + }); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyIvLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().enc_mac_keys_iv.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyIvOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().enc_mac_keys_iv.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyIvLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& enc_mac_keys_iv = + license_messages->core_response().enc_mac_keys_iv; + enc_mac_keys_iv.length = + response_message_length - enc_mac_keys_iv.offset + 1; + }); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyIvOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& enc_mac_keys_iv = + license_messages->core_response().enc_mac_keys_iv; + enc_mac_keys_iv.offset = + response_message_length - enc_mac_keys_iv.length + 1; + }); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().enc_mac_keys.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().enc_mac_keys.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& enc_mac_keys = license_messages->core_response().enc_mac_keys; + enc_mac_keys.length = response_message_length - enc_mac_keys.offset + 1; + }); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& enc_mac_keys = license_messages->core_response().enc_mac_keys; + enc_mac_keys.offset = response_message_length - enc_mac_keys.length + 1; + }); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringPstLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().pst.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringPstOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().pst.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringPstLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& pst = license_messages->core_response().pst; + pst.length = response_message_length - pst.offset + 1; + }); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringPstOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& pst = license_messages->core_response().pst; + pst.offset = response_message_length - pst.length + 1; + }); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringSrmRestrictionDataLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().srm_restriction_data.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringSrmRestrictionDataOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().srm_restriction_data.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringSrmRestrictionDataLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& srm_restriction_data = + license_messages->core_response().srm_restriction_data; + srm_restriction_data.length = + response_message_length - srm_restriction_data.offset + 1; + }); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringSrmRestrictionDataOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& srm_restriction_data = + license_messages->core_response().srm_restriction_data; + srm_restriction_data.offset = + response_message_length - srm_restriction_data.length + 1; + }); +} + +TEST_F(OEMCryptoSessionTests, OEMCryptoMemoryLoadLicenseForHugeResponseLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t message_size, LicenseRoundTrip* license_messages) { + license_messages->set_message_size(message_size); + }, + !kCheckStatus, !kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t message_size, LicenseRoundTrip* license_messages) { + license_messages->set_core_message_size(message_size); + }, + !kCheckStatus, !kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, OEMCryptoMemoryLoadRenewalForHugeResponseLength) { + auto oemcrypto_function = [&](size_t message_size) { + Session s; + LicenseRoundTrip license_messages(&s); + s.open(); + LoadLicense(s, license_messages); + + RenewalRoundTrip renewal_messages(&license_messages); + renewal_messages.SignAndVerifyRequest(); + renewal_messages.CreateDefaultResponse(); + renewal_messages.set_message_size(message_size); + renewal_messages.EncryptAndSignResponse(); + OEMCryptoResult result = renewal_messages.LoadResponse(); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadRenewalForHugeSignatureLength) { + auto oemcrypto_function = [&](size_t signature_size) { + Session s; + LicenseRoundTrip license_messages(&s); + s.open(); + LoadLicense(s, license_messages); + + RenewalRoundTrip renewal_messages(&license_messages); + renewal_messages.SignAndVerifyRequest(); + renewal_messages.CreateDefaultResponse(); + renewal_messages.EncryptAndSignResponse(); + vector signature(signature_size); + OEMCryptoResult result = OEMCrypto_LoadRenewal( + s.session_id(), renewal_messages.encrypted_response_buffer().data(), + renewal_messages.encrypted_response_buffer().size(), + renewal_messages.serialized_core_message().size(), signature.data(), + signature_size); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadRenewalForHugeCoreMessageLength) { + auto oemcrypto_function = [&](size_t core_message_size) { + Session s; + LicenseRoundTrip license_messages(&s); + s.open(); + LoadLicense(s, license_messages); + + RenewalRoundTrip renewal_messages(&license_messages); + renewal_messages.SignAndVerifyRequest(); + renewal_messages.CreateDefaultResponse(); + renewal_messages.set_core_message_size(core_message_size); + renewal_messages.EncryptAndSignResponse(); + OEMCryptoResult result = renewal_messages.LoadResponse(); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +// Test OEMCrypto_QueryKeyControl doesn't crash for huge key_id_length. +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryQueryKeyControlForHugeKeyIdLength) { + Session session; + LicenseRoundTrip license_messages(&session); + session.open(); + LoadLicense(session, license_messages); + OEMCrypto_SESSION session_id = session.session_id(); vector valid_key_id( - license_messages_.response_data().keys[0].key_id, - license_messages_.response_data().keys[0].key_id + kTestKeyIdMaxLength); + license_messages.response_data().keys[0].key_id, + license_messages.response_data().keys[0].key_id + kTestKeyIdMaxLength); auto oemcrypto_function = [&session_id, &valid_key_id](size_t additional_key_id_length) { vector key_id(valid_key_id); @@ -1929,18 +3186,15 @@ TEST_F(OEMCryptoLicenseTestAPI16, // Test OEMCrypto_QueryKeyControl doesn't crash for huge key_control_block // length. -TEST_F(OEMCryptoLicenseTestAPI16, +TEST_F(OEMCryptoSessionTests, OEMCryptoMemoryQueryKeyControlForHugeKeyControlBlockLength) { - ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce()); - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); - - OEMCrypto_SESSION session_id = session_.session_id(); - uint8_t* key_id = license_messages_.response_data().keys[0].key_id; - size_t key_id_length = - license_messages_.response_data().keys[0].key_id_length; + Session session; + LicenseRoundTrip license_messages(&session); + session.open(); + LoadLicense(session, license_messages); + OEMCrypto_SESSION session_id = session.session_id(); + uint8_t* key_id = license_messages.response_data().keys[0].key_id; + size_t key_id_length = license_messages.response_data().keys[0].key_id_length; auto oemcrypto_function = [&session_id, &key_id, &key_id_length](size_t buffer_length) { size_t key_control_block_length = buffer_length; @@ -2342,7 +3596,7 @@ TEST_P(OEMCryptoLicenseTest, HashForbiddenAPI15) { // This test verifies that OEMCrypto_SetDecryptHash doesn't crash for a very // large hash buffer. -TEST_F(OEMCryptoLicenseTestAPI16, +TEST_F(OEMCryptoMemoryLicenseTest, OEMCryptoMemoryDecryptHashForLargeHashBuffer) { uint32_t session_id = session_.session_id(); auto f = [session_id](size_t hash_length) { @@ -2351,13 +3605,12 @@ TEST_F(OEMCryptoLicenseTestAPI16, return OEMCrypto_SetDecryptHash(session_id, frame_number, hash_buffer.data(), hash_buffer.size()); }; - TestHugeLengthDoesNotCrashAPI(f, sizeof(uint32_t), kHugeInputBufferLength, - kCheckStatus); + TestHugeLengthDoesNotCrashAPI(f, kCheckStatus); } // This test verifies OEMCrypto_SetDecryptHash for out of range frame number. TEST_P(OEMCryptoLicenseTest, DecryptHashForOutOfRangeFrameNumber) { - uint32_t frame_number = 40; + uint32_t frame_number = kHugeRandomNumber; uint32_t hash = 42; ASSERT_NO_FATAL_FAILURE(OEMCrypto_SetDecryptHash( session_.session_id(), frame_number, @@ -2661,50 +3914,17 @@ class OEMCryptoSessionTestsDecryptTests OEMCrypto_SUCCESS); } - void TestDecryptCENC() { - OEMCryptoResult sts; + void TestDecryptCENC() { ASSERT_EQ(DecryptCENC(), OEMCrypto_SUCCESS); } - // OEMCrypto only supports providing a decrypt hash for one sample. - if (samples_.size() > 1) verify_crc_ = false; - - // If supported, check the decrypt hashes. - if (verify_crc_) { - const TestSample& sample = samples_[0]; - - uint32_t hash = - wvcrc32(sample.truth_buffer.data(), sample.truth_buffer.size()); - ASSERT_EQ(OEMCrypto_SetDecryptHash( - session_.session_id(), 1, - reinterpret_cast(&hash), sizeof(hash)), - OEMCrypto_SUCCESS); - } - - // Build an array of just the sample descriptions. - std::vector sample_descriptions; - sample_descriptions.reserve(samples_.size()); - for (TestSample& sample : samples_) { - // This must be deferred until this point in case the test modifies the - // buffer before testing decrypt. - sample.description.buffers.input_data = sample.encrypted_buffer.data(); - // Append to the description array. - sample_descriptions.push_back(sample.description); - } - - // Perform decryption using the test data that was previously set up. - sts = DecryptFallbackChain::Decrypt( - session_.session_id(), sample_descriptions.data(), - sample_descriptions.size(), cipher_mode_, &pattern_); - ASSERT_EQ(sts, OEMCrypto_SUCCESS); - - // Validate the decrypted data. + void ValidateDecryptedData() { for (TestSample& sample : samples_) { if (sample.description.buffers.output_descriptor.type == OEMCrypto_BufferType_Clear) { const size_t total_size = sample.description.buffers.input_data_length; // To verify there is no buffer overrun after decrypting, look at the - // padded bytes just after the data buffer that was written. It should - // not have changed from the original 0xaa that we set in MakeBuffer - // function. + // padded bytes just after the data buffer that was written. It + // should not have changed from the original 0xaa that we set in + // MakeBuffer function. if (decrypt_inplace_) { EXPECT_EQ(std::count(sample.encrypted_buffer.begin() + total_size, sample.encrypted_buffer.end(), 0xaa), @@ -2730,6 +3950,41 @@ class OEMCryptoSessionTestsDecryptTests } } + OEMCryptoResult DecryptCENC() { + // OEMCrypto only supports providing a decrypt hash for one sample. + if (samples_.size() > 1) verify_crc_ = false; + + // If supported, check the decrypt hashes. + if (verify_crc_) { + const TestSample& sample = samples_[0]; + + uint32_t hash = + wvcrc32(sample.truth_buffer.data(), sample.truth_buffer.size()); + OEMCrypto_SetDecryptHash(session_.session_id(), 1, + reinterpret_cast(&hash), + sizeof(hash)); + } + + // Build an array of just the sample descriptions. + std::vector sample_descriptions; + sample_descriptions.reserve(samples_.size()); + for (TestSample& sample : samples_) { + // This must be deferred until this point in case the test modifies the + // buffer before testing decrypt. + sample.description.buffers.input_data = sample.encrypted_buffer.data(); + // Append to the description array. + sample_descriptions.push_back(sample.description); + } + + // Perform decryption using the test data that was previously set up. + OEMCryptoResult result = DecryptFallbackChain::Decrypt( + session_.session_id(), sample_descriptions.data(), + sample_descriptions.size(), cipher_mode_, &pattern_); + if (result != OEMCrypto_SUCCESS) return result; + ValidateDecryptedData(); + return result; + } + // Parameters of test case OEMCrypto_CENCEncryptPatternDesc pattern_; OEMCryptoCipherMode cipher_mode_; @@ -2905,7 +4160,6 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptMaxSampleAPI16) { // max_sample_size. const size_t subsample_size = std::min(max_sample_size / max_num_subsamples + 1, max_subsample_size); - size_t bytes_remaining = max_sample_size; std::vector subsample_sizes; while (bytes_remaining > 0 && subsample_sizes.size() < max_num_subsamples) { @@ -2924,6 +4178,103 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptMaxSampleAPI16) { ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); } +TEST_P(OEMCryptoSessionTestsDecryptTests, + OEMCryptoMemoryDecryptCENCForHugeNumberOfSubSamples) { + auto oemcrypto_function = [&](size_t number_of_subsamples) { + std::vector subsample_sizes; + while (number_of_subsamples-- > 0) { + subsample_sizes.push_back({1, 1}); + } + SetSubsampleSizes(subsample_sizes); + LoadLicense(); + MakeBuffers(); + EncryptData(); + OEMCryptoResult result = DecryptCENC(); + // Closing the session and opening it for next iteration. + // If it is last iteration, session will be closed in teardown method of + // class. + session_.close(); + session_.open(); + InstallTestRSAKey(&session_); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 1, 2 * MiB, kCheckStatus); +} + +TEST_P(OEMCryptoSessionTestsDecryptTests, + OEMCryptoMemoryCheckDecryptCENCStatusForHugeNumberOfSubSamples) { + size_t number_of_subsamples = 10000; + std::vector subsample_sizes; + while (number_of_subsamples-- > 0) { + subsample_sizes.push_back({100, 100}); + } + SetSubsampleSizes(subsample_sizes); + LoadLicense(); + MakeBuffers(); + EncryptData(); + // Build an array of just the sample descriptions. + std::vector sample_descriptions; + sample_descriptions.reserve(samples_.size()); + for (TestSample& sample : samples_) { + // This must be deferred until this point in case the test modifies the + // buffer before testing decrypt. + sample.description.buffers.input_data = sample.encrypted_buffer.data(); + // Append to the description array. + sample_descriptions.push_back(sample.description); + } + OEMCryptoResult result = OEMCrypto_DecryptCENC( + session_.session_id(), sample_descriptions.data(), 1, &pattern_); + LOGD("Large number of subsamples test has return code %d", result); +} + +TEST_P(OEMCryptoSessionTestsDecryptTests, + OEMCryptoMemoryCheckDecryptCENCStatusForHugeSubSample) { + std::vector subsample_sizes; + subsample_sizes.push_back({100000, 100000}); + SetSubsampleSizes(subsample_sizes); + LoadLicense(); + MakeBuffers(); + EncryptData(); + // Build an array of just the sample descriptions. + std::vector sample_descriptions; + sample_descriptions.reserve(samples_.size()); + for (TestSample& sample : samples_) { + // This must be deferred until this point in case the test modifies the + // buffer before testing decrypt. + sample.description.buffers.input_data = sample.encrypted_buffer.data(); + // Append to the description array. + sample_descriptions.push_back(sample.description); + } + OEMCryptoResult result = OEMCrypto_DecryptCENC( + session_.session_id(), sample_descriptions.data(), 1, &pattern_); + LOGD("Large subsample test has return code %d", result); +} + +TEST_P(OEMCryptoSessionTestsDecryptTests, + OEMCryptoMemoryDecryptCENCForHugeNumberOfSamples) { + auto oemcrypto_function = [&](size_t number_of_samples) { + std::vector> samples; + std::vector subsample_sizes; + subsample_sizes.push_back({1, 1}); + while (number_of_samples-- > 0) { + samples.push_back(subsample_sizes); + } + SetSampleSizes(samples); + LoadLicense(); + MakeBuffers(); + EncryptData(); + OEMCryptoResult result = DecryptCENC(); + // Closing the session and opening it for next iteration. + // If it is last iteration, session will be closed in teardown method of + // class. + session_.close(); + session_.open(); + InstallTestRSAKey(&session_); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 1, 2 * MiB, kCheckStatus); +} + // Based on the resource rating, OEMCrypto should be able to handle the maximum // subsample size. TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptMaxSubsample) { @@ -3068,11 +4419,78 @@ INSTANTIATE_TEST_CASE_P(TestAll, OEMCryptoLicenseTest, // // Certificate Root of Trust Tests // -class OEMCryptoLoadsCertificate : public OEMCryptoSessionTestKeyboxTest {}; +class OEMCryptoLoadsCertificate : public OEMCryptoSessionTestKeyboxTest { + protected: + void TestPrepareProvisioningRequestForHugeBufferLengths( + const std::function f, + bool check_status) { + auto oemcrypto_function = [&](size_t message_length) { + Session s; + s.open(); + s.GenerateNonce(); + if (global_features.provisioning_method == OEMCrypto_OEMCertificate) { + s.LoadOEMCert(true); + } else { + s.GenerateDerivedKeysFromKeybox(keybox_); + } + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + f(message_length, &provisioning_messages); + return provisioning_messages + .SignAndCreateRequestWithCustomBufferLengths(); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } + + void TestLoadProvisioningForHugeBufferLengths( + const std::function f, + bool check_status, bool update_core_message_substring_values) { + auto oemcrypto_function = [&](size_t message_length) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + provisioning_messages.SignAndVerifyRequest(); + provisioning_messages.CreateDefaultResponse(); + if (update_core_message_substring_values) { + // Make provisioning message big enough so that updated core message + // substring offset and length values from tests are still able to read + // valid data from provisioning_message buffer rather than some garbage + // data. + provisioning_messages.set_message_size( + sizeof(provisioning_messages.response_data()) + message_length); + } + f(message_length, &provisioning_messages); + provisioning_messages + .EncryptAndSignResponseWithoutUpdatingEncPrivateKeyLength(); + OEMCryptoResult result = provisioning_messages.LoadResponse(); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } + + void TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + const std::function f) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + provisioning_messages.SignAndVerifyRequest(); + provisioning_messages.CreateDefaultResponse(); + size_t message_length = sizeof(provisioning_messages.response_data()); + f(message_length, &provisioning_messages); + provisioning_messages + .EncryptAndSignResponseWithoutUpdatingEncPrivateKeyLength(); + OEMCryptoResult result = provisioning_messages.LoadResponse(); + s.close(); + // Verifying error is not due to signature failure which can be caused due + // to test code. + ASSERT_NE(OEMCrypto_ERROR_SIGNATURE_FAILURE, result); + ASSERT_NE(OEMCrypto_SUCCESS, result); + } +}; // This test verifies that we can create a wrapped RSA key, and then reload it. TEST_F(OEMCryptoLoadsCertificate, LoadRSASessionKey) { - CreateWrappedRSAKey(); + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(s.InstallRSASessionTestKey(wrapped_rsa_key_)); @@ -3288,10 +4706,221 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionLargeBuffer) { provisioning_messages.encoded_rsa_key())); } +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeResponseLength) { + TestLoadProvisioningForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_message_size(message_size); + }, + !kCheckStatus, !kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageLength) { + TestLoadProvisioningForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_core_message_size(message_size); + }, + !kCheckStatus, !kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyLength) { + TestLoadProvisioningForHugeBufferLengths( + [](size_t length, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().enc_private_key.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyOffset) { + TestLoadProvisioningForHugeBufferLengths( + [](size_t offset, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().enc_private_key.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyLength) { + TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + [](size_t response_message_length, + ProvisioningRoundTrip* provisioning_messages) { + auto& enc_private_key = + provisioning_messages->core_response().enc_private_key; + enc_private_key.length = + response_message_length - enc_private_key.offset + 1; + }); +} + +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyOffset) { + TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + [](size_t response_message_length, + ProvisioningRoundTrip* provisioning_messages) { + auto& enc_private_key = + provisioning_messages->core_response().enc_private_key; + enc_private_key.offset = + response_message_length - enc_private_key.length + 1; + }); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyIvLength) { + TestLoadProvisioningForHugeBufferLengths( + [](size_t length, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().enc_private_key_iv.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyIvOffset) { + TestLoadProvisioningForHugeBufferLengths( + [](size_t offset, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().enc_private_key_iv.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyIvLength) { + TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + [](size_t response_message_length, + ProvisioningRoundTrip* provisioning_messages) { + auto& enc_private_key_iv = + provisioning_messages->core_response().enc_private_key_iv; + enc_private_key_iv.length = + response_message_length - enc_private_key_iv.offset + 1; + }); +} + +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyIvOffset) { + TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + [](size_t response_message_length, + ProvisioningRoundTrip* provisioning_messages) { + auto& enc_private_key_iv = + provisioning_messages->core_response().enc_private_key_iv; + enc_private_key_iv.offset = + response_message_length - enc_private_key_iv.length + 1; + }); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncMessageKeyLength) { + TestLoadProvisioningForHugeBufferLengths( + [](size_t length, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().encrypted_message_key.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncMessageKeyOffset) { + TestLoadProvisioningForHugeBufferLengths( + [](size_t offset, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().encrypted_message_key.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncMessageKeyLength) { + TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + [](size_t response_message_length, + ProvisioningRoundTrip* provisioning_messages) { + auto& encrypted_message_key = + provisioning_messages->core_response().encrypted_message_key; + encrypted_message_key.length = + response_message_length - encrypted_message_key.offset + 1; + }); +} + +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncMessageKeyOffset) { + TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + [](size_t response_message_length, + ProvisioningRoundTrip* provisioning_messages) { + auto& encrypted_message_key = + provisioning_messages->core_response().encrypted_message_key; + encrypted_message_key.offset = + response_message_length - encrypted_message_key.length + 1; + }); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeSignatureLength) { + auto oemcrypto_function = [&](size_t signature_size) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + provisioning_messages.SignAndVerifyRequest(); + provisioning_messages.CreateDefaultResponse(); + provisioning_messages.EncryptAndSignResponse(); + vector signature(signature_size); + size_t wrapped_private_key_length = 0; + // Find wrapped_private_key_length. + OEMCrypto_LoadProvisioning( + s.session_id(), + provisioning_messages.encrypted_response_buffer().data(), + provisioning_messages.encrypted_response_buffer().size(), + provisioning_messages.serialized_core_message().size(), + signature.data(), signature_size, nullptr, &wrapped_private_key_length); + std::vector wrapped_rsa_key(wrapped_private_key_length); + OEMCryptoResult result = OEMCrypto_LoadProvisioning( + s.session_id(), + provisioning_messages.encrypted_response_buffer().data(), + provisioning_messages.encrypted_response_buffer().size(), + provisioning_messages.serialized_core_message().size(), + signature.data(), signature_size, wrapped_rsa_key.data(), + &wrapped_private_key_length); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeWrappedRsaKeyLength) { + auto oemcrypto_function = [&](size_t buffer_length) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + provisioning_messages.SignAndVerifyRequest(); + provisioning_messages.CreateDefaultResponse(); + provisioning_messages.EncryptAndSignResponse(); + size_t wrapped_private_key_length = buffer_length; + vector wrapped_private_key(wrapped_private_key_length); + OEMCryptoResult result = OEMCrypto_LoadProvisioning( + s.session_id(), + provisioning_messages.encrypted_response_buffer().data(), + provisioning_messages.encrypted_response_buffer().size(), + provisioning_messages.serialized_core_message().size(), + provisioning_messages.response_signature().data(), + provisioning_messages.response_signature().size(), + wrapped_private_key.data(), &wrapped_private_key_length); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + // Test that a wrapped RSA key can be loaded. TEST_F(OEMCryptoLoadsCertificate, LoadWrappedRSAKey) { OEMCryptoResult sts; - CreateWrappedRSAKey(); + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); sts = OEMCrypto_LoadDRMPrivateKey(s.session_id(), OEMCrypto_RSA_Private_Key, @@ -3300,12 +4929,54 @@ TEST_F(OEMCryptoLoadsCertificate, LoadWrappedRSAKey) { ASSERT_EQ(OEMCrypto_SUCCESS, sts); } +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadDrmPrivateKeyForHugeWrappedRsaKeyLength) { + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); + auto oemcrypto_function = [&](size_t wrapped_rsa_key_length) { + Session s; + s.open(); + vector wrapped_rsa_key_buffer(wrapped_rsa_key_length); + memcpy(wrapped_rsa_key_buffer.data(), wrapped_rsa_key_.data(), + wrapped_rsa_key_.size()); + OEMCryptoResult result = OEMCrypto_LoadDRMPrivateKey( + s.session_id(), OEMCrypto_RSA_Private_Key, + wrapped_rsa_key_buffer.data(), wrapped_rsa_key_buffer.size()); + s.close(); + return result; + }; + // It is hard to generate varying length valid wrapped rsa key with valid + // signature. Hence we just call function with random data and do not check + // status to test API with varying length wrapped rsa key. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, wrapped_rsa_key_.size(), + kHugeInputBufferLength, !kCheckStatus); +} + +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadDrmPrivateKeyForHugeWrappedRsaKeyLengthStartingFromLength1) { + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); + auto oemcrypto_function = [&](size_t wrapped_rsa_key_length) { + Session s; + s.open(); + vector wrapped_rsa_key_buffer(wrapped_rsa_key_length); + OEMCryptoResult result = OEMCrypto_LoadDRMPrivateKey( + s.session_id(), OEMCrypto_RSA_Private_Key, + wrapped_rsa_key_buffer.data(), wrapped_rsa_key_buffer.size()); + s.close(); + return result; + }; + // It is hard to generate varying length valid wrapped rsa key with valid + // signature. Hence we just call function with random data and do not check + // status to test API with varying length wrapped rsa key. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + // Test a 3072 bit RSA key certificate. TEST_F(OEMCryptoLoadsCertificate, TestLargeRSAKey3072) { encoded_rsa_key_.assign(kTestRSAPKCS8PrivateKeyInfo3_3072, kTestRSAPKCS8PrivateKeyInfo3_3072 + sizeof(kTestRSAPKCS8PrivateKeyInfo3_3072)); - CreateWrappedRSAKey(); + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE( @@ -3327,7 +4998,7 @@ TEST_F(OEMCryptoLoadsCertificate, TestCarmichaelRSAKey) { encoded_rsa_key_.assign( kTestKeyRSACarmichael_2048, kTestKeyRSACarmichael_2048 + sizeof(kTestKeyRSACarmichael_2048)); - CreateWrappedRSAKey(); + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE( @@ -3345,7 +5016,7 @@ TEST_F(OEMCryptoLoadsCertificate, TestCarmichaelRSAKey) { // This tests that two sessions can use different RSA keys simultaneously. TEST_F(OEMCryptoLoadsCertificate, TestMultipleRSAKeys) { - CreateWrappedRSAKey(); + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); Session s1; // Session s1 loads the default rsa key, but doesn't use it // until after s2 uses its key. ASSERT_NO_FATAL_FAILURE(s1.open()); @@ -3360,7 +5031,7 @@ TEST_F(OEMCryptoLoadsCertificate, TestMultipleRSAKeys) { encoded_rsa_key_.assign(kTestRSAPKCS8PrivateKeyInfo4_2048, kTestRSAPKCS8PrivateKeyInfo4_2048 + sizeof(kTestRSAPKCS8PrivateKeyInfo4_2048)); - CreateWrappedRSAKey(); + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); ASSERT_NO_FATAL_FAILURE(s2.open()); ASSERT_NO_FATAL_FAILURE( s2.PreparePublicKey(encoded_rsa_key_.data(), encoded_rsa_key_.size())); @@ -3391,6 +5062,33 @@ TEST_F(OEMCryptoLoadsCertificate, SupportsCertificatesAPI13) { << "Supported certificates is only " << OEMCrypto_SupportedCertificates(); } +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryPrepareProvisioningRequestForHugeRequestMessageLength) { + TestPrepareProvisioningRequestForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_message_size(message_size); + }, + kCheckStatus); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryPrepareProvisioningRequestForHugeSignatureLength) { + TestPrepareProvisioningRequestForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_request_signature_size(message_size); + }, + !kCheckStatus); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryPrepareProvisioningRequestForHugeCoreMessageLength) { + TestPrepareProvisioningRequestForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_core_message_size(message_size); + }, + kCheckStatus); +} + // These tests are run by all L1 devices that load and use certificates. It is // also run by a few L3 devices that use a baked in certificate, but cannot load // a certificate. @@ -3424,14 +5122,14 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) { auto start_time = clock.now(); int count = 15; for (int i = 0; i < count; i++) { // Only 20 nonce available. - CreateWrappedRSAKey(); + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); } auto delta_time = clock.now() - start_time; const double provision_time = delta_time / std::chrono::milliseconds(1) / count; Session session; - CreateWrappedRSAKey(); + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); start_time = clock.now(); count = 0; while (clock.now() - start_time < kTestDuration) { @@ -3559,7 +5257,7 @@ TEST_F(OEMCryptoUsesCertificate, } TEST_F(OEMCryptoUsesCertificate, - OEMCryptoMemoryDeriveKeysFromSessionKeyForLargeEncContext) { + OEMCryptoMemoryDeriveKeysFromSessionKeyForHugeEncContext) { vector session_key; vector enc_session_key; ASSERT_NO_FATAL_FAILURE(session_.PreparePublicKey(encoded_rsa_key_.data(), @@ -3580,6 +5278,29 @@ TEST_F(OEMCryptoUsesCertificate, TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); } +TEST_F(OEMCryptoUsesCertificate, + OEMCryptoMemoryDeriveKeysFromSessionKeyForHugeEncSessionKey) { + vector session_key; + vector enc_session_key; + ASSERT_NO_FATAL_FAILURE(session_.PreparePublicKey(encoded_rsa_key_.data(), + encoded_rsa_key_.size())); + ASSERT_TRUE(session_.GenerateRSASessionKey(&session_key, &enc_session_key)); + vector mac_context; + vector enc_context; + session_.FillDefaultContext(&mac_context, &enc_context); + OEMCrypto_SESSION session_id = session_.session_id(); + auto oemcrypto_function = [&session_id, &session_key, &enc_context, + &mac_context, + &enc_session_key](size_t buffer_length) { + session_key.resize(buffer_length); + return OEMCrypto_DeriveKeysFromSessionKey( + session_id, enc_session_key.data(), enc_session_key.size(), + mac_context.data(), mac_context.size(), enc_context.data(), + enc_context.size()); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + // This test attempts to use alternate algorithms for loaded device certs. class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { protected: @@ -4939,6 +6660,48 @@ TEST_P(OEMCryptoGenericCryptoTest, OEMCryptoMemorySelectKeyForHugeKeyIdLength) { TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); } +TEST_P(OEMCryptoGenericCryptoTest, + OEMCryptoMemoryGenericKeyEncryptForHugeBuffer) { + EncryptAndLoadKeys(); + unsigned int key_index = 0; + vector expected_encrypted; + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); + OEMCrypto_SESSION session_id = session_.session_id(); + auto& iv = iv_; + auto oemcrypto_function = [&session_id, &iv](size_t buffer_length) mutable { + vector buffer(buffer_length); + return OEMCrypto_Generic_Encrypt(session_id, buffer.data(), buffer.size(), + iv, OEMCrypto_AES_CBC_128_NO_PADDING, + buffer.data()); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 16, kHugeInputBufferLength, + kCheckStatus); +} + +TEST_P( + OEMCryptoGenericCryptoTest, + OEMCryptoMemoryGenericKeyEncryptForHugeBufferWithBufferLengthNotMultipleOf16) { + EncryptAndLoadKeys(); + unsigned int key_index = 0; + vector expected_encrypted; + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); + OEMCrypto_SESSION session_id = session_.session_id(); + vector buffer(17); + ASSERT_NO_FATAL_FAILURE(OEMCrypto_Generic_Encrypt( + session_id, buffer.data(), buffer.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, buffer.data())); +} + // Test Generic_Decrypt works correctly. TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecrypt) { EncryptAndLoadKeys(); @@ -4959,6 +6722,29 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecrypt) { ASSERT_EQ(clear_buffer_, resultant); } +TEST_P(OEMCryptoGenericCryptoTest, + OEMCryptoMemoryGenericKeyDecryptForHugeBuffer) { + EncryptAndLoadKeys(); + unsigned int key_index = 1; + OEMCrypto_SelectKey(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR); + OEMCrypto_SESSION session_id = session_.session_id(); + auto iv = iv_; + auto oemcrypto_function = [&session_id, &iv](size_t buffer_length) { + vector encrypted(buffer_length); + vector resultant(encrypted.size()); + + return OEMCrypto_Generic_Decrypt( + session_id, encrypted.data(), encrypted.size(), iv, + OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()); + }; + // API expects length to be multiple of 16. Starting from 16. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 16, kHugeInputBufferLength, + kCheckStatus); +} + // Test that Generic_Decrypt works correctly when the input and output buffers // are the same. TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecryptSameBufferAPI12) { @@ -5041,6 +6827,51 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeySign) { ASSERT_EQ(expected_signature, signature); } +TEST_P(OEMCryptoGenericCryptoTest, OEMCryptoMemoryGenericKeySignForHugeBuffer) { + EncryptAndLoadKeys(); + unsigned int key_index = 2; + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); + vector signature(SHA256_DIGEST_LENGTH); + size_t signature_length = signature.size(); + OEMCrypto_SESSION session_id = session_.session_id(); + auto oemcrypto_function = [&session_id, &signature, + &signature_length](size_t buffer_length) { + vector buffer(buffer_length); + return OEMCrypto_Generic_Sign(session_id, buffer.data(), buffer.size(), + OEMCrypto_HMAC_SHA256, signature.data(), + &signature_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_P(OEMCryptoGenericCryptoTest, + OEMCryptoMemoryGenericKeySignForHugeSignatureLength) { + EncryptAndLoadKeys(); + unsigned int key_index = 2; + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); + OEMCrypto_SESSION session_id = session_.session_id(); + auto clear_buffer = clear_buffer_; + auto oemcrypto_function = [&session_id, + &clear_buffer](size_t signature_length) { + vector signature(signature_length); + size_t gen_signature_length = signature_length; + return OEMCrypto_Generic_Sign(session_id, clear_buffer.data(), + clear_buffer.size(), OEMCrypto_HMAC_SHA256, + signature.data(), &gen_signature_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + // Test that the Generic_Sign function fails when not allowed. TEST_P(OEMCryptoGenericCryptoTest, GenericKeyBadSign) { EncryptAndLoadKeys(); @@ -5068,6 +6899,51 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyVerify) { signature.data(), signature.size())); } +TEST_P(OEMCryptoGenericCryptoTest, + OEMCryptoMemoryGenericKeyVerifyForHugeBuffer) { + EncryptAndLoadKeys(); + unsigned int key_index = 3; + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); + auto oemcrypto_function = [&](size_t buffer_length) { + vector buffer(buffer_length); + vector signature; + SignBuffer(key_index, buffer, &signature); + return OEMCrypto_Generic_Verify(session_.session_id(), buffer.data(), + buffer.size(), OEMCrypto_HMAC_SHA256, + signature.data(), signature.size()); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_P(OEMCryptoGenericCryptoTest, + OEMCryptoMemoryGenericKeyVerifyForHugeSignatureLength) { + EncryptAndLoadKeys(); + unsigned int key_index = 3; + vector signature; + SignBuffer(key_index, clear_buffer_, &signature); + + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); + OEMCrypto_SESSION session_id = session_.session_id(); + auto clear_buffer = clear_buffer_; + auto oemcrypto_function = [&session_id, &clear_buffer, + &signature](size_t signature_length) { + return OEMCrypto_Generic_Verify(session_id, clear_buffer.data(), + clear_buffer.size(), OEMCrypto_HMAC_SHA256, + signature.data(), signature_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + // Test that the Generic_Verify function fails when not allowed. TEST_P(OEMCryptoGenericCryptoTest, GenericKeyBadVerify) { EncryptAndLoadKeys(); @@ -5527,6 +7403,8 @@ class LicenseWithUsageEntry { class OEMCryptoUsageTableTest : public OEMCryptoGenericCryptoTest { public: + void SetUp() override { OEMCryptoGenericCryptoTest::SetUp(); } + virtual void ShutDown() { ASSERT_NO_FATAL_FAILURE(session_.close()); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Terminate()); @@ -5556,6 +7434,214 @@ class OEMCryptoUsageTableTest : public OEMCryptoGenericCryptoTest { } }; +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryUpdateUsageEntryForHugeHeaderBuffer) { + auto oemcrypto_function = [&](size_t buffer_length) { + if (buffer_length < encrypted_usage_header_.size()) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + size_t header_buffer_length = 0; + size_t entry_buffer_length = 0; + // Header buffer length varies as generation_numbers size changes on every + // call. Hence, we need to call update usage entry in every loop to get + // latest value of header_buffer_length. + OEMCrypto_UpdateUsageEntry(s.session_id(), nullptr, &header_buffer_length, + nullptr, &entry_buffer_length); + vector encrypted_usage_entry(entry_buffer_length); + vector header_buffer(encrypted_usage_header_); + header_buffer.resize(buffer_length); + return OEMCrypto_UpdateUsageEntry( + s.session_id(), header_buffer.data(), &buffer_length, + encrypted_usage_entry.data(), &entry_buffer_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryUpdateUsageEntryForHugeUsageEntryBuffer) { + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + size_t header_buffer_length = 0; + size_t entry_buffer_length = 0; + // Header buffer length varies as generation_numbers size changes on every + // call. Hence, we need to call update usage entry in every loop to get + // latest value of header_buffer_length. + OEMCrypto_UpdateUsageEntry(s.session_id(), nullptr, &header_buffer_length, + nullptr, &entry_buffer_length); + vector header_buffer(encrypted_usage_header_); + header_buffer.resize(header_buffer_length); + vector encrypted_usage_entry(buffer_length); + return OEMCrypto_UpdateUsageEntry( + s.session_id(), header_buffer.data(), &header_buffer_length, + encrypted_usage_entry.data(), &buffer_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryDeactivateUsageEntryForHugePstBuffer) { + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry; + std::string pst("pst"); + pst.resize(buffer_length); + entry.license_messages().set_pst(pst); + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + return OEMCrypto_DeactivateUsageEntry( + s.session_id(), reinterpret_cast(pst.c_str()), + pst.length()); + }; + // The test setup assertions fails if pst length goes beyond kMaxPSTLength. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 1, kMaxPSTLength, + kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryLoadUsageTableHeaderForHugeHeader) { + auto oemcrypto_function = [&](size_t buffer_length) { + if (buffer_length < encrypted_usage_header_.size()) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeOfflineAndClose(this); + vector header_buffer(encrypted_usage_header_); + header_buffer.resize(buffer_length); + return OEMCrypto_LoadUsageTableHeader(header_buffer.data(), + header_buffer.size()); + }; + // We cannot generate an encrypted usage header of varying length with + // valid signature. Hence irrespective of return status, we call API for + // varying buffer lengths. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, + encrypted_usage_header_.size(), + kHugeInputBufferLength, !kCheckStatus); +} + +TEST_P( + OEMCryptoUsageTableTest, + OEMCryptoMemoryLoadUsageTableHeaderForHugeHeaderStartingHeaderLengthFrom1) { + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeOfflineAndClose(this); + vector header_buffer(buffer_length); + return OEMCrypto_LoadUsageTableHeader(header_buffer.data(), + header_buffer.size()); + }; + // We cannot generate an encrypted usage header of varying length with + // valid signature. Hence irrespective of return status, we call API for + // varying buffer lengths. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryLoadUsageEntryForHugeUsageEntryBuffer) { + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + Session& s = entry.session(); + // Make first entry 0. + entry.MakeOfflineAndClose(this); + if (buffer_length < s.encrypted_usage_entry().size()) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + Session s2; + s2.open(); + InstallTestRSAKey(&s2); + vector encrypted_usage_entry(buffer_length); + memcpy(encrypted_usage_entry.data(), s.encrypted_usage_entry().data(), + s.encrypted_usage_entry().size()); + const uint32_t usage_entry_number = s.usage_entry_number(); + return OEMCrypto_LoadUsageEntry(s2.session_id(), usage_entry_number, + encrypted_usage_entry.data(), + encrypted_usage_entry.size()); + }; + // We cannot generate an encrypted usage enctry of varying length with + // valid signature. Hence irrespective of return status, we call API for + // varying buffer lengths. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryLoadUsageEntryForHugeInvalidUsageEntryNumber) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + // Make first entry 0. + entry.MakeOfflineAndClose(this); + Session s; + s.open(); + InstallTestRSAKey(&s); + const uint32_t usage_entry_number = kHugeRandomNumber; + ASSERT_NO_FATAL_FAILURE(OEMCrypto_LoadUsageEntry( + s.session_id(), usage_entry_number, s.encrypted_usage_entry().data(), + s.encrypted_usage_entry().size())); +} + +TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryReportUsageForHugeReportBuffer) { + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + s.UpdateUsageEntry(&encrypted_usage_header_); + size_t length = 0; + OEMCrypto_ReportUsage(s.session_id(), + reinterpret_cast(entry.pst().c_str()), + entry.pst().length(), nullptr, &length); + vector pst_report_buffer(buffer_length); + return OEMCrypto_ReportUsage( + s.session_id(), reinterpret_cast(entry.pst().c_str()), + entry.pst().length(), pst_report_buffer.data(), &buffer_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryReportUsageForHugePstBuffer) { + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + s.UpdateUsageEntry(&encrypted_usage_header_); + size_t length = 0; + OEMCrypto_ReportUsage(s.session_id(), + reinterpret_cast(entry.pst().c_str()), + entry.pst().length(), nullptr, &length); + vector pst_report_buffer(length); + vector pst(buffer_length); + return OEMCrypto_ReportUsage(s.session_id(), pst.data(), pst.size(), + pst_report_buffer.data(), &length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryShrinkUsageTableHeaderForHugeHeaderBufferLength) { + LicenseWithUsageEntry entry0; + entry0.set_pst("pst 0"); + entry0.MakeOfflineAndClose(this); + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry1; + entry1.set_pst("pst 1"); + entry1.MakeOfflineAndClose(this); + size_t header_buffer_length = buffer_length; + encrypted_usage_header_.resize(header_buffer_length); + return OEMCrypto_ShrinkUsageTableHeader(1, encrypted_usage_header_.data(), + &header_buffer_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + // Test an online or streaming license with PST. This license requires a valid // nonce and can only be loaded once. TEST_P(OEMCryptoUsageTableTest, OnlineLicense) { @@ -5744,7 +7830,7 @@ TEST_P(OEMCryptoUsageTableTest, CreateAndLoadMultipleEntriesAPI16) { // Reload entry 0. ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry()); // Create new entry 1 should fail. - ASSERT_EQ(OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES, + ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_CreateNewUsageEntry(entry.session().session_id(), &usage_entry_number)); ASSERT_NO_FATAL_FAILURE(s.close()); @@ -5755,7 +7841,7 @@ TEST_P(OEMCryptoUsageTableTest, CreateAndLoadMultipleEntriesAPI16) { // Create entry 1. ASSERT_NO_FATAL_FAILURE(s2.CreateNewUsageEntry()); // Try to reload entry 0. - ASSERT_EQ(OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES, + ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_LoadUsageEntry(s2.session_id(), s.usage_entry_number(), s.encrypted_usage_entry().data(), s.encrypted_usage_entry().size())); @@ -5765,7 +7851,7 @@ TEST_P(OEMCryptoUsageTableTest, CreateAndLoadMultipleEntriesAPI16) { // This reloads entry 0. ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry()); - ASSERT_EQ(OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES, + ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(), s.encrypted_usage_entry().data(), s.encrypted_usage_entry().size())); @@ -5774,9 +7860,8 @@ TEST_P(OEMCryptoUsageTableTest, CreateAndLoadMultipleEntriesAPI16) { // Create an entry, then try to create a second entry. ASSERT_NO_FATAL_FAILURE(s2.open()); ASSERT_NO_FATAL_FAILURE(s2.CreateNewUsageEntry()); - ASSERT_EQ( - OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES, - OEMCrypto_CreateNewUsageEntry(s2.session_id(), &usage_entry_number)); + ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_CreateNewUsageEntry( + s2.session_id(), &usage_entry_number)); } // An entry can be loaded in only one session at a time. @@ -6354,6 +8439,16 @@ TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntriesToOpenSession) { 0, &encrypted_usage_header_, OEMCrypto_ERROR_ENTRY_IN_USE)); } +TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntriesToInvalidHugeEntryIndex) { + LicenseWithUsageEntry entry0; + entry0.set_pst("pst 0"); + entry0.MakeOfflineAndClose(this); + entry0.session().open(); + entry0.ReloadUsageEntry(); + ASSERT_NO_FATAL_FAILURE( + OEMCrypto_MoveEntry(entry0.session().session_id(), kHugeRandomNumber)); +} + // The usage table cannot be shrunk if any session is using an entry that would // be deleted. TEST_P(OEMCryptoUsageTableDefragTest, ShrinkOverOpenSessions) { diff --git a/util/include/advance_iv_ctr.h b/util/include/advance_iv_ctr.h index b7b9ff4..db69414 100644 --- a/util/include/advance_iv_ctr.h +++ b/util/include/advance_iv_ctr.h @@ -1,6 +1,6 @@ // Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. #ifndef WVCDM_UTIL_ADVANCE_IV_CTR_H_ #define WVCDM_UTIL_ADVANCE_IV_CTR_H_ diff --git a/util/include/arraysize.h b/util/include/arraysize.h index 3e02553..5b5c843 100644 --- a/util/include/arraysize.h +++ b/util/include/arraysize.h @@ -1,6 +1,6 @@ // Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. #ifndef WVCDM_UTIL_ARRAYSIZE_H_ #define WVCDM_UTIL_ARRAYSIZE_H_ diff --git a/util/include/cdm_random.h b/util/include/cdm_random.h index bc97840..744b10e 100644 --- a/util/include/cdm_random.h +++ b/util/include/cdm_random.h @@ -1,6 +1,6 @@ // Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. #ifndef WVCDM_CORE_CDM_RANDOM_H_ #define WVCDM_CORE_CDM_RANDOM_H_ diff --git a/util/include/clock.h b/util/include/clock.h index 487ae26..4ec5905 100644 --- a/util/include/clock.h +++ b/util/include/clock.h @@ -1,6 +1,6 @@ // Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. // // Clock - Platform independent interface for a time library // diff --git a/util/include/disallow_copy_and_assign.h b/util/include/disallow_copy_and_assign.h index abc1048..9d38907 100644 --- a/util/include/disallow_copy_and_assign.h +++ b/util/include/disallow_copy_and_assign.h @@ -1,6 +1,6 @@ // Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. #ifndef WVCDM_UTIL_DISALLOW_COPY_AND_ASSIGN_H_ #define WVCDM_UTIL_DISALLOW_COPY_AND_ASSIGN_H_ diff --git a/util/include/file_store.h b/util/include/file_store.h index 39c49d7..94dded6 100644 --- a/util/include/file_store.h +++ b/util/include/file_store.h @@ -1,6 +1,6 @@ // Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. // // File - Platform independent interface for a File class // diff --git a/util/include/log.h b/util/include/log.h index 37706fa..5d945e4 100644 --- a/util/include/log.h +++ b/util/include/log.h @@ -1,6 +1,6 @@ // Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. // // Log - Platform independent interface for a Logging class // @@ -33,8 +33,18 @@ extern LogPriority g_cutoff; // unit tests. CORE_UTIL_EXPORT void InitLogging(); +// Only enable format specifier warnings on LP64 systems. There is +// no easy portable method to handle format specifiers for int64_t. +#if (defined(__GNUC__) || defined(__clang__)) && defined(__LP64__) +[[gnu::format(printf, 5, 6)]] CORE_UTIL_EXPORT void Log(const char* file, + const char* function, + int line, + LogPriority level, + const char* fmt, ...); +#else CORE_UTIL_EXPORT void Log(const char* file, const char* function, int line, LogPriority level, const char* fmt, ...); +#endif // Log APIs #ifndef LOGE diff --git a/util/include/platform.h b/util/include/platform.h index 4168e44..effc514 100644 --- a/util/include/platform.h +++ b/util/include/platform.h @@ -1,6 +1,6 @@ // Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. // // Platform - Abstracts some utilities between platforms. // diff --git a/util/include/rw_lock.h b/util/include/rw_lock.h index 8272405..6082443 100644 --- a/util/include/rw_lock.h +++ b/util/include/rw_lock.h @@ -1,6 +1,6 @@ // Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. #ifndef WVCDM_UTIL_RW_LOCK_H_ #define WVCDM_UTIL_RW_LOCK_H_ diff --git a/util/include/string_conversions.h b/util/include/string_conversions.h index cb6c9ee..feff9dc 100644 --- a/util/include/string_conversions.h +++ b/util/include/string_conversions.h @@ -1,6 +1,6 @@ // Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. #ifndef WVCDM_UTIL_STRING_CONVERSIONS_H_ #define WVCDM_UTIL_STRING_CONVERSIONS_H_ diff --git a/util/include/util_common.h b/util/include/util_common.h index 100e138..4477ca1 100644 --- a/util/include/util_common.h +++ b/util/include/util_common.h @@ -1,6 +1,6 @@ // Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. #ifndef WVCDM_UTIL_UTIL_COMMON_H_ #define WVCDM_UTIL_UTIL_COMMON_H_ diff --git a/util/libcrypto_dependency.gypi b/util/libcrypto_dependency.gypi index 288c91d..c456cec 100644 --- a/util/libcrypto_dependency.gypi +++ b/util/libcrypto_dependency.gypi @@ -1,6 +1,6 @@ # Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary -# source code may only be used and distributed under the Widevine Master -# License Agreement. +# source code may only be used and distributed under the Widevine License +# Agreement. { 'conditions': [ [ diff --git a/util/libssl_dependency.gypi b/util/libssl_dependency.gypi index 6bd512d..837c4ce 100644 --- a/util/libssl_dependency.gypi +++ b/util/libssl_dependency.gypi @@ -1,6 +1,6 @@ # Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary -# source code may only be used and distributed under the Widevine Master -# License Agreement. +# source code may only be used and distributed under the Widevine License +# Agreement. { 'conditions': [ [ diff --git a/util/src/cdm_random.cpp b/util/src/cdm_random.cpp index 751836e..ca4020a 100644 --- a/util/src/cdm_random.cpp +++ b/util/src/cdm_random.cpp @@ -1,6 +1,6 @@ // Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. #include "cdm_random.h" diff --git a/util/src/dllmain.cpp b/util/src/dllmain.cpp index 8edea4a..78519c8 100644 --- a/util/src/dllmain.cpp +++ b/util/src/dllmain.cpp @@ -1,6 +1,6 @@ // Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. // // dllmain - A dummy DllMain method for Windows DLLs. // diff --git a/util/src/platform.cpp b/util/src/platform.cpp index 820a487..648ebd8 100644 --- a/util/src/platform.cpp +++ b/util/src/platform.cpp @@ -1,6 +1,6 @@ // Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. #include "platform.h" diff --git a/util/src/rw_lock.cpp b/util/src/rw_lock.cpp index 43dff64..f962017 100644 --- a/util/src/rw_lock.cpp +++ b/util/src/rw_lock.cpp @@ -1,6 +1,6 @@ // Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. #include "rw_lock.h" diff --git a/util/src/string_conversions.cpp b/util/src/string_conversions.cpp index b9b4979..e40e6f7 100644 --- a/util/src/string_conversions.cpp +++ b/util/src/string_conversions.cpp @@ -1,6 +1,6 @@ // Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. #include "string_conversions.h" @@ -56,12 +56,12 @@ std::vector a2b_hex(const std::string& byte) { return array; } - for (unsigned int i = 0; i < count / 2; ++i) { + for (size_t i = 0; i < count / 2; ++i) { unsigned char msb = 0; // most significant 4 bits unsigned char lsb = 0; // least significant 4 bits if (!DecodeHexChar(byte[i * 2], &msb) || !DecodeHexChar(byte[i * 2 + 1], &lsb)) { - LOGE("Invalid hex value %c%c at index %d", byte[i * 2], byte[i * 2 + 1], + LOGE("Invalid hex value %c%c at index %zu", byte[i * 2], byte[i * 2 + 1], i); return array; } @@ -254,6 +254,8 @@ std::vector Base64SafeDecode(const std::string& b64_input) { std::string HexEncode(const uint8_t* in_buffer, unsigned int size) { static const char kHexChars[] = "0123456789ABCDEF"; if (size == 0) return ""; + constexpr unsigned int kMaxSafeSize = 2048; + if (size > kMaxSafeSize) size = kMaxSafeSize; // Each input byte creates two output hex characters. std::string out_buffer(size * 2, '\0'); diff --git a/util/test/base64_test.cpp b/util/test/base64_test.cpp index dd25a20..81d32a9 100644 --- a/util/test/base64_test.cpp +++ b/util/test/base64_test.cpp @@ -1,6 +1,6 @@ // Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. #include diff --git a/util/test/cdm_random_unittest.cpp b/util/test/cdm_random_unittest.cpp index 8555524..097a698 100644 --- a/util/test/cdm_random_unittest.cpp +++ b/util/test/cdm_random_unittest.cpp @@ -1,6 +1,6 @@ // Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. #include diff --git a/util/test/file_store_unittest.cpp b/util/test/file_store_unittest.cpp index 5140b88..c89fe6e 100644 --- a/util/test/file_store_unittest.cpp +++ b/util/test/file_store_unittest.cpp @@ -1,6 +1,6 @@ // Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. #include #include diff --git a/util/test/test_clock.cpp b/util/test/test_clock.cpp index 151bb28..f593e58 100644 --- a/util/test/test_clock.cpp +++ b/util/test/test_clock.cpp @@ -1,4 +1,6 @@ -// Copyright 2019 Google Inc. All Rights Reserved. +// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. // // Clock - A fake clock just for running tests. diff --git a/util/test/test_sleep.cpp b/util/test/test_sleep.cpp index 1656381..f3f219c 100644 --- a/util/test/test_sleep.cpp +++ b/util/test/test_sleep.cpp @@ -1,6 +1,6 @@ // Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. #include "test_sleep.h" @@ -23,7 +23,7 @@ namespace wvcdm { bool TestSleep::real_sleep_ = true; TestSleep::CallBack* TestSleep::callback_ = nullptr; -int TestSleep::total_clock_rollback_ = 0; +int TestSleep::total_clock_rollback_seconds_ = 0; void TestSleep::Sleep(unsigned int seconds) { int64_t milliseconds = 1000 * seconds; @@ -33,11 +33,15 @@ void TestSleep::Sleep(unsigned int seconds) { // total since the start, and then compare to a running total of sleep // calls. We sleep for approximately x second, and then advance the clock by // the amount of time that has actually passed. - static auto start_real = std::chrono::system_clock().now(); - static int64_t fake_clock = 0; + static const auto start_real = std::chrono::system_clock().now(); sleep(seconds); - auto now_real = std::chrono::system_clock().now(); - int64_t total_real = (now_real - start_real) / std::chrono::milliseconds(1); + const auto now_real = std::chrono::system_clock().now(); + const int64_t rollback_adjustment = 1000 * total_clock_rollback_seconds_; + const int64_t total_real = + (now_real - start_real) / std::chrono::milliseconds(1) + + rollback_adjustment; + + static int64_t fake_clock = 0; // We want to advance the fake clock by the difference between the real // clock, and the previous value on the fake clock. milliseconds = total_real - fake_clock; @@ -90,7 +94,7 @@ bool TestSleep::RollbackSystemTime(int seconds) { // For both real and fake sleep we still update the callback and we still keep // track of the total amount of time slept. - total_clock_rollback_ += seconds; + total_clock_rollback_seconds_ += seconds; if (callback_ != nullptr) callback_->ElapseTime(-1000 * seconds); return true; } @@ -98,7 +102,6 @@ bool TestSleep::RollbackSystemTime(int seconds) { bool TestSleep::CanChangeSystemTime() { // If we are using a fake clock, then we can move the clock backwards by // just going backwards. - // ElapseTime. if (!real_sleep_) { return true; } diff --git a/util/test/test_sleep.h b/util/test/test_sleep.h index 34c4b3f..9658ca3 100644 --- a/util/test/test_sleep.h +++ b/util/test/test_sleep.h @@ -1,6 +1,6 @@ // Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +// source code may only be used and distributed under the Widevine License +// Agreement. // // TestSleep - Controls sleep and clock adjustment during tests. // @@ -44,8 +44,8 @@ class TestSleep { // Roll the system clock forward to undo all previous calls to // RollBackSystemTime. Returns true on success. static bool ResetRollback() { - return total_clock_rollback_ == 0 || - RollbackSystemTime(-total_clock_rollback_); + return total_clock_rollback_seconds_ == 0 || + RollbackSystemTime(-total_clock_rollback_seconds_); } // Returns true if the system time can be rolled back. This is true on some @@ -67,7 +67,7 @@ class TestSleep { static CallBack* callback_; // The sum of all calls to RollBackSystemTime. Kept so we can undo all changes // at the end of a test. - static int total_clock_rollback_; + static int total_clock_rollback_seconds_; }; } // namespace wvcdm