Make RequestSigner optional for WidevineKeySource

Change-Id: I4298d5c5ba1d8539c5cd28130266b1a988308f0b
This commit is contained in:
KongQun Yang 2014-10-10 15:36:40 -07:00
parent 7e9515c349
commit e72d12c54f
4 changed files with 48 additions and 97 deletions

View File

@ -136,11 +136,9 @@ class WidevineKeySource::RefCountedEncryptionKeyMap
DISALLOW_COPY_AND_ASSIGN(RefCountedEncryptionKeyMap); DISALLOW_COPY_AND_ASSIGN(RefCountedEncryptionKeyMap);
}; };
WidevineKeySource::WidevineKeySource( WidevineKeySource::WidevineKeySource(const std::string& server_url,
const std::string& server_url,
scoped_ptr<RequestSigner> signer) scoped_ptr<RequestSigner> signer)
: key_production_thread_( : key_production_thread_("KeyProductionThread",
"KeyProductionThread",
base::Bind(&WidevineKeySource::FetchKeysTask, base::Bind(&WidevineKeySource::FetchKeysTask,
base::Unretained(this))), base::Unretained(this))),
key_fetcher_(new HttpKeyFetcher(kKeyFetchTimeoutInSeconds)), key_fetcher_(new HttpKeyFetcher(kKeyFetchTimeoutInSeconds)),
@ -150,7 +148,6 @@ WidevineKeySource::WidevineKeySource(
key_production_started_(false), key_production_started_(false),
start_key_production_(false, false), start_key_production_(false, false),
first_crypto_period_index_(0) { first_crypto_period_index_(0) {
DCHECK(signer_);
} }
WidevineKeySource::~WidevineKeySource() { WidevineKeySource::~WidevineKeySource() {
@ -313,7 +310,7 @@ Status WidevineKeySource::FetchKeysInternal(bool enable_key_rotation,
&request); &request);
std::string message; std::string message;
Status status = SignRequest(request, &message); Status status = GenerateKeyMessage(request, &message);
if (!status.ok()) if (!status.ok())
return status; return status;
VLOG(1) << "Message: " << message; VLOG(1) << "Message: " << message;
@ -397,28 +394,30 @@ void WidevineKeySource::FillRequest(bool enable_key_rotation,
base::JSONWriter::Write(&request_dict_, request); base::JSONWriter::Write(&request_dict_, request);
} }
Status WidevineKeySource::SignRequest(const std::string& request, Status WidevineKeySource::GenerateKeyMessage(const std::string& request,
std::string* signed_request) { std::string* message) {
DCHECK(signed_request); DCHECK(message);
std::string request_base64_string;
base::Base64Encode(request, &request_base64_string);
base::DictionaryValue request_dict;
request_dict.SetString("request", request_base64_string);
// Sign the request. // Sign the request.
if (signer_) {
std::string signature; std::string signature;
if (!signer_->GenerateSignature(request, &signature)) if (!signer_->GenerateSignature(request, &signature))
return Status(error::INTERNAL_ERROR, "Signature generation failed."); 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; std::string signature_base64_string;
base::Base64Encode(signature, &signature_base64_string); base::Base64Encode(signature, &signature_base64_string);
base::DictionaryValue signed_request_dict; request_dict.SetString("signature", signature_base64_string);
signed_request_dict.SetString("request", request_base64_string); request_dict.SetString("signer", signer_->signer_name());
signed_request_dict.SetString("signature", signature_base64_string); }
signed_request_dict.SetString("signer", signer_->signer_name());
base::JSONWriter::Write(&signed_request_dict, signed_request); base::JSONWriter::Write(&request_dict, message);
return Status::OK; return Status::OK;
} }

View File

@ -26,7 +26,7 @@ template <class T> class ProducerConsumerQueue;
class WidevineKeySource : public KeySource { class WidevineKeySource : public KeySource {
public: public:
/// @param server_url is the Widevine common encryption server url. /// @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, WidevineKeySource(const std::string& server_url,
scoped_ptr<RequestSigner> signer); scoped_ptr<RequestSigner> signer);
@ -81,9 +81,9 @@ class WidevineKeySource : public KeySource {
void FillRequest(bool enable_key_rotation, void FillRequest(bool enable_key_rotation,
uint32_t first_crypto_period_index, uint32_t first_crypto_period_index,
std::string* request); std::string* request);
// Sign and properly format |request|. // Base64 escape and format the request. Optionally sign the request if a
// |signed_request| should not be NULL. Return OK on success. // signer is provided. |message| should not be NULL. Return OK on success.
Status SignRequest(const std::string& request, std::string* signed_request); Status GenerateKeyMessage(const std::string& request, std::string* message);
// Decode |response| from JSON formatted |raw_response|. // Decode |response| from JSON formatted |raw_response|.
// |response| should not be NULL. // |response| should not be NULL.
bool DecodeResponse(const std::string& raw_response, std::string* response); bool DecodeResponse(const std::string& raw_response, std::string* response);

View File

@ -156,10 +156,9 @@ class WidevineKeySourceTest : public ::testing::Test {
} }
protected: protected:
void CreateWidevineKeySource() { void CreateWidevineKeySource(scoped_ptr<RequestSigner> request_signer) {
widevine_key_source_.reset(new WidevineKeySource( widevine_key_source_.reset(
kServerUrl, new WidevineKeySource(kServerUrl, request_signer.Pass()));
mock_request_signer_.PassAs<RequestSigner>()));
widevine_key_source_->set_key_fetcher( widevine_key_source_->set_key_fetcher(
mock_key_fetcher_.PassAs<KeyFetcher>()); mock_key_fetcher_.PassAs<KeyFetcher>());
} }
@ -204,7 +203,7 @@ TEST_F(WidevineKeySourceTest, GenerateSignatureFailure) {
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _)) EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
.WillOnce(Return(false)); .WillOnce(Return(false));
CreateWidevineKeySource(); CreateWidevineKeySource(mock_request_signer_.PassAs<RequestSigner>());
ASSERT_EQ(Status(error::INTERNAL_ERROR, "Signature generation failed."), ASSERT_EQ(Status(error::INTERNAL_ERROR, "Signature generation failed."),
widevine_key_source_->FetchKeys(content_id_, kPolicy)); widevine_key_source_->FetchKeys(content_id_, kPolicy));
} }
@ -227,30 +226,24 @@ TEST_F(WidevineKeySourceTest, HttpFetchFailure) {
FetchKeys(StrEq(kServerUrl), expected_post_data, _)) FetchKeys(StrEq(kServerUrl), expected_post_data, _))
.WillOnce(Return(kMockStatus)); .WillOnce(Return(kMockStatus));
CreateWidevineKeySource(); CreateWidevineKeySource(mock_request_signer_.PassAs<RequestSigner>());
ASSERT_EQ(kMockStatus, ASSERT_EQ(kMockStatus,
widevine_key_source_->FetchKeys(content_id_, kPolicy)); widevine_key_source_->FetchKeys(content_id_, kPolicy));
} }
TEST_F(WidevineKeySourceTest, LicenseStatusCencOK) { TEST_F(WidevineKeySourceTest, LicenseStatusCencOK) {
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
.WillOnce(Return(true));
std::string mock_response = base::StringPrintf( std::string mock_response = base::StringPrintf(
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str()); kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _)) EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _))
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
CreateWidevineKeySource(); CreateWidevineKeySource(scoped_ptr<RequestSigner>());
ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy)); ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
VerifyKeys(false); VerifyKeys(false);
} }
TEST_F(WidevineKeySourceTest, LicenseStatusCencNotOK) { TEST_F(WidevineKeySourceTest, LicenseStatusCencNotOK) {
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
.WillOnce(Return(true));
std::string mock_response = base::StringPrintf( std::string mock_response = base::StringPrintf(
kHttpResponseFormat, Base64Encode( kHttpResponseFormat, Base64Encode(
GenerateMockClassicLicenseResponse()).c_str()); GenerateMockClassicLicenseResponse()).c_str());
@ -258,23 +251,20 @@ TEST_F(WidevineKeySourceTest, LicenseStatusCencNotOK) {
EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _)) EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _))
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
CreateWidevineKeySource(); CreateWidevineKeySource(scoped_ptr<RequestSigner>());
ASSERT_EQ(error::SERVER_ERROR, ASSERT_EQ(error::SERVER_ERROR,
widevine_key_source_->FetchKeys(content_id_, kPolicy) widevine_key_source_->FetchKeys(content_id_, kPolicy)
.error_code()); .error_code());
} }
TEST_F(WidevineKeySourceTest, LicenseStatusCencWithPsshDataOK) { TEST_F(WidevineKeySourceTest, LicenseStatusCencWithPsshDataOK) {
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
.WillOnce(Return(true));
std::string mock_response = base::StringPrintf( std::string mock_response = base::StringPrintf(
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str()); kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _)) EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _))
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
CreateWidevineKeySource(); CreateWidevineKeySource(scoped_ptr<RequestSigner>());
std::vector<uint8_t> pssh_data( std::vector<uint8_t> pssh_data(
reinterpret_cast<const uint8_t*>(kRequestPsshData), reinterpret_cast<const uint8_t*>(kRequestPsshData),
reinterpret_cast<const uint8_t*>(kRequestPsshData) + strlen(kContentId)); reinterpret_cast<const uint8_t*>(kRequestPsshData) + strlen(kContentId));
@ -283,9 +273,6 @@ TEST_F(WidevineKeySourceTest, LicenseStatusCencWithPsshDataOK) {
} }
TEST_F(WidevineKeySourceTest, LicenseStatusClassicOK) { TEST_F(WidevineKeySourceTest, LicenseStatusClassicOK) {
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
.WillOnce(Return(true));
std::string mock_response = base::StringPrintf( std::string mock_response = base::StringPrintf(
kHttpResponseFormat, Base64Encode( kHttpResponseFormat, Base64Encode(
GenerateMockClassicLicenseResponse()).c_str()); GenerateMockClassicLicenseResponse()).c_str());
@ -293,15 +280,12 @@ TEST_F(WidevineKeySourceTest, LicenseStatusClassicOK) {
EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _)) EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _))
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
CreateWidevineKeySource(); CreateWidevineKeySource(scoped_ptr<RequestSigner>());
ASSERT_OK(widevine_key_source_->FetchKeys(kClassicAssetId)); ASSERT_OK(widevine_key_source_->FetchKeys(kClassicAssetId));
VerifyKeys(true); VerifyKeys(true);
} }
TEST_F(WidevineKeySourceTest, RetryOnHttpTimeout) { TEST_F(WidevineKeySourceTest, RetryOnHttpTimeout) {
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
.WillOnce(Return(true));
std::string mock_response = base::StringPrintf( std::string mock_response = base::StringPrintf(
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str()); kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
@ -310,15 +294,12 @@ TEST_F(WidevineKeySourceTest, RetryOnHttpTimeout) {
.WillOnce(Return(Status(error::TIME_OUT, ""))) .WillOnce(Return(Status(error::TIME_OUT, "")))
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
CreateWidevineKeySource(); CreateWidevineKeySource(scoped_ptr<RequestSigner>());
ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy)); ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
VerifyKeys(false); VerifyKeys(false);
} }
TEST_F(WidevineKeySourceTest, RetryOnTransientError) { TEST_F(WidevineKeySourceTest, RetryOnTransientError) {
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
.WillOnce(Return(true));
std::string mock_license_status = base::StringPrintf( std::string mock_license_status = base::StringPrintf(
kLicenseResponseFormat, kLicenseStatusTransientError, ""); kLicenseResponseFormat, kLicenseStatusTransientError, "");
std::string mock_response = base::StringPrintf( std::string mock_response = base::StringPrintf(
@ -333,15 +314,12 @@ TEST_F(WidevineKeySourceTest, RetryOnTransientError) {
.WillOnce(DoAll(SetArgPointee<2>(expected_retried_response), .WillOnce(DoAll(SetArgPointee<2>(expected_retried_response),
Return(Status::OK))); Return(Status::OK)));
CreateWidevineKeySource(); CreateWidevineKeySource(scoped_ptr<RequestSigner>());
ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy)); ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
VerifyKeys(false); VerifyKeys(false);
} }
TEST_F(WidevineKeySourceTest, NoRetryOnUnknownError) { TEST_F(WidevineKeySourceTest, NoRetryOnUnknownError) {
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
.WillOnce(Return(true));
std::string mock_license_status = base::StringPrintf( std::string mock_license_status = base::StringPrintf(
kLicenseResponseFormat, kLicenseStatusUnknownError, ""); kLicenseResponseFormat, kLicenseStatusUnknownError, "");
std::string mock_response = base::StringPrintf( std::string mock_response = base::StringPrintf(
@ -350,7 +328,7 @@ TEST_F(WidevineKeySourceTest, NoRetryOnUnknownError) {
EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _)) EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _))
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
CreateWidevineKeySource(); CreateWidevineKeySource(scoped_ptr<RequestSigner>());
ASSERT_EQ(error::SERVER_ERROR, ASSERT_EQ(error::SERVER_ERROR,
widevine_key_source_->FetchKeys(content_id_, kPolicy).error_code()); 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))); .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
} }
CreateWidevineKeySource(); CreateWidevineKeySource(mock_request_signer_.PassAs<RequestSigner>());
ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy)); ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
EncryptionKey encryption_key; EncryptionKey encryption_key;

