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