Use IV from Widevine key server if available
Fixes #555. Change-Id: Ic077f97884a0c3d26159cd44791298bdd400068d
This commit is contained in:
parent
a529d4677d
commit
fcfc843a2e
|
@ -453,6 +453,7 @@ bool WidevineKeySource::ExtractEncryptionKey(
|
||||||
if (!widevine_classic) {
|
if (!widevine_classic) {
|
||||||
encryption_key->key_id.assign(track.key_id().begin(),
|
encryption_key->key_id.assign(track.key_id().begin(),
|
||||||
track.key_id().end());
|
track.key_id().end());
|
||||||
|
encryption_key->iv.assign(track.iv().begin(), track.iv().end());
|
||||||
|
|
||||||
if (generate_widevine_protection_system_) {
|
if (generate_widevine_protection_system_) {
|
||||||
if (track.pssh_size() != 1) {
|
if (track.pssh_size() != 1) {
|
||||||
|
|
|
@ -34,6 +34,9 @@ using ::testing::WithParamInterface;
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
namespace media {
|
namespace media {
|
||||||
namespace {
|
namespace {
|
||||||
|
const bool kClassic = true;
|
||||||
|
const bool kHasIv = true;
|
||||||
|
|
||||||
const char kServerUrl[] = "http://www.foo.com/getcontentkey";
|
const char kServerUrl[] = "http://www.foo.com/getcontentkey";
|
||||||
const char kContentId[] = "ContentFoo";
|
const char kContentId[] = "ContentFoo";
|
||||||
const char kPolicy[] = "PolicyFoo";
|
const char kPolicy[] = "PolicyFoo";
|
||||||
|
@ -73,6 +76,9 @@ const char kExpectedSignedMessageFormat[] =
|
||||||
R"({"request":"%s","signature":"%s","signer":"%s"})";
|
R"({"request":"%s","signature":"%s","signer":"%s"})";
|
||||||
const char kTrackFormat[] = R"({"type":"%s","key_id":"%s","key":"%s",)"
|
const char kTrackFormat[] = R"({"type":"%s","key_id":"%s","key":"%s",)"
|
||||||
R"("pssh":[{"drm_type":"WIDEVINE","data":"%s"}]})";
|
R"("pssh":[{"drm_type":"WIDEVINE","data":"%s"}]})";
|
||||||
|
const char kTrackFormatWithIv[] =
|
||||||
|
R"({"type":"%s","key_id":"%s","key":"%s","iv":"%s",)"
|
||||||
|
R"("pssh":[{"drm_type":"WIDEVINE","data":"%s"}]})";
|
||||||
const char kTrackFormatWithBoxes[] =
|
const char kTrackFormatWithBoxes[] =
|
||||||
R"({"type":"%s","key_id":"%s","key":"%s",)"
|
R"({"type":"%s","key_id":"%s","key":"%s",)"
|
||||||
R"("pssh":[{"drm_type":"WIDEVINE","data":"%s","boxes":"%s"}]})";
|
R"("pssh":[{"drm_type":"WIDEVINE","data":"%s","boxes":"%s"}]})";
|
||||||
|
@ -119,6 +125,13 @@ std::string GetMockKey(const std::string& track_type) {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GetMockIv(const std::string& track_type) {
|
||||||
|
// IV must be 16 characters.
|
||||||
|
std::string iv = "MockIv" + track_type;
|
||||||
|
iv.resize(16, '~');
|
||||||
|
return iv;
|
||||||
|
}
|
||||||
|
|
||||||
std::string GetMockPsshData() {
|
std::string GetMockPsshData() {
|
||||||
return kRequestPsshData;
|
return kRequestPsshData;
|
||||||
}
|
}
|
||||||
|
@ -126,14 +139,14 @@ std::string GetMockPsshData() {
|
||||||
std::string GenerateMockLicenseResponseWithBoxes(const std::string& boxes) {
|
std::string GenerateMockLicenseResponseWithBoxes(const std::string& boxes) {
|
||||||
const std::string kTrackTypes[] = {"SD", "HD", "UHD1", "UHD2", "AUDIO"};
|
const std::string kTrackTypes[] = {"SD", "HD", "UHD1", "UHD2", "AUDIO"};
|
||||||
std::string tracks;
|
std::string tracks;
|
||||||
for (size_t i = 0; i < 5; ++i) {
|
for (const std::string& track_type : kTrackTypes) {
|
||||||
if (!tracks.empty())
|
if (!tracks.empty())
|
||||||
tracks += ",";
|
tracks += ",";
|
||||||
tracks += base::StringPrintf(
|
tracks += base::StringPrintf(kTrackFormatWithBoxes, track_type.c_str(),
|
||||||
kTrackFormatWithBoxes, kTrackTypes[i].c_str(),
|
Base64Encode(GetMockKeyId(track_type)).c_str(),
|
||||||
Base64Encode(GetMockKeyId(kTrackTypes[i])).c_str(),
|
Base64Encode(GetMockKey(track_type)).c_str(),
|
||||||
Base64Encode(GetMockKey(kTrackTypes[i])).c_str(),
|
Base64Encode(GetMockPsshData()).c_str(),
|
||||||
Base64Encode(GetMockPsshData()).c_str(), boxes.c_str());
|
boxes.c_str());
|
||||||
}
|
}
|
||||||
return base::StringPrintf(kLicenseResponseFormat, "OK", tracks.c_str());
|
return base::StringPrintf(kLicenseResponseFormat, "OK", tracks.c_str());
|
||||||
}
|
}
|
||||||
|
@ -141,14 +154,28 @@ std::string GenerateMockLicenseResponseWithBoxes(const std::string& boxes) {
|
||||||
std::string GenerateMockLicenseResponse() {
|
std::string GenerateMockLicenseResponse() {
|
||||||
const std::string kTrackTypes[] = {"SD", "HD", "UHD1", "UHD2", "AUDIO"};
|
const std::string kTrackTypes[] = {"SD", "HD", "UHD1", "UHD2", "AUDIO"};
|
||||||
std::string tracks;
|
std::string tracks;
|
||||||
for (size_t i = 0; i < 5; ++i) {
|
for (const std::string& track_type : kTrackTypes) {
|
||||||
if (!tracks.empty())
|
if (!tracks.empty())
|
||||||
tracks += ",";
|
tracks += ",";
|
||||||
tracks +=
|
tracks += base::StringPrintf(kTrackFormat, track_type.c_str(),
|
||||||
base::StringPrintf(kTrackFormat, kTrackTypes[i].c_str(),
|
Base64Encode(GetMockKeyId(track_type)).c_str(),
|
||||||
Base64Encode(GetMockKeyId(kTrackTypes[i])).c_str(),
|
Base64Encode(GetMockKey(track_type)).c_str(),
|
||||||
Base64Encode(GetMockKey(kTrackTypes[i])).c_str(),
|
Base64Encode(GetMockPsshData()).c_str());
|
||||||
Base64Encode(GetMockPsshData()).c_str());
|
}
|
||||||
|
return base::StringPrintf(kLicenseResponseFormat, "OK", tracks.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GenerateMockLicenseResponseWithIv() {
|
||||||
|
const std::string kTrackTypes[] = {"SD", "HD", "UHD1", "UHD2", "AUDIO"};
|
||||||
|
std::string tracks;
|
||||||
|
for (const std::string& track_type : kTrackTypes) {
|
||||||
|
if (!tracks.empty())
|
||||||
|
tracks += ",";
|
||||||
|
tracks += base::StringPrintf(kTrackFormatWithIv, track_type.c_str(),
|
||||||
|
Base64Encode(GetMockKeyId(track_type)).c_str(),
|
||||||
|
Base64Encode(GetMockKey(track_type)).c_str(),
|
||||||
|
Base64Encode(GetMockIv(track_type)).c_str(),
|
||||||
|
Base64Encode(GetMockPsshData()).c_str());
|
||||||
}
|
}
|
||||||
return base::StringPrintf(kLicenseResponseFormat, "OK", tracks.c_str());
|
return base::StringPrintf(kLicenseResponseFormat, "OK", tracks.c_str());
|
||||||
}
|
}
|
||||||
|
@ -156,13 +183,11 @@ std::string GenerateMockLicenseResponse() {
|
||||||
std::string GenerateMockClassicLicenseResponse() {
|
std::string GenerateMockClassicLicenseResponse() {
|
||||||
const std::string kTrackTypes[] = {"SD", "HD", "UHD1", "UHD2", "AUDIO"};
|
const std::string kTrackTypes[] = {"SD", "HD", "UHD1", "UHD2", "AUDIO"};
|
||||||
std::string tracks;
|
std::string tracks;
|
||||||
for (size_t i = 0; i < 5; ++i) {
|
for (const std::string& track_type : kTrackTypes) {
|
||||||
if (!tracks.empty())
|
if (!tracks.empty())
|
||||||
tracks += ",";
|
tracks += ",";
|
||||||
tracks += base::StringPrintf(
|
tracks += base::StringPrintf(kClassicTrackFormat, track_type.c_str(),
|
||||||
kClassicTrackFormat,
|
Base64Encode(GetMockKey(track_type)).c_str());
|
||||||
kTrackTypes[i].c_str(),
|
|
||||||
Base64Encode(GetMockKey(kTrackTypes[i])).c_str());
|
|
||||||
}
|
}
|
||||||
return base::StringPrintf(kLicenseResponseFormat, "OK", tracks.c_str());
|
return base::StringPrintf(kLicenseResponseFormat, "OK", tracks.c_str());
|
||||||
}
|
}
|
||||||
|
@ -237,7 +262,7 @@ class WidevineKeySourceTest : public Test {
|
||||||
widevine_key_source_->set_key_fetcher(std::move(mock_key_fetcher_));
|
widevine_key_source_->set_key_fetcher(std::move(mock_key_fetcher_));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerifyKeys(bool classic) {
|
void VerifyKeys(bool classic, bool has_iv) {
|
||||||
EncryptionKey encryption_key;
|
EncryptionKey encryption_key;
|
||||||
const std::string kStreamLabels[] = {"SD", "HD", "UHD1", "UHD2", "AUDIO"};
|
const std::string kStreamLabels[] = {"SD", "HD", "UHD1", "UHD2", "AUDIO"};
|
||||||
for (const std::string& stream_label : kStreamLabels) {
|
for (const std::string& stream_label : kStreamLabels) {
|
||||||
|
@ -248,6 +273,10 @@ class WidevineKeySourceTest : public Test {
|
||||||
(add_widevine_pssh_ && add_common_pssh_) ? 2 : 1;
|
(add_widevine_pssh_ && add_common_pssh_) ? 2 : 1;
|
||||||
ASSERT_EQ(num_key_system_info, encryption_key.key_system_info.size());
|
ASSERT_EQ(num_key_system_info, encryption_key.key_system_info.size());
|
||||||
EXPECT_EQ(GetMockKeyId(stream_label), ToString(encryption_key.key_id));
|
EXPECT_EQ(GetMockKeyId(stream_label), ToString(encryption_key.key_id));
|
||||||
|
if (has_iv)
|
||||||
|
EXPECT_EQ(GetMockIv(stream_label), ToString(encryption_key.iv));
|
||||||
|
else
|
||||||
|
EXPECT_TRUE(encryption_key.iv.empty());
|
||||||
|
|
||||||
auto key_system_info_iter = encryption_key.key_system_info.begin();
|
auto key_system_info_iter = encryption_key.key_system_info.begin();
|
||||||
|
|
||||||
|
@ -307,7 +336,7 @@ TEST_F(WidevineKeySourceTest, RetryOnHttpTimeout) {
|
||||||
|
|
||||||
CreateWidevineKeySource();
|
CreateWidevineKeySource();
|
||||||
ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
|
ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
|
||||||
VerifyKeys(false);
|
VerifyKeys(!kClassic, !kHasIv);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WidevineKeySourceTest, RetryOnTransientError) {
|
TEST_F(WidevineKeySourceTest, RetryOnTransientError) {
|
||||||
|
@ -327,7 +356,7 @@ TEST_F(WidevineKeySourceTest, RetryOnTransientError) {
|
||||||
|
|
||||||
CreateWidevineKeySource();
|
CreateWidevineKeySource();
|
||||||
ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
|
ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
|
||||||
VerifyKeys(false);
|
VerifyKeys(!kClassic, !kHasIv);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WidevineKeySourceTest, NoRetryOnUnknownError) {
|
TEST_F(WidevineKeySourceTest, NoRetryOnUnknownError) {
|
||||||
|
@ -344,6 +373,19 @@ TEST_F(WidevineKeySourceTest, NoRetryOnUnknownError) {
|
||||||
widevine_key_source_->FetchKeys(content_id_, kPolicy).error_code());
|
widevine_key_source_->FetchKeys(content_id_, kPolicy).error_code());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(WidevineKeySourceTest, CheckIv) {
|
||||||
|
std::string mock_response = base::StringPrintf(
|
||||||
|
kHttpResponseFormat,
|
||||||
|
Base64Encode(GenerateMockLicenseResponseWithIv()).c_str());
|
||||||
|
|
||||||
|
EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _))
|
||||||
|
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||||
|
|
||||||
|
CreateWidevineKeySource();
|
||||||
|
ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
|
||||||
|
VerifyKeys(!kClassic, kHasIv);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(WidevineKeySourceTest, BoxesInResponse) {
|
TEST_F(WidevineKeySourceTest, BoxesInResponse) {
|
||||||
const char kMockBoxes[] = "mock_pssh_boxes";
|
const char kMockBoxes[] = "mock_pssh_boxes";
|
||||||
std::string mock_response = base::StringPrintf(
|
std::string mock_response = base::StringPrintf(
|
||||||
|
@ -410,7 +452,7 @@ TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusCencOK) {
|
||||||
|
|
||||||
CreateWidevineKeySource();
|
CreateWidevineKeySource();
|
||||||
ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
|
ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
|
||||||
VerifyKeys(false);
|
VerifyKeys(!kClassic, !kHasIv);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusCencMalformedResponse) {
|
TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusCencMalformedResponse) {
|
||||||
|
@ -444,7 +486,7 @@ TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusCencWithPsshBoxOK) {
|
||||||
std::vector<uint8_t> pssh_box(std::begin(kRequestPsshBox),
|
std::vector<uint8_t> pssh_box(std::begin(kRequestPsshBox),
|
||||||
std::end(kRequestPsshBox));
|
std::end(kRequestPsshBox));
|
||||||
ASSERT_OK(widevine_key_source_->FetchKeys(EmeInitDataType::CENC, pssh_box));
|
ASSERT_OK(widevine_key_source_->FetchKeys(EmeInitDataType::CENC, pssh_box));
|
||||||
VerifyKeys(false);
|
VerifyKeys(!kClassic, !kHasIv);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusCencWithKeyIdsOK) {
|
TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusCencWithKeyIdsOK) {
|
||||||
|
@ -467,7 +509,7 @@ TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusCencWithKeyIdsOK) {
|
||||||
std::vector<uint8_t> key_id(std::begin(kRequestKeyId),
|
std::vector<uint8_t> key_id(std::begin(kRequestKeyId),
|
||||||
std::end(kRequestKeyId));
|
std::end(kRequestKeyId));
|
||||||
ASSERT_OK(widevine_key_source_->FetchKeys(EmeInitDataType::WEBM, key_id));
|
ASSERT_OK(widevine_key_source_->FetchKeys(EmeInitDataType::WEBM, key_id));
|
||||||
VerifyKeys(false);
|
VerifyKeys(!kClassic, !kHasIv);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusClassicOK) {
|
TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusClassicOK) {
|
||||||
|
@ -489,7 +531,7 @@ TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusClassicOK) {
|
||||||
EmeInitDataType::WIDEVINE_CLASSIC,
|
EmeInitDataType::WIDEVINE_CLASSIC,
|
||||||
std::vector<uint8_t>(std::begin(kClassicAssetIdBytes),
|
std::vector<uint8_t>(std::begin(kClassicAssetIdBytes),
|
||||||
std::end(kClassicAssetIdBytes))));
|
std::end(kClassicAssetIdBytes))));
|
||||||
VerifyKeys(true);
|
VerifyKeys(kClassic, !kHasIv);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(WidevineKeySourceParameterizedTest, VerifyEntitlementLicenseRequest) {
|
TEST_P(WidevineKeySourceParameterizedTest, VerifyEntitlementLicenseRequest) {
|
||||||
|
@ -539,15 +581,13 @@ std::string GenerateMockKeyRotationLicenseResponse(
|
||||||
for (uint32_t index = initial_crypto_period_index;
|
for (uint32_t index = initial_crypto_period_index;
|
||||||
index < initial_crypto_period_index + crypto_period_count;
|
index < initial_crypto_period_index + crypto_period_count;
|
||||||
++index) {
|
++index) {
|
||||||
for (size_t i = 0; i < 5; ++i) {
|
for (const std::string& track_type : kTrackTypes) {
|
||||||
if (!tracks.empty())
|
if (!tracks.empty())
|
||||||
tracks += ",";
|
tracks += ",";
|
||||||
tracks += base::StringPrintf(
|
tracks += base::StringPrintf(
|
||||||
kCryptoPeriodTrackFormat,
|
kCryptoPeriodTrackFormat, track_type.c_str(),
|
||||||
kTrackTypes[i].c_str(),
|
Base64Encode(GetMockKeyId(track_type)).c_str(),
|
||||||
Base64Encode(GetMockKeyId(kTrackTypes[i])).c_str(),
|
Base64Encode(GetMockKey(track_type, index)).c_str(), index);
|
||||||
Base64Encode(GetMockKey(kTrackTypes[i], index)).c_str(),
|
|
||||||
index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return base::StringPrintf(kLicenseResponseFormat, "OK", tracks.c_str());
|
return base::StringPrintf(kLicenseResponseFormat, "OK", tracks.c_str());
|
||||||
|
|
Loading…
Reference in New Issue