View File

@ -17,7 +17,7 @@
#include "packager/media/base/stream_info.h" #include "packager/media/base/stream_info.h"
#include "packager/media/base/timestamp.h" #include "packager/media/base/timestamp.h"
#include "packager/media/base/video_stream_info.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/formats/wvm/wvm_media_parser.h"
#include "packager/media/test/test_data_util.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 uint32_t kExpectedStreams = 4;
const int kExpectedVideoFrameCount = 6665; const int kExpectedVideoFrameCount = 6665;
const int kExpectedAudioFrameCount = 11964; const int kExpectedAudioFrameCount = 11964;
const char kServerUrl[] = "fake_server_url"; const uint8_t kExpectedAssetKey[] =
const char kSigner[] = "fake_signer"; "\x06\x81\x7f\x48\x6b\xf2\x7f\x3e\xc7\x39\xa8\x3f\x12\x0a\xd2\xfc";
const uint8 kExpectedAssetKey[16] = {'\006', static_cast<uint8>('\201'), '\177',
'H', 'k', static_cast<uint8>('\362'), '\177', '>', static_cast<uint8>('\307'),
'9', static_cast<uint8>('\250'), '?', '\022', '\n',
static_cast<uint8>('\322'), static_cast<uint8>('\374')};
} // namespace } // namespace
using ::testing::_; using ::testing::_;
using ::testing::DoAll; using ::testing::DoAll;
using ::testing::InSequence;
using ::testing::Return; using ::testing::Return;
using ::testing::SetArgPointee; using ::testing::SetArgPointee;
namespace edash_packager { namespace edash_packager {
namespace media { namespace media {
class FakeRequestSigner : public RequestSigner { class MockKeySource : public KeySource {
public: public:
FakeRequestSigner() : RequestSigner(kSigner) {} MockKeySource() {}
virtual ~FakeRequestSigner() {}
virtual bool GenerateSignature(const std::string& message,
std::string* signature) OVERRIDE {
return true;
}
private:
DISALLOW_COPY_AND_ASSIGN(FakeRequestSigner);
};
scoped_ptr<FakeRequestSigner> kFakeRequestSigner(new FakeRequestSigner());
class MockKeySource : public WidevineKeySource {
public:
MockKeySource() : WidevineKeySource(
kServerUrl, kFakeRequestSigner.PassAs<RequestSigner>()) {
// KeyProduction thread started in test because FetchKeys()
// is mocked. ~ClosureThread expects to terminate this thread.
key_production_thread_.Start();
}
virtual ~MockKeySource() {} virtual ~MockKeySource() {}
MOCK_METHOD1(FetchKeys, Status(uint32_t asset_id)); MOCK_METHOD1(FetchKeys, Status(uint32_t asset_id));