Key derivation failure on key release
Signing and encryption keys are not correctly setup in OEMCrypto, when an offline license is restored, before generating a key release message. This results in key release failures. Playing back the license response causes keys to be derived and allows the key release message to be constructed. b/9016545 Merge of https://widevine-internal-review.googlesource.com/#/c/5682/ from the Widevine CDM repository Change-Id: Ica9f13acc7c87e3125fa706f3a56e95b77a14a3c
This commit is contained in:
@@ -98,11 +98,10 @@ CdmResponseType CdmSession::RestoreOfflineSession(
|
||||
}
|
||||
}
|
||||
|
||||
if (license_type == kLicenseTypeOffline) {
|
||||
if (!license_parser_.RestoreOfflineLicense(offline_key_request_,
|
||||
offline_key_response_,
|
||||
offline_key_renewal_response_))
|
||||
return UNKNOWN_ERROR;
|
||||
if (!license_parser_.RestoreOfflineLicense(offline_key_request_,
|
||||
offline_key_response_,
|
||||
offline_key_renewal_response_)) {
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
license_received_ = true;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "string_conversions.h"
|
||||
#include "url_request.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
#include "wv_cdm_event_listener.h"
|
||||
#include "wv_content_decryption_module.h"
|
||||
|
||||
namespace {
|
||||
@@ -60,6 +61,20 @@ typedef struct DecryptionData {
|
||||
std::vector<uint8_t> decrypt_data;
|
||||
} DecryptionData;
|
||||
|
||||
class TestWvCdmEventListener : public WvCdmEventListener {
|
||||
public:
|
||||
TestWvCdmEventListener() : WvCdmEventListener() {}
|
||||
virtual void onEvent(const CdmSessionId& id, CdmEventType event) {
|
||||
session_id_ = id;
|
||||
event_type_ = event;
|
||||
}
|
||||
CdmSessionId session_id() { return session_id_; };
|
||||
CdmEventType event_type() { return event_type_; };
|
||||
private:
|
||||
CdmSessionId session_id_;
|
||||
CdmEventType event_type_;
|
||||
};
|
||||
|
||||
class WvCdmRequestLicenseTest : public testing::Test {
|
||||
public:
|
||||
WvCdmRequestLicenseTest() {}
|
||||
@@ -91,6 +106,8 @@ class WvCdmRequestLicenseTest : public testing::Test {
|
||||
decryptor_.GenerateKeyRequest(session_id_, key_set_id, init_data,
|
||||
license_type, app_parameters,
|
||||
&key_msg_, &server_url));
|
||||
// TODO(edwinwong, rfrias): Add tests cases for when license server url
|
||||
// is empty on renewal. Need appropriate key id at the server.
|
||||
EXPECT_NE(0, static_cast<int>(server_url.size()));
|
||||
}
|
||||
|
||||
@@ -103,7 +120,6 @@ class WvCdmRequestLicenseTest : public testing::Test {
|
||||
decryptor_.GenerateKeyRequest(session_id, key_set_id, init_data,
|
||||
kLicenseTypeRelease, app_parameters,
|
||||
&key_msg_, &server_url));
|
||||
EXPECT_EQ(0, static_cast<int>(server_url.size()));
|
||||
}
|
||||
|
||||
void DumpResponse(const std::string& description,
|
||||
@@ -377,7 +393,7 @@ TEST_F(WvCdmRequestLicenseTest, RestoreOfflineKeyTest) {
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, DISABLED_ReleaseOfflineKeyTest) {
|
||||
TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeyTest) {
|
||||
decryptor_.OpenSession(g_key_system, &session_id_);
|
||||
GenerateKeyRequest(g_key_system, kServerSdkKeyId, kLicenseTypeOffline);
|
||||
VerifyKeyRequestResponse(kServerSdkLicenseServer, kServerSdkClientAuth,
|
||||
@@ -395,11 +411,43 @@ TEST_F(WvCdmRequestLicenseTest, DISABLED_ReleaseOfflineKeyTest) {
|
||||
session_id_.clear();
|
||||
key_set_id_.clear();
|
||||
GenerateKeyRelease(key_set_id);
|
||||
key_set_id_ = key_set_id;
|
||||
VerifyKeyRequestResponse(kServerSdkLicenseServer, kServerSdkClientAuth,
|
||||
kServerSdkKeyId, false);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, LicenseRenewal) {
|
||||
TEST_F(WvCdmRequestLicenseTest, ExpiryOnReleaseOfflineKeyTest) {
|
||||
decryptor_.OpenSession(g_key_system, &session_id_);
|
||||
GenerateKeyRequest(g_key_system, kServerSdkKeyId, kLicenseTypeOffline);
|
||||
VerifyKeyRequestResponse(kServerSdkLicenseServer, kServerSdkClientAuth,
|
||||
kServerSdkKeyId, false);
|
||||
CdmKeySetId key_set_id = key_set_id_;
|
||||
EXPECT_FALSE(key_set_id_.empty());
|
||||
decryptor_.CloseSession(session_id_);
|
||||
|
||||
session_id_.clear();
|
||||
key_set_id_.clear();
|
||||
decryptor_.OpenSession(g_key_system, &session_id_);
|
||||
CdmSessionId restore_session_id = session_id_;
|
||||
TestWvCdmEventListener listener;
|
||||
EXPECT_TRUE(decryptor_.AttachEventListener(restore_session_id, &listener));
|
||||
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(restore_session_id,
|
||||
key_set_id));
|
||||
|
||||
session_id_.clear();
|
||||
key_set_id_.clear();
|
||||
EXPECT_TRUE(listener.session_id().size() == 0);
|
||||
GenerateKeyRelease(key_set_id);
|
||||
key_set_id_ = key_set_id;
|
||||
EXPECT_TRUE(listener.session_id().size() != 0);
|
||||
EXPECT_TRUE(listener.session_id().compare(restore_session_id) == 0);
|
||||
EXPECT_TRUE(listener.event_type() == LICENSE_EXPIRED_EVENT);
|
||||
VerifyKeyRequestResponse(kServerSdkLicenseServer, kServerSdkClientAuth,
|
||||
kServerSdkKeyId, false);
|
||||
decryptor_.CloseSession(restore_session_id);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, StreamingLicenseRenewal) {
|
||||
decryptor_.OpenSession(g_key_system, &session_id_);
|
||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
||||
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
||||
@@ -409,6 +457,18 @@ TEST_F(WvCdmRequestLicenseTest, LicenseRenewal) {
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, OfflineLicenseRenewal) {
|
||||
decryptor_.OpenSession(g_key_system, &session_id_);
|
||||
GenerateKeyRequest(g_key_system, kServerSdkKeyId, kLicenseTypeOffline);
|
||||
VerifyKeyRequestResponse(kServerSdkLicenseServer, kServerSdkClientAuth,
|
||||
kServerSdkKeyId, false);
|
||||
|
||||
GenerateRenewalRequest(g_key_system, kLicenseTypeOffline);
|
||||
VerifyKeyRequestResponse(kServerSdkLicenseServer, kServerSdkClientAuth,
|
||||
kServerSdkKeyId, true);
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, QueryKeyStatus) {
|
||||
decryptor_.OpenSession(g_key_system, &session_id_);
|
||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
||||
@@ -648,6 +708,118 @@ TEST_F(WvCdmRequestLicenseTest, DecryptionTest) {
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, OfflineLicenseDecryptionTest) {
|
||||
decryptor_.OpenSession(g_key_system, &session_id_);
|
||||
GenerateKeyRequest(g_key_system, kServerSdkKeyId, kLicenseTypeOffline);
|
||||
VerifyKeyRequestResponse(kServerSdkLicenseServer, kServerSdkClientAuth,
|
||||
kServerSdkKeyId, false);
|
||||
|
||||
// key 1, encrypted, 256b
|
||||
DecryptionData data;
|
||||
data.is_encrypted = true;
|
||||
data.is_secure = false;
|
||||
data.key_id = wvcdm::a2bs_hex("30313233343536373839414243444546");
|
||||
data.encrypt_data = wvcdm::a2b_hex(
|
||||
"b6d7d2430aa82b1cb8bd32f02e1f3b2a8d84f9eddf935ced5a6a98022cbb4561"
|
||||
"8346a749fdb336858a64d7169fd0aa898a32891d14c24bed17fdc17fd62b8771"
|
||||
"a8e22e9f093fa0f2aacd293d471b8e886d5ed8d0998ab2fde2d908580ff88c93"
|
||||
"c0f0bbc14867267b3a3955bb6e7d05fca734a3aec3463d786d555cad83536ebe"
|
||||
"4496d934d40df2aba5aea98c1145a2890879568ae31bb8a85d74714a4ad75785"
|
||||
"7488523e697f5fd370eac746d56990a81cc76a178e3d6d65743520cdbc669412"
|
||||
"9e73b86214256c67430cf78662346cab3e2bdd6f095dddf75b7fb3868c5ff5ff"
|
||||
"3e1bbf08d456532ffa9df6e21a8bb2664c2d2a6d47ee78f9a6d53b2f2c8c087c");
|
||||
data.iv = wvcdm::a2b_hex("86856b9409743ca107b043e82068c7b6");
|
||||
data.block_offset = 0;
|
||||
data.decrypt_data = wvcdm::a2b_hex(
|
||||
"cc4a7fed8c5ac6e316e45317805c43e6d62a383ad738219c65e7a259dc12b46a"
|
||||
"d50a3f8ce2facec8eeadff9cfa6b649212b88602b41f6d4c510c05af07fd523a"
|
||||
"e7032634d9f8db5dd652d35f776376c5fc56e7031ed7cb28b72427fd4b367b6d"
|
||||
"8c4eb6e46ed1249de5d24a61aeb08ebd60984c10581042ca8b0ef6bc44ec34a0"
|
||||
"d4a77d68125c9bb1ace6f650e8716540f5b20d6482f7cfdf1b57a9ee9802160c"
|
||||
"a632ce42934347410abc61bb78fba11b093498572de38bca96101ecece455e3b"
|
||||
"5fef6805c44a2609cf97ce0dac7f15695c8058c590eda517f845108b90dfb29c"
|
||||
"e73f3656000399f2fd196bc6fc225f3a7b8f578237751fd485ff070b5289e5cf");
|
||||
|
||||
std::vector<uint8_t> decrypt_buffer;
|
||||
size_t encrypt_length = data.encrypt_data.size();
|
||||
decrypt_buffer.resize(encrypt_length);
|
||||
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_,
|
||||
data.is_encrypted,
|
||||
data.is_secure,
|
||||
data.key_id,
|
||||
&data.encrypt_data.front(),
|
||||
encrypt_length,
|
||||
data.iv,
|
||||
data.block_offset,
|
||||
&decrypt_buffer.front(),
|
||||
0));
|
||||
|
||||
EXPECT_TRUE(std::equal(data.decrypt_data.begin(), data.decrypt_data.end(),
|
||||
decrypt_buffer.begin()));
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, RestoreOfflineLicenseDecryptionTest) {
|
||||
decryptor_.OpenSession(g_key_system, &session_id_);
|
||||
GenerateKeyRequest(g_key_system, kServerSdkKeyId, kLicenseTypeOffline);
|
||||
VerifyKeyRequestResponse(kServerSdkLicenseServer, kServerSdkClientAuth,
|
||||
kServerSdkKeyId, false);
|
||||
CdmKeySetId key_set_id = key_set_id_;
|
||||
EXPECT_FALSE(key_set_id_.empty());
|
||||
decryptor_.CloseSession(session_id_);
|
||||
|
||||
session_id_.clear();
|
||||
decryptor_.OpenSession(g_key_system, &session_id_);
|
||||
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id));
|
||||
|
||||
// key 1, encrypted, 256b
|
||||
DecryptionData data;
|
||||
data.is_encrypted = true;
|
||||
data.is_secure = false;
|
||||
data.key_id = wvcdm::a2bs_hex("30313233343536373839414243444546");
|
||||
data.encrypt_data = wvcdm::a2b_hex(
|
||||
"b6d7d2430aa82b1cb8bd32f02e1f3b2a8d84f9eddf935ced5a6a98022cbb4561"
|
||||
"8346a749fdb336858a64d7169fd0aa898a32891d14c24bed17fdc17fd62b8771"
|
||||
"a8e22e9f093fa0f2aacd293d471b8e886d5ed8d0998ab2fde2d908580ff88c93"
|
||||
"c0f0bbc14867267b3a3955bb6e7d05fca734a3aec3463d786d555cad83536ebe"
|
||||
"4496d934d40df2aba5aea98c1145a2890879568ae31bb8a85d74714a4ad75785"
|
||||
"7488523e697f5fd370eac746d56990a81cc76a178e3d6d65743520cdbc669412"
|
||||
"9e73b86214256c67430cf78662346cab3e2bdd6f095dddf75b7fb3868c5ff5ff"
|
||||
"3e1bbf08d456532ffa9df6e21a8bb2664c2d2a6d47ee78f9a6d53b2f2c8c087c");
|
||||
data.iv = wvcdm::a2b_hex("86856b9409743ca107b043e82068c7b6");
|
||||
data.block_offset = 0;
|
||||
data.decrypt_data = wvcdm::a2b_hex(
|
||||
"cc4a7fed8c5ac6e316e45317805c43e6d62a383ad738219c65e7a259dc12b46a"
|
||||
"d50a3f8ce2facec8eeadff9cfa6b649212b88602b41f6d4c510c05af07fd523a"
|
||||
"e7032634d9f8db5dd652d35f776376c5fc56e7031ed7cb28b72427fd4b367b6d"
|
||||
"8c4eb6e46ed1249de5d24a61aeb08ebd60984c10581042ca8b0ef6bc44ec34a0"
|
||||
"d4a77d68125c9bb1ace6f650e8716540f5b20d6482f7cfdf1b57a9ee9802160c"
|
||||
"a632ce42934347410abc61bb78fba11b093498572de38bca96101ecece455e3b"
|
||||
"5fef6805c44a2609cf97ce0dac7f15695c8058c590eda517f845108b90dfb29c"
|
||||
"e73f3656000399f2fd196bc6fc225f3a7b8f578237751fd485ff070b5289e5cf");
|
||||
|
||||
std::vector<uint8_t> decrypt_buffer;
|
||||
size_t encrypt_length = data.encrypt_data.size();
|
||||
decrypt_buffer.resize(encrypt_length);
|
||||
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_,
|
||||
data.is_encrypted,
|
||||
data.is_secure,
|
||||
data.key_id,
|
||||
&data.encrypt_data.front(),
|
||||
encrypt_length,
|
||||
data.iv,
|
||||
data.block_offset,
|
||||
&decrypt_buffer.front(),
|
||||
0));
|
||||
|
||||
EXPECT_TRUE(std::equal(data.decrypt_data.begin(), data.decrypt_data.end(),
|
||||
decrypt_buffer.begin()));
|
||||
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, SwitchKeyDecryptionTest) {
|
||||
decryptor_.OpenSession(g_key_system, &session_id_);
|
||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
||||
|
||||
Reference in New Issue
Block a user