Key Rotation: Get the initial crypto index from first request
This change also updates the WidevineEncryptionKeySource to be able to support KeyRotation enabled and disabled requests simultaneously. Change-Id: I5178cafc0dbabbb64ac9af9969d3bf7d8117a4dd
This commit is contained in:
parent
33a87aa84b
commit
f609b2947c
|
@ -70,8 +70,7 @@ scoped_ptr<EncryptionKeySource> CreateEncryptionKeySource() {
|
||||||
FLAGS_key_server_url,
|
FLAGS_key_server_url,
|
||||||
FLAGS_content_id,
|
FLAGS_content_id,
|
||||||
FLAGS_policy,
|
FLAGS_policy,
|
||||||
signer.Pass(),
|
signer.Pass()));
|
||||||
FLAGS_crypto_period_duration == 0 ? kDisableKeyRotation : 0));
|
|
||||||
Status status = widevine_encryption_key_source->Initialize();
|
Status status = widevine_encryption_key_source->Initialize();
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
LOG(ERROR) << "Widevine encryption key source failed to initialize: "
|
LOG(ERROR) << "Widevine encryption key source failed to initialize: "
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "base/stl_util.h"
|
#include "base/stl_util.h"
|
||||||
#include "base/values.h"
|
#include "base/values.h"
|
||||||
#include "media/base/http_fetcher.h"
|
#include "media/base/http_fetcher.h"
|
||||||
|
#include "media/base/producer_consumer_queue.h"
|
||||||
#include "media/base/request_signer.h"
|
#include "media/base/request_signer.h"
|
||||||
|
|
||||||
#define RCHECK(x) \
|
#define RCHECK(x) \
|
||||||
|
@ -26,6 +27,8 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
const bool kEnableKeyRotation = true;
|
||||||
|
|
||||||
const char kLicenseStatusOK[] = "OK";
|
const char kLicenseStatusOK[] = "OK";
|
||||||
// Server may return INTERNAL_ERROR intermittently, which is a transient error
|
// Server may return INTERNAL_ERROR intermittently, which is a transient error
|
||||||
// and the next client request may succeed without problem.
|
// and the next client request may succeed without problem.
|
||||||
|
@ -128,50 +131,52 @@ WidevineEncryptionKeySource::WidevineEncryptionKeySource(
|
||||||
const std::string& server_url,
|
const std::string& server_url,
|
||||||
const std::string& content_id,
|
const std::string& content_id,
|
||||||
const std::string& policy,
|
const std::string& policy,
|
||||||
scoped_ptr<RequestSigner> signer,
|
scoped_ptr<RequestSigner> signer)
|
||||||
int first_crypto_period_index)
|
|
||||||
: http_fetcher_(new SimpleHttpFetcher(kHttpTimeoutInSeconds)),
|
: http_fetcher_(new SimpleHttpFetcher(kHttpTimeoutInSeconds)),
|
||||||
server_url_(server_url),
|
server_url_(server_url),
|
||||||
content_id_(content_id),
|
content_id_(content_id),
|
||||||
policy_(policy),
|
policy_(policy),
|
||||||
signer_(signer.Pass()),
|
signer_(signer.Pass()),
|
||||||
key_rotation_enabled_(first_crypto_period_index >= 0),
|
|
||||||
crypto_period_count_(kDefaultCryptoPeriodCount),
|
crypto_period_count_(kDefaultCryptoPeriodCount),
|
||||||
first_crypto_period_index_(first_crypto_period_index),
|
key_production_started_(false),
|
||||||
|
start_key_production_(false, false),
|
||||||
|
first_crypto_period_index_(0),
|
||||||
key_production_thread_(
|
key_production_thread_(
|
||||||
"KeyProductionThread",
|
"KeyProductionThread",
|
||||||
base::Bind(&WidevineEncryptionKeySource::FetchKeysTask,
|
base::Bind(&WidevineEncryptionKeySource::FetchKeysTask,
|
||||||
base::Unretained(this))),
|
base::Unretained(this))) {
|
||||||
key_pool_(kDefaultCryptoPeriodCount,
|
|
||||||
key_rotation_enabled_ ? first_crypto_period_index : 0) {
|
|
||||||
DCHECK(signer_);
|
DCHECK(signer_);
|
||||||
}
|
}
|
||||||
|
|
||||||
WidevineEncryptionKeySource::~WidevineEncryptionKeySource() {
|
WidevineEncryptionKeySource::~WidevineEncryptionKeySource() {
|
||||||
key_pool_.Stop();
|
if (key_pool_)
|
||||||
if (key_production_thread_.HasBeenStarted())
|
key_pool_->Stop();
|
||||||
|
if (key_production_thread_.HasBeenStarted()) {
|
||||||
|
// Signal the production thread to start key production if it is not
|
||||||
|
// signaled yet so the thread can be joined.
|
||||||
|
start_key_production_.Signal();
|
||||||
key_production_thread_.Join();
|
key_production_thread_.Join();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Status WidevineEncryptionKeySource::Initialize() {
|
Status WidevineEncryptionKeySource::Initialize() {
|
||||||
// |first_crypto_period_index| might be updated after starting production.
|
|
||||||
// Make a local copy for prime later.
|
|
||||||
const uint32 first_crypto_period_index = first_crypto_period_index_;
|
|
||||||
DCHECK(!key_production_thread_.HasBeenStarted());
|
DCHECK(!key_production_thread_.HasBeenStarted());
|
||||||
key_production_thread_.Start();
|
key_production_thread_.Start();
|
||||||
|
|
||||||
// Perform a GetKey request to find out common encryption request status.
|
// Perform a fetch request to find out if the key source is healthy.
|
||||||
// It also primes the key_pool if successful.
|
// It also stores the keys fetched for consumption later.
|
||||||
return key_rotation_enabled_ ? GetCryptoPeriodKey(first_crypto_period_index,
|
return FetchKeys(!kEnableKeyRotation, 0);
|
||||||
TRACK_TYPE_SD, NULL)
|
|
||||||
: GetKey(TRACK_TYPE_SD, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Status WidevineEncryptionKeySource::GetKey(TrackType track_type,
|
Status WidevineEncryptionKeySource::GetKey(TrackType track_type,
|
||||||
EncryptionKey* key) {
|
EncryptionKey* key) {
|
||||||
DCHECK(key_production_thread_.HasBeenStarted());
|
DCHECK(key);
|
||||||
DCHECK(!key_rotation_enabled_);
|
if (encryption_key_map_.find(track_type) == encryption_key_map_.end()) {
|
||||||
return GetKeyInternal(0u, track_type, key);
|
return Status(error::INTERNAL_ERROR,
|
||||||
|
"Cannot find key of type " + TrackTypeToString(track_type));
|
||||||
|
}
|
||||||
|
*key = *encryption_key_map_[track_type];
|
||||||
|
return Status::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status WidevineEncryptionKeySource::GetCryptoPeriodKey(
|
Status WidevineEncryptionKeySource::GetCryptoPeriodKey(
|
||||||
|
@ -179,7 +184,20 @@ Status WidevineEncryptionKeySource::GetCryptoPeriodKey(
|
||||||
TrackType track_type,
|
TrackType track_type,
|
||||||
EncryptionKey* key) {
|
EncryptionKey* key) {
|
||||||
DCHECK(key_production_thread_.HasBeenStarted());
|
DCHECK(key_production_thread_.HasBeenStarted());
|
||||||
DCHECK(key_rotation_enabled_);
|
// TODO(kqyang): This is not elegant. Consider refactoring later.
|
||||||
|
{
|
||||||
|
base::AutoLock scoped_lock(lock_);
|
||||||
|
if (!key_production_started_) {
|
||||||
|
// Another client may have a slightly smaller starting crypto period
|
||||||
|
// index. Set the initial value to account for that.
|
||||||
|
first_crypto_period_index_ = crypto_period_index ? crypto_period_index - 1 : 0;
|
||||||
|
DCHECK(!key_pool_);
|
||||||
|
key_pool_.reset(new EncryptionKeyQueue(crypto_period_count_,
|
||||||
|
first_crypto_period_index_));
|
||||||
|
start_key_production_.Signal();
|
||||||
|
key_production_started_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return GetKeyInternal(crypto_period_index, track_type, key);
|
return GetKeyInternal(crypto_period_index, track_type, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,12 +210,14 @@ Status WidevineEncryptionKeySource::GetKeyInternal(
|
||||||
uint32 crypto_period_index,
|
uint32 crypto_period_index,
|
||||||
TrackType track_type,
|
TrackType track_type,
|
||||||
EncryptionKey* key) {
|
EncryptionKey* key) {
|
||||||
|
DCHECK(key_pool_);
|
||||||
|
DCHECK(key);
|
||||||
DCHECK_LE(track_type, NUM_VALID_TRACK_TYPES);
|
DCHECK_LE(track_type, NUM_VALID_TRACK_TYPES);
|
||||||
DCHECK_NE(track_type, TRACK_TYPE_UNKNOWN);
|
DCHECK_NE(track_type, TRACK_TYPE_UNKNOWN);
|
||||||
|
|
||||||
scoped_refptr<RefCountedEncryptionKeyMap> ref_counted_encryption_key_map;
|
scoped_refptr<RefCountedEncryptionKeyMap> ref_counted_encryption_key_map;
|
||||||
Status status = key_pool_.Peek(crypto_period_index,
|
Status status =
|
||||||
&ref_counted_encryption_key_map,
|
key_pool_->Peek(crypto_period_index, &ref_counted_encryption_key_map,
|
||||||
kGetKeyTimeoutInSeconds * 1000);
|
kGetKeyTimeoutInSeconds * 1000);
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
if (status.error_code() == error::STOPPED) {
|
if (status.error_code() == error::STOPPED) {
|
||||||
|
@ -212,27 +232,30 @@ Status WidevineEncryptionKeySource::GetKeyInternal(
|
||||||
return Status(error::INTERNAL_ERROR,
|
return Status(error::INTERNAL_ERROR,
|
||||||
"Cannot find key of type " + TrackTypeToString(track_type));
|
"Cannot find key of type " + TrackTypeToString(track_type));
|
||||||
}
|
}
|
||||||
if (key)
|
|
||||||
*key = *encryption_key_map[track_type];
|
*key = *encryption_key_map[track_type];
|
||||||
return Status::OK;
|
return Status::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WidevineEncryptionKeySource::FetchKeysTask() {
|
void WidevineEncryptionKeySource::FetchKeysTask() {
|
||||||
Status status = FetchKeys(first_crypto_period_index_);
|
// Wait until key production is signaled.
|
||||||
if (key_rotation_enabled_) {
|
start_key_production_.Wait();
|
||||||
|
if (!key_pool_ || key_pool_->Stopped())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Status status = FetchKeys(kEnableKeyRotation, first_crypto_period_index_);
|
||||||
while (status.ok()) {
|
while (status.ok()) {
|
||||||
first_crypto_period_index_ += crypto_period_count_;
|
first_crypto_period_index_ += crypto_period_count_;
|
||||||
status = FetchKeys(first_crypto_period_index_);
|
status = FetchKeys(kEnableKeyRotation, first_crypto_period_index_);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
common_encryption_request_status_ = status;
|
common_encryption_request_status_ = status;
|
||||||
key_pool_.Stop();
|
key_pool_->Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
Status WidevineEncryptionKeySource::FetchKeys(
|
Status WidevineEncryptionKeySource::FetchKeys(
|
||||||
uint32 first_crypto_period_index) {
|
bool enable_key_rotation, uint32 first_crypto_period_index) {
|
||||||
std::string request;
|
std::string request;
|
||||||
FillRequest(content_id_, first_crypto_period_index, &request);
|
FillRequest(content_id_, enable_key_rotation, first_crypto_period_index,
|
||||||
|
&request);
|
||||||
|
|
||||||
std::string message;
|
std::string message;
|
||||||
Status status = SignRequest(request, &message);
|
Status status = SignRequest(request, &message);
|
||||||
|
@ -257,7 +280,7 @@ Status WidevineEncryptionKeySource::FetchKeys(
|
||||||
}
|
}
|
||||||
|
|
||||||
bool transient_error = false;
|
bool transient_error = false;
|
||||||
if (ExtractEncryptionKey(response, &transient_error))
|
if (ExtractEncryptionKey(enable_key_rotation, response, &transient_error))
|
||||||
return Status::OK;
|
return Status::OK;
|
||||||
|
|
||||||
if (!transient_error) {
|
if (!transient_error) {
|
||||||
|
@ -281,6 +304,7 @@ Status WidevineEncryptionKeySource::FetchKeys(
|
||||||
}
|
}
|
||||||
|
|
||||||
void WidevineEncryptionKeySource::FillRequest(const std::string& content_id,
|
void WidevineEncryptionKeySource::FillRequest(const std::string& content_id,
|
||||||
|
bool enable_key_rotation,
|
||||||
uint32 first_crypto_period_index,
|
uint32 first_crypto_period_index,
|
||||||
std::string* request) {
|
std::string* request) {
|
||||||
DCHECK(request);
|
DCHECK(request);
|
||||||
|
@ -313,7 +337,7 @@ void WidevineEncryptionKeySource::FillRequest(const std::string& content_id,
|
||||||
request_dict.Set("drm_types", drm_types);
|
request_dict.Set("drm_types", drm_types);
|
||||||
|
|
||||||
// Build key rotation fields.
|
// Build key rotation fields.
|
||||||
if (key_rotation_enabled_) {
|
if (enable_key_rotation) {
|
||||||
request_dict.SetInteger("first_crypto_period_index",
|
request_dict.SetInteger("first_crypto_period_index",
|
||||||
first_crypto_period_index);
|
first_crypto_period_index);
|
||||||
request_dict.SetInteger("crypto_period_count", crypto_period_count_);
|
request_dict.SetInteger("crypto_period_count", crypto_period_count_);
|
||||||
|
@ -368,6 +392,7 @@ bool WidevineEncryptionKeySource::DecodeResponse(
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WidevineEncryptionKeySource::ExtractEncryptionKey(
|
bool WidevineEncryptionKeySource::ExtractEncryptionKey(
|
||||||
|
bool enable_key_rotation,
|
||||||
const std::string& response,
|
const std::string& response,
|
||||||
bool* transient_error) {
|
bool* transient_error) {
|
||||||
DCHECK(transient_error);
|
DCHECK(transient_error);
|
||||||
|
@ -392,7 +417,7 @@ bool WidevineEncryptionKeySource::ExtractEncryptionKey(
|
||||||
|
|
||||||
const base::ListValue* tracks;
|
const base::ListValue* tracks;
|
||||||
RCHECK(license_dict->GetList("tracks", &tracks));
|
RCHECK(license_dict->GetList("tracks", &tracks));
|
||||||
RCHECK(key_rotation_enabled_
|
RCHECK(enable_key_rotation
|
||||||
? tracks->GetSize() >= NUM_VALID_TRACK_TYPES * crypto_period_count_
|
? tracks->GetSize() >= NUM_VALID_TRACK_TYPES * crypto_period_count_
|
||||||
: tracks->GetSize() >= NUM_VALID_TRACK_TYPES);
|
: tracks->GetSize() >= NUM_VALID_TRACK_TYPES);
|
||||||
|
|
||||||
|
@ -403,7 +428,7 @@ bool WidevineEncryptionKeySource::ExtractEncryptionKey(
|
||||||
const base::DictionaryValue* track_dict;
|
const base::DictionaryValue* track_dict;
|
||||||
RCHECK(tracks->GetDictionary(i, &track_dict));
|
RCHECK(tracks->GetDictionary(i, &track_dict));
|
||||||
|
|
||||||
if (key_rotation_enabled_) {
|
if (enable_key_rotation) {
|
||||||
int crypto_period_index;
|
int crypto_period_index;
|
||||||
RCHECK(
|
RCHECK(
|
||||||
track_dict->GetInteger("crypto_period_index", &crypto_period_index));
|
track_dict->GetInteger("crypto_period_index", &crypto_period_index));
|
||||||
|
@ -438,14 +463,19 @@ bool WidevineEncryptionKeySource::ExtractEncryptionKey(
|
||||||
}
|
}
|
||||||
|
|
||||||
DCHECK(!encryption_key_map.empty());
|
DCHECK(!encryption_key_map.empty());
|
||||||
|
if (!enable_key_rotation) {
|
||||||
|
encryption_key_map_ = encryption_key_map;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return PushToKeyPool(&encryption_key_map);
|
return PushToKeyPool(&encryption_key_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WidevineEncryptionKeySource::PushToKeyPool(
|
bool WidevineEncryptionKeySource::PushToKeyPool(
|
||||||
EncryptionKeyMap* encryption_key_map) {
|
EncryptionKeyMap* encryption_key_map) {
|
||||||
|
DCHECK(key_pool_);
|
||||||
DCHECK(encryption_key_map);
|
DCHECK(encryption_key_map);
|
||||||
Status status =
|
Status status =
|
||||||
key_pool_.Push(scoped_refptr<RefCountedEncryptionKeyMap>(
|
key_pool_->Push(scoped_refptr<RefCountedEncryptionKeyMap>(
|
||||||
new RefCountedEncryptionKeyMap(encryption_key_map)),
|
new RefCountedEncryptionKeyMap(encryption_key_map)),
|
||||||
kInfiniteTimeout);
|
kInfiniteTimeout);
|
||||||
encryption_key_map->clear();
|
encryption_key_map->clear();
|
||||||
|
|
|
@ -11,16 +11,14 @@
|
||||||
|
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
#include "base/memory/scoped_ptr.h"
|
#include "base/memory/scoped_ptr.h"
|
||||||
|
#include "base/synchronization/waitable_event.h"
|
||||||
#include "media/base/closure_thread.h"
|
#include "media/base/closure_thread.h"
|
||||||
#include "media/base/encryption_key_source.h"
|
#include "media/base/encryption_key_source.h"
|
||||||
#include "media/base/producer_consumer_queue.h"
|
|
||||||
|
|
||||||
namespace media {
|
namespace media {
|
||||||
/// A negative crypto period index disables key rotation.
|
|
||||||
static const int kDisableKeyRotation = -1;
|
|
||||||
|
|
||||||
class HttpFetcher;
|
class HttpFetcher;
|
||||||
class RequestSigner;
|
class RequestSigner;
|
||||||
|
template <class T> class ProducerConsumerQueue;
|
||||||
|
|
||||||
/// WidevineEncryptionKeySource talks to the Widevine encryption service to
|
/// WidevineEncryptionKeySource talks to the Widevine encryption service to
|
||||||
/// acquire the encryption keys.
|
/// acquire the encryption keys.
|
||||||
|
@ -30,13 +28,10 @@ class WidevineEncryptionKeySource : public EncryptionKeySource {
|
||||||
/// @param content_id the unique id identify the content to be encrypted.
|
/// @param content_id the unique id identify the content to be encrypted.
|
||||||
/// @param policy specifies the DRM content rights.
|
/// @param policy specifies the DRM content rights.
|
||||||
/// @param signer signs the request message. It should not be NULL.
|
/// @param signer signs the request message. It should not be NULL.
|
||||||
/// @param first_crypto_period_index indicates the starting crypto period
|
|
||||||
/// index. Set it to kDisableKeyRotation to disable key rotation.
|
|
||||||
WidevineEncryptionKeySource(const std::string& server_url,
|
WidevineEncryptionKeySource(const std::string& server_url,
|
||||||
const std::string& content_id,
|
const std::string& content_id,
|
||||||
const std::string& policy,
|
const std::string& policy,
|
||||||
scoped_ptr<RequestSigner> signer,
|
scoped_ptr<RequestSigner> signer);
|
||||||
int first_crypto_period_index);
|
|
||||||
virtual ~WidevineEncryptionKeySource();
|
virtual ~WidevineEncryptionKeySource();
|
||||||
|
|
||||||
/// Initialize the key source. Must be called before calling GetKey or
|
/// Initialize the key source. Must be called before calling GetKey or
|
||||||
|
@ -59,6 +54,8 @@ class WidevineEncryptionKeySource : public EncryptionKeySource {
|
||||||
private:
|
private:
|
||||||
typedef std::map<TrackType, EncryptionKey*> EncryptionKeyMap;
|
typedef std::map<TrackType, EncryptionKey*> EncryptionKeyMap;
|
||||||
class RefCountedEncryptionKeyMap;
|
class RefCountedEncryptionKeyMap;
|
||||||
|
typedef ProducerConsumerQueue<scoped_refptr<RefCountedEncryptionKeyMap> >
|
||||||
|
EncryptionKeyQueue;
|
||||||
|
|
||||||
// Internal routine for getting keys.
|
// Internal routine for getting keys.
|
||||||
Status GetKeyInternal(uint32 crypto_period_index,
|
Status GetKeyInternal(uint32 crypto_period_index,
|
||||||
|
@ -69,11 +66,12 @@ class WidevineEncryptionKeySource : public EncryptionKeySource {
|
||||||
void FetchKeysTask();
|
void FetchKeysTask();
|
||||||
|
|
||||||
// Fetch keys from server.
|
// Fetch keys from server.
|
||||||
Status FetchKeys(uint32 first_crypto_period_index);
|
Status FetchKeys(bool enable_key_rotation, uint32 first_crypto_period_index);
|
||||||
|
|
||||||
// Fill |request| with necessary fields for Widevine encryption request.
|
// Fill |request| with necessary fields for Widevine encryption request.
|
||||||
// |request| should not be NULL.
|
// |request| should not be NULL.
|
||||||
void FillRequest(const std::string& content_id,
|
void FillRequest(const std::string& content_id,
|
||||||
|
bool enable_key_rotation,
|
||||||
uint32 first_crypto_period_index,
|
uint32 first_crypto_period_index,
|
||||||
std::string* request);
|
std::string* request);
|
||||||
// Sign and properly format |request|.
|
// Sign and properly format |request|.
|
||||||
|
@ -86,7 +84,8 @@ class WidevineEncryptionKeySource : public EncryptionKeySource {
|
||||||
// formatted. |transient_error| will be set to true if it fails and the
|
// formatted. |transient_error| will be set to true if it fails and the
|
||||||
// failure is because of a transient error from the server. |transient_error|
|
// failure is because of a transient error from the server. |transient_error|
|
||||||
// should not be NULL.
|
// should not be NULL.
|
||||||
bool ExtractEncryptionKey(const std::string& response, bool* transient_error);
|
bool ExtractEncryptionKey(bool enable_key_rotation,
|
||||||
|
const std::string& response, bool* transient_error);
|
||||||
// Push the keys to the key pool.
|
// Push the keys to the key pool.
|
||||||
bool PushToKeyPool(EncryptionKeyMap* encryption_key_map);
|
bool PushToKeyPool(EncryptionKeyMap* encryption_key_map);
|
||||||
|
|
||||||
|
@ -99,11 +98,14 @@ class WidevineEncryptionKeySource : public EncryptionKeySource {
|
||||||
std::string policy_;
|
std::string policy_;
|
||||||
scoped_ptr<RequestSigner> signer_;
|
scoped_ptr<RequestSigner> signer_;
|
||||||
|
|
||||||
const bool key_rotation_enabled_;
|
|
||||||
const uint32 crypto_period_count_;
|
const uint32 crypto_period_count_;
|
||||||
|
base::Lock lock_;
|
||||||
|
bool key_production_started_;
|
||||||
|
base::WaitableEvent start_key_production_;
|
||||||
uint32 first_crypto_period_index_;
|
uint32 first_crypto_period_index_;
|
||||||
ClosureThread key_production_thread_;
|
ClosureThread key_production_thread_;
|
||||||
ProducerConsumerQueue<scoped_refptr<RefCountedEncryptionKeyMap> > key_pool_;
|
scoped_ptr<EncryptionKeyQueue> key_pool_;
|
||||||
|
EncryptionKeyMap encryption_key_map_; // For non key rotation request.
|
||||||
Status common_encryption_request_status_;
|
Status common_encryption_request_status_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(WidevineEncryptionKeySource);
|
DISALLOW_COPY_AND_ASSIGN(WidevineEncryptionKeySource);
|
||||||
|
|
|
@ -132,13 +132,12 @@ class WidevineEncryptionKeySourceTest : public ::testing::Test {
|
||||||
mock_http_fetcher_(new MockHttpFetcher()) {}
|
mock_http_fetcher_(new MockHttpFetcher()) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void CreateWidevineEncryptionKeySource(int first_crypto_period_index) {
|
void CreateWidevineEncryptionKeySource() {
|
||||||
widevine_encryption_key_source_.reset(new WidevineEncryptionKeySource(
|
widevine_encryption_key_source_.reset(new WidevineEncryptionKeySource(
|
||||||
kServerUrl,
|
kServerUrl,
|
||||||
kContentId,
|
kContentId,
|
||||||
kPolicy,
|
kPolicy,
|
||||||
mock_request_signer_.PassAs<RequestSigner>(),
|
mock_request_signer_.PassAs<RequestSigner>()));
|
||||||
first_crypto_period_index));
|
|
||||||
widevine_encryption_key_source_->set_http_fetcher(
|
widevine_encryption_key_source_->set_http_fetcher(
|
||||||
mock_http_fetcher_.PassAs<HttpFetcher>());
|
mock_http_fetcher_.PassAs<HttpFetcher>());
|
||||||
}
|
}
|
||||||
|
@ -180,15 +179,9 @@ TEST_F(WidevineEncryptionKeySourceTest, GenerateSignatureFailure) {
|
||||||
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
|
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
|
||||||
.WillOnce(Return(false));
|
.WillOnce(Return(false));
|
||||||
|
|
||||||
CreateWidevineEncryptionKeySource(kDisableKeyRotation);
|
CreateWidevineEncryptionKeySource();
|
||||||
ASSERT_EQ(Status(error::INTERNAL_ERROR, "Signature generation failed."),
|
ASSERT_EQ(Status(error::INTERNAL_ERROR, "Signature generation failed."),
|
||||||
widevine_encryption_key_source_->Initialize());
|
widevine_encryption_key_source_->Initialize());
|
||||||
|
|
||||||
// GetKey should return the same failure.
|
|
||||||
EncryptionKey encryption_key;
|
|
||||||
ASSERT_EQ(Status(error::INTERNAL_ERROR, "Signature generation failed."),
|
|
||||||
widevine_encryption_key_source_->GetKey(
|
|
||||||
EncryptionKeySource::TRACK_TYPE_SD, &encryption_key));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether expected request message and post data was generated and
|
// Check whether expected request message and post data was generated and
|
||||||
|
@ -208,15 +201,9 @@ TEST_F(WidevineEncryptionKeySourceTest, HttpPostFailure) {
|
||||||
EXPECT_CALL(*mock_http_fetcher_, Post(kServerUrl, expected_post_data, _))
|
EXPECT_CALL(*mock_http_fetcher_, Post(kServerUrl, expected_post_data, _))
|
||||||
.WillOnce(Return(kMockStatus));
|
.WillOnce(Return(kMockStatus));
|
||||||
|
|
||||||
CreateWidevineEncryptionKeySource(kDisableKeyRotation);
|
CreateWidevineEncryptionKeySource();
|
||||||
ASSERT_EQ(kMockStatus,
|
ASSERT_EQ(kMockStatus,
|
||||||
widevine_encryption_key_source_->Initialize());
|
widevine_encryption_key_source_->Initialize());
|
||||||
|
|
||||||
// GetKey should return the same failure.
|
|
||||||
EncryptionKey encryption_key;
|
|
||||||
ASSERT_EQ(kMockStatus,
|
|
||||||
widevine_encryption_key_source_->GetKey(
|
|
||||||
EncryptionKeySource::TRACK_TYPE_SD, &encryption_key));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WidevineEncryptionKeySourceTest, LicenseStatusOK) {
|
TEST_F(WidevineEncryptionKeySourceTest, LicenseStatusOK) {
|
||||||
|
@ -229,7 +216,7 @@ TEST_F(WidevineEncryptionKeySourceTest, LicenseStatusOK) {
|
||||||
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
||||||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||||
|
|
||||||
CreateWidevineEncryptionKeySource(kDisableKeyRotation);
|
CreateWidevineEncryptionKeySource();
|
||||||
ASSERT_OK(widevine_encryption_key_source_->Initialize());
|
ASSERT_OK(widevine_encryption_key_source_->Initialize());
|
||||||
VerifyKeys();
|
VerifyKeys();
|
||||||
}
|
}
|
||||||
|
@ -246,7 +233,7 @@ TEST_F(WidevineEncryptionKeySourceTest, 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)));
|
||||||
|
|
||||||
CreateWidevineEncryptionKeySource(kDisableKeyRotation);
|
CreateWidevineEncryptionKeySource();
|
||||||
ASSERT_OK(widevine_encryption_key_source_->Initialize());
|
ASSERT_OK(widevine_encryption_key_source_->Initialize());
|
||||||
VerifyKeys();
|
VerifyKeys();
|
||||||
}
|
}
|
||||||
|
@ -269,7 +256,7 @@ TEST_F(WidevineEncryptionKeySourceTest, RetryOnTransientError) {
|
||||||
.WillOnce(DoAll(SetArgPointee<2>(expected_retried_response),
|
.WillOnce(DoAll(SetArgPointee<2>(expected_retried_response),
|
||||||
Return(Status::OK)));
|
Return(Status::OK)));
|
||||||
|
|
||||||
CreateWidevineEncryptionKeySource(kDisableKeyRotation);
|
CreateWidevineEncryptionKeySource();
|
||||||
ASSERT_OK(widevine_encryption_key_source_->Initialize());
|
ASSERT_OK(widevine_encryption_key_source_->Initialize());
|
||||||
VerifyKeys();
|
VerifyKeys();
|
||||||
}
|
}
|
||||||
|
@ -286,7 +273,7 @@ TEST_F(WidevineEncryptionKeySourceTest, NoRetryOnUnknownError) {
|
||||||
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
||||||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||||
|
|
||||||
CreateWidevineEncryptionKeySource(kDisableKeyRotation);
|
CreateWidevineEncryptionKeySource();
|
||||||
ASSERT_EQ(error::SERVER_ERROR,
|
ASSERT_EQ(error::SERVER_ERROR,
|
||||||
widevine_encryption_key_source_->Initialize().error_code());
|
widevine_encryption_key_source_->Initialize().error_code());
|
||||||
}
|
}
|
||||||
|
@ -307,8 +294,8 @@ std::string GetMockKey(const std::string& track_type, uint32 index) {
|
||||||
return "MockKey" + track_type + "@" + base::UintToString(index);
|
return "MockKey" + track_type + "@" + base::UintToString(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GenerateMockLicenseResponse(uint32 initial_crypto_period_index,
|
std::string GenerateMockKeyRotationLicenseResponse(
|
||||||
uint32 crypto_period_count) {
|
uint32 initial_crypto_period_index, uint32 crypto_period_count) {
|
||||||
const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"};
|
const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"};
|
||||||
std::string tracks;
|
std::string tracks;
|
||||||
for (uint32 index = initial_crypto_period_index;
|
for (uint32 index = initial_crypto_period_index;
|
||||||
|
@ -340,9 +327,18 @@ TEST_F(WidevineEncryptionKeySourceTest, KeyRotationTest) {
|
||||||
|
|
||||||
// Generate expectations in sequence.
|
// Generate expectations in sequence.
|
||||||
InSequence dummy;
|
InSequence dummy;
|
||||||
|
|
||||||
|
// Expecting a non-key rotation enabled request on Initialize().
|
||||||
|
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
|
||||||
|
.WillOnce(Return(true));
|
||||||
|
std::string mock_response = base::StringPrintf(
|
||||||
|
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
|
||||||
|
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
||||||
|
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||||
|
|
||||||
for (uint32 i = 0; i < kCryptoIterations; ++i) {
|
for (uint32 i = 0; i < kCryptoIterations; ++i) {
|
||||||
uint32 first_crypto_period_index =
|
uint32 first_crypto_period_index =
|
||||||
kFirstCryptoPeriodIndex + i * kCryptoPeriodCount;
|
kFirstCryptoPeriodIndex - 1 + i * kCryptoPeriodCount;
|
||||||
std::string expected_message =
|
std::string expected_message =
|
||||||
base::StringPrintf(kCryptoPeriodRequestMessageFormat,
|
base::StringPrintf(kCryptoPeriodRequestMessageFormat,
|
||||||
Base64Encode(kContentId).c_str(),
|
Base64Encode(kContentId).c_str(),
|
||||||
|
@ -354,24 +350,17 @@ TEST_F(WidevineEncryptionKeySourceTest, KeyRotationTest) {
|
||||||
|
|
||||||
std::string mock_response = base::StringPrintf(
|
std::string mock_response = base::StringPrintf(
|
||||||
kHttpResponseFormat,
|
kHttpResponseFormat,
|
||||||
Base64Encode(GenerateMockLicenseResponse(first_crypto_period_index,
|
Base64Encode(GenerateMockKeyRotationLicenseResponse(
|
||||||
kCryptoPeriodCount)).c_str());
|
first_crypto_period_index, kCryptoPeriodCount))
|
||||||
|
.c_str());
|
||||||
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
||||||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateWidevineEncryptionKeySource(kFirstCryptoPeriodIndex);
|
CreateWidevineEncryptionKeySource();
|
||||||
ASSERT_OK(widevine_encryption_key_source_->Initialize());
|
ASSERT_OK(widevine_encryption_key_source_->Initialize());
|
||||||
|
|
||||||
EncryptionKey encryption_key;
|
EncryptionKey encryption_key;
|
||||||
|
|
||||||
// Index before kFirstCryptoPeriodIndex is invalid.
|
|
||||||
Status status = widevine_encryption_key_source_->GetCryptoPeriodKey(
|
|
||||||
kFirstCryptoPeriodIndex - 1,
|
|
||||||
EncryptionKeySource::TRACK_TYPE_SD,
|
|
||||||
&encryption_key);
|
|
||||||
EXPECT_EQ(error::INVALID_ARGUMENT, status.error_code());
|
|
||||||
|
|
||||||
for (size_t i = 0; i < arraysize(kCryptoPeriodIndexes); ++i) {
|
for (size_t i = 0; i < arraysize(kCryptoPeriodIndexes); ++i) {
|
||||||
const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"};
|
const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"};
|
||||||
for (size_t j = 0; j < 3; ++j) {
|
for (size_t j = 0; j < 3; ++j) {
|
||||||
|
@ -385,36 +374,11 @@ TEST_F(WidevineEncryptionKeySourceTest, KeyRotationTest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The old crypto period indexes should have been garbage collected.
|
// The old crypto period indexes should have been garbage collected.
|
||||||
status = widevine_encryption_key_source_->GetCryptoPeriodKey(
|
Status status = widevine_encryption_key_source_->GetCryptoPeriodKey(
|
||||||
kFirstCryptoPeriodIndex,
|
kFirstCryptoPeriodIndex,
|
||||||
EncryptionKeySource::TRACK_TYPE_SD,
|
EncryptionKeySource::TRACK_TYPE_SD,
|
||||||
&encryption_key);
|
&encryption_key);
|
||||||
EXPECT_EQ(error::INVALID_ARGUMENT, status.error_code());
|
EXPECT_EQ(error::INVALID_ARGUMENT, status.error_code());
|
||||||
}
|
}
|
||||||
|
|
||||||
class WidevineEncryptionKeySourceDeathTest
|
|
||||||
: public WidevineEncryptionKeySourceTest {};
|
|
||||||
|
|
||||||
TEST_F(WidevineEncryptionKeySourceDeathTest,
|
|
||||||
GetCryptoPeriodKeyOnNonKeyRotationSource) {
|
|
||||||
CreateWidevineEncryptionKeySource(kDisableKeyRotation);
|
|
||||||
widevine_encryption_key_source_->Initialize();
|
|
||||||
|
|
||||||
EncryptionKey encryption_key;
|
|
||||||
EXPECT_DEBUG_DEATH(
|
|
||||||
widevine_encryption_key_source_->GetCryptoPeriodKey(
|
|
||||||
0, EncryptionKeySource::TRACK_TYPE_SD, &encryption_key),
|
|
||||||
"");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(WidevineEncryptionKeySourceDeathTest, GetKeyOnKeyRotationSource) {
|
|
||||||
CreateWidevineEncryptionKeySource(0);
|
|
||||||
widevine_encryption_key_source_->Initialize();
|
|
||||||
|
|
||||||
EncryptionKey encryption_key;
|
|
||||||
EXPECT_DEBUG_DEATH(widevine_encryption_key_source_->GetKey(
|
|
||||||
EncryptionKeySource::TRACK_TYPE_SD, &encryption_key),
|
|
||||||
"");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
|
|
Loading…
Reference in New Issue