From f79f9bf998ff8ad0e7307eeca1a73ea8c492b761 Mon Sep 17 00:00:00 2001 From: Vicky Min Date: Tue, 26 Nov 2024 20:08:25 +0000 Subject: [PATCH] OEMCrypto and OPK 18.8 --- CHANGELOG.md | 11 + oemcrypto/include/OEMCryptoCENC.h | 2 +- oemcrypto/odk/include/core_message_features.h | 4 +- oemcrypto/odk/include/odk_structs.h | 4 +- oemcrypto/odk/src/core_message_features.cpp | 2 +- oemcrypto/odk/src/odk_timer.c | 2 +- oemcrypto/odk/test/odk_test.cpp | 4 +- oemcrypto/opk/build/ree-sources.mk | 1 + oemcrypto/opk/oemcrypto_ta/oemcrypto.c | 18 +- .../opk/oemcrypto_ta/oemcrypto_api_macros.h | 2 +- .../ta/common/wtpi_impl/wtpi_test_impl.gyp | 7 +- oemcrypto/opk/ports/trusty/ta/README.md | 2 +- .../trusty/ta/reference/liboemcrypto/build.sh | 2 +- .../liboemcrypto/liboemcrypto-inc.mk | 2 +- .../ports/trusty/ta/reference/widevine_app.c | 15 +- oemcrypto/test/common.mk | 1 + oemcrypto/test/extract_bcc_tool.cpp | 177 +++ oemcrypto/test/oec_decrypt_fallback_chain.cpp | 16 +- oemcrypto/test/oemcrypto_basic_test.cpp | 139 +- oemcrypto/test/oemcrypto_basic_test.h | 1 + oemcrypto/test/oemcrypto_cast_test.cpp | 21 +- oemcrypto/test/oemcrypto_cast_test.h | 31 +- oemcrypto/test/oemcrypto_decrypt_test.cpp | 4 + .../test/oemcrypto_generic_crypto_test.cpp | 5 +- oemcrypto/test/oemcrypto_license_test.cpp | 6 + .../test/oemcrypto_provisioning_test.cpp | 23 +- oemcrypto/test/oemcrypto_security_test.cpp | 1171 ++++++++++++++++- oemcrypto/test/oemcrypto_test.cpp | 1153 +--------------- oemcrypto/test/oemcrypto_test_android.cpp | 4 + oemcrypto/test/oemcrypto_unittests.gypi | 1 + oemcrypto/test/oemcrypto_usage_table_test.cpp | 4 + util/include/file_store.h | 91 +- util/test/file_store_unittest.cpp | 592 ++++++--- 33 files changed, 2047 insertions(+), 1471 deletions(-) create mode 100644 oemcrypto/test/extract_bcc_tool.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d1bdf0..b52101a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ [TOC] +## [Version 18.8][v18.8] + +This is a minor release with minor test improvements. + +### Tests + +- Update some CAST tests to enforce format of the message signed by + OEMCrypto_GenerateRSASignature() +- Skip usage table tests on devices that don't support usage tables + ## [Version 18.7][v18.7] This release adds new tests that provide stricter enforcement of the existing @@ -588,3 +598,4 @@ Public release for OEMCrypto API and ODK library version 16.4. [v18.5]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v18.5 [v18.6]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v18.6 [v18.7]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v18.7 +[v18.8]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v18.8 diff --git a/oemcrypto/include/OEMCryptoCENC.h b/oemcrypto/include/OEMCryptoCENC.h index 42184e2..7c27ae0 100644 --- a/oemcrypto/include/OEMCryptoCENC.h +++ b/oemcrypto/include/OEMCryptoCENC.h @@ -3,7 +3,7 @@ // License Agreement. /** - * @mainpage OEMCrypto API v18.7 + * @mainpage OEMCrypto API v18.8 * * OEMCrypto is the low level library implemented by the OEM to provide key and * content protection, usually in a separate secure memory or process space. The diff --git a/oemcrypto/odk/include/core_message_features.h b/oemcrypto/odk/include/core_message_features.h index 3779f02..4626507 100644 --- a/oemcrypto/odk/include/core_message_features.h +++ b/oemcrypto/odk/include/core_message_features.h @@ -26,9 +26,9 @@ struct CoreMessageFeatures { // This is the published version of the ODK Core Message library. The default // behavior is for the server to restrict messages to at most this version - // number. The default is 18.7. + // number. The default is 18.8. uint32_t maximum_major_version = 18; - uint32_t maximum_minor_version = 7; + uint32_t maximum_minor_version = 8; bool operator==(const CoreMessageFeatures &other) const; bool operator!=(const CoreMessageFeatures &other) const { diff --git a/oemcrypto/odk/include/odk_structs.h b/oemcrypto/odk/include/odk_structs.h index cabe6f0..54d1886 100644 --- a/oemcrypto/odk/include/odk_structs.h +++ b/oemcrypto/odk/include/odk_structs.h @@ -16,10 +16,10 @@ extern "C" { /* The version of this library. */ #define ODK_MAJOR_VERSION 18 -#define ODK_MINOR_VERSION 7 +#define ODK_MINOR_VERSION 8 /* ODK Version string. Date changed automatically on each release. */ -#define ODK_RELEASE_DATE "ODK v18.7 2024-09-04" +#define ODK_RELEASE_DATE "ODK v18.8 2024-11-04" /* The lowest version number for an ODK message. */ #define ODK_FIRST_VERSION 16 diff --git a/oemcrypto/odk/src/core_message_features.cpp b/oemcrypto/odk/src/core_message_features.cpp index e9e075c..7b726bd 100644 --- a/oemcrypto/odk/src/core_message_features.cpp +++ b/oemcrypto/odk/src/core_message_features.cpp @@ -30,7 +30,7 @@ CoreMessageFeatures CoreMessageFeatures::DefaultFeatures( features.maximum_minor_version = 2; // 17.2 break; case 18: - features.maximum_minor_version = 7; // 18.7 + features.maximum_minor_version = 8; // 18.8 break; default: features.maximum_minor_version = 0; diff --git a/oemcrypto/odk/src/odk_timer.c b/oemcrypto/odk/src/odk_timer.c index b79ac05..c3a9456 100644 --- a/oemcrypto/odk/src/odk_timer.c +++ b/oemcrypto/odk/src/odk_timer.c @@ -274,7 +274,7 @@ OEMCryptoResult ODK_InitializeSessionValues(ODK_TimerLimits* timer_limits, nonce_values->api_minor_version = 2; break; case 18: - nonce_values->api_minor_version = 7; + nonce_values->api_minor_version = 8; break; default: nonce_values->api_minor_version = 0; diff --git a/oemcrypto/odk/test/odk_test.cpp b/oemcrypto/odk/test/odk_test.cpp index fe172bd..def762d 100644 --- a/oemcrypto/odk/test/odk_test.cpp +++ b/oemcrypto/odk/test/odk_test.cpp @@ -1216,7 +1216,7 @@ std::vector TestCases() { // number. {16, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 16, 5}, {17, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 17, 2}, - {18, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 18, 7}, + {18, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 18, 8}, // Here are some known good versions. Make extra sure they work. {ODK_MAJOR_VERSION, 16, 3, 16, 3}, {ODK_MAJOR_VERSION, 16, 4, 16, 4}, @@ -1230,6 +1230,7 @@ std::vector TestCases() { {ODK_MAJOR_VERSION, 18, 5, 18, 5}, {ODK_MAJOR_VERSION, 18, 6, 18, 6}, {ODK_MAJOR_VERSION, 18, 7, 18, 7}, + {ODK_MAJOR_VERSION, 18, 8, 18, 8}, {0, 16, 3, 16, 3}, {0, 16, 4, 16, 4}, {0, 16, 5, 16, 5}, @@ -1239,6 +1240,7 @@ std::vector TestCases() { {0, 18, 5, 18, 5}, {0, 18, 6, 18, 6}, {0, 18, 7, 18, 7}, + {0, 18, 8, 18, 8}, }; return test_cases; } diff --git a/oemcrypto/opk/build/ree-sources.mk b/oemcrypto/opk/build/ree-sources.mk index 6d7c67d..e4fcfac 100644 --- a/oemcrypto/opk/build/ree-sources.mk +++ b/oemcrypto/opk/build/ree-sources.mk @@ -216,6 +216,7 @@ oemcrypto_unittests_sources += \ $(oemcrypto_unittests_dir)/oemcrypto_generic_crypto_test.cpp \ $(oemcrypto_unittests_dir)/oemcrypto_license_test.cpp \ $(oemcrypto_unittests_dir)/oemcrypto_provisioning_test.cpp \ + $(oemcrypto_unittests_dir)/oemcrypto_security_test.cpp \ $(oemcrypto_unittests_dir)/oemcrypto_usage_table_test.cpp \ $(oemcrypto_unittests_dir)/oemcrypto_test.cpp \ $(oemcrypto_dir)/util/src/cmac.cpp \ diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto.c index a3c83e3..3c00289 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto.c @@ -350,10 +350,24 @@ static OEMCryptoResult RewrapDeviceDRMKeyOEMCert( LOGE("Failed to AES CBC decrypt DRM private key with result: %u", result); goto cleanup; } + /* Adjust for RSA keys with specified schemes */ + uint32_t allowed_schemes = 0; + size_t key_offset = 0; + if (drm_key_type == DRM_RSA_PRIVATE_KEY) { + if (enc_drm_key_length >= 8 && + crypto_memcmp(clear_drm_key, "SIGN", 4) == 0) { + memcpy(&allowed_schemes, clear_drm_key + 4, 4); + allowed_schemes = oemcrypto_be32toh(allowed_schemes); + key_offset = 8; + } else { + allowed_schemes = kSign_RSASSA_PSS; + } + } /* Create asymmetric key handle for DRM private key in order to get the * signature size. */ WTPI_AsymmetricKey_Handle private_key_handle; - result = WTPI_CreateAsymmetricKeyHandle(clear_drm_key, enc_drm_key_length, + result = WTPI_CreateAsymmetricKeyHandle(clear_drm_key + key_offset, + enc_drm_key_length - key_offset, drm_key_type, &private_key_handle); if (result != OEMCrypto_SUCCESS) { LOGE( @@ -380,7 +394,7 @@ static OEMCryptoResult RewrapDeviceDRMKeyOEMCert( /* Check that it's a valid DRM key. */ result = OPKI_LoadDRMKey(session_context, drm_key_type, wrapped_drm_key, - wrapped_drm_key_length, signature_size, kSign_RSASSA_PSS); + wrapped_drm_key_length, signature_size, allowed_schemes); if (result != OEMCrypto_SUCCESS) { LOGE("Failed to load DRM key with result: %u", result); } diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h b/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h index afdf953..1ee8255 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h @@ -34,7 +34,7 @@ // version bumps to v17.1, the first released OPK implementation would be // v17.1.0 #define API_MAJOR_VERSION 18 -#define API_MINOR_VERSION 7 +#define API_MINOR_VERSION 8 #define OPK_PATCH_VERSION 0 #endif /* OEMCRYPTO_TA_OEMCRYPTO_API_MACROS_H_ */ diff --git a/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_test_impl.gyp b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_test_impl.gyp index 26e4d8c..3659857 100644 --- a/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_test_impl.gyp +++ b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_test_impl.gyp @@ -13,6 +13,7 @@ # production use. 'wtpi_stub_dir': '<(oemcrypto_ta_dir)/wtpi_useless', 'use_provisioning_40%': 0, + 'use_random_device_key%': 0, }, 'target_defaults': { 'toolsets' : [ 'target' ], @@ -31,7 +32,6 @@ 'test-only/wtpi_persistent_storage.c', 'test-only/file_store_interface.c', 'test-only/wtpi_cas.c', - 'test-only/wtpi_device_key_access.c', '<(wtpi_stub_dir)/wtpi_root_of_trust_layer2.c', '<(wtpi_stub_dir)/wtpi_secure_buffer_access.c', '<(wtpi_stub_dir)/wtpi_fused.c', @@ -49,6 +49,11 @@ 'wtpi_device_renewal_layer2_test.c', ], }], + ['use_random_device_key', { + 'sources': ['<(wtpi_stub_dir)/wtpi_device_key_access.c',], + }, { + 'sources': ['test-only/wtpi_device_key_access.c',], + }], ], 'dependencies': [ '<(oemcrypto_ta_dir)/oemcrypto_ta.gyp:oemcrypto_ta_linux_tee', diff --git a/oemcrypto/opk/ports/trusty/ta/README.md b/oemcrypto/opk/ports/trusty/ta/README.md index 729ed76..68f6672 100644 --- a/oemcrypto/opk/ports/trusty/ta/README.md +++ b/oemcrypto/opk/ports/trusty/ta/README.md @@ -40,7 +40,7 @@ repo sync -c -j32 # Download an Android NDK prebuilt to compile liboemcrypto.so cd $TRUSTY_DIR/prebuilts mkdir ndk && cd ndk -git clone https://android.googlesource.com/toolchain/prebuilts/ndk/r25 +git clone https://android.googlesource.com/toolchain/prebuilts/ndk/r26 # Add the OEMCrypto TA path as a user module. The OEMCRYPTO_TA_DIR must expand # to a path that is relative to the Trusty directory diff --git a/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/build.sh b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/build.sh index fb9eca7..40e577d 100755 --- a/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/build.sh +++ b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/build.sh @@ -8,7 +8,7 @@ SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}") # Build liboemcrypto.so if [ ! -v ANDROID_NDK_ROOT ]; then - ANDROID_NDK_ROOT=$(realpath "$SCRIPT_DIR/../../../../../prebuilts/ndk/r25") + ANDROID_NDK_ROOT=$(realpath "$SCRIPT_DIR/../../../../../prebuilts/ndk/r26") fi "$ANDROID_NDK_ROOT/ndk-build" \ diff --git a/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/liboemcrypto-inc.mk b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/liboemcrypto-inc.mk index 0b1f6a3..8ac25ae 100644 --- a/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/liboemcrypto-inc.mk +++ b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/liboemcrypto-inc.mk @@ -28,7 +28,7 @@ LIBOEMCRYPTO_SO := $(LIBOEMCRYPTO_OUT_DIR)/lib/arm64-v8a/liboemcrypto.so $(LIBOEMCRYPTO_SO): LOCAL_DIR := $(GET_LOCAL_DIR) $(LIBOEMCRYPTO_SO): LIBOEMCRYPTO_BUILD_DIR := $(LIBOEMCRYPTO_BUILD_DIR) $(LIBOEMCRYPTO_SO): LIBOEMCRYPTO_OUT_DIR := $(LIBOEMCRYPTO_OUT_DIR) -$(LIBOEMCRYPTO_SO): NDK_ROOT := $(TRUSTY_TOP)/prebuilts/ndk/r25 +$(LIBOEMCRYPTO_SO): NDK_ROOT := $(TRUSTY_TOP)/prebuilts/ndk/r26 $(LIBOEMCRYPTO_SO): $(NOECHO)$(NDK_ROOT)/ndk-build \ -C $(LOCAL_DIR) \ diff --git a/oemcrypto/opk/ports/trusty/ta/reference/widevine_app.c b/oemcrypto/opk/ports/trusty/ta/reference/widevine_app.c index f388136..b44a9dc 100644 --- a/oemcrypto/opk/ports/trusty/ta/reference/widevine_app.c +++ b/oemcrypto/opk/ports/trusty/ta/reference/widevine_app.c @@ -185,12 +185,18 @@ static bool is_bound(struct widevine_ctx* ctx) { static void close_shared_memory(struct widevine_ctx* ctx) { TEE_SharedMemory_Bind(NULL, 0); if (ctx->shared_buffer_addr != NULL) { - munmap(ctx->shared_buffer_addr, ctx->shared_buffer_size); + int rc = munmap(ctx->shared_buffer_addr, ctx->shared_buffer_size); + if (rc != NO_ERROR) { + TLOGW("munmap() failed: %d\n", rc); + } ctx->shared_buffer_addr = NULL; ctx->shared_buffer_size = 0; } if (ctx->shared_message_addr != NULL) { - munmap(ctx->shared_message_addr, ctx->shared_message_size); + int rc = munmap(ctx->shared_message_addr, ctx->shared_message_size); + if (rc != NO_ERROR) { + TLOGW("munmap() failed: %d\n", rc); + } ctx->shared_message_addr = NULL; ctx->shared_message_size = 0; } @@ -310,7 +316,10 @@ static int dispatch_bind_message(handle_t chan, PROT_READ | PROT_WRITE, 0, handles[1], 0); if (shared_buffer_addr == MAP_FAILED) { TLOGE("Could not map shared buffer.\n"); - munmap(shared_message_addr, shared_message_size); + int rc = munmap(shared_message_addr, shared_message_size); + if (rc != NO_ERROR) { + TLOGW("munmap() failed: %d\n", rc); + } return -1; } diff --git a/oemcrypto/test/common.mk b/oemcrypto/test/common.mk index 8624ca0..481a207 100644 --- a/oemcrypto/test/common.mk +++ b/oemcrypto/test/common.mk @@ -22,6 +22,7 @@ LOCAL_SRC_FILES:= \ oemcrypto_generic_crypto_test.cpp \ oemcrypto_license_test.cpp \ oemcrypto_provisioning_test.cpp \ + oemcrypto_security_test.cpp \ oemcrypto_usage_table_test.cpp \ oemcrypto_test.cpp \ oemcrypto_test_android.cpp \ diff --git a/oemcrypto/test/extract_bcc_tool.cpp b/oemcrypto/test/extract_bcc_tool.cpp new file mode 100644 index 0000000..31305bf --- /dev/null +++ b/oemcrypto/test/extract_bcc_tool.cpp @@ -0,0 +1,177 @@ +// Copyright 2024 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// This tool extracts BCC by calling OEMCrypto APIs and generates a CSR file in +// JSON format, which can be handled by CE CDM wv_upload_tool.py. +#include +#include +#include +#include +#include +#include + +#include "OEMCryptoCENC.h" +#include "string_conversions.h" + +namespace { +// Make and Model for system ID resolution. +const std::string kDeviceMake = "widevine_test"; +const std::string kDeviceModel = "prov4"; + +// Informative fields. +const std::string kDeviceArchitecture = "x86_64"; +const std::string kDeviceName = "prov40 test client"; +const std::string kDeviceProduct = "prov40 test"; +const std::string kDeviceBuildInfo = "prov40 test build"; + +// == Utils == + +std::string StringMapToJson( + const std::map& string_map) { + std::string json = "{"; + for (const auto& value_pair : string_map) { + std::string escaped_value = + std::regex_replace(value_pair.second, std::regex("\""), "\\\""); + json.append("\"" + value_pair.first + "\": " + "\"" + escaped_value + + "\","); + } + json.resize(json.size() - 1); // Remove the last comma. + json.append("}"); + return json; +} + +// == Primary == + +bool GetBccAndBuildInfo(std::vector* bcc, + std::string* oemcrypto_build_info) { + // Step 1: Initialize. + OEMCryptoResult result = OEMCrypto_Initialize(); + if (result != OEMCrypto_SUCCESS) { + std::cerr << "Failed to initialize: result = " << result << std::endl; + return false; + } + + // Step 2: Get BCC. + const OEMCrypto_ProvisioningMethod method = OEMCrypto_GetProvisioningMethod(); + if (method != OEMCrypto_BootCertificateChain) { + std::cerr << "ProvisioningMethod is not BCC type: method = "; + std::cerr << method << std::endl; + OEMCrypto_Terminate(); + return false; + } + + bcc->resize(0); + size_t bcc_size = 0; + std::vector additional_signature; // It should be empty. + size_t additional_signature_size = 0; + result = OEMCrypto_GetBootCertificateChain(bcc->data(), &bcc_size, + additional_signature.data(), + &additional_signature_size); + if (additional_signature_size != 0) { + std::cerr << "The additional_signature_size required by OEMCrypto is " + << additional_signature_size + << ", while it is expected to be zero." << std::endl; + OEMCrypto_Terminate(); + return false; + } + if (result == OEMCrypto_ERROR_SHORT_BUFFER) { + bcc->resize(bcc_size); + additional_signature.resize(additional_signature_size); + result = OEMCrypto_GetBootCertificateChain(bcc->data(), &bcc_size, + additional_signature.data(), + &additional_signature_size); + } + if (result != OEMCrypto_SUCCESS) { + std::cerr << "Failed to get BCC: result = " << result << std::endl; + OEMCrypto_Terminate(); + return false; + } + bcc->resize(bcc_size); + + // Step 3: Get oemcrypto build info. + oemcrypto_build_info->resize(0); + std::vector build_info_buffer; + size_t oemcrypto_build_info_size = 0; + result = OEMCrypto_BuildInformation(build_info_buffer.data(), + &oemcrypto_build_info_size); + if (result == OEMCrypto_ERROR_SHORT_BUFFER) { + build_info_buffer.resize(oemcrypto_build_info_size); + result = OEMCrypto_BuildInformation(build_info_buffer.data(), + &oemcrypto_build_info_size); + } + if (result != OEMCrypto_SUCCESS) { + std::cerr << "Failed to get build information: result = " << result + << std::endl; + OEMCrypto_Terminate(); + return false; + } + build_info_buffer.resize(oemcrypto_build_info_size); + oemcrypto_build_info->assign(build_info_buffer.begin(), + build_info_buffer.end()); + oemcrypto_build_info->resize(oemcrypto_build_info_size); + + // Step 4: Cleanup. + result = OEMCrypto_Terminate(); + if (result != OEMCrypto_SUCCESS) { + std::cerr << "Failed to terminate: result = " << result << std::endl; + return false; + } + return true; +} + +bool GenerateBccRecord(const std::vector& bcc, + const std::string& oemcrypto_build_info, + std::string* bcc_record) { + std::map record; + record["company"] = kDeviceMake; + record["model"] = kDeviceModel; + + record["architecture"] = kDeviceArchitecture; + record["name"] = kDeviceName; + record["product"] = kDeviceProduct; + record["build_info"] = kDeviceBuildInfo; + record["bcc"] = wvutil::Base64Encode(bcc); + record["oemcrypto_build_info"] = oemcrypto_build_info; + + const std::string record_json = StringMapToJson(record); + bcc_record->assign(record_json.begin(), record_json.end()); + return true; +} + +bool OutputBccRecord(const std::string& path, const std::string& record) { + std::cout << "Writing BCC record to file " << path << std::endl; + std::cout << record << std::endl; + std::ofstream out(path); + if (out) out << record; + if (out.bad()) { + std::cerr << "Failed to write BCC record to file " << path << std::endl; + return false; + } + return true; +} +} // namespace + +int main(int argc, char** argv) { + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + const std::string bcc_path = argv[1]; + + std::vector bcc; + std::string oemcrypto_build_info; + if (!GetBccAndBuildInfo(&bcc, &oemcrypto_build_info)) { + std::cerr << "Failed to get BCC or OEMCrypto build info" << std::endl; + return 1; + } + std::string bcc_record; + if (!GenerateBccRecord(bcc, oemcrypto_build_info, &bcc_record)) { + std::cerr << "Failed to generate BCC record" << std::endl; + return 1; + } + if (!OutputBccRecord(bcc_path, bcc_record)) { + std::cerr << "Failed to output BCC record" << std::endl; + return 1; + } + return 0; +} diff --git a/oemcrypto/test/oec_decrypt_fallback_chain.cpp b/oemcrypto/test/oec_decrypt_fallback_chain.cpp index fe303fc..6cb7aac 100644 --- a/oemcrypto/test/oec_decrypt_fallback_chain.cpp +++ b/oemcrypto/test/oec_decrypt_fallback_chain.cpp @@ -17,6 +17,7 @@ void advance_dest_buffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) { switch (dest_buffer->type) { case OEMCrypto_BufferType_Clear: dest_buffer->buffer.clear.clear_buffer += bytes; + dest_buffer->buffer.clear.clear_buffer_length -= bytes; break; case OEMCrypto_BufferType_Secure: @@ -98,11 +99,6 @@ OEMCryptoResult DecryptFallbackChain::DecryptSample( const size_t length = subsample.num_bytes_clear + subsample.num_bytes_encrypted; fake_sample.buffers.input_data_length = length; - if (fake_sample.buffers.output_descriptor.type == - OEMCrypto_BufferType_Clear) { - fake_sample.buffers.output_descriptor.buffer.clear.clear_buffer_length = - length; - } fake_sample.subsamples = &subsample; fake_sample.subsamples_length = 1; @@ -148,11 +144,6 @@ OEMCryptoResult DecryptFallbackChain::DecryptSubsample( if (subsample.num_bytes_clear > 0) { fake_sample.buffers.input_data_length = subsample.num_bytes_clear; - if (fake_sample.buffers.output_descriptor.type == - OEMCrypto_BufferType_Clear) { - fake_sample.buffers.output_descriptor.buffer.clear.clear_buffer_length = - subsample.num_bytes_clear; - } fake_subsample.num_bytes_clear = subsample.num_bytes_clear; fake_subsample.num_bytes_encrypted = 0; fake_subsample.block_offset = 0; @@ -176,11 +167,6 @@ OEMCryptoResult DecryptFallbackChain::DecryptSubsample( if (subsample.num_bytes_encrypted > 0) { fake_sample.buffers.input_data_length = subsample.num_bytes_encrypted; - if (fake_sample.buffers.output_descriptor.type == - OEMCrypto_BufferType_Clear) { - fake_sample.buffers.output_descriptor.buffer.clear.clear_buffer_length = - subsample.num_bytes_encrypted; - } fake_subsample.num_bytes_clear = 0; fake_subsample.num_bytes_encrypted = subsample.num_bytes_encrypted; fake_subsample.block_offset = subsample.block_offset; diff --git a/oemcrypto/test/oemcrypto_basic_test.cpp b/oemcrypto/test/oemcrypto_basic_test.cpp index eae6766..d27c000 100644 --- a/oemcrypto/test/oemcrypto_basic_test.cpp +++ b/oemcrypto/test/oemcrypto_basic_test.cpp @@ -73,6 +73,76 @@ int32_t JsmnAncestorCount(const std::vector& tokens, } return count; } + +const char* BoolName(bool value) { return value ? "true" : "false"; } +const char* SecurityLevelName(OEMCrypto_Security_Level value) { + switch (value) { + case OEMCrypto_Level_Unknown: + return "OEMCrypto_Level_Unknown"; + case OEMCrypto_Level1: + return "OEMCrypto_Level1"; + case OEMCrypto_Level2: + return "OEMCrypto_Level2"; + case OEMCrypto_Level3: + return "OEMCrypto_Level3"; + } + // Not reachable unless the enum value is invalid + return ""; +} +const char* HDCPCapabilityName(OEMCrypto_HDCP_Capability value) { + switch (value) { + case HDCP_NONE: + return "HDCP_NONE"; + case HDCP_V1: + return "HDCP_V1"; + case HDCP_V1_0: + return "HDCP_V1_0"; + case HDCP_V1_1: + return "HDCP_V1_1"; + case HDCP_V1_2: + return "HDCP_V1_2"; + case HDCP_V1_3: + return "HDCP_V1_3"; + case HDCP_V1_4: + return "HDCP_V1_4"; + case HDCP_V2: + return "HDCP_V2"; + case HDCP_V2_1: + return "HDCP_V2_1"; + case HDCP_V2_2: + return "HDCP_V2_2"; + case HDCP_V2_3: + return "HDCP_V2_3"; + case HDCP_NO_DIGITAL_OUTPUT: + return "HDCP_NO_DIGITAL_OUTPUT"; + } + // Not reachable unless the enum value is invalid + return ""; +} +const char* WatermarkingSupportName(OEMCrypto_WatermarkingSupport value) { + switch (value) { + case OEMCrypto_WatermarkingError: + return "OEMCrypto_WatermarkingError"; + case OEMCrypto_WatermarkingNotSupported: + return "OEMCrypto_WatermarkingNotSupported"; + case OEMCrypto_WatermarkingConfigurable: + return "OEMCrypto_WatermarkingConfigurable"; + case OEMCrypto_WatermarkingAlwaysOn: + return "OEMCrypto_WatermarkingAlwaysOn"; + } + // Not reachable unless the enum value is invalid + return ""; +} +const char* DTCP2CapabiityName(OEMCrypto_DTCP2_Capability value) { + switch (value) { + case OEMCrypto_NO_DTCP2: + return "OEMCrypto_NO_DTCP2"; + case OEMCrypto_DTCP2_V1: + return "OEMCrypto_DTCP2_V1"; + } + // Not reachable unless the enum value is invalid + return ""; +} } // namespace void OEMCryptoClientTest::SetUp() { @@ -148,6 +218,11 @@ OEMCryptoResult OEMCryptoClientTest::CopyBuffer( dest_buffer_descriptor, subsample_flags); } +void OEMCryptoClientTest::RecordWvProperty(const std::string& key, + const std::string& value) { + RecordProperty("widevine_metadata_oec_" + key, value); +} + const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value) { switch (value) { case HDCP_NONE: @@ -174,9 +249,9 @@ const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value) { return "HDCP version 2.3"; case HDCP_NO_DIGITAL_OUTPUT: return "No HDCP device attached/using local display with secure path"; - default: - return ""; } + // Not reachable unless the enum value is invalid + return ""; } // Return a printable string from data. If all the characters are printable, @@ -218,7 +293,7 @@ TEST_F(OEMCryptoClientTest, FreeUnallocatedSecureBufferNoFailure) { */ TEST_F(OEMCryptoClientTest, VersionNumber) { const std::string log_message = - "OEMCrypto unit tests for API 18.7. Tests last updated 2024-09-04"; + "OEMCrypto unit tests for API 18.8. Tests last updated 2024-11-04"; cout << " " << log_message << "\n"; cout << " " << "These tests are part of Android U." @@ -227,30 +302,45 @@ TEST_F(OEMCryptoClientTest, VersionNumber) { // If any of the following fail, then it is time to update the log message // above. EXPECT_EQ(ODK_MAJOR_VERSION, 18); - EXPECT_EQ(ODK_MINOR_VERSION, 7); + EXPECT_EQ(ODK_MINOR_VERSION, 8); EXPECT_EQ(kCurrentAPI, static_cast(ODK_MAJOR_VERSION)); + RecordWvProperty("test_major_version", std::to_string(ODK_MAJOR_VERSION)); + RecordWvProperty("test_minor_version", std::to_string(ODK_MINOR_VERSION)); + OEMCrypto_Security_Level level = OEMCrypto_SecurityLevel(); EXPECT_GT(level, OEMCrypto_Level_Unknown); EXPECT_LE(level, OEMCrypto_Level3); cout << " OEMCrypto Security Level is L" << level << endl; + RecordWvProperty("security_level", SecurityLevelName(level)); + uint32_t version = OEMCrypto_APIVersion(); uint32_t minor_version = OEMCrypto_MinorAPIVersion(); cout << " OEMCrypto API version is " << version << "." << minor_version << endl; - if (OEMCrypto_SupportsUsageTable()) { + RecordWvProperty("major_version", std::to_string(version)); + RecordWvProperty("minor_version", std::to_string(minor_version)); + + const bool supports_usage_tables = OEMCrypto_SupportsUsageTable(); + if (supports_usage_tables) { cout << " OEMCrypto supports usage tables" << endl; } else { cout << " OEMCrypto does not support usage tables" << endl; } + RecordWvProperty("supports_usage_tables", BoolName(supports_usage_tables)); + if (version >= 15) { const uint32_t tier = OEMCrypto_ResourceRatingTier(); cout << " Resource Rating Tier: " << tier << endl; + RecordWvProperty("resource_rating_tier", std::to_string(tier)); } + if (version >= 17) { OEMCryptoResult sts = OEMCrypto_ProductionReady(); if (sts != OEMCrypto_SUCCESS) { LOGW("Device is not production ready, returns %d", sts); } + RecordWvProperty("is_production_ready", BoolName(sts == OEMCrypto_SUCCESS)); + std::string build_info; size_t buf_length = 0; sts = OEMCrypto_BuildInformation(&build_info[0], &buf_length); @@ -262,6 +352,7 @@ TEST_F(OEMCryptoClientTest, VersionNumber) { if (build_info.size() != buf_length) { build_info.resize(buf_length); } + RecordWvProperty("build_information", build_info); const std::string comma = ","; const std::string pretty_comma = ",\n "; std::string::size_type pos = 0; @@ -270,9 +361,12 @@ TEST_F(OEMCryptoClientTest, VersionNumber) { pos += pretty_comma.size(); } cout << " BuildInformation: " << build_info << endl; + OEMCrypto_WatermarkingSupport support = OEMCrypto_GetWatermarkingSupport(); cout << " WatermarkingSupport: " << support << endl; + RecordWvProperty("watermarking_support", WatermarkingSupportName(support)); } + ASSERT_GE(version, 8u); ASSERT_LE(version, kCurrentAPI); } @@ -292,8 +386,9 @@ TEST_F(OEMCryptoClientTest, ResourceRatingAPI15) { TEST_F(OEMCryptoClientTest, ProvisioningDeclaredAPI12) { OEMCrypto_ProvisioningMethod provisioning_method = OEMCrypto_GetProvisioningMethod(); - cout << " Provisioning method = " - << ProvisioningMethodName(provisioning_method) << endl; + const char* const name = ProvisioningMethodName(provisioning_method); + cout << " Provisioning method = " << name << endl; + RecordWvProperty("provisioning_method", name); ASSERT_NE(OEMCrypto_ProvisioningError, provisioning_method); } @@ -306,6 +401,8 @@ TEST_F(OEMCryptoClientTest, CheckHDCPCapabilityAPI09) { static_cast(current), HDCPCapabilityAsString(current)); printf(" Maximum HDCP Capability: 0x%02x = %s.\n", static_cast(maximum), HDCPCapabilityAsString(maximum)); + RecordWvProperty("hdcp_current", HDCPCapabilityName(current)); + RecordWvProperty("hdcp_max", HDCPCapabilityName(maximum)); } TEST_F(OEMCryptoClientTest, CheckSRMCapabilityV13) { @@ -314,11 +411,15 @@ TEST_F(OEMCryptoClientTest, CheckSRMCapabilityV13) { OEMCryptoResult current_result = OEMCrypto_GetCurrentSRMVersion(&version); if (current_result == OEMCrypto_SUCCESS) { printf(" Current SRM Version: %d.\n", version); + RecordWvProperty("srm_supported", BoolName(true)); + RecordWvProperty("srm_version", std::to_string(version)); EXPECT_NE(OEMCrypto_SUCCESS, OEMCrypto_GetCurrentSRMVersion(nullptr)); } else if (current_result == OEMCrypto_LOCAL_DISPLAY_ONLY) { printf(" Current SRM Status: Local Display Only.\n"); + RecordWvProperty("srm_supported", BoolName(false)); } else { EXPECT_EQ(OEMCrypto_ERROR_NOT_IMPLEMENTED, current_result); + RecordWvProperty("srm_supported", BoolName(false)); } } @@ -547,6 +648,9 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) { {"is_debug", JSMN_PRIMITIVE}, }; + // The prefix of every field name when logged to RecordWvProperty. + const std::string kBuildInfoRecordPrefix = "build_info_"; + // A set of the required fields found when examining the // build information, use to verify all fields are present. std::set found_required_fields; @@ -573,11 +677,17 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) { << "Unexpected required field type: field = " << key << ", build_info = " << build_info; found_required_fields.insert(key); + RecordWvProperty(kBuildInfoRecordPrefix + key, + build_info.substr(value_token.start, + value_token.end - value_token.start)); } else if (kOptionalFields.find(key) != kOptionalFields.end()) { ASSERT_EQ(value_token.type, kOptionalFields.at(key)) << "Unexpected optional field type: field = " << key << ", build_info = " << build_info; - } // Do not validate vendor fields. + RecordWvProperty(kBuildInfoRecordPrefix + key, + build_info.substr(value_token.start, + value_token.end - value_token.start)); + } // Do not validate or record vendor fields. if (key == kSpecialCaseReeKey) { // Store the tokens of the "ree" field for additional validation. @@ -618,6 +728,11 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) { // If no "ree" field tokens, then end here. if (!has_ree_info) return; // Step 4a: Verify "ree" object scheme. + + // The prefix of every REE field name when logged to RecordWvProperty. + const std::string kReeBuildInfoRecordPrefix = + kBuildInfoRecordPrefix + kSpecialCaseReeKey + "_"; + ASSERT_FALSE(ree_tokens.empty()) << "REE field was specified, but contents were empty: build_info = " << build_info; @@ -647,7 +762,10 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) { << "Unexpected optional REE field type: ree_field = " << key << ", build_info = " << build_info; found_required_fields.insert(key); - } // Do not validate vendor fields. + RecordWvProperty(kReeBuildInfoRecordPrefix + key, + build_info.substr(value_token.start, + value_token.end - value_token.start)); + } // Do not validate or record vendor fields. // Skip potential nested tokens. i += JsmnAncestorCount(ree_tokens, i + 1); @@ -683,6 +801,7 @@ TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) { OEMCryptoResult sts = OEMCrypto_GetMaxNumberOfSessions(&maximum); ASSERT_EQ(OEMCrypto_SUCCESS, sts); printf(" Max Number of Sessions: %zu.\n", maximum); + RecordWvProperty("max_number_of_sessions", std::to_string(maximum)); size_t required_max = GetResourceValue(kMaxConcurrentSession); ASSERT_GE(maximum, required_max); } @@ -690,6 +809,7 @@ TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) { TEST_F(OEMCryptoClientTest, CheckUsageTableSizeAPI16) { const size_t maximum = OEMCrypto_MaximumUsageTableHeaderSize(); printf(" Max Usage Table Size: %zu.\n", maximum); + RecordWvProperty("max_usage_table_size", std::to_string(maximum)); // A maximum of 0 means the table is constrained by dynamic memory allocation. if (maximum > 0) { ASSERT_GE(maximum, RequiredUsageSize()); @@ -723,6 +843,7 @@ TEST_F(OEMCryptoClientTest, CheckDTCP2CapabilityAPI17) { "DTCP2 is supported.\n"); break; } + RecordWvProperty("dtcp2_capability", DTCP2CapabiityName(capability)); } // diff --git a/oemcrypto/test/oemcrypto_basic_test.h b/oemcrypto/test/oemcrypto_basic_test.h index 2cbe235..303ee4a 100644 --- a/oemcrypto/test/oemcrypto_basic_test.h +++ b/oemcrypto/test/oemcrypto_basic_test.h @@ -35,6 +35,7 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil { size_t input_buffer_size, const OEMCrypto_DestBufferDesc* dest_buffer_descriptor, uint8_t subsample_flags); + void RecordWvProperty(const std::string& key, const std::string& value); }; } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_cast_test.cpp b/oemcrypto/test/oemcrypto_cast_test.cpp index 9173025..9c19447 100644 --- a/oemcrypto/test/oemcrypto_cast_test.cpp +++ b/oemcrypto/test/oemcrypto_cast_test.cpp @@ -5,12 +5,13 @@ #include "oemcrypto_cast_test.h" -#include "oemcrypto_usage_table_test.h" - using ::testing::Range; namespace wvoec { +/// @addtogroup cast +/// @{ + /** If a device can load a private key with the alternate padding schemes, it * should support signing with the alternate scheme. */ TEST_F(OEMCryptoLoadsCertificateAlternates, TestSignaturePKCS1) { @@ -262,18 +263,8 @@ class OEMCryptoCastReceiverTest : public OEMCryptoLoadsCertificateAlternates { ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_)); - // The application will compute the SHA-1 Hash of the message, so this - // test must do that also. - uint8_t hash[SHA_DIGEST_LENGTH]; - if (!SHA1(message.data(), message.size(), hash)) { - dump_boringssl_error(); - FAIL() << "boringssl error creating SHA1 hash."; - } - - // The application will prepend the digest info to the hash. - // SHA-1 digest info prefix = 0x30 0x21 0x30 ... - vector digest = wvutil::a2b_hex("3021300906052b0e03021a05000414"); - digest.insert(digest.end(), hash, hash + SHA_DIGEST_LENGTH); + vector digest; + ASSERT_NO_FATAL_FAILURE(PrepareCastDigestedMessage(message, digest)); // OEMCrypto will apply the padding, and encrypt to generate the // signature. @@ -1018,4 +1009,6 @@ TEST_P(OEMCryptoSessionTestLoadCasKeysWithHDCP, CasOnlyLoadCasKeysAPI17) { } INSTANTIATE_TEST_SUITE_P(TestHDCP, OEMCryptoSessionTestLoadCasKeysWithHDCP, Range(1, 6)); + +/// @} } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_cast_test.h b/oemcrypto/test/oemcrypto_cast_test.h index 283df69..c308e2d 100644 --- a/oemcrypto/test/oemcrypto_cast_test.h +++ b/oemcrypto/test/oemcrypto_cast_test.h @@ -14,6 +14,7 @@ #include "OEMCryptoCENC.h" #include "oemcrypto_provisioning_test.h" #include "oemcrypto_session_tests_helper.h" +#include "oemcrypto_usage_table_test.h" namespace wvoec { @@ -25,6 +26,25 @@ std::string MaybeHex(const std::vector& data); // This test attempts to use alternate algorithms for loaded device certs. class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { protected: + // The message to be signed by OEMCrypto_GenerateRSASignature() starts with a + // constant digest info prefix followed by a SHA-1 hash of the message. + void PrepareCastDigestedMessage(const std::vector& message, + std::vector& digest) { + // The application will compute the SHA-1 Hash of the message, so this + // test must do that also. + uint8_t hash[SHA_DIGEST_LENGTH]; + if (!SHA1(message.data(), message.size(), hash)) { + dump_boringssl_error(); + FAIL() << "boringssl error creating SHA1 hash."; + } + // The application will prepend the digest info to the hash. + // SHA-1 digest info prefix = 0x30 0x21 0x30 ... + static const std::vector prefix = + wvutil::a2b_hex("3021300906052b0e03021a05000414"); + digest.insert(digest.end(), prefix.begin(), prefix.end()); + digest.insert(digest.end(), hash, hash + SHA_DIGEST_LENGTH); + } + void TestSignature(RSA_Padding_Scheme scheme, size_t size) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); @@ -32,16 +52,19 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { vector licenseRequest(size); GetRandBytes(licenseRequest.data(), licenseRequest.size()); + vector digested_message; + ASSERT_NO_FATAL_FAILURE( + PrepareCastDigestedMessage(licenseRequest, digested_message)); size_t signature_length = 0; OEMCryptoResult sts = OEMCrypto_GenerateRSASignature( - s.session_id(), licenseRequest.data(), licenseRequest.size(), nullptr, - &signature_length, scheme); + s.session_id(), digested_message.data(), digested_message.size(), + nullptr, &signature_length, scheme); ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); ASSERT_NE(static_cast(0), signature_length); std::vector signature(signature_length, 0); sts = OEMCrypto_GenerateRSASignature( - s.session_id(), licenseRequest.data(), licenseRequest.size(), + s.session_id(), digested_message.data(), digested_message.size(), signature.data(), &signature_length, scheme); ASSERT_EQ(OEMCrypto_SUCCESS, sts) @@ -51,7 +74,7 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo( encoded_rsa_key_.data(), encoded_rsa_key_.size())); ASSERT_NO_FATAL_FAILURE(s.VerifyRsaSignature( - licenseRequest, signature.data(), signature_length, scheme)); + digested_message, signature.data(), signature_length, scheme)); } void DisallowDeriveKeys() { diff --git a/oemcrypto/test/oemcrypto_decrypt_test.cpp b/oemcrypto/test/oemcrypto_decrypt_test.cpp index 63e598a..78d26bb 100644 --- a/oemcrypto/test/oemcrypto_decrypt_test.cpp +++ b/oemcrypto/test/oemcrypto_decrypt_test.cpp @@ -13,6 +13,9 @@ using ::testing::Values; namespace wvoec { +/// @addtogroup decrypt +/// @{ + // Cannot decrypt without first getting a key handle. TEST_P(OEMCryptoLicenseTest, FailDecryptWithoutGettingAHandle) { ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); @@ -661,4 +664,5 @@ TEST_P(OEMCryptoLicenseTest, KeyDuration) { INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoLicenseTest, Range(kCurrentAPI - 2, kCurrentAPI + 1)); +/// @} } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_generic_crypto_test.cpp b/oemcrypto/test/oemcrypto_generic_crypto_test.cpp index 867b4f8..e98dd7a 100644 --- a/oemcrypto/test/oemcrypto_generic_crypto_test.cpp +++ b/oemcrypto/test/oemcrypto_generic_crypto_test.cpp @@ -11,6 +11,9 @@ using ::testing::Range; namespace wvoec { +/// @addtogroup generic +/// @{ + TEST_P(OEMCryptoGenericCryptoTest, GenericKeyLoad) { EncryptAndLoadKeys(); } // Test that the Generic_Encrypt function works correctly. @@ -574,4 +577,4 @@ INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoGenericCryptoKeyIdLengthTest, Range(kCoreMessagesAPI, kCurrentAPI + 1)); /// @} -} // namespace wvoec \ No newline at end of file +} // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_license_test.cpp b/oemcrypto/test/oemcrypto_license_test.cpp index 93065b2..8228bb5 100644 --- a/oemcrypto/test/oemcrypto_license_test.cpp +++ b/oemcrypto/test/oemcrypto_license_test.cpp @@ -5,6 +5,8 @@ #include "oemcrypto_license_test.h" +#include + #include "platform.h" #include "test_sleep.h" @@ -12,6 +14,9 @@ using ::testing::Range; namespace wvoec { +/// @addtogroup license +/// @{ + // Function to test APIs that expect a buffer length as input // by passing huge buffer lengths up to end_buffer_length and test that the API // doesn't crash. @@ -758,6 +763,7 @@ TEST_P(OEMCryptoLicenseTest, MaxTotalKeysManySessions) { TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) { uint8_t patch_level = OEMCrypto_Security_Patch_Level(); printf(" Current Patch Level: %u.\n", patch_level); + RecordWvProperty("security_patch_level", std::to_string(patch_level)); { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); diff --git a/oemcrypto/test/oemcrypto_provisioning_test.cpp b/oemcrypto/test/oemcrypto_provisioning_test.cpp index db5e9bd..8f1087c 100644 --- a/oemcrypto/test/oemcrypto_provisioning_test.cpp +++ b/oemcrypto/test/oemcrypto_provisioning_test.cpp @@ -5,6 +5,10 @@ #include "oemcrypto_provisioning_test.h" +#include + +#include + #include "log.h" #include "oec_device_features.h" #include "platform.h" @@ -12,6 +16,9 @@ namespace wvoec { +/// @addtogroup provision +/// @{ + // This test is used to print the device ID to stdout. TEST_F(OEMCryptoKeyboxTest, NormalGetDeviceId) { OEMCryptoResult sts; @@ -21,6 +28,7 @@ TEST_F(OEMCryptoKeyboxTest, NormalGetDeviceId) { ASSERT_EQ(OEMCrypto_SUCCESS, sts); cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id, dev_id_len) << " len = " << dev_id_len << endl; + RecordWvProperty("device_id", wvutil::HexEncode(dev_id, dev_id_len)); } TEST_F(OEMCryptoKeyboxTest, GetDeviceIdShortBuffer) { @@ -50,8 +58,12 @@ TEST_F(OEMCryptoKeyboxTest, NormalGetKeyData) { sts = OEMCrypto_GetKeyData(key_data, &key_data_len); uint32_t* data = reinterpret_cast(key_data); + const uint32_t system_id = htonl(data[1]); + const uint32_t version = htonl(data[0]); printf(" NormalGetKeyData: system_id = %u = 0x%04X, version=%u\n", - htonl(data[1]), htonl(data[1]), htonl(data[0])); + system_id, system_id, version); + RecordWvProperty("system_id", std::to_string(system_id)); + RecordWvProperty("key_data_version", std::to_string(version)); ASSERT_EQ(OEMCrypto_SUCCESS, sts); } @@ -106,6 +118,8 @@ TEST_F(OEMCryptoProv30Test, GetDeviceId) { dev_id.resize(dev_id_len); cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id) << " len = " << dev_id_len << endl; + RecordWvProperty("device_id", + wvutil::HexEncode(dev_id.data(), dev_id.size())); } // The OEM certificate must be valid. @@ -545,13 +559,13 @@ TEST_F(OEMCryptoProv40Test, InstallOemPrivateKeyCanBeUsed) { wrapped_private_key2.resize(wrapped_private_key_size2); // Verify public_key_signature2 with public_key1. - if (key_type2 == OEMCrypto_PrivateKeyType::OEMCrypto_RSA_Private_Key) { + if (key_type1 == OEMCrypto_PrivateKeyType::OEMCrypto_RSA_Private_Key) { ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromSubjectPublicKey( public_key1.data(), public_key1.size())); ASSERT_NO_FATAL_FAILURE( s.VerifyRsaSignature(public_key2, public_key_signature2.data(), public_key_signature2.size(), kSign_RSASSA_PSS)); - } else if (key_type2 == OEMCrypto_PrivateKeyType::OEMCrypto_ECC_Private_Key) { + } else if (key_type1 == OEMCrypto_PrivateKeyType::OEMCrypto_ECC_Private_Key) { ASSERT_NO_FATAL_FAILURE(s.SetEccPublicKeyFromSubjectPublicKey( public_key1.data(), public_key1.size())); ASSERT_NO_FATAL_FAILURE(s.VerifyEccSignature(public_key2, @@ -619,6 +633,8 @@ TEST_F(OEMCryptoProv40Test, GetDeviceId) { dev_id.resize(dev_id_len); cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id) << " len = " << dev_id_len << endl; + RecordWvProperty("device_id", + wvutil::HexEncode(dev_id.data(), dev_id.size())); // Device id should be stable. Query again. std::vector dev_id2(dev_id_len); sts = OEMCrypto_GetDeviceID(dev_id2.data(), &dev_id_len); @@ -1310,4 +1326,5 @@ TEST_F(OEMCryptoUsesCertificate, GenerateDerivedKeysLargeBuffer) { enc_context.data(), enc_context.size())); } +/// @} } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_security_test.cpp b/oemcrypto/test/oemcrypto_security_test.cpp index 72390ee..192a583 100644 --- a/oemcrypto/test/oemcrypto_security_test.cpp +++ b/oemcrypto/test/oemcrypto_security_test.cpp @@ -23,14 +23,14 @@ #include #include -// TODO(b/253779846) Change it to include a header instead -#include "oemcrypto_test.cpp" +#include "oemcrypto_basic_test.h" +#include "oemcrypto_cast_test.h" +#include "oemcrypto_decrypt_test.h" +#include "oemcrypto_license_test.h" +#include "oemcrypto_provisioning_test.h" +#include "oemcrypto_usage_table_test.h" -using ::testing::Bool; -using ::testing::Combine; using ::testing::Range; -using ::testing::tuple; -using ::testing::Values; using ::testing::WithParamInterface; using namespace std; @@ -39,6 +39,136 @@ namespace wvoec { /// @addtogroup security /// @{ +class OEMCryptoLicenseOverflowTest : public OEMCryptoSessionTests, + public WithParamInterface { + public: + OEMCryptoLicenseOverflowTest() : license_api_version_(kCurrentAPI) {} + + void SetUp() override { + OEMCryptoSessionTests::SetUp(); + license_api_version_ = GetParam(); + } + + void TearDown() override { OEMCryptoSessionTests::TearDown(); } + + 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); + license_messages.set_api_version(license_api_version_); + s.open(); + InstallTestDrmKey(&s); + 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); + license_messages.set_api_version(license_api_version_); + s.open(); + InstallTestDrmKey(&s); + 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); + } + + protected: + uint32_t license_api_version_; +}; + +// 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(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(); + uint32_t key_session_id = 0; + OEMCryptoResult sts = OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id); + if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) { + return; + } + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + entitled_message_.SetEntitledKeySession(key_session_id); + } + + void TearDown() override { OEMCryptoLicenseTestAPI16::TearDown(); } + + protected: + EntitledMessage entitled_message_; + size_t entitlement_response_length_; + + void TestLoadEntitledKeysForHugeBufferLengths( + 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); + } +}; + /** Test that OEMCrypto_FreeSecureBuffer fails gracefully on a huge buffer. */ TEST_F(OEMCryptoClientTest, @@ -102,7 +232,7 @@ TEST_F(OEMCryptoClientTest, TEST_F(OEMCryptoClientTest, OEMCryptoMemoryWrapKeyboxOrOEMCertForHugeTransportKey) { auto oemcrypto_function = [](size_t transport_key_length) { - size_t wrapped_keybox_length = sizeof(&kTestKeybox) + 50; + 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( @@ -359,7 +489,7 @@ TEST_F(OEMCryptoKeyboxTest, * buffer. */ TEST_F(OEMCryptoProv30Test, OEMCryptoMemoryGetOEMPublicCertForHugeCertLength) { - if (wrapped_rsa_key_.size() == 0) { + if (wrapped_drm_key_.size() == 0) { // If we don't have a wrapped key yet, create one. // This wrapped key will be shared by all sessions in the test. ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey()); @@ -367,7 +497,7 @@ TEST_F(OEMCryptoProv30Test, OEMCryptoMemoryGetOEMPublicCertForHugeCertLength) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); // Install the DRM Cert's RSA key. - ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_rsa_key_)); + ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_)); ASSERT_NO_FATAL_FAILURE(s.SetTestRsaPublicKey()); auto oemcrypto_function = [](size_t input_length) { @@ -612,11 +742,8 @@ TEST_F(OEMCryptoMemoryLicenseTest, 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); + std::vector subsample_sizes(number_of_subsamples, {1, 1}); + SetSubsampleSizes(std::move(subsample_sizes)); LoadLicense(); MakeBuffers(); EncryptData(); @@ -640,13 +767,10 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, 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); + std::vector subsample_sizes(1, {1, 1}); + std::vector> sample_sizes(number_of_samples, + subsample_sizes); + SetSampleSizes(std::move(sample_sizes)); LoadLicense(); MakeBuffers(); EncryptData(); @@ -692,13 +816,13 @@ TEST_F(OEMCryptoLoadsCertificate, 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); + std::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(), - signature.data(), signature_size, wrapped_rsa_key.data(), + signature.data(), signature_size, wrapped_private_key.data(), &wrapped_private_key_length); s.close(); return result; @@ -750,21 +874,21 @@ TEST_F(OEMCryptoLoadsCertificate, GTEST_SKIP() << "Test for non Prov 4.0 devices only."; } ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey()); - auto oemcrypto_function = [&](size_t wrapped_rsa_key_length) { + auto oemcrypto_function = [&](size_t wrapped_drm_key_length) { Session s; s.open(); - vector wrapped_rsa_key_buffer = wrapped_rsa_key_; - wrapped_rsa_key_buffer.resize(wrapped_rsa_key_length); + vector wrapped_drm_key_buffer = wrapped_drm_key_; + wrapped_drm_key_buffer.resize(wrapped_drm_key_length); OEMCryptoResult result = OEMCrypto_LoadDRMPrivateKey( s.session_id(), OEMCrypto_RSA_Private_Key, - wrapped_rsa_key_buffer.data(), wrapped_rsa_key_buffer.size()); + wrapped_drm_key_buffer.data(), wrapped_drm_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(), + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, wrapped_drm_key_.size(), kHugeInputBufferLength, !kCheckStatus); } @@ -780,13 +904,13 @@ TEST_F( GTEST_SKIP() << "Test for non Prov 4.0 devices only."; } ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey()); - auto oemcrypto_function = [&](size_t wrapped_rsa_key_length) { + auto oemcrypto_function = [&](size_t wrapped_drm_key_length) { Session s; s.open(); - vector wrapped_rsa_key_buffer(wrapped_rsa_key_length); + vector wrapped_drm_key_buffer(wrapped_drm_key_length); OEMCryptoResult result = OEMCrypto_LoadDRMPrivateKey( s.session_id(), OEMCrypto_RSA_Private_Key, - wrapped_rsa_key_buffer.data(), wrapped_rsa_key_buffer.size()); + wrapped_drm_key_buffer.data(), wrapped_drm_key_buffer.size()); s.close(); return result; }; @@ -796,6 +920,318 @@ TEST_F( TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); } +/** Test that LoadProvisioning fails gracefully on huge buffer. */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeResponseLength) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_message_size(message_size); + }, + !kCheckStatus, !kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadProvisioning fails gracefully on huge buffer. */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageLength) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_core_message_size(message_size); + }, + !kCheckStatus, !kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadProvisioning fails gracefully on huge buffer. */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyLength) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForHugeBufferLengths( + [](size_t length, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().enc_private_key.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadProvisioning fails gracefully on huge buffer. */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyOffset) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForHugeBufferLengths( + [](size_t offset, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().enc_private_key.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyLength) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + 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 that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyOffset) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + 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 that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyIvLength) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForHugeBufferLengths( + [](size_t length, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().enc_private_key_iv.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyIvOffset) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForHugeBufferLengths( + [](size_t offset, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().enc_private_key_iv.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyIvLengthAPI16) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + 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 that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyIvOffset) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + 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 that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncMessageKeyLength) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForHugeBufferLengths( + [](size_t length, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().encrypted_message_key.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncMessageKeyOffset) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForHugeBufferLengths( + [](size_t offset, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().encrypted_message_key.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncMessageKeyLengthProv30) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + if (global_features.provisioning_method != OEMCrypto_OEMCertificate) { + GTEST_SKIP() << "Test for Prov 3.0 devices only."; + } + 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 that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncMessageKeyOffsetProv30) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + if (global_features.provisioning_method != OEMCrypto_OEMCertificate) { + GTEST_SKIP() << "Test for Prov 3.0 devices only."; + } + 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 that OEMCrypto_PrepAndSignProvisioningRequest fails gracefully on a + * huge buffer. + */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryPrepareProvisioningRequestForHugeRequestMessageLength) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestPrepareProvisioningRequestForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_message_size(message_size); + }, + kCheckStatus); +} + +/** Test that OEMCrypto_PrepAndSignProvisioningRequest fails gracefully on a + * huge buffer. + */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryPrepareProvisioningRequestForHugeSignatureLength) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestPrepareProvisioningRequestForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_request_signature_size(message_size); + }, + !kCheckStatus); +} + +/** Test that OEMCrypto_PrepAndSignProvisioningRequest fails gracefully on a + * huge buffer. + */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryPrepareProvisioningRequestForHugeCoreMessageLength) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestPrepareProvisioningRequestForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_core_message_size(message_size); + }, + kCheckStatus); +} + /** Test that OEMCrypto_LoadDRMPrivateKey fails gracefully on a huge buffer. */ TEST_F(OEMCryptoUsesCertificate, @@ -883,7 +1319,7 @@ TEST_F(OEMCryptoLoadsCertificateAlternates, // If the key did load, then it should be processed correctly. Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_rsa_key_)); + ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_)); vector message_buffer(10); size_t signature_length = 0; @@ -925,7 +1361,7 @@ TEST_F(OEMCryptoLoadsCertificateAlternates, // If the key did load, then it should be processed correctly. Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_rsa_key_)); + ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_)); vector message_buffer(50); vector signature; @@ -966,9 +1402,7 @@ TEST_P(OEMCryptoGenericCryptoTest, session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CENC, key_handle)); - OEMCrypto_SESSION session_id = session_.session_id(); - auto& iv = iv_; - auto oemcrypto_function = [&session_id, &iv](size_t buffer_length) mutable { + auto oemcrypto_function = [&key_handle, &iv = iv_](size_t buffer_length) { vector buffer(buffer_length); return OEMCrypto_Generic_Encrypt( key_handle.data(), key_handle.size(), buffer.data(), buffer.size(), iv, @@ -988,9 +1422,7 @@ TEST_P(OEMCryptoGenericCryptoTest, session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CENC, key_handle); - OEMCrypto_SESSION session_id = session_.session_id(); - auto iv = iv_; - auto oemcrypto_function = [&session_id, &iv](size_t buffer_length) { + auto oemcrypto_function = [&key_handle, &iv = iv_](size_t buffer_length) { vector encrypted(buffer_length); vector resultant(encrypted.size()); @@ -1014,12 +1446,10 @@ TEST_P(OEMCryptoGenericCryptoTest, OEMCryptoMemoryGenericKeySignForHugeBuffer) { GetKeyHandleIntoVector(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC), - key_handle); + OEMCrypto_CipherMode_CENC, key_handle)); vector signature(SHA256_DIGEST_LENGTH); size_t signature_length = signature.size(); - OEMCrypto_SESSION session_id = session_.session_id(); - auto oemcrypto_function = [&session_id, &signature, + auto oemcrypto_function = [&key_handle, &signature, &signature_length](size_t buffer_length) { vector buffer(buffer_length); return OEMCrypto_Generic_Sign( @@ -1040,19 +1470,16 @@ TEST_P(OEMCryptoGenericCryptoTest, GetKeyHandleIntoVector(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC), - key_handle); - 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(key_handle.data(), key_handle.size(), - clear_buffer.data(), clear_buffer.size(), - OEMCrypto_HMAC_SHA256, signature.data(), - &gen_signature_length); - }; + OEMCrypto_CipherMode_CENC, key_handle)); + auto oemcrypto_function = + [&key_handle, &clear_buffer = clear_buffer_](size_t signature_length) { + vector signature(signature_length); + size_t gen_signature_length = signature_length; + return OEMCrypto_Generic_Sign(key_handle.data(), key_handle.size(), + clear_buffer.data(), clear_buffer.size(), + OEMCrypto_HMAC_SHA256, signature.data(), + &gen_signature_length); + }; TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); } @@ -1094,9 +1521,7 @@ TEST_P(OEMCryptoGenericCryptoTest, session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CENC, key_handle)); - OEMCrypto_SESSION session_id = session_.session_id(); - auto clear_buffer = clear_buffer_; - auto oemcrypto_function = [&session_id, &clear_buffer, + auto oemcrypto_function = [&key_handle, &clear_buffer = clear_buffer_, &signature](size_t signature_length) { return OEMCrypto_Generic_Verify(key_handle.data(), key_handle.size(), clear_buffer.data(), clear_buffer.size(), @@ -1341,6 +1766,632 @@ TEST_P(OEMCryptoUsageTableTest, }; TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); } -/// @} +/** Test that LoadEntitledContentKeys fails gracefully on huge buffer. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyIdLength) { + TestLoadEntitledKeysForHugeBufferLengths( + [](size_t key_id_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_id.length = + key_id_length; + }, + !kCheckStatus); +} + +/** Test that LoadEntitledContentKeys fails gracefully on huge buffer. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyIdOffset) { + TestLoadEntitledKeysForHugeBufferLengths( + [](size_t key_id_offset, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_id.offset = + key_id_offset; + }, + !kCheckStatus); +} + +/** Test that LoadEntitledContentKeys fails gracefully on huge buffer. */ +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyIdLength) { + 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 LoadEntitledContentKeys rejects out of range substring. */ +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyIdOffset) { + 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 that LoadEntitledContentKeys fails gracefully on huge substring. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringEntitlementKeyIdLength) { + TestLoadEntitledKeysForHugeBufferLengths( + [](size_t key_id_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].entitlement_key_id.length = + key_id_length; + }, + !kCheckStatus); +} + +/** Test LoadEntitledContentKeys rejects out of range substring. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringEntitlementKeyIdOffset) { + TestLoadEntitledKeysForHugeBufferLengths( + [](size_t key_id_offset, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].entitlement_key_id.offset = + key_id_offset; + }, + !kCheckStatus); +} + +/** Test LoadEntitledContentKeys rejects out of range substring. */ +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringEntitlementKeyIdLength) { + 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 LoadEntitledContentKeys rejects out of range substring. */ +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringEntitlementKeyIdOffset) { + 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 LoadEntitledContentKeys rejects out of range substring. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataIvLength) { + TestLoadEntitledKeysForHugeBufferLengths( + [](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 LoadEntitledContentKeys rejects out of range substring. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataIvOffset) { + TestLoadEntitledKeysForHugeBufferLengths( + [](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 LoadEntitledContentKeys rejects out of range substring. */ +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataIvLength) { + 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 LoadEntitledContentKeys rejects out of range substring. */ +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataIvOffset) { + 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 LoadEntitledContentKeys rejects out of range substring. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataLength) { + TestLoadEntitledKeysForHugeBufferLengths( + [](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 LoadEntitledContentKeys rejects out of range substring. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataOffset) { + TestLoadEntitledKeysForHugeBufferLengths( + [](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 LoadEntitledContentKeys rejects out of range substring. */ +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataLength) { + 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 LoadEntitledContentKeys rejects out of range substring. */ +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataOffset) { + 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 LoadEntitledContentKeys rejects out of range substring. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeEntitlementKeyIdLength) { + TestLoadEntitledKeysForHugeBufferLengths( + [](size_t key_id_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_data()->entitlement_key_id_length = + key_id_length; + }, + !kCheckStatus); +} + +/** Test LoadEntitledContentKeys rejects out of range substring. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeContentKeyIdLength) { + TestLoadEntitledKeysForHugeBufferLengths( + [](size_t key_id_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_data()->content_key_id_length = + key_id_length; + }, + !kCheckStatus); +} + +/** Test that LoadLicense fails gracefully on huge buffer. */ +TEST_P(OEMCryptoLicenseOverflowTest, + 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 that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyIdOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_id.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + 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 that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + 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 that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataIvLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_data_iv.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataIvOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_data_iv.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + 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 that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + 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 that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + 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 that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_data.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + 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 that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + 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 that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlIvLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_control_iv.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlIvOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_control_iv.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlIvLengthAPI16) { + 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 that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + 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 that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_control.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_control.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlLengthAPI16) { + 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 that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + 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 that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyIvLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().enc_mac_keys_iv.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyIvOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().enc_mac_keys_iv.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + 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 that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + 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 that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().enc_mac_keys.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().enc_mac_keys.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + 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 that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + 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 that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringPstLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().pst.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringPstOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().pst.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + 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 that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringPstOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& pst = license_messages->core_response().pst; + pst.offset = response_message_length; + if (pst.length == 0) pst.length = 1; + }); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringSrmRestrictionDataLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().srm_restriction_data.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringSrmRestrictionDataOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().srm_restriction_data.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + 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 that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + 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; + if (srm_restriction_data.length == 0) srm_restriction_data.length = 1; + }); +} + +/** Test that LoadLicense fails gracefully on huge buffer. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeResponseLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t message_size, LicenseRoundTrip* license_messages) { + license_messages->set_message_size(message_size); + }, + !kCheckStatus, !kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on huge buffer. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t message_size, LicenseRoundTrip* license_messages) { + license_messages->set_core_message_size(message_size); + }, + !kCheckStatus, !kUpdateCoreMessageSubstringValues); +} + +INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoLicenseOverflowTest, + Range(kCurrentAPI - 1, kCurrentAPI + 1)); + +/// @} } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_test.cpp b/oemcrypto/test/oemcrypto_test.cpp index 089c3b2..dec7054 100644 --- a/oemcrypto/test/oemcrypto_test.cpp +++ b/oemcrypto/test/oemcrypto_test.cpp @@ -18,36 +18,39 @@ * be skipped. * * @defgroup license License Request Tests - * Test for requesting and loading licenses. + * Test for requesting and loading licenses. * - * @defgroup renewal License Renewal Tests - * Tests for renewing licenses. + * @defgroup renewal License Renewal Tests + * Tests for renewing licenses. * - * @defgroup decrypt Decrypt Tests - * Tests for decrypting content. + * @defgroup decrypt Decrypt Tests + * Tests for decrypting content. * - * @defgroup usage_table Usage Table Tests - * Tests that use the usage table. + * @defgroup usage_table Usage Table Tests + * Tests that use the usage table. * - * @defgroup entitle Entitlement License tests - * Tests for entitlement licenses. + * @defgroup entitle Entitlement License tests + * Tests for entitlement licenses. * - * @defgroup cas Conditional Access System Tests - * Tests for OEMCrypto implementations that support MediaCAS. + * @defgroup cas Conditional Access System Tests + * Tests for OEMCrypto implementations that support MediaCAS. * - * @defgroup cast Cast Test - * Tests for OEMCrypto implementations that support being a Cast receiver. + * @defgroup cast Cast Test + * Tests for OEMCrypto implementations that support being a Cast receiver. * - * @defgroup generic Generic Crypto Tests - * Tests for the Generic Crypto functionality. + * @defgroup android Android Tests + * Tests that enforce requirements that are specific to Android. * - * @defgroup security Security Tests - * Buffer overflow tests, off-by-one tests, and other security tests. + * @defgroup generic Generic Crypto Tests + * Tests for the Generic Crypto functionality. * - * The way the huge buffer tests work is to create a large buffer and then call - * the API. The test then loops and doubles the buffer until the API returns an - * error. An error is considered a passing test. We expect OEMCrypto to fail - * gracefully on a huge buffer rather than crashing. + * @defgroup security Security Tests + * Buffer overflow tests, off-by-one tests, and other security tests. + * + * The way the huge buffer tests work is to create a large buffer and then call + * the API. The test then loops and doubles the buffer until the API returns an + * error. An error is considered a passing test. We expect OEMCrypto to fail + * gracefully on a huge buffer rather than crashing. */ #include @@ -94,7 +97,6 @@ using ::testing::Range; using ::testing::tuple; -using ::testing::WithParamInterface; using namespace std; namespace std { // GTest wants PrintTo to be in the std namespace. @@ -129,141 +131,6 @@ void PrintTo(const tuple { - public: - OEMCryptoLicenseOverflowTest() : license_api_version_(kCurrentAPI) {} - - void SetUp() override { - OEMCryptoSessionTests::SetUp(); - license_api_version_ = GetParam(); - } - - void TearDown() override { OEMCryptoSessionTests::TearDown(); } - - 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); - license_messages.set_api_version(license_api_version_); - s.open(); - InstallTestDrmKey(&s); - 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); - license_messages.set_api_version(license_api_version_); - s.open(); - InstallTestDrmKey(&s); - 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); - } - - protected: - uint32_t license_api_version_; -}; - -// 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(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(); - uint32_t key_session_id = 0; - OEMCryptoResult sts = OEMCrypto_CreateEntitledKeySession( - session_.session_id(), &key_session_id); - if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) { - return; - } - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - entitled_message_.SetEntitledKeySession(key_session_id); - } - - void TearDown() override { OEMCryptoLicenseTestAPI16::TearDown(); } - - protected: - EntitledMessage entitled_message_; - size_t entitlement_response_length_; - - void TestLoadEntitledKeysForHugeBufferLengths( - 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); - } -}; - -/// @} - /// @addtogroup entitle /// @{ @@ -488,214 +355,6 @@ TEST_P(OEMCryptoEntitlementLicenseTest, INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoEntitlementLicenseTest, Range(kCoreMessagesAPI, kCurrentAPI + 1)); -/// @} - -/// @addtogroup security -/// @{ - -/** Test that LoadEntitledContentKeys fails gracefully on huge buffer. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyIdLength) { - TestLoadEntitledKeysForHugeBufferLengths( - [](size_t key_id_length, EntitledMessage* entitled_message) { - entitled_message->entitled_key_array()[0].content_key_id.length = - key_id_length; - }, - !kCheckStatus); -} - -/** Test that LoadEntitledContentKeys fails gracefully on huge buffer. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyIdOffset) { - TestLoadEntitledKeysForHugeBufferLengths( - [](size_t key_id_offset, EntitledMessage* entitled_message) { - entitled_message->entitled_key_array()[0].content_key_id.offset = - key_id_offset; - }, - !kCheckStatus); -} - -/** Test that LoadEntitledContentKeys fails gracefully on huge buffer. */ -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyIdLength) { - 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 LoadEntitledContentKeys rejects out of range substring. */ -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyIdOffset) { - 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 that LoadEntitledContentKeys fails gracefully on huge substring. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeSubstringEntitlementKeyIdLength) { - TestLoadEntitledKeysForHugeBufferLengths( - [](size_t key_id_length, EntitledMessage* entitled_message) { - entitled_message->entitled_key_array()[0].entitlement_key_id.length = - key_id_length; - }, - !kCheckStatus); -} - -/** Test LoadEntitledContentKeys rejects out of range substring. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeSubstringEntitlementKeyIdOffset) { - TestLoadEntitledKeysForHugeBufferLengths( - [](size_t key_id_offset, EntitledMessage* entitled_message) { - entitled_message->entitled_key_array()[0].entitlement_key_id.offset = - key_id_offset; - }, - !kCheckStatus); -} - -/** Test LoadEntitledContentKeys rejects out of range substring. */ -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringEntitlementKeyIdLength) { - 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 LoadEntitledContentKeys rejects out of range substring. */ -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringEntitlementKeyIdOffset) { - 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 LoadEntitledContentKeys rejects out of range substring. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataIvLength) { - TestLoadEntitledKeysForHugeBufferLengths( - [](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 LoadEntitledContentKeys rejects out of range substring. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataIvOffset) { - TestLoadEntitledKeysForHugeBufferLengths( - [](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 LoadEntitledContentKeys rejects out of range substring. */ -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataIvLength) { - 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 LoadEntitledContentKeys rejects out of range substring. */ -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataIvOffset) { - 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 LoadEntitledContentKeys rejects out of range substring. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataLength) { - TestLoadEntitledKeysForHugeBufferLengths( - [](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 LoadEntitledContentKeys rejects out of range substring. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataOffset) { - TestLoadEntitledKeysForHugeBufferLengths( - [](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 LoadEntitledContentKeys rejects out of range substring. */ -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataLength) { - 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 LoadEntitledContentKeys rejects out of range substring. */ -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataOffset) { - 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 LoadEntitledContentKeys rejects out of range substring. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeEntitlementKeyIdLength) { - TestLoadEntitledKeysForHugeBufferLengths( - [](size_t key_id_length, EntitledMessage* entitled_message) { - entitled_message->entitled_key_data()->entitlement_key_id_length = - key_id_length; - }, - !kCheckStatus); -} - -/** Test LoadEntitledContentKeys rejects out of range substring. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeContentKeyIdLength) { - TestLoadEntitledKeysForHugeBufferLengths( - [](size_t key_id_length, EntitledMessage* entitled_message) { - entitled_message->entitled_key_data()->content_key_id_length = - key_id_length; - }, - !kCheckStatus); -} - -/// @} - -/// @addtogroup entitle -/// @{ - TEST_P(OEMCryptoLicenseTest, GetKeyHandleEntitledKeyAPI17) { license_messages_.set_license_type(OEMCrypto_EntitlementLicense); ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); @@ -1048,771 +707,9 @@ TEST_P(OEMCryptoEntitlementLicenseTest, ReassociateEntitledKeySessionAPI17) { /// @} -/// @addtogroup security -/// @{ - -/** Test that LoadLicense fails gracefully on huge buffer. */ -TEST_P(OEMCryptoLicenseOverflowTest, - 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 that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyIdOffset) { - TestLoadLicenseForHugeBufferLengths( - [](size_t offset, LicenseRoundTrip* license_messages) { - license_messages->core_response().key_array[0].key_id.offset = offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - 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 that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - 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 that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataIvLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t length, LicenseRoundTrip* license_messages) { - license_messages->core_response().key_array[0].key_data_iv.length = - length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataIvOffset) { - TestLoadLicenseForHugeBufferLengths( - [](size_t offset, LicenseRoundTrip* license_messages) { - license_messages->core_response().key_array[0].key_data_iv.offset = - offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - 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 that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - 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 that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - 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 that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataOffset) { - TestLoadLicenseForHugeBufferLengths( - [](size_t offset, LicenseRoundTrip* license_messages) { - license_messages->core_response().key_array[0].key_data.offset = offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - 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 that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - 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 that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlIvLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t length, LicenseRoundTrip* license_messages) { - license_messages->core_response().key_array[0].key_control_iv.length = - length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlIvOffset) { - TestLoadLicenseForHugeBufferLengths( - [](size_t offset, LicenseRoundTrip* license_messages) { - license_messages->core_response().key_array[0].key_control_iv.offset = - offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlIvLengthAPI16) { - 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 that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - 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 that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t length, LicenseRoundTrip* license_messages) { - license_messages->core_response().key_array[0].key_control.length = - length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlOffset) { - TestLoadLicenseForHugeBufferLengths( - [](size_t offset, LicenseRoundTrip* license_messages) { - license_messages->core_response().key_array[0].key_control.offset = - offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlLengthAPI16) { - 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 that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - 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 that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyIvLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t length, LicenseRoundTrip* license_messages) { - license_messages->core_response().enc_mac_keys_iv.length = length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyIvOffset) { - TestLoadLicenseForHugeBufferLengths( - [](size_t offset, LicenseRoundTrip* license_messages) { - license_messages->core_response().enc_mac_keys_iv.offset = offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - 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 that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - 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 that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t length, LicenseRoundTrip* license_messages) { - license_messages->core_response().enc_mac_keys.length = length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyOffset) { - TestLoadLicenseForHugeBufferLengths( - [](size_t offset, LicenseRoundTrip* license_messages) { - license_messages->core_response().enc_mac_keys.offset = offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - 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 that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - 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 that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringPstLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t length, LicenseRoundTrip* license_messages) { - license_messages->core_response().pst.length = length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringPstOffset) { - TestLoadLicenseForHugeBufferLengths( - [](size_t offset, LicenseRoundTrip* license_messages) { - license_messages->core_response().pst.offset = offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - 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 that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringPstOffset) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](size_t response_message_length, LicenseRoundTrip* license_messages) { - auto& pst = license_messages->core_response().pst; - pst.offset = response_message_length; - if (pst.length == 0) pst.length = 1; - }); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringSrmRestrictionDataLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t length, LicenseRoundTrip* license_messages) { - license_messages->core_response().srm_restriction_data.length = length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringSrmRestrictionDataOffset) { - TestLoadLicenseForHugeBufferLengths( - [](size_t offset, LicenseRoundTrip* license_messages) { - license_messages->core_response().srm_restriction_data.offset = offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - 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 that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - 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; - if (srm_restriction_data.length == 0) srm_restriction_data.length = 1; - }); -} - -/** Test that LoadLicense fails gracefully on huge buffer. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeResponseLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t message_size, LicenseRoundTrip* license_messages) { - license_messages->set_message_size(message_size); - }, - !kCheckStatus, !kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on huge buffer. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t message_size, LicenseRoundTrip* license_messages) { - license_messages->set_core_message_size(message_size); - }, - !kCheckStatus, !kUpdateCoreMessageSubstringValues); -} - -INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoLicenseOverflowTest, - Range(kCurrentAPI - 1, kCurrentAPI + 1)); - -/// @} - /// @addtogroup cas /// @{ -/// @} - -/// @addtogroup security -/// @{ - -/** Test that LoadProvisioning fails gracefully on huge buffer. */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForHugeResponseLength) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForHugeBufferLengths( - [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->set_message_size(message_size); - }, - !kCheckStatus, !kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadProvisioning fails gracefully on huge buffer. */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForHugeCoreMessageLength) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForHugeBufferLengths( - [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->set_core_message_size(message_size); - }, - !kCheckStatus, !kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadProvisioning fails gracefully on huge buffer. */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyLength) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForHugeBufferLengths( - [](size_t length, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->core_response().enc_private_key.length = length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadProvisioning fails gracefully on huge buffer. */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyOffset) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForHugeBufferLengths( - [](size_t offset, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->core_response().enc_private_key.offset = offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F( - OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyLength) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - 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 that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F( - OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyOffset) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - 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 that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyIvLength) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForHugeBufferLengths( - [](size_t length, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->core_response().enc_private_key_iv.length = - length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyIvOffset) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForHugeBufferLengths( - [](size_t offset, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->core_response().enc_private_key_iv.offset = - offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F( - OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyIvLengthAPI16) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - 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 that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F( - OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyIvOffset) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - 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 that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncMessageKeyLength) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForHugeBufferLengths( - [](size_t length, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->core_response().encrypted_message_key.length = - length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncMessageKeyOffset) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForHugeBufferLengths( - [](size_t offset, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->core_response().encrypted_message_key.offset = - offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F( - OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncMessageKeyLengthProv30) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - if (global_features.provisioning_method != OEMCrypto_OEMCertificate) { - GTEST_SKIP() << "Test for Prov 3.0 devices only."; - } - 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 that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F( - OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncMessageKeyOffsetProv30) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - if (global_features.provisioning_method != OEMCrypto_OEMCertificate) { - GTEST_SKIP() << "Test for Prov 3.0 devices only."; - } - 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; - }); -} - -/// @} - -/// @addtogroup security -/// @{ - -/** Test that OEMCrypto_PrepAndSignProvisioningRequest fails gracefully on a - * huge buffer. - */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryPrepareProvisioningRequestForHugeRequestMessageLength) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestPrepareProvisioningRequestForHugeBufferLengths( - [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->set_message_size(message_size); - }, - kCheckStatus); -} - -/** Test that OEMCrypto_PrepAndSignProvisioningRequest fails gracefully on a - * huge buffer. - */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryPrepareProvisioningRequestForHugeSignatureLength) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestPrepareProvisioningRequestForHugeBufferLengths( - [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->set_request_signature_size(message_size); - }, - !kCheckStatus); -} - -/** Test that OEMCrypto_PrepAndSignProvisioningRequest fails gracefully on a - * huge buffer. - */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryPrepareProvisioningRequestForHugeCoreMessageLength) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestPrepareProvisioningRequestForHugeBufferLengths( - [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->set_core_message_size(message_size); - }, - kCheckStatus); -} - -/// @} - -/// @addtogroup cast -/// @{ - -/// @} - #ifdef CAS_TEST # include "tuner_hal.h" @@ -1898,4 +795,6 @@ INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoCasDemoTest, Range(kCoreMessagesAPI, kCurrentAPI + 1)); #endif + +/// @} } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_test_android.cpp b/oemcrypto/test/oemcrypto_test_android.cpp index 4337f75..b876f72 100644 --- a/oemcrypto/test/oemcrypto_test_android.cpp +++ b/oemcrypto/test/oemcrypto_test_android.cpp @@ -21,6 +21,9 @@ namespace wvoec { +/// @addtogroup android +/// @{ + // These tests are required for LollyPop Android devices. class OEMCryptoAndroidLMPTest : public ::testing::Test { protected: @@ -174,4 +177,5 @@ TEST_F(OEMCryptoAndroidQTest, MinVersionNumber14) { ASSERT_GE(version, 15u); } +/// @} } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_unittests.gypi b/oemcrypto/test/oemcrypto_unittests.gypi index 3ccd422..7b2c8ba 100644 --- a/oemcrypto/test/oemcrypto_unittests.gypi +++ b/oemcrypto/test/oemcrypto_unittests.gypi @@ -23,6 +23,7 @@ 'oemcrypto_generic_crypto_test.cpp', 'oemcrypto_license_test.cpp', 'oemcrypto_provisioning_test.cpp', + 'oemcrypto_security_test.cpp', 'oemcrypto_usage_table_test.cpp', 'oemcrypto_test.cpp', '<(jsmn_dir)/jsmn.c', diff --git a/oemcrypto/test/oemcrypto_usage_table_test.cpp b/oemcrypto/test/oemcrypto_usage_table_test.cpp index ba62ad3..9e0506b 100644 --- a/oemcrypto/test/oemcrypto_usage_table_test.cpp +++ b/oemcrypto/test/oemcrypto_usage_table_test.cpp @@ -10,6 +10,9 @@ using ::testing::Values; namespace wvoec { +/// @addtogroup usage_table +/// @{ + // Test that successive calls to PrepAndSignProvisioningRequest only increase // the provisioning count in the ODK message TEST_F(OEMCryptoSessionTests, Provisioning_IncrementCounterAPI18) { @@ -1757,4 +1760,5 @@ INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoUsageTableDefragTest, INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoUsageTableTestWallClock, Values(kCurrentAPI)); +/// @} } // namespace wvoec diff --git a/util/include/file_store.h b/util/include/file_store.h index 9563b5e..73de53d 100644 --- a/util/include/file_store.h +++ b/util/include/file_store.h @@ -7,7 +7,8 @@ #ifndef WVCDM_UTIL_FILE_STORE_H_ #define WVCDM_UTIL_FILE_STORE_H_ -#include +#include + #include #include #include @@ -18,16 +19,35 @@ namespace wvutil { +// Fixed filename for ATSC DRM certificate pre-installed +// on ATSC devices for ATSC licenses. static const std::string kAtscCertificateFileName = "atsccert.bin"; +// General filename for either global or unmapped app-origin +// DRM certificates. static const std::string kCertificateFileName = "cert1.bin"; +// File extension for DRM and OEM certificate files. static const std::string kCertificateFileNameExt = ".bin"; -static const std::string kCertificateFileNamePrefix = "cert1_"; +// Filename prefix for mapped (scoped) DRM certificate filenames +// specific to a particular app-origin. +static const std::string kScopedCertificateFilenamePrefix = "cert1_"; +// TODO(b/376533901): Replace this constant with +// kScopedCertificateFilenamePrefix in source code.. +static const std::string kCertificateFileNamePrefix = + kScopedCertificateFilenamePrefix; +// Legacy general filename for either global or unmapped app-origin +// DRM certificates. static const std::string kLegacyCertificateFileName = "cert.bin"; -static const std::string kLegacyCertificateFileNamePrefix = "cert"; +// Legacy filename prefix for mapped (scoped) DRM certificate filenames +// specific to a particular app-origin. +static const std::string kLegacyScopedCertificateFilenamePrefix = "cert"; +// TODO(b/376533901): Replace this constant with +// kLegacyScopedCertificateFilenamePrefix in source code.. +static const std::string kLegacyCertificateFileNamePrefix = + kLegacyScopedCertificateFilenamePrefix; +// Filename for global OEM certificates. static const std::string kOemCertificateFileName = "oemcert.bin"; -static const std::string kOemCertificateFileNamePrefix = "oemcert_"; -// File class. The implementation is platform dependent. +// File interface. The implementation is platform dependent. class File { public: File() {} @@ -35,35 +55,70 @@ class File { virtual ssize_t Read(char* buffer, size_t bytes) = 0; virtual ssize_t Write(const char* buffer, size_t bytes) = 0; - friend class FileSystem; CORE_DISALLOW_COPY_AND_ASSIGN(File); }; +// File system base class. The implementation is platform dependent. class FileSystem { public: FileSystem(); FileSystem(const std::string& origin, void* extra_data); virtual ~FileSystem(); + // Concreate implementation of FileSystem. + // Depending on the platform, this may be vendor or Widevine implemented. class Impl; - // defines as bit flag - enum OpenFlags { - kNoFlags = 0, - kCreate = 1, - kReadOnly = 2, // defaults to read and write access - kTruncate = 4 - }; + // Flags for calls to Open. + static constexpr int kNoFlags = 0; + // Create file if does not already exist, open file if it does exist. + static constexpr int kCreate = (1 << 0); + // Open file as read-only; typically should not be used with kCreate. + static constexpr int kReadOnly = (1 << 1); + // Open file and truncated. May be used with kCreate; should not + // be used with kReadOnly. + static constexpr int kTruncate = (1 << 2); virtual std::unique_ptr Open(const std::string& file_path, int flags); - virtual bool Exists(const std::string& file_path); - virtual bool Exists(const std::string& file_path, int* errno_value); - virtual bool Remove(const std::string& file_path); + // Checks if the |path| exists. The |path| may be a file or directory. + // Return true if an entry in the file system exists; false otherwise. + virtual bool Exists(const std::string& path); + // Same as above, except the optional parameter of |errno_value| should + // be set to 0 or the value of C errno when attempting to check + // the existence of a file. + virtual bool Exists(const std::string& path, int* errno_value); + + // Removes the specified |path|. + // + // If |path| is a regular file, the file should be removed. + // If |path| is a directory, both the directory and the directory + // contents should be removed. + // + // Implementation must support a |path| containing a single wildcard + // character in the filename component of the path. + // + // Return value: + // - true : File/directory was removed, or file/directory did not exist + // - false : File/directory could not be removed, or other error. + virtual bool Remove(const std::string& path); + + // Obtain the size of a file in bytes. |file_path| must be a file, + // and not a directory. + // + // Return value: + // - non-negative : size of file in bytes if file exists + // - negative : file does not exist, or error occurred. virtual ssize_t FileSize(const std::string& file_path); - // Return the filenames stored at dir_path. - // dir_path will be stripped from the returned names. + // Return the entries stored at |dir_path| (includes both files + // and directories). + // + // Return value: + // - true : Directory exists, and directory entry names are stored + // in |names|; |names| may be empty if directory was empty. + // - false : Directory does not exist, |dir_path| is not a directory, + // or error was encountered. virtual bool List(const std::string& dir_path, std::vector* names); diff --git a/util/test/file_store_unittest.cpp b/util/test/file_store_unittest.cpp index a62bfc0..ad30ac2 100644 --- a/util/test/file_store_unittest.cpp +++ b/util/test/file_store_unittest.cpp @@ -1,9 +1,14 @@ // Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine License // Agreement. - #include "file_store.h" +#include + +#include +#include +#include + #include #include @@ -11,18 +16,20 @@ #include "test_vectors.h" namespace wvutil { - namespace { -const std::string kTestDirName = "test_dir"; -const std::string kTestFileName = "test.txt"; -const std::string kTestFileName2 = "test2.txt"; -const std::string kTestFileName3 = "test3.other"; -const std::string kTestFileNameExt = ".txt"; -const std::string kTestFileNameExt3 = ".other"; -const std::string kTestIdentifier1 = "some_identifier"; -const std::string kTestIdentifier2 = "some_other_identifier"; -const std::string kWildcard = "*"; -const std::string kUnderscore = "_"; +constexpr char kTestFilename[] = "sample.txt"; + +constexpr char kTestIdentifier1[] = "some_identifier"; +constexpr char kTestIdentifier2[] = "some_other_identifier"; + +constexpr int kNoError = 0; +constexpr int kEntryDoesNotExist = ENOENT; + +bool StartsWith(const std::string& haystack, const std::string& needle) { + if (needle.empty()) return true; + if (haystack.size() < needle.size()) return false; + return haystack.find(needle) == 0; +} } // namespace class FileTest : public testing::Test { @@ -32,7 +39,19 @@ class FileTest : public testing::Test { void TearDown() override { RemoveTestDir(); } void RemoveTestDir() { - EXPECT_TRUE(file_system_.Remove(wvcdm::test_vectors::kTestDir)); + ASSERT_TRUE(file_system_.Remove(wvcdm::test_vectors::kTestDir)) + << "Failed to update test directory: " << wvcdm::test_vectors::kTestDir; + } + + std::string PathJoin(const std::string& base_path, + const std::string& add_path) { + if (base_path.empty()) return add_path; + std::string path = base_path; + if (path.back() != '/') { + path.push_back('/'); + } + path.append(add_path); + return path; } FileSystem file_system_; @@ -40,336 +59,505 @@ class FileTest : public testing::Test { TEST_F(FileTest, FileExists) { int errno_value = -1; - EXPECT_TRUE(file_system_.Exists(wvcdm::test_vectors::kExistentFile)); + EXPECT_TRUE(file_system_.Exists(wvcdm::test_vectors::kExistentFile)) + << "path = " << wvcdm::test_vectors::kExistentFile; EXPECT_TRUE( - file_system_.Exists(wvcdm::test_vectors::kExistentFile, &errno_value)); - EXPECT_EQ(0, errno_value); - EXPECT_TRUE(file_system_.Exists(wvcdm::test_vectors::kExistentDir)); + file_system_.Exists(wvcdm::test_vectors::kExistentFile, &errno_value)) + << "path = " << wvcdm::test_vectors::kExistentFile; + EXPECT_EQ(kNoError, errno_value); +} - EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kNonExistentFile)); +TEST_F(FileTest, FileDoesNotExist) { + int errno_value = -1; + EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kNonExistentFile)) + << "path = " << wvcdm::test_vectors::kNonExistentFile; EXPECT_FALSE( - file_system_.Exists(wvcdm::test_vectors::kNonExistentFile, &errno_value)); - EXPECT_EQ(ENOENT, errno_value); - EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kNonExistentDir)); + file_system_.Exists(wvcdm::test_vectors::kNonExistentFile, &errno_value)) + << "path = " << wvcdm::test_vectors::kNonExistentFile; + EXPECT_EQ(kEntryDoesNotExist, errno_value); +} + +TEST_F(FileTest, DirectoryExists) { + int errno_value = -1; + EXPECT_TRUE(file_system_.Exists(wvcdm::test_vectors::kExistentDir)) + << "path = " << wvcdm::test_vectors::kExistentDir; + EXPECT_TRUE( + file_system_.Exists(wvcdm::test_vectors::kExistentDir, &errno_value)) + << "path = " << wvcdm::test_vectors::kExistentDir; + EXPECT_EQ(kNoError, errno_value); +} + +TEST_F(FileTest, DirectoryDoesNotExist) { + int errno_value = -1; + EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kNonExistentDir)) + << "path = " << wvcdm::test_vectors::kNonExistentDir; + EXPECT_FALSE( + file_system_.Exists(wvcdm::test_vectors::kNonExistentDir, &errno_value)) + << "path = " << wvcdm::test_vectors::kNonExistentDir; + EXPECT_EQ(kEntryDoesNotExist, errno_value); } TEST_F(FileTest, RemoveDir) { - EXPECT_TRUE(file_system_.Remove(wvcdm::test_vectors::kTestDir)); - EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir)); + EXPECT_TRUE(file_system_.Remove(wvcdm::test_vectors::kTestDir)) + << "path = " << wvcdm::test_vectors::kTestDir; + EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir)) + << "path = " << wvcdm::test_vectors::kTestDir; } TEST_F(FileTest, OpenFile) { - std::string path = wvcdm::test_vectors::kTestDir + kTestFileName; - EXPECT_TRUE(file_system_.Remove(path)); + const std::string path = + PathJoin(wvcdm::test_vectors::kTestDir, kTestFilename); + EXPECT_TRUE(file_system_.Remove(path)) << "path = " << path; std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file: " << path; - EXPECT_TRUE(file_system_.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path; } TEST_F(FileTest, RemoveDirAndFile) { - std::string path = wvcdm::test_vectors::kTestDir + kTestFileName; + const std::string path = + PathJoin(wvcdm::test_vectors::kTestDir, kTestFilename); std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file: " << path; - EXPECT_TRUE(file_system_.Exists(path)); - EXPECT_TRUE(file_system_.Remove(path)); - EXPECT_FALSE(file_system_.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path; + EXPECT_TRUE(file_system_.Remove(path)) << "path = " << path; + EXPECT_FALSE(file_system_.Exists(path)) << "path = " << path; file = file_system_.Open(path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file: " << path; - EXPECT_TRUE(file_system_.Exists(path)); - RemoveTestDir(); - EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir)); - EXPECT_FALSE(file_system_.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path; + ASSERT_NO_FATAL_FAILURE(RemoveTestDir()); + EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir)) + << "path = " << path; + EXPECT_FALSE(file_system_.Exists(path)) << "path = " << path; } TEST_F(FileTest, RemoveWildcardFiles) { - std::string path1 = wvcdm::test_vectors::kTestDir + kTestFileName; - std::string path2 = wvcdm::test_vectors::kTestDir + kTestFileName2; - std::string wildcard_path = - wvcdm::test_vectors::kTestDir + kWildcard + kTestFileNameExt; + const std::string path1 = + PathJoin(wvcdm::test_vectors::kTestDir, "first.txt"); + const std::string path2 = + PathJoin(wvcdm::test_vectors::kTestDir, "second.txt"); + const std::string wildcard_path = + PathJoin(wvcdm::test_vectors::kTestDir, "*.txt"); std::unique_ptr file = file_system_.Open(path1, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file (1): " << path1; file = file_system_.Open(path2, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file (2): " << path2; - EXPECT_TRUE(file_system_.Exists(path1)); - EXPECT_TRUE(file_system_.Exists(path2)); - EXPECT_TRUE(file_system_.Remove(wildcard_path)); - EXPECT_FALSE(file_system_.Exists(path1)); - EXPECT_FALSE(file_system_.Exists(path2)); + EXPECT_TRUE(file_system_.Exists(path1)) << "path = " << path1; + EXPECT_TRUE(file_system_.Exists(path2)) << "path = " << path2; + EXPECT_TRUE(file_system_.Remove(wildcard_path)) + << "wildcard_path = " << wildcard_path; + EXPECT_FALSE(file_system_.Exists(path1)) << "path = " << path1; + EXPECT_FALSE(file_system_.Exists(path2)) << "path = " << path2; } TEST_F(FileTest, FileSize) { - std::string path = wvcdm::test_vectors::kTestDir + kTestFileName; + const std::string path = + PathJoin(wvcdm::test_vectors::kTestDir, kTestFilename); file_system_.Remove(path); - std::string write_data = CdmRandom::RandomData(600); - size_t write_data_size = write_data.size(); - std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_EQ(file->Write(write_data.data(), write_data_size), write_data_size); - EXPECT_TRUE(file_system_.Exists(path)); + constexpr size_t kDataSize = 600; + const std::string write_data = CdmRandom::RandomData(kDataSize); + ASSERT_EQ(write_data.size(), kDataSize); - EXPECT_EQ(static_cast(write_data_size), file_system_.FileSize(path)); + std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); + ASSERT_TRUE(file) << "Failed to create file: " << path; + + EXPECT_EQ(file->Write(write_data.data(), write_data.size()), + write_data.size()); + file.reset(); // Close file. + + EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path; + + EXPECT_EQ(static_cast(kDataSize), file_system_.FileSize(path)) + << "path = " << path; } TEST_F(FileTest, WriteReadBinaryFile) { - std::string path = wvcdm::test_vectors::kTestDir + kTestFileName; + const std::string path = + PathJoin(wvcdm::test_vectors::kTestDir, kTestFilename); file_system_.Remove(path); - std::string write_data = CdmRandom::RandomData(600); - size_t write_data_size = write_data.size(); - std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_EQ(file->Write(write_data.data(), write_data_size), write_data_size); - EXPECT_TRUE(file_system_.Exists(path)); + constexpr size_t kDataSize = 600; + const std::string write_data = CdmRandom::RandomData(kDataSize); + ASSERT_EQ(write_data.size(), kDataSize); + + std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); + ASSERT_TRUE(file) << "Failed to create file: " << path; + + constexpr ssize_t kExpectedFileSizeResult = static_cast(kDataSize); + EXPECT_EQ(file->Write(write_data.data(), write_data.size()), + kExpectedFileSizeResult) + << "path = " << path; + file.reset(); // Close file. + + EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path; - std::string read_data; - read_data.resize(file_system_.FileSize(path)); - size_t read_data_size = read_data.size(); file = file_system_.Open(path, FileSystem::kReadOnly); - ASSERT_TRUE(file); - EXPECT_EQ(file->Read(&read_data[0], read_data_size), read_data_size); + ASSERT_TRUE(file) << "Failed to re-open file: " << path; + + std::string read_data(kDataSize, '\0'); + ; + ASSERT_EQ(file->Read(&read_data[0], read_data.size()), + kExpectedFileSizeResult) + << "path = " << path; EXPECT_EQ(write_data, read_data); } TEST_F(FileTest, ListFiles) { - std::vector names; + const std::string kTxtFilename1 = "data.txt"; + const std::string kTxtFilename2 = "other.txt"; + const std::string kBinFilename = "sample.bin"; - std::string not_path("zzz"); - std::string path1 = wvcdm::test_vectors::kTestDir + kTestFileName; - std::string path2 = wvcdm::test_vectors::kTestDir + kTestFileName2; - std::string path3 = wvcdm::test_vectors::kTestDir + kTestFileName3; - std::string path_dir = wvcdm::test_vectors::kTestDir; + const std::string dir_path = wvcdm::test_vectors::kTestDir; + const std::string path1 = PathJoin(dir_path, kTxtFilename1); + const std::string path2 = PathJoin(dir_path, kTxtFilename2); + const std::string path3 = PathJoin(dir_path, kBinFilename); + // Create files. std::unique_ptr file = file_system_.Open(path1, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file (1): " << path1; file = file_system_.Open(path2, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file (2): " << path2; file = file_system_.Open(path3, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file (3): " << path3; + file.reset(); // Close file EXPECT_TRUE(file_system_.Exists(path1)); EXPECT_TRUE(file_system_.Exists(path2)); EXPECT_TRUE(file_system_.Exists(path3)); - // Ask for non-existent path. - EXPECT_FALSE(file_system_.List(not_path, &names)); + std::vector names; + ASSERT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path; - // Valid path, but no way to return names. - EXPECT_FALSE(file_system_.List(path_dir, nullptr)); + size_t expected_file_count = 3; + EXPECT_EQ(names.size(), expected_file_count); - // Valid path, valid return. - EXPECT_TRUE(file_system_.List(path_dir, &names)); - - // Should find three files. Order not important. - EXPECT_EQ(3u, names.size()); + // Should find the three files. Order not important. EXPECT_THAT(names, ::testing::UnorderedElementsAre( - kTestFileName, kTestFileName2, kTestFileName3)); + kTxtFilename1, kTxtFilename2, kBinFilename)); - std::string wild_card_path = path_dir + kWildcard + kTestFileNameExt; - EXPECT_TRUE(file_system_.Remove(wild_card_path)); - EXPECT_TRUE(file_system_.List(path_dir, &names)); + // Remove .txt files. + const std::string txt_wildcard_path = PathJoin(dir_path, "*.txt"); - EXPECT_EQ(1u, names.size()); - EXPECT_TRUE(names[0].compare(kTestFileName3) == 0); + EXPECT_TRUE(file_system_.Remove(txt_wildcard_path)) + << "txt_wildcard_path = " << txt_wildcard_path; + EXPECT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path; - std::string wild_card_path2 = path_dir + kWildcard + kTestFileNameExt3; - EXPECT_TRUE(file_system_.Remove(wild_card_path2)); - EXPECT_TRUE(file_system_.List(path_dir, &names)); + expected_file_count = 1; + ASSERT_EQ(names.size(), expected_file_count); + EXPECT_EQ(names.front(), kBinFilename); - EXPECT_EQ(0u, names.size()); + const std::string bin_wildcard_path = PathJoin(dir_path, "*.bin"); + EXPECT_TRUE(file_system_.Remove(bin_wildcard_path)) + << "bin_wildcard_path = " << bin_wildcard_path; + + // All files should be removed, but listing should still succeed. + EXPECT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path; + expected_file_count = 0; + EXPECT_EQ(expected_file_count, names.size()); } -TEST_F(FileTest, CreateGlobalCertificates) { - // Clear directory +TEST_F(FileTest, ListFiles_NotAPath) { + const std::string not_path("zzz/xxx"); std::vector names; - std::string path_dir = wvcdm::test_vectors::kTestDir; - std::string wild_card_path = path_dir + kWildcard; - file_system_.Remove(wild_card_path); - if (file_system_.List(path_dir, &names)) { - EXPECT_EQ(0u, names.size()); + // Ask for non-existent path. + EXPECT_FALSE(file_system_.List(not_path, &names)); +} + +TEST_F(FileTest, ListFiles_NullParameter) { + const std::string dir_path = wvcdm::test_vectors::kTestDir; + const std::string path = PathJoin(dir_path, kTestFilename); + + std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); + ASSERT_TRUE(file) << "Failed to create file: " << path; + file.reset(); // Close file. + + // Valid path, but no way to return names. + EXPECT_FALSE(file_system_.List(dir_path, nullptr)); +} + +// On certain platforms, the FileSystem may perform special +// name translations on certificate filenames which make them behave +// differently from non-certificate filenames. +TEST_F(FileTest, CreateGlobalCertificates) { + ASSERT_TRUE(file_system_.IsGlobal()) + << "Test case requires global file system"; + + const std::string dir_path = wvcdm::test_vectors::kTestDir; + + // Clear directory + const std::string all_file_wildcard_path = PathJoin(dir_path, "*"); + file_system_.Remove(all_file_wildcard_path); + // Ensure directory is empty. + std::vector names; + if (file_system_.List(dir_path, &names)) { + constexpr size_t kZero = 0; + ASSERT_EQ(kZero, names.size()) << "Test requires empty directory"; } - // Create certificates and verify that they exist - std::string certificate_path = - wvcdm::test_vectors::kTestDir + kCertificateFileName; - std::string legacy_certificate_path = - wvcdm::test_vectors::kTestDir + kLegacyCertificateFileName; + const std::string certificate_path = PathJoin(dir_path, kCertificateFileName); + const std::string legacy_certificate_path = + PathJoin(dir_path, kLegacyCertificateFileName); + // Create certificates and verify that they exist std::unique_ptr file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create certificate file: " + << certificate_path; + file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create legacy certificate file: " + << legacy_certificate_path; + file.reset(); // Close file. - EXPECT_TRUE(file_system_.Exists(certificate_path)); - EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)); + EXPECT_TRUE(file_system_.Exists(certificate_path)) + << "certificate_path = " << certificate_path; + EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)) + << "legacy_certificate_path = " << legacy_certificate_path; - EXPECT_TRUE(file_system_.List(path_dir, &names)); + ASSERT_TRUE(file_system_.List(dir_path, &names)); // Should find two files. Order not important. - EXPECT_EQ(2u, names.size()); + constexpr size_t kExpectedCount = 2; + EXPECT_EQ(kExpectedCount, names.size()); EXPECT_THAT(names, ::testing::UnorderedElementsAre( kCertificateFileName, kLegacyCertificateFileName)); } +// On certain platforms, the FileSystem may perform special +// name translations on certificate filenames which make them behave +// differently from non-certificate filenames. TEST_F(FileTest, CreateCertificates) { + ASSERT_TRUE(file_system_.IsGlobal()) + << "Test case requires starting with a global file system"; + const std::string dir_path = wvcdm::test_vectors::kTestDir; + // Clear directory + const std::string all_file_wildcard_path = PathJoin(dir_path, "*"); + file_system_.Remove(all_file_wildcard_path); + // Ensure directory is empty. std::vector names; - std::string path_dir = wvcdm::test_vectors::kTestDir; - std::string wild_card_path = path_dir + kWildcard; - file_system_.Remove(wild_card_path); - if (file_system_.List(path_dir, &names)) { - EXPECT_EQ(0u, names.size()); + if (file_system_.List(dir_path, &names)) { + constexpr size_t kZero = 0; + ASSERT_EQ(kZero, names.size()) << "Test requires empty directory"; } - std::string certificate_path = - wvcdm::test_vectors::kTestDir + kCertificateFileName; - std::string legacy_certificate_path = - wvcdm::test_vectors::kTestDir + kLegacyCertificateFileName; + const std::string certificate_path = PathJoin(dir_path, kCertificateFileName); + const std::string legacy_certificate_path = + PathJoin(dir_path, kLegacyCertificateFileName); - // Create Global certificates + // Create Global certificates. std::unique_ptr file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create global certificate: " + << certificate_path; file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create global legacy certificate: " + << legacy_certificate_path; + file.reset(); // Close file. + + EXPECT_TRUE(file_system_.Exists(certificate_path)) + << "Global certificate: " << certificate_path; + EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)) + << "Global legacy certificate: " << legacy_certificate_path; + + // Switch to first identifier. + file_system_.set_identifier(kTestIdentifier1); + ASSERT_FALSE(file_system_.IsGlobal()) << "identifier = " << kTestIdentifier1; + + // Global certificates should not be visible once identifier has been + // specified. + EXPECT_FALSE(file_system_.Exists(certificate_path)) + << kTestIdentifier1 << " certificate: " << certificate_path; + EXPECT_FALSE(file_system_.Exists(legacy_certificate_path)) + << kTestIdentifier1 << " legacy certificate: " << legacy_certificate_path; // Create certificates with first identifier - file_system_.set_identifier(kTestIdentifier1); file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier1 + << " certificate: " << certificate_path; file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(!file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier1 + << " legacy certificate: " << legacy_certificate_path; + file.reset(); // Close file. + + // Verify they now exist. + EXPECT_TRUE(file_system_.Exists(certificate_path)) + << kTestIdentifier1 << " certificate: " << certificate_path; + EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)) + << kTestIdentifier1 << " legacy certificate: " << legacy_certificate_path; + + // Switch to second identifier. + file_system_.set_identifier(kTestIdentifier2); + ASSERT_FALSE(file_system_.IsGlobal()) << "identifier = " << kTestIdentifier2; + + // Global and first identifier certificates should not be + // visible. + EXPECT_FALSE(file_system_.Exists(certificate_path)) + << kTestIdentifier2 << " certificate: " << certificate_path; + EXPECT_FALSE(file_system_.Exists(legacy_certificate_path)) + << kTestIdentifier2 << " legacy certificate: " << legacy_certificate_path; // Create certificates with second identifier - file_system_.set_identifier(kTestIdentifier2); file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier2 + << " certificate: " << certificate_path; file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(!file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier2 + << " legacy certificate: " << legacy_certificate_path; + file.reset(); // Close file. - EXPECT_TRUE(file_system_.Exists(certificate_path)); - EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)); + // Verify they now exist. + EXPECT_TRUE(file_system_.Exists(certificate_path)) + << kTestIdentifier2 << " certificate: " << certificate_path; + EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)) + << kTestIdentifier2 << " legacy certificate: " << legacy_certificate_path; - EXPECT_TRUE(file_system_.List(path_dir, &names)); + // FileSystem::List is expected to still return all certificate files + // (both global and scoped). + ASSERT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path; // Should find six files. Order not important. + constexpr size_t kExpectedTotalCertCount = 6; + ASSERT_EQ(names.size(), kExpectedTotalCertCount); + bool is_global_certificate_present = false; bool is_global_legacy_certificate_present = false; size_t certificate_count = 0; size_t legacy_certificate_count = 0; - EXPECT_EQ(6u, names.size()); - for (size_t i = 0; i < names.size(); ++i) { - if (names[i].size() > kCertificateFileName.size()) { - if (names[i].compare(0, kCertificateFileNamePrefix.size(), - kCertificateFileNamePrefix) == 0) - ++certificate_count; - else if (names[i].compare(0, kLegacyCertificateFileNamePrefix.size(), - kLegacyCertificateFileNamePrefix) == 0) - ++legacy_certificate_count; - } else if (names[i].compare(kCertificateFileName) == 0) { - is_global_certificate_present = true; - } else if (names[i].compare(kLegacyCertificateFileName) == 0) { + for (const auto& filename : names) { + if (filename == kLegacyCertificateFileName) { is_global_legacy_certificate_present = true; + } else if (filename == kCertificateFileName) { + is_global_certificate_present = true; + } else if (StartsWith(filename, kScopedCertificateFilenamePrefix)) { + certificate_count++; + } else if (StartsWith(filename, kLegacyScopedCertificateFilenamePrefix)) { + legacy_certificate_count++; } else { - EXPECT_TRUE(false); + ADD_FAILURE() << "Unexpected filename: " << filename; } } - EXPECT_EQ(2, certificate_count); - EXPECT_EQ(2, legacy_certificate_count); - EXPECT_TRUE(is_global_certificate_present); - EXPECT_TRUE(is_global_legacy_certificate_present); + constexpr size_t kExpectedScopedCertCount = 2; + EXPECT_EQ(certificate_count, kExpectedScopedCertCount) + << "Missing certificates"; + EXPECT_EQ(legacy_certificate_count, kExpectedScopedCertCount) + << "Missing legacy certificates"; + EXPECT_TRUE(is_global_certificate_present) + << "Missing global certificate: " << kCertificateFileName; + EXPECT_TRUE(is_global_legacy_certificate_present) + << "Missing legacy global certificate: " << kLegacyCertificateFileName; } +// On certain platforms, the FileSystem may perform special +// name translations on certificate file names which make them behave +// differently from non-certificate file names. TEST_F(FileTest, RemoveCertificates) { + ASSERT_TRUE(file_system_.IsGlobal()) + << "Test case requires starting with a global file system"; + const std::string dir_path = wvcdm::test_vectors::kTestDir; + // Clear directory + const std::string all_file_wildcard_path = PathJoin(dir_path, "*"); + file_system_.Remove(all_file_wildcard_path); + // Ensure directory is empty. std::vector names; - std::string path_dir = wvcdm::test_vectors::kTestDir; - std::string wild_card_path = path_dir + kWildcard; - file_system_.Remove(wild_card_path); - if (file_system_.List(path_dir, &names)) { - EXPECT_EQ(0u, names.size()); + if (file_system_.List(dir_path, &names)) { + constexpr size_t kZero = 0; + ASSERT_EQ(kZero, names.size()) << "Test requires empty directory"; } - std::string certificate_path = - wvcdm::test_vectors::kTestDir + kCertificateFileName; - std::string legacy_certificate_path = - wvcdm::test_vectors::kTestDir + kLegacyCertificateFileName; + const std::string certificate_path = PathJoin(dir_path, kCertificateFileName); + const std::string legacy_certificate_path = + PathJoin(dir_path, kLegacyCertificateFileName); - // Create Global certificates + // Create Global certificates. std::unique_ptr file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create global certificate: " + << certificate_path; file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create global legacy certificate: " + << legacy_certificate_path; + file.reset(); // Close file. + + // Switch to first identifier. + file_system_.set_identifier(kTestIdentifier1); + ASSERT_FALSE(file_system_.IsGlobal()) << "identifier = " << kTestIdentifier1; // Create certificates with first identifier - file_system_.set_identifier(kTestIdentifier1); file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier1 + << " certificate: " << certificate_path; file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(!file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier1 + << " legacy certificate: " << legacy_certificate_path; + file.reset(); // Close file. + + // Switch to second identifier. + file_system_.set_identifier(kTestIdentifier2); + ASSERT_FALSE(file_system_.IsGlobal()) << "identifier = " << kTestIdentifier2; // Create certificates with second identifier - file_system_.set_identifier(kTestIdentifier2); file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier2 + << " certificate: " << certificate_path; file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(!file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier2 + << " legacy certificate: " << legacy_certificate_path; + file.reset(); // Close file. - EXPECT_TRUE(file_system_.Exists(certificate_path)); - EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)); - - EXPECT_TRUE(file_system_.List(path_dir, &names)); - - EXPECT_EQ(6u, names.size()); + // FileSystem::List is expected to still return all certificate files + // (both global and scoped). + ASSERT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path; + // Should find six files. Order not important. + constexpr size_t kExpectedTotalCertCount = 6; + ASSERT_EQ(names.size(), kExpectedTotalCertCount); + std::set removed_certs; // Remove all even number listed files for (size_t i = 0; i < names.size(); ++i) { - if (i % 2 == 0) { - EXPECT_TRUE( - file_system_.Remove(wvcdm::test_vectors::kTestDir + names[i])); - } + if ((i % 2) != 0) continue; + const std::string& cert_filename = names[i]; + const std::string cert_path = PathJoin(dir_path, cert_filename); + ASSERT_TRUE(file_system_.Remove(cert_path)) + << "Failed to remove cert: " << cert_path; + removed_certs.insert(cert_filename); } // Verify that they have been removed - for (size_t i = 0; i < names.size(); ++i) { - if (i % 2 == 1) { - EXPECT_TRUE( - file_system_.Exists(wvcdm::test_vectors::kTestDir + names[i])); + for (const std::string& cert_filename : names) { + const std::string cert_path = PathJoin(dir_path, cert_filename); + if (removed_certs.find(cert_filename) == removed_certs.end()) { + // Ensure still exists. + ASSERT_TRUE(file_system_.Exists(cert_path)) + << "Cert missing: " << cert_filename; } else { - EXPECT_FALSE( - file_system_.Exists(wvcdm::test_vectors::kTestDir + names[i])); + ASSERT_FALSE(file_system_.Exists(cert_path)) + << "Cert not removed: " << cert_filename; } } - // Remove all odd number listed files - for (size_t i = 0; i < names.size(); ++i) { - if (i % 2 == 1) { - EXPECT_TRUE( - file_system_.Remove(wvcdm::test_vectors::kTestDir + names[i])); - } + // Remove all remaining. + for (const std::string& cert_filename : names) { + if (removed_certs.find(cert_filename) != removed_certs.end()) continue; + const std::string cert_path = PathJoin(dir_path, cert_filename); + ASSERT_TRUE(file_system_.Remove(cert_path)) + << "Failed to remove cert: " << cert_path; } // Verify that all have been removed - for (size_t i = 0; i < names.size(); ++i) { - EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir + names[i])); + for (const std::string& cert_filename : names) { + const std::string cert_path = PathJoin(dir_path, cert_filename); + EXPECT_FALSE(file_system_.Exists(cert_path)) + << "Cert not removed: " << cert_filename; } } - } // namespace wvutil