Cherry pick 18.4 changes to udc-widevine-dev
Get the udc-widevine-dev Android branch and oemcrypto-v18 cdm branch in sync. The commit ID for 18.4 on oemcrypto-v18 is a2f23a2281e5e06dc2867585bdc516fa132b6396. Merged from go/wvgerrit/190151 Bug: 290252845 Test: WVTS tests are running and passing Change-Id: I457332e7ca70a5b5169345e1279b3eb9f18413b6
This commit is contained in:
327
libwvdrmengine/cdm/cdm.gyp
Normal file
327
libwvdrmengine/cdm/cdm.gyp
Normal file
@@ -0,0 +1,327 @@
|
||||
# Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
||||
# source code may only be used and distributed under the Widevine License
|
||||
# Agreement.
|
||||
#
|
||||
# Refer to the distribution package's integration guide for information about
|
||||
# setting up your system, performing the build, and using/testing the build
|
||||
# targets.
|
||||
|
||||
{
|
||||
'includes': [
|
||||
'platform_properties.gypi',
|
||||
'core.gypi',
|
||||
'util.gypi',
|
||||
], # Get list of core source files.
|
||||
'variables': {
|
||||
'has_dual_key%': 'false',
|
||||
'embedded_cert%': '',
|
||||
},
|
||||
'targets': [
|
||||
{
|
||||
'toolsets' : [ 'target' ],
|
||||
'target_name': 'license_protocol',
|
||||
'type': 'static_library',
|
||||
'standalone_static_library': 1,
|
||||
'hard_dependency': 1,
|
||||
'includes': ['../third_party/disable_warnings.gypi'],
|
||||
'dependencies': [ '<(proto_gen_gyp_path):generate_license_protocol' ],
|
||||
'sources': [
|
||||
'<(proto_cc_dir)/license_protocol.pb.cc'
|
||||
],
|
||||
'include_dirs': [
|
||||
'<(proto_cc_dir)',
|
||||
'<(DEPTH)/third_party/protobuf/src'
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'<(proto_cc_dir)',
|
||||
'<(DEPTH)/third_party/protobuf/src'
|
||||
]
|
||||
},
|
||||
},
|
||||
{
|
||||
'toolsets' : [ 'target' ],
|
||||
'target_name': 'device_files',
|
||||
'type': 'static_library',
|
||||
'standalone_static_library': 1,
|
||||
'hard_dependency': 1,
|
||||
'includes': ['../third_party/disable_warnings.gypi'],
|
||||
'dependencies': [ '<(proto_gen_gyp_path):generate_device_files' ],
|
||||
'sources': [
|
||||
'<(proto_cc_dir)/device_files.pb.cc'
|
||||
],
|
||||
'include_dirs': [
|
||||
'<(proto_cc_dir)',
|
||||
'<(DEPTH)/third_party/protobuf/src'
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'<(proto_cc_dir)',
|
||||
'<(DEPTH)/third_party/protobuf/src'
|
||||
]
|
||||
},
|
||||
},
|
||||
{
|
||||
'toolsets' : [ 'target' ],
|
||||
'target_name': 'metrics_proto',
|
||||
'type': 'static_library',
|
||||
'standalone_static_library': 1,
|
||||
'hard_dependency': 1,
|
||||
'includes': ['../third_party/disable_warnings.gypi'],
|
||||
'dependencies': [ '<(proto_gen_gyp_path):generate_metrics_proto' ],
|
||||
'sources': [
|
||||
'<(proto_cc_dir)/wv_metrics.pb.cc'
|
||||
],
|
||||
'include_dirs': [
|
||||
'<(proto_cc_dir)',
|
||||
'<(DEPTH)/third_party/protobuf/src'
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'<(proto_cc_dir)',
|
||||
'<(DEPTH)/third_party/protobuf/src'
|
||||
]
|
||||
},
|
||||
},
|
||||
{
|
||||
'toolsets' : [ 'target' ],
|
||||
'target_name': 'widevine_utils',
|
||||
'type': 'static_library',
|
||||
'standalone_static_library': 1,
|
||||
'hard_dependency': 1,
|
||||
'include_dirs': [
|
||||
'../util/include',
|
||||
],
|
||||
'sources': [ '<@(wvutil_sources)'],
|
||||
},
|
||||
{
|
||||
'toolsets' : [ 'target' ],
|
||||
'target_name': 'widevine_cdm_core',
|
||||
'type': 'static_library',
|
||||
'standalone_static_library': 1,
|
||||
'hard_dependency': 1,
|
||||
'dependencies': [
|
||||
'device_files',
|
||||
'license_protocol',
|
||||
'metrics_proto',
|
||||
'widevine_utils',
|
||||
],
|
||||
'include_dirs': [
|
||||
'../core/include',
|
||||
'../metrics/include',
|
||||
'../oemcrypto/include',
|
||||
'../oemcrypto/odk/include',
|
||||
'../third_party/jsmn',
|
||||
'../util/include',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'../core/include',
|
||||
'../metrics/include',
|
||||
'../oemcrypto/include',
|
||||
'../util/include',
|
||||
],
|
||||
},
|
||||
'sources': [
|
||||
'<@(wvcdm_sources)',
|
||||
'../third_party/jsmn/jsmn.h',
|
||||
'../third_party/jsmn/jsmn.c',
|
||||
],
|
||||
'includes': [ '../util/libcrypto_dependency.gypi' ],
|
||||
'conditions': [
|
||||
['client_info_source=="compiled"', {
|
||||
'conditions': [
|
||||
['client_company_name=="" or " | " in client_company_name or "%" in client_company_name', {
|
||||
'sources': [ 'invalid_client_company_name.c' ],
|
||||
}],
|
||||
['client_model_name=="" or " | " in client_model_name or "%" in client_model_name', {
|
||||
'sources': [ 'invalid_client_model_name.c' ],
|
||||
}],
|
||||
# year may be a number, so use __str__ to convert to string. Can't use
|
||||
# str() since we can't use global functions.
|
||||
['client_model_year=="" or " | " in client_model_year.__str__() or "%" in client_model_year.__str__()', {
|
||||
'sources': [ 'invalid_client_model_year.c' ],
|
||||
}],
|
||||
['client_product_name=="" or " | " in client_product_name or "%" in client_product_name', {
|
||||
'sources': [ 'invalid_client_product_name.c' ],
|
||||
}],
|
||||
['client_device_name=="" or " | " in client_device_name or "%" in client_device_name', {
|
||||
'sources': [ 'invalid_client_device_name.c' ],
|
||||
}],
|
||||
['client_arch_name=="" or " | " in client_arch_name or "%" in client_arch_name', {
|
||||
'sources': [ 'invalid_client_arch_name.c' ],
|
||||
}],
|
||||
['client_platform=="" or " | " in client_platform or "%" in client_platform', {
|
||||
'sources': [ 'invalid_client_platform.c' ],
|
||||
}],
|
||||
['client_form_factor=="" or " | " in client_form_factor or "%" in client_form_factor', {
|
||||
'sources': [ 'invalid_client_form_factor.c' ],
|
||||
}],
|
||||
['client_version=="" or " | " in client_version or "%" in client_version', {
|
||||
'sources': [ 'invalid_client_version.c' ],
|
||||
}],
|
||||
],
|
||||
}],
|
||||
|
||||
['privacy_crypto_impl=="boringssl" or privacy_crypto_impl=="openssl"', {
|
||||
'sources': [
|
||||
'../core/src/privacy_crypto_boringssl.cpp',
|
||||
],
|
||||
}, { # else
|
||||
'sources': [
|
||||
'../core/src/privacy_crypto_<(privacy_crypto_impl).cpp',
|
||||
],
|
||||
'conditions': [
|
||||
['privacy_crypto_impl=="apple"', {
|
||||
'link_settings': {
|
||||
'libraries': [
|
||||
'$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
|
||||
'$(SDKROOT)/System/Library/Frameworks/Security.framework',
|
||||
],
|
||||
},
|
||||
}],
|
||||
],
|
||||
}], # end else
|
||||
['oemcrypto_adapter_type=="dynamic"', {
|
||||
'sources': [
|
||||
'../core/src/oemcrypto_adapter_dynamic.cpp',
|
||||
],
|
||||
}],
|
||||
['oemcrypto_adapter_type=="static"', {
|
||||
'sources': [
|
||||
'../core/src/oemcrypto_adapter_static.cpp',
|
||||
],
|
||||
}],
|
||||
['oemcrypto_adapter_type=="static_v16"', {
|
||||
'sources': [
|
||||
'../core/src/oemcrypto_adapter_static.cpp',
|
||||
'../core/src/oemcrypto_adapter_static_v17.cpp',
|
||||
],
|
||||
}],
|
||||
['has_dual_key=="true"', {
|
||||
'defines': ['HAS_DUAL_KEY'],
|
||||
}],
|
||||
['support_ota_keybox_functions=="false"', {
|
||||
'sources': [
|
||||
'../core/src/oemcrypto_ota_stubs.cpp',
|
||||
],
|
||||
}],
|
||||
],
|
||||
}, # widevine_cdm_core target
|
||||
{
|
||||
# This is the widevine_ce_cdm built as a static library. This name does
|
||||
# not mean that it uses oemcrypto's static adapter. Control over which
|
||||
# adapter is used comes from the settings file for the platform.
|
||||
'toolsets' : [ 'target' ],
|
||||
'target_name': 'widevine_ce_cdm_static',
|
||||
'type': 'static_library',
|
||||
'standalone_static_library': 1,
|
||||
'hard_dependency': 1,
|
||||
'dependencies': [
|
||||
'widevine_cdm_core',
|
||||
'device_files',
|
||||
'license_protocol',
|
||||
'metrics_proto',
|
||||
],
|
||||
# Without this, library deps do not propagate from the protocol targets
|
||||
# up to the shared lib or executable above.
|
||||
'export_dependent_settings': [
|
||||
'device_files',
|
||||
'license_protocol',
|
||||
'metrics_proto',
|
||||
],
|
||||
'defines': [
|
||||
'CDM_IMPLEMENTATION',
|
||||
],
|
||||
'include_dirs': [
|
||||
'include',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'include',
|
||||
],
|
||||
},
|
||||
'sources': [
|
||||
'include/cdm.h',
|
||||
'include/cdm_version.h',
|
||||
'include/properties_ce.h',
|
||||
'src/cdm.cpp',
|
||||
'src/log.cpp',
|
||||
'src/logger_global.cpp',
|
||||
'src/properties_ce.cpp',
|
||||
],
|
||||
'conditions': [
|
||||
['embedded_cert!=""', {
|
||||
'actions': [{
|
||||
'action_name': 'generate_cert',
|
||||
'msvs_cygwin_shell': 0,
|
||||
'message': 'Generating cert.cc',
|
||||
'inputs': [
|
||||
'create_cert_cc.py',
|
||||
'<(embedded_cert)',
|
||||
],
|
||||
'outputs': [
|
||||
'<(INTERMEDIATE_DIR)/cert.cc',
|
||||
],
|
||||
'action': [
|
||||
'python3',
|
||||
'>@(_inputs)',
|
||||
'>@(_outputs)',
|
||||
],
|
||||
}],
|
||||
'sources': [
|
||||
'<(INTERMEDIATE_DIR)/cert.cc',
|
||||
],
|
||||
'defines': ['HAS_EMBEDDED_CERT'],
|
||||
}], # embedded_cert!=""
|
||||
|
||||
# This block defines preprocessor values that match the client
|
||||
# information variables in platform properties.gypi. If you are writing
|
||||
# your own build files to build CE CDM insted of using these GYP files
|
||||
# and you are using compile-time client info, make sure to define these
|
||||
# values, following the rules in the client info section in
|
||||
# platform_properties.gypi.
|
||||
['client_info_source=="compiled"', {
|
||||
'defines': [
|
||||
'CLIENT_COMPANY_NAME="<(client_company_name)"',
|
||||
'CLIENT_MODEL_NAME="<(client_model_name)"',
|
||||
'CLIENT_MODEL_YEAR="<(client_model_year)"',
|
||||
'CLIENT_PRODUCT_NAME="<(client_product_name)"',
|
||||
'CLIENT_DEVICE_NAME="<(client_device_name)"',
|
||||
'CLIENT_ARCH_NAME="<(client_arch_name)"',
|
||||
'CLIENT_PLATFORM="<(client_platform)"',
|
||||
'CLIENT_FORM_FACTOR="<(client_form_factor)"',
|
||||
'CLIENT_VERSION="<(client_version)"',
|
||||
],
|
||||
}], # client_info_source=="compiled"
|
||||
|
||||
['client_info_source=="runtime"', {
|
||||
'defines': [
|
||||
'RUNTIME_CLIENT_INFO',
|
||||
],
|
||||
'dependencies': [
|
||||
'<(read_client_info_path)',
|
||||
],
|
||||
}], # client_info_source=="runtime"
|
||||
], # conditions
|
||||
}, # widevine_cdm_static target
|
||||
{
|
||||
'toolsets' : [ 'target' ],
|
||||
'target_name': 'widevine_ce_cdm_shared',
|
||||
'type': 'shared_library',
|
||||
'dependencies': [
|
||||
'widevine_ce_cdm_static',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'include',
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
'toolsets' : [ 'target' ],
|
||||
'target_name': 'dummy',
|
||||
'type': 'none',
|
||||
},
|
||||
],
|
||||
}
|
||||
134
libwvdrmengine/cdm/cdm_reboot_tests.gyp
Normal file
134
libwvdrmengine/cdm/cdm_reboot_tests.gyp
Normal file
@@ -0,0 +1,134 @@
|
||||
# Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
||||
# source code may only be used and distributed under the Widevine License
|
||||
# Agreement.
|
||||
#
|
||||
# Any top-level targets in this file (and their dependencies) will be built by
|
||||
# the CE CDM's ./build.py build system. Refer to the distribution package's
|
||||
# README for details.
|
||||
{
|
||||
'includes': [
|
||||
'platform_properties.gypi',
|
||||
],
|
||||
'variables': {
|
||||
# Directory where OEMCrypto header, test, and reference files lives.
|
||||
'oemcrypto_dir': '../oemcrypto',
|
||||
# Directory where widevine utilities live.
|
||||
'util_dir': '../util',
|
||||
'metrics_target': 'cdm.gyp:metrics_proto',
|
||||
'device_files_target': 'cdm.gyp:device_files',
|
||||
},
|
||||
'targets': [{
|
||||
'toolsets' : [ 'target' ],
|
||||
'target_name': 'widevine_ce_cdm_reboot_tests',
|
||||
'sources': [
|
||||
'test/cdm_reboot_test_main.cpp',
|
||||
'test/cdm_test_runner.cpp',
|
||||
'test/create_test_file_system.cpp',
|
||||
'test/test_host.cpp',
|
||||
'test/test_host.h',
|
||||
'../core/test/config_test_env.cpp',
|
||||
'../core/test/fake_provisioning_server.cpp',
|
||||
'../core/test/http_socket.cpp',
|
||||
'../core/test/license_holder.cpp',
|
||||
'../core/test/license_request.cpp',
|
||||
'../core/test/message_dumper.cpp',
|
||||
'../core/test/provisioning_holder.cpp',
|
||||
'../core/test/reboot_test.cpp',
|
||||
'../core/test/test_base.cpp',
|
||||
'../core/test/test_printers.cpp',
|
||||
'../core/test/url_request.cpp',
|
||||
'../oemcrypto/test/oec_key_deriver.cpp',
|
||||
'../oemcrypto/test/oec_device_features.cpp',
|
||||
'../util/test/test_sleep.cpp',
|
||||
],
|
||||
'includes': [
|
||||
'../oemcrypto/odk/src/kdo.gypi',
|
||||
'../util/libssl_dependency.gypi',
|
||||
],
|
||||
'include_dirs': [
|
||||
'../cdm/include',
|
||||
'../core/include',
|
||||
'../core/test',
|
||||
'../metrics/include',
|
||||
'../oemcrypto/test',
|
||||
'../oemcrypto/include',
|
||||
'../util/include',
|
||||
'../util/test',
|
||||
],
|
||||
'dependencies': [
|
||||
'cdm.gyp:widevine_ce_cdm_static',
|
||||
'../oemcrypto/odk/src/odk.gyp:odk',
|
||||
'../third_party/googletest.gyp:gmock',
|
||||
'../third_party/googletest.gyp:gtest',
|
||||
'<(metrics_target)',
|
||||
'<(device_files_target)',
|
||||
],
|
||||
'defines': [
|
||||
'UNIT_TEST',
|
||||
'CDM_TESTS',
|
||||
],
|
||||
'msvs_settings': {
|
||||
'VCLinkerTool': {
|
||||
# Additionally, since they are loaded locally, suppress these
|
||||
# warnings.
|
||||
'AdditionalOptions': [
|
||||
'/IGNORE:4049',
|
||||
'/IGNORE:4217',
|
||||
],
|
||||
},
|
||||
},
|
||||
'conditions': [
|
||||
['OS=="ios"', {
|
||||
'type': 'loadable_module',
|
||||
'mac_xctest_bundle': '1',
|
||||
'defines': [
|
||||
'GTEST_FILTER="<(gtest_filter)"',
|
||||
],
|
||||
'dependencies': [
|
||||
'cdm_unittests.gyp:dummy_app',
|
||||
],
|
||||
'sources': [
|
||||
'test/gtest_xctest_wrapper.mm',
|
||||
],
|
||||
'xcode_settings': {
|
||||
'BUNDLE_LOADER': '$(TEST_HOST)',
|
||||
'TEST_HOST': '<(PRODUCT_DIR)/dummy_app.app/dummy_app',
|
||||
'WRAPPER_EXTENSION': 'xctest',
|
||||
},
|
||||
}, {
|
||||
'type': 'executable',
|
||||
}],
|
||||
# TODO(b/139814713): For testing and internal use only.
|
||||
['oemcrypto_adapter_type=="static_v15"', {
|
||||
'defines': [
|
||||
# This is used by the unit tests to use some v15 functions.
|
||||
'TEST_OEMCRYPTO_V15',
|
||||
],
|
||||
}],
|
||||
['oemcrypto_lib=="level3"', {
|
||||
'sources': [
|
||||
# The test impl of OEMCrypto_Level3FileSystem and its factory.
|
||||
'test/level3_file_system_ce_test.h',
|
||||
'test/level3_file_system_ce_test.cpp',
|
||||
'test/level3_file_system_ce_test_factory.cpp',
|
||||
],
|
||||
'conditions': [
|
||||
['oemcrypto_adapter_type=="dynamic" ', {
|
||||
'dependencies': [
|
||||
'../oemcrypto/level3/oec_level3.gyp:oec_level3_dynamic',
|
||||
],
|
||||
}, {
|
||||
'dependencies': [
|
||||
'../oemcrypto/level3/oec_level3.gyp:oec_level3_static',
|
||||
],
|
||||
}],
|
||||
],
|
||||
}],
|
||||
['oemcrypto_lib=="target"', {
|
||||
'dependencies': [
|
||||
'<(oemcrypto_gyp_path)',
|
||||
],
|
||||
}],
|
||||
],
|
||||
}],
|
||||
}
|
||||
242
libwvdrmengine/cdm/cdm_unittests.gyp
Normal file
242
libwvdrmengine/cdm/cdm_unittests.gyp
Normal file
@@ -0,0 +1,242 @@
|
||||
# Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
||||
# source code may only be used and distributed under the Widevine License
|
||||
# Agreement.
|
||||
#
|
||||
# Any top-level targets in this file (and their dependencies) will be built by
|
||||
# the CE CDM's ./build.py build system. Refer to the distribution package's
|
||||
# README for details.
|
||||
{
|
||||
'includes': [
|
||||
'platform_properties.gypi',
|
||||
],
|
||||
'variables': {
|
||||
# Directory where OEMCrypto header, test, and reference files lives.
|
||||
'oemcrypto_dir': '../oemcrypto',
|
||||
# Directory where widevine utilities live.
|
||||
'util_dir': '../util',
|
||||
'metrics_target': 'cdm.gyp:metrics_proto',
|
||||
'device_files_target': 'cdm.gyp:device_files',
|
||||
# The path to the prebuilt CDM to test against. (iOS only)
|
||||
'prebuilt_cdm_path%': '',
|
||||
'supports_dynamic_perf_test%': 0,
|
||||
'json_dir': '../third_party/nlohmann-json',
|
||||
'jsmn_dir': '../third_party/jsmn',
|
||||
},
|
||||
'targets': [{
|
||||
'toolsets' : [ 'target' ],
|
||||
'target_name': 'widevine_ce_cdm_unittest',
|
||||
'sources': [
|
||||
'test/cdm_test_main.cpp',
|
||||
'test/cdm_test_runner.cpp',
|
||||
'test/create_test_file_system.cpp',
|
||||
# The test host, which is required for all test suites on CE.
|
||||
'test/test_host.cpp',
|
||||
'test/test_host.h',
|
||||
'../util/test/test_sleep.cpp',
|
||||
],
|
||||
'includes': [
|
||||
'../oemcrypto/test/oemcrypto_unittests.gypi',
|
||||
'../oemcrypto/odk/src/kdo.gypi',
|
||||
'../oemcrypto/odk/test/odk_test.gypi',
|
||||
'../oemcrypto/util/oec_ref_util_unittests.gypi',
|
||||
'cdm_unittests.gypi',
|
||||
'core_unittests.gypi',
|
||||
'util_unittests.gypi',
|
||||
],
|
||||
'dependencies': [
|
||||
'cdm.gyp:widevine_ce_cdm_static',
|
||||
'../oemcrypto/util/oec_ref_util.gyp:oec_ref_util',
|
||||
'../third_party/googletest.gyp:gmock',
|
||||
'../third_party/googletest.gyp:gtest',
|
||||
],
|
||||
'msvs_settings': {
|
||||
'VCLinkerTool': {
|
||||
# Additionally, since they are loaded locally, suppress these
|
||||
# warnings.
|
||||
'AdditionalOptions': [
|
||||
'/IGNORE:4049',
|
||||
'/IGNORE:4217',
|
||||
],
|
||||
},
|
||||
},
|
||||
'conditions': [
|
||||
['OS=="ios"', {
|
||||
'type': 'loadable_module',
|
||||
'mac_xctest_bundle': '1',
|
||||
'defines': [
|
||||
'GTEST_FILTER="<(gtest_filter)"',
|
||||
],
|
||||
'dependencies': [
|
||||
'dummy_app',
|
||||
],
|
||||
'sources': [
|
||||
'test/gtest_xctest_wrapper.mm',
|
||||
],
|
||||
'xcode_settings': {
|
||||
'BUNDLE_LOADER': '$(TEST_HOST)',
|
||||
'INFOPLIST_FILE': 'test/info.plist',
|
||||
'PRODUCT_BUNDLE_IDENTIFIER': 'EQHXZ8M8AV.widevine_ce_cdm_unittest',
|
||||
'TEST_HOST': '<(PRODUCT_DIR)/dummy_app.app/dummy_app',
|
||||
'WRAPPER_EXTENSION': 'xctest',
|
||||
},
|
||||
}, {
|
||||
'type': 'executable',
|
||||
}],
|
||||
# TODO(b/139814713): For testing and internal use only.
|
||||
['oemcrypto_adapter_type=="static_v15"', {
|
||||
'defines': [
|
||||
# This is used by the unit tests to use some v15 functions.
|
||||
'TEST_OEMCRYPTO_V15',
|
||||
],
|
||||
}],
|
||||
['oemcrypto_lib=="level3"', {
|
||||
'sources': [
|
||||
# The test impl of OEMCrypto_Level3FileSystem and its factory.
|
||||
'test/level3_file_system_ce_test.h',
|
||||
'test/level3_file_system_ce_test.cpp',
|
||||
'test/level3_file_system_ce_test_factory.cpp',
|
||||
],
|
||||
'conditions': [
|
||||
['oemcrypto_adapter_type=="dynamic" ', {
|
||||
'dependencies': [
|
||||
'../oemcrypto/level3/oec_level3.gyp:oec_level3_dynamic',
|
||||
],
|
||||
}, {
|
||||
'dependencies': [
|
||||
'../oemcrypto/level3/oec_level3.gyp:oec_level3_static',
|
||||
],
|
||||
}],
|
||||
],
|
||||
}],
|
||||
['oemcrypto_lib=="target"', {
|
||||
'dependencies': [
|
||||
'<(oemcrypto_gyp_path)',
|
||||
],
|
||||
}],
|
||||
],
|
||||
}],
|
||||
'conditions': [
|
||||
['supports_dynamic_perf_test', {
|
||||
'targets': [{
|
||||
'target_name': 'widevine_perf_test_dynamic',
|
||||
'type': 'executable',
|
||||
'sources': [
|
||||
'../core/test/config_test_env.cpp',
|
||||
'../core/test/http_socket.cpp',
|
||||
'../core/test/license_request.cpp',
|
||||
'../core/test/url_request.cpp',
|
||||
'../util/src/string_conversions.cpp',
|
||||
'../util/src/string_format.cpp',
|
||||
'../util/test/test_sleep.cpp',
|
||||
'src/log.cpp',
|
||||
'src/logger_global.cpp',
|
||||
'test/perf_test.cpp',
|
||||
'test/perf_test_dynamic.cpp',
|
||||
'test/test_host.cpp',
|
||||
],
|
||||
'includes': [ '../util/libssl_dependency.gypi' ],
|
||||
'include_dirs': [
|
||||
'../core/include',
|
||||
'../core/test',
|
||||
'../oemcrypto/include',
|
||||
'../util/include',
|
||||
'../util/test',
|
||||
'include',
|
||||
],
|
||||
'dependencies': [
|
||||
'../third_party/googletest.gyp:gmock',
|
||||
'../third_party/googletest.gyp:gtest',
|
||||
],
|
||||
'conditions': [
|
||||
['OS=="linux"', {
|
||||
'libraries': [ '-ldl' ],
|
||||
}],
|
||||
],
|
||||
}],
|
||||
}], # condition: supports_dynamic_perf_test
|
||||
['OS=="ios"', {
|
||||
'targets': [{
|
||||
'toolsets' : [ 'target' ],
|
||||
'target_name': 'dummy_app',
|
||||
'type': 'executable',
|
||||
'mac_bundle': '1',
|
||||
'sources': [
|
||||
'test/dummy_app.mm',
|
||||
],
|
||||
'libraries': [
|
||||
'CoreFoundation.framework',
|
||||
'UIKit.framework',
|
||||
],
|
||||
'xcode_settings': {
|
||||
'INFOPLIST_FILE': 'test/info.plist',
|
||||
},
|
||||
'conditions': [
|
||||
['prebuilt_cdm_path!=""', {
|
||||
'copies': [{
|
||||
'destination': '<(PRODUCT_DIR)/dummy_app.app/Frameworks',
|
||||
'xcode_code_sign': 1,
|
||||
'files': [
|
||||
# GYP seems to always use relative paths here, even if they
|
||||
# start with '/'.
|
||||
'<!(realpath --relative-to=. "<(prebuilt_cdm_path)")',
|
||||
],
|
||||
}],
|
||||
}],
|
||||
],
|
||||
}],
|
||||
'conditions': [
|
||||
['supports_dynamic_perf_test', {
|
||||
'targets': [{
|
||||
'target_name': 'widevine_perf_test_xctest',
|
||||
'type': 'loadable_module',
|
||||
'mac_xctest_bundle': '1',
|
||||
'defines': [
|
||||
'GTEST_FILTER="<(gtest_filter)"',
|
||||
],
|
||||
'xcode_settings': {
|
||||
'BUNDLE_LOADER': '$(TEST_HOST)',
|
||||
'INFOPLIST_FILE': 'test/info.plist',
|
||||
'PRODUCT_BUNDLE_IDENTIFIER': 'EQHXZ8M8AV.widevine_perf_test_xctest',
|
||||
'TEST_HOST': '<(PRODUCT_DIR)/dummy_app.app/dummy_app',
|
||||
'WRAPPER_EXTENSION': 'xctest',
|
||||
|
||||
'OTHER_LDFLAGS': [
|
||||
'-iframework',
|
||||
'<(prebuilt_cdm_path)/..',
|
||||
],
|
||||
},
|
||||
'libraries': [
|
||||
'<(prebuilt_cdm_path)',
|
||||
],
|
||||
'sources': [
|
||||
'../core/test/config_test_env.cpp',
|
||||
'../core/test/http_socket.cpp',
|
||||
'../core/test/license_request.cpp',
|
||||
'../core/test/url_request.cpp',
|
||||
'../util/src/string_conversions.cpp',
|
||||
'../util/test/test_clock.cpp',
|
||||
'../util/test/test_sleep.cpp',
|
||||
'src/log.cpp',
|
||||
'test/perf_test.cpp',
|
||||
'test/perf_test_xctest.mm',
|
||||
'test/test_host.cpp',
|
||||
],
|
||||
'includes': [ '../util/libssl_dependency.gypi' ],
|
||||
'include_dirs': [
|
||||
'../core/include',
|
||||
'../core/test',
|
||||
'../util/include',
|
||||
'../util/test',
|
||||
'include',
|
||||
],
|
||||
'dependencies': [
|
||||
'../third_party/googletest.gyp:gmock',
|
||||
'../third_party/googletest.gyp:gtest',
|
||||
'dummy_app',
|
||||
],
|
||||
}],
|
||||
}], # condition: supports_dynamic_perf_test
|
||||
],
|
||||
}], # condition: OS=="ios"
|
||||
],
|
||||
}
|
||||
40
libwvdrmengine/cdm/cdm_unittests.gypi
Normal file
40
libwvdrmengine/cdm/cdm_unittests.gypi
Normal file
@@ -0,0 +1,40 @@
|
||||
# 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 this in any custom unit test targets.
|
||||
# Does not include the device certificate or the test runner main.
|
||||
{
|
||||
'cflags_cc+': [
|
||||
'-Wno-inconsistent-missing-override',
|
||||
],
|
||||
'sources': [
|
||||
'../core/test/http_socket.cpp',
|
||||
'../core/test/license_request.cpp',
|
||||
'../core/test/url_request.cpp',
|
||||
|
||||
'test/cdm_test.cpp',
|
||||
'test/cdm_test_printers.cpp',
|
||||
'test/cdm_test_printers.h',
|
||||
'test/test_host.cpp',
|
||||
'test/test_host.h',
|
||||
|
||||
'../util/test/test_sleep.cpp',
|
||||
],
|
||||
'conditions': [
|
||||
['support_ota_keybox_functions=="true"', {
|
||||
'sources': [
|
||||
'../core/test/keybox_ota_test.cpp',
|
||||
],
|
||||
}],
|
||||
],
|
||||
'include_dirs': [
|
||||
'../core/test',
|
||||
'../util/test',
|
||||
],
|
||||
'defines': [
|
||||
'UNIT_TEST',
|
||||
'CDM_TESTS',
|
||||
],
|
||||
'includes': [ '../util/libssl_dependency.gypi' ],
|
||||
}
|
||||
80
libwvdrmengine/cdm/core.gypi
Normal file
80
libwvdrmengine/cdm/core.gypi
Normal file
@@ -0,0 +1,80 @@
|
||||
# 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 this in any custom unit test targets.
|
||||
# Does not include the test runner main.
|
||||
{
|
||||
'variables': {
|
||||
'wvcdm_sources': [
|
||||
'../core/include/buffer_reader.h',
|
||||
'../core/include/cdm_client_property_set.h',
|
||||
'../core/include/cdm_engine.h',
|
||||
'../core/include/cdm_engine_factory.h',
|
||||
'../core/include/cdm_engine_metrics_decorator.h',
|
||||
'../core/include/cdm_session.h',
|
||||
'../core/include/cdm_session_map.h',
|
||||
'../core/include/cdm_usage_table.h',
|
||||
'../core/include/certificate_provisioning.h',
|
||||
'../core/include/client_identification.h',
|
||||
'../core/include/content_key_session.h',
|
||||
'../core/include/crypto_key.h',
|
||||
'../core/include/crypto_session.h',
|
||||
'../core/include/crypto_wrapped_key.h',
|
||||
'../core/include/device_files.h',
|
||||
'../core/include/entitlement_key_session.h',
|
||||
'../core/include/initialization_data.h',
|
||||
'../core/include/key_session.h',
|
||||
'../core/include/license_key_status.h',
|
||||
'../core/include/license.h',
|
||||
'../core/include/oemcrypto_adapter.h',
|
||||
'../core/include/okp_fallback_policy.h',
|
||||
'../core/include/okp_info.h',
|
||||
'../core/include/ota_keybox_provisioner.h',
|
||||
'../core/include/policy_engine.h',
|
||||
'../core/include/policy_timers.h',
|
||||
'../core/include/policy_timers_v16.h',
|
||||
'../core/include/policy_timers_v18.h',
|
||||
'../core/include/privacy_crypto.h',
|
||||
'../core/include/properties.h',
|
||||
'../core/include/service_certificate.h',
|
||||
'../core/include/wv_cdm_constants.h',
|
||||
'../core/include/wv_cdm_event_listener.h',
|
||||
'../core/include/wv_cdm_types.h',
|
||||
'../core/src/buffer_reader.cpp',
|
||||
'../core/src/cdm_engine.cpp',
|
||||
'../core/src/cdm_engine_factory.cpp',
|
||||
'../core/src/cdm_session.cpp',
|
||||
'../core/src/cdm_session_map.cpp',
|
||||
'../core/src/cdm_usage_table.cpp',
|
||||
'../core/src/certificate_provisioning.cpp',
|
||||
'../core/src/client_identification.cpp',
|
||||
'../core/src/content_key_session.cpp',
|
||||
'../core/src/crypto_session.cpp',
|
||||
'../core/src/device_files.cpp',
|
||||
'../core/src/entitlement_key_session.cpp',
|
||||
'../core/src/initialization_data.cpp',
|
||||
'../core/src/license.cpp',
|
||||
'../core/src/license_key_status.cpp',
|
||||
'../core/src/license_protocol_conversions.cpp',
|
||||
'../core/src/okp_fallback_policy.cpp',
|
||||
'../core/src/okp_info.cpp',
|
||||
'../core/src/ota_keybox_provisioner.cpp',
|
||||
'../core/src/policy_engine.cpp',
|
||||
'../core/src/policy_timers.cpp',
|
||||
'../core/src/policy_timers_v16.cpp',
|
||||
'../core/src/policy_timers_v18.cpp',
|
||||
'../core/src/properties.cpp',
|
||||
'../core/src/service_certificate.cpp',
|
||||
'../core/src/system_id_extractor.cpp',
|
||||
'../core/src/wv_cdm_types.cpp',
|
||||
'../metrics/src/attribute_handler.cpp',
|
||||
'../metrics/src/counter_metric.cpp',
|
||||
'../metrics/src/distribution.cpp',
|
||||
'../metrics/src/event_metric.cpp',
|
||||
'../metrics/src/metrics_collections.cpp',
|
||||
'../metrics/src/timer_metric.cpp',
|
||||
'../metrics/src/value_metric.cpp',
|
||||
],
|
||||
},
|
||||
}
|
||||
65
libwvdrmengine/cdm/core_unittests.gypi
Normal file
65
libwvdrmengine/cdm/core_unittests.gypi
Normal file
@@ -0,0 +1,65 @@
|
||||
# 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 this in any custom unit test targets.
|
||||
# Does not include the test runner main.
|
||||
{
|
||||
'sources': [
|
||||
'../core/test/buffer_reader_test.cpp',
|
||||
'../core/test/cdm_engine_test.cpp',
|
||||
'../core/test/cdm_engine_metrics_decorator_unittest.cpp',
|
||||
'../core/test/cdm_session_unittest.cpp',
|
||||
'../core/test/cdm_usage_table_unittest.cpp',
|
||||
'../core/test/config_test_env.cpp',
|
||||
'../core/test/certificate_provisioning_unittest.cpp',
|
||||
'../core/test/crypto_session_unittest.cpp',
|
||||
'../core/test/device_files_unittest.cpp',
|
||||
'../core/test/duration_use_case_test.cpp',
|
||||
'../core/test/fake_provisioning_server.cpp',
|
||||
'../core/test/generic_crypto_unittest.cpp',
|
||||
'../core/test/http_socket.cpp',
|
||||
'../core/test/http_socket_test.cpp',
|
||||
'../core/test/initialization_data_unittest.cpp',
|
||||
'../core/test/license_holder.cpp',
|
||||
'../core/test/license_keys_unittest.cpp',
|
||||
'../core/test/license_request.cpp',
|
||||
'../core/test/license_unittest.cpp',
|
||||
'../core/test/message_dumper.cpp',
|
||||
'../core/test/okp_fallback_policy_test.cpp',
|
||||
'../core/test/ota_keybox_provisioner_test.cpp',
|
||||
'../core/test/parallel_operations_test.cpp',
|
||||
'../core/test/policy_engine_constraints_unittest.cpp',
|
||||
'../core/test/policy_engine_unittest.cpp',
|
||||
'../core/test/policy_integration_test.cpp',
|
||||
'../core/test/provisioning_holder.cpp',
|
||||
'../core/test/rw_lock_test.cpp',
|
||||
'../core/test/service_certificate_unittest.cpp',
|
||||
'../core/test/system_id_extractor_unittest.cpp',
|
||||
'../core/test/test_base.cpp',
|
||||
'../core/test/test_printers.cpp',
|
||||
'../core/test/url_request.cpp',
|
||||
'../core/test/url_request_unittest.cpp',
|
||||
'../metrics/test/counter_metric_unittest.cpp',
|
||||
'../metrics/test/distribution_unittest.cpp',
|
||||
'../metrics/test/event_metric_unittest.cpp',
|
||||
'../metrics/test/metrics_collections_unittest.cpp',
|
||||
'../metrics/test/value_metric_unittest.cpp',
|
||||
],
|
||||
'include_dirs': [
|
||||
'../cdm/include',
|
||||
'../core/include',
|
||||
'../core/test',
|
||||
'../metrics/include',
|
||||
'../util/include',
|
||||
],
|
||||
'defines': [
|
||||
'UNIT_TEST',
|
||||
'CORE_TESTS',
|
||||
],
|
||||
'dependencies': [
|
||||
'<(metrics_target)',
|
||||
'<(device_files_target)',
|
||||
],
|
||||
'includes': [ '../util/libssl_dependency.gypi' ],
|
||||
}
|
||||
34
libwvdrmengine/cdm/create_cert_cc.py
Executable file
34
libwvdrmengine/cdm/create_cert_cc.py
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/python3
|
||||
# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||
# source code may only be used and distributed under the Widevine License
|
||||
# Agreement.
|
||||
|
||||
"""Creates a cert.cc file from a cert.bin file."""
|
||||
|
||||
import argparse
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('input')
|
||||
parser.add_argument('output')
|
||||
parser.add_argument('--variable', default='DeviceCert')
|
||||
|
||||
options = parser.parse_args(sys.argv[1:])
|
||||
in_path = pathlib.Path(options.input)
|
||||
dat = ', '.join(str(x) for x in in_path.read_bytes())
|
||||
out_path = pathlib.Path(options.output)
|
||||
out_path.write_text(f"""// Copyright 2021 Google LLC. All Rights Reserved.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
namespace widevine {{
|
||||
|
||||
extern const uint8_t k{options.variable}[];
|
||||
const uint8_t k{options.variable}[] = {{ {dat} }};
|
||||
|
||||
extern const size_t k{options.variable}Size;
|
||||
const size_t k{options.variable}Size = sizeof(k{options.variable});
|
||||
|
||||
}} // namespace widevine""")
|
||||
953
libwvdrmengine/cdm/include/cdm.h
Normal file
953
libwvdrmengine/cdm/include/cdm.h
Normal file
@@ -0,0 +1,953 @@
|
||||
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
// Based on the EME draft spec from 2016 June 10.
|
||||
// http://www.w3.org/TR/2016/WD-encrypted-media-20160610/"
|
||||
#ifndef WVCDM_CDM_CDM_H_
|
||||
#define WVCDM_CDM_CDM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Uncomment this line when making static CDM builds. This will be edited by
|
||||
// release scripts.
|
||||
//#define CDM_STATIC 1
|
||||
|
||||
// Define CDM_EXPORT to export functionality across shared library boundaries.
|
||||
#if defined(CDM_STATIC)
|
||||
# define CDM_EXPORT
|
||||
#else
|
||||
# if defined(_WIN32)
|
||||
# if defined(CDM_IMPLEMENTATION)
|
||||
# define CDM_EXPORT __declspec(dllexport)
|
||||
# else
|
||||
# define CDM_EXPORT __declspec(dllimport)
|
||||
# endif // defined(CDM_IMPLEMENTATION)
|
||||
# else // defined(_WIN32)
|
||||
# if defined(CDM_IMPLEMENTATION)
|
||||
# define CDM_EXPORT __attribute__((visibility("default")))
|
||||
# else
|
||||
# define CDM_EXPORT
|
||||
# endif
|
||||
# endif // defined(_WIN32)
|
||||
#endif // defined(CDM_STATIC)
|
||||
|
||||
namespace widevine {
|
||||
|
||||
class CDM_EXPORT ITimerClient {
|
||||
public:
|
||||
virtual ~ITimerClient() {}
|
||||
|
||||
// Called by ITimer when a timer expires.
|
||||
virtual void onTimerExpired(void* context) = 0;
|
||||
|
||||
protected:
|
||||
ITimerClient() {}
|
||||
};
|
||||
|
||||
class CDM_EXPORT Cdm : public ITimerClient {
|
||||
public:
|
||||
// Session types defined by EME.
|
||||
enum SessionType : int32_t {
|
||||
kTemporary = 0,
|
||||
kPersistentLicense = 1,
|
||||
kPersistent = kPersistentLicense, // deprecated name from June 1 draft
|
||||
// kPersistentUsageRecord = 2, // deprecated, no longer supported.
|
||||
};
|
||||
|
||||
// Message types defined by EME.
|
||||
enum MessageType : int32_t {
|
||||
kLicenseRequest = 0,
|
||||
kLicenseRenewal = 1,
|
||||
kLicenseRelease = 2,
|
||||
kIndividualizationRequest = 3, // Not used. Direct Individualization
|
||||
// is used instead of App-Assisted
|
||||
};
|
||||
|
||||
// Status codes returned by CDM functions.
|
||||
//
|
||||
enum Status : int32_t {
|
||||
kSuccess = 0,
|
||||
|
||||
// These are analogous to the exceptions defined in the EME specification.
|
||||
// Client implementations that support the EME API should pass these
|
||||
// directly to the client application.
|
||||
// Note: kTypeError replaced kInvalidAccess in the 6/1/2015 EME spec.
|
||||
kTypeError = 1,
|
||||
kNotSupported = 2,
|
||||
kInvalidState = 3,
|
||||
kQuotaExceeded = 4,
|
||||
|
||||
// These are additional codes defined by Widevine. In client implementations
|
||||
// that support the EME API, these codes should be handled in the system
|
||||
// layer. If it is necessary to notify the client application of one of
|
||||
// these statuses, it should be mapped to one of the exception codes defined
|
||||
// in the EME specification. Some of these errors are considered
|
||||
// "recoverable" in that there are specific known remedies that the client
|
||||
// may take in response to them. See the Integration Guide for further
|
||||
// information.
|
||||
kNeedsDeviceCertificate = 101, // Recoverable
|
||||
kSessionNotFound = 102,
|
||||
kDecryptError = 103,
|
||||
kNoKey = 104,
|
||||
kKeyUsageBlockedByPolicy = 105,
|
||||
kRangeError = 106,
|
||||
kResourceContention = 107, // Recoverable
|
||||
kSessionStateLost = 108, // Recoverable
|
||||
kSystemStateLost = 109, // Recoverable
|
||||
kOutputTooLarge = 110, // Recoverable
|
||||
kNeedsServiceCertificate = 111, // Recoverable
|
||||
|
||||
// This covers errors that we do not expect (see logs for details):
|
||||
kUnexpectedError = 99999,
|
||||
};
|
||||
|
||||
// These are the init data types defined by EME.
|
||||
enum InitDataType : int32_t {
|
||||
kCenc = 0,
|
||||
kKeyIds = 1, // NOTE: not supported by Widevine at this time
|
||||
kWebM = 2,
|
||||
|
||||
// This type is not defined by EME but is supported by Widevine
|
||||
kHls = 10000,
|
||||
};
|
||||
|
||||
// These are the crypto schemes supported by CENC 3.0.
|
||||
enum EncryptionScheme : int32_t {
|
||||
kClear = 0,
|
||||
kAesCtr = 1, // AES-CTR, for use with the "cenc" schema
|
||||
kAesCbc = 2, // AES-CBC, for use with the "cbcs" schema
|
||||
};
|
||||
|
||||
// These are key statuses defined by EME.
|
||||
enum KeyStatus : int32_t {
|
||||
kUsable = 0,
|
||||
kExpired = 1,
|
||||
kOutputRestricted = 2,
|
||||
kOutputNotAllowed = kOutputRestricted, // deprecated name from June 1 draft
|
||||
kStatusPending = 3,
|
||||
kInternalError = 4,
|
||||
kReleased = 5,
|
||||
};
|
||||
|
||||
// These are the possible HDCP levels supported by Widevine.
|
||||
// For ease of comparison, these values are kept in ascending order by version
|
||||
// number.
|
||||
enum HdcpVersion : int32_t {
|
||||
kHdcp1_x = 0,
|
||||
kHdcp2_0 = 1,
|
||||
kHdcp2_1 = 2,
|
||||
kHdcp2_2 = 3,
|
||||
kHdcp2_3 = 4,
|
||||
};
|
||||
|
||||
// Permissible usages for a key. Returned as a set of flags; multiple
|
||||
// flags may be set. The specific settings are defined in the license
|
||||
// and the OEMCrypto Key Control Block. The CDM uses settings in the
|
||||
// license to derive these flags.
|
||||
typedef uint32_t KeyAllowedUsageFlags;
|
||||
static const KeyAllowedUsageFlags kAllowNone = 0;
|
||||
static const KeyAllowedUsageFlags kAllowDecryptToClearBuffer = 1;
|
||||
static const KeyAllowedUsageFlags kAllowDecryptToSecureBuffer = 2;
|
||||
static const KeyAllowedUsageFlags kAllowGenericEncrypt = 4;
|
||||
static const KeyAllowedUsageFlags kAllowGenericDecrypt = 8;
|
||||
static const KeyAllowedUsageFlags kAllowGenericSign = 16;
|
||||
static const KeyAllowedUsageFlags kAllowGenericSignatureVerify = 32;
|
||||
|
||||
// These are defined by Widevine. The CDM can be configured to decrypt in
|
||||
// three modes (dependent on OEMCrypto support).
|
||||
enum SecureOutputType : int32_t {
|
||||
// Data is decrypted to an opaque handle.
|
||||
// Translates to OEMCrypto's OEMCrypto_BufferType_Secure.
|
||||
kOpaqueHandle = 0,
|
||||
|
||||
// Decrypted data never returned to the caller, but is decoded and rendered
|
||||
// by OEMCrypto.
|
||||
// Translates to OEMCrypto's OEMCrypto_BufferType_Direct.
|
||||
kDirectRender = 1,
|
||||
|
||||
// There is no secure output available, so all data is decrypted into a
|
||||
// clear buffer in main memory.
|
||||
// Translates to OEMCrypto's OEMCrypto_BufferType_Clear.
|
||||
kNoSecureOutput = 2,
|
||||
};
|
||||
|
||||
// Logging levels defined by Widevine.
|
||||
// See Cdm::initialize().
|
||||
enum LogLevel : int32_t {
|
||||
kSilent = -1,
|
||||
kErrors = 0,
|
||||
kWarnings = 1,
|
||||
kInfo = 2,
|
||||
kDebug = 3,
|
||||
kVerbose = 4,
|
||||
};
|
||||
|
||||
// Types of service defined by Widevine.
|
||||
// The service certificate installation methods - Cdm::setServiceCertificate()
|
||||
// and Cdm::parseAndLoadServiceCertificateResponse() - use these to identify
|
||||
// which service the certificate is intended for.
|
||||
enum ServiceRole : int32_t {
|
||||
kAllServices = 0,
|
||||
kProvisioningService = 1,
|
||||
kLicensingService = 2,
|
||||
};
|
||||
|
||||
// These are the available Widevine robustness levels.
|
||||
enum RobustnessLevel : int32_t {
|
||||
kL1 = 1,
|
||||
kL2 = 2,
|
||||
kL3 = 3,
|
||||
};
|
||||
|
||||
// Status code returned by getProvisioningStatus API.
|
||||
enum ProvisioningStatus : int32_t {
|
||||
kProvisioned = 0,
|
||||
kUnknownProvisionStatus = 1,
|
||||
kNeedsDrmCertProvisioning = 2,
|
||||
kNeedsOemCertProvisioning = 3,
|
||||
};
|
||||
|
||||
// A map of key statuses.
|
||||
// See Cdm::getKeyStatuses().
|
||||
typedef std::map<std::string, KeyStatus> KeyStatusMap;
|
||||
|
||||
// An event listener interface provided by the application and attached to
|
||||
// each CDM session.
|
||||
// See Cdm::createSession().
|
||||
class IEventListener {
|
||||
public:
|
||||
virtual ~IEventListener() {}
|
||||
|
||||
// A message (license request, renewal, etc.) to be dispatched to the
|
||||
// application's license server.
|
||||
// The response, if successful, should be provided back to the CDM via a
|
||||
// call to Cdm::update().
|
||||
//
|
||||
// The |server_url| parameter is not part of EME and may be ignored
|
||||
// on EME-based integrations. It will be blank for initial license requests
|
||||
// but filled in for renewal and release messages. It's offered for the use
|
||||
// of apps that want to know the URL to send renewals and releases to
|
||||
// without hardcoding it or retrieving it out-of-band.
|
||||
virtual void onMessage(const std::string& session_id,
|
||||
MessageType message_type, const std::string& message,
|
||||
const std::string& server_url) = 0;
|
||||
|
||||
// There has been a change in the keys in the session or their status.
|
||||
virtual void onKeyStatusesChange(const std::string& session_id,
|
||||
bool has_new_usable_key) = 0;
|
||||
|
||||
// Called when the CDM changes the expiration time for a session.
|
||||
// |new_expiration| is in milliseconds since 1970 UTC. If the license
|
||||
// doesn't expire, it'll be -1.
|
||||
virtual void onExpirationChange(const std::string& session_id,
|
||||
int64_t new_expiration) = 0;
|
||||
|
||||
// A remove() operation has been completed.
|
||||
virtual void onRemoveComplete(const std::string& session_id) = 0;
|
||||
|
||||
protected:
|
||||
IEventListener() {}
|
||||
};
|
||||
|
||||
// A storage interface provided by the application. This defines the "origin"
|
||||
// that the CDM will operate in by the files it can access. Passing different
|
||||
// IStorage instances to Cdm::create will cause those CDM instances to be in
|
||||
// different "origins" as defined by the IStorage instance. For example,
|
||||
// different IStorage instances could be tied to different folders for
|
||||
// different origins.
|
||||
//
|
||||
// It is important for multi-origin hosts to verify the application's origin.
|
||||
// This ensures that the application does not access files from another
|
||||
// origin.
|
||||
//
|
||||
// NOTE: It is important for users of your application to be able to clear
|
||||
// stored data. Also, browsers or other multi-application systems should
|
||||
// store data separately per-app or per-origin.
|
||||
// See http://www.w3.org/TR/encrypted-media/#privacy-storedinfo.
|
||||
class IStorage {
|
||||
public:
|
||||
virtual ~IStorage() {}
|
||||
|
||||
virtual bool read(const std::string& name, std::string* data) = 0;
|
||||
virtual bool write(const std::string& name, const std::string& data) = 0;
|
||||
virtual bool exists(const std::string& name) = 0;
|
||||
virtual bool remove(const std::string& name) = 0;
|
||||
|
||||
// Returns the size of the given file. If the file does not exist or any
|
||||
// other error occurs, this should return a negative number.
|
||||
virtual int32_t size(const std::string& name) = 0;
|
||||
|
||||
// Populates |file_names| with the name of each file in the file system.
|
||||
// This is assumed to be a flat filename space (top level directory is
|
||||
// unnamed, and there are no subdirectories).
|
||||
virtual bool list(std::vector<std::string>* file_names) = 0;
|
||||
|
||||
protected:
|
||||
IStorage() {}
|
||||
};
|
||||
|
||||
// A clock interface provided by the application, independent of CDM
|
||||
// instances.
|
||||
// See Cdm::initialize().
|
||||
class IClock {
|
||||
public:
|
||||
virtual ~IClock() {}
|
||||
|
||||
// Returns the current time in milliseconds since 1970 UTC.
|
||||
virtual int64_t now() = 0;
|
||||
|
||||
protected:
|
||||
IClock() {}
|
||||
};
|
||||
|
||||
// A timer interface provided by the application, independent of CDM
|
||||
// instances.
|
||||
// See Cdm::initialize().
|
||||
// Implementations of this class only need to deal with at most one
|
||||
// outstanding timer per IClient at a time. It is an error for setTimeout() to
|
||||
// be called while there is already a timer running for that client. It is
|
||||
// recommended for implementers of this class to cancel the preexisting timer
|
||||
// and start the new timer if this erroneous situation occurs.
|
||||
// Timers are non-repeating. If the CDM wants to repeat a timer, it will call
|
||||
// setTimeout() again inside the timeout callback.
|
||||
class ITimer {
|
||||
public:
|
||||
virtual ~ITimer() {}
|
||||
|
||||
// This typedef is for backward compatibility with v3.0.0.
|
||||
typedef ITimerClient IClient;
|
||||
|
||||
// Call |client->onTimerExpired(context)| after a delay of |delay_ms| ms.
|
||||
virtual void setTimeout(int64_t delay_ms, IClient* client,
|
||||
void* context) = 0;
|
||||
|
||||
// Cancel the timer associated with |client|.
|
||||
virtual void cancel(IClient* client) = 0;
|
||||
|
||||
protected:
|
||||
ITimer() {}
|
||||
};
|
||||
|
||||
// A logging interface provided by the application. This will be called any
|
||||
// time the CE CDM wants to log a message.
|
||||
// See Cdm::initialize().
|
||||
//
|
||||
// A reference implementation that logs to stderr is provided in
|
||||
// stderr_logger.h. Its behavior is identical to the behavior of previous
|
||||
// CE CDM releases.
|
||||
class ILogger {
|
||||
public:
|
||||
virtual ~ILogger() {}
|
||||
|
||||
// Log the provided message.
|
||||
virtual void log(const std::string& message) = 0;
|
||||
|
||||
protected:
|
||||
ILogger() {}
|
||||
};
|
||||
|
||||
// The CE CDM has various pieces of client information baked into it at
|
||||
// compile-time. These can be retrieved at runtime by Cdm::getClientInfo(),
|
||||
// which returns them in this struct.
|
||||
// These parameters match the client identification in license requests.
|
||||
struct ClientInfo {
|
||||
// The name of the company who makes the client, e.g. "KubrickTech".
|
||||
// This matches the "Make" field in the Widevine Integration Console.
|
||||
std::string company_name;
|
||||
|
||||
// The client's model name, e.g. "HAL 9000".
|
||||
// This matches the "Model" field in the Widevine Integration Console.
|
||||
std::string model_name;
|
||||
|
||||
// The client's model year, e.g. "2001".
|
||||
// Can be used to distinguish different devices with the same model name.
|
||||
// This matches the "Year" field in the Widevine Integration Console.
|
||||
std::string model_year;
|
||||
|
||||
// The name or codename of the product or application, e.g. "clarke".
|
||||
// This may be the same as "model_name".
|
||||
std::string product_name;
|
||||
|
||||
// The name or codename of the client, e.g. "HAL".
|
||||
// This may be the same as "model_name" or "product_name".
|
||||
std::string device_name;
|
||||
|
||||
// The CPU architecture of the client, e.g. "ARMv7".
|
||||
std::string arch_name;
|
||||
|
||||
// A string containing build information about the CE CDM and the client
|
||||
// it's integrated into. Consists of multiple values separated by spaces
|
||||
// and vertical pipes. (e.g. " | ")
|
||||
std::string build_info;
|
||||
};
|
||||
|
||||
// Initialize the CDM library and provide access to platform services.
|
||||
// All platform interfaces are required. It is the responsibility of the host
|
||||
// platform to ensure that the objects passed into this method remain valid
|
||||
// for the lifetime of the CDM library.
|
||||
// Logging is controlled by |verbosity|.
|
||||
// Must be called and must return kSuccess before create() is called.
|
||||
static Status initialize(SecureOutputType secure_output_type,
|
||||
IStorage* storage, IClock* clock, ITimer* timer,
|
||||
ILogger* logger, LogLevel verbosity);
|
||||
|
||||
// This is a variant of the above function that allows the caller to pass a
|
||||
// Sandbox ID. Platforms that use Sandbox IDs should use this initialize()
|
||||
// function instead of the previous one. Platforms that do not use Sandbox IDs
|
||||
// should not use this version of initialize().
|
||||
static Status initialize(SecureOutputType secure_output_type,
|
||||
IStorage* storage, IClock* clock, ITimer* timer,
|
||||
ILogger* logger, LogLevel verbosity,
|
||||
const std::string& sandbox_id);
|
||||
|
||||
// Query the CDM library version.
|
||||
static const char* version();
|
||||
|
||||
// Retrieves the client information for this CE CDM integration.
|
||||
static Status getClientInfo(ClientInfo* client_info);
|
||||
|
||||
// Constructs a new CDM instance.
|
||||
// initialize() must be called first and must return kSuccess before a CDM
|
||||
// instance may be constructed.
|
||||
// The CDM may notify of events at any time via the provided |listener|,
|
||||
// which may not be NULL.
|
||||
// |storage| defines the storage to use for this instance. By providing
|
||||
// different objects here for different origins, this parameter can be used to
|
||||
// provide per-origin storage. It may not be NULL.
|
||||
//
|
||||
// If |privacy_mode| is true, service certificates are required and will be
|
||||
// used to encrypt messages to the license server.
|
||||
// By using service certificates to encrypt communication with the license
|
||||
// server, device-identifying information cannot be extracted from the
|
||||
// license exchange process by an intermediate layer between the CDM and
|
||||
// the server.
|
||||
// This is particularly useful for browser environments, but is recommended
|
||||
// for use whenever possible.
|
||||
//
|
||||
// If |storage_is_read_only| is true, the Widevine CE CDM will treat |storage|
|
||||
// as read-only and prevent attempts to modify any data in the IStorage. Note
|
||||
// that this is *not* the expected operation mode for most clients and will
|
||||
// likely lead to playback failures. It should only be used in cases where
|
||||
// read-only certificates and licenses have been pre-loaded on a device, such
|
||||
// as the preloaded licenses in ATSC 3.
|
||||
// It is not possible to mix read-only and non-read-only files in the same
|
||||
// IStorage instance. A separate CDM with a separate IStorage pointing to the
|
||||
// non-read-only files should be created with the read-only flag set to false.
|
||||
static Cdm* create(IEventListener* listener, IStorage* storage,
|
||||
bool privacy_mode = false,
|
||||
bool storage_is_read_only = false);
|
||||
|
||||
~Cdm() override {}
|
||||
|
||||
// The following three methods relate to service certificates. A service
|
||||
// certificate holds the RSA public key for a server, as well as other fields
|
||||
// needed for provisioning. Service certificates are mandatory if privacy mode
|
||||
// is turned on, as they are used to encrypt portions of outgoing messages to
|
||||
// the provisioning and licensing servers.
|
||||
// If a provisioning service certificate has not been installed before
|
||||
// generating a provisioning request, a default certificate that only works
|
||||
// with the Widevine-hosted provisioning service will be used.
|
||||
// It is an error to generate a licensing request while privacy mode is
|
||||
// turned on without installing a service certificate for the licensing
|
||||
// service first.
|
||||
|
||||
// Installs a service certificate from a data buffer.
|
||||
// This is used when the system or application already knows the certificate
|
||||
// of the service it wishes to communicate with, either because it is baked
|
||||
// into the software or because it was previously cached after a call to
|
||||
// Cdm::parseAndLoadServiceCertificateResponse().
|
||||
// If this method returns |Status::kSuccess|, the service certificate was
|
||||
// installed successfully.
|
||||
// The certificate is installed only for the service given by |role|. If the
|
||||
// role |ServiceRole::kAllServices| is given, it is installed for all
|
||||
// services.
|
||||
virtual Status setServiceCertificate(ServiceRole role,
|
||||
const std::string& certificate) = 0;
|
||||
|
||||
// Generate a Service Certificate Request message.
|
||||
// This is used to fetch a service certificate from the license server.
|
||||
// It is needed in cases where the system or application does not have
|
||||
// a service certificate for the license server already.
|
||||
virtual Status getServiceCertificateRequest(std::string* message) = 0;
|
||||
|
||||
// Parse a Service Certificate Response message, extracting the certificate
|
||||
// from the message and installing it into the CDM.
|
||||
// This is used when fetching a service certificate from the license server.
|
||||
// A request should be generated by getServiceCertificateRequest() and sent
|
||||
// to the license server. The server's response should be passed into this
|
||||
// method.
|
||||
// If this method returns |Status::kSuccess|, the service certificate was
|
||||
// installed successfully.
|
||||
// If a pointer to a string is passed in the |certificate| parameter, this
|
||||
// method will fill it with the extracted certificate. This certificate
|
||||
// string may be used with future CDM instances as the input to
|
||||
// setServiceCertificate(). This avoids needing to make a call to the license
|
||||
// server to get the certificate. The |certificate| argument may be NULL if
|
||||
// you do not want to take advantage of this.
|
||||
// The certificate is installed only for the service given by |role|. If the
|
||||
// role |ServiceRole::kAllServices| is given, it is installed for all
|
||||
// services.
|
||||
virtual Status parseAndLoadServiceCertificateResponse(
|
||||
ServiceRole role, const std::string& response,
|
||||
std::string* certificate) = 0;
|
||||
|
||||
// Returns the robustness level of the device, as reported by OEMCrypto. Note
|
||||
// that this function is *not* cryptographically secure and it should only be
|
||||
// relied upon for informational purposes (e.g. determining which content to
|
||||
// show in the UI) and not security purposes. (e.g. determining which content
|
||||
// to allow the device to play) *Only* secure communication between OEMCrypto
|
||||
// and the license service should be used to make security decisions.
|
||||
virtual Status getRobustnessLevel(RobustnessLevel* level) = 0;
|
||||
|
||||
// Query the underlying OEMCrypto implementation's System ID.
|
||||
virtual Status getSystemId(uint32_t* id) = 0;
|
||||
|
||||
// Returns the resource rating tier of the device, as reported by OEMCrypto.
|
||||
virtual Status getResourceRatingTier(uint32_t* tier) = 0;
|
||||
|
||||
// Retrieves the build information for the underlying OEMCrypto
|
||||
// implementation.
|
||||
virtual Status getOemCryptoBuildInfo(std::string* build_info) = 0;
|
||||
|
||||
// Retrieves the current provisioning status. The Device Certificate is
|
||||
// origin-specific, and the origin is determined by the CDM's current IStorage
|
||||
// object.
|
||||
virtual ProvisioningStatus getProvisioningStatus() = 0;
|
||||
|
||||
// Creates a Provisioning Request message.
|
||||
// This is used to provision the device. The request should be sent to the
|
||||
// provisioning server and the response given to handleProvisioningResponse().
|
||||
virtual Status getProvisioningRequest(std::string* request) = 0;
|
||||
|
||||
// Handles a provisioning response and provisions the device. If this returns
|
||||
// success, the device will now be provisioned.
|
||||
virtual Status handleProvisioningResponse(const std::string& response) = 0;
|
||||
|
||||
// Remove the device's Device Certificate (for the current origin).
|
||||
// The Device Certificate is origin-specific, and the origin is
|
||||
// determined by the CDM's current IStorage object.
|
||||
virtual Status removeProvisioning() = 0;
|
||||
|
||||
// Get the current list of offline licenses on the system.
|
||||
// License storage is origin-specific, and the origin is determined by the
|
||||
// CDM's current IStorage object.
|
||||
virtual Status listStoredLicenses(std::vector<std::string>* key_set_ids) = 0;
|
||||
|
||||
// Checks whether the device is capable of supporting a given HDCP version.
|
||||
// If successful, |key_status| is set to either kUsable or kOutputRestricted.
|
||||
virtual Status getStatusForHdcpVersion(HdcpVersion hdcp,
|
||||
KeyStatus* key_status) = 0;
|
||||
|
||||
// Checks if the given initialization data contains embedded, entitled keys.
|
||||
// Sets the variable pointed to by |contains_keys| to true if the init data
|
||||
// contains embedded keys or false if it does not. This function is useful if
|
||||
// apps choose to handle such initialization data differently, such as in the
|
||||
// case of key rotation or loading an offline entitlement license.
|
||||
//
|
||||
// For PSSH init data, this function accepts the full concatenated blob of
|
||||
// PSSH boxes from the stream. It will return true if any of the PSSHs contain
|
||||
// embedded Widevine keys.
|
||||
virtual Status initDataContainsEmbeddedKeys(InitDataType init_data_type,
|
||||
const std::string& init_data,
|
||||
bool* contains_keys) = 0;
|
||||
|
||||
// Creates a new session.
|
||||
// Do not use this to load an existing persistent session (use load()).
|
||||
// If successful, the session ID is returned via |session_id|.
|
||||
virtual Status createSession(SessionType session_type,
|
||||
std::string* session_id) = 0;
|
||||
|
||||
// Generates a request based on the provided |init_data|. For PSSH init data,
|
||||
// the CE CDM can accept the full concatenated blob of PSSH boxes from the
|
||||
// stream. It will select the correct Widevine PSSH, so callers do not have to
|
||||
// determine the correct PSSH from the list themselves.
|
||||
// If the init data contains embedded keys, they will be remembered by the
|
||||
// session and loaded after the matching entitlement key is provided to
|
||||
// update().
|
||||
//
|
||||
// The request will be provided via a synchronous call to
|
||||
// IEventListener::onMessage().
|
||||
// This is done so that license requests and renewals follow the same flow.
|
||||
virtual Status generateRequest(const std::string& session_id,
|
||||
InitDataType init_data_type,
|
||||
const std::string& init_data) = 0;
|
||||
|
||||
// Loads an existing persisted session from storage.
|
||||
virtual Status load(const std::string& session_id) = 0;
|
||||
|
||||
// Provides messages, including licenses, to the CDM.
|
||||
// If the message is a successful response to a release message, stored
|
||||
// session data will be removed for the session.
|
||||
virtual Status update(const std::string& session_id,
|
||||
const std::string& response) = 0;
|
||||
|
||||
// Loads the entitled keys embedded in |init_data| into the session identified
|
||||
// by |session_id|. The matching entitlement key must already be loaded in the
|
||||
// session via previous calls to update() or load(). For PSSH init data, the
|
||||
// CE CDM can accept the full concatenated blob of PSSH boxes from the stream.
|
||||
// It will select the correct Widevine PSSH, so callers do not have to
|
||||
// determine the correct PSSH from the list themselves.
|
||||
//
|
||||
// It is not necessary to call this function after passing PSSHs containing
|
||||
// entitled keys to generateRequest(). This function is only used when adding
|
||||
// new entitled keys to an existing session, such as for key rotation or
|
||||
// after loading a persisted entitlement license.
|
||||
virtual Status loadEmbeddedKeys(const std::string& session_id,
|
||||
InitDataType init_data_type,
|
||||
const std::string& init_data) = 0;
|
||||
|
||||
// The time, in milliseconds since 1970 UTC, after which the key(s) in the
|
||||
// session will no longer be usable to decrypt media data, or -1 if no such
|
||||
// time exists.
|
||||
virtual Status getExpiration(const std::string& session_id,
|
||||
int64_t* expiration) = 0;
|
||||
|
||||
// A map of known key IDs to the current status of the associated key.
|
||||
virtual Status getKeyStatuses(const std::string& session_id,
|
||||
KeyStatusMap* key_statuses) = 0;
|
||||
|
||||
// Gets the permitted usage for a specific key by ID.
|
||||
virtual Status getKeyAllowedUsages(const std::string& session_id,
|
||||
const std::string& key_id,
|
||||
KeyAllowedUsageFlags* usage_flags) = 0;
|
||||
|
||||
// Gets the permitted usage for a specific key by ID.
|
||||
// Search for key across all known sessions. If there are keys in separate
|
||||
// sessions that match the given key_id, return kTypeError unless all such
|
||||
// keys have identical Allowed Usage settings.
|
||||
virtual Status getKeyAllowedUsages(const std::string& key_id,
|
||||
KeyAllowedUsageFlags* usage_flags) = 0;
|
||||
|
||||
// Indicates that the application no longer needs the session and the CDM
|
||||
// should release any resources associated with it and close it.
|
||||
// Does not generate release messages for persistent sessions.
|
||||
// Does not remove stored session data for persistent sessions.
|
||||
virtual Status close(const std::string& session_id) = 0;
|
||||
|
||||
// Removes stored session data associated with the session.
|
||||
// The session must be loaded before it can be removed.
|
||||
// Generates release messages, which must be delivered to the license server.
|
||||
// A reply from the license server must be provided via update() before the
|
||||
// session is fully removed.
|
||||
virtual Status remove(const std::string& session_id) = 0;
|
||||
|
||||
// Removes stored session data associated with the session.
|
||||
// The session must be loaded before it can be removed.
|
||||
// Unlike remove(), this method does not generate a release message. The
|
||||
// stored data is removed immediately. The session is closed if this function
|
||||
// returns successfully.
|
||||
// Generally, callers should not use this method, as it prevents usage data
|
||||
// from being gathered and it does not allow the license's release to be
|
||||
// tracked by the server. Most callers will want to use remove(), which
|
||||
// generates a release request. However, this method is provided for
|
||||
// applications that have a specific need to release licenses without a server
|
||||
// roundtrip and are aware of the costs of doing so.
|
||||
// There is no EME equivalent to this method. EME specifies that removal
|
||||
// should require a release request, as is done by the remove() method.
|
||||
virtual Status forceRemove(const std::string& session_id) = 0;
|
||||
|
||||
// Describes a repeating pattern as defined by the CENC 3.0 standard. A
|
||||
// CENC 3.0 pattern consists of a number of encrypted blocks followed by a
|
||||
// number of clear blocks, after which it repeats.
|
||||
struct Pattern {
|
||||
public:
|
||||
Pattern() : encrypted_blocks(0), clear_blocks(0) {}
|
||||
|
||||
Pattern(uint32_t encrypt, uint32_t clear)
|
||||
: encrypted_blocks(encrypt), clear_blocks(clear) {}
|
||||
|
||||
// The number of crypto blocks that are encrypted and therefore need to be
|
||||
// decrypted.
|
||||
uint32_t encrypted_blocks;
|
||||
|
||||
// The number of crypto blocks that are not encrypted and therefore should
|
||||
// be skipped when doing decryption.
|
||||
uint32_t clear_blocks;
|
||||
};
|
||||
|
||||
struct Subsample {
|
||||
public:
|
||||
Subsample() : clear_bytes(0), protected_bytes(0) {}
|
||||
|
||||
// The number of bytes of data that are not protected and therefore should
|
||||
// be copied unchanged when doing decryption. The clear bytes come before
|
||||
// the protected bytes in the subsample.
|
||||
uint32_t clear_bytes;
|
||||
|
||||
// The number of bytes of data that are protected and therefore should be
|
||||
// considered for decryption. Depending on the pattern, these bytes may all
|
||||
// be decrypted or only some of them may be. The protected bytes come after
|
||||
// the clear bytes in the subsample.
|
||||
uint32_t protected_bytes;
|
||||
};
|
||||
|
||||
struct InputBuffer {
|
||||
public:
|
||||
InputBuffer()
|
||||
: iv(nullptr),
|
||||
iv_length(0),
|
||||
data(nullptr),
|
||||
data_length(0),
|
||||
subsamples(nullptr),
|
||||
subsamples_length(0) {}
|
||||
|
||||
// These fields are treated as an array of bytes, with the |iv| pointer
|
||||
// pointing to the first byte and containing |iv_length| number of bytes.
|
||||
// These should be the bytes of the initial IV that should be used to
|
||||
// decrypt this sample.
|
||||
//
|
||||
// |iv_length| must be 16 if the sample contains any protected data. If the
|
||||
// content contains an 8-byte IV, it is the responsibility of the caller to
|
||||
// expand it to 16 bytes following the method in the ISO-CENC standard.
|
||||
const uint8_t* iv;
|
||||
uint32_t iv_length;
|
||||
|
||||
// These fields are treated as an array of bytes, with the |data| pointer
|
||||
// pointing to the first byte and containing |data_length| number of bytes.
|
||||
// This data should be ready to be decrypted with no further processing. If
|
||||
// the data is coming from a format that requires processing before
|
||||
// decryption, that processing needs to happen before the data is passed in
|
||||
// here. For example, content coming from HLS will need to have its extra
|
||||
// start code emulation prevention removed before it is passed to the
|
||||
// Widevine CE CDM.
|
||||
const uint8_t* data;
|
||||
uint32_t data_length;
|
||||
|
||||
// These fields are treated as an array of Subsample structs, with the
|
||||
// |subsamples| pointer pointing to the first Subsample and containing
|
||||
// |samples_length| number of entries. These structs describe all the
|
||||
// ISO-CENC subsamples that make up the sample.
|
||||
//
|
||||
// The sum of all the |clear_bytes| and |protected_bytes| in all the
|
||||
// subsamples must equal the |data_length| field.
|
||||
const Subsample* subsamples;
|
||||
uint32_t subsamples_length;
|
||||
};
|
||||
|
||||
struct OutputBuffer {
|
||||
OutputBuffer() : data(nullptr), data_offset(0), data_length(0) {}
|
||||
|
||||
// The type of value stored in this pointer depends on the secure output
|
||||
// type passed to Cdm::initialize() and the |is_secure| field of the
|
||||
// DecryptionBatch.
|
||||
//
|
||||
// If |is_secure| is false or the secure output type is kNoSecureOutput,
|
||||
// this is a memory address in main memory.
|
||||
// If |is_secure| is true and the secure output type is kOpaqueHandle,
|
||||
// this is an opaque handle.
|
||||
// If |is_secure| is true and the secure output type is kDirectRender,
|
||||
// this is ignored.
|
||||
//
|
||||
// See also the SecureOutputType argument to initialize().
|
||||
void* data;
|
||||
|
||||
// An offset applied to the output address inside OEMCrypto.
|
||||
// Useful when |data| is an opaque handle rather than a memory address.
|
||||
uint32_t data_offset;
|
||||
|
||||
// The maximum amount of data that can be decrypted to the |data| buffer.
|
||||
// Must be at least as large as the input buffer's |data_length| plus the
|
||||
// bytes that will be skipped by |data_offset|.
|
||||
uint32_t data_length;
|
||||
};
|
||||
|
||||
struct Sample {
|
||||
public:
|
||||
Sample() : input(), output() {}
|
||||
|
||||
// These structs describe the protected input data of the sample and the
|
||||
// output buffer that decrypted data should be written to.
|
||||
InputBuffer input;
|
||||
OutputBuffer output;
|
||||
};
|
||||
|
||||
struct DecryptionBatch {
|
||||
public:
|
||||
DecryptionBatch()
|
||||
: samples(nullptr),
|
||||
samples_length(0),
|
||||
key_id(nullptr),
|
||||
key_id_length(0),
|
||||
pattern(),
|
||||
is_secure(false),
|
||||
encryption_scheme(kClear),
|
||||
is_video(true) {}
|
||||
|
||||
// These fields are treated as an array of Sample structs, with the
|
||||
// |samples| pointer pointing to the first Sample and containing
|
||||
// |samples_length| number of entries. These structs describe all the data
|
||||
// that is going to be decrypted. You can pass as many samples to the CDM as
|
||||
// you want, but be aware that passing more samples than your OEMCrypto
|
||||
// implementation can handle in one decrypt call is inefficient, as the CDM
|
||||
// will have to do work to break the data up into smaller pieces.
|
||||
const Sample* samples;
|
||||
uint32_t samples_length;
|
||||
|
||||
// These fields are treated as an array of bytes, with the |key_id| pointer
|
||||
// pointing to the first byte and containing |key_id_length| number of
|
||||
// bytes. These should be the bytes of the Key ID of the key that should be
|
||||
// used to decrypt the |samples|.
|
||||
const uint8_t* key_id;
|
||||
uint32_t key_id_length;
|
||||
|
||||
// Describes the repeating pattern with which the content was encrypted. If
|
||||
// left at its default value of (0,0), patterns will be disabled. Should
|
||||
// only be changed for content that uses patterns, such as for CENC 3.0
|
||||
// "cbcs" content or for HLS content.
|
||||
Pattern pattern;
|
||||
|
||||
// Indicates whether the OutputBuffers in the Samples are secure outputs or
|
||||
// not. False for clear buffers, true otherwise.
|
||||
// Must be false if the secure output type is kNoSecureOutput.
|
||||
// See also the SecureOutputType argument to initialize().
|
||||
bool is_secure;
|
||||
|
||||
// Specifies the encryption scheme, if any, to be used to decrypt the data.
|
||||
// When set to kClear, decryption will copy the input data directly to the
|
||||
// output buffer. This is necessary for secure output types, where the
|
||||
// output buffer cannot be directly accessed above the CDM.
|
||||
EncryptionScheme encryption_scheme;
|
||||
|
||||
// Used by secure output type kDirectRender, where the secure hardware must
|
||||
// decode and render the decrypted content:
|
||||
bool is_video;
|
||||
};
|
||||
|
||||
// Decrypt the samples contained in the DecryptionBatch |batch| from their
|
||||
// InputBuffer to their OutputBuffer. The |key_id| field of |batch|
|
||||
// must refer to a key that is already loaded in some session.
|
||||
virtual Status decrypt(const DecryptionBatch& batch) = 0;
|
||||
|
||||
// Decrypt the samples contained in the DecryptionBatch |batch| from their
|
||||
// InputBuffer to their OutputBuffer. Decryption will be attempted in the
|
||||
// session identified by |session_id|, regardless of whether the |key_id|
|
||||
// field of |batch| refers to a key loaded in that session. If |key_id| refers
|
||||
// to a key that is not loaded in the given session, decryption will fail.
|
||||
//
|
||||
// This overload is used when platforms need to play clear content through the
|
||||
// secure path before a key is loaded.
|
||||
virtual Status decrypt(const std::string& session_id,
|
||||
const DecryptionBatch& batch) = 0;
|
||||
|
||||
// Sets a value in the custom app settings. These are settings
|
||||
// that are sent with any message to the license server. These methods
|
||||
// should only be used by advanced users maintaining existing systems.
|
||||
// The |key| cannot be empty.
|
||||
virtual Status setAppParameter(const std::string& key,
|
||||
const std::string& value) = 0;
|
||||
|
||||
// Gets the current value in the custom app settings. If the key is
|
||||
// not present, then kTypeError is returned. The |key| cannot be
|
||||
// empty. |result| cannot be null. See setAppParameter().
|
||||
virtual Status getAppParameter(const std::string& key,
|
||||
std::string* result) = 0;
|
||||
|
||||
// Removes the value in the custom app settings. If the key is not
|
||||
// present, then kTypeError is returned. The |key| cannot be empty.
|
||||
// See setAppParameter().
|
||||
virtual Status removeAppParameter(const std::string& key) = 0;
|
||||
|
||||
// Clears all the values in the custom app settings. See setAppParameter().
|
||||
virtual Status clearAppParameters() = 0;
|
||||
|
||||
// Generic crypto - functions for applying crypto operations to
|
||||
// app-level data (outside the content stream).
|
||||
|
||||
enum GenericEncryptionAlgorithmType : int32_t {
|
||||
kEncryptionAlgorithmUnknown,
|
||||
kEncryptionAlgorithmAesCbc128,
|
||||
};
|
||||
|
||||
enum GenericSigningAlgorithmType : int32_t {
|
||||
kSigningAlgorithmUnknown,
|
||||
kSigningAlgorithmHmacSha256
|
||||
};
|
||||
|
||||
// Encrypts a buffer of app-level data.
|
||||
virtual Status genericEncrypt(const std::string& session_id,
|
||||
const std::string& in_buffer,
|
||||
const std::string& key_id,
|
||||
const std::string& iv,
|
||||
GenericEncryptionAlgorithmType algorithm,
|
||||
std::string* out_buffer) = 0;
|
||||
|
||||
// Decrypts a buffer of app-level data.
|
||||
virtual Status genericDecrypt(const std::string& session_id,
|
||||
const std::string& in_buffer,
|
||||
const std::string& key_id,
|
||||
const std::string& iv,
|
||||
GenericEncryptionAlgorithmType algorithm,
|
||||
std::string* out_buffer) = 0;
|
||||
|
||||
// Signs a buffer of app-level data.
|
||||
virtual Status genericSign(const std::string& session_id,
|
||||
const std::string& message,
|
||||
const std::string& key_id,
|
||||
GenericSigningAlgorithmType algorithm,
|
||||
std::string* signature) = 0;
|
||||
|
||||
// Verifies the signature on a buffer of app-level data.
|
||||
// Returns kSuccess if signature is verified, otherwise returns kDecryptError.
|
||||
virtual Status genericVerify(const std::string& session_id,
|
||||
const std::string& message,
|
||||
const std::string& key_id,
|
||||
GenericSigningAlgorithmType algorithm,
|
||||
const std::string& signature) = 0;
|
||||
|
||||
// Enable enforcement of Video Resolution Constraints.
|
||||
// This function should be called during session startup and any time
|
||||
// the resolution of the video stream changes. The resolution passed in should
|
||||
// be the resolution of the content being played, not the output resolution of
|
||||
// the device.
|
||||
// Video resolutions in the license policy are stored as 32-bit values
|
||||
// representing the total number of pixels. If the product of |width| and
|
||||
// |height| is greater than or equal to 2^32, this will return kRangeError.
|
||||
virtual Status setVideoResolution(const std::string& session_id,
|
||||
uint32_t width, uint32_t height) = 0;
|
||||
|
||||
// Retrieve the metrics gathered by this CDM instance.
|
||||
// The Widevine CE CDM gathers metrics about the time taken to perform various
|
||||
// computations, as well as their error codes. This method allows platforms
|
||||
// and apps to gather these metrics to send them back to Google for analysis.
|
||||
virtual Status getMetrics(std::string* serialized_metrics) = 0;
|
||||
|
||||
// Creates a Cast Provisioning Request message.
|
||||
// This method is only useful on devices that implement support for Google
|
||||
// Cast. Calling this method will generate a provisioning request that can be
|
||||
// used to provision the device's Cast certificate. The request should be sent
|
||||
// to the provisioning server just like a request from
|
||||
// getProvisioningRequest(). However, the response should be given to
|
||||
// handleCastProvisioningResponse() in order to extract the additional,
|
||||
// Cast-specific fields.
|
||||
virtual Status getCastProvisioningRequest(std::string* request) = 0;
|
||||
|
||||
// Handles a Cast provisioning response.
|
||||
// This method is only useful on devices that implement support for Google
|
||||
// Cast. It returns both the Cast public certificate and a wrapped private key
|
||||
// that can be used with castSign(). Handling a Cast provisioning response
|
||||
// does not affect the device's Widevine provisioning status. See
|
||||
// handleProvisioningResponse() for handling Widevine provisioning.
|
||||
virtual Status handleCastProvisioningResponse(const std::string& response,
|
||||
std::string* cert,
|
||||
std::string* wrapped_key) = 0;
|
||||
|
||||
// Signs a method for Cast usage.
|
||||
// This method is only useful on devices that support Google Cast and after
|
||||
// receiving a wrapped private key from handleCastProvisioningResponse(). This
|
||||
// method generates a signature for the message using the given private key in
|
||||
// PKCS#1 with block type 1 padding.
|
||||
virtual Status castSign(const std::string& wrapped_key,
|
||||
const std::string& message,
|
||||
std::string* signature) = 0;
|
||||
|
||||
protected:
|
||||
Cdm() {}
|
||||
};
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
#endif // WVCDM_CDM_CDM_H_
|
||||
25
libwvdrmengine/cdm/include/cdm_version.h
Normal file
25
libwvdrmengine/cdm/include/cdm_version.h
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2015 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
|
||||
#define CDM_VERSION_STR_(x, y, z, w) #x "." #y "." #z w
|
||||
#define CDM_VERSION_STR(x, y, z, w) CDM_VERSION_STR_(x, y, z, w)
|
||||
|
||||
// Widevine CE CDM Version
|
||||
#ifndef CDM_VERSION_MAJOR
|
||||
# define CDM_VERSION_MAJOR 18
|
||||
#endif
|
||||
#ifndef CDM_VERSION_MINOR
|
||||
# define CDM_VERSION_MINOR 3
|
||||
#endif
|
||||
#ifndef CDM_VERSION_PATCH
|
||||
# define CDM_VERSION_PATCH 0
|
||||
#endif
|
||||
#ifndef CDM_VERSION_TAG
|
||||
# define CDM_VERSION_TAG "-non-prod"
|
||||
#endif
|
||||
#define CDM_VERSION \
|
||||
CDM_VERSION_STR(CDM_VERSION_MAJOR, CDM_VERSION_MINOR, CDM_VERSION_PATCH, \
|
||||
CDM_VERSION_TAG)
|
||||
|
||||
#define EME_VERSION "https://www.w3.org/TR/2017/REC-encrypted-media-20170918"
|
||||
42
libwvdrmengine/cdm/include/compiler_detection.h
Normal file
42
libwvdrmengine/cdm/include/compiler_detection.h
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
#ifndef WVCDM_CDM_COMPILER_DETECTION_H_
|
||||
#define WVCDM_CDM_COMPILER_DETECTION_H_
|
||||
|
||||
// This file makes some best-effort attempts to detect details about the
|
||||
// compilation environment used by SetClientInfo.
|
||||
|
||||
#if defined(CDM_DISABLE_LOGGING)
|
||||
# define LOGGING_MESSAGE "Logging Disabled"
|
||||
#else
|
||||
# define LOGGING_MESSAGE "Logging Enabled"
|
||||
#endif
|
||||
|
||||
#if defined(_DEBUG)
|
||||
# define BUILD_FLAVOR_MESSAGE "Debug"
|
||||
#elif defined(NDEBUG)
|
||||
# define BUILD_FLAVOR_MESSAGE "Release"
|
||||
#else
|
||||
# define BUILD_FLAVOR_MESSAGE "Unknown"
|
||||
#endif
|
||||
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
# define CPU_ARCH_MESSAGE "x86-64"
|
||||
#elif defined(__i386__) || defined(_M_IX86)
|
||||
# define CPU_ARCH_MESSAGE "i386"
|
||||
#elif defined(__aarch64__) || defined(_M_ARM64)
|
||||
# define CPU_ARCH_MESSAGE "AArch64"
|
||||
#elif defined(__arm__) || defined(_M_ARM)
|
||||
# define CPU_ARCH_MESSAGE "AArch32"
|
||||
#elif defined(__mips__)
|
||||
# define CPU_ARCH_MESSAGE "MIPS"
|
||||
#elif defined(__powerpc64__)
|
||||
# define CPU_ARCH_MESSAGE "64-bit PowerPC"
|
||||
#elif defined(__powerpc__) || defined(_M_PPC)
|
||||
# define CPU_ARCH_MESSAGE "32-bit PowerPC"
|
||||
#else
|
||||
# define CPU_ARCH_MESSAGE "Unrecognized CPU"
|
||||
#endif
|
||||
|
||||
#endif // WVCDM_CDM_COMPILER_DETECTION_H_
|
||||
14
libwvdrmengine/cdm/include/logger_global.h
Normal file
14
libwvdrmengine/cdm/include/logger_global.h
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
|
||||
#ifndef WVCDM_CDM_LOGGER_GLOBAL_H_
|
||||
#define WVCDM_CDM_LOGGER_GLOBAL_H_
|
||||
|
||||
#include "cdm.h"
|
||||
|
||||
namespace widevine {
|
||||
extern Cdm::ILogger* g_logger;
|
||||
}
|
||||
|
||||
#endif // WVCDM_CDM_LOGGER_GLOBAL_H_
|
||||
35
libwvdrmengine/cdm/include/properties_ce.h
Normal file
35
libwvdrmengine/cdm/include/properties_ce.h
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
#ifndef WVCDM_CDM_PROPERTIES_CE_H_
|
||||
#define WVCDM_CDM_PROPERTIES_CE_H_
|
||||
|
||||
#include "cdm.h"
|
||||
|
||||
#if defined(UNIT_TEST)
|
||||
# include <gtest/gtest.h>
|
||||
#endif
|
||||
|
||||
namespace widevine {
|
||||
|
||||
class PropertiesCE {
|
||||
public:
|
||||
static Cdm::SecureOutputType GetSecureOutputType();
|
||||
static void SetProvisioningMessagesAreBinary(bool bin_prov);
|
||||
// If this is set to an empty string, (which is the default) then PropertiesCE
|
||||
// will report that there is no Sandbox ID in use.
|
||||
static void SetSandboxId(const std::string& sandbox_id);
|
||||
static bool ClientInfoIsValid();
|
||||
|
||||
private:
|
||||
static void SetSecureOutputType(Cdm::SecureOutputType secure_output_type);
|
||||
|
||||
friend class Cdm;
|
||||
#if defined(UNIT_TEST)
|
||||
FRIEND_TEST(CdmTest, DeviceCertificateRequest);
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
#endif // WVCDM_CDM_PROPERTIES_CE_H_
|
||||
32
libwvdrmengine/cdm/include/read_client_info.h
Normal file
32
libwvdrmengine/cdm/include/read_client_info.h
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
#ifndef WVCDM_CDM_READ_CLIENT_INFO_H_
|
||||
#define WVCDM_CDM_READ_CLIENT_INFO_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace widevine {
|
||||
|
||||
// This function must be implemented by partners who wish to use run-time client
|
||||
// information. (i.e. Those that set 'client_info_source' to 'runtime' in their
|
||||
// platform's properties.) These partners must set 'read_client_info_path' to
|
||||
// a GYP target that contains an implementation of this function. This function
|
||||
// will be called by the CE CDM during Cdm::initialize() to retrieve the client
|
||||
// information at runtime.
|
||||
//
|
||||
// This function should fill in each of the strings with the relevant piece of
|
||||
// client information and return true. If for any reason the platform cannot
|
||||
// fill in all the strings or an error occurs, the function should return false.
|
||||
//
|
||||
// For a definition of each string's meaning, see the client info property
|
||||
// documentation in platform_properties.gypi.
|
||||
bool ReadClientInformation(std::string* company_name, std::string* model_name,
|
||||
std::string* model_year, std::string* product_name,
|
||||
std::string* device_name, std::string* arch_name,
|
||||
std::string* platform, std::string* form_factor,
|
||||
std::string* version);
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
#endif // WVCDM_CDM_READ_CLIENT_INFO_H_
|
||||
28
libwvdrmengine/cdm/include/stderr_logger.h
Normal file
28
libwvdrmengine/cdm/include/stderr_logger.h
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
//
|
||||
// You can use this implementation of ILogger when calling Cdm::initialize() in
|
||||
// order to log all messages to stderr. This preserves the behavior of past CE
|
||||
// CDM releases.
|
||||
#ifndef WVCDM_CDM_STDERR_LOGGER_H_
|
||||
#define WVCDM_CDM_STDERR_LOGGER_H_
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "cdm.h"
|
||||
|
||||
namespace widevine {
|
||||
class StderrLogger : public Cdm::ILogger {
|
||||
public:
|
||||
StderrLogger() {}
|
||||
~StderrLogger() override {}
|
||||
|
||||
void log(const std::string& message) override {
|
||||
std::cerr << message << std::endl << std::flush;
|
||||
}
|
||||
};
|
||||
} // namespace widevine
|
||||
|
||||
#endif // WVCDM_CDM_STDERR_LOGGER_H_
|
||||
218
libwvdrmengine/cdm/platform_properties.gypi
Normal file
218
libwvdrmengine/cdm/platform_properties.gypi
Normal file
@@ -0,0 +1,218 @@
|
||||
# Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
|
||||
# source code may only be used and distributed under the Widevine License
|
||||
# Agreement.
|
||||
|
||||
# This file contains all the variables that Widevine exposes for integration
|
||||
# partners to customize in their platforms' settings.gypi files. Partners will
|
||||
# usually need to override some or all of these variables in the 'variables'
|
||||
# section of their platform's settings.gypi file.
|
||||
#
|
||||
# This file is included into multiple GYP files throughout the project. Those
|
||||
# files may also define their own variables. However, variables defined outside
|
||||
# this file are *not* intended to be overridden by integration partners. If
|
||||
# your device requires overriding a variable from outside this file, please let
|
||||
# Widevine know so that we can evaluate whether it should be included in this
|
||||
# file or whether there is a better way to achieve what you are trying to
|
||||
# achieve.
|
||||
{
|
||||
'variables': {
|
||||
# Choose whether the client information is compiled into the binary at
|
||||
# compile-time or whether it is gathered by the CDM at runtime. The client
|
||||
# information ends up as client identification in license requests. All
|
||||
# values may be used by a license server proxy to drive business logic.
|
||||
# Valid values are:
|
||||
#
|
||||
# 'compiled' - The client information is read from the platform properties
|
||||
# and compiled into the CE CDM binary. The platform properties
|
||||
# that define client info must be defined.
|
||||
#
|
||||
# 'runtime' - The client information is read at runtime using
|
||||
# read_client_info.h. The property 'read_client_info_path' must
|
||||
# also be defined, pointing to a GYP target that provides an
|
||||
# implementation of read_client_info.h.
|
||||
'client_info_source%': 'compiled',
|
||||
|
||||
# The following variables define the client info that is baked into the CDM
|
||||
# binary at build-time. If 'client_info_source' is 'compiled'. You *must*
|
||||
# set meaningful values for all of these variables as part of defining your
|
||||
# platform. Values may not contain double quotes, percent signs, or the
|
||||
# substring " | ". (a vertical pipe surrounded by spaces) If
|
||||
# 'client_info_source' is 'runtime', these variables are ignored.
|
||||
|
||||
# The name of the company who makes the client, e.g. "KubrickTech".
|
||||
# This should match the "Make" field in the Widevine Integration Console.
|
||||
#'client_company_name%': '',
|
||||
|
||||
# The client's model name, e.g. "HAL 9000".
|
||||
# This should match the "Model" field in the Widevine Integration Console.
|
||||
#'client_model_name%': '',
|
||||
|
||||
# The client's model year, e.g. "2001".
|
||||
# Can be used to distinguish different devices with the same model name.
|
||||
# This should match the "Year" field in the Widevine Integration Console.
|
||||
#'client_model_year%': '',
|
||||
|
||||
# The name or codename of the product or application, e.g. "clarke".
|
||||
# This may be the same as "client_model_name".
|
||||
#'client_product_name%': '',
|
||||
|
||||
# The name or codename of the client, e.g. "HAL".
|
||||
# This may be the same as "client_model_name" or "client_product_name".
|
||||
#'client_device_name%': '',
|
||||
|
||||
# The CPU architecture of the client, e.g. "ARMv7".
|
||||
#'client_arch_name%': '',
|
||||
# The OS platform of the client, e.g. "Linux".
|
||||
# This should match the "Platform" field in the Widevine Integration
|
||||
# Console.
|
||||
#'client_platform%': '',
|
||||
|
||||
# The form factor of the client, e.g. "TV".
|
||||
# This should match the "Type" field in the Widevine Integration Console.
|
||||
#'client_form_factor%': '',
|
||||
|
||||
# The version number of the client that the CE CDM is integrated into. This
|
||||
# is the operating system or app version, not the CDM version.
|
||||
#'client_version%': '',
|
||||
|
||||
# If 'client_info_source' is 'runtime', this variable must be set to the
|
||||
# path to a GYP target that provides an implementation of
|
||||
# read_client_info.h. This implementation will be compiled into the CDM and
|
||||
# used at runtime to get the client info. If 'client_info_source' is
|
||||
# 'compiled', this variable is ignored.
|
||||
'read_client_info_path%': '',
|
||||
|
||||
|
||||
# Choose type of OEMCrypto library to compile in. Valid values are:
|
||||
#
|
||||
# 'vendor' - Production Level 1 systems should use 'vendor' to indicate that
|
||||
# they are providing their own OEMCrypto library and the Widevine
|
||||
# CE CDM build system is not responsible for building anything.
|
||||
#
|
||||
# 'level3' - Partners who have received a Widevine-generated Level 3 library
|
||||
# should use 'level3' to indicate that the Widevine CE CDM build
|
||||
# system should include it in the build.
|
||||
#
|
||||
# 'target' - If your vendor OEMCrypto is built using GYP and you would like
|
||||
# the Widevine CE CDM build system to build it as part of the CE
|
||||
# CDM build process, you can use 'target' and also set the
|
||||
# variable 'oemcrypto_gyp_path' below. Most vendors will want to
|
||||
# use 'vendor', above, instead. This setting exists primarily for
|
||||
# Google's internal testing.
|
||||
#'oemcrypto_lib%': '',
|
||||
|
||||
# You only need to set this value if you set 'oemcrypto_lib' to 'target'
|
||||
# above.
|
||||
#'oemcrypto_gyp_path%': '',
|
||||
|
||||
# Choose the oemcrypto adapter type. Valid values are:
|
||||
#
|
||||
# 'static' - (default). Statically link oemcrypto into the tests.
|
||||
# other values - for internal testing.
|
||||
'oemcrypto_adapter_type%': 'static',
|
||||
|
||||
# Whether to include OTA Keybox functionality or not. This is an optional
|
||||
# feature that is only used a few platforms. Generally, to qualify as an L1
|
||||
# device, a keybox must be installed on the device in the factory.
|
||||
# Valid values are 'true' or 'false'.
|
||||
'support_ota_keybox_functions%': 'false',
|
||||
|
||||
# Compile with clang source based code coverage tool when run a code coverage
|
||||
# build by set this to true.
|
||||
'generate_code_coverage_report%': 'false',
|
||||
|
||||
# Override this to indicate what CPU architecture's assembly-language files
|
||||
# should be used when building assembly language files. Or, set it to
|
||||
# "none" to turn off the use of assembly language. The default is "none" for
|
||||
# compatibility, but we strongly recommend overriding this value to
|
||||
# improve performance. Turning it off or leaving it turned off is not
|
||||
# recommended unless your CPU architecture is unsupported or you are using
|
||||
# a tool that does not play nice with assembly language, like Address
|
||||
# Sanitizer.
|
||||
#
|
||||
# Valid values are:
|
||||
# * x86
|
||||
# * x64 or x86-64
|
||||
# * arm
|
||||
# * arm64
|
||||
# * ppc64
|
||||
# * none
|
||||
'asm_target_arch%': 'none',
|
||||
|
||||
# When building on Windows, we have to use the NASM assembler. By default
|
||||
# we disable assembly on Windows since this is usually not installed. You
|
||||
# can override it with these variables.
|
||||
'has_nasm%': 'false',
|
||||
'nasm_path%': 'nasm.exe',
|
||||
|
||||
# Although OEMCrypto is used to perform secure crypto operations, the
|
||||
# Widevine CE CDM also needs a crypto library to perform non-secure crypto
|
||||
# operations for Privacy Mode and Provisioning 3.0. By default, the copy
|
||||
# of BoringSSL in third_party/boringssl/ is compiled statically into the CE
|
||||
# CDM with hidden linkage. However, by overriding these values, partners can
|
||||
# choose to use other crypto libraries.
|
||||
#
|
||||
# Valid values are:
|
||||
# * boringssl
|
||||
# * openssl
|
||||
# * dummy
|
||||
#
|
||||
# If this option is set to 'dummy', the CDM will compile, but Privacy Mode
|
||||
# and Provisioning 3.0 will always fail.
|
||||
#
|
||||
# Some of these libraries can be further configured with the options that
|
||||
# follow this one.
|
||||
'privacy_crypto_impl%': 'boringssl',
|
||||
|
||||
# BoringSSL Configuration
|
||||
# These options are only relevant if privacy_crypto_impl is 'boringssl'.
|
||||
#
|
||||
# When using BoringSSL, the Widevine CE CDM defaults to the copy of
|
||||
# BoringSSL in third_party/boringssl/. If you have an alternative BoringSSL
|
||||
# GYP build, you can override these variables to point to it instead.
|
||||
'boringssl_libcrypto_path%': '<(DEPTH)/third_party/boringssl/boringssl.gyp:crypto',
|
||||
'boringssl_libssl_path%': '<(DEPTH)/third_party/boringssl/boringssl.gyp:ssl',
|
||||
|
||||
# There are three protobuf configurations:
|
||||
#
|
||||
# 1) protobuf_config == 'system'
|
||||
# Use a system-wide installation of protobuf.
|
||||
# Specify the protobuf library in protobuf_lib.
|
||||
# Specify the path to protoc in protoc_bin.
|
||||
#
|
||||
# 2) protobuf_config == 'target'
|
||||
# Use an existing protobuf gyp target from your project.
|
||||
# Specify the protobuf gyp file and target in protobuf_lib_path.
|
||||
# Specify the protoc gyp file and target in protoc_host_path.
|
||||
# Specify the path to protoc in protoc_bin.
|
||||
#
|
||||
# 3) protobuf_config == 'source' (default)
|
||||
# Build protobuf and protoc from the copy in third_party/protobuf.
|
||||
'protobuf_config%': 'source',
|
||||
'protobuf_lib%': '',
|
||||
'protoc_bin%': '',
|
||||
'protobuf_lib_path%': '',
|
||||
'protoc_host_path%': '',
|
||||
|
||||
# Protobuf Generation and Build configurations:
|
||||
#
|
||||
# These options allow for different build steps to be specified for proto
|
||||
# cc file generation than the default step. This can be used to customize
|
||||
# cc file generation or add additional cc file processing steps before
|
||||
# proto cc files are built.
|
||||
#
|
||||
# The directory where proto cc files that will be compiled are located.
|
||||
'proto_cc_dir%': '<(SHARED_INTERMEDIATE_DIR)/protoc_out',
|
||||
|
||||
# The directory where proto cc files generated from proto files will be
|
||||
# located.
|
||||
'proto_gen_dir%': '<(SHARED_INTERMEDIATE_DIR)/protoc_out',
|
||||
|
||||
# Path to the GYP file that contains the proto cc file generation targets.
|
||||
# This file must provide the following targets:
|
||||
# - generate_license_protocol
|
||||
# - generate_device_files
|
||||
# - generate_metrics_proto
|
||||
'proto_gen_gyp_path%': '<(DEPTH)/third_party/generate_proto_cc.gyp',
|
||||
}, # variables
|
||||
}
|
||||
1776
libwvdrmengine/cdm/src/cdm.cpp
Normal file
1776
libwvdrmengine/cdm/src/cdm.cpp
Normal file
File diff suppressed because it is too large
Load Diff
68
libwvdrmengine/cdm/src/log.cpp
Normal file
68
libwvdrmengine/cdm/src/log.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
//
|
||||
// Log - implemented using stderr.
|
||||
|
||||
#include "log.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "logger_global.h"
|
||||
#include "string_format.h"
|
||||
|
||||
namespace {
|
||||
// We initialize every log message with this message so that if formatting
|
||||
// fails, we'll still get a readable message.
|
||||
const char* const kFallbackLogMessage = "[FATAL] Unable to format log message";
|
||||
} // namespace
|
||||
|
||||
namespace wvutil {
|
||||
|
||||
LogPriority g_cutoff = CDM_LOG_WARN;
|
||||
|
||||
void InitLogging() {}
|
||||
|
||||
void Log(const char* file, const char* function, int line, LogPriority level,
|
||||
const char* fmt, ...) {
|
||||
if (widevine::g_logger == nullptr) {
|
||||
// If somehow we got here with no logger configured, as a last resort
|
||||
// complain to stderr and bail.
|
||||
fprintf(stderr, "[FATAL:%s(%d):%s] NO LOGGER CONFIGURED\n", file, line,
|
||||
function);
|
||||
fflush(stderr);
|
||||
return;
|
||||
}
|
||||
|
||||
const char* severities[] = {"ERROR", "WARN", "INFO", "DEBUG", "VERBOSE"};
|
||||
if (level >=
|
||||
static_cast<LogPriority>(sizeof(severities) / sizeof(*severities))) {
|
||||
std::string fatal_message(kFallbackLogMessage);
|
||||
FormatString(&fatal_message,
|
||||
"[FATAL:%s(%d):%s] Invalid log priority level: %d", file, line,
|
||||
function, level);
|
||||
widevine::g_logger->log(fatal_message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (level > g_cutoff) return;
|
||||
|
||||
std::string formatted_message(kFallbackLogMessage);
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
VFormatString(&formatted_message, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
std::string log_line(kFallbackLogMessage);
|
||||
FormatString(&log_line, "[%s:%s(%d):%s] %s", severities[level], file, line,
|
||||
function, formatted_message.c_str());
|
||||
|
||||
widevine::g_logger->log(log_line);
|
||||
}
|
||||
|
||||
} // namespace wvutil
|
||||
9
libwvdrmengine/cdm/src/logger_global.cpp
Normal file
9
libwvdrmengine/cdm/src/logger_global.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
|
||||
#include "logger_global.h"
|
||||
|
||||
namespace widevine {
|
||||
Cdm::ILogger* g_logger = nullptr;
|
||||
}
|
||||
281
libwvdrmengine/cdm/src/properties_ce.cpp
Normal file
281
libwvdrmengine/cdm/src/properties_ce.cpp
Normal file
@@ -0,0 +1,281 @@
|
||||
// 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 "properties_ce.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "cdm_version.h"
|
||||
#include "compiler_detection.h"
|
||||
#include "log.h"
|
||||
#include "properties.h"
|
||||
#include "read_client_info.h"
|
||||
#include "string_format.h"
|
||||
|
||||
// This anonymous namespace is shared between both the widevine namespace and
|
||||
// wvcdm namespace objects below.
|
||||
namespace {
|
||||
|
||||
bool use_secure_buffers_ = false;
|
||||
bool use_fifo_ = false;
|
||||
bool use_userspace_buffers_ = true;
|
||||
bool set_provisioning_messages_to_binary_ = false;
|
||||
std::string sandbox_id_;
|
||||
|
||||
widevine::Cdm::SecureOutputType secure_output_type_ =
|
||||
widevine::Cdm::kNoSecureOutput;
|
||||
|
||||
bool client_info_is_valid_;
|
||||
std::string company_name_;
|
||||
std::string model_name_;
|
||||
std::string model_year_;
|
||||
std::string product_name_;
|
||||
std::string device_name_;
|
||||
std::string arch_name_;
|
||||
std::string build_info_;
|
||||
|
||||
bool isClientInfoFieldValid(const char* tag, const char* value) {
|
||||
constexpr char kForbiddenSeparator[] = " | ";
|
||||
constexpr char kForbiddenPercent[] = "%";
|
||||
if (value[0] == '\0') {
|
||||
LOGE("%s may not be empty, but it is.", tag);
|
||||
return false;
|
||||
}
|
||||
if (strstr(value, kForbiddenSeparator) != nullptr) {
|
||||
LOGE("%s may not contain \"%s\", but it's \"%s\"", tag, kForbiddenSeparator,
|
||||
value);
|
||||
return false;
|
||||
}
|
||||
if (strstr(value, kForbiddenPercent) != nullptr) {
|
||||
LOGE("%s may not contain \"%s\", but it's \"%s\"", tag, kForbiddenPercent,
|
||||
value);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetClientInfo() {
|
||||
std::string platform;
|
||||
std::string form_factor;
|
||||
std::string version;
|
||||
|
||||
#if defined(RUNTIME_CLIENT_INFO)
|
||||
if (!widevine::ReadClientInformation(
|
||||
&company_name_, &model_name_, &model_year_, &product_name_,
|
||||
&device_name_, &arch_name_, &platform, &form_factor, &version)) {
|
||||
LOGE("ReadClientInformation failed.");
|
||||
client_info_is_valid_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(isClientInfoFieldValid("company_name", company_name_.c_str()) &&
|
||||
isClientInfoFieldValid("model_name", model_name_.c_str()) &&
|
||||
isClientInfoFieldValid("model_year", model_year_.c_str()) &&
|
||||
isClientInfoFieldValid("product_name", product_name_.c_str()) &&
|
||||
isClientInfoFieldValid("device_name", device_name_.c_str()) &&
|
||||
isClientInfoFieldValid("arch_name", arch_name_.c_str()) &&
|
||||
isClientInfoFieldValid("platform", platform.c_str()) &&
|
||||
isClientInfoFieldValid("form_factor", form_factor.c_str()) &&
|
||||
isClientInfoFieldValid("version", version.c_str()))) {
|
||||
client_info_is_valid_ = false;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (!(isClientInfoFieldValid("CLIENT_COMPANY_NAME", CLIENT_COMPANY_NAME) &&
|
||||
isClientInfoFieldValid("CLIENT_MODEL_NAME", CLIENT_MODEL_NAME) &&
|
||||
isClientInfoFieldValid("CLIENT_MODEL_YEAR", CLIENT_MODEL_YEAR) &&
|
||||
isClientInfoFieldValid("CLIENT_PRODUCT_NAME", CLIENT_PRODUCT_NAME) &&
|
||||
isClientInfoFieldValid("CLIENT_DEVICE_NAME", CLIENT_DEVICE_NAME) &&
|
||||
isClientInfoFieldValid("CLIENT_ARCH_NAME", CLIENT_ARCH_NAME) &&
|
||||
isClientInfoFieldValid("CLIENT_PLATFORM", CLIENT_PLATFORM) &&
|
||||
isClientInfoFieldValid("CLIENT_FORM_FACTOR", CLIENT_FORM_FACTOR) &&
|
||||
isClientInfoFieldValid("CLIENT_VERSION", CLIENT_VERSION))) {
|
||||
client_info_is_valid_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
company_name_ = CLIENT_COMPANY_NAME;
|
||||
model_name_ = CLIENT_MODEL_NAME;
|
||||
model_year_ = CLIENT_MODEL_YEAR;
|
||||
product_name_ = CLIENT_PRODUCT_NAME;
|
||||
device_name_ = CLIENT_DEVICE_NAME;
|
||||
arch_name_ = CLIENT_ARCH_NAME;
|
||||
platform = CLIENT_PLATFORM;
|
||||
form_factor = CLIENT_FORM_FACTOR;
|
||||
version = CLIENT_VERSION;
|
||||
#endif
|
||||
|
||||
if (!wvutil::FormatString(
|
||||
&build_info_, "%s | %s | %s | %s | CE CDM %s | %s | %s | %s",
|
||||
version.c_str(), platform.c_str(), form_factor.c_str(),
|
||||
arch_name_.c_str(), CDM_VERSION, CPU_ARCH_MESSAGE, LOGGING_MESSAGE,
|
||||
BUILD_FLAVOR_MESSAGE)) {
|
||||
client_info_is_valid_ = false;
|
||||
LOGE("Formatting the build info failed.");
|
||||
} else {
|
||||
client_info_is_valid_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool GetValue(const char* source, std::string* output) {
|
||||
if (!source || !output) {
|
||||
return false;
|
||||
}
|
||||
*output = source;
|
||||
return source[0] != '\0';
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace widevine {
|
||||
|
||||
// static
|
||||
void PropertiesCE::SetSecureOutputType(
|
||||
Cdm::SecureOutputType secure_output_type) {
|
||||
secure_output_type_ = secure_output_type;
|
||||
|
||||
switch (secure_output_type) {
|
||||
case Cdm::kOpaqueHandle:
|
||||
use_secure_buffers_ = true;
|
||||
use_fifo_ = false;
|
||||
use_userspace_buffers_ = false;
|
||||
break;
|
||||
case Cdm::kDirectRender:
|
||||
use_secure_buffers_ = false;
|
||||
use_fifo_ = true;
|
||||
use_userspace_buffers_ = false;
|
||||
break;
|
||||
case Cdm::kNoSecureOutput:
|
||||
default:
|
||||
use_secure_buffers_ = false;
|
||||
use_fifo_ = false;
|
||||
use_userspace_buffers_ = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
Cdm::SecureOutputType PropertiesCE::GetSecureOutputType() {
|
||||
return secure_output_type_;
|
||||
}
|
||||
|
||||
// static
|
||||
void PropertiesCE::SetProvisioningMessagesAreBinary(bool new_setting) {
|
||||
set_provisioning_messages_to_binary_ = new_setting;
|
||||
}
|
||||
|
||||
// static
|
||||
void PropertiesCE::SetSandboxId(const std::string& sandbox_id) {
|
||||
sandbox_id_ = sandbox_id;
|
||||
}
|
||||
|
||||
// static
|
||||
bool PropertiesCE::ClientInfoIsValid() { return client_info_is_valid_; }
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
// static
|
||||
void Properties::InitOnce() {
|
||||
oem_crypto_use_secure_buffers_ = use_secure_buffers_;
|
||||
oem_crypto_use_fifo_ = use_fifo_;
|
||||
oem_crypto_use_userspace_buffers_ = use_userspace_buffers_;
|
||||
provisioning_messages_are_binary_ = set_provisioning_messages_to_binary_;
|
||||
allow_service_certificate_requests_ = false;
|
||||
device_files_is_a_real_filesystem_ = false;
|
||||
allow_restore_of_offline_licenses_with_release_ = true;
|
||||
delay_oem_crypto_termination_ = false;
|
||||
SetClientInfo();
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(session_mutex_);
|
||||
session_property_set_.reset(new CdmClientPropertySetMap());
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool Properties::GetCompanyName(std::string* company_name) {
|
||||
return GetValue(company_name_.c_str(), company_name);
|
||||
}
|
||||
|
||||
// static
|
||||
bool Properties::GetModelName(std::string* model_name) {
|
||||
return GetValue(model_name_.c_str(), model_name);
|
||||
}
|
||||
|
||||
// static
|
||||
bool Properties::GetModelYear(std::string* model_year) {
|
||||
return GetValue(model_year_.c_str(), model_year);
|
||||
}
|
||||
|
||||
// static
|
||||
bool Properties::GetArchitectureName(std::string* arch_name) {
|
||||
return GetValue(arch_name_.c_str(), arch_name);
|
||||
}
|
||||
|
||||
// static
|
||||
bool Properties::GetDeviceName(std::string* device_name) {
|
||||
return GetValue(device_name_.c_str(), device_name);
|
||||
}
|
||||
|
||||
// static
|
||||
bool Properties::GetProductName(std::string* product_name) {
|
||||
return GetValue(product_name_.c_str(), product_name);
|
||||
}
|
||||
|
||||
// static
|
||||
bool Properties::GetBuildInfo(std::string* build_info) {
|
||||
return GetValue(build_info_.c_str(), build_info);
|
||||
}
|
||||
|
||||
// static
|
||||
bool Properties::GetWVCdmVersion(std::string* version) {
|
||||
return GetValue(CDM_VERSION, version);
|
||||
}
|
||||
|
||||
// static
|
||||
bool Properties::GetDeviceFilesBasePath(CdmSecurityLevel,
|
||||
std::string* base_path) {
|
||||
if (base_path == nullptr) return false;
|
||||
// A no-op, but successful.
|
||||
base_path->clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool Properties::GetFactoryKeyboxPath(std::string*) {
|
||||
// Unused on CE devices.
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
bool Properties::GetOEMCryptoPaths(std::vector<std::string>* paths) {
|
||||
if (paths == nullptr) return false;
|
||||
// Using an environment variable is useful for testing.
|
||||
const char* env_path = getenv("LIBOEMCRYPTO_PATH");
|
||||
if (env_path) {
|
||||
paths->push_back(std::string(env_path));
|
||||
} else {
|
||||
paths->push_back(std::string("liboemcrypto.so"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool Properties::GetSandboxId(std::string* sandbox_id_ptr) {
|
||||
if (sandbox_id_.empty() || sandbox_id_ptr == nullptr) return false;
|
||||
(*sandbox_id_ptr) = sandbox_id_;
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool Properties::AlwaysUseKeySetIds() { return true; }
|
||||
|
||||
// static
|
||||
bool Properties::UseProviderIdInProvisioningRequest() { return true; }
|
||||
|
||||
} // namespace wvcdm
|
||||
121
libwvdrmengine/cdm/test/cdm_reboot_test_main.cpp
Normal file
121
libwvdrmengine/cdm/test/cdm_reboot_test_main.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
|
||||
#include <assert.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(__linux__)
|
||||
# include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
#include "cdm.h"
|
||||
#include "cdm_test_runner.h"
|
||||
#include "clock.h"
|
||||
#include "log.h"
|
||||
#include "reboot_test.h"
|
||||
#include "test_base.h"
|
||||
#include "test_host.h"
|
||||
|
||||
using namespace widevine;
|
||||
|
||||
// TODO(b/195338975): document how a partner should modify this so that they can
|
||||
// use a real host.
|
||||
TestHost* g_host = nullptr;
|
||||
|
||||
namespace {
|
||||
constexpr char kGlobalDumpFileName[] = "dumped_global_filesystem.dat";
|
||||
constexpr char kPerOriginDumpFileName[] = "dumped_per_origin_filesystem.dat";
|
||||
|
||||
using StorageMap = TestHost::Storage::StorageMap;
|
||||
|
||||
// Load a TestHost file system from the real file system.
|
||||
bool ReloadFileSystem(const char* file_name, StorageMap* map) {
|
||||
std::ifstream input(file_name);
|
||||
if (input.fail()) {
|
||||
// This is OK for first pass, but an error for later passes.
|
||||
LOGD("Could not read %s", file_name);
|
||||
return false;
|
||||
}
|
||||
std::string dumped_file_system((std::istreambuf_iterator<char>(input)),
|
||||
std::istreambuf_iterator<char>());
|
||||
if (!wvcdm::RebootTest::ParseDump(dumped_file_system, map)) {
|
||||
LOGE("Could not parse %s", file_name);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReloadFileSystems() {
|
||||
StorageMap global_map;
|
||||
StorageMap per_origin_map;
|
||||
if (!ReloadFileSystem(kGlobalDumpFileName, &global_map) ||
|
||||
!ReloadFileSystem(kPerOriginDumpFileName, &per_origin_map)) {
|
||||
return false;
|
||||
}
|
||||
g_host->global_storage().ResetFiles(global_map);
|
||||
g_host->per_origin_storage().ResetFiles(per_origin_map);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Dump a TestHost file system to the real file system. If the dump file
|
||||
// cannot be written, this raises an exception and crashes the program. Since
|
||||
// we usually build with exceptions turned off, what this means is that the test
|
||||
// executable will halt if the file cannot be written.
|
||||
void DumpFileSystem(const char* file_name, const StorageMap& map) {
|
||||
std::string dump = wvcdm::RebootTest::DumpData(map);
|
||||
std::ofstream output(file_name);
|
||||
output << dump;
|
||||
output.close();
|
||||
}
|
||||
|
||||
void DumpFileSystems() {
|
||||
DumpFileSystem(kGlobalDumpFileName, g_host->global_storage().files());
|
||||
DumpFileSystem(kPerOriginDumpFileName, g_host->per_origin_storage().files());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// Set up a Host and initialize the library. This makes these services
|
||||
// available to the tests. We would do this in the test suite itself, but the
|
||||
// core & OEMCrypto tests don't know they depend on this for storage.
|
||||
g_host = new TestHost();
|
||||
ReloadFileSystems();
|
||||
|
||||
// Partners will want to replace this with a real IStorage.
|
||||
Cdm::IStorage* const storage = &g_host->global_storage();
|
||||
|
||||
// Partners may also want to replace this with real implementations of IClock
|
||||
// and ITimer. If so, make not to set the command line argument
|
||||
// "--fake_sleep".
|
||||
Cdm::IClock* const clock = g_host;
|
||||
Cdm::ITimer* const timer = g_host;
|
||||
|
||||
// Partners who prefer their logs to go somewhere other than stderr may want
|
||||
// to replace this implementation.
|
||||
Cdm::ILogger* const logger = &g_stderr_logger;
|
||||
|
||||
// If the tests need a separate file system from that used by the host, that
|
||||
// should be set up here. For the reference code, we use a default test file
|
||||
// system, but save the data from the file system.
|
||||
// A separate file system might be needed, for example, if the test data needs
|
||||
// to be saved off-device. Or, for example, if the main file system limits the
|
||||
// names and types of files it can save to certificates and offline licenses.
|
||||
wvutil::FileSystem* file_system = nullptr;
|
||||
wvcdm::RebootTest::set_file_system(file_system);
|
||||
|
||||
const int test_results = Main(storage, clock, timer, logger, argc, argv);
|
||||
DumpFileSystems();
|
||||
// This is used by the test driver to know what time to use for initializing
|
||||
// the fake clock for the next pass.
|
||||
std::cout << "END_OF_TEST " << wvutil::Clock().GetCurrentTime() << "\n";
|
||||
return test_results;
|
||||
}
|
||||
2516
libwvdrmengine/cdm/test/cdm_test.cpp
Normal file
2516
libwvdrmengine/cdm/test/cdm_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
44
libwvdrmengine/cdm/test/cdm_test_main.cpp
Normal file
44
libwvdrmengine/cdm/test/cdm_test_main.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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 <assert.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cdm.h"
|
||||
#include "cdm_test_runner.h"
|
||||
#include "log.h"
|
||||
#include "test_base.h"
|
||||
#include "test_host.h"
|
||||
|
||||
using namespace widevine;
|
||||
|
||||
TestHost* g_host = nullptr;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
g_host = new TestHost();
|
||||
|
||||
// TODO(b/195338975): document that using a real IStorage means you should not
|
||||
// run the tests in $CDM_DIR/cdm/test/cdm_test.cpp
|
||||
|
||||
// Partners will want to replace this with a real IStorage.
|
||||
Cdm::IStorage* const storage = &g_host->global_storage();
|
||||
|
||||
// Partners may also want to replace this with real implementations of IClock
|
||||
// and ITimer. If so, make not to set the command line argument
|
||||
// "--fake_sleep".
|
||||
Cdm::IClock* const clock = g_host;
|
||||
Cdm::ITimer* const timer = g_host;
|
||||
|
||||
// Partners who prefer their logs to go somewhere other than stderr may want
|
||||
// to replace this implementation.
|
||||
Cdm::ILogger* const logger = &g_stderr_logger;
|
||||
|
||||
const int test_results = Main(storage, clock, timer, logger, argc, argv);
|
||||
return test_results;
|
||||
}
|
||||
118
libwvdrmengine/cdm/test/cdm_test_printers.cpp
Normal file
118
libwvdrmengine/cdm/test/cdm_test_printers.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
// 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 "cdm_test_printers.h"
|
||||
|
||||
namespace widevine {
|
||||
|
||||
void PrintTo(const Cdm::MessageType& value, ::std::ostream* os) {
|
||||
switch (value) {
|
||||
case Cdm::kLicenseRequest:
|
||||
*os << "Cdm::kLicenseRequest";
|
||||
break;
|
||||
case Cdm::kLicenseRenewal:
|
||||
*os << "Cdm::kLicenseRenewal";
|
||||
break;
|
||||
case Cdm::kLicenseRelease:
|
||||
*os << "Cdm::kLicenseRelease";
|
||||
break;
|
||||
case Cdm::kIndividualizationRequest:
|
||||
*os << "Cdm::kIndividualizationRequest";
|
||||
break;
|
||||
default:
|
||||
*os << "Unknown Cdm::MessageType value " << value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PrintTo(const Cdm::Status& value, ::std::ostream* os) {
|
||||
switch (value) {
|
||||
case Cdm::kSuccess:
|
||||
*os << "Cdm::kSuccess";
|
||||
break;
|
||||
|
||||
case Cdm::kTypeError:
|
||||
*os << "Cdm::kTypeError";
|
||||
break;
|
||||
case Cdm::kNotSupported:
|
||||
*os << "Cdm::kNotSupported";
|
||||
break;
|
||||
case Cdm::kInvalidState:
|
||||
*os << "Cdm::kInvalidState";
|
||||
break;
|
||||
case Cdm::kQuotaExceeded:
|
||||
*os << "Cdm::kQuotaExceeded";
|
||||
break;
|
||||
|
||||
case Cdm::kNeedsDeviceCertificate:
|
||||
*os << "Cdm::kNeedsDeviceCertificate";
|
||||
break;
|
||||
case Cdm::kSessionNotFound:
|
||||
*os << "Cdm::kSessionNotFound";
|
||||
break;
|
||||
case Cdm::kDecryptError:
|
||||
*os << "Cdm::kDecryptError";
|
||||
break;
|
||||
case Cdm::kNoKey:
|
||||
*os << "Cdm::kNoKey";
|
||||
break;
|
||||
case Cdm::kKeyUsageBlockedByPolicy:
|
||||
*os << "Cdm::kKeyUsageBlockedByPolicy";
|
||||
break;
|
||||
case Cdm::kRangeError:
|
||||
*os << "Cdm::kRangeError";
|
||||
break;
|
||||
case Cdm::kResourceContention:
|
||||
*os << "Cdm::kResourceContention";
|
||||
break;
|
||||
case Cdm::kSessionStateLost:
|
||||
*os << "Cdm::kSessionStateLost";
|
||||
break;
|
||||
case Cdm::kSystemStateLost:
|
||||
*os << "Cdm::kSystemStateLost";
|
||||
break;
|
||||
case Cdm::kOutputTooLarge:
|
||||
*os << "Cdm::kOutputTooLarge";
|
||||
break;
|
||||
case Cdm::kNeedsServiceCertificate:
|
||||
*os << "Cdm::kNeedsServiceCertificate";
|
||||
break;
|
||||
|
||||
case Cdm::kUnexpectedError:
|
||||
*os << "Cdm::kUnexpectedError";
|
||||
break;
|
||||
|
||||
default:
|
||||
*os << "Unknown Cdm::Status value " << value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PrintTo(const Cdm::KeyStatus& value, ::std::ostream* os) {
|
||||
switch (value) {
|
||||
case Cdm::kUsable:
|
||||
*os << "Cdm::kUsable";
|
||||
break;
|
||||
case Cdm::kExpired:
|
||||
*os << "Cdm::kExpired";
|
||||
break;
|
||||
case Cdm::kOutputRestricted:
|
||||
*os << "Cdm::kOutputRestricted";
|
||||
break;
|
||||
case Cdm::kStatusPending:
|
||||
*os << "Cdm::kStatusPending";
|
||||
break;
|
||||
case Cdm::kInternalError:
|
||||
*os << "Cdm::kInternalError";
|
||||
break;
|
||||
case Cdm::kReleased:
|
||||
*os << "Cdm::kReleased";
|
||||
break;
|
||||
default:
|
||||
*os << "Unknown Cdm::KeyStatus value " << value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
21
libwvdrmengine/cdm/test/cdm_test_printers.h
Normal file
21
libwvdrmengine/cdm/test/cdm_test_printers.h
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
// This file adds some print methods so that when unit tests fail, the
|
||||
// will print the name of an enumeration instead of the numeric value.
|
||||
|
||||
#ifndef WVCDM_CDM_TEST_CDM_TEST_PRINTERS_H_
|
||||
#define WVCDM_CDM_TEST_CDM_TEST_PRINTERS_H_
|
||||
|
||||
#include <iostream>
|
||||
#include "cdm.h"
|
||||
|
||||
namespace widevine {
|
||||
|
||||
void PrintTo(const Cdm::MessageType& value, ::std::ostream* os);
|
||||
void PrintTo(const Cdm::Status& value, ::std::ostream* os);
|
||||
void PrintTo(const Cdm::KeyStatus& value, ::std::ostream* os);
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
#endif // WVCDM_CDM_TEST_CDM_TEST_PRINTERS_H_
|
||||
69
libwvdrmengine/cdm/test/cdm_test_runner.cpp
Normal file
69
libwvdrmengine/cdm/test/cdm_test_runner.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
|
||||
#include <assert.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cdm.h"
|
||||
#include "log.h"
|
||||
#include "stderr_logger.h"
|
||||
#include "test_base.h"
|
||||
#include "test_host.h"
|
||||
|
||||
widevine::StderrLogger g_stderr_logger;
|
||||
std::string g_sandbox_id;
|
||||
|
||||
namespace widevine {
|
||||
namespace {
|
||||
constexpr char kSandboxIdParam[] = "--sandbox_id=";
|
||||
|
||||
// Following the pattern established by help text in test_base.cpp
|
||||
constexpr char kExtraHelpText[] =
|
||||
" --sandbox_id=<sandbox_id>\n"
|
||||
" Specifies the Sandbox ID that should be sent to OEMCrypto via\n"
|
||||
" OEMCrypto_SetSandbox(). On most platforms, since Sandbox IDs are not\n"
|
||||
" in use, this parameter should be omitted.\n";
|
||||
} // namespace
|
||||
|
||||
int Main(Cdm::IStorage* storage, Cdm::IClock* clock, Cdm::ITimer* timer,
|
||||
Cdm::ILogger* logger, int argc, char** argv) {
|
||||
// Find and filter out the Sandbox ID, if any.
|
||||
std::vector<std::string> args(argv, argv + argc);
|
||||
auto sandbox_id_iter = std::find_if(std::begin(args) + 1, std::end(args),
|
||||
[](const std::string& elem) -> bool {
|
||||
return elem.find(kSandboxIdParam) == 0;
|
||||
});
|
||||
if (sandbox_id_iter != std::end(args)) {
|
||||
g_sandbox_id = sandbox_id_iter->substr(strlen(kSandboxIdParam));
|
||||
args.erase(sandbox_id_iter);
|
||||
}
|
||||
|
||||
Cdm::Status status = Cdm::initialize(
|
||||
Cdm::kOpaqueHandle, storage, clock, timer, logger,
|
||||
static_cast<Cdm::LogLevel>(wvutil::g_cutoff), g_sandbox_id);
|
||||
(void)status; // status is now used when assertions are turned off.
|
||||
assert(status == Cdm::kSuccess);
|
||||
|
||||
std::vector<const char*> new_argv(args.size());
|
||||
std::transform(
|
||||
std::begin(args), std::end(args), std::begin(new_argv),
|
||||
[](const std::string& arg) -> const char* { return arg.c_str(); });
|
||||
// This must take place after the call to Cdm::initialize() because it makes
|
||||
// calls that are only valid after the library is initialized.
|
||||
if (!wvcdm::WvCdmTestBase::Initialize(static_cast<int>(new_argv.size()),
|
||||
new_argv.data(), kExtraHelpText)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Init gtest after oemcrypto and cdm host have been initialized.
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
} // namespace widevine
|
||||
20
libwvdrmengine/cdm/test/cdm_test_runner.h
Normal file
20
libwvdrmengine/cdm/test/cdm_test_runner.h
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
|
||||
#ifndef WVCDM_CDM_TEST_CDM_TEST_RUNNER_H_
|
||||
#define WVCDM_CDM_TEST_CDM_TEST_RUNNER_H_
|
||||
|
||||
#include <iostream>
|
||||
#include "cdm.h"
|
||||
|
||||
namespace widevine {
|
||||
// Run all CDM tests using the specified storage, clock, and timer. It parses
|
||||
// standard command line arguments, sets some default test client info,
|
||||
// initializes a CDM object, and then runs all the tests.
|
||||
// Returns 0 on success.
|
||||
int Main(Cdm::IStorage* storage, Cdm::IClock* clock, Cdm::ITimer* timer,
|
||||
Cdm::ILogger* logger, int argc, char** argv);
|
||||
} // namespace widevine
|
||||
|
||||
#endif // WVCDM_CDM_TEST_CDM_TEST_RUNNER_H_
|
||||
@@ -4,4 +4,8 @@
|
||||
|
||||
#include "create_test_file_system.h"
|
||||
|
||||
wvutil::FileSystem* CreateTestFileSystem() { return new wvutil::FileSystem(); }
|
||||
#include "test_host.h"
|
||||
|
||||
wvutil::FileSystem* CreateTestFileSystem() {
|
||||
return new wvutil::FileSystem("", &g_host->per_origin_storage());
|
||||
}
|
||||
|
||||
122583
libwvdrmengine/cdm/test/decryption_test_data.h
Normal file
122583
libwvdrmengine/cdm/test/decryption_test_data.h
Normal file
File diff suppressed because it is too large
Load Diff
14
libwvdrmengine/cdm/test/dummy_app.mm
Normal file
14
libwvdrmengine/cdm/test/dummy_app.mm
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright 2019 Google LLC. All Rights Reserved.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||
@end
|
||||
|
||||
@implementation AppDelegate {
|
||||
}
|
||||
@end
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||
}
|
||||
23
libwvdrmengine/cdm/test/gtest_xctest_wrapper.mm
Normal file
23
libwvdrmengine/cdm/test/gtest_xctest_wrapper.mm
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2019 Google LLC. All Rights Reserved.
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// Defined in cdm_test_main.cpp.
|
||||
int main(int argc, char** argv);
|
||||
|
||||
@interface GtestTests : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation GtestTests
|
||||
|
||||
- (void)testAll {
|
||||
testing::GTEST_FLAG(filter) = GTEST_FILTER;
|
||||
|
||||
char arg0[] = "tests";
|
||||
char* argv[] = {arg0, nullptr};
|
||||
XCTAssertEqual(main(1, argv), 0);
|
||||
}
|
||||
|
||||
@end
|
||||
25
libwvdrmengine/cdm/test/info.plist
Normal file
25
libwvdrmengine/cdm/test/info.plist
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>EQHXZ8M8AV.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
64
libwvdrmengine/cdm/test/level3_file_system_ce_test.cpp
Normal file
64
libwvdrmengine/cdm/test/level3_file_system_ce_test.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
|
||||
/**
|
||||
The test file system for the Level 3 OEMCrypto sits on top of the host file
|
||||
system. A real production version may either use the host file system or it
|
||||
may write files directly to the file system.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "level3_file_system_ce_test.h"
|
||||
|
||||
#include "test_host.h"
|
||||
|
||||
namespace wvoec3 {
|
||||
|
||||
ssize_t OEMCrypto_Level3CETestFileSystem::Read(const char* filename,
|
||||
void* buffer, size_t size) {
|
||||
if (!g_host) return 0;
|
||||
const std::string name(filename);
|
||||
if (!g_host->global_storage().exists(name)) return 0;
|
||||
std::string data;
|
||||
if (!g_host->global_storage().read(name, &data)) return 0;
|
||||
size_t bytes_read = std::min(size, data.size());
|
||||
memcpy(buffer, data.data(), bytes_read);
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
ssize_t OEMCrypto_Level3CETestFileSystem::Write(const char* filename,
|
||||
const void* buffer,
|
||||
size_t size) {
|
||||
if (!g_host) return 0;
|
||||
std::string data(static_cast<const char*>(buffer), size);
|
||||
const std::string name(filename);
|
||||
if (!g_host->global_storage().write(name, data)) return 0;
|
||||
return size;
|
||||
}
|
||||
|
||||
bool OEMCrypto_Level3CETestFileSystem::Exists(const char* filename) {
|
||||
if (!g_host) return false;
|
||||
const std::string name(filename);
|
||||
return g_host->global_storage().exists(name);
|
||||
}
|
||||
|
||||
ssize_t OEMCrypto_Level3CETestFileSystem::FileSize(const char* filename) {
|
||||
if (!g_host) return 0;
|
||||
const std::string name(filename);
|
||||
if (!g_host->global_storage().exists(name)) return 0;
|
||||
return static_cast<ssize_t>(g_host->global_storage().size(name));
|
||||
}
|
||||
|
||||
bool OEMCrypto_Level3CETestFileSystem::Remove(const char* filename) {
|
||||
if (!g_host) return false;
|
||||
const std::string name(filename);
|
||||
if (!g_host->global_storage().exists(name)) return false;
|
||||
return g_host->global_storage().remove(name);
|
||||
}
|
||||
|
||||
} // namespace wvoec3
|
||||
33
libwvdrmengine/cdm/test/level3_file_system_ce_test.h
Normal file
33
libwvdrmengine/cdm/test/level3_file_system_ce_test.h
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
|
||||
/*********************************************************************
|
||||
* level3_file_system_ce_test.h
|
||||
*
|
||||
* Test file system for CE CDM for OEMCrypto Level3 File Operations.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef LEVEL3_FILE_SYSTEM_CE_TEST_H_
|
||||
#define LEVEL3_FILE_SYSTEM_CE_TEST_H_
|
||||
|
||||
#include "cdm.h"
|
||||
#include "file_store.h"
|
||||
#include "level3_file_system.h"
|
||||
|
||||
namespace wvoec3 {
|
||||
|
||||
class OEMCrypto_Level3CETestFileSystem : public OEMCrypto_Level3FileSystem {
|
||||
public:
|
||||
OEMCrypto_Level3CETestFileSystem() {}
|
||||
~OEMCrypto_Level3CETestFileSystem() override {}
|
||||
ssize_t Read(const char* filename, void* buffer, size_t size) override;
|
||||
ssize_t Write(const char* filename, const void* buffer, size_t size) override;
|
||||
bool Exists(const char* filename) override;
|
||||
ssize_t FileSize(const char* filename) override;
|
||||
bool Remove(const char* filename) override;
|
||||
};
|
||||
|
||||
} // namespace wvoec3
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "level3.h"
|
||||
|
||||
#include "level3_file_system_ce_test.h"
|
||||
|
||||
namespace wvoec3 {
|
||||
|
||||
OEMCrypto_Level3FileSystem* createLevel3FileSystem() {
|
||||
return new OEMCrypto_Level3CETestFileSystem();
|
||||
}
|
||||
|
||||
void deleteLevel3FileSystem(OEMCrypto_Level3FileSystem* file_system) {
|
||||
if (file_system) {
|
||||
delete file_system;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wvoec3
|
||||
349
libwvdrmengine/cdm/test/perf_test.cpp
Normal file
349
libwvdrmengine/cdm/test/perf_test.cpp
Normal file
@@ -0,0 +1,349 @@
|
||||
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
|
||||
#include "perf_test.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "config_test_env.h"
|
||||
#include "license_request.h"
|
||||
#include "logger_global.h"
|
||||
#include "test_host.h"
|
||||
#include "url_request.h"
|
||||
|
||||
#define ASSERT_SUCCESS(code) ASSERT_EQ(code, Cdm::kSuccess)
|
||||
#define EXPECT_SUCCESS(code) EXPECT_EQ(code, Cdm::kSuccess)
|
||||
|
||||
#define WALL_NOW std::chrono::high_resolution_clock::now()
|
||||
|
||||
TestHost* g_host = nullptr;
|
||||
widevine::StderrLogger g_stderr_logger;
|
||||
|
||||
namespace widevine {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const size_t kTestCount = 50;
|
||||
|
||||
const wvcdm::ConfigTestEnv kTestData(wvcdm::kContentProtectionUatServer);
|
||||
CreateFuncType create_func = nullptr;
|
||||
|
||||
using TimeType = std::chrono::duration<double, std::milli>;
|
||||
|
||||
struct PerfInfo {
|
||||
double mean;
|
||||
double min;
|
||||
double max;
|
||||
double std_dev;
|
||||
|
||||
template <size_t Size>
|
||||
PerfInfo(const double (&values)[Size]) {
|
||||
static_assert(Size > 0, "Must pass at least one value");
|
||||
|
||||
// First pass to calculate min/max/mean.
|
||||
bool first = true;
|
||||
double sum = 0;
|
||||
for (auto v : values) {
|
||||
sum += v;
|
||||
if (first) {
|
||||
min = max = v;
|
||||
first = false;
|
||||
} else {
|
||||
if (v < min) min = v;
|
||||
if (v > max) max = v;
|
||||
}
|
||||
}
|
||||
mean = sum / Size;
|
||||
|
||||
// Second pass to calculate standard deviation.
|
||||
sum = 0;
|
||||
for (auto v : values) {
|
||||
sum += (v - mean) * (v - mean);
|
||||
}
|
||||
std_dev = std::sqrt(sum / Size);
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const PerfInfo& info) {
|
||||
// mean=12.33442, std-dev=1.44421, min=1.22431, max=244.1133144
|
||||
return os << "mean=" << info.mean << ", std-dev=" << info.std_dev
|
||||
<< ", min=" << info.min << ", max=" << info.max;
|
||||
}
|
||||
|
||||
class PerfTracker {
|
||||
public:
|
||||
class Test {
|
||||
public:
|
||||
Test(PerfTracker* tracker)
|
||||
: wall_start_(WALL_NOW), cpu_start_(std::clock()), tracker_(tracker) {}
|
||||
|
||||
~Test() {
|
||||
tracker_->wall_times_[tracker_->index_] =
|
||||
TimeType(WALL_NOW - wall_start_).count();
|
||||
tracker_->cpu_times_[tracker_->index_] =
|
||||
(std::clock() - cpu_start_) * 1000.0 / CLOCKS_PER_SEC;
|
||||
tracker_->index_++;
|
||||
}
|
||||
|
||||
private:
|
||||
std::chrono::high_resolution_clock::time_point wall_start_;
|
||||
std::clock_t cpu_start_;
|
||||
PerfTracker* tracker_;
|
||||
};
|
||||
|
||||
void Print(const std::string& name, size_t block_size_bytes = 0) {
|
||||
PerfInfo wall_perf(wall_times_);
|
||||
PerfInfo cpu_perf(cpu_times_);
|
||||
std::cout << name << " (wall, ms): " << wall_perf << "\n";
|
||||
std::cout << name << " (cpu, ms): " << cpu_perf << "\n";
|
||||
if (block_size_bytes) {
|
||||
// |mean| is in milliseconds.
|
||||
std::cout << name << " (wall, MBit/sec): "
|
||||
<< (block_size_bytes * 8 * 1000 / wall_perf.mean / 1024 / 1024)
|
||||
<< "\n";
|
||||
std::cout << name << " (cpu, MBit/sec): "
|
||||
<< (block_size_bytes * 8 * 1000 / cpu_perf.mean / 1024 / 1024)
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
double wall_times_[kTestCount];
|
||||
double cpu_times_[kTestCount];
|
||||
size_t index_ = 0;
|
||||
};
|
||||
|
||||
#define MEASURE_PERF(tracker, code) \
|
||||
{ \
|
||||
PerfTracker::Test test(&(tracker)); \
|
||||
code; \
|
||||
}
|
||||
|
||||
class EventListener : public Cdm::IEventListener {
|
||||
public:
|
||||
struct MessageInfo {
|
||||
std::string session_id;
|
||||
std::string message;
|
||||
Cdm::MessageType message_type;
|
||||
std::string url;
|
||||
};
|
||||
|
||||
void onMessage(const std::string& session_id, Cdm::MessageType message_type,
|
||||
const std::string& message, const std::string& url) override {
|
||||
messages.push_back({session_id, message, message_type, url});
|
||||
}
|
||||
void onKeyStatusesChange(const std::string& session_id,
|
||||
bool has_new_usable_key) override {}
|
||||
void onExpirationChange(const std::string& session_id,
|
||||
int64_t new_expiration) override {}
|
||||
void onRemoveComplete(const std::string& session_id) override {}
|
||||
|
||||
std::vector<MessageInfo> messages;
|
||||
};
|
||||
|
||||
bool SendPost(const std::string& message, std::string* response) {
|
||||
wvcdm::UrlRequest req(kTestData.license_server());
|
||||
std::string raw_response;
|
||||
if (!req.is_connected() || !req.PostRequest(message) ||
|
||||
!req.GetResponse(&raw_response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wvcdm::LicenseRequest helper;
|
||||
helper.GetDrmMessage(raw_response, *response);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<Cdm> CreateCdm(EventListener* event_listener) {
|
||||
std::unique_ptr<Cdm> ret(
|
||||
create_func(event_listener, &g_host->per_origin_storage(), true));
|
||||
if (ret) {
|
||||
EXPECT_SUCCESS(ret->setServiceCertificate(
|
||||
Cdm::kProvisioningService,
|
||||
kTestData.provisioning_service_certificate()));
|
||||
EXPECT_SUCCESS(ret->setServiceCertificate(
|
||||
Cdm::kLicensingService, kTestData.license_service_certificate()));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
class GlobalEnv : public testing::Environment {
|
||||
public:
|
||||
GlobalEnv(InitFuncType init_func, const std::string& cert)
|
||||
: init_func_(init_func), cert_(cert) {}
|
||||
|
||||
void SetUp() override {
|
||||
// Manually set the logger because `TestHost` makes logging calls before
|
||||
// the global logger is set in |init_func_|.
|
||||
g_logger = &g_stderr_logger;
|
||||
|
||||
g_host = new TestHost;
|
||||
if (!cert_.empty()) g_host->per_origin_storage().write("cert.bin", cert_);
|
||||
|
||||
Cdm::LogLevel log_level = Cdm::kErrors;
|
||||
if (const char* verbose = getenv("VERBOSE_OUTPUT")) {
|
||||
if (std::strcmp(verbose, "1") == 0) log_level = Cdm::kVerbose;
|
||||
}
|
||||
ASSERT_SUCCESS(init_func_(Cdm::kNoSecureOutput, &g_host->global_storage(),
|
||||
g_host, g_host, &g_stderr_logger, log_level));
|
||||
}
|
||||
|
||||
private:
|
||||
const InitFuncType init_func_;
|
||||
const std::string cert_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class PerfTest : public testing::Test {};
|
||||
|
||||
TEST_F(PerfTest, LicenseExchange) {
|
||||
EventListener event_listener;
|
||||
auto cdm = CreateCdm(&event_listener);
|
||||
ASSERT_TRUE(cdm);
|
||||
ASSERT_EQ(cdm->getProvisioningStatus(), Cdm::kProvisioned);
|
||||
|
||||
PerfTracker create;
|
||||
PerfTracker generate;
|
||||
PerfTracker update;
|
||||
PerfTracker close;
|
||||
for (size_t i = 0; i < kTestCount; i++) {
|
||||
std::string session_id;
|
||||
MEASURE_PERF(create, ASSERT_SUCCESS(
|
||||
cdm->createSession(Cdm::kTemporary, &session_id)));
|
||||
|
||||
MEASURE_PERF(
|
||||
generate,
|
||||
ASSERT_SUCCESS(cdm->generateRequest(
|
||||
session_id, Cdm::kCenc,
|
||||
wvcdm::ConfigTestEnv::GetInitData(wvcdm::kContentIdStreaming))));
|
||||
|
||||
std::string response;
|
||||
ASSERT_TRUE(SendPost(event_listener.messages[0].message, &response));
|
||||
|
||||
MEASURE_PERF(update, ASSERT_SUCCESS(cdm->update(session_id, response)));
|
||||
|
||||
MEASURE_PERF(close, ASSERT_SUCCESS(cdm->close(session_id)));
|
||||
|
||||
event_listener.messages.pop_back();
|
||||
}
|
||||
|
||||
create.Print("Create ");
|
||||
generate.Print("Generate");
|
||||
update.Print("Update ");
|
||||
close.Print("Close ");
|
||||
}
|
||||
|
||||
class DecryptPerfTest : public PerfTest,
|
||||
public testing::WithParamInterface<bool> {};
|
||||
|
||||
TEST_P(DecryptPerfTest, Decrypt) {
|
||||
EventListener event_listener;
|
||||
auto cdm = CreateCdm(&event_listener);
|
||||
ASSERT_TRUE(cdm);
|
||||
ASSERT_EQ(cdm->getProvisioningStatus(), Cdm::kProvisioned);
|
||||
|
||||
std::string session_id;
|
||||
ASSERT_SUCCESS(cdm->createSession(Cdm::kTemporary, &session_id));
|
||||
ASSERT_SUCCESS(cdm->generateRequest(
|
||||
session_id, Cdm::kCenc,
|
||||
wvcdm::ConfigTestEnv::GetInitData(wvcdm::kContentIdStreaming)));
|
||||
|
||||
std::string response;
|
||||
ASSERT_TRUE(SendPost(event_listener.messages[0].message, &response));
|
||||
ASSERT_SUCCESS(cdm->update(session_id, response));
|
||||
|
||||
Cdm::KeyStatusMap statuses;
|
||||
ASSERT_SUCCESS(cdm->getKeyStatuses(session_id, &statuses));
|
||||
ASSERT_GT(statuses.size(), 0u);
|
||||
const std::string key_id = statuses.begin()->first;
|
||||
|
||||
// Use in-place decrypt to avoid allocations. We don't care about the data,
|
||||
// so we can just decrypt the same buffer again.
|
||||
constexpr const size_t k16M = 16 * 1024 * 1024;
|
||||
std::vector<uint8_t> buffer(k16M);
|
||||
uint8_t iv[16];
|
||||
for (auto& b : buffer) b = rand();
|
||||
|
||||
Cdm::DecryptionBatch batch;
|
||||
batch.key_id = reinterpret_cast<const uint8_t*>(key_id.data());
|
||||
batch.key_id_length = static_cast<uint32_t>(key_id.size());
|
||||
if (GetParam()) {
|
||||
batch.pattern.encrypted_blocks = batch.pattern.clear_blocks = 0;
|
||||
} else {
|
||||
batch.pattern.encrypted_blocks = 1;
|
||||
batch.pattern.clear_blocks = 9;
|
||||
}
|
||||
batch.is_secure = false;
|
||||
batch.encryption_scheme = GetParam() ? Cdm::kAesCtr : Cdm::kAesCbc;
|
||||
batch.is_video = true;
|
||||
|
||||
Cdm::Subsample subsample;
|
||||
subsample.clear_bytes = 0;
|
||||
// subsample.encrypted_bytes set in the test.
|
||||
Cdm::Sample sample;
|
||||
sample.input.iv = iv;
|
||||
sample.input.iv_length = 16;
|
||||
sample.input.data = buffer.data();
|
||||
// sample.data_length set in the test.
|
||||
sample.input.subsamples = &subsample;
|
||||
sample.input.subsamples_length = 1;
|
||||
sample.output.data = buffer.data();
|
||||
sample.output.data_offset = 0;
|
||||
sample.output.data_length = static_cast<uint32_t>(buffer.size());
|
||||
batch.samples = &sample;
|
||||
batch.samples_length = 1;
|
||||
|
||||
constexpr const size_t block_sizes[] = {8 * 1024, 256 * 1024, k16M};
|
||||
constexpr const size_t sizes_count =
|
||||
sizeof(block_sizes) / sizeof(block_sizes[0]);
|
||||
const std::string block_names[] = {" 8k", "256k", " 16M"};
|
||||
PerfTracker perf[sizes_count];
|
||||
for (size_t i = 0; i < sizes_count; i++) {
|
||||
subsample.protected_bytes = sample.input.data_length =
|
||||
sample.output.data_length = static_cast<uint32_t>(block_sizes[i]);
|
||||
for (size_t j = 0; j < kTestCount; j++) {
|
||||
MEASURE_PERF(perf[i], ASSERT_SUCCESS(cdm->decrypt(batch)));
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sizes_count; i++) {
|
||||
perf[i].Print("Decrypt " + block_names[i], block_sizes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
std::string PrintDecryptParam(const testing::TestParamInfo<bool>& info) {
|
||||
return info.param ? "CTR" : "CBC";
|
||||
}
|
||||
INSTANTIATE_TEST_SUITE_P(Decrypt, DecryptPerfTest, testing::Bool(),
|
||||
PrintDecryptParam);
|
||||
|
||||
int PerfTestMain(InitFuncType init_func, CreateFuncType create,
|
||||
const std::string& cert) {
|
||||
#ifdef _DEBUG
|
||||
// Don't use #error since we build all targets and we don't want to fail the
|
||||
// debug build (and we can't have configuration-specific targets).
|
||||
fprintf(stderr, "Don't run performance tests in Debug mode\n");
|
||||
return 1;
|
||||
#else
|
||||
create_func = create;
|
||||
testing::AddGlobalTestEnvironment(new GlobalEnv(init_func, cert));
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
24
libwvdrmengine/cdm/test/perf_test.h
Normal file
24
libwvdrmengine/cdm/test/perf_test.h
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
|
||||
#ifndef WVCDM_CDM_TEST_PERF_TEST_H_
|
||||
#define WVCDM_CDM_TEST_PERF_TEST_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "cdm.h"
|
||||
|
||||
namespace widevine {
|
||||
|
||||
using InitFuncType = Cdm::Status (*)(Cdm::SecureOutputType, Cdm::IStorage*,
|
||||
Cdm::IClock*, Cdm::ITimer*, Cdm::ILogger*,
|
||||
Cdm::LogLevel);
|
||||
using CreateFuncType = Cdm* (*)(Cdm::IEventListener*, Cdm::IStorage*, bool);
|
||||
|
||||
int PerfTestMain(InitFuncType init_func, CreateFuncType create_func,
|
||||
const std::string& cert);
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
#endif // WVCDM_CDM_TEST_PERF_TEST_H_
|
||||
84
libwvdrmengine/cdm/test/perf_test_dynamic.cpp
Normal file
84
libwvdrmengine/cdm/test/perf_test_dynamic.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
|
||||
// This uses dlopen() which is only usable on POSIX platforms. The function
|
||||
// names assume GCC/Clang.
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <tuple>
|
||||
|
||||
#include "clock.h"
|
||||
#include "perf_test.h"
|
||||
#include "test_host.h"
|
||||
|
||||
namespace widevine {
|
||||
|
||||
constexpr char kInitName[] =
|
||||
"_ZN8widevine3Cdm10initializeENS0_16SecureOutputTypeEPNS0_8IStorageEPNS0_"
|
||||
"6IClockEPNS0_6ITimerEPNS0_7ILoggerENS0_8LogLevelE";
|
||||
constexpr char kCreateName[] =
|
||||
"_ZN8widevine3Cdm6createEPNS0_14IEventListenerEPNS0_8IStorageEbb";
|
||||
|
||||
bool ReadFile(const std::string& path, std::string* output) {
|
||||
constexpr size_t kReadSize = 8 * 1024;
|
||||
std::ifstream fs(path, std::ios::in | std::ios::binary);
|
||||
if (!fs) return false;
|
||||
while (true) {
|
||||
const size_t offset = output->size();
|
||||
output->resize(output->size() + kReadSize);
|
||||
fs.read(&output->at(offset), kReadSize);
|
||||
if (fs.eof()) {
|
||||
output->resize(offset + fs.gcount());
|
||||
return true;
|
||||
} else if (!fs) {
|
||||
fprintf(stderr, "Error reading from cert file\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<InitFuncType, CreateFuncType> LoadCdm(const char* path) {
|
||||
// Note we will leak the library object; but this is just for tests and will
|
||||
// be unloaded when we exit anyway.
|
||||
auto dll = dlopen(path, RTLD_NOW);
|
||||
if (!dll) {
|
||||
fprintf(stderr, "Error loading so file: %s\n", dlerror());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
auto init = reinterpret_cast<InitFuncType>(dlsym(dll, kInitName));
|
||||
auto create = reinterpret_cast<CreateFuncType>(dlsym(dll, kCreateName));
|
||||
if (!init || !create) {
|
||||
fprintf(stderr, "Error finding CDM functions: %s\n", dlerror());
|
||||
exit(1);
|
||||
}
|
||||
return std::make_tuple(init, create);
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
namespace wvutil {
|
||||
|
||||
int64_t Clock::GetCurrentTime() { return g_host->now() / 1000; }
|
||||
|
||||
} // namespace wvutil
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s <CDM_SO_PATH> <CERT_PATH>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string cert;
|
||||
if (!widevine::ReadFile(argv[2], &cert))
|
||||
return 1;
|
||||
|
||||
auto funcs = widevine::LoadCdm(argv[1]);
|
||||
return widevine::PerfTestMain(std::get<0>(funcs), std::get<1>(funcs), cert);
|
||||
}
|
||||
26
libwvdrmengine/cdm/test/perf_test_xctest.mm
Normal file
26
libwvdrmengine/cdm/test/perf_test_xctest.mm
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#include "cdm.h"
|
||||
#include "perf_test.h"
|
||||
|
||||
@interface GtestTests : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation GtestTests
|
||||
|
||||
- (void)testAll {
|
||||
testing::GTEST_FLAG(filter) = GTEST_FILTER;
|
||||
char arg0[] = "tests";
|
||||
char* argv[] = {arg0, nullptr};
|
||||
int argc = 1;
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
XCTAssertEqual(widevine::PerfTestMain(&widevine::Cdm::initialize, &widevine::Cdm::create, ""), 0);
|
||||
}
|
||||
|
||||
@end
|
||||
185
libwvdrmengine/cdm/test/test_host.cpp
Normal file
185
libwvdrmengine/cdm/test/test_host.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
// 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 "test_host.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <chrono>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "cdm_version.h"
|
||||
#include "file_store.h"
|
||||
#include "log.h"
|
||||
|
||||
using namespace widevine;
|
||||
|
||||
namespace {
|
||||
|
||||
// Some files are expected to go in global storage. All other files are expected
|
||||
// to go in per-origin storage. To help us enforce this in tests, this set
|
||||
// tracks the filenames that belong in global storage. TestHost::Storage will
|
||||
// reject attempts to access these files via per-origin storage or to access
|
||||
// files not in this list via global storage.
|
||||
const std::unordered_set<std::string> kGlobalFilenames = {
|
||||
"usgtable.bin", // CDM usage table data
|
||||
"StoredUsageTime.dat", // Reference OEMCrypto usage table data
|
||||
"GenerationNumber.dat", // Reference OEMCrypto master generation number
|
||||
"persistent.dat", // Persistent data storage for certain TEE
|
||||
// implementations
|
||||
"keybox.dat", // Legacy file for storing keybox in non-secure storage.
|
||||
// CDM data for OTA keybox renewal.
|
||||
"okp.bin",
|
||||
"debug_ignore_keybox_count.txt",
|
||||
"debug_allow_test_keybox.txt",
|
||||
// Widevine L3 data files.
|
||||
"ay64.dat",
|
||||
"ay64.dat2",
|
||||
"ay64.dat3",
|
||||
"ay64.dat4",
|
||||
"ay64.dat5",
|
||||
"ay64.dat6",
|
||||
"l3_failure_file",
|
||||
wvutil::kOemCertificateFileName,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TestHost::TestHost() : global_storage_(true), per_origin_storage_(false) {
|
||||
Reset();
|
||||
}
|
||||
TestHost::~TestHost() { wvutil::TestSleep::set_callback(nullptr); }
|
||||
|
||||
void TestHost::Reset() {
|
||||
auto now = std::chrono::system_clock().now();
|
||||
now_ = now.time_since_epoch() / std::chrono::milliseconds(1);
|
||||
wvutil::TestSleep::set_callback(this);
|
||||
|
||||
// Surprisingly, std::priority_queue has no clear().
|
||||
while (!timers_.empty()) {
|
||||
timers_.pop();
|
||||
}
|
||||
|
||||
global_storage_.Reset();
|
||||
per_origin_storage_.Reset();
|
||||
}
|
||||
|
||||
void TestHost::ElapseTime(int64_t milliseconds) {
|
||||
// Note that, during the time rollback tests, milliseconds will be negative,
|
||||
// so we cannot assume goal_time > now_.
|
||||
int64_t goal_time = now_ + milliseconds;
|
||||
|
||||
// Walk forward from now_ to goal_time, stepping at each timer along the way
|
||||
// to fire its callback.
|
||||
while (!timers_.empty() && now_ < goal_time) {
|
||||
Timer t = timers_.top();
|
||||
ASSERT_GE(t.expiry_time(), now_);
|
||||
if (t.expiry_time() <= goal_time) {
|
||||
timers_.pop();
|
||||
now_ = t.expiry_time();
|
||||
t.client()->onTimerExpired(t.context());
|
||||
} else {
|
||||
// The next timer is further in the future than goal_time, so we are done
|
||||
// processing the timers.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// No matter what happened with the timers, update now_ to the goal_time.
|
||||
now_ = goal_time;
|
||||
}
|
||||
|
||||
size_t TestHost::NumTimers() const { return timers_.size(); }
|
||||
|
||||
int64_t TestHost::now() { return now_; }
|
||||
|
||||
void TestHost::setTimeout(int64_t delay_ms, IClient* client, void* context) {
|
||||
int64_t expiry_time = now_ + delay_ms;
|
||||
timers_.push(Timer(expiry_time, client, context));
|
||||
}
|
||||
|
||||
void TestHost::cancel(IClient* client) {
|
||||
// Filter out the timers for this client and put the rest into |others|.
|
||||
std::priority_queue<Timer> others;
|
||||
|
||||
while (timers_.size()) {
|
||||
Timer t = timers_.top();
|
||||
timers_.pop();
|
||||
|
||||
if (t.client() != client) {
|
||||
others.push(t);
|
||||
}
|
||||
}
|
||||
|
||||
// Now swap the queues.
|
||||
std::swap(timers_, others);
|
||||
}
|
||||
|
||||
TestHost::Storage::Storage(bool is_global) : is_global_(is_global) { Reset(); }
|
||||
|
||||
void TestHost::Storage::Reset() {
|
||||
files_.clear();
|
||||
}
|
||||
|
||||
bool TestHost::Storage::read(const std::string& name, std::string* data) {
|
||||
StorageMap::iterator it = files_.find(name);
|
||||
bool ok = it != files_.end();
|
||||
LOGV("read file: %s: %s", name.c_str(), ok ? "ok" : "fail");
|
||||
if (!CheckFilename(name) || !ok) return false;
|
||||
*data = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestHost::Storage::write(const std::string& name,
|
||||
const std::string& data) {
|
||||
LOGV("write file: %s", name.c_str());
|
||||
if (!CheckFilename(name)) return false;
|
||||
files_[name] = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestHost::Storage::exists(const std::string& name) {
|
||||
StorageMap::iterator it = files_.find(name);
|
||||
bool ok = it != files_.end();
|
||||
LOGV("exists? %s: %s", name.c_str(), ok ? "true" : "false");
|
||||
if (!CheckFilename(name)) return false;
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool TestHost::Storage::remove(const std::string& name) {
|
||||
if (name.empty()) {
|
||||
// If no name, delete all files (see DeviceFiles::DeleteAllFiles())
|
||||
LOGV("remove all files");
|
||||
files_.clear();
|
||||
return true;
|
||||
}
|
||||
LOGV("remove: %s", name.c_str());
|
||||
if (!CheckFilename(name)) return false;
|
||||
return files_.erase(name) > 0;
|
||||
}
|
||||
|
||||
int32_t TestHost::Storage::size(const std::string& name) {
|
||||
StorageMap::iterator it = files_.find(name);
|
||||
bool ok = (it != files_.end());
|
||||
LOGV("size? %s: %s", name.c_str(), ok ? "ok" : "fail");
|
||||
if (!CheckFilename(name) || !ok) return -1;
|
||||
return static_cast<int32_t>(it->second.size());
|
||||
}
|
||||
|
||||
bool TestHost::Storage::list(std::vector<std::string>* names) {
|
||||
names->clear();
|
||||
for (StorageMap::iterator it = files_.begin(); it != files_.end(); it++) {
|
||||
names->push_back(it->first);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestHost::Storage::CheckFilename(const std::string& name) {
|
||||
const bool is_global_filename =
|
||||
(kGlobalFilenames.find(name) != kGlobalFilenames.end());
|
||||
if (is_global_ != is_global_filename) {
|
||||
LOGE("Attempt to access %s in %s storage rejected.", name.c_str(),
|
||||
is_global_ ? "global" : "per-origin");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
101
libwvdrmengine/cdm/test/test_host.h
Normal file
101
libwvdrmengine/cdm/test/test_host.h
Normal file
@@ -0,0 +1,101 @@
|
||||
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
#ifndef WVCDM_CDM_TEST_TEST_HOST_H_
|
||||
#define WVCDM_CDM_TEST_TEST_HOST_H_
|
||||
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cdm.h"
|
||||
#include "stderr_logger.h"
|
||||
#include "test_sleep.h"
|
||||
|
||||
// This provides a host environment for running CDM tests. It implements the
|
||||
// IStorage, IClock and ITimer interfaces that a host would normally implement,
|
||||
// while allowing them to be manipulated by the test.
|
||||
class TestHost : public widevine::Cdm::IClock,
|
||||
public widevine::Cdm::ITimer,
|
||||
public wvutil::TestSleep::CallBack {
|
||||
public:
|
||||
class Storage : public widevine::Cdm::IStorage {
|
||||
public:
|
||||
typedef std::map<std::string, std::string> StorageMap;
|
||||
|
||||
explicit Storage(bool is_global);
|
||||
~Storage() override {}
|
||||
void Reset();
|
||||
|
||||
// Reset the file system to contain the specified files.
|
||||
void ResetFiles(const StorageMap& files) { files_ = files; };
|
||||
const StorageMap& files() const { return files_; }
|
||||
|
||||
// widevine::Cdm::IStorage
|
||||
bool read(const std::string& name, std::string* data) override;
|
||||
bool write(const std::string& name, const std::string& data) override;
|
||||
bool exists(const std::string& name) override;
|
||||
bool remove(const std::string& name) override;
|
||||
int32_t size(const std::string& name) override;
|
||||
bool list(std::vector<std::string>* names) override;
|
||||
|
||||
private:
|
||||
bool is_global_;
|
||||
StorageMap files_;
|
||||
|
||||
bool CheckFilename(const std::string& name);
|
||||
};
|
||||
|
||||
TestHost();
|
||||
~TestHost() override;
|
||||
void Reset();
|
||||
|
||||
// Used for manipulating and inspecting timer states during testing.
|
||||
void ElapseTime(int64_t milliseconds) override;
|
||||
size_t NumTimers() const;
|
||||
|
||||
Storage& global_storage() { return global_storage_; }
|
||||
Storage& per_origin_storage() { return per_origin_storage_; }
|
||||
|
||||
// widevine::Cdm::IClock
|
||||
int64_t now() override;
|
||||
|
||||
// widevine::Cdm::ITimer
|
||||
void setTimeout(int64_t delay_ms, IClient* client, void* context) override;
|
||||
void cancel(IClient* client) override;
|
||||
|
||||
private:
|
||||
struct Timer {
|
||||
Timer(int64_t expiry_time, IClient* client, void* context)
|
||||
: expiry_time_(expiry_time), client_(client), context_(context) {}
|
||||
|
||||
bool operator<(const Timer& other) const {
|
||||
// We want to reverse the order so that the smallest expiry times go to
|
||||
// the top of the priority queue.
|
||||
return expiry_time_ > other.expiry_time_;
|
||||
}
|
||||
|
||||
int64_t expiry_time() { return expiry_time_; }
|
||||
IClient* client() { return client_; }
|
||||
void* context() { return context_; }
|
||||
|
||||
private:
|
||||
int64_t expiry_time_;
|
||||
IClient* client_;
|
||||
void* context_;
|
||||
};
|
||||
|
||||
int64_t now_;
|
||||
std::priority_queue<Timer> timers_;
|
||||
|
||||
Storage global_storage_;
|
||||
Storage per_origin_storage_;
|
||||
};
|
||||
|
||||
// Owned and managed by the test runner.
|
||||
extern TestHost* g_host;
|
||||
extern widevine::StderrLogger g_stderr_logger;
|
||||
extern std::string g_sandbox_id;
|
||||
|
||||
#endif // WVCDM_CDM_TEST_TEST_HOST_H_
|
||||
14
libwvdrmengine/cdm/util.gypi
Normal file
14
libwvdrmengine/cdm/util.gypi
Normal file
@@ -0,0 +1,14 @@
|
||||
# Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
|
||||
# source code may only be used and distributed under the Widevine License
|
||||
# Agreement.
|
||||
{
|
||||
'variables': {
|
||||
'wvutil_sources': [
|
||||
'../util/src/cdm_random.cpp',
|
||||
'../util/src/platform.cpp',
|
||||
'../util/src/rw_lock.cpp',
|
||||
'../util/src/string_conversions.cpp',
|
||||
'../util/src/string_format.cpp',
|
||||
],
|
||||
},
|
||||
}
|
||||
19
libwvdrmengine/cdm/util_unittests.gypi
Normal file
19
libwvdrmengine/cdm/util_unittests.gypi
Normal file
@@ -0,0 +1,19 @@
|
||||
# Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
|
||||
# source code may only be used and distributed under the Widevine License
|
||||
# Agreement.
|
||||
{
|
||||
'sources': [
|
||||
'../util/test/base64_test.cpp',
|
||||
'../util/test/cdm_random_unittest.cpp',
|
||||
# TODO(b/167126046): Needs test vectors
|
||||
# '../util/test/file_store_unittest.cpp',
|
||||
'../util/test/string_format_unittest.cpp',
|
||||
],
|
||||
'include_dirs': [
|
||||
'../util/include'
|
||||
],
|
||||
'defines': [
|
||||
'UNIT_TEST',
|
||||
'UTIL_TESTS'
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user