From 23f7cd60a731718381ce9c7054d545ba411344a5 Mon Sep 17 00:00:00 2001 From: Alex Dale Date: Fri, 19 Feb 2021 17:16:32 -0800 Subject: [PATCH] Sync Android reference with CDM reference. The sc-dev branch on Android is out of sync with several important changes on the CDM master branch. This changes copies several CLs. [ Merge of http://go/wvgerrit/104524 ] OEMCrypto unittest: generic crypto APIs Add unit tests to verify that generic crypto APIs do not crash for large input buffer lengths and signature lengths. [ Merge of http://go/wvgerrit/106583 ] Fix secure buffer tests in OEMCrypto testbed The secure buffers were not being used correctly in the testbed, and were failing OEMCryptoMemoryCopyBufferForHugeBufferLengths. [ Merge of http://go/wvgerrit/109603 ] Reject block_offsets of 16 or greater in OEC Ref This is a potential security hole. We will be enforcing that OEMCrypto rejects this in an upcoming test, so the Ref must be updated to reject it. [ Merge of http://go/wvgerrit/110165 ] Fix Format String Signedness See above for full description. [ Merge of http://go/wvgerrit/111784 ] Fix heap overflow test in L3 and OEMCrypto ref Check the length of wrapped_rsa_key_length before casting to WrappedRSAKey struct. [ Merge of http://go/wvgerrit/113563 ] Reword "blacklisted" to "forbidden" [ Merge of http://go/wvgerrit/113583 ] Use error code from RAND_bytes The return code from RAND_bytes was not used correctly. [ Merge of http://go/wvgerrit/113644 ] Check for buffer overflow when computing subsample size The test DecryptCENCForNumBytesClearPlusEncryptedOverflowsSize cleverly picks num_bytes_clear + num_bytes_encrypted = 1 after integer overflow. This is in the refernce code, level 3, and odkitee. [ Merge of http://go/wvgerrit/113683 ] OEMCrypto reference code: respect analog flags for clear buffers The reference code should honor the analog_display_active flag for both clear and secure buffers. [ Merge of http://go/wvgerrit/114883 ] Add size check for IV in OEMCrypto APIs IV is supposed to be 16 bytes but the size is never checked before iv gets used in LoadProvisioning. Bug: 145026457 Bug: 147569428 Bug: 159847851 Bug: 162372059 Bug: 169278035 Bug: 169980065 Bug: 173460694 Bug: 173994023 Bug: 174523584 Bug: 175001473 Bug: 175041667 Test: No compiled files changed Change-Id: If0ccd1cd3a56f72eedd2a6cb202a34bc7b43ca0d --- .../ref/src/oemcrypto_engine_ref.cpp | 7 + .../oemcrypto/ref/src/oemcrypto_engine_ref.h | 6 +- .../oemcrypto/ref/src/oemcrypto_ref.cpp | 162 ++++++++++++------ .../oemcrypto/ref/src/oemcrypto_session.cpp | 83 +++++---- .../ref/src/oemcrypto_usage_table_ref.cpp | 19 +- 5 files changed, 167 insertions(+), 110 deletions(-) diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.cpp index 596ff72a..e329f271 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.cpp +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.cpp @@ -230,6 +230,13 @@ OEMCryptoResult CryptoEngine::SetDestination( max_length = out_description.buffer.clear.address_length; break; case OEMCrypto_BufferType_Secure: + if (out_description.buffer.secure.handle_length < + out_description.buffer.secure.offset) { + LOGE("Secure buffer offset too large: %zu < %zu", + out_description.buffer.secure.handle_length, + out_description.buffer.secure.offset); + return OEMCrypto_ERROR_SHORT_BUFFER; + } destination_ = reinterpret_cast(out_description.buffer.secure.handle) + out_description.buffer.secure.offset; diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.h b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.h index 299c527b..07d31cfc 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.h +++ b/libwvdrmengine/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/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp index 9c038b6c..3f256466 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp +++ b/libwvdrmengine/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 validity 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( @@ -1111,6 +1132,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadProvisioning( LOGE("ODK Error %d", result); return result; } + if (parsed_response.enc_private_key_iv.length != wvoec::KEY_IV_SIZE) { + LOGE("Encrypted private key iv has invalid length: %zu", + parsed_response.enc_private_key_iv.length); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } // For the reference implementation, the wrapped key and the encrypted // key are the same size -- just encrypted with different keys. @@ -1178,6 +1204,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 +1423,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 +1474,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 +1505,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 +1539,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 +1568,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 +1633,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 +1677,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 +1715,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 +1738,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 +1796,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/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp index cbbc6fbe..15671234 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp +++ b/libwvdrmengine/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/libwvdrmengine/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp index 69f2f463..d61ec052 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp +++ b/libwvdrmengine/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;