diff options
Diffstat (limited to 'media/cdm')
-rw-r--r-- | media/cdm/aes_decryptor.cc | 69 | ||||
-rw-r--r-- | media/cdm/aes_decryptor.h | 19 | ||||
-rw-r--r-- | media/cdm/aes_decryptor_unittest.cc | 58 | ||||
-rw-r--r-- | media/cdm/ppapi/external_clear_key/clear_key_cdm.cc | 43 | ||||
-rw-r--r-- | media/cdm/ppapi/external_clear_key/clear_key_cdm.h | 4 |
5 files changed, 141 insertions, 52 deletions
diff --git a/media/cdm/aes_decryptor.cc b/media/cdm/aes_decryptor.cc index b83c9b1..23f41d7 100644 --- a/media/cdm/aes_decryptor.cc +++ b/media/cdm/aes_decryptor.cc @@ -224,17 +224,27 @@ static scoped_refptr<DecoderBuffer> DecryptData(const DecoderBuffer& input, } AesDecryptor::AesDecryptor(const SessionMessageCB& session_message_cb, - const SessionClosedCB& session_closed_cb) + const SessionClosedCB& session_closed_cb, + const SessionKeysChangeCB& session_keys_change_cb) : session_message_cb_(session_message_cb), - session_closed_cb_(session_closed_cb) { + session_closed_cb_(session_closed_cb), + session_keys_change_cb_(session_keys_change_cb) { DCHECK(!session_message_cb_.is_null()); DCHECK(!session_closed_cb_.is_null()); + DCHECK(!session_keys_change_cb_.is_null()); } AesDecryptor::~AesDecryptor() { key_map_.clear(); } +void AesDecryptor::SetServerCertificate(const uint8* certificate_data, + int certificate_data_length, + scoped_ptr<SimpleCdmPromise> promise) { + promise->reject( + NOT_SUPPORTED_ERROR, 0, "SetServerCertificate() is not supported."); +} + void AesDecryptor::CreateSession(const std::string& init_data_type, const uint8* init_data, int init_data_length, @@ -318,6 +328,43 @@ void AesDecryptor::UpdateSession(const std::string& web_session_id, } promise->resolve(); + + // Assume that at least 1 new key has been successfully added and thus + // sending true. + session_keys_change_cb_.Run(web_session_id, true); +} + +void AesDecryptor::CloseSession(const std::string& web_session_id, + scoped_ptr<SimpleCdmPromise> promise) { + // Validate that this is a reference to an active session and then forget it. + std::set<std::string>::iterator it = valid_sessions_.find(web_session_id); + DCHECK(it != valid_sessions_.end()); + + valid_sessions_.erase(it); + + // Close the session. + DeleteKeysForSession(web_session_id); + promise->resolve(); + session_closed_cb_.Run(web_session_id); +} + +void AesDecryptor::RemoveSession(const std::string& web_session_id, + scoped_ptr<SimpleCdmPromise> promise) { + // AesDecryptor doesn't keep any persistent data, so this should be + // NOT_REACHED(). + // TODO(jrummell): Make sure persistent session types are rejected. + // http://crbug.com/384152. + // + // However, v0.1b calls to CancelKeyRequest() will call this, so close the + // session, if it exists. + // TODO(jrummell): Remove the close() call when prefixed EME is removed. + // http://crbug.com/249976. + if (valid_sessions_.find(web_session_id) != valid_sessions_.end()) { + CloseSession(web_session_id, promise.Pass()); + return; + } + + promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist."); } void AesDecryptor::GetUsableKeyIds(const std::string& web_session_id, @@ -337,24 +384,6 @@ void AesDecryptor::GetUsableKeyIds(const std::string& web_session_id, promise->resolve(keyids); } -void AesDecryptor::ReleaseSession(const std::string& web_session_id, - scoped_ptr<SimpleCdmPromise> promise) { - // Validate that this is a reference to an active session and then forget it. - std::set<std::string>::iterator it = valid_sessions_.find(web_session_id); - // TODO(jrummell): Convert back to a DCHECK once prefixed EME is removed. - if (it == valid_sessions_.end()) { - promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist."); - return; - } - - valid_sessions_.erase(it); - - // Close the session. - DeleteKeysForSession(web_session_id); - promise->resolve(); - session_closed_cb_.Run(web_session_id); -} - Decryptor* AesDecryptor::GetDecryptor() { return this; } diff --git a/media/cdm/aes_decryptor.h b/media/cdm/aes_decryptor.h index dc08bb3..98a79dd 100644 --- a/media/cdm/aes_decryptor.h +++ b/media/cdm/aes_decryptor.h @@ -28,10 +28,15 @@ namespace media { class MEDIA_EXPORT AesDecryptor : public MediaKeys, public Decryptor { public: AesDecryptor(const SessionMessageCB& session_message_cb, - const SessionClosedCB& session_closed_cb); + const SessionClosedCB& session_closed_cb, + const SessionKeysChangeCB& session_keys_change_cb); virtual ~AesDecryptor(); // MediaKeys implementation. + virtual void SetServerCertificate( + const uint8* certificate_data, + int certificate_data_length, + scoped_ptr<SimpleCdmPromise> promise) OVERRIDE; virtual void CreateSession(const std::string& init_data_type, const uint8* init_data, int init_data_length, @@ -43,8 +48,12 @@ class MEDIA_EXPORT AesDecryptor : public MediaKeys, public Decryptor { const uint8* response, int response_length, scoped_ptr<SimpleCdmPromise> promise) OVERRIDE; - virtual void ReleaseSession(const std::string& web_session_id, - scoped_ptr<SimpleCdmPromise> promise) OVERRIDE; + virtual void CloseSession(const std::string& web_session_id, + scoped_ptr<SimpleCdmPromise> promise) OVERRIDE; + virtual void RemoveSession(const std::string& web_session_id, + scoped_ptr<SimpleCdmPromise> promise) OVERRIDE; + virtual void GetUsableKeyIds(const std::string& web_session_id, + scoped_ptr<KeyIdsPromise> promise) OVERRIDE; virtual Decryptor* GetDecryptor() OVERRIDE; // Decryptor implementation. @@ -67,9 +76,6 @@ class MEDIA_EXPORT AesDecryptor : public MediaKeys, public Decryptor { virtual void ResetDecoder(StreamType stream_type) OVERRIDE; virtual void DeinitializeDecoder(StreamType stream_type) OVERRIDE; - void GetUsableKeyIds(const std::string& web_session_id, - scoped_ptr<KeyIdsPromise> promise); - private: // TODO(fgalligan): Remove this and change KeyMap to use crypto::SymmetricKey // as there are no decryptors that are performing an integrity check. @@ -120,6 +126,7 @@ class MEDIA_EXPORT AesDecryptor : public MediaKeys, public Decryptor { // Callbacks for firing session events. SessionMessageCB session_message_cb_; SessionClosedCB session_closed_cb_; + SessionKeysChangeCB session_keys_change_cb_; // Since only Decrypt() is called off the renderer thread, we only need to // protect |key_map_|, the only member variable that is shared between diff --git a/media/cdm/aes_decryptor_unittest.cc b/media/cdm/aes_decryptor_unittest.cc index a40867e7..de52d69 100644 --- a/media/cdm/aes_decryptor_unittest.cc +++ b/media/cdm/aes_decryptor_unittest.cc @@ -211,6 +211,8 @@ class AesDecryptorTest : public testing::Test { : decryptor_(base::Bind(&AesDecryptorTest::OnSessionMessage, base::Unretained(this)), base::Bind(&AesDecryptorTest::OnSessionClosed, + base::Unretained(this)), + base::Bind(&AesDecryptorTest::OnSessionKeysChange, base::Unretained(this))), decrypt_cb_(base::Bind(&AesDecryptorTest::BufferDecrypted, base::Unretained(this))), @@ -307,23 +309,38 @@ class AesDecryptorTest : public testing::Test { return web_session_id_; } - // Releases the session specified by |session_id|. - void ReleaseSession(const std::string& session_id) { + // Closes the session specified by |session_id|. + void CloseSession(const std::string& session_id) { EXPECT_CALL(*this, OnSessionClosed(session_id)); - decryptor_.ReleaseSession(session_id, CreatePromise(RESOLVED)); + decryptor_.CloseSession(session_id, CreatePromise(RESOLVED)); + } + + // Removes the session specified by |session_id|. This should simply do a + // CloseSession(). + // TODO(jrummell): Clean this up when the prefixed API is removed. + // http://crbug.com/249976. + void RemoveSession(const std::string& session_id) { + EXPECT_CALL(*this, OnSessionClosed(session_id)); + decryptor_.RemoveSession(session_id, CreatePromise(RESOLVED)); } // Updates the session specified by |session_id| with |key|. |result| // tests that the update succeeds or generates an error. void UpdateSessionAndExpect(std::string session_id, const std::string& key, - PromiseResult result) { + PromiseResult expected_result) { DCHECK(!key.empty()); + if (expected_result == RESOLVED) { + EXPECT_CALL(*this, OnSessionKeysChange(session_id, true)); + } else { + EXPECT_CALL(*this, OnSessionKeysChange(_, _)).Times(0); + } + decryptor_.UpdateSession(session_id, reinterpret_cast<const uint8*>(key.c_str()), key.length(), - CreatePromise(result)); + CreatePromise(expected_result)); } void GetUsableKeyIdsAndExpect(const std::string& session_id, @@ -406,6 +423,9 @@ class AesDecryptorTest : public testing::Test { void(const std::string& web_session_id, const std::vector<uint8>& message, const GURL& destination_url)); + MOCK_METHOD2(OnSessionKeysChange, + void(const std::string& web_session_id, + bool has_additional_usable_key)); MOCK_METHOD1(OnSessionClosed, void(const std::string& web_session_id)); AesDecryptor decryptor_; @@ -647,7 +667,21 @@ TEST_F(AesDecryptorTest, SubsampleCypherBytesOnly) { DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS); } -TEST_F(AesDecryptorTest, ReleaseSession) { +TEST_F(AesDecryptorTest, CloseSession) { + std::string session_id = CreateSession(key_id_); + scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer( + encrypted_data_, key_id_, iv_, no_subsample_entries_); + + UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED); + ASSERT_NO_FATAL_FAILURE( + DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS)); + + CloseSession(session_id); +} + +TEST_F(AesDecryptorTest, RemoveSession) { + // TODO(jrummell): Clean this up when the prefixed API is removed. + // http://crbug.com/249976. std::string session_id = CreateSession(key_id_); scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer( encrypted_data_, key_id_, iv_, no_subsample_entries_); @@ -656,10 +690,10 @@ TEST_F(AesDecryptorTest, ReleaseSession) { ASSERT_NO_FATAL_FAILURE( DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS)); - ReleaseSession(session_id); + RemoveSession(session_id); } -TEST_F(AesDecryptorTest, NoKeyAfterReleaseSession) { +TEST_F(AesDecryptorTest, NoKeyAfterCloseSession) { std::string session_id = CreateSession(key_id_); scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer( encrypted_data_, key_id_, iv_, no_subsample_entries_); @@ -668,7 +702,7 @@ TEST_F(AesDecryptorTest, NoKeyAfterReleaseSession) { ASSERT_NO_FATAL_FAILURE( DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS)); - ReleaseSession(session_id); + CloseSession(session_id); ASSERT_NO_FATAL_FAILURE( DecryptAndExpect(encrypted_buffer, original_data_, NO_KEY)); } @@ -692,7 +726,7 @@ TEST_F(AesDecryptorTest, LatestKeyUsed) { DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS)); } -TEST_F(AesDecryptorTest, LatestKeyUsedAfterReleaseSession) { +TEST_F(AesDecryptorTest, LatestKeyUsedAfterCloseSession) { std::string session_id1 = CreateSession(key_id_); scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer( encrypted_data_, key_id_, iv_, no_subsample_entries_); @@ -709,7 +743,7 @@ TEST_F(AesDecryptorTest, LatestKeyUsedAfterReleaseSession) { DecryptAndExpect(encrypted_buffer, original_data_, DATA_MISMATCH)); // Close second session, should revert to original key. - ReleaseSession(session_id2); + CloseSession(session_id2); ASSERT_NO_FATAL_FAILURE( DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS)); } @@ -841,7 +875,7 @@ TEST_F(AesDecryptorTest, JWKKey) { " ]" "}"; UpdateSessionAndExpect(session_id, kJwksWithEmptyKeyId, REJECTED); - ReleaseSession(session_id); + CloseSession(session_id); } TEST_F(AesDecryptorTest, GetKeyIds) { diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc index e06f41b..a49b6c2 100644 --- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc +++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc @@ -220,8 +220,10 @@ namespace media { ClearKeyCdm::ClearKeyCdm(ClearKeyCdmHost* host, const std::string& key_system) : decryptor_( - base::Bind(&ClearKeyCdm::OnSessionMessage, base::Unretained(this)), - base::Bind(&ClearKeyCdm::OnSessionClosed, base::Unretained(this))), + base::Bind(&ClearKeyCdm::OnSessionMessage, base::Unretained(this)), + base::Bind(&ClearKeyCdm::OnSessionClosed, base::Unretained(this)), + base::Bind(&ClearKeyCdm::OnSessionKeysChange, + base::Unretained(this))), host_(host), key_system_(key_system), timer_delay_ms_(kInitialTimerDelayMs), @@ -327,13 +329,11 @@ void ClearKeyCdm::CloseSession(uint32 promise_id, std::string web_session_str(web_session_id, web_session_id_length); scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise( - base::Bind(&ClearKeyCdm::OnSessionReleased, - base::Unretained(this), - promise_id, - web_session_str), + base::Bind( + &ClearKeyCdm::OnPromiseResolved, base::Unretained(this), promise_id), base::Bind( &ClearKeyCdm::OnPromiseFailed, base::Unretained(this), promise_id))); - decryptor_.ReleaseSession(web_session_str, promise.Pass()); + decryptor_.CloseSession(web_session_str, promise.Pass()); } void ClearKeyCdm::RemoveSession(uint32 promise_id, @@ -345,8 +345,19 @@ void ClearKeyCdm::RemoveSession(uint32 promise_id, std::string(kLoadableWebSessionId) == std::string(web_session_id, web_session_id_length); if (is_persistent_session) { - host_->OnResolvePromise(promise_id); + std::string web_session_str(web_session_id, web_session_id_length); + + scoped_ptr<media::SimpleCdmPromise> promise( + new media::SimpleCdmPromise(base::Bind(&ClearKeyCdm::OnPromiseResolved, + base::Unretained(this), + promise_id), + base::Bind(&ClearKeyCdm::OnPromiseFailed, + base::Unretained(this), + promise_id))); + decryptor_.RemoveSession(web_session_str, promise.Pass()); } else { + // TODO(jrummell): This should be a DCHECK once blink does the proper + // checks. std::string message("Not supported for non-persistent sessions."); host_->OnRejectPromise(promise_id, cdm::kInvalidAccessError, @@ -683,6 +694,13 @@ void ClearKeyCdm::OnSessionMessage(const std::string& web_session_id, destination_url.spec().size()); } +void ClearKeyCdm::OnSessionKeysChange(const std::string& web_session_id, + bool has_additional_usable_key) { + host_->OnSessionUsableKeysChange(web_session_id.data(), + web_session_id.length(), + has_additional_usable_key); +} + void ClearKeyCdm::OnSessionClosed(const std::string& web_session_id) { host_->OnSessionClosed(web_session_id.data(), web_session_id.length()); } @@ -733,11 +751,6 @@ void ClearKeyCdm::OnSessionUpdated(uint32 promise_id, host_->OnResolvePromise(promise_id); } -void ClearKeyCdm::OnSessionReleased(uint32 promise_id, - const std::string& web_session_id) { - host_->OnResolvePromise(promise_id); -} - void ClearKeyCdm::OnUsableKeyIdsObtained(uint32 promise_id, const KeyIdsVector& key_ids) { scoped_ptr<cdm::BinaryData[]> result(new cdm::BinaryData[key_ids.size()]); @@ -748,6 +761,10 @@ void ClearKeyCdm::OnUsableKeyIdsObtained(uint32 promise_id, host_->OnResolveKeyIdsPromise(promise_id, result.get(), key_ids.size()); } +void ClearKeyCdm::OnPromiseResolved(uint32 promise_id) { + host_->OnResolvePromise(promise_id); +} + void ClearKeyCdm::OnPromiseFailed(uint32 promise_id, MediaKeys::Exception exception_code, uint32 system_code, diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm.h b/media/cdm/ppapi/external_clear_key/clear_key_cdm.h index c491cd7..19d41f8 100644 --- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.h +++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.h @@ -92,6 +92,8 @@ class ClearKeyCdm : public ClearKeyCdmInterface { void OnSessionMessage(const std::string& web_session_id, const std::vector<uint8>& message, const GURL& destination_url); + void OnSessionKeysChange(const std::string& web_session_id, + bool has_additional_usable_key); void OnSessionClosed(const std::string& web_session_id); // Handle the success/failure of a promise. These methods are responsible for @@ -99,8 +101,8 @@ class ClearKeyCdm : public ClearKeyCdmInterface { void OnSessionCreated(uint32 promise_id, const std::string& web_session_id); void OnSessionLoaded(uint32 promise_id, const std::string& web_session_id); void OnSessionUpdated(uint32 promise_id, const std::string& web_session_id); - void OnSessionReleased(uint32 promise_id, const std::string& web_session_id); void OnUsableKeyIdsObtained(uint32 promise_id, const KeyIdsVector& key_ids); + void OnPromiseResolved(uint32 promise_id); void OnPromiseFailed(uint32 promise_id, MediaKeys::Exception exception_code, uint32 system_code, |