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