Add client information to release and renewal messages

[ Merge of go/wvgerrit/14240 ]

Client information is reported in release and renewal messages based on
flag in the license. License proto has been updated to match server updates.

There are two caveats
* Client IDs will be reported unencrypted when usage reports are requested.
* Release requests that enable privacy mode (encrypted client IDs) but do not
  specify a service certificate are not supported.

b/19247020

Change-Id: I95e709922122370f310936fbad3d312262128e49
This commit is contained in:
Rahul Frias
2015-05-04 11:39:57 -07:00
parent 2229e51c18
commit 20fc54e384
14 changed files with 1252 additions and 524 deletions

View File

@@ -11,6 +11,7 @@
#include "config_test_env.h"
#include "device_files.h"
#include "file_store.h"
#include "license_protocol.pb.h"
#include "license_request.h"
#include "log.h"
#include "oemcrypto_adapter.h"
@@ -49,8 +50,7 @@ wvcdm::KeyId g_key_id;
wvcdm::CdmKeySystem g_key_system;
std::string g_license_server;
wvcdm::KeyId g_wrong_key_id;
wvcdm::LicenseServerId g_license_server_id =
wvcdm::kContentProtectionServer;
wvcdm::LicenseServerId g_license_server_id = wvcdm::kContentProtectionServer;
std::string kServiceCertificate =
"0803121028703454C008F63618ADE7443DB6C4C8188BE7F99005228E023082010"
@@ -399,9 +399,47 @@ UsageInfoSubSampleInfo usage_info_sub_sample_info[] = {
{&usage_info_sub_samples_icp[0], 5, wvcdm::kLevel3, ""},
{&usage_info_sub_samples_icp[0], 3, wvcdm::kLevel3, "other app id"}};
struct RenewWithClientIdTestConfiguration {
bool renew_with_client_id;
bool specify_app_parameters;
bool enable_privacy_mode;
bool specify_service_certificate;
std::string test_description;
};
RenewWithClientIdTestConfiguration
streaming_renew_client_id_test_configuration[] = {
{false, false, false, false,
"Test: Streaming renewal without client Id"},
{true, false, false, false, "Test: Streaming renewal with client Id"},
{true, true, false, false,
"Test: Streaming renewal with app parameters"},
{true, false, true, false,
"Test: Streaming renewal fetch service cert"},
{true, false, true, true,
"Test: Streaming renewal, service cert provided"}};
// Note: Offline renewal/release with encrypted client Ids and where a service
// certificate needs to be fetched is not supported.
RenewWithClientIdTestConfiguration
offline_release_client_id_test_configuration[] = {
{false, false, false, false,
"Test: Offline renewal/release without client Id"},
{true, false, false, false,
"Test: Offline renewal/release with client Id"},
{true, true, false, false,
"Test: Offline renewal/release with app parameters"},
{true, false, true, true,
"Test: Offline renewal/release, service cert provided"}};
} // namespace
namespace wvcdm {
// Protobuf generated classes
using video_widevine_server::sdk::ClientIdentification;
using video_widevine_server::sdk::ClientIdentification_NameValue;
using video_widevine_server::sdk::SignedMessage;
class TestWvCdmClientPropertySet : public CdmClientPropertySet {
public:
TestWvCdmClientPropertySet()
@@ -487,7 +525,14 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
void GenerateKeyRequest(const std::string& init_data,
CdmLicenseType license_type,
CdmClientPropertySet* property_set) {
wvcdm::CdmAppParameterMap app_parameters;
CdmAppParameterMap app_parameters;
GenerateKeyRequest(init_data, app_parameters, license_type, property_set);
}
void GenerateKeyRequest(const std::string& init_data,
CdmAppParameterMap& app_parameters,
CdmLicenseType license_type,
CdmClientPropertySet* property_set) {
std::string server_url;
std::string key_set_id;
EXPECT_EQ(wvcdm::KEY_MESSAGE,
@@ -499,13 +544,13 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
}
void GenerateRenewalRequest(CdmLicenseType license_type,
std::string* server_url) {
GenerateRenewalRequest(license_type, server_url, NULL);
CdmKeyMessage* key_msg, std::string* server_url) {
GenerateRenewalRequest(license_type, server_url);
*key_msg = key_msg_;
}
void GenerateRenewalRequest(CdmLicenseType license_type,
std::string* server_url,
CdmClientPropertySet* property_set) {
std::string* server_url) {
// TODO application makes a license request, CDM will renew the license
// when appropriate.
std::string init_data;
@@ -514,8 +559,8 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
EXPECT_EQ(wvcdm::KEY_MESSAGE,
decryptor_.GenerateKeyRequest(
session_id_, key_set_id_, "video/mp4", init_data,
license_type, app_parameters, property_set, EMPTY_ORIGIN,
&key_msg_, &key_request_type, server_url));
license_type, app_parameters, NULL, EMPTY_ORIGIN, &key_msg_,
&key_request_type, server_url));
EXPECT_EQ(kKeyRequestTypeRenewal, key_request_type);
// TODO(edwinwong, rfrias): Add tests cases for when license server url
// is empty on renewal. Need appropriate key id at the server.
@@ -523,11 +568,12 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
}
void GenerateKeyRelease(CdmKeySetId key_set_id) {
GenerateKeyRelease(key_set_id, NULL);
GenerateKeyRelease(key_set_id, NULL, NULL);
}
void GenerateKeyRelease(CdmKeySetId key_set_id,
CdmClientPropertySet* property_set) {
CdmClientPropertySet* property_set,
CdmKeyMessage* key_msg) {
CdmSessionId session_id;
CdmInitData init_data;
wvcdm::CdmAppParameterMap app_parameters;
@@ -539,6 +585,7 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
kLicenseTypeRelease, app_parameters, property_set,
EMPTY_ORIGIN, &key_msg_, &key_request_type, &server_url));
EXPECT_EQ(kKeyRequestTypeRelease, key_request_type);
if (key_msg) *key_msg = key_msg_;
}
void LogResponseError(const std::string& message, int http_status_code) {
@@ -622,15 +669,22 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
void VerifyKeyRequestResponse(const std::string& server_url,
const std::string& client_auth,
bool is_renewal) {
std::string resp = GetKeyRequestResponse(server_url, client_auth);
std::string response;
VerifyKeyRequestResponse(server_url, client_auth, is_renewal, &response);
}
void VerifyKeyRequestResponse(const std::string& server_url,
const std::string& client_auth, bool is_renewal,
std::string* response) {
*response = GetKeyRequestResponse(server_url, client_auth);
if (is_renewal) {
// TODO application makes a license request, CDM will renew the license
// when appropriate
EXPECT_EQ(decryptor_.AddKey(session_id_, resp, &key_set_id_),
EXPECT_EQ(decryptor_.AddKey(session_id_, *response, &key_set_id_),
wvcdm::KEY_ADDED);
} else {
EXPECT_EQ(decryptor_.AddKey(session_id_, resp, &key_set_id_),
EXPECT_EQ(decryptor_.AddKey(session_id_, *response, &key_set_id_),
wvcdm::KEY_ADDED);
}
}
@@ -649,9 +703,8 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
property_set = &property_set_L3;
}
CdmResponseType status =
decryptor_.OpenSession(g_key_system, property_set, EMPTY_ORIGIN, NULL,
&session_id_);
CdmResponseType status = decryptor_.OpenSession(
g_key_system, property_set, EMPTY_ORIGIN, NULL, &session_id_);
switch (status) {
case NO_ERROR:
decryptor_.CloseSession(session_id_);
@@ -667,9 +720,9 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
CdmCertificateType cert_type = kCertificateWidevine;
std::string cert_authority, cert, wrapped_key;
status = decryptor_.GetProvisioningRequest(
cert_type, cert_authority, EMPTY_ORIGIN, &key_msg_,
&provisioning_server_url);
status = decryptor_.GetProvisioningRequest(cert_type, cert_authority,
EMPTY_ORIGIN, &key_msg_,
&provisioning_server_url);
EXPECT_EQ(wvcdm::NO_ERROR, status);
if (NO_ERROR != status) return;
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
@@ -678,8 +731,8 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
GetCertRequestResponse(g_config->provisioning_server_url());
EXPECT_NE(0, static_cast<int>(response.size()));
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_.HandleProvisioningResponse(EMPTY_ORIGIN, response, &cert,
&wrapped_key));
decryptor_.HandleProvisioningResponse(EMPTY_ORIGIN, response,
&cert, &wrapped_key));
EXPECT_EQ(0, static_cast<int>(cert.size()));
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
decryptor_.CloseSession(session_id_);
@@ -687,9 +740,9 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
}
std::string GetSecurityLevel(TestWvCdmClientPropertySet* property_set) {
EXPECT_EQ(NO_ERROR, decryptor_.OpenSession(g_key_system, property_set,
EMPTY_ORIGIN, NULL,
&session_id_));
EXPECT_EQ(NO_ERROR,
decryptor_.OpenSession(g_key_system, property_set, EMPTY_ORIGIN,
NULL, &session_id_));
CdmQueryMap query_info;
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_.QuerySessionStatus(session_id_, &query_info));
@@ -704,7 +757,6 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
}
}
CdmSecurityLevel GetDefaultSecurityLevel() {
std::string level = GetSecurityLevel(NULL).c_str();
CdmSecurityLevel security_level = kSecurityLevelUninitialized;
@@ -738,9 +790,8 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) {
std::string response =
GetCertRequestResponse(g_config->provisioning_server_url());
EXPECT_NE(0, static_cast<int>(response.size()));
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_.HandleProvisioningResponse(EMPTY_ORIGIN, response, &cert,
&wrapped_key));
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(
EMPTY_ORIGIN, response, &cert, &wrapped_key));
EXPECT_EQ(0, static_cast<int>(cert.size()));
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
decryptor_.CloseSession(session_id_);
@@ -781,18 +832,16 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningRetryTest) {
std::string response =
GetCertRequestResponse(g_config->provisioning_server_url());
EXPECT_NE(0, static_cast<int>(response.size()));
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_.HandleProvisioningResponse(EMPTY_ORIGIN, response, &cert,
&wrapped_key));
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(
EMPTY_ORIGIN, response, &cert, &wrapped_key));
EXPECT_EQ(0, static_cast<int>(cert.size()));
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
response =
GetCertRequestResponse(g_config->provisioning_server_url());
response = GetCertRequestResponse(g_config->provisioning_server_url());
EXPECT_NE(0, static_cast<int>(response.size()));
EXPECT_EQ(wvcdm::EMPTY_PROVISIONING_CERTIFICATE,
decryptor_.HandleProvisioningResponse(EMPTY_ORIGIN, response, &cert,
&wrapped_key));
decryptor_.HandleProvisioningResponse(EMPTY_ORIGIN, response, &cert,
&wrapped_key));
EXPECT_EQ(0, static_cast<int>(cert.size()));
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
decryptor_.CloseSession(session_id_);
@@ -814,9 +863,8 @@ TEST_F(WvCdmRequestLicenseTest, DISABLED_X509ProvisioningTest) {
std::string response =
GetCertRequestResponse(g_config->provisioning_server_url());
EXPECT_NE(0, static_cast<int>(response.size()));
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_.HandleProvisioningResponse(EMPTY_ORIGIN, response, &cert,
&wrapped_key));
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(
EMPTY_ORIGIN, response, &cert, &wrapped_key));
EXPECT_NE(0, static_cast<int>(cert.size()));
EXPECT_NE(0, static_cast<int>(wrapped_key.size()));
decryptor_.CloseSession(session_id_);
@@ -833,31 +881,29 @@ TEST_F(WvCdmRequestLicenseTest, PropertySetTest) {
property_set_L1.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L1);
property_set_L1.set_use_privacy_mode(true);
decryptor_.OpenSession(g_key_system, &property_set_L1, EMPTY_ORIGIN, NULL,
&session_id_L1);
&session_id_L1);
property_set_L3.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
property_set_L3.set_use_privacy_mode(false);
CdmResponseType sts = decryptor_.OpenSession(g_key_system, &property_set_L3,
EMPTY_ORIGIN, NULL,
&session_id_L3);
CdmResponseType sts = decryptor_.OpenSession(
g_key_system, &property_set_L3, EMPTY_ORIGIN, NULL, &session_id_L3);
if (NEED_PROVISIONING == sts) {
std::string provisioning_server_url;
CdmCertificateType cert_type = kCertificateWidevine;
std::string cert_authority, cert, wrapped_key;
EXPECT_EQ(NO_ERROR, decryptor_.GetProvisioningRequest(
cert_type, cert_authority, EMPTY_ORIGIN,
&key_msg_, &provisioning_server_url));
cert_type, cert_authority, EMPTY_ORIGIN, &key_msg_,
&provisioning_server_url));
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
std::string response =
GetCertRequestResponse(g_config->provisioning_server_url());
EXPECT_NE(0, static_cast<int>(response.size()));
EXPECT_EQ(NO_ERROR, decryptor_.HandleProvisioningResponse(
EMPTY_ORIGIN, response, &cert, &wrapped_key));
EXPECT_EQ(NO_ERROR,
decryptor_.HandleProvisioningResponse(EMPTY_ORIGIN, response, &cert,
&wrapped_key));
EXPECT_EQ(NO_ERROR, decryptor_.OpenSession(g_key_system, &property_set_L3,
EMPTY_ORIGIN, NULL,
&session_id_L3));
decryptor_.OpenSession(g_key_system, &property_set_L3,
EMPTY_ORIGIN, NULL, &session_id_L3));
} else {
EXPECT_EQ(NO_ERROR, sts);
}
@@ -903,10 +949,9 @@ TEST_F(WvCdmRequestLicenseTest, ForceL3Test) {
handle.SetTestFile(&file);
EXPECT_TRUE(handle.DeleteAllFiles());
EXPECT_EQ(
NEED_PROVISIONING,
decryptor_.OpenSession(g_key_system, &property_set, EMPTY_ORIGIN, NULL,
&session_id_));
EXPECT_EQ(NEED_PROVISIONING,
decryptor_.OpenSession(g_key_system, &property_set, EMPTY_ORIGIN,
NULL, &session_id_));
std::string provisioning_server_url;
CdmCertificateType cert_type = kCertificateWidevine;
std::string cert_authority, cert, wrapped_key;
@@ -917,9 +962,8 @@ TEST_F(WvCdmRequestLicenseTest, ForceL3Test) {
std::string response =
GetCertRequestResponse(g_config->provisioning_server_url());
EXPECT_NE(0, static_cast<int>(response.size()));
EXPECT_EQ(NO_ERROR,
decryptor_.HandleProvisioningResponse(EMPTY_ORIGIN, response, &cert,
&wrapped_key));
EXPECT_EQ(NO_ERROR, decryptor_.HandleProvisioningResponse(
EMPTY_ORIGIN, response, &cert, &wrapped_key));
EXPECT_EQ(NO_ERROR, decryptor_.OpenSession(g_key_system, &property_set,
EMPTY_ORIGIN, NULL, &session_id_));
@@ -1117,9 +1161,8 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseRetryL3OfflineKeyTest) {
std::string client_auth;
GetOfflineConfiguration(&key_id, &client_auth);
CdmResponseType sts =
decryptor_.OpenSession(g_key_system, &property_set, EMPTY_ORIGIN, NULL,
&session_id_);
CdmResponseType sts = decryptor_.OpenSession(
g_key_system, &property_set, EMPTY_ORIGIN, NULL, &session_id_);
if (NEED_PROVISIONING == sts) {
std::string provisioning_server_url;
@@ -1132,12 +1175,11 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseRetryL3OfflineKeyTest) {
std::string response =
GetCertRequestResponse(g_config->provisioning_server_url());
EXPECT_NE(0, static_cast<int>(response.size()));
EXPECT_EQ(NO_ERROR, decryptor_.HandleProvisioningResponse(
EMPTY_ORIGIN, response, &cert, &wrapped_key));
EXPECT_EQ(NO_ERROR,
decryptor_.HandleProvisioningResponse(EMPTY_ORIGIN, response, &cert,
&wrapped_key));
EXPECT_EQ(NO_ERROR, decryptor_.OpenSession(g_key_system, &property_set,
EMPTY_ORIGIN, NULL,
&session_id_));
decryptor_.OpenSession(g_key_system, &property_set, EMPTY_ORIGIN,
NULL, &session_id_));
} else {
EXPECT_EQ(NO_ERROR, sts);
}
@@ -1160,7 +1202,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseRetryL3OfflineKeyTest) {
session_id_.clear();
key_set_id_.clear();
GenerateKeyRelease(key_set_id, &property_set);
GenerateKeyRelease(key_set_id, &property_set, NULL);
session_id_.clear();
decryptor_.OpenSession(g_key_system, &property_set, EMPTY_ORIGIN, NULL,
@@ -1171,7 +1213,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseRetryL3OfflineKeyTest) {
session_id_.clear();
key_set_id_.clear();
GenerateKeyRelease(key_set_id, &property_set);
GenerateKeyRelease(key_set_id, &property_set, NULL);
key_set_id_ = key_set_id;
VerifyKeyRequestResponse(g_license_server, client_auth, false);
}
@@ -1199,11 +1241,11 @@ TEST_F(WvCdmRequestLicenseTest, ExpiryOnReleaseOfflineKeyTest) {
decryptor_.OpenSession(g_key_system, NULL, EMPTY_ORIGIN, &listener,
&session_id_);
CdmSessionId restore_session_id = session_id_;
EXPECT_CALL(listener,
OnSessionKeysChange(restore_session_id,
AllOf(Each(Pair(_, kKeyStatusUsable)),
Not(IsEmpty())),
true));
EXPECT_CALL(
listener,
OnSessionKeysChange(
restore_session_id,
AllOf(Each(Pair(_, kKeyStatusUsable)), Not(IsEmpty())), true));
EXPECT_CALL(listener, OnExpirationUpdate(restore_session_id, _));
EXPECT_EQ(wvcdm::KEY_ADDED,
decryptor_.RestoreKey(restore_session_id, key_set_id));
@@ -1213,11 +1255,11 @@ TEST_F(WvCdmRequestLicenseTest, ExpiryOnReleaseOfflineKeyTest) {
// Maybe called since VerifyKeyRequestResponse could take some time.
EXPECT_CALL(listener, OnSessionRenewalNeeded(restore_session_id))
.Times(AtLeast(0));
EXPECT_CALL(listener,
OnSessionKeysChange(restore_session_id,
AllOf(Each(Pair(_, kKeyStatusExpired)),
Not(IsEmpty())),
false));
EXPECT_CALL(
listener,
OnSessionKeysChange(
restore_session_id,
AllOf(Each(Pair(_, kKeyStatusExpired)), Not(IsEmpty())), false));
GenerateKeyRelease(key_set_id);
key_set_id_ = key_set_id;
VerifyKeyRequestResponse(g_license_server, client_auth, false);
@@ -1254,15 +1296,277 @@ TEST_F(WvCdmRequestLicenseTest, OfflineLicenseRenewal) {
}
TEST_F(WvCdmRequestLicenseTest, RemoveKeys) {
ASSERT_EQ(NO_ERROR,
decryptor_.OpenSession(g_key_system, NULL, EMPTY_ORIGIN, NULL,
&session_id_));
ASSERT_EQ(NO_ERROR, decryptor_.OpenSession(g_key_system, NULL, EMPTY_ORIGIN,
NULL, &session_id_));
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
ASSERT_EQ(NO_ERROR, decryptor_.RemoveKeys(session_id_));
ASSERT_EQ(NO_ERROR, decryptor_.CloseSession(session_id_));
}
class WvCdmStreamingLicenseRenewalTest
: public WvCdmRequestLicenseTest,
public ::testing::WithParamInterface<
RenewWithClientIdTestConfiguration*> {};
TEST_P(WvCdmStreamingLicenseRenewalTest, DISABLED_WithClientId) {
RenewWithClientIdTestConfiguration* config = GetParam();
std::string key_id;
if (config->renew_with_client_id) {
key_id = a2bs_hex(
"000000427073736800000000" // blob size and pssh
"EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id
"08011a0d7769646576696e655f74657374220f73" // pssh data
"747265616d696e675f636c697036");
} else {
key_id = g_key_id;
}
const uint32_t kNameValueParamSize = 2;
std::pair<std::string, std::string> name_value_params[kNameValueParamSize] = {
{"Name1", "Value1"}, {"Name2", "Value2"}};
wvcdm::CdmAppParameterMap app_parameters;
if (config->specify_app_parameters) {
for (uint32_t i = 0; i < kNameValueParamSize; ++i) {
app_parameters[name_value_params[i].first] = name_value_params[i].second;
}
}
TestWvCdmClientPropertySet property_set;
if (config->enable_privacy_mode) {
property_set.set_use_privacy_mode(true);
if (config->specify_service_certificate)
property_set.set_service_certificate(a2bs_hex(kServiceCertificate));
}
decryptor_.OpenSession(g_key_system, &property_set, EMPTY_ORIGIN, NULL,
&session_id_);
GenerateKeyRequest(key_id, app_parameters, kLicenseTypeStreaming,
&property_set);
if (config->enable_privacy_mode && !config->specify_service_certificate) {
std::string resp = GetKeyRequestResponse(g_license_server, g_client_auth);
EXPECT_EQ(decryptor_.AddKey(session_id_, resp, &key_set_id_),
wvcdm::NEED_KEY);
GenerateKeyRequest(key_id, kLicenseTypeStreaming);
}
std::string key_response;
VerifyKeyRequestResponse(g_license_server, g_client_auth, false,
&key_response);
// Validate signed license
SignedMessage signed_message;
EXPECT_TRUE(signed_message.ParseFromString(key_response))
<< config->test_description;
EXPECT_EQ(SignedMessage::LICENSE, signed_message.type())
<< config->test_description;
EXPECT_TRUE(signed_message.has_signature()) << config->test_description;
EXPECT_TRUE(!signed_message.msg().empty()) << config->test_description;
// Verify license request
video_widevine_server::sdk::License license;
EXPECT_TRUE(license.ParseFromString(signed_message.msg()))
<< config->test_description;
// Verify renew_with_client_id
EXPECT_EQ(config->renew_with_client_id,
license.policy().has_renew_with_client_id());
std::string license_server;
CdmKeyMessage key_msg;
GenerateRenewalRequest(kLicenseTypeStreaming, &key_msg, &license_server);
if (license_server.empty()) license_server = g_license_server;
// Validate signed renewal request
EXPECT_TRUE(signed_message.ParseFromString(key_msg))
<< config->test_description;
EXPECT_EQ(SignedMessage::LICENSE_REQUEST, signed_message.type())
<< config->test_description;
EXPECT_TRUE(signed_message.has_signature()) << config->test_description;
EXPECT_TRUE(!signed_message.msg().empty()) << config->test_description;
// Verify license request
video_widevine_server::sdk::LicenseRequest license_renewal;
EXPECT_TRUE(license_renewal.ParseFromString(signed_message.msg()))
<< config->test_description;
// Verify ClientId
EXPECT_EQ(config->renew_with_client_id && !config->enable_privacy_mode,
license_renewal.has_client_id())
<< config->test_description;
if (config->specify_app_parameters) {
for (uint32_t i = 0; i < kNameValueParamSize; ++i) {
bool found = false;
for (int j = 0; j < license_renewal.client_id().client_info_size(); ++j) {
ClientIdentification_NameValue client_info =
license_renewal.client_id().client_info(i);
if (name_value_params[i].first.compare(client_info.name()) == 0 &&
name_value_params[i].second.compare(client_info.value()) == 0) {
found = true;
break;
}
}
EXPECT_TRUE(found) << config->test_description;
}
}
if (config->enable_privacy_mode) {
EXPECT_EQ(config->renew_with_client_id,
license_renewal.has_encrypted_client_id())
<< config->test_description;
EXPECT_NE(
0u, license_renewal.encrypted_client_id().encrypted_client_id().size());
}
VerifyKeyRequestResponse(license_server, g_client_auth, true);
decryptor_.CloseSession(session_id_);
}
INSTANTIATE_TEST_CASE_P(
Cdm, WvCdmStreamingLicenseRenewalTest,
::testing::Range(&streaming_renew_client_id_test_configuration[0],
&streaming_renew_client_id_test_configuration[5]));
class WvCdmOfflineLicenseReleaseTest
: public WvCdmRequestLicenseTest,
public ::testing::WithParamInterface<
RenewWithClientIdTestConfiguration*> {};
TEST_P(WvCdmOfflineLicenseReleaseTest, DISABLED_WithClientId) {
Unprovision();
Provision(kLevelDefault);
RenewWithClientIdTestConfiguration* config = GetParam();
std::string key_id;
std::string client_auth;
GetOfflineConfiguration(&key_id, &client_auth);
if (config->renew_with_client_id) {
key_id = a2bs_hex(
"00000040" // blob size
"70737368" // "pssh"
"00000000" // flags
"edef8ba979d64acea3c827dcd51d21ed" // Widevine system id
"00000020" // pssh data size
// pssh data:
"08011a0d7769646576696e655f746573"
"74220d6f66666c696e655f636c697033");
}
const uint32_t kNameValueParamSize = 2;
std::pair<std::string, std::string> name_value_params[kNameValueParamSize] = {
{"Name1", "Value1"}, {"Name2", "Value2"}};
wvcdm::CdmAppParameterMap app_parameters;
if (config->specify_app_parameters) {
for (uint32_t i = 0; i < kNameValueParamSize; ++i) {
app_parameters[name_value_params[i].first] = name_value_params[i].second;
}
}
TestWvCdmClientPropertySet property_set;
if (config->enable_privacy_mode) {
property_set.set_use_privacy_mode(true);
if (config->specify_service_certificate)
property_set.set_service_certificate(a2bs_hex(kServiceCertificate));
}
decryptor_.OpenSession(g_key_system, &property_set, EMPTY_ORIGIN, NULL,
&session_id_);
GenerateKeyRequest(key_id, app_parameters, kLicenseTypeOffline, NULL);
if (config->enable_privacy_mode && !config->specify_service_certificate) {
std::string resp = GetKeyRequestResponse(g_license_server, client_auth);
EXPECT_EQ(decryptor_.AddKey(session_id_, resp, &key_set_id_),
wvcdm::NEED_KEY);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
}
std::string key_response;
VerifyKeyRequestResponse(g_license_server, client_auth, false, &key_response);
// Validate signed license
SignedMessage signed_message;
EXPECT_TRUE(signed_message.ParseFromString(key_response))
<< config->test_description;
EXPECT_EQ(SignedMessage::LICENSE, signed_message.type())
<< config->test_description;
EXPECT_TRUE(signed_message.has_signature()) << config->test_description;
EXPECT_TRUE(!signed_message.msg().empty()) << config->test_description;
// Verify license request
video_widevine_server::sdk::License license;
EXPECT_TRUE(license.ParseFromString(signed_message.msg()))
<< config->test_description;
// Verify renew_with_client_id
EXPECT_EQ(config->renew_with_client_id,
license.policy().has_renew_with_client_id());
CdmKeySetId key_set_id = key_set_id_;
EXPECT_TRUE(key_set_id_.size() > 0);
decryptor_.CloseSession(session_id_);
session_id_.clear();
key_set_id_.clear();
decryptor_.OpenSession(g_key_system, &property_set, EMPTY_ORIGIN, NULL,
&session_id_);
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id));
decryptor_.CloseSession(session_id_);
session_id_.clear();
key_set_id_.clear();
CdmKeyMessage key_msg;
GenerateKeyRelease(key_set_id, &property_set, &key_msg);
key_set_id_ = key_set_id;
// Validate signed renewal request
EXPECT_TRUE(signed_message.ParseFromString(key_msg))
<< config->test_description;
EXPECT_EQ(SignedMessage::LICENSE_REQUEST, signed_message.type())
<< config->test_description;
EXPECT_TRUE(signed_message.has_signature()) << config->test_description;
EXPECT_TRUE(!signed_message.msg().empty()) << config->test_description;
// Verify license request
video_widevine_server::sdk::LicenseRequest license_release;
EXPECT_TRUE(license_release.ParseFromString(signed_message.msg()))
<< config->test_description;
// Verify ClientId
EXPECT_EQ(config->renew_with_client_id && !config->enable_privacy_mode,
license_release.has_client_id())
<< config->test_description;
if (config->specify_app_parameters) {
for (uint32_t i = 0; i < kNameValueParamSize; ++i) {
bool found = false;
for (int j = 0; j < license_release.client_id().client_info_size(); ++j) {
ClientIdentification_NameValue client_info =
license_release.client_id().client_info(i);
if (name_value_params[i].first.compare(client_info.name()) == 0 &&
name_value_params[i].second.compare(client_info.value()) == 0) {
found = true;
break;
}
}
EXPECT_TRUE(found) << config->test_description;
}
}
if (config->enable_privacy_mode) {
EXPECT_EQ(config->renew_with_client_id,
license_release.has_encrypted_client_id())
<< config->test_description;
EXPECT_NE(
0u, license_release.encrypted_client_id().encrypted_client_id().size());
}
VerifyKeyRequestResponse(g_license_server, client_auth, false);
decryptor_.CloseSession(session_id_);
}
INSTANTIATE_TEST_CASE_P(
Cdm, WvCdmOfflineLicenseReleaseTest,
::testing::Range(&offline_release_client_id_test_configuration[0],
&offline_release_client_id_test_configuration[4]));
TEST_F(WvCdmRequestLicenseTest, UsageInfoRetryTest) {
Unprovision();
Provision(kLevelDefault);
@@ -1318,10 +1622,15 @@ TEST_F(WvCdmRequestLicenseTest, UsageInfoRetryTest) {
}
status = decryptor_.GetUsageInfo(app_id, &usage_info);
switch (status) {
case KEY_MESSAGE: EXPECT_FALSE(usage_info.empty()); break;
case NO_ERROR: EXPECT_TRUE(usage_info.empty()); break;
default: FAIL() << "GetUsageInfo failed with error "
<< static_cast<int>(status) ; break;
case KEY_MESSAGE:
EXPECT_FALSE(usage_info.empty());
break;
case NO_ERROR:
EXPECT_TRUE(usage_info.empty());
break;
default:
FAIL() << "GetUsageInfo failed with error " << static_cast<int>(status);
break;
}
}
}
@@ -1581,9 +1890,8 @@ TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) {
std::string response =
GetCertRequestResponse(g_config->provisioning_server_url());
EXPECT_NE(0, static_cast<int>(response.size()));
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_.HandleProvisioningResponse(EMPTY_ORIGIN, response, &cert,
&wrapped_key));
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(
EMPTY_ORIGIN, response, &cert, &wrapped_key));
decryptor_.CloseSession(session_id_);
std::vector<std::string> files;
@@ -1630,20 +1938,17 @@ TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) {
TestWvCdmClientPropertySet property_set;
property_set.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
EXPECT_EQ(
wvcdm::NEED_PROVISIONING,
decryptor_.OpenSession(g_key_system, &property_set, EMPTY_ORIGIN, NULL,
&session_id_));
EXPECT_EQ(wvcdm::NEED_PROVISIONING,
decryptor_.OpenSession(g_key_system, &property_set, EMPTY_ORIGIN,
NULL, &session_id_));
EXPECT_EQ(NO_ERROR, decryptor_.GetProvisioningRequest(
cert_type, cert_authority, EMPTY_ORIGIN, &key_msg_,
&provisioning_server_url));
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
response =
GetCertRequestResponse(g_config->provisioning_server_url());
response = GetCertRequestResponse(g_config->provisioning_server_url());
EXPECT_NE(0, static_cast<int>(response.size()));
EXPECT_EQ(NO_ERROR,
decryptor_.HandleProvisioningResponse(EMPTY_ORIGIN, response, &cert,
&wrapped_key));
EXPECT_EQ(NO_ERROR, decryptor_.HandleProvisioningResponse(
EMPTY_ORIGIN, response, &cert, &wrapped_key));
EXPECT_EQ(NO_ERROR, decryptor_.OpenSession(g_key_system, &property_set,
EMPTY_ORIGIN, NULL, &session_id_));
@@ -1948,16 +2253,17 @@ TEST(VersionNumberTest, VersionNumberChangeCanary) {
char release_number[PROPERTY_VALUE_MAX];
ASSERT_GT(property_get("ro.build.version.release", release_number, "Unknown"),
0);
EXPECT_STREQ("MNC", release_number) <<
"The Android version number has changed. You need to update this test "
"and also possibly update the Widevine version number in "
"properties_android.cpp.";
EXPECT_STREQ("MNC", release_number)
<< "The Android version number has changed. You need to update this test "
"and also possibly update the Widevine version number in "
"properties_android.cpp.";
std::string widevine_version;
ASSERT_TRUE(Properties::GetWVCdmVersion(&widevine_version));
EXPECT_EQ("v3.0.0-android", widevine_version) <<
"The Widevine CDM version number has changed. Did you forget to update "
"this test after changing it?";
EXPECT_EQ("v3.0.0-android", widevine_version)
<< "The Widevine CDM version number has changed. Did you forget to "
"update "
"this test after changing it?";
}
} // namespace wvcdm
@@ -1981,8 +2287,8 @@ void show_menu(char* prog_name) {
std::cout << std::setw(35) << std::left << " ";
std::cout << "gp (case sensitive) for GooglePlay server" << std::endl;
std::cout << std::setw(35) << std::left << " ";
std::cout << "cp (case sensitive) for Content Protection server"
<< std::endl << std::endl;
std::cout << "cp (case sensitive) for Content Protection server" << std::endl
<< std::endl;
std::cout << std::setw(35) << std::left << " -k/--keyid=<key_id>";
std::cout << "configure the key id or pssh, in hex format" << std::endl
@@ -1997,7 +2303,8 @@ void show_menu(char* prog_name) {
std::cout << std::setw(35) << std::left << " -u/--server=<server_url>";
std::cout
<< "configure the license server url, please include http[s] in the url"
<< std::endl << std::endl;
<< std::endl
<< std::endl;
}
int main(int argc, char** argv) {