summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorddorwin <ddorwin@chromium.org>2015-02-19 23:27:58 -0800
committerCommit bot <commit-bot@chromium.org>2015-02-20 07:28:22 +0000
commit3d1d8a66842259f071b98c4a87c0cc460a21f5b5 (patch)
tree1893dd166677282c88c3c281e0dc381747ca6cab
parent7b8da89177433e1f551afd684b0fe6c24fdf71e8 (diff)
downloadchromium_src-3d1d8a66842259f071b98c4a87c0cc460a21f5b5.zip
chromium_src-3d1d8a66842259f071b98c4a87c0cc460a21f5b5.tar.gz
chromium_src-3d1d8a66842259f071b98c4a87c0cc460a21f5b5.tar.bz2
Unprefixed EME: Check that key system is explicitly supported or begins with 'x-'.
A key system registered by an embedder but not explicitly supported in Chromium may not be exposed in an interoperable way. This check prevents misuse of such key system names by default to avoid compatibility issues. BUG=393397 Review URL: https://codereview.chromium.org/944653003 Cr-Commit-Position: refs/heads/master@{#317263}
-rw-r--r--media/base/key_systems.cc66
-rw-r--r--media/base/key_systems_unittest.cc166
-rw-r--r--media/cdm/key_system_names.cc4
-rw-r--r--media/cdm/key_system_names.h4
4 files changed, 191 insertions, 49 deletions
diff --git a/media/base/key_systems.cc b/media/base/key_systems.cc
index f85ba80..f8500f8 100644
--- a/media/base/key_systems.cc
+++ b/media/base/key_systems.cc
@@ -16,6 +16,8 @@
#include "media/base/key_system_info.h"
#include "media/base/key_systems_support_uma.h"
#include "media/base/media_client.h"
+#include "media/cdm/key_system_names.h"
+#include "third_party/widevine/cdm/widevine_cdm_common.h"
namespace media {
@@ -109,6 +111,56 @@ static void AddClearKey(std::vector<KeySystemInfo>* concrete_key_systems) {
concrete_key_systems->push_back(info);
}
+// Returns whether the |key_system| is known to Chromium and is thus likely to
+// be implemented in an interoperable way.
+// True is always returned for a |key_system| that begins with "x-".
+//
+// As with other web platform features, advertising support for a key system
+// implies that it adheres to a defined and interoperable specification.
+//
+// To ensure interoperability, implementations of a specific |key_system| string
+// must conform to a specification for that identifier that defines
+// key system-specific behaviors not fully defined by the EME specification.
+// That specification should be provided by the owner of the domain that is the
+// reverse of the |key_system| string.
+// This involves more than calling a library, SDK, or platform API. KeySystems
+// must be populated appropriately, and there will likely be glue code to adapt
+// to the API of the library, SDK, or platform API.
+//
+// Chromium mainline contains this data and glue code for specific key systems,
+// which should help ensure interoperability with other implementations using
+// these key systems.
+//
+// If you need to add support for other key systems, ensure that you have
+// obtained the specification for how to integrate it with EME, implemented the
+// appropriate glue/adapter code, and added all the appropriate data to
+// KeySystems. Only then should you change this function.
+static bool IsPotentiallySupportedKeySystem(const std::string& key_system) {
+ // Known and supported key systems.
+ if (key_system == kWidevineKeySystem)
+ return true;
+ if (key_system == kClearKey)
+ return true;
+
+ // External Clear Key is known and supports suffixes for testing.
+ if (IsExternalClearKey(key_system))
+ return true;
+
+ // Chromecast defines behaviors for Cast clients within its reverse domain.
+ const char kChromecastRoot[] = "com.chromecast";
+ if (IsParentKeySystemOf(kChromecastRoot, key_system))
+ return true;
+
+ // Implementations that do not have a specification or appropriate glue code
+ // can use the "x-" prefix to avoid conflicting with and advertising support
+ // for real key system names. Use is discouraged.
+ const char kExcludedPrefix[] = "x-";
+ if (key_system.find(kExcludedPrefix, 0, arraysize(kExcludedPrefix) - 1) == 0)
+ return true;
+
+ return false;
+}
+
class KeySystems {
public:
static KeySystems& GetInstance();
@@ -726,7 +778,19 @@ bool PrefixedIsSupportedConcreteKeySystem(const std::string& key_system) {
}
bool IsSupportedKeySystem(const std::string& key_system) {
- return KeySystems::GetInstance().IsSupportedKeySystem(key_system);
+ if (!KeySystems::GetInstance().IsSupportedKeySystem(key_system))
+ return false;
+
+ // TODO(ddorwin): Move this to where we add key systems when prefixed EME is
+ // removed (crbug.com/249976).
+ if (!IsPotentiallySupportedKeySystem(key_system)) {
+ // If you encounter this path, see the comments for the above function.
+ NOTREACHED() << "Unrecognized key system " << key_system
+ << ". See code comments.";
+ return false;
+ }
+
+ return true;
}
bool IsSupportedKeySystemWithInitDataType(
diff --git a/media/base/key_systems_unittest.cc b/media/base/key_systems_unittest.cc
index 03a16cf..7f8d27c 100644
--- a/media/base/key_systems_unittest.cc
+++ b/media/base/key_systems_unittest.cc
@@ -35,11 +35,11 @@ namespace media {
// These are the (fake) key systems that are registered for these tests.
// kUsesAes uses the AesDecryptor like Clear Key.
// kExternal uses an external CDM, such as Pepper-based or Android platform CDM.
-const char kUsesAes[] = "org.example.clear";
-const char kUsesAesParent[] = "org.example"; // Not registered.
+const char kUsesAes[] = "x-org.example.clear";
+const char kUsesAesParent[] = "x-org.example"; // Not registered.
const char kUseAesNameForUMA[] = "UseAes";
-const char kExternal[] = "com.example.test";
-const char kExternalParent[] = "com.example";
+const char kExternal[] = "x-com.example.test";
+const char kExternalParent[] = "x-com.example";
const char kExternalNameForUMA[] = "External";
const char kClearKey[] = "org.w3.clearkey";
@@ -91,14 +91,14 @@ static void AddContainerAndCodecMasksForTest() {
class TestMediaClient : public MediaClient {
public:
TestMediaClient();
- ~TestMediaClient() final;
+ ~TestMediaClient() override;
// MediaClient implementation.
void AddKeySystemsInfoForUMA(
std::vector<KeySystemInfoForUMA>* key_systems_info_for_uma) final;
bool IsKeySystemsUpdateNeeded() final;
void AddSupportedKeySystems(
- std::vector<KeySystemInfo>* key_systems_info) final;
+ std::vector<KeySystemInfo>* key_systems_info) override;
// Helper function to test the case where IsKeySystemsUpdateNeeded() is true
// after AddSupportedKeySystems() is called.
@@ -109,8 +109,8 @@ class TestMediaClient : public MediaClient {
void DisableExternalKeySystemSupport();
protected:
- void AddUsesAesKeySystem(
- std::vector<KeySystemInfo>* key_systems_info);
+ void AddUsesAesKeySystem(const std::string& name,
+ std::vector<KeySystemInfo>* key_systems_info);
void AddExternalKeySystem(
std::vector<KeySystemInfo>* key_systems_info);
@@ -142,7 +142,7 @@ void TestMediaClient::AddSupportedKeySystems(
std::vector<KeySystemInfo>* key_systems) {
DCHECK(is_update_needed_);
- AddUsesAesKeySystem(key_systems);
+ AddUsesAesKeySystem(kUsesAes, key_systems);
if (supports_external_key_system_)
AddExternalKeySystem(key_systems);
@@ -159,18 +159,19 @@ void TestMediaClient::DisableExternalKeySystemSupport() {
}
void TestMediaClient::AddUsesAesKeySystem(
+ const std::string& name,
std::vector<KeySystemInfo>* key_systems) {
- KeySystemInfo aes;
- aes.key_system = kUsesAes;
- aes.supported_codecs = EME_CODEC_WEBM_ALL;
- aes.supported_codecs |= TEST_CODEC_FOO_ALL;
- aes.supported_init_data_types = EME_INIT_DATA_TYPE_WEBM;
- aes.persistent_license_support = EME_SESSION_TYPE_NOT_SUPPORTED;
- aes.persistent_release_message_support = EME_SESSION_TYPE_NOT_SUPPORTED;
- aes.persistent_state_support = EME_FEATURE_NOT_SUPPORTED;
- aes.distinctive_identifier_support = EME_FEATURE_NOT_SUPPORTED;
- aes.use_aes_decryptor = true;
- key_systems->push_back(aes);
+ KeySystemInfo system;
+ system.key_system = name;
+ system.supported_codecs = EME_CODEC_WEBM_ALL;
+ system.supported_codecs |= TEST_CODEC_FOO_ALL;
+ system.supported_init_data_types = EME_INIT_DATA_TYPE_WEBM;
+ system.persistent_license_support = EME_SESSION_TYPE_NOT_SUPPORTED;
+ system.persistent_release_message_support = EME_SESSION_TYPE_NOT_SUPPORTED;
+ system.persistent_state_support = EME_FEATURE_NOT_SUPPORTED;
+ system.distinctive_identifier_support = EME_FEATURE_NOT_SUPPORTED;
+ system.use_aes_decryptor = true;
+ key_systems->push_back(system);
}
void TestMediaClient::AddExternalKeySystem(
@@ -191,6 +192,36 @@ void TestMediaClient::AddExternalKeySystem(
key_systems->push_back(ext);
}
+class PotentiallySupportedNamesTestMediaClient : public TestMediaClient {
+ void AddSupportedKeySystems(
+ std::vector<KeySystemInfo>* key_systems_info) final;
+};
+
+void PotentiallySupportedNamesTestMediaClient::AddSupportedKeySystems(
+ std::vector<KeySystemInfo>* key_systems) {
+ // org.w3.clearkey is automatically registered.
+ AddUsesAesKeySystem("com.widevine.alpha", key_systems);
+ AddUsesAesKeySystem("org.chromium.externalclearkey", key_systems);
+ AddUsesAesKeySystem("org.chromium.externalclearkey.something", key_systems);
+ AddUsesAesKeySystem("com.chromecast.something", key_systems);
+ AddUsesAesKeySystem("x-something", key_systems);
+}
+
+class KeySystemsPotentiallySupportedNamesTest : public testing::Test {
+ protected:
+ KeySystemsPotentiallySupportedNamesTest() {
+ SetMediaClient(&test_media_client_);
+ }
+
+ ~KeySystemsPotentiallySupportedNamesTest() override {
+ // Clear the use of |test_media_client_|, which was set in SetUp().
+ SetMediaClient(nullptr);
+ }
+
+ private:
+ PotentiallySupportedNamesTestMediaClient test_media_client_;
+};
+
// TODO(sandersd): Refactor. http://crbug.com/417444
class KeySystemsTest : public testing::Test {
protected:
@@ -325,7 +356,7 @@ TEST_F(KeySystemsTest, ClearKey) {
// The key system is not registered and therefore is unrecognized.
TEST_F(KeySystemsTest, Basic_UnrecognizedKeySystem) {
- static const char* const kUnrecognized = "org.example.unrecognized";
+ static const char* const kUnrecognized = "x-org.example.unrecognized";
EXPECT_FALSE(IsSupportedKeySystem(kUnrecognized));
EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
@@ -336,13 +367,14 @@ TEST_F(KeySystemsTest, Basic_UnrecognizedKeySystem) {
bool can_use = false;
EXPECT_DEBUG_DEATH_PORTABLE(
can_use = CanUseAesDecryptor(kUnrecognized),
- "org.example.unrecognized is not a known concrete system");
+ "x-org.example.unrecognized is not a known concrete system");
EXPECT_FALSE(can_use);
#if defined(ENABLE_PEPPER_CDMS)
std::string type;
- EXPECT_DEBUG_DEATH(type = GetPepperType(kUnrecognized),
- "org.example.unrecognized is not a known concrete system");
+ EXPECT_DEBUG_DEATH(
+ type = GetPepperType(kUnrecognized),
+ "x-org.example.unrecognized is not a known concrete system");
EXPECT_TRUE(type.empty());
#endif
}
@@ -359,7 +391,7 @@ TEST_F(KeySystemsTest, Basic_UsesAesDecryptor) {
#if defined(ENABLE_PEPPER_CDMS)
std::string type;
EXPECT_DEBUG_DEATH(type = GetPepperType(kUsesAes),
- "org.example.clear is not Pepper-based");
+ "x-org.example.clear is not Pepper-based");
EXPECT_TRUE(type.empty());
#endif
}
@@ -421,21 +453,21 @@ TEST_F(KeySystemsTest, Parent_NoParentRegistered) {
EXPECT_EQ("Unknown", GetKeySystemNameForUMA(kUsesAesParent));
bool result = false;
EXPECT_DEBUG_DEATH_PORTABLE(result = CanUseAesDecryptor(kUsesAesParent),
- "org.example is not a known concrete system");
+ "x-org.example is not a known concrete system");
EXPECT_FALSE(result);
#if defined(ENABLE_PEPPER_CDMS)
std::string type;
EXPECT_DEBUG_DEATH(type = GetPepperType(kUsesAesParent),
- "org.example is not a known concrete system");
+ "x-org.example is not a known concrete system");
EXPECT_TRUE(type.empty());
#endif
}
TEST_F(KeySystemsTest, IsSupportedKeySystem_InvalidVariants) {
// Case sensitive.
- EXPECT_FALSE(IsSupportedKeySystem("org.example.ClEaR"));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), "org.example.ClEaR"));
+ EXPECT_FALSE(IsSupportedKeySystem("x-org.example.ClEaR"));
+ EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(kVideoWebM, no_codecs(),
+ "x-org.example.ClEaR"));
// TLDs are not allowed.
EXPECT_FALSE(IsSupportedKeySystem("org."));
@@ -446,24 +478,27 @@ TEST_F(KeySystemsTest, IsSupportedKeySystem_InvalidVariants) {
kVideoWebM, no_codecs(), "com"));
// Extra period.
- EXPECT_FALSE(IsSupportedKeySystem("org.example."));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), "org.example."));
+ EXPECT_FALSE(IsSupportedKeySystem("x-org.example.clear."));
+ EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(kVideoWebM, no_codecs(),
+ "x-org.example.clear."));
+ EXPECT_FALSE(IsSupportedKeySystem("x-org.example."));
+ EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(kVideoWebM, no_codecs(),
+ "x-org.example."));
// Incomplete.
- EXPECT_FALSE(IsSupportedKeySystem("org.example.clea"));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), "org.example.clea"));
+ EXPECT_FALSE(IsSupportedKeySystem("x-org.example.clea"));
+ EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(kVideoWebM, no_codecs(),
+ "x-org.example.clea"));
// Extra character.
- EXPECT_FALSE(IsSupportedKeySystem("org.example.clearz"));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), "org.example.clearz"));
+ EXPECT_FALSE(IsSupportedKeySystem("x-org.example.clearz"));
+ EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(kVideoWebM, no_codecs(),
+ "x-org.example.clearz"));
// There are no child key systems for UsesAes.
- EXPECT_FALSE(IsSupportedKeySystem("org.example.clear.foo"));
+ EXPECT_FALSE(IsSupportedKeySystem("x-org.example.clear.foo"));
EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- kVideoWebM, no_codecs(), "org.example.clear.foo"));
+ kVideoWebM, no_codecs(), "x-org.example.clear.foo"));
}
TEST_F(KeySystemsTest, IsSupportedKeySystemWithMediaMimeType_NoType) {
@@ -472,10 +507,10 @@ TEST_F(KeySystemsTest, IsSupportedKeySystemWithMediaMimeType_NoType) {
EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
std::string(), no_codecs(), kUsesAesParent));
+ EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(std::string(), no_codecs(),
+ "x-org.example.foo"));
EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- std::string(), no_codecs(), "org.example.foo"));
- EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
- std::string(), no_codecs(), "org.example.clear.foo"));
+ std::string(), no_codecs(), "x-org.example.clear.foo"));
}
// Tests the second registered container type.
@@ -556,12 +591,12 @@ TEST_F(KeySystemsTest, Parent_ParentRegistered) {
EXPECT_EQ("Unknown", GetKeySystemNameForUMA(kExternalParent));
bool result = false;
EXPECT_DEBUG_DEATH_PORTABLE(result = CanUseAesDecryptor(kExternalParent),
- "com.example is not a known concrete system");
+ "x-com.example is not a known concrete system");
EXPECT_FALSE(result);
#if defined(ENABLE_PEPPER_CDMS)
std::string type;
EXPECT_DEBUG_DEATH(type = GetPepperType(kExternalParent),
- "com.example is not a known concrete system");
+ "x-com.example is not a known concrete system");
EXPECT_TRUE(type.empty());
#endif
}
@@ -788,4 +823,43 @@ TEST_F(KeySystemsTest, PrefixedKeySystemsUpdate) {
kVideoWebM, no_codecs(), kExternal));
}
+TEST_F(KeySystemsPotentiallySupportedNamesTest, PotentiallySupportedNames) {
+ EXPECT_FALSE(IsSupportedKeySystem("org.w3"));
+ EXPECT_FALSE(IsSupportedKeySystem("org.w3."));
+ EXPECT_FALSE(IsSupportedKeySystem("org.w3.clearke"));
+ EXPECT_TRUE(IsSupportedKeySystem("org.w3.clearkey"));
+ EXPECT_FALSE(IsSupportedKeySystem("org.w3.clearkeys"));
+
+ EXPECT_FALSE(IsSupportedKeySystem("com.widevine"));
+ EXPECT_FALSE(IsSupportedKeySystem("com.widevine."));
+ EXPECT_FALSE(IsSupportedKeySystem("com.widevine.alph"));
+ EXPECT_TRUE(IsSupportedKeySystem("com.widevine.alpha"));
+ EXPECT_FALSE(IsSupportedKeySystem("com.widevine.beta"));
+ EXPECT_FALSE(IsSupportedKeySystem("com.widevine.alphabeta"));
+ EXPECT_FALSE(IsSupportedKeySystem("com.widevine.alpha.beta"));
+
+ EXPECT_FALSE(IsSupportedKeySystem("org.chromium"));
+ EXPECT_FALSE(IsSupportedKeySystem("org.chromium."));
+ EXPECT_FALSE(IsSupportedKeySystem("org.chromium.externalclearke"));
+ EXPECT_TRUE(IsSupportedKeySystem("org.chromium.externalclearkey"));
+ EXPECT_FALSE(IsSupportedKeySystem("org.chromium.externalclearkeys"));
+ EXPECT_FALSE(IsSupportedKeySystem("org.chromium.externalclearkey."));
+ EXPECT_TRUE(IsSupportedKeySystem("org.chromium.externalclearkey.something"));
+ EXPECT_FALSE(
+ IsSupportedKeySystem("org.chromium.externalclearkey.something.else"));
+ EXPECT_FALSE(IsSupportedKeySystem("org.chromium.externalclearkey.other"));
+ EXPECT_FALSE(IsSupportedKeySystem("org.chromium.other"));
+
+ EXPECT_FALSE(IsSupportedKeySystem("com.chromecast"));
+ EXPECT_FALSE(IsSupportedKeySystem("com.chromecast."));
+ EXPECT_TRUE(IsSupportedKeySystem("com.chromecast.something"));
+ EXPECT_FALSE(IsSupportedKeySystem("com.chromecast.something.else"));
+ EXPECT_FALSE(IsSupportedKeySystem("com.chromecast.other"));
+
+ EXPECT_FALSE(IsSupportedKeySystem("x-"));
+ EXPECT_TRUE(IsSupportedKeySystem("x-something"));
+ EXPECT_FALSE(IsSupportedKeySystem("x-something.else"));
+ EXPECT_FALSE(IsSupportedKeySystem("x-other"));
+}
+
} // namespace media
diff --git a/media/cdm/key_system_names.cc b/media/cdm/key_system_names.cc
index 32b7475..f0abaf0 100644
--- a/media/cdm/key_system_names.cc
+++ b/media/cdm/key_system_names.cc
@@ -11,8 +11,8 @@ namespace media {
const char kClearKey[] = "org.w3.clearkey";
const char kExternalClearKey[] = "org.chromium.externalclearkey";
-static bool IsParentKeySystemOf(const std::string& parent_key_system,
- const std::string& key_system) {
+bool IsParentKeySystemOf(const std::string& parent_key_system,
+ const std::string& key_system) {
std::string prefix = parent_key_system + '.';
return key_system.substr(0, prefix.size()) == prefix;
}
diff --git a/media/cdm/key_system_names.h b/media/cdm/key_system_names.h
index c181849..94c84da 100644
--- a/media/cdm/key_system_names.h
+++ b/media/cdm/key_system_names.h
@@ -24,6 +24,10 @@ MEDIA_EXPORT inline bool IsClearKey(const std::string& key_system) {
return key_system == kClearKey;
}
+// Returns true if |key_system| is (reverse) sub-domain of |parent_key_system|.
+MEDIA_EXPORT bool IsParentKeySystemOf(const std::string& parent_key_system,
+ const std::string& key_system);
+
// Returns true if |key_system| is External Clear Key, false otherwise.
MEDIA_EXPORT bool IsExternalClearKey(const std::string& key_system);