| 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 |