Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(281)

Unified Diff: media/blink/webcontentdecryptionmodulesession_impl.cc

Issue 1132223002: Sanitize data before providing it to the CDM (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: windows change Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | media/cdm/json_web_key.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/blink/webcontentdecryptionmodulesession_impl.cc
diff --git a/media/blink/webcontentdecryptionmodulesession_impl.cc b/media/blink/webcontentdecryptionmodulesession_impl.cc
index 5ecba27e9cbabe567e24af5855fcdc9a63b61c47..c80a1d52d550443b7b014b729586dc89a0a8d38c 100644
--- a/media/blink/webcontentdecryptionmodulesession_impl.cc
+++ b/media/blink/webcontentdecryptionmodulesession_impl.cc
@@ -22,6 +22,7 @@
#include "media/blink/webmediaplayer_util.h"
#include "media/cdm/cenc_utils.h"
#include "media/cdm/json_web_key.h"
+#include "media/cdm/key_system_names.h"
#include "third_party/WebKit/public/platform/WebData.h"
#include "third_party/WebKit/public/platform/WebEncryptedMediaKeyInformation.h"
#include "third_party/WebKit/public/platform/WebString.h"
@@ -148,6 +149,67 @@ static bool SanitizeInitData(EmeInitDataType init_data_type,
return false;
}
+static bool SanitizeSessionId(const blink::WebString& session_id,
+ std::string* sanitized_session_id) {
+ // The user agent should thoroughly validate the sessionId value before
+ // passing it to the CDM. At a minimum, this should include checking that
+ // the length and value (e.g. alphanumeric) are reasonable.
+ if (!base::IsStringASCII(session_id))
+ return false;
+
+ sanitized_session_id->assign(base::UTF16ToASCII(session_id));
+ if (sanitized_session_id->length() > limits::kMaxSessionIdLength)
+ return false;
+
+ for (const char c : *sanitized_session_id) {
+ if (!IsAsciiAlpha(c) && !IsAsciiDigit(c))
+ return false;
+ }
+
+ return true;
+}
+
+static bool SanitizeResponse(const std::string& key_system,
+ const uint8* response,
+ size_t response_length,
+ std::vector<uint8>* sanitized_response) {
+ // The user agent should thoroughly validate the response before passing it
+ // to the CDM. This may include verifying values are within reasonable limits,
+ // stripping irrelevant data or fields, pre-parsing it, sanitizing it,
+ // and/or generating a fully sanitized version. The user agent should check
+ // that the length and values of fields are reasonable. Unknown fields should
+ // be rejected or removed.
+ if (response_length > limits::kMaxSessionResponseLength)
+ return false;
+
+ if (IsClearKey(key_system) || IsExternalClearKey(key_system)) {
+ std::string key_string(response, response + response_length);
+ KeyIdAndKeyPairs keys;
+ MediaKeys::SessionType session_type = MediaKeys::TEMPORARY_SESSION;
+ if (!ExtractKeysFromJWKSet(key_string, &keys, &session_type))
+ return false;
+
+ // Must contain at least one key.
+ if (keys.empty())
+ return false;
+
+ for (const auto key_pair : keys) {
+ if (key_pair.first.size() < limits::kMinKeyIdLength ||
+ key_pair.first.size() > limits::kMaxKeyIdLength) {
+ return false;
+ }
+ }
+
+ std::string sanitized_data = GenerateJWKSet(keys, session_type);
+ sanitized_response->assign(sanitized_data.begin(), sanitized_data.end());
+ return true;
+ }
+
+ // TODO(jrummell): Verify responses for Widevine.
+ sanitized_response->assign(response, response + response_length);
+ return true;
+}
+
WebContentDecryptionModuleSessionImpl::WebContentDecryptionModuleSessionImpl(
const scoped_refptr<CdmSessionAdapter>& adapter)
: adapter_(adapter), is_closed_(false), weak_ptr_factory_(this) {
@@ -240,11 +302,19 @@ void WebContentDecryptionModuleSessionImpl::load(
DCHECK(!session_id.isEmpty());
DCHECK(session_id_.empty());
+ std::string sanitized_session_id;
+ if (!SanitizeSessionId(session_id, &sanitized_session_id)) {
+ result.completeWithError(
+ blink::WebContentDecryptionModuleExceptionInvalidAccessError, 0,
+ "Invalid session ID.");
+ return;
+ }
+
// TODO(jrummell): Now that there are 2 types of persistent sessions, the
// session type should be passed from blink. Type should also be passed in the
// constructor (and removed from initializeNewSession()).
adapter_->LoadSession(
- MediaKeys::PERSISTENT_LICENSE_SESSION, base::UTF16ToASCII(session_id),
+ MediaKeys::PERSISTENT_LICENSE_SESSION, sanitized_session_id,
scoped_ptr<NewSessionCdmPromise>(new NewSessionCdmResultPromise(
result, adapter_->GetKeySystemUMAPrefix() + kLoadSessionUMAName,
base::Bind(
@@ -258,8 +328,18 @@ void WebContentDecryptionModuleSessionImpl::update(
blink::WebContentDecryptionModuleResult result) {
DCHECK(response);
DCHECK(!session_id_.empty());
+
+ std::vector<uint8> sanitized_response;
+ if (!SanitizeResponse(adapter_->GetKeySystem(), response, response_length,
+ &sanitized_response)) {
+ result.completeWithError(
+ blink::WebContentDecryptionModuleExceptionInvalidAccessError, 0,
+ "Invalid response.");
+ return;
+ }
+
adapter_->UpdateSession(
- session_id_, std::vector<uint8>(response, response + response_length),
+ session_id_, sanitized_response,
scoped_ptr<SimpleCdmPromise>(new CdmResultPromise<>(
result, adapter_->GetKeySystemUMAPrefix() + kUpdateSessionUMAName)));
}
« no previous file with comments | « no previous file | media/cdm/json_web_key.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698