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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « no previous file | media/cdm/json_web_key.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "webcontentdecryptionmodulesession_impl.h" 5 #include "webcontentdecryptionmodulesession_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback_helpers.h" 8 #include "base/callback_helpers.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/numerics/safe_conversions.h" 10 #include "base/numerics/safe_conversions.h"
11 #include "base/stl_util.h" 11 #include "base/stl_util.h"
12 #include "base/strings/string_util.h" 12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h" 13 #include "base/strings/utf_string_conversions.h"
14 #include "media/base/cdm_key_information.h" 14 #include "media/base/cdm_key_information.h"
15 #include "media/base/cdm_promise.h" 15 #include "media/base/cdm_promise.h"
16 #include "media/base/key_systems.h" 16 #include "media/base/key_systems.h"
17 #include "media/base/limits.h" 17 #include "media/base/limits.h"
18 #include "media/base/media_keys.h" 18 #include "media/base/media_keys.h"
19 #include "media/blink/cdm_result_promise.h" 19 #include "media/blink/cdm_result_promise.h"
20 #include "media/blink/cdm_session_adapter.h" 20 #include "media/blink/cdm_session_adapter.h"
21 #include "media/blink/new_session_cdm_result_promise.h" 21 #include "media/blink/new_session_cdm_result_promise.h"
22 #include "media/blink/webmediaplayer_util.h" 22 #include "media/blink/webmediaplayer_util.h"
23 #include "media/cdm/cenc_utils.h" 23 #include "media/cdm/cenc_utils.h"
24 #include "media/cdm/json_web_key.h" 24 #include "media/cdm/json_web_key.h"
25 #include "media/cdm/key_system_names.h"
25 #include "third_party/WebKit/public/platform/WebData.h" 26 #include "third_party/WebKit/public/platform/WebData.h"
26 #include "third_party/WebKit/public/platform/WebEncryptedMediaKeyInformation.h" 27 #include "third_party/WebKit/public/platform/WebEncryptedMediaKeyInformation.h"
27 #include "third_party/WebKit/public/platform/WebString.h" 28 #include "third_party/WebKit/public/platform/WebString.h"
28 #include "third_party/WebKit/public/platform/WebURL.h" 29 #include "third_party/WebKit/public/platform/WebURL.h"
29 #include "third_party/WebKit/public/platform/WebVector.h" 30 #include "third_party/WebKit/public/platform/WebVector.h"
30 31
31 namespace media { 32 namespace media {
32 33
33 const char kCloseSessionUMAName[] = "CloseSession"; 34 const char kCloseSessionUMAName[] = "CloseSession";
34 const char kGenerateRequestUMAName[] = "GenerateRequest"; 35 const char kGenerateRequestUMAName[] = "GenerateRequest";
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 142
142 case EmeInitDataType::UNKNOWN: 143 case EmeInitDataType::UNKNOWN:
143 break; 144 break;
144 } 145 }
145 146
146 NOTREACHED(); 147 NOTREACHED();
147 error_message->assign("Initialization data type is not supported."); 148 error_message->assign("Initialization data type is not supported.");
148 return false; 149 return false;
149 } 150 }
150 151
152 static bool SanitizeSessionId(const blink::WebString& session_id,
153 std::string* sanitized_session_id) {
154 // The user agent should thoroughly validate the sessionId value before
155 // passing it to the CDM. At a minimum, this should include checking that
156 // the length and value (e.g. alphanumeric) are reasonable.
157 if (!base::IsStringASCII(session_id))
158 return false;
159
160 sanitized_session_id->assign(base::UTF16ToASCII(session_id));
161 if (sanitized_session_id->length() > limits::kMaxSessionIdLength)
162 return false;
163
164 for (const char c : *sanitized_session_id) {
165 if (!IsAsciiAlpha(c) && !IsAsciiDigit(c))
166 return false;
167 }
168
169 return true;
170 }
171
172 static bool SanitizeResponse(const std::string& key_system,
173 const uint8* response,
174 size_t response_length,
175 std::vector<uint8>* sanitized_response) {
176 // The user agent should thoroughly validate the response before passing it
177 // to the CDM. This may include verifying values are within reasonable limits,
178 // stripping irrelevant data or fields, pre-parsing it, sanitizing it,
179 // and/or generating a fully sanitized version. The user agent should check
180 // that the length and values of fields are reasonable. Unknown fields should
181 // be rejected or removed.
182 if (response_length > limits::kMaxSessionResponseLength)
183 return false;
184
185 if (IsClearKey(key_system) || IsExternalClearKey(key_system)) {
186 std::string key_string(response, response + response_length);
187 KeyIdAndKeyPairs keys;
188 MediaKeys::SessionType session_type = MediaKeys::TEMPORARY_SESSION;
189 if (!ExtractKeysFromJWKSet(key_string, &keys, &session_type))
190 return false;
191
192 // Must contain at least one key.
193 if (keys.empty())
194 return false;
195
196 for (const auto key_pair : keys) {
197 if (key_pair.first.size() < limits::kMinKeyIdLength ||
198 key_pair.first.size() > limits::kMaxKeyIdLength) {
199 return false;
200 }
201 }
202
203 std::string sanitized_data = GenerateJWKSet(keys, session_type);
204 sanitized_response->assign(sanitized_data.begin(), sanitized_data.end());
205 return true;
206 }
207
208 // TODO(jrummell): Verify responses for Widevine.
209 sanitized_response->assign(response, response + response_length);
210 return true;
211 }
212
151 WebContentDecryptionModuleSessionImpl::WebContentDecryptionModuleSessionImpl( 213 WebContentDecryptionModuleSessionImpl::WebContentDecryptionModuleSessionImpl(
152 const scoped_refptr<CdmSessionAdapter>& adapter) 214 const scoped_refptr<CdmSessionAdapter>& adapter)
153 : adapter_(adapter), is_closed_(false), weak_ptr_factory_(this) { 215 : adapter_(adapter), is_closed_(false), weak_ptr_factory_(this) {
154 } 216 }
155 217
156 WebContentDecryptionModuleSessionImpl:: 218 WebContentDecryptionModuleSessionImpl::
157 ~WebContentDecryptionModuleSessionImpl() { 219 ~WebContentDecryptionModuleSessionImpl() {
158 if (!session_id_.empty()) 220 if (!session_id_.empty())
159 adapter_->UnregisterSession(session_id_); 221 adapter_->UnregisterSession(session_id_);
160 } 222 }
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 &WebContentDecryptionModuleSessionImpl::OnSessionInitialized, 295 &WebContentDecryptionModuleSessionImpl::OnSessionInitialized,
234 base::Unretained(this))))); 296 base::Unretained(this)))));
235 } 297 }
236 298
237 void WebContentDecryptionModuleSessionImpl::load( 299 void WebContentDecryptionModuleSessionImpl::load(
238 const blink::WebString& session_id, 300 const blink::WebString& session_id,
239 blink::WebContentDecryptionModuleResult result) { 301 blink::WebContentDecryptionModuleResult result) {
240 DCHECK(!session_id.isEmpty()); 302 DCHECK(!session_id.isEmpty());
241 DCHECK(session_id_.empty()); 303 DCHECK(session_id_.empty());
242 304
305 std::string sanitized_session_id;
306 if (!SanitizeSessionId(session_id, &sanitized_session_id)) {
307 result.completeWithError(
308 blink::WebContentDecryptionModuleExceptionInvalidAccessError, 0,
309 "Invalid session ID.");
310 return;
311 }
312
243 // TODO(jrummell): Now that there are 2 types of persistent sessions, the 313 // TODO(jrummell): Now that there are 2 types of persistent sessions, the
244 // session type should be passed from blink. Type should also be passed in the 314 // session type should be passed from blink. Type should also be passed in the
245 // constructor (and removed from initializeNewSession()). 315 // constructor (and removed from initializeNewSession()).
246 adapter_->LoadSession( 316 adapter_->LoadSession(
247 MediaKeys::PERSISTENT_LICENSE_SESSION, base::UTF16ToASCII(session_id), 317 MediaKeys::PERSISTENT_LICENSE_SESSION, sanitized_session_id,
248 scoped_ptr<NewSessionCdmPromise>(new NewSessionCdmResultPromise( 318 scoped_ptr<NewSessionCdmPromise>(new NewSessionCdmResultPromise(
249 result, adapter_->GetKeySystemUMAPrefix() + kLoadSessionUMAName, 319 result, adapter_->GetKeySystemUMAPrefix() + kLoadSessionUMAName,
250 base::Bind( 320 base::Bind(
251 &WebContentDecryptionModuleSessionImpl::OnSessionInitialized, 321 &WebContentDecryptionModuleSessionImpl::OnSessionInitialized,
252 base::Unretained(this))))); 322 base::Unretained(this)))));
253 } 323 }
254 324
255 void WebContentDecryptionModuleSessionImpl::update( 325 void WebContentDecryptionModuleSessionImpl::update(
256 const uint8* response, 326 const uint8* response,
257 size_t response_length, 327 size_t response_length,
258 blink::WebContentDecryptionModuleResult result) { 328 blink::WebContentDecryptionModuleResult result) {
259 DCHECK(response); 329 DCHECK(response);
260 DCHECK(!session_id_.empty()); 330 DCHECK(!session_id_.empty());
331
332 std::vector<uint8> sanitized_response;
333 if (!SanitizeResponse(adapter_->GetKeySystem(), response, response_length,
334 &sanitized_response)) {
335 result.completeWithError(
336 blink::WebContentDecryptionModuleExceptionInvalidAccessError, 0,
337 "Invalid response.");
338 return;
339 }
340
261 adapter_->UpdateSession( 341 adapter_->UpdateSession(
262 session_id_, std::vector<uint8>(response, response + response_length), 342 session_id_, sanitized_response,
263 scoped_ptr<SimpleCdmPromise>(new CdmResultPromise<>( 343 scoped_ptr<SimpleCdmPromise>(new CdmResultPromise<>(
264 result, adapter_->GetKeySystemUMAPrefix() + kUpdateSessionUMAName))); 344 result, adapter_->GetKeySystemUMAPrefix() + kUpdateSessionUMAName)));
265 } 345 }
266 346
267 void WebContentDecryptionModuleSessionImpl::close( 347 void WebContentDecryptionModuleSessionImpl::close(
268 blink::WebContentDecryptionModuleResult result) { 348 blink::WebContentDecryptionModuleResult result) {
269 DCHECK(!session_id_.empty()); 349 DCHECK(!session_id_.empty());
270 adapter_->CloseSession( 350 adapter_->CloseSession(
271 session_id_, 351 session_id_,
272 scoped_ptr<SimpleCdmPromise>(new CdmResultPromise<>( 352 scoped_ptr<SimpleCdmPromise>(new CdmResultPromise<>(
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
328 return blink::WebContentDecryptionModuleResult::SessionNotFound; 408 return blink::WebContentDecryptionModuleResult::SessionNotFound;
329 409
330 DCHECK(session_id_.empty()) << "Session ID may not be changed once set."; 410 DCHECK(session_id_.empty()) << "Session ID may not be changed once set.";
331 session_id_ = session_id; 411 session_id_ = session_id;
332 return adapter_->RegisterSession(session_id_, weak_ptr_factory_.GetWeakPtr()) 412 return adapter_->RegisterSession(session_id_, weak_ptr_factory_.GetWeakPtr())
333 ? blink::WebContentDecryptionModuleResult::NewSession 413 ? blink::WebContentDecryptionModuleResult::NewSession
334 : blink::WebContentDecryptionModuleResult::SessionAlreadyExists; 414 : blink::WebContentDecryptionModuleResult::SessionAlreadyExists;
335 } 415 }
336 416
337 } // namespace media 417 } // namespace media
OLDNEW
« 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