diff --git a/packager/media/base/widevine_key_source.cc b/packager/media/base/widevine_key_source.cc index f9ca63fbdc..e6225c197a 100644 --- a/packager/media/base/widevine_key_source.cc +++ b/packager/media/base/widevine_key_source.cc @@ -136,13 +136,11 @@ class WidevineKeySource::RefCountedEncryptionKeyMap DISALLOW_COPY_AND_ASSIGN(RefCountedEncryptionKeyMap); }; -WidevineKeySource::WidevineKeySource( - const std::string& server_url, - scoped_ptr signer) - : key_production_thread_( - "KeyProductionThread", - base::Bind(&WidevineKeySource::FetchKeysTask, - base::Unretained(this))), +WidevineKeySource::WidevineKeySource(const std::string& server_url, + scoped_ptr signer) + : key_production_thread_("KeyProductionThread", + base::Bind(&WidevineKeySource::FetchKeysTask, + base::Unretained(this))), key_fetcher_(new HttpKeyFetcher(kKeyFetchTimeoutInSeconds)), server_url_(server_url), signer_(signer.Pass()), @@ -150,7 +148,6 @@ WidevineKeySource::WidevineKeySource( key_production_started_(false), start_key_production_(false, false), first_crypto_period_index_(0) { - DCHECK(signer_); } WidevineKeySource::~WidevineKeySource() { @@ -313,7 +310,7 @@ Status WidevineKeySource::FetchKeysInternal(bool enable_key_rotation, &request); std::string message; - Status status = SignRequest(request, &message); + Status status = GenerateKeyMessage(request, &message); if (!status.ok()) return status; VLOG(1) << "Message: " << message; @@ -397,28 +394,30 @@ void WidevineKeySource::FillRequest(bool enable_key_rotation, base::JSONWriter::Write(&request_dict_, request); } -Status WidevineKeySource::SignRequest(const std::string& request, - std::string* signed_request) { - DCHECK(signed_request); +Status WidevineKeySource::GenerateKeyMessage(const std::string& request, + std::string* message) { + DCHECK(message); - // Sign the request. - std::string signature; - if (!signer_->GenerateSignature(request, &signature)) - return Status(error::INTERNAL_ERROR, "Signature generation failed."); - - // Encode request and signature using Base64 encoding. std::string request_base64_string; base::Base64Encode(request, &request_base64_string); - std::string signature_base64_string; - base::Base64Encode(signature, &signature_base64_string); + base::DictionaryValue request_dict; + request_dict.SetString("request", request_base64_string); - base::DictionaryValue signed_request_dict; - signed_request_dict.SetString("request", request_base64_string); - signed_request_dict.SetString("signature", signature_base64_string); - signed_request_dict.SetString("signer", signer_->signer_name()); + // Sign the request. + if (signer_) { + std::string signature; + if (!signer_->GenerateSignature(request, &signature)) + return Status(error::INTERNAL_ERROR, "Signature generation failed."); - base::JSONWriter::Write(&signed_request_dict, signed_request); + std::string signature_base64_string; + base::Base64Encode(signature, &signature_base64_string); + + request_dict.SetString("signature", signature_base64_string); + request_dict.SetString("signer", signer_->signer_name()); + } + + base::JSONWriter::Write(&request_dict, message); return Status::OK; } diff --git a/packager/media/base/widevine_key_source.h b/packager/media/base/widevine_key_source.h index 8ab63ab12c..a777e88c30 100644 --- a/packager/media/base/widevine_key_source.h +++ b/packager/media/base/widevine_key_source.h @@ -26,7 +26,7 @@ template class ProducerConsumerQueue; class WidevineKeySource : public KeySource { public: /// @param server_url is the Widevine common encryption server url. - /// @param signer signs the request message. It should not be NULL. + /// @param signer signs the request message. Can be NULL. WidevineKeySource(const std::string& server_url, scoped_ptr signer); @@ -81,9 +81,9 @@ class WidevineKeySource : public KeySource { void FillRequest(bool enable_key_rotation, uint32_t first_crypto_period_index, std::string* request); - // Sign and properly format |request|. - // |signed_request| should not be NULL. Return OK on success. - Status SignRequest(const std::string& request, std::string* signed_request); + // Base64 escape and format the request. Optionally sign the request if a + // signer is provided. |message| should not be NULL. Return OK on success. + Status GenerateKeyMessage(const std::string& request, std::string* message); // Decode |response| from JSON formatted |raw_response|. // |response| should not be NULL. bool DecodeResponse(const std::string& raw_response, std::string* response); diff --git a/packager/media/base/widevine_key_source_unittest.cc b/packager/media/base/widevine_key_source_unittest.cc index 56ab7805c2..97d5244ae9 100644 --- a/packager/media/base/widevine_key_source_unittest.cc +++ b/packager/media/base/widevine_key_source_unittest.cc @@ -156,10 +156,9 @@ class WidevineKeySourceTest : public ::testing::Test { } protected: - void CreateWidevineKeySource() { - widevine_key_source_.reset(new WidevineKeySource( - kServerUrl, - mock_request_signer_.PassAs())); + void CreateWidevineKeySource(scoped_ptr request_signer) { + widevine_key_source_.reset( + new WidevineKeySource(kServerUrl, request_signer.Pass())); widevine_key_source_->set_key_fetcher( mock_key_fetcher_.PassAs()); } @@ -204,7 +203,7 @@ TEST_F(WidevineKeySourceTest, GenerateSignatureFailure) { EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _)) .WillOnce(Return(false)); - CreateWidevineKeySource(); + CreateWidevineKeySource(mock_request_signer_.PassAs()); ASSERT_EQ(Status(error::INTERNAL_ERROR, "Signature generation failed."), widevine_key_source_->FetchKeys(content_id_, kPolicy)); } @@ -227,30 +226,24 @@ TEST_F(WidevineKeySourceTest, HttpFetchFailure) { FetchKeys(StrEq(kServerUrl), expected_post_data, _)) .WillOnce(Return(kMockStatus)); - CreateWidevineKeySource(); + CreateWidevineKeySource(mock_request_signer_.PassAs()); ASSERT_EQ(kMockStatus, widevine_key_source_->FetchKeys(content_id_, kPolicy)); } TEST_F(WidevineKeySourceTest, LicenseStatusCencOK) { - EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _)) - .WillOnce(Return(true)); - std::string mock_response = base::StringPrintf( kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str()); EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _)) .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); - CreateWidevineKeySource(); + CreateWidevineKeySource(scoped_ptr()); ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy)); VerifyKeys(false); } TEST_F(WidevineKeySourceTest, LicenseStatusCencNotOK) { - EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _)) - .WillOnce(Return(true)); - std::string mock_response = base::StringPrintf( kHttpResponseFormat, Base64Encode( GenerateMockClassicLicenseResponse()).c_str()); @@ -258,23 +251,20 @@ TEST_F(WidevineKeySourceTest, LicenseStatusCencNotOK) { EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _)) .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); - CreateWidevineKeySource(); + CreateWidevineKeySource(scoped_ptr()); ASSERT_EQ(error::SERVER_ERROR, widevine_key_source_->FetchKeys(content_id_, kPolicy) .error_code()); } TEST_F(WidevineKeySourceTest, LicenseStatusCencWithPsshDataOK) { - EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _)) - .WillOnce(Return(true)); - std::string mock_response = base::StringPrintf( kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str()); EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _)) .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); - CreateWidevineKeySource(); + CreateWidevineKeySource(scoped_ptr()); std::vector pssh_data( reinterpret_cast(kRequestPsshData), reinterpret_cast(kRequestPsshData) + strlen(kContentId)); @@ -283,9 +273,6 @@ TEST_F(WidevineKeySourceTest, LicenseStatusCencWithPsshDataOK) { } TEST_F(WidevineKeySourceTest, LicenseStatusClassicOK) { - EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _)) - .WillOnce(Return(true)); - std::string mock_response = base::StringPrintf( kHttpResponseFormat, Base64Encode( GenerateMockClassicLicenseResponse()).c_str()); @@ -293,15 +280,12 @@ TEST_F(WidevineKeySourceTest, LicenseStatusClassicOK) { EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _)) .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); - CreateWidevineKeySource(); + CreateWidevineKeySource(scoped_ptr()); ASSERT_OK(widevine_key_source_->FetchKeys(kClassicAssetId)); VerifyKeys(true); } TEST_F(WidevineKeySourceTest, RetryOnHttpTimeout) { - EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _)) - .WillOnce(Return(true)); - std::string mock_response = base::StringPrintf( kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str()); @@ -310,15 +294,12 @@ TEST_F(WidevineKeySourceTest, RetryOnHttpTimeout) { .WillOnce(Return(Status(error::TIME_OUT, ""))) .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); - CreateWidevineKeySource(); + CreateWidevineKeySource(scoped_ptr()); ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy)); VerifyKeys(false); } TEST_F(WidevineKeySourceTest, RetryOnTransientError) { - EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _)) - .WillOnce(Return(true)); - std::string mock_license_status = base::StringPrintf( kLicenseResponseFormat, kLicenseStatusTransientError, ""); std::string mock_response = base::StringPrintf( @@ -333,15 +314,12 @@ TEST_F(WidevineKeySourceTest, RetryOnTransientError) { .WillOnce(DoAll(SetArgPointee<2>(expected_retried_response), Return(Status::OK))); - CreateWidevineKeySource(); + CreateWidevineKeySource(scoped_ptr()); ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy)); VerifyKeys(false); } TEST_F(WidevineKeySourceTest, NoRetryOnUnknownError) { - EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _)) - .WillOnce(Return(true)); - std::string mock_license_status = base::StringPrintf( kLicenseResponseFormat, kLicenseStatusUnknownError, ""); std::string mock_response = base::StringPrintf( @@ -350,7 +328,7 @@ TEST_F(WidevineKeySourceTest, NoRetryOnUnknownError) { EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _)) .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); - CreateWidevineKeySource(); + CreateWidevineKeySource(scoped_ptr()); ASSERT_EQ(error::SERVER_ERROR, widevine_key_source_->FetchKeys(content_id_, kPolicy).error_code()); } @@ -435,7 +413,7 @@ TEST_F(WidevineKeySourceTest, KeyRotationTest) { .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); } - CreateWidevineKeySource(); + CreateWidevineKeySource(mock_request_signer_.PassAs()); ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy)); EncryptionKey encryption_key; diff --git a/packager/media/formats/wvm/wvm_media_parser_unittest.cc b/packager/media/formats/wvm/wvm_media_parser_unittest.cc index 068f0446ed..7482f43c65 100644 --- a/packager/media/formats/wvm/wvm_media_parser_unittest.cc +++ b/packager/media/formats/wvm/wvm_media_parser_unittest.cc @@ -17,7 +17,7 @@ #include "packager/media/base/stream_info.h" #include "packager/media/base/timestamp.h" #include "packager/media/base/video_stream_info.h" -#include "packager/media/base/widevine_key_source.h" +#include "packager/media/base/key_source.h" #include "packager/media/formats/wvm/wvm_media_parser.h" #include "packager/media/test/test_data_util.h" @@ -28,47 +28,21 @@ const char kWvmFile[] = "hb2_4stream_encrypted.wvm"; const uint32_t kExpectedStreams = 4; const int kExpectedVideoFrameCount = 6665; const int kExpectedAudioFrameCount = 11964; -const char kServerUrl[] = "fake_server_url"; -const char kSigner[] = "fake_signer"; -const uint8 kExpectedAssetKey[16] = {'\006', static_cast('\201'), '\177', - 'H', 'k', static_cast('\362'), '\177', '>', static_cast('\307'), - '9', static_cast('\250'), '?', '\022', '\n', - static_cast('\322'), static_cast('\374')}; -} // namespace +const uint8_t kExpectedAssetKey[] = + "\x06\x81\x7f\x48\x6b\xf2\x7f\x3e\xc7\x39\xa8\x3f\x12\x0a\xd2\xfc"; +} // namespace using ::testing::_; using ::testing::DoAll; -using ::testing::InSequence; using ::testing::Return; using ::testing::SetArgPointee; namespace edash_packager { namespace media { -class FakeRequestSigner : public RequestSigner { +class MockKeySource : public KeySource { public: - FakeRequestSigner() : RequestSigner(kSigner) {} - virtual ~FakeRequestSigner() {} - - virtual bool GenerateSignature(const std::string& message, - std::string* signature) OVERRIDE { - return true; - } - - private: - DISALLOW_COPY_AND_ASSIGN(FakeRequestSigner); -}; - -scoped_ptr kFakeRequestSigner(new FakeRequestSigner()); - -class MockKeySource : public WidevineKeySource { - public: - MockKeySource() : WidevineKeySource( - kServerUrl, kFakeRequestSigner.PassAs()) { - // KeyProduction thread started in test because FetchKeys() - // is mocked. ~ClosureThread expects to terminate this thread. - key_production_thread_.Start(); - } + MockKeySource() {} virtual ~MockKeySource() {} MOCK_METHOD1(FetchKeys, Status(uint32_t asset_id)); @@ -169,7 +143,7 @@ class WvmMediaParserTest : public testing::Test { TEST_F(WvmMediaParserTest, ParseWvm) { EXPECT_CALL(*key_source_, FetchKeys(_)).WillOnce(Return(Status::OK)); - EXPECT_CALL(*key_source_, GetKey(_,_)) + EXPECT_CALL(*key_source_, GetKey(_, _)) .WillOnce(DoAll(SetArgPointee<1>(encryption_key_), Return(Status::OK))); Parse(kWvmFile); EXPECT_EQ(kExpectedStreams, stream_map_.size());