OLD | NEW |
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 "media/cdm/aes_decryptor.h" | 5 #include "media/cdm/aes_decryptor.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <list> | 8 #include <list> |
9 #include <utility> | 9 #include <utility> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/macros.h" | 13 #include "base/macros.h" |
14 #include "base/strings/string_number_conversions.h" | 14 #include "base/strings/string_number_conversions.h" |
15 #include "crypto/encryptor.h" | 15 #include "crypto/encryptor.h" |
16 #include "crypto/symmetric_key.h" | 16 #include "crypto/symmetric_key.h" |
17 #include "media/base/audio_decoder_config.h" | 17 #include "media/base/audio_decoder_config.h" |
18 #include "media/base/cdm_key_information.h" | |
19 #include "media/base/cdm_promise.h" | 18 #include "media/base/cdm_promise.h" |
20 #include "media/base/decoder_buffer.h" | 19 #include "media/base/decoder_buffer.h" |
21 #include "media/base/decrypt_config.h" | 20 #include "media/base/decrypt_config.h" |
22 #include "media/base/limits.h" | 21 #include "media/base/limits.h" |
23 #include "media/base/video_decoder_config.h" | 22 #include "media/base/video_decoder_config.h" |
24 #include "media/base/video_frame.h" | 23 #include "media/base/video_frame.h" |
25 #include "media/cdm/json_web_key.h" | 24 #include "media/cdm/json_web_key.h" |
26 #include "media/media_features.h" | 25 #include "media/media_features.h" |
27 | 26 |
28 #if BUILDFLAG(USE_PROPRIETARY_CODECS) | 27 #if BUILDFLAG(USE_PROPRIETARY_CODECS) |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 DCHECK_EQ(decrypted_text.size(), encrypted_text.size()); | 223 DCHECK_EQ(decrypted_text.size(), encrypted_text.size()); |
225 | 224 |
226 scoped_refptr<DecoderBuffer> output = DecoderBuffer::CopyFrom( | 225 scoped_refptr<DecoderBuffer> output = DecoderBuffer::CopyFrom( |
227 reinterpret_cast<const uint8_t*>(sample), sample_size); | 226 reinterpret_cast<const uint8_t*>(sample), sample_size); |
228 CopySubsamples(subsamples, kDstContainsClearBytes, | 227 CopySubsamples(subsamples, kDstContainsClearBytes, |
229 reinterpret_cast<const uint8_t*>(decrypted_text.data()), | 228 reinterpret_cast<const uint8_t*>(decrypted_text.data()), |
230 output->writable_data()); | 229 output->writable_data()); |
231 return output; | 230 return output; |
232 } | 231 } |
233 | 232 |
234 AesDecryptor::AesDecryptor(const GURL& /* security_origin */, | 233 AesDecryptor::AesDecryptor( |
235 const SessionMessageCB& session_message_cb, | 234 const GURL& /* security_origin */, |
236 const SessionClosedCB& session_closed_cb, | 235 const SessionMessageCB& session_message_cb, |
237 const SessionKeysChangeCB& session_keys_change_cb) | 236 const SessionClosedCB& session_closed_cb, |
| 237 const SessionKeysChangeCB& session_keys_change_cb, |
| 238 const SessionExpirationUpdateCB& session_expiration_update_cb) |
238 : session_message_cb_(session_message_cb), | 239 : session_message_cb_(session_message_cb), |
239 session_closed_cb_(session_closed_cb), | 240 session_closed_cb_(session_closed_cb), |
240 session_keys_change_cb_(session_keys_change_cb) { | 241 session_keys_change_cb_(session_keys_change_cb), |
| 242 session_expiration_update_cb_(session_expiration_update_cb) { |
241 // AesDecryptor doesn't keep any persistent data, so no need to do anything | 243 // AesDecryptor doesn't keep any persistent data, so no need to do anything |
242 // with |security_origin|. | 244 // with |security_origin|. |
243 DCHECK(!session_message_cb_.is_null()); | 245 DCHECK(!session_message_cb_.is_null()); |
244 DCHECK(!session_closed_cb_.is_null()); | 246 DCHECK(!session_closed_cb_.is_null()); |
245 DCHECK(!session_keys_change_cb_.is_null()); | 247 DCHECK(!session_keys_change_cb_.is_null()); |
246 } | 248 } |
247 | 249 |
248 AesDecryptor::~AesDecryptor() { | 250 AesDecryptor::~AesDecryptor() { |
249 key_map_.clear(); | 251 key_map_.clear(); |
250 } | 252 } |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
384 | 386 |
385 if (!new_audio_key_cb_.is_null()) | 387 if (!new_audio_key_cb_.is_null()) |
386 new_audio_key_cb_.Run(); | 388 new_audio_key_cb_.Run(); |
387 | 389 |
388 if (!new_video_key_cb_.is_null()) | 390 if (!new_video_key_cb_.is_null()) |
389 new_video_key_cb_.Run(); | 391 new_video_key_cb_.Run(); |
390 } | 392 } |
391 | 393 |
392 promise->resolve(); | 394 promise->resolve(); |
393 | 395 |
394 // Create the list of all available keys for this session. | 396 session_keys_change_cb_.Run( |
395 CdmKeysInfo keys_info; | 397 session_id, key_added, |
396 { | 398 GenerateKeysInfoList(session_id, CdmKeyInformation::USABLE)); |
397 base::AutoLock auto_lock(key_map_lock_); | |
398 for (const auto& item : key_map_) { | |
399 if (item.second->Contains(session_id)) { | |
400 keys_info.push_back( | |
401 new CdmKeyInformation(item.first, CdmKeyInformation::USABLE, 0)); | |
402 } | |
403 } | |
404 } | |
405 | |
406 session_keys_change_cb_.Run(session_id, key_added, std::move(keys_info)); | |
407 } | 399 } |
408 | 400 |
409 // Runs the parallel steps from https://w3c.github.io/encrypted-media/#close. | 401 // Runs the parallel steps from https://w3c.github.io/encrypted-media/#close. |
410 void AesDecryptor::CloseSession(const std::string& session_id, | 402 void AesDecryptor::CloseSession(const std::string& session_id, |
411 std::unique_ptr<SimpleCdmPromise> promise) { | 403 std::unique_ptr<SimpleCdmPromise> promise) { |
412 // Validate that this is a reference to an open session. close() shouldn't | 404 // Validate that this is a reference to an open session. close() shouldn't |
413 // be called if the session is already closed. However, the operation is | 405 // be called if the session is already closed. However, the operation is |
414 // asynchronous, so there is a window where close() was called a second time | 406 // asynchronous, so there is a window where close() was called a second time |
415 // just before the closed event arrives. As a result it is possible that the | 407 // just before the closed event arrives. As a result it is possible that the |
416 // session is already closed, so assume that the session is closed if it | 408 // session is already closed, so assume that the session is closed if it |
(...skipping 13 matching lines...) Expand all Loading... |
430 open_sessions_.erase(it); | 422 open_sessions_.erase(it); |
431 DeleteKeysForSession(session_id); | 423 DeleteKeysForSession(session_id); |
432 | 424 |
433 // 5.3. Queue a task to run the following steps: | 425 // 5.3. Queue a task to run the following steps: |
434 // 5.3.1. Run the Session Closed algorithm on the session. | 426 // 5.3.1. Run the Session Closed algorithm on the session. |
435 session_closed_cb_.Run(session_id); | 427 session_closed_cb_.Run(session_id); |
436 // 5.3.2. Resolve promise. | 428 // 5.3.2. Resolve promise. |
437 promise->resolve(); | 429 promise->resolve(); |
438 } | 430 } |
439 | 431 |
| 432 // Runs the parallel steps from https://w3c.github.io/encrypted-media/#remove. |
440 void AesDecryptor::RemoveSession(const std::string& session_id, | 433 void AesDecryptor::RemoveSession(const std::string& session_id, |
441 std::unique_ptr<SimpleCdmPromise> promise) { | 434 std::unique_ptr<SimpleCdmPromise> promise) { |
442 NOTIMPLEMENTED() << "Need to address https://crbug.com/616166."; | 435 std::set<std::string>::iterator it = open_sessions_.find(session_id); |
443 promise->reject(CdmPromise::INVALID_ACCESS_ERROR, 0, | 436 if (it == open_sessions_.end()) { |
444 "Session does not exist."); | 437 // Session doesn't exist. Since this should only be called if the session |
| 438 // existed at one time, this must mean the session has been closed. |
| 439 promise->reject(CdmPromise::INVALID_STATE_ERROR, 0, |
| 440 "The session is already closed."); |
| 441 return; |
| 442 } |
| 443 |
| 444 // Create the list of all existing keys for this session. They will be |
| 445 // removed, so set the status to "released". |
| 446 CdmKeysInfo keys_info = |
| 447 GenerateKeysInfoList(session_id, CdmKeyInformation::RELEASED); |
| 448 |
| 449 // 4.1. Let cdm be the CDM instance represented by session's cdm instance |
| 450 // value. |
| 451 // 4.2 Let message be null. |
| 452 // 4.3 Let message type be null. |
| 453 // 4.4 Use the cdm to execute the following steps: |
| 454 // 4.4.1.1 Destroy the license(s) and/or key(s) associated with the session. |
| 455 DeleteKeysForSession(session_id); |
| 456 |
| 457 // 4.4.1.2 Follow the steps for the value of this object's session type |
| 458 // from the following list: |
| 459 // "temporary" |
| 460 // Continue with the following steps. |
| 461 // "persistent-license" |
| 462 // (Not supported, so no need to do anything.) |
| 463 |
| 464 // 4.5. Queue a task to run the following steps: |
| 465 // 4.5.1 Run the Update Key Statuses algorithm on the session, providing |
| 466 // all key ID(s) in the session along with the "released" |
| 467 // MediaKeyStatus value for each. |
| 468 session_keys_change_cb_.Run(session_id, false, std::move(keys_info)); |
| 469 |
| 470 // 4.5.2 Run the Update Expiration algorithm on the session, providing NaN. |
| 471 session_expiration_update_cb_.Run(session_id, base::Time()); |
| 472 |
| 473 // 4.5.3 If any of the preceding steps failed, reject promise with a new |
| 474 // DOMException whose name is the appropriate error name. |
| 475 // 4.5.4 Let message type be "license-release". |
| 476 // 4.5.5 If message is not null, run the Queue a "message" Event algorithm |
| 477 // on the session, providing message type and message. |
| 478 // (Not needed as message is only set for persistent licenses, and they're |
| 479 // not supported here.) |
| 480 |
| 481 // 4.5.6. Resolve promise. |
| 482 promise->resolve(); |
445 } | 483 } |
446 | 484 |
447 CdmContext* AesDecryptor::GetCdmContext() { | 485 CdmContext* AesDecryptor::GetCdmContext() { |
448 return this; | 486 return this; |
449 } | 487 } |
450 | 488 |
451 Decryptor* AesDecryptor::GetDecryptor() { | 489 Decryptor* AesDecryptor::GetDecryptor() { |
452 return this; | 490 return this; |
453 } | 491 } |
454 | 492 |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
601 // iterator, so we need to increment it first. | 639 // iterator, so we need to increment it first. |
602 KeyIdToSessionKeysMap::iterator current = it; | 640 KeyIdToSessionKeysMap::iterator current = it; |
603 ++it; | 641 ++it; |
604 key_map_.erase(current); | 642 key_map_.erase(current); |
605 } else { | 643 } else { |
606 ++it; | 644 ++it; |
607 } | 645 } |
608 } | 646 } |
609 } | 647 } |
610 | 648 |
| 649 CdmKeysInfo AesDecryptor::GenerateKeysInfoList( |
| 650 const std::string& session_id, |
| 651 CdmKeyInformation::KeyStatus status) { |
| 652 // Create the list of all available keys for this session. |
| 653 CdmKeysInfo keys_info; |
| 654 { |
| 655 base::AutoLock auto_lock(key_map_lock_); |
| 656 for (const auto& item : key_map_) { |
| 657 if (item.second->Contains(session_id)) { |
| 658 keys_info.push_back(new CdmKeyInformation(item.first, status, 0)); |
| 659 } |
| 660 } |
| 661 } |
| 662 return keys_info; |
| 663 } |
| 664 |
611 AesDecryptor::DecryptionKey::DecryptionKey(const std::string& secret) | 665 AesDecryptor::DecryptionKey::DecryptionKey(const std::string& secret) |
612 : secret_(secret) { | 666 : secret_(secret) { |
613 } | 667 } |
614 | 668 |
615 AesDecryptor::DecryptionKey::~DecryptionKey() {} | 669 AesDecryptor::DecryptionKey::~DecryptionKey() {} |
616 | 670 |
617 bool AesDecryptor::DecryptionKey::Init() { | 671 bool AesDecryptor::DecryptionKey::Init() { |
618 CHECK(!secret_.empty()); | 672 CHECK(!secret_.empty()); |
619 decryption_key_ = | 673 decryption_key_ = |
620 crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, secret_); | 674 crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, secret_); |
621 if (!decryption_key_) | 675 if (!decryption_key_) |
622 return false; | 676 return false; |
623 return true; | 677 return true; |
624 } | 678 } |
625 | 679 |
626 } // namespace media | 680 } // namespace media |
OLD | NEW |