widevine_key_system_properties.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. // Copyright 2016 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/cdm/renderer/widevine_key_system_properties.h"
  5. #include "base/command_line.h"
  6. #include "base/feature_list.h"
  7. #include "build/build_config.h"
  8. #include "build/chromeos_buildflags.h"
  9. #include "media/base/media_switches.h"
  10. #include "media/media_buildflags.h"
  11. #include "third_party/widevine/cdm/buildflags.h"
  12. #include "third_party/widevine/cdm/widevine_cdm_common.h"
  13. #if !BUILDFLAG(ENABLE_WIDEVINE)
  14. #error This file should only be built when Widevine is enabled.
  15. #endif
  16. using media::CdmSessionType;
  17. using media::EmeConfig;
  18. using media::EmeConfigRuleState;
  19. using media::EmeFeatureSupport;
  20. using media::EmeInitDataType;
  21. using media::EmeMediaType;
  22. using media::EncryptionScheme;
  23. using media::SupportedCodecs;
  24. using Robustness = cdm::WidevineKeySystemProperties::Robustness;
  25. namespace cdm {
  26. namespace {
  27. Robustness ConvertRobustness(const std::string& robustness) {
  28. if (robustness.empty())
  29. return Robustness::EMPTY;
  30. if (robustness == "SW_SECURE_CRYPTO")
  31. return Robustness::SW_SECURE_CRYPTO;
  32. if (robustness == "SW_SECURE_DECODE")
  33. return Robustness::SW_SECURE_DECODE;
  34. if (robustness == "HW_SECURE_CRYPTO")
  35. return Robustness::HW_SECURE_CRYPTO;
  36. if (robustness == "HW_SECURE_DECODE")
  37. return Robustness::HW_SECURE_DECODE;
  38. if (robustness == "HW_SECURE_ALL")
  39. return Robustness::HW_SECURE_ALL;
  40. return Robustness::INVALID;
  41. }
  42. #if BUILDFLAG(IS_WIN)
  43. bool IsHardwareSecurityEnabledForKeySystem(const std::string& key_system) {
  44. return (key_system == kWidevineKeySystem &&
  45. base::FeatureList::IsEnabled(media::kHardwareSecureDecryption)) ||
  46. (key_system == kWidevineExperimentKeySystem &&
  47. base::FeatureList::IsEnabled(
  48. media::kHardwareSecureDecryptionExperiment));
  49. }
  50. #endif // BUILDFLAG(IS_WIN)
  51. } // namespace
  52. WidevineKeySystemProperties::WidevineKeySystemProperties(
  53. SupportedCodecs codecs,
  54. base::flat_set<EncryptionScheme> encryption_schemes,
  55. base::flat_set<CdmSessionType> session_types,
  56. SupportedCodecs hw_secure_codecs,
  57. base::flat_set<EncryptionScheme> hw_secure_encryption_schemes,
  58. base::flat_set<CdmSessionType> hw_secure_session_types,
  59. Robustness max_audio_robustness,
  60. Robustness max_video_robustness,
  61. EmeFeatureSupport persistent_state_support,
  62. EmeFeatureSupport distinctive_identifier_support)
  63. : codecs_(codecs),
  64. encryption_schemes_(std::move(encryption_schemes)),
  65. session_types_(std::move(session_types)),
  66. hw_secure_codecs_(hw_secure_codecs),
  67. hw_secure_encryption_schemes_(std::move(hw_secure_encryption_schemes)),
  68. hw_secure_session_types_(std::move(hw_secure_session_types)),
  69. max_audio_robustness_(max_audio_robustness),
  70. max_video_robustness_(max_video_robustness),
  71. persistent_state_support_(persistent_state_support),
  72. distinctive_identifier_support_(distinctive_identifier_support) {}
  73. WidevineKeySystemProperties::~WidevineKeySystemProperties() = default;
  74. std::string WidevineKeySystemProperties::GetBaseKeySystemName() const {
  75. return kWidevineKeySystem;
  76. }
  77. bool WidevineKeySystemProperties::IsSupportedKeySystem(
  78. const std::string& key_system) const {
  79. #if BUILDFLAG(IS_WIN)
  80. if (key_system == kWidevineExperimentKeySystem &&
  81. base::FeatureList::IsEnabled(
  82. media::kHardwareSecureDecryptionExperiment)) {
  83. return true;
  84. }
  85. #endif // BUILDFLAG(IS_WIN)
  86. return key_system == kWidevineKeySystem;
  87. }
  88. bool WidevineKeySystemProperties::ShouldUseBaseKeySystemName() const {
  89. // Internally Widevine CDM only supports kWidevineKeySystem.
  90. return true;
  91. }
  92. bool WidevineKeySystemProperties::IsSupportedInitDataType(
  93. EmeInitDataType init_data_type) const {
  94. // Here we assume that support for a container implies support for the
  95. // associated initialization data type. KeySystems handles validating
  96. // |init_data_type| x |container| pairings.
  97. if (init_data_type == EmeInitDataType::WEBM)
  98. return (codecs_ & media::EME_CODEC_WEBM_ALL) != 0;
  99. if (init_data_type == EmeInitDataType::CENC)
  100. return (codecs_ & media::EME_CODEC_MP4_ALL) != 0;
  101. return false;
  102. }
  103. EmeConfig::Rule WidevineKeySystemProperties::GetEncryptionSchemeConfigRule(
  104. EncryptionScheme encryption_scheme) const {
  105. bool is_supported = encryption_schemes_.contains(encryption_scheme);
  106. bool is_hw_secure_supported =
  107. hw_secure_encryption_schemes_.contains(encryption_scheme);
  108. if (is_supported && is_hw_secure_supported) {
  109. return EmeConfig::SupportedRule();
  110. } else if (is_supported && !is_hw_secure_supported) {
  111. return EmeConfig{.hw_secure_codecs = EmeConfigRuleState::kNotAllowed};
  112. } else if (!is_supported && is_hw_secure_supported) {
  113. return EmeConfig{.hw_secure_codecs = EmeConfigRuleState::kRequired};
  114. } else {
  115. return media::EmeConfig::UnsupportedRule();
  116. }
  117. }
  118. SupportedCodecs WidevineKeySystemProperties::GetSupportedCodecs() const {
  119. return codecs_;
  120. }
  121. SupportedCodecs WidevineKeySystemProperties::GetSupportedHwSecureCodecs()
  122. const {
  123. return hw_secure_codecs_;
  124. }
  125. EmeConfig::Rule WidevineKeySystemProperties::GetRobustnessConfigRule(
  126. const std::string& key_system,
  127. EmeMediaType media_type,
  128. const std::string& requested_robustness,
  129. const bool* hw_secure_requirement) const {
  130. Robustness robustness = ConvertRobustness(requested_robustness);
  131. if (robustness == Robustness::INVALID) {
  132. return EmeConfig::UnsupportedRule();
  133. }
  134. Robustness max_robustness = Robustness::INVALID;
  135. switch (media_type) {
  136. case EmeMediaType::AUDIO:
  137. max_robustness = max_audio_robustness_;
  138. break;
  139. case EmeMediaType::VIDEO:
  140. max_robustness = max_video_robustness_;
  141. break;
  142. }
  143. // We can compare robustness levels whenever they are not HW_SECURE_CRYPTO
  144. // and SW_SECURE_DECODE in some order. If they are exactly those two then the
  145. // robustness requirement is not supported.
  146. if ((max_robustness == Robustness::HW_SECURE_CRYPTO &&
  147. robustness == Robustness::SW_SECURE_DECODE) ||
  148. (max_robustness == Robustness::SW_SECURE_DECODE &&
  149. robustness == Robustness::HW_SECURE_CRYPTO) ||
  150. robustness > max_robustness) {
  151. return media::EmeConfig::UnsupportedRule();
  152. }
  153. [[maybe_unused]] bool hw_secure_codecs_required =
  154. hw_secure_requirement && *hw_secure_requirement;
  155. #if BUILDFLAG(IS_CHROMEOS)
  156. // Hardware security requires HWDRM or remote attestation, both of these
  157. // require an identifier.
  158. if (robustness >= Robustness::HW_SECURE_CRYPTO || hw_secure_codecs_required) {
  159. #if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
  160. #if BUILDFLAG(IS_CHROMEOS_LACROS)
  161. if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
  162. switches::kLacrosUseChromeosProtectedMedia)) {
  163. return EmeConfig{.identifier = EmeConfigRuleState::kRequired};
  164. }
  165. #endif // BUILDFLAG(IS_CHROMEOS_LACROS)
  166. return EmeConfig{.identifier = EmeConfigRuleState::kRequired,
  167. .hw_secure_codecs = EmeConfigRuleState::kRequired};
  168. #else
  169. return EmeConfig{.identifier = EmeConfigRuleState::kRequired};
  170. #endif
  171. }
  172. // For video, recommend remote attestation if HW_SECURE_ALL is available,
  173. // regardless of the value of |robustness|, because it enables hardware
  174. // accelerated decoding.
  175. // TODO(sandersd): Only do this when hardware accelerated decoding is
  176. // available for the requested codecs.
  177. if (media_type == EmeMediaType::VIDEO &&
  178. max_robustness == Robustness::HW_SECURE_ALL) {
  179. return EmeConfig{.identifier = EmeConfigRuleState::kRecommended};
  180. }
  181. #elif BUILDFLAG(IS_ANDROID)
  182. // On Android, require hardware secure codecs for SW_SECURE_DECODE and above.
  183. if (robustness >= Robustness::SW_SECURE_DECODE || hw_secure_codecs_required) {
  184. return EmeConfig{.hw_secure_codecs = EmeConfigRuleState::kRequired};
  185. }
  186. #elif BUILDFLAG(IS_WIN)
  187. if (robustness >= Robustness::HW_SECURE_CRYPTO) {
  188. // On Windows, hardware security uses MediaFoundation-based CDM which
  189. // requires identifier and persistent state.
  190. if (IsHardwareSecurityEnabledForKeySystem(key_system)) {
  191. return EmeConfig{.identifier = EmeConfigRuleState::kRequired,
  192. .persistence = EmeConfigRuleState::kRequired,
  193. .hw_secure_codecs = EmeConfigRuleState::kRequired};
  194. } else {
  195. return media::EmeConfig::UnsupportedRule();
  196. }
  197. } else if (robustness < Robustness::HW_SECURE_CRYPTO) {
  198. // On Windows, when software security is queried, explicitly not allow
  199. // hardware secure codecs to prevent robustness level upgrade, for stability
  200. // and compatibility reasons. See https://crbug.com/1327043.
  201. return EmeConfig{.hw_secure_codecs = EmeConfigRuleState::kNotAllowed};
  202. }
  203. #else
  204. // On other platforms, require hardware secure codecs for HW_SECURE_CRYPTO and
  205. // above.
  206. if (robustness >= Robustness::HW_SECURE_CRYPTO) {
  207. return EmeConfig{.hw_secure_codecs = EmeConfigRuleState::kRequired};
  208. }
  209. #endif // BUILDFLAG(IS_CHROMEOS)
  210. return media::EmeConfig::SupportedRule();
  211. }
  212. EmeConfig::Rule
  213. WidevineKeySystemProperties::GetPersistentLicenseSessionSupport() const {
  214. bool is_supported =
  215. session_types_.contains(CdmSessionType::kPersistentLicense);
  216. #if BUILDFLAG(IS_CHROMEOS)
  217. // The logic around hardware/software security support is complicated on
  218. // ChromeOS. This code is to preserve the original logic, by deciding the
  219. // support only based on `is_supported` and ignore `is_hw_secure_supported`.
  220. // Note: On ChromeOS, platform verification (similar to CDM host verification)
  221. // is required for persistent license support, which requires identifier.
  222. // TODO(crbug.com/1324262): Fix the logic after refactoring EmeConfig.
  223. if (is_supported) {
  224. return EmeConfig{.identifier = EmeConfigRuleState::kRequired,
  225. .persistence = EmeConfigRuleState::kRequired};
  226. } else {
  227. return media::EmeConfig::UnsupportedRule();
  228. }
  229. #else // BUILDFLAG(IS_CHROMEOS)
  230. bool is_hw_secure_supported =
  231. hw_secure_session_types_.contains(CdmSessionType::kPersistentLicense);
  232. // Per GetPersistentLicenseSessionSupport() API, there's no need to specify
  233. // the PERSISTENCE requirement here, which is implicitly assumed and enforced
  234. // by `KeySystemConfigSelector`.
  235. if (is_supported && is_hw_secure_supported) {
  236. return EmeConfig::SupportedRule();
  237. } else if (is_supported && !is_hw_secure_supported) {
  238. return EmeConfig{.hw_secure_codecs = EmeConfigRuleState::kNotAllowed};
  239. } else if (!is_supported && is_hw_secure_supported) {
  240. return EmeConfig{.hw_secure_codecs = EmeConfigRuleState::kRequired};
  241. } else {
  242. return media::EmeConfig::UnsupportedRule();
  243. }
  244. #endif // BUILDFLAG(IS_CHROMEOS)
  245. }
  246. EmeFeatureSupport WidevineKeySystemProperties::GetPersistentStateSupport()
  247. const {
  248. return persistent_state_support_;
  249. }
  250. EmeFeatureSupport WidevineKeySystemProperties::GetDistinctiveIdentifierSupport()
  251. const {
  252. return distinctive_identifier_support_;
  253. }
  254. } // namespace cdm