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,13 +136,11 @@ class WidevineKeySource::RefCountedEncryptionKeyMap
DISALLOW_COPY_AND_ASSIGN(RefCountedEncryptionKeyMap);
};
WidevineKeySource::WidevineKeySource(
const std::string& server_url,
scoped_ptr<RequestSigner> signer)
: key_production_thread_(
"KeyProductionThread",
base::Bind(&WidevineKeySource::FetchKeysTask,
base::Unretained(this))),
WidevineKeySource::WidevineKeySource(const std::string& server_url,
scoped_ptr<RequestSigner> 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;
}

View File

@ -26,7 +26,7 @@ template <class T> 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<RequestSigner> 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);

View File

@ -156,10 +156,9 @@ class WidevineKeySourceTest : public ::testing::Test {
}
protected:
void CreateWidevineKeySource() {
widevine_key_source_.reset(new WidevineKeySource(
kServerUrl,
mock_request_signer_.PassAs<RequestSigner>()));
void CreateWidevineKeySource(scoped_ptr<RequestSigner> request_signer) {
widevine_key_source_.reset(
new WidevineKeySource(kServerUrl, request_signer.Pass()));
widevine_key_source_->set_key_fetcher(
mock_key_fetcher_.PassAs<KeyFetcher>());
}
@ -204,7 +203,7 @@ TEST_F(WidevineKeySourceTest, GenerateSignatureFailure) {
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
.WillOnce(Return(false));
CreateWidevineKeySource();
CreateWidevineKeySource(mock_request_signer_.PassAs<RequestSigner>());
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<RequestSigner>());
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<RequestSigner>());
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<RequestSigner>());
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<RequestSigner>());
std::vector<uint8_t> pssh_data(
reinterpret_cast<const uint8_t*>(kRequestPsshData),
reinterpret_cast<const uint8_t*>(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<RequestSigner>());
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<RequestSigner>());
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<RequestSigner>());
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<RequestSigner>());
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<RequestSigner>());
ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
EncryptionKey encryption_key;

View File

@ -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<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
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<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();
}
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());