From fce5af14a8df4138a967951b7c2e4da18dd762bd Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Tue, 4 Oct 2022 15:54:13 -0400 Subject: [PATCH] widevine: Support CDM host verification and storage ID (fixes issue #3404) This functionality will be enabled if .sig files exist in the required locations. See the issue for details. --- BUILD.gn | 16 +++ libcef/common/alloy/alloy_content_client.cc | 4 +- libcef/common/cdm_host_file_path.cc | 119 ++++++++++++++++++ libcef/common/cdm_host_file_path.h | 20 +++ .../chrome/chrome_content_client_cef.cc | 18 +++ .../common/chrome/chrome_content_client_cef.h | 3 + libcef/common/util_mac.h | 7 +- libcef/common/util_mac.mm | 9 +- tools/gn_args.py | 13 ++ 9 files changed, 201 insertions(+), 8 deletions(-) create mode 100644 libcef/common/cdm_host_file_path.cc create mode 100644 libcef/common/cdm_host_file_path.h diff --git a/BUILD.gn b/BUILD.gn index c871b3938..ae03d34d6 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -106,6 +106,7 @@ import("//media/media_options.gni") import("//mojo/public/tools/bindings/mojom.gni") import("//ppapi/buildflags/buildflags.gni") import("//printing/buildflags/buildflags.gni") +import("//rlz/buildflags/buildflags.gni") import("//testing/test.gni") import("//third_party/icu/config.gni") import("//third_party/widevine/cdm/widevine.gni") @@ -257,6 +258,14 @@ assert(enable_print_preview) # Enable support for Widevine CDM. assert(enable_widevine) +if (is_mac || is_win) { + # Enable Widevine CDM host verification and storage ID. + assert(enable_cdm_host_verification) + assert(enable_cdm_storage_id) + assert(alternate_cdm_storage_id_key != "") + assert(enable_rlz) +} + # Enable Views UI framework. assert(toolkit_views) @@ -1165,6 +1174,13 @@ source_set("libcef_static") { "//ui/wm/public", ] } + + if (enable_cdm_host_verification) { + sources += [ + "libcef/common/cdm_host_file_path.cc", + "libcef/common/cdm_host_file_path.h", + ] + } } diff --git a/libcef/common/alloy/alloy_content_client.cc b/libcef/common/alloy/alloy_content_client.cc index badba86c8..5d653ab40 100644 --- a/libcef/common/alloy/alloy_content_client.cc +++ b/libcef/common/alloy/alloy_content_client.cc @@ -39,7 +39,7 @@ #include "ui/base/resource/resource_bundle.h" #if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) -#include "chrome/common/media/cdm_host_file_path.h" +#include "libcef/common/cdm_host_file_path.h" #endif namespace { @@ -92,7 +92,7 @@ void AlloyContentClient::AddContentDecryptionModules( #if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) if (cdm_host_file_paths) - AddCdmHostFilePaths(cdm_host_file_paths); + cef::AddCdmHostFilePaths(cdm_host_file_paths); #endif } diff --git a/libcef/common/cdm_host_file_path.cc b/libcef/common/cdm_host_file_path.cc new file mode 100644 index 000000000..d76009fab --- /dev/null +++ b/libcef/common/cdm_host_file_path.cc @@ -0,0 +1,119 @@ +// Copyright 2022 The Chromium Embedded Framework Authors. Portions Copyright +// 2017 The Chromium Authors. Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "libcef/common/cdm_host_file_path.h" + +#include "base/check.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/logging.h" +#include "base/notreached.h" +#include "base/path_service.h" +#include "build/build_config.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/chrome_version.h" + +#if BUILDFLAG(IS_MAC) +#include "libcef/common/util_mac.h" +#endif + +namespace cef { + +namespace { + +// TODO(xhwang): Move this to a common place if needed. +const base::FilePath::CharType kSignatureFileExtension[] = + FILE_PATH_LITERAL(".sig"); + +// Returns the signature file path given the |file_path|. This function should +// only be used when the signature file and the file are located in the same +// directory. +base::FilePath GetSigFilePath(const base::FilePath& file_path) { + return file_path.AddExtension(kSignatureFileExtension); +} + +bool FileExists(const base::FilePath& path) { + return base::PathExists(path) && !base::DirectoryExists(path); +} + +} // namespace + +void AddCdmHostFilePaths( + std::vector* cdm_host_file_paths) { + DVLOG(1) << __func__; + DCHECK(cdm_host_file_paths); + DCHECK(cdm_host_file_paths->empty()); + +#if BUILDFLAG(IS_WIN) + + // Find the full path to the current executable. + base::FilePath cef_exe; + CHECK(base::PathService::Get(base::FILE_EXE, &cef_exe)); + const auto cef_exe_sig = GetSigFilePath(cef_exe); + DVLOG(2) << __func__ << ": exe_path=" << cef_exe.value() + << ", signature_path=" << cef_exe_sig.value(); + + if (FileExists(cef_exe_sig)) { + cdm_host_file_paths->emplace_back(cef_exe, cef_exe_sig); + } + + // Find the full path to the module. This may be the same as the executable if + // libcef is statically linked. + base::FilePath cef_module; + CHECK(base::PathService::Get(base::FILE_MODULE, &cef_module)); + if (cef_module != cef_exe) { + const auto cef_module_sig = GetSigFilePath(cef_module); + DVLOG(2) << __func__ << ": module_path=" << cef_module.value() + << ", signature_path=" << cef_module_sig.value(); + + if (FileExists(cef_module_sig)) { + cdm_host_file_paths->emplace_back(cef_module, cef_module_sig); + } + } + +#elif BUILDFLAG(IS_MAC) + + // Find the full path to the current executable. + base::FilePath cef_exe; + CHECK(base::PathService::Get(base::FILE_EXE, &cef_exe)); + + // Find the sig file for the executable in the main Resources directory. This + // directory may be empty if we're not bundled. + const auto main_resources_path = util_mac::GetMainResourcesDirectory(); + if (!main_resources_path.empty()) { + const auto exe_name = cef_exe.BaseName(); + const auto exe_sig_path = + GetSigFilePath(main_resources_path.Append(exe_name)); + + DVLOG(2) << __func__ << ": exe_path=" << cef_exe.value() + << ", signature_path=" << exe_sig_path.value(); + + if (FileExists(exe_sig_path)) { + cdm_host_file_paths->emplace_back(cef_exe, exe_sig_path); + } + } + + // Find the sig file for the framework in the framework Resources directory. + // This directory may be empty if we're not bundled. + const auto framework_resources_path = + util_mac::GetFrameworkResourcesDirectory(); + if (!framework_resources_path.empty()) { + const auto framework_name = util_mac::GetFrameworkName(); + const auto framework_path = + util_mac::GetFrameworkDirectory().Append(framework_name); + const auto framework_sig_path = + GetSigFilePath(framework_resources_path.Append(framework_name)); + + DVLOG(2) << __func__ << ": framework_path=" << framework_path.value() + << ", signature_path=" << framework_sig_path.value(); + + if (FileExists(framework_sig_path)) { + cdm_host_file_paths->emplace_back(framework_path, framework_sig_path); + } + } + +#endif // !BUILDFLAG(IS_MAC) +} + +} // namespace cef diff --git a/libcef/common/cdm_host_file_path.h b/libcef/common/cdm_host_file_path.h new file mode 100644 index 000000000..4a41e6964 --- /dev/null +++ b/libcef/common/cdm_host_file_path.h @@ -0,0 +1,20 @@ +// Copyright 2022 The Chromium Embedded Framework Authors. Portions Copyright +// 2017 The Chromium Authors. Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef CEF_LIBCEF_COMMON_CDM_HOST_FILE_PATH_H_ +#define CEF_LIBCEF_COMMON_CDM_HOST_FILE_PATH_H_ + +#include + +#include "media/cdm/cdm_host_file.h" + +namespace cef { + +// Gets a list of CDM host file paths and put them in |cdm_host_file_paths|. +void AddCdmHostFilePaths( + std::vector* cdm_host_file_paths); + +} // namespace cef + +#endif // CEF_LIBCEF_COMMON_CDM_HOST_FILE_PATH_H_ diff --git a/libcef/common/chrome/chrome_content_client_cef.cc b/libcef/common/chrome/chrome_content_client_cef.cc index acdf115de..55c68e19a 100644 --- a/libcef/common/chrome/chrome_content_client_cef.cc +++ b/libcef/common/chrome/chrome_content_client_cef.cc @@ -7,9 +7,27 @@ #include "libcef/common/app_manager.h" +#include "chrome/common/media/cdm_registration.h" + +#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) +#include "libcef/common/cdm_host_file_path.h" +#endif + ChromeContentClientCef::ChromeContentClientCef() = default; ChromeContentClientCef::~ChromeContentClientCef() = default; +void ChromeContentClientCef::AddContentDecryptionModules( + std::vector* cdms, + std::vector* cdm_host_file_paths) { + if (cdms) + RegisterCdmInfo(cdms); + +#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) + if (cdm_host_file_paths) + cef::AddCdmHostFilePaths(cdm_host_file_paths); +#endif +} + void ChromeContentClientCef::AddAdditionalSchemes(Schemes* schemes) { ChromeContentClient::AddAdditionalSchemes(schemes); CefAppManager::Get()->AddAdditionalSchemes(schemes); diff --git a/libcef/common/chrome/chrome_content_client_cef.h b/libcef/common/chrome/chrome_content_client_cef.h index 4076aca58..e5ec8778b 100644 --- a/libcef/common/chrome/chrome_content_client_cef.h +++ b/libcef/common/chrome/chrome_content_client_cef.h @@ -14,6 +14,9 @@ class ChromeContentClientCef : public ChromeContentClient { ~ChromeContentClientCef() override; // content::ContentClient overrides. + void AddContentDecryptionModules( + std::vector* cdms, + std::vector* cdm_host_file_paths) override; void AddAdditionalSchemes(Schemes* schemes) override; }; diff --git a/libcef/common/util_mac.h b/libcef/common/util_mac.h index ff5766024..5c8c3d113 100644 --- a/libcef/common/util_mac.h +++ b/libcef/common/util_mac.h @@ -8,15 +8,16 @@ #include -namespace base { -class FilePath; -} +#include "base/files/file_path.h" namespace util_mac { // Returns the path to the NSLibraryDirectory (e.g. "~/Library"). bool GetLocalLibraryDirectory(base::FilePath* result); +// Returns the framework name (e.g. "Chromium Embedded Framework"). +base::FilePath::StringType GetFrameworkName(); + // Returns the path to the CEF framework directory inside the top-level app // bundle (e.g. "myapp.app/Contents/Frameworks/Chromium Embedded // Framework.framework"). May return an empty value if not running in an app diff --git a/libcef/common/util_mac.mm b/libcef/common/util_mac.mm index b1852730a..8f9ed0a08 100644 --- a/libcef/common/util_mac.mm +++ b/libcef/common/util_mac.mm @@ -8,7 +8,6 @@ #include "base/base_paths.h" #include "base/command_line.h" -#include "base/files/file_path.h" #include "base/logging.h" #include "base/mac/bundle_locations.h" #include "base/mac/foundation_util.h" @@ -72,6 +71,10 @@ bool GetLocalLibraryDirectory(base::FilePath* result) { return base::mac::GetLocalDirectory(NSLibraryDirectory, result); } +base::FilePath::StringType GetFrameworkName() { + return FILE_PATH_LITERAL("Chromium Embedded Framework"); +} + base::FilePath GetFrameworkDirectory() { base::FilePath frameworks_path = base::CommandLine::ForCurrentProcess()->GetSwitchValuePath( @@ -83,8 +86,8 @@ base::FilePath GetFrameworkDirectory() { if (frameworks_path.empty()) return base::FilePath(); - return frameworks_path.Append( - FILE_PATH_LITERAL("Chromium Embedded Framework.framework")); + return frameworks_path.Append(GetFrameworkName()) + .AddExtension(FILE_PATH_LITERAL(".framework")); } base::FilePath GetFrameworkResourcesDirectory() { diff --git a/tools/gn_args.py b/tools/gn_args.py index 0175af30c..15afb5fcc 100644 --- a/tools/gn_args.py +++ b/tools/gn_args.py @@ -235,6 +235,11 @@ def GetRecommendedDefaultArgs(): 'v8_enable_sandbox': False, } + if platform == 'windows' or platform == 'mac': + # A browser specific value of at least 32 characters that will be used in + # the computation of the CDM storage ID. + result['alternate_cdm_storage_id_key'] = '968b476909da4373b08903c28e859454' + if platform != 'windows': # Only allow non-component Debug builds on non-Windows platforms. These # builds will fail on Windows due to linker issues (running out of memory, @@ -287,6 +292,14 @@ def GetRequiredArgs(): 'clang_use_chrome_plugins': False, } + if platform == 'windows' or platform == 'mac': + # Enable Widevine CDM host verification and storage ID. + result['enable_cdm_host_verification'] = True + result['enable_cdm_storage_id'] = True + + # Enable use of the RLZ library as required by CDM storage ID. + result['enable_rlz'] = True + if platform == 'linux': # Don't generate Chromium installer packages. This avoids GN dependency # errors with CEF (see issue #2301).