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

@@ -139,6 +139,7 @@ class CdmSession {
bool is_release_;
CdmSecurityLevel security_level_;
SecurityLevel requested_security_level_;
CdmAppParameterMap app_parameters_;
// decryption and usage flags
bool is_initial_decryption_;

View File

@@ -51,13 +51,15 @@ class DeviceFiles {
const CdmKeyResponse& key_renewal_response,
const std::string& release_server_url,
int64_t playback_start_time,
int64_t last_playback_time);
int64_t last_playback_time,
const CdmAppParameterMap& app_parameters);
virtual bool RetrieveLicense(
const std::string& key_set_id, LicenseState* state,
CdmInitData* pssh_data, CdmKeyMessage* key_request,
CdmKeyResponse* key_response, CdmKeyMessage* key_renewal_request,
CdmKeyResponse* key_renewal_response, std::string* release_server_url,
int64_t* playback_start_time, int64_t* last_playback_time);
int64_t* playback_start_time, int64_t* last_playback_time,
CdmAppParameterMap* app_parameters);
virtual bool DeleteLicense(const std::string& key_set_id);
virtual bool DeleteAllFiles();
virtual bool DeleteAllLicenses();
@@ -122,6 +124,7 @@ class DeviceFiles {
FRIEND_TEST(DeviceFilesTest, DeleteLicense);
FRIEND_TEST(DeviceFilesTest, ReserveLicenseIds);
FRIEND_TEST(DeviceFilesTest, RetrieveLicenses);
FRIEND_TEST(DeviceFilesTest, AppParametersBackwardCompatibility);
FRIEND_TEST(DeviceFilesTest, SecurityLevelPathBackwardCompatibility);
FRIEND_TEST(DeviceFilesTest, StoreLicenses);
FRIEND_TEST(DeviceFilesTest, UpdateLicenseState);

View File

@@ -12,6 +12,7 @@
namespace video_widevine_server {
namespace sdk {
class SignedMessage;
class LicenseRequest;
}
} // namespace video_widevine_server
@@ -35,8 +36,9 @@ class CdmLicense {
const CdmSessionId& session_id,
CdmKeyMessage* signed_request,
std::string* server_url);
virtual CdmResponseType PrepareKeyUpdateRequest(bool is_renewal,
CdmKeyMessage* signed_request,
virtual CdmResponseType PrepareKeyUpdateRequest(
bool is_renewal, const CdmAppParameterMap& app_parameters,
const CdmSessionId& session_id, CdmKeyMessage* signed_request,
std::string* server_url);
virtual CdmResponseType HandleKeyResponse(
const CdmKeyResponse& license_response);
@@ -66,10 +68,17 @@ class CdmLicense {
CdmResponseType HandleKeyErrorResponse(
const video_widevine_server::sdk::SignedMessage& signed_message);
CdmResponseType PrepareClientId(
bool encrypt, const std::string& certificate,
const CdmAppParameterMap& app_parameters,
video_widevine_server::sdk::LicenseRequest* license_request);
template <typename T>
bool PrepareContentId(const CdmLicenseType license_type,
const std::string& request_id, T* content_id);
bool GetServiceCertificate(const CdmSessionId& session_id,
std::string* service_certificate);
CryptoSession* session_;
PolicyEngine* policy_engine_;
std::string server_url_;
@@ -79,6 +88,7 @@ class CdmLicense {
bool initialized_;
std::set<KeyId> loaded_keys_;
std::string provider_session_token_;
bool renew_with_client_id_;
// Used for certificate based licensing
CdmKeyMessage key_request_;

View File

@@ -177,6 +177,14 @@ enum CdmResponseType {
UNPROVISION_ERROR_4,
UNSUPPORTED_INIT_DATA,
USAGE_INFO_NOT_FOUND,
SERVICE_CERTIFICATE_REQUEST_GENERATE_ERROR,
PARSE_SERVICE_CERTIFICATE_ERROR,
SERVICE_CERTIFICATE_TYPE_ERROR,
CLIENT_ID_GENERATE_RANDOM_ERROR,
CLIENT_ID_AES_INIT_ERROR,
CLIENT_ID_AES_ENCRYPT_ERROR,
CLIENT_ID_RSA_INIT_ERROR,
CLIENT_ID_RSA_ENCRYPT_ERROR,
};
enum CdmKeyStatus {

View File

@@ -107,7 +107,7 @@ CdmResponseType CdmSession::RestoreOfflineSession(
key_set_id, &license_state, &offline_init_data_, &key_request_,
&key_response_, &offline_key_renewal_request_,
&offline_key_renewal_response_, &offline_release_server_url_,
&playback_start_time, &last_playback_time)) {
&playback_start_time, &last_playback_time, &app_parameters_)) {
LOGE("CdmSession::Init failed to retrieve license. key set id = %s",
key_set_id.c_str());
return GET_LICENSE_ERROR;
@@ -208,6 +208,7 @@ CdmResponseType CdmSession::GenerateKeyRequest(
return KEY_REQUEST_ERROR_1;
}
app_parameters_ = app_parameters;
if (!license_parser_->PrepareKeyRequest(init_data, license_type,
app_parameters, session_id_,
key_request, server_url)) {
@@ -361,8 +362,8 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
// session keys.
CdmResponseType CdmSession::GenerateRenewalRequest(CdmKeyMessage* key_request,
std::string* server_url) {
CdmResponseType status =
license_parser_->PrepareKeyUpdateRequest(true, key_request, server_url);
CdmResponseType status = license_parser_->PrepareKeyUpdateRequest(
true, app_parameters_, session_id_, key_request, server_url);
if (KEY_MESSAGE != status) return status;
@@ -389,8 +390,8 @@ CdmResponseType CdmSession::RenewKey(const CdmKeyResponse& key_response) {
CdmResponseType CdmSession::GenerateReleaseRequest(CdmKeyMessage* key_request,
std::string* server_url) {
is_release_ = true;
CdmResponseType status =
license_parser_->PrepareKeyUpdateRequest(false, key_request, server_url);
CdmResponseType status = license_parser_->PrepareKeyUpdateRequest(
false, app_parameters_, session_id_, key_request, server_url);
if (KEY_MESSAGE != status) return status;
@@ -499,7 +500,7 @@ bool CdmSession::StoreLicense(DeviceFiles::LicenseState state) {
key_set_id_, state, offline_init_data_, key_request_, key_response_,
offline_key_renewal_request_, offline_key_renewal_response_,
offline_release_server_url_, policy_engine_->GetPlaybackStartTime(),
policy_engine_->GetLastPlaybackTime());
policy_engine_->GetLastPlaybackTime(), app_parameters_);
}
bool CdmSession::DeleteLicense() {
@@ -507,7 +508,7 @@ bool CdmSession::DeleteLicense() {
return false;
if (!license_parser_->provider_session_token().empty()) {
if(crypto_session_->DeleteUsageInformation(
if (crypto_session_->DeleteUsageInformation(
license_parser_->provider_session_token()) != NO_ERROR) {
LOGE("CdmSession::DeleteLicense: error deleting usage info");
}
@@ -555,8 +556,8 @@ void CdmSession::GetApplicationId(std::string* app_id) {
CdmResponseType CdmSession::DeleteMultipleUsageInformation(
const std::vector<std::string>& provider_session_tokens) {
return crypto_session_
->DeleteMultipleUsageInformation(provider_session_tokens);
return crypto_session_->DeleteMultipleUsageInformation(
provider_session_tokens);
}
CdmResponseType CdmSession::UpdateUsageInformation() {

View File

@@ -27,6 +27,7 @@ using video_widevine_client::sdk::HashedFile;
using video_widevine_client::sdk::License;
using video_widevine_client::sdk::License_LicenseState_ACTIVE;
using video_widevine_client::sdk::License_LicenseState_RELEASING;
using video_widevine_client::sdk::NameValue;
using video_widevine_client::sdk::UsageInfo;
using video_widevine_client::sdk::UsageInfo_ProviderSession;
@@ -176,16 +177,14 @@ bool DeviceFiles::RemoveCertificate(const std::string& origin) {
return RemoveFile(GetCertificateFileName(origin));
}
bool DeviceFiles::StoreLicense(const std::string& key_set_id,
const LicenseState state,
const CdmInitData& pssh_data,
const CdmKeyMessage& license_request,
bool DeviceFiles::StoreLicense(
const std::string& key_set_id, const LicenseState state,
const CdmInitData& pssh_data, const CdmKeyMessage& license_request,
const CdmKeyResponse& license_message,
const CdmKeyMessage& license_renewal_request,
const CdmKeyResponse& license_renewal,
const std::string& release_server_url,
int64_t playback_start_time,
int64_t last_playback_time) {
const std::string& release_server_url, int64_t playback_start_time,
int64_t last_playback_time, const CdmAppParameterMap& app_parameters) {
if (!initialized_) {
LOGW("DeviceFiles::StoreLicense: not initialized");
return false;
@@ -218,6 +217,13 @@ bool DeviceFiles::StoreLicense(const std::string& key_set_id,
license->set_release_server_url(release_server_url);
license->set_playback_start_time(playback_start_time);
license->set_last_playback_time(last_playback_time);
NameValue* app_params;
for (CdmAppParameterMap::const_iterator iter = app_parameters.begin();
iter != app_parameters.end(); ++iter) {
app_params = license->add_app_parameters();
app_params->set_name(iter->first);
app_params->set_value(iter->second);
}
std::string serialized_file;
file.SerializeToString(&serialized_file);
@@ -230,7 +236,7 @@ bool DeviceFiles::RetrieveLicense(
CdmKeyMessage* license_request, CdmKeyResponse* license_message,
CdmKeyMessage* license_renewal_request, CdmKeyResponse* license_renewal,
std::string* release_server_url, int64_t* playback_start_time,
int64_t* last_playback_time) {
int64_t* last_playback_time, CdmAppParameterMap* app_parameters) {
if (!initialized_) {
LOGW("DeviceFiles::RetrieveLicense: not initialized");
return false;
@@ -285,6 +291,10 @@ bool DeviceFiles::RetrieveLicense(
*release_server_url = license.release_server_url();
*playback_start_time = license.playback_start_time();
*last_playback_time = license.last_playback_time();
for (int i = 0; i < license.app_parameters_size(); ++i) {
(*app_parameters)[license.app_parameters(i).name()] =
license.app_parameters(i).value();
}
return true;
}

View File

@@ -13,6 +13,11 @@ package video_widevine_client.sdk;
// need this if we are using libprotobuf-cpp-2.3.0-lite
option optimize_for = LITE_RUNTIME;
message NameValue {
optional string name = 1;
optional string value = 2;
}
message DeviceCertificate {
optional bytes certificate = 1;
optional bytes wrapped_private_key = 2;
@@ -33,6 +38,7 @@ message License {
optional bytes release_server_url = 7;
optional int64 playback_start_time = 8 [default = 0];
optional int64 last_playback_time = 9 [default = 0];
repeated NameValue app_parameters = 10;
}
message UsageInfo {

View File

@@ -129,7 +129,10 @@ static std::vector<CryptoKey> ExtractContentKeys(const License& license) {
}
CdmLicense::CdmLicense()
: session_(NULL), initialized_(false), clock_(new Clock()) {}
: session_(NULL),
initialized_(false),
renew_with_client_id_(false),
clock_(new Clock()) {}
CdmLicense::CdmLicense(Clock* clock) : session_(NULL), initialized_(false) {
if (NULL == clock) {
@@ -194,184 +197,23 @@ bool CdmLicense::PrepareKeyRequest(const InitializationData& init_data,
return false;
}
std::string service_certificate;
bool privacy_mode_enabled = Properties::UsePrivacyMode(session_id);
std::string serialized_service_certificate;
if (!Properties::GetServiceCertificate(session_id,
&serialized_service_certificate) ||
serialized_service_certificate.empty())
serialized_service_certificate = service_certificate_;
if (privacy_mode_enabled && serialized_service_certificate.empty()) {
if (privacy_mode_enabled) {
if (!GetServiceCertificate(session_id, &service_certificate)) {
stored_init_data_ = init_data.data();
return PrepareServiceCertificateRequest(signed_request, server_url);
}
}
std::string request_id;
session_->GenerateRequestId(&request_id);
LicenseRequest license_request;
ClientIdentification* client_id = license_request.mutable_client_id();
if (Properties::use_certificates_as_identification())
client_id->set_type(ClientIdentification::DEVICE_CERTIFICATE);
else
client_id->set_type(ClientIdentification::KEYBOX);
client_id->set_token(token_);
ClientIdentification_NameValue* client_info;
CdmAppParameterMap::const_iterator iter;
for (iter = app_parameters.begin(); iter != app_parameters.end(); iter++) {
client_info = client_id->add_client_info();
client_info->set_name(iter->first);
client_info->set_value(iter->second);
}
std::string value;
if (Properties::GetCompanyName(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kCompanyNameKey);
client_info->set_value(value);
}
if (Properties::GetModelName(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kModelNameKey);
client_info->set_value(value);
}
if (Properties::GetArchitectureName(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kArchitectureNameKey);
client_info->set_value(value);
}
if (Properties::GetDeviceName(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kDeviceNameKey);
client_info->set_value(value);
}
if (Properties::GetProductName(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kProductNameKey);
client_info->set_value(value);
}
if (Properties::GetBuildInfo(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kBuildInfoKey);
client_info->set_value(value);
}
if (session_->GetDeviceUniqueId(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kDeviceIdKey);
client_info->set_value(value);
}
if (Properties::GetWVCdmVersion(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kWVCdmVersionKey);
client_info->set_value(value);
}
ClientIdentification_ClientCapabilities* client_capabilities =
client_id->mutable_client_capabilities();
bool supports_usage_information;
if (session_->UsageInformationSupport(&supports_usage_information)) {
client_capabilities->set_session_token(supports_usage_information);
}
client_capabilities->set_anti_rollback_usage_table(
session_->IsAntiRollbackHwPresent());
uint32_t api_version = 0;
if (session_->GetApiVersion(&api_version)) {
client_capabilities->set_oem_crypto_api_version(api_version);
}
CryptoSession::HdcpCapability current_version, max_version;
if (session_->GetHdcpCapabilities(&current_version, &max_version)) {
switch (max_version) {
case HDCP_NONE:
client_capabilities->set_max_hdcp_version(
video_widevine_server::sdk::
ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_NONE);
break;
case HDCP_V1:
client_capabilities->set_max_hdcp_version(
video_widevine_server::sdk::
ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V1);
break;
case HDCP_V2:
client_capabilities->set_max_hdcp_version(
video_widevine_server::sdk::
ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2);
break;
case HDCP_V2_1:
client_capabilities->set_max_hdcp_version(
video_widevine_server::sdk::
ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2_1);
break;
case HDCP_V2_2:
client_capabilities->set_max_hdcp_version(
video_widevine_server::sdk::
ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2_2);
break;
case HDCP_NO_DIGITAL_OUTPUT:
client_capabilities->set_max_hdcp_version(
video_widevine_server::sdk::
ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_NO_DIGITAL_OUTPUT);
break;
default:
LOGW(
"CdmLicense::PrepareKeyRequest: unexpected HDCP max capability "
"version %d",
max_version);
}
}
if (privacy_mode_enabled) {
EncryptedClientIdentification* encrypted_client_id =
license_request.mutable_encrypted_client_id();
DeviceCertificate service_certificate;
if (!service_certificate.ParseFromString(serialized_service_certificate)) {
LOGE(
"CdmLicense::PrepareKeyRequest: unable to parse retrieved "
"service certificate");
return false;
}
if (service_certificate.type() !=
video_widevine_server::sdk::DeviceCertificate_CertificateType_SERVICE) {
LOGE(
"CdmLicense::PrepareKeyRequest: retrieved certificate not of type"
" service, %d",
service_certificate.type());
return false;
}
encrypted_client_id->set_service_id(service_certificate.service_id());
encrypted_client_id->set_service_certificate_serial_number(
service_certificate.serial_number());
std::string iv(KEY_IV_SIZE, 0);
std::string key(KEY_SIZE, 0);
if (!session_->GetRandom(key.size(), reinterpret_cast<uint8_t*>(&key[0]))) {
return false;
}
if (!session_->GetRandom(iv.size(), reinterpret_cast<uint8_t*>(&iv[0]))) {
return false;
}
std::string id, enc_id, enc_key;
client_id->SerializeToString(&id);
AesCbcKey aes;
if (!aes.Init(key)) return false;
if (!aes.Encrypt(id, &enc_id, &iv)) return false;
RsaPublicKey rsa;
if (!rsa.Init(service_certificate.public_key())) return false;
if (!rsa.Encrypt(key, &enc_key)) return false;
encrypted_client_id->set_encrypted_client_id_iv(iv);
encrypted_client_id->set_encrypted_privacy_key(enc_key);
encrypted_client_id->set_encrypted_client_id(enc_id);
license_request.clear_client_id();
}
CdmResponseType status =
PrepareClientId(privacy_mode_enabled, service_certificate, app_parameters,
&license_request);
if (NO_ERROR != status) return false;
// Content Identification may be a cenc_id, a webm_id or a license_id
LicenseRequest_ContentIdentification* content_id =
@@ -463,7 +305,9 @@ bool CdmLicense::PrepareKeyRequest(const InitializationData& init_data,
}
CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
bool is_renewal, CdmKeyMessage* signed_request, std::string* server_url) {
bool is_renewal, const CdmAppParameterMap& app_parameters,
const CdmSessionId& session_id, CdmKeyMessage* signed_request,
std::string* server_url) {
if (!initialized_) {
LOGE("CdmLicense::PrepareKeyUpdateRequest: not initialized");
return LICENSE_PARSER_NOT_INITIALIZED_1;
@@ -485,6 +329,22 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
license_request.set_request_time(clock_->GetCurrentTime());
if (renew_with_client_id_) {
std::string service_certificate;
bool privacy_mode_enabled = Properties::UsePrivacyMode(session_id);
if (privacy_mode_enabled) {
if (!GetServiceCertificate(session_id, &service_certificate)) {
return PrepareServiceCertificateRequest(signed_request, server_url)
? KEY_MESSAGE
: SERVICE_CERTIFICATE_REQUEST_GENERATE_ERROR;
}
}
CdmResponseType status =
PrepareClientId(privacy_mode_enabled, service_certificate,
app_parameters, &license_request);
if (NO_ERROR != status) return status;
}
LicenseRequest_ContentIdentification_ExistingLicense* current_license =
license_request.mutable_content_id()->mutable_license();
LicenseIdentification license_id = policy_engine_->license_id();
@@ -653,6 +513,10 @@ CdmResponseType CdmLicense::HandleKeyResponse(
policy_engine_->SetLicense(license);
if (license.policy().has_renew_with_client_id()) {
renew_with_client_id_ = license.policy().renew_with_client_id();
}
CdmResponseType resp = session_->LoadKeys(
signed_response.msg(), signed_response.signature(), mac_key_iv, mac_key,
key_array, provider_session_token_);
@@ -684,8 +548,19 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
return LICENSE_RESPONSE_PARSE_ERROR_2;
}
if (signed_response.type() == SignedMessage::ERROR_RESPONSE) {
switch (signed_response.type()) {
case SignedMessage::LICENSE:
break;
case SignedMessage::SERVICE_CERTIFICATE:
return CdmLicense::HandleServiceCertificateResponse(signed_response);
case SignedMessage::ERROR_RESPONSE:
return HandleKeyErrorResponse(signed_response);
default:
LOGE(
"CdmLicense::HandleKeyUpdateResponse: unrecognized signed message "
"type: %d",
signed_response.type());
return INVALID_LICENSE_TYPE;
}
if (!signed_response.has_signature()) {
@@ -708,6 +583,10 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
policy_engine_->UpdateLicense(license);
if (license.policy().has_renew_with_client_id()) {
renew_with_client_id_ = license.policy().renew_with_client_id();
}
if (!is_renewal) {
if (!license.id().has_provider_session_token()) return KEY_ADDED;
@@ -842,26 +721,31 @@ bool CdmLicense::RestoreLicenseForRelease(
SignedMessage signed_response;
if (!signed_response.ParseFromString(license_response)) {
LOGE("CdmLicense::RestoreLicenseForRelease: unable to parse signed license"
LOGE(
"CdmLicense::RestoreLicenseForRelease: unable to parse signed license"
" response");
return false;
}
if (SignedMessage::LICENSE != signed_response.type()) {
LOGE("CdmLicense::RestoreLicenseForRelease: unrecognized signed message "
"type: %d", signed_response.type());
LOGE(
"CdmLicense::RestoreLicenseForRelease: unrecognized signed message "
"type: %d",
signed_response.type());
return false;
}
if (!signed_response.has_signature()) {
LOGE("CdmLicense::RestoreLicenseForRelease: license response is not"
LOGE(
"CdmLicense::RestoreLicenseForRelease: license response is not"
" signed");
return false;
}
License license;
if (!license.ParseFromString(signed_response.msg())) {
LOGE("CdmLicense::RestoreLicenseForRelease: unable to parse license"
LOGE(
"CdmLicense::RestoreLicenseForRelease: unable to parse license"
" response");
return false;
}
@@ -994,6 +878,183 @@ CdmResponseType CdmLicense::HandleKeyErrorResponse(
}
}
CdmResponseType CdmLicense::PrepareClientId(
bool encrypt, const std::string& certificate,
const CdmAppParameterMap& app_parameters, LicenseRequest* license_request) {
ClientIdentification* client_id = license_request->mutable_client_id();
if (Properties::use_certificates_as_identification())
client_id->set_type(ClientIdentification::DEVICE_CERTIFICATE);
else
client_id->set_type(ClientIdentification::KEYBOX);
client_id->set_token(token_);
ClientIdentification_NameValue* client_info;
CdmAppParameterMap::const_iterator iter;
for (iter = app_parameters.begin(); iter != app_parameters.end(); iter++) {
client_info = client_id->add_client_info();
client_info->set_name(iter->first);
client_info->set_value(iter->second);
}
std::string value;
if (Properties::GetCompanyName(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kCompanyNameKey);
client_info->set_value(value);
}
if (Properties::GetModelName(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kModelNameKey);
client_info->set_value(value);
}
if (Properties::GetArchitectureName(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kArchitectureNameKey);
client_info->set_value(value);
}
if (Properties::GetDeviceName(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kDeviceNameKey);
client_info->set_value(value);
}
if (Properties::GetProductName(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kProductNameKey);
client_info->set_value(value);
}
if (Properties::GetBuildInfo(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kBuildInfoKey);
client_info->set_value(value);
}
if (session_->GetDeviceUniqueId(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kDeviceIdKey);
client_info->set_value(value);
}
if (Properties::GetWVCdmVersion(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kWVCdmVersionKey);
client_info->set_value(value);
}
ClientIdentification_ClientCapabilities* client_capabilities =
client_id->mutable_client_capabilities();
bool supports_usage_information;
if (session_->UsageInformationSupport(&supports_usage_information)) {
client_capabilities->set_session_token(supports_usage_information);
}
client_capabilities->set_anti_rollback_usage_table(
session_->IsAntiRollbackHwPresent());
uint32_t api_version = 0;
if (session_->GetApiVersion(&api_version)) {
client_capabilities->set_oem_crypto_api_version(api_version);
}
CryptoSession::HdcpCapability current_version, max_version;
if (session_->GetHdcpCapabilities(&current_version, &max_version)) {
switch (max_version) {
case HDCP_NONE:
client_capabilities->set_max_hdcp_version(
video_widevine_server::sdk::
ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_NONE);
break;
case HDCP_V1:
client_capabilities->set_max_hdcp_version(
video_widevine_server::sdk::
ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V1);
break;
case HDCP_V2:
client_capabilities->set_max_hdcp_version(
video_widevine_server::sdk::
ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2);
break;
case HDCP_V2_1:
client_capabilities->set_max_hdcp_version(
video_widevine_server::sdk::
ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2_1);
break;
case HDCP_V2_2:
client_capabilities->set_max_hdcp_version(
video_widevine_server::sdk::
ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2_2);
break;
case HDCP_NO_DIGITAL_OUTPUT:
client_capabilities->set_max_hdcp_version(
video_widevine_server::sdk::
ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_NO_DIGITAL_OUTPUT);
break;
default:
LOGW(
"CdmLicense::PrepareClientId: unexpected HDCP max capability "
"version %d",
max_version);
}
}
if (encrypt) {
EncryptedClientIdentification* encrypted_client_id =
license_request->mutable_encrypted_client_id();
DeviceCertificate service_certificate;
if (!service_certificate.ParseFromString(certificate)) {
LOGE(
"CdmLicense::PrepareClientId: unable to parse retrieved "
"service certificate");
return PARSE_SERVICE_CERTIFICATE_ERROR;
}
if (service_certificate.type() !=
video_widevine_server::sdk::DeviceCertificate_CertificateType_SERVICE) {
LOGE(
"CdmLicense::PrepareClientId: retrieved certificate not of type"
" service, %d",
service_certificate.type());
return SERVICE_CERTIFICATE_TYPE_ERROR;
}
encrypted_client_id->set_service_id(service_certificate.service_id());
encrypted_client_id->set_service_certificate_serial_number(
service_certificate.serial_number());
std::string iv(KEY_IV_SIZE, 0);
std::string key(KEY_SIZE, 0);
if (!session_->GetRandom(key.size(), reinterpret_cast<uint8_t*>(&key[0])))
return CLIENT_ID_GENERATE_RANDOM_ERROR;
if (!session_->GetRandom(iv.size(), reinterpret_cast<uint8_t*>(&iv[0])))
return CLIENT_ID_GENERATE_RANDOM_ERROR;
std::string id, enc_id, enc_key;
client_id->SerializeToString(&id);
AesCbcKey aes;
if (!aes.Init(key)) return CLIENT_ID_AES_INIT_ERROR;
if (!aes.Encrypt(id, &enc_id, &iv)) return CLIENT_ID_AES_ENCRYPT_ERROR;
RsaPublicKey rsa;
if (!rsa.Init(service_certificate.public_key()))
return CLIENT_ID_RSA_INIT_ERROR;
if (!rsa.Encrypt(key, &enc_key)) return CLIENT_ID_RSA_ENCRYPT_ERROR;
encrypted_client_id->set_encrypted_client_id_iv(iv);
encrypted_client_id->set_encrypted_privacy_key(enc_key);
encrypted_client_id->set_encrypted_client_id(enc_id);
license_request->clear_client_id();
}
return NO_ERROR;
}
bool CdmLicense::GetServiceCertificate(const CdmSessionId& session_id,
std::string* service_certificate) {
if (!Properties::GetServiceCertificate(session_id, service_certificate) ||
service_certificate->empty())
*service_certificate = service_certificate_;
if (service_certificate->size() > 0) return true;
return false;
}
template <typename T>
bool CdmLicense::PrepareContentId(const CdmLicenseType license_type,
const std::string& request_id,

View File

@@ -78,6 +78,10 @@ message License {
// Indicates that the license shall be sent for renewal when usage is
// started.
optional bool renew_with_usage = 11 [default = false];
// Indicates to client that license renewal and release requests ought to
// include ClientIdentification (client_id).
optional bool renew_with_client_id = 12 [default = false];
}
message KeyContainer {
@@ -167,6 +171,8 @@ message License {
optional KeyType type = 4;
optional SecurityLevel level = 5 [default = SW_SECURE_CRYPTO];
optional OutputProtection required_protection = 6;
// NOTE: Use of requested_protection is not recommended as it is only
// supported on a small number of platforms.
optional OutputProtection requested_protection = 7;
optional KeyControl key_control = 8;
optional OperatorSessionKeyPermissions operator_session_key_permissions = 9;
@@ -174,7 +180,13 @@ message License {
// content being decrypted/decoded falls within one of the specified ranges,
// the optional required_protections may be applied. Otherwise an error will
// be reported.
// NOTE: Use of this feature is not recommended, as it is only supported on
// a small number of platforms.
repeated VideoResolutionConstraint video_resolution_constraints = 10;
// Optional flag to indicate the key must only be used if the client
// supports anti rollback of the user table. Content provider can query the
// client capabilities to determine if the client support this feature.
optional bool anti_rollback_usage_table = 11 [default = false];
}
optional LicenseIdentification id = 1;
@@ -286,36 +298,6 @@ message SignedMessage {
optional RemoteAttestation remote_attestation = 5;
}
// This message is used to pass optional data on initial license issuance.
message SessionInit {
optional bytes session_id = 1;
optional bytes purchase_id = 2;
// master_signing_key should be 128 bits in length.
optional bytes master_signing_key = 3;
// signing_key should be 512 bits in length to be split into two
// (server || client) HMAC-SHA256 keys.
optional bytes signing_key = 4;
optional int64 license_start_time = 5;
// Client token for the session. This session is for use by the license
// provider, and is akin to a client cookie. It will be copied to
// License::provider_client_token, and sent back by the client in
// ClientIdentification::provider_client_token in all license requests
// thereafter.
optional bytes provider_client_token = 6;
// Session token for the session. This token is for use by the license
// provider, and is akin to a session cookie. It will be copied to
// LicenseIdentfication::provider_session_token, and sent back in all
// license renewal and release requests for the session thereafter.
optional bytes provider_session_token = 7;
}
// This message is used by the server to preserve and restore session state.
message SessionState {
optional LicenseIdentification license_id = 1;
optional bytes signing_key = 2;
optional uint32 keybox_system_id = 3;
}
// ----------------------------------------------------------------------------
// certificate_provisioning.proto
// ----------------------------------------------------------------------------

View File

@@ -5,7 +5,8 @@
namespace {
const std::string kWidevineKeySystem = "com.widevine.alpha";
// Content Protection license server data
// Content Protection license server (UAT) data
// For staging server replace url with http://wv-staging-proxy.appspot.com/proxy
const std::string kCpLicenseServer = "http://widevine-proxy.appspot.com/proxy";
const std::string kCpClientAuth = "";
const std::string kCpKeyId =

View File

@@ -130,6 +130,7 @@ struct LicenseInfo {
std::string key_release_url;
int64_t playback_start_time;
int64_t last_playback_time;
std::string app_parameters;
std::string file_data;
};
@@ -236,7 +237,7 @@ LicenseInfo license_test_data[] = {
"0112001A16200342120A106B63746C0000000000ECDCBE0000000020DBDF"
"A68F051A20182F029E35047A3841FA176C74E5B387350E8D58DEA6878FF0"
"BEA6CABACA1C2C"),
"https://test.google.com/license/GetCencLicense", 0x0, 0x0,
"https://test.google.com/license/GetCencLicense", 0x0, 0x0, "",
wvcdm::a2bs_hex(
"0AA8150802100122A1150801121408011210303132333435363738394142434445461"
"A9D0E080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591BC4D0"
@@ -417,8 +418,9 @@ LicenseInfo license_test_data[] = {
"A68F051A20BDA6A56F7CBFD0942198F87C23A34AA5CBD64AFEB134277774"
"CCF8E789D815DD"),
"https://test.google.com/license/GetCencLicense", 0x12345678, 0x12348765,
"Name1 Value1",
wvcdm::a2bs_hex(
"0AB0150802100122A9150802121408011210303132333435363738394142434445461"
"0AC1150802100122BA150802121408011210303132333435363738394142434445461"
"A9D0E080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591BC4D0"
"7A7D507618A5D3A68F05228E023082010A0282010100A947904B8DBD55FB685FDB302"
"5574517CCCC74EE4FEAF6629D5179A52FF85CE7409528EFFA0E5DFC3DE9A34BA5F08B"
@@ -497,8 +499,8 @@ LicenseInfo license_test_data[] = {
"106B63746C00000000CA3A6A75000000002083E5A68F051A20BDA6A56F7CBFD094219"
"8F87C23A34AA5CBD64AFEB134277774CCF8E789D815DD3A2E68747470733A2F2F7465"
"73742E676F6F676C652E636F6D2F6C6963656E73652F47657443656E634C6963656E7"
"36540F8ACD1910148E58ED291011220C47DDCB3FA0DF569B95DD9F46F83608632C93E"
"E0EA5C9360D7D537730D028EC6")},
"36540F8ACD1910148E58ED29101520F0A054E616D6531120656616C7565311220BE69"
"AAB25B481BCAF57B741518D9F9DB8E3A7A6911D10C53D4F4649D78393C65")},
// license 2
{"ksidE8C37662C88DC673", DeviceFiles::kLicenseStateReleasing,
@@ -597,9 +599,9 @@ LicenseInfo license_test_data[] = {
"A68F051A2041EF0A9267D613D17AA90E1D1DA5BE091860E5E296D41D6D0F"
"75E73660C279B3"),
"https://test.google.com/license/GetCencLicense", 0x0123456789abcdef,
0x123456789abfedc,
0x123456789abfedc, "Name1 Value1 Name2 Param2",
wvcdm::a2bs_hex(
"0AB8150802100122B1150802121408011210303132333435363738394142434445461"
"0AE7150802100122E0150802121408011210303132333435363738394142434445461"
"A9D0E080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591BC4D0"
"7A7D507618A5D3A68F05228E023082010A0282010100A947904B8DBD55FB685FDB302"
"5574517CCCC74EE4FEAF6629D5179A52FF85CE7409528EFFA0E5DFC3DE9A34BA5F08B"
@@ -678,8 +680,10 @@ LicenseInfo license_test_data[] = {
"106B63746C000000001FF4944E000000002082E7A68F051A2041EF0A9267D613D17AA"
"90E1D1DA5BE091860E5E296D41D6D0F75E73660C279B33A2E68747470733A2F2F7465"
"73742E676F6F676C652E636F6D2F6C6963656E73652F47657443656E634C6963656E7"
"36540EF9BAFCDF8ACD1910148DCFDAFCDF8ACD1910112201486F63DAF90694D3C63C8"
"EA8D2B68A7592252154A193D4DF8CEA95635EA0543")}};
"36540EF9BAFCDF8ACD1910148DCFDAFCDF8ACD1910152150A054E616D6531120C5661"
"6C756531204E616D653252160A0C4E616D653220506172616D321206506172616D321"
"2203653BA57F16FE28D66D9F7A76128B7AD7F33680815FF70A3684617DE1FBB0F9"
"F")}};
// Sample license data and related data for storage and use for offline
// playback. The license data and URLs in this test are not real.
@@ -782,7 +786,7 @@ LicenseInfo license_update_test_data[] = {
"B68F051A2000351030900858FCFD6977B67803ADFD1280AA661E6B0BD30B"
"08B2C467355129"),
"https://test.google.com/license/GetCencLicense", 0x0123456789abcdef,
0x123456789abfedc,
0x123456789abfedc, "Name1 Value1 Name2 Value2 Name3 Value3",
wvcdm::a2bs_hex(
"0AB8150802100122B1150801121408011210303132333435363738394142434445461"
"A9D0E080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591BC4D0"
@@ -867,7 +871,7 @@ LicenseInfo license_update_test_data[] = {
"126C3222C2E584A50D08EFA75BC4FC091E7034E1DD")},
// license being released. all fields are identical except for license
// state and hashed file data
{"", DeviceFiles::kLicenseStateReleasing, "", "", "", "", "", "", 0, 0,
{"", DeviceFiles::kLicenseStateReleasing, "", "", "", "", "", "", 0, 0, "",
wvcdm::a2bs_hex(
"0AB8150802100122B1150802121408011210303132333435363738394142434445461"
"A9D0E080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591BC4D0"
@@ -951,6 +955,190 @@ LicenseInfo license_update_test_data[] = {
"36540EF9BAFCDF8ACD1910148DCFDAFCDF8ACD1910112203D8933A735A22FE27AA956"
"802B597529E8FFCB91A5F3CBBB3CE0C38E4AF3DC88")}};
// Application parameters were added to the License message. This data
// is used to verify that a License saved without application parameters can
// be read out correctly by an updated version of the CDM.
LicenseInfo license_app_parameters_backwards_compatibility_test_data = {
"ksid54C57C966E23CEF5", DeviceFiles::kLicenseStateActive,
wvcdm::a2bs_hex("0801121030313233343536373839414243444546"),
wvcdm::a2bs_hex(
"080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591B"
"C4D07A7D507618A5D3A68F05228E023082010A0282010100A947904B8DBD"
"55FB685FDB3025574517CCCC74EE4FEAF6629D5179A52FF85CE7409528EF"
"FA0E5DFC3DE9A34BA5F08BE349553C319A9FB274905A8770ADC9CA4A2CBC"
"D8E556A1587FA18BFD4D286C644A6904F19EAAFBDFADD3B371B306D0B289"
"F459B491C814B5AD1F747610E990A60248A7DA5152F1CCFC047EF4230013"
"1F9C4758F4D9F30579393B860AAD9AD2EE43D721D6DB9F5800EF188386B9"
"4825AE05A883AC976D6970DF43EA6C83B86CE6D0F540207725B9890FCCEC"
"83A49027872DAFD2740B7748E9C3B1752D6F12859CED07E8882969B433EC"
"66F17FFC29AC6FDBEA79230B0FAED5D94CF6B829A420BBE3270323941776"
"EE60DD6BFD660BDDCA870203010001288001300112800250D1F8B1ECF849"
"B60FF93E37C4DEEF09E6FFB10BCFC996A4A24B7AA96928835ED5A72E1584"
"6D0A14015733239BD8B6E6D5E5D229B08394CE1E0692C159C44337CA7CAF"
"88476449B068D9D2FADED8EB1BC0F4B8F0FCAF293E8690E7403209534180"
"3408A0E8279E545945EE97838FDE7812F7171C3CC4F5ECF9418BBF1D336C"
"E58F4CBB1B44D4ADE6BF3364BAE7EC093281846E569E13E7719014030A60"
"59044FE7BBFF3E8F5723AEDD54DC6E0D041B309D7700B55575690E95CE60"
"85D0914F991C5F45E98CBB9C45BA33F47FD0862EBCC7EEBA8E60643C86E8"
"5476B18AEF8DE871571A75681A75F75028A5B58751C09A5296AAE99CEDCD"
"9785E9E2103240D40A1AB6050AB002080112102CE5CCF42200D6B5BCCF33"
"D7CC2D9C7018EAD1B88D05228E023082010A0282010100BE1B661EEC4700"
"DF4B0C83292D02AE029B8A224DD3048125049F74E30E1257FC2BE8D9CFAF"
"0BFFCACAF7305351771C78FA451F13AF5EEBFB360941A4396A805833730D"
"C6E534C62408B7C5076FC22568021C59ED34F98487196DA32078DAFCA37C"
"7CFB8E79612FA384963DF2167D5E87305D7BC92D621C10160672C27B9A69"
"1B1534F60D78C5893E40C5FF8A3F9DF8898612E9A5CCB56F4A0CC2A61A7A"
"EB04A9DCC015D9BC37DEF2AB9EAA9AAFD838869081D9249755F129BB0DBE"
"CA3B894975A65A36FD005CE77CD407E925D3172E33122A11D327968A08F8"
"E771FAEB2540EB52D17C4906405F47C31F60F0AF6C78AF53291B236E692B"
"506A2AF92AF43E3A81020301000128800130011280033A08A60418E5C81B"
"8D71A5C0A28C26999FF4FA992E14107CA8A9E6A2B36259834000FE35DCD8"
"14426F9C5D332418ED94C9C0C992217B1B6DC01C99085A3C3956C8267B87"
"73BABCF3F2C841C67D830F9DBC780DD68BF4E2FE424C6A54123BE4B2A1F7"
"E1F4DB58AB1164DAE9CF75C3392284A44B8CDB85D837E86C6B908243987E"
"552C8693878C9A1B7BEA3759783036F1595C406D6CBBA7F8642A9B3B244D"
"AA1F00531D0B908ADE4B533FD9FAFA21D0FB0C033D2AD5DDF24C60F4FAC3"
"0820758877F2E1A78EB44E9336DCFAFDF572BB22A84A5DEFDF2EB87B61DE"
"26EE9C4CEAA646A2AFDB2BB953845E6D7FE6F79A9501D1C379C96961316B"
"5D2A66F38C222091AF74141B6CAF93507485A5D8F82808025451824F00C8"
"B6A0CD5803F6564584138C8B18BC679B442D837307B5CC90B1FD1FD32288"
"B4A5D18D2D80E5E6A7A9EFD255B8B363038BCC67AF534EAEE4A5903E304E"
"ED4990BB5BE735DB027A6DE35329D321EC051B956C55A5B11674017517FC"
"C3C7FF7397C13A7B7087A1F6AEC7F6761A130A0C636F6D70616E795F6E61"
"6D6512034C47451A150A0A6D6F64656C5F6E616D6512074E657875732034"
"1A200A116172636869746563747572655F6E616D65120B61726D65616269"
"2D7637611A130A0B6465766963655F6E616D6512046D616B6F1A150A0C70"
"726F647563745F6E616D6512056F6363616D1A440A0A6275696C645F696E"
"666F1236676F6F676C652F6F6363616D2F6D616B6F3A342E332F4A425F4D"
"52322F3731343239313A7573657264656275672F6465762D6B6579731A21"
"0A096465766963655F696412144C474D4332303132313030353030363339"
"32373812250A230A14080112103031323334353637383941424344454610"
"021A09393837363534333231180120002A0C333934303739343733370000"
"30151A8002734FBDED946EB74A1B61811C4C4A491214F6BEA125A80F0141"
"65B28AA97AD0AF60E4D129EB7F424AD659F24E5EED4B702BEE328E38B72C"
"A6F38CD0ECFD2E6D7B98147744C9B8A9610B3BDFE17675FF7D584C5BF680"
"64B0FE513FC322C9148795E4C2F2443C3024F5C1F29E6FEFB6D77005DAB2"
"2CD2B63131908DE4D88795BB931CEA38452CC568BE25032245E372F07A12"
"97F51748C7EA02F2C88360AFE7ABBC71DCDD5366126258E5AFA27C2A20B3"
"39FA1E7AE925B494B361F6F7116F20BE8EE6E446146027F4FD4300F4A0B0"
"A3361EE34925F338D0AACF20AE919B4BAE81C1D57A8D2B8FA38732A57697"
"C316C180717C182A971C94E4AC4C7DF8F161CB8CC1"),
wvcdm::a2bs_hex(
"080212CC020A190A0939383736353433323112084B9F26DAB8B06E112002"
"2800124108011801301E4239687474703A2F2F6B69723033666370673137"
"342E7769646576696E652E6E65742F7769646576696E652F6367692D6269"
"6E2F64726D2E6367691A6612102531DFD6CCEA511D00F8C0172F1189AA1A"
"5057FF9D9DBD5A205B1DEB075E4A90467C1E074CDE6071BFF831AD590BD5"
"D117614F33CE2C3CE1824FC0D54B36ECEAE58DF5C8F9347C2FEED17A3327"
"E8F52B8ECA6313A1FA6A042EB9525DD328113C05F920011A7E0A10303132"
"3334353637383941424344454612106D23622142B58F6D1EDD33AF3ECD2C"
"7E1A20884EE13BEA9DECDDBF68B532131C82B11CEC4D23C7FA9F3EF4C5EE"
"172E7C9736200242340A2050BFE71BB1BA683E35E0B49BB33048E5103FBB"
"B9C3E1CD6EBCDA7DD485DBAF431210D69D6F14C95CB6CFDB998E50D00F4D"
"A020DBDFA68F051A20AE5D6895E70F86F42F5FE3C58A505A865D05AB94B1"
"ABAA6CC59C3322F61C458D228002331F2BE95B5C796E0921CC27A7295501"
"DA10044E5CA36C0E2866FF068EA3515A6786BD5D60D74D80C6BA8BE6AAD0"
"85AF967909A143171E9CDDE36EA528402867CD04FB6F97A150CDE55F9B81"
"9F4104BEF48E4280D76645569E10AEF524D34D865B5B9E3EBC66C45EEBBE"
"16AB04493E7AEC4F99E7A99F3FC08FA431BECCC1978A079FA4801DB75E13"
"29A9921604E6F80CB148AA2DD5C8348057E9F4FC2AEA57EA4D215D0A8D48"
"6294860DFB4F4C42D57D9542B76179E179DD4AA23F9F7B2AE432B39E4CE8"
"F156E84877DDA781AAAAFC797FF75AFE2019ADC3A2E419BF0253C705BD47"
"97A96866AC4C059AD8F2E9C6B617C60C6ADCDB894C25F0C7D29252F52FD5"),
wvcdm::a2bs_hex(
"08011231121D1A1B0A190A0939383736353433323112084B9F26DAB8B06E"
"112002280018022A0C31353532333030360000000030151A20C30375683C"
"4D2033E05DCC95DDFB278CFB5125A021C3C043A16ACC933A768A27"),
wvcdm::a2bs_hex(
"0802123B0A190A0939383736353433323112084B9F26DAB8B06E11200228"
"0112001A16200342120A106B63746C0000000000ECDCBE0000000020DBDF"
"A68F051A20182F029E35047A3841FA176C74E5B387350E8D58DEA6878FF0"
"BEA6CABACA1C2C"),
"https://test.google.com/license/GetCencLicense", 0x0, 0x0, "",
wvcdm::a2bs_hex(
"0AA8150802100122A1150801121408011210303132333435363738394142434445461"
"A9D0E080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591BC4D0"
"7A7D507618A5D3A68F05228E023082010A0282010100A947904B8DBD55FB685FDB302"
"5574517CCCC74EE4FEAF6629D5179A52FF85CE7409528EFFA0E5DFC3DE9A34BA5F08B"
"E349553C319A9FB274905A8770ADC9CA4A2CBCD8E556A1587FA18BFD4D286C644A690"
"4F19EAAFBDFADD3B371B306D0B289F459B491C814B5AD1F747610E990A60248A7DA51"
"52F1CCFC047EF42300131F9C4758F4D9F30579393B860AAD9AD2EE43D721D6DB9F580"
"0EF188386B94825AE05A883AC976D6970DF43EA6C83B86CE6D0F540207725B9890FCC"
"EC83A49027872DAFD2740B7748E9C3B1752D6F12859CED07E8882969B433EC66F17FF"
"C29AC6FDBEA79230B0FAED5D94CF6B829A420BBE3270323941776EE60DD6BFD660BDD"
"CA870203010001288001300112800250D1F8B1ECF849B60FF93E37C4DEEF09E6FFB10"
"BCFC996A4A24B7AA96928835ED5A72E15846D0A14015733239BD8B6E6D5E5D229B083"
"94CE1E0692C159C44337CA7CAF88476449B068D9D2FADED8EB1BC0F4B8F0FCAF293E8"
"690E74032095341803408A0E8279E545945EE97838FDE7812F7171C3CC4F5ECF9418B"
"BF1D336CE58F4CBB1B44D4ADE6BF3364BAE7EC093281846E569E13E7719014030A605"
"9044FE7BBFF3E8F5723AEDD54DC6E0D041B309D7700B55575690E95CE6085D0914F99"
"1C5F45E98CBB9C45BA33F47FD0862EBCC7EEBA8E60643C86E85476B18AEF8DE871571"
"A75681A75F75028A5B58751C09A5296AAE99CEDCD9785E9E2103240D40A1AB6050AB0"
"02080112102CE5CCF42200D6B5BCCF33D7CC2D9C7018EAD1B88D05228E023082010A0"
"282010100BE1B661EEC4700DF4B0C83292D02AE029B8A224DD3048125049F74E30E12"
"57FC2BE8D9CFAF0BFFCACAF7305351771C78FA451F13AF5EEBFB360941A4396A80583"
"3730DC6E534C62408B7C5076FC22568021C59ED34F98487196DA32078DAFCA37C7CFB"
"8E79612FA384963DF2167D5E87305D7BC92D621C10160672C27B9A691B1534F60D78C"
"5893E40C5FF8A3F9DF8898612E9A5CCB56F4A0CC2A61A7AEB04A9DCC015D9BC37DEF2"
"AB9EAA9AAFD838869081D9249755F129BB0DBECA3B894975A65A36FD005CE77CD407E"
"925D3172E33122A11D327968A08F8E771FAEB2540EB52D17C4906405F47C31F60F0AF"
"6C78AF53291B236E692B506A2AF92AF43E3A81020301000128800130011280033A08A"
"60418E5C81B8D71A5C0A28C26999FF4FA992E14107CA8A9E6A2B36259834000FE35DC"
"D814426F9C5D332418ED94C9C0C992217B1B6DC01C99085A3C3956C8267B8773BABCF"
"3F2C841C67D830F9DBC780DD68BF4E2FE424C6A54123BE4B2A1F7E1F4DB58AB1164DA"
"E9CF75C3392284A44B8CDB85D837E86C6B908243987E552C8693878C9A1B7BEA37597"
"83036F1595C406D6CBBA7F8642A9B3B244DAA1F00531D0B908ADE4B533FD9FAFA21D0"
"FB0C033D2AD5DDF24C60F4FAC30820758877F2E1A78EB44E9336DCFAFDF572BB22A84"
"A5DEFDF2EB87B61DE26EE9C4CEAA646A2AFDB2BB953845E6D7FE6F79A9501D1C379C9"
"6961316B5D2A66F38C222091AF74141B6CAF93507485A5D8F82808025451824F00C8B"
"6A0CD5803F6564584138C8B18BC679B442D837307B5CC90B1FD1FD32288B4A5D18D2D"
"80E5E6A7A9EFD255B8B363038BCC67AF534EAEE4A5903E304EED4990BB5BE735DB027"
"A6DE35329D321EC051B956C55A5B11674017517FCC3C7FF7397C13A7B7087A1F6AEC7"
"F6761A130A0C636F6D70616E795F6E616D6512034C47451A150A0A6D6F64656C5F6E6"
"16D6512074E6578757320341A200A116172636869746563747572655F6E616D65120B"
"61726D656162692D7637611A130A0B6465766963655F6E616D6512046D616B6F1A150"
"A0C70726F647563745F6E616D6512056F6363616D1A440A0A6275696C645F696E666F"
"1236676F6F676C652F6F6363616D2F6D616B6F3A342E332F4A425F4D52322F3731343"
"239313A7573657264656275672F6465762D6B6579731A210A096465766963655F6964"
"12144C474D433230313231303035303036333932373812250A230A140801121030313"
"23334353637383941424344454610021A09393837363534333231180120002A0C3339"
"3430373934373337000030151A8002734FBDED946EB74A1B61811C4C4A491214F6BEA"
"125A80F014165B28AA97AD0AF60E4D129EB7F424AD659F24E5EED4B702BEE328E38B7"
"2CA6F38CD0ECFD2E6D7B98147744C9B8A9610B3BDFE17675FF7D584C5BF68064B0FE5"
"13FC322C9148795E4C2F2443C3024F5C1F29E6FEFB6D77005DAB22CD2B63131908DE4"
"D88795BB931CEA38452CC568BE25032245E372F07A1297F51748C7EA02F2C88360AFE"
"7ABBC71DCDD5366126258E5AFA27C2A20B339FA1E7AE925B494B361F6F7116F20BE8E"
"E6E446146027F4FD4300F4A0B0A3361EE34925F338D0AACF20AE919B4BAE81C1D57A8"
"D2B8FA38732A57697C316C180717C182A971C94E4AC4C7DF8F161CB8CC122F6040802"
"12CC020A190A0939383736353433323112084B9F26DAB8B06E1120022800124108011"
"801301E4239687474703A2F2F6B69723033666370673137342E7769646576696E652E"
"6E65742F7769646576696E652F6367692D62696E2F64726D2E6367691A6612102531D"
"FD6CCEA511D00F8C0172F1189AA1A5057FF9D9DBD5A205B1DEB075E4A90467C1E074C"
"DE6071BFF831AD590BD5D117614F33CE2C3CE1824FC0D54B36ECEAE58DF5C8F9347C2"
"FEED17A3327E8F52B8ECA6313A1FA6A042EB9525DD328113C05F920011A7E0A103031"
"323334353637383941424344454612106D23622142B58F6D1EDD33AF3ECD2C7E1A208"
"84EE13BEA9DECDDBF68B532131C82B11CEC4D23C7FA9F3EF4C5EE172E7C9736200242"
"340A2050BFE71BB1BA683E35E0B49BB33048E5103FBBB9C3E1CD6EBCDA7DD485DBAF4"
"31210D69D6F14C95CB6CFDB998E50D00F4DA020DBDFA68F051A20AE5D6895E70F86F4"
"2F5FE3C58A505A865D05AB94B1ABAA6CC59C3322F61C458D228002331F2BE95B5C796"
"E0921CC27A7295501DA10044E5CA36C0E2866FF068EA3515A6786BD5D60D74D80C6BA"
"8BE6AAD085AF967909A143171E9CDDE36EA528402867CD04FB6F97A150CDE55F9B819"
"F4104BEF48E4280D76645569E10AEF524D34D865B5B9E3EBC66C45EEBBE16AB04493E"
"7AEC4F99E7A99F3FC08FA431BECCC1978A079FA4801DB75E1329A9921604E6F80CB14"
"8AA2DD5C8348057E9F4FC2AEA57EA4D215D0A8D486294860DFB4F4C42D57D9542B761"
"79E179DD4AA23F9F7B2AE432B39E4CE8F156E84877DDA781AAAAFC797FF75AFE2019A"
"DC3A2E419BF0253C705BD4797A96866AC4C059AD8F2E9C6B617C60C6ADCDB894C25F0"
"C7D29252F52FD52A5708011231121D1A1B0A190A0939383736353433323112084B9F2"
"6DAB8B06E112002280018022A0C31353532333030360000000030151A20C30375683C"
"4D2033E05DCC95DDFB278CFB5125A021C3C043A16ACC933A768A2732610802123B0A1"
"90A0939383736353433323112084B9F26DAB8B06E112002280112001A16200342120A"
"106B63746C0000000000ECDCBE0000000020DBDFA68F051A20182F029E35047A3841F"
"A176C74E5B387350E8D58DEA6878FF0BEA6CABACA1C2C3A2E68747470733A2F2F7465"
"73742E676F6F676C652E636F6D2F6C6963656E73652F47657443656E634C6963656E7"
"365400048001220CD0599C2B85D9F2D573AC7893CE77CB5A10B326828BA8C89047505"
"A8C9B606AC")};
struct UsageInfo {
std::string provider_session_token;
std::string license_request;
@@ -1276,6 +1464,25 @@ class DeviceFilesTest : public ::testing::Test {
data.key_release_url.size() + 2 * sizeof(int64_t);
}
CdmAppParameterMap GetAppParameters(std::string str) {
CdmAppParameterMap app_parameters;
size_t start_pos = 0;
size_t len = str.length();
bool more = true;
while (start_pos < len) {
size_t name_end_pos = str.find(' ', start_pos);
if (name_end_pos == std::string::npos) return app_parameters;
if (name_end_pos + 1 >= len) return app_parameters;
size_t value_end_pos = str.find(' ', name_end_pos + 1);
app_parameters[str.substr(start_pos, name_end_pos)] =
str.substr(name_end_pos + 1, value_end_pos);
if (value_end_pos == std::string::npos || value_end_pos + 1 >= len)
return app_parameters;
start_pos = value_end_pos + 1;
}
return app_parameters;
}
std::string device_base_path_;
};
@@ -1284,8 +1491,7 @@ class DeviceFilesStoreTest : public DeviceFilesTest,
struct CertStorageVariant {
CertStorageVariant(bool dir_exists_value, const std::string& origin_value)
: dir_exists(dir_exists_value),
origin(origin_value) {}
: dir_exists(dir_exists_value), origin(origin_value) {}
const bool dir_exists;
const std::string origin;
@@ -1344,6 +1550,32 @@ MATCHER_P6(Contains, str1, str2, str3, str4, str5, str6, "") {
data.find(str6) != std::string::npos);
}
MATCHER_P7(Contains, str1, str2, str3, str4, str5, str6, map7, "") {
// Estimating the length of data. We can have gmock provide length
// as well as pointer to data but that will introduce a dependency on tr1
size_t map7_len = 0;
CdmAppParameterMap::const_iterator itr = map7.begin();
for (itr = map7.begin(); itr != map7.end(); ++itr) {
map7_len += itr->first.length();
map7_len += itr->second.length();
}
std::string data(arg, str1.size() + str2.size() + str3.size() + str4.size() +
str5.size() + str6.size() + map7_len +
kProtobufEstimatedOverhead);
bool map7_entries_present = true;
for (itr = map7.begin(); itr != map7.end(); ++itr) {
map7_entries_present = map7_entries_present &&
data.find(itr->first) != std::string::npos &&
data.find(itr->second) != std::string::npos;
}
return (data.find(str1) != std::string::npos &&
data.find(str2) != std::string::npos &&
data.find(str3) != std::string::npos &&
data.find(str4) != std::string::npos &&
data.find(str5) != std::string::npos &&
data.find(str6) != std::string::npos && map7_entries_present);
}
TEST_P(DeviceCertificateStoreTest, StoreCertificate) {
MockFile file;
CertStorageVariant params = GetParam();
@@ -1402,14 +1634,14 @@ TEST_P(DeviceCertificateTest, ReadCertificate) {
Return(data.size())));
EXPECT_CALL(file, Close()).Times(1);
EXPECT_CALL(file, Write(_, _)).Times(0);
EXPECT_CALL(file, List(_, NotNull())).WillOnce(Return(false));
DeviceFiles device_files;
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
device_files.SetTestFile(&file);
std::string certificate, wrapped_private_key;
ASSERT_TRUE(
device_files.RetrieveCertificate(origin, &certificate,
ASSERT_TRUE(device_files.RetrieveCertificate(origin, &certificate,
&wrapped_private_key));
EXPECT_EQ(kTestCertificate, b2a_hex(certificate));
EXPECT_EQ(kTestWrappedPrivateKey, b2a_hex(wrapped_private_key));
@@ -1492,6 +1724,9 @@ TEST_P(DeviceFilesStoreTest, StoreLicense) {
.WillOnce(Return(true));
}
CdmAppParameterMap app_parameters =
GetAppParameters(license_test_data[license_num].app_parameters);
EXPECT_CALL(file, Open(StrEq(license_path),
AllOf(IsCreateFileFlagSet(), IsBinaryFileFlagSet())))
.WillOnce(Return(true));
@@ -1501,7 +1736,8 @@ TEST_P(DeviceFilesStoreTest, StoreLicense) {
license_test_data[license_num].key_response,
license_test_data[license_num].key_renewal_request,
license_test_data[license_num].key_renewal_response,
license_test_data[license_num].key_release_url),
license_test_data[license_num].key_release_url,
app_parameters),
Gt(GetLicenseDataSize(license_test_data[license_num]))))
.WillOnce(ReturnArg<1>());
EXPECT_CALL(file, Close()).Times(1);
@@ -1520,7 +1756,7 @@ TEST_P(DeviceFilesStoreTest, StoreLicense) {
license_test_data[license_num].key_renewal_response,
license_test_data[license_num].key_release_url,
license_test_data[license_num].playback_start_time,
license_test_data[license_num].last_playback_time));
license_test_data[license_num].last_playback_time, app_parameters));
}
INSTANTIATE_TEST_CASE_P(StoreLicense, DeviceFilesStoreTest, ::testing::Bool());
@@ -1537,6 +1773,9 @@ TEST_F(DeviceFilesTest, StoreLicenses) {
license_test_data[i].key_set_id +
DeviceFiles::GetLicenseFileNameExtension();
CdmAppParameterMap app_parameters =
GetAppParameters(license_test_data[i].app_parameters);
EXPECT_CALL(file, Open(StrEq(license_path),
AllOf(IsCreateFileFlagSet(), IsBinaryFileFlagSet())))
.WillOnce(Return(true));
@@ -1546,7 +1785,8 @@ TEST_F(DeviceFilesTest, StoreLicenses) {
license_test_data[i].key_response,
license_test_data[i].key_renewal_request,
license_test_data[i].key_renewal_response,
license_test_data[i].key_release_url),
license_test_data[i].key_release_url,
app_parameters),
Gt(GetLicenseDataSize(license_test_data[i]))))
.WillOnce(ReturnArg<1>());
}
@@ -1557,6 +1797,9 @@ TEST_F(DeviceFilesTest, StoreLicenses) {
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
device_files.SetTestFile(&file);
for (size_t i = 0; i < kNumberOfLicenses; i++) {
CdmAppParameterMap app_parameters =
GetAppParameters(license_test_data[i].app_parameters);
EXPECT_TRUE(device_files.StoreLicense(
license_test_data[i].key_set_id, license_test_data[i].license_state,
license_test_data[i].pssh_data, license_test_data[i].key_request,
@@ -1565,7 +1808,7 @@ TEST_F(DeviceFilesTest, StoreLicenses) {
license_test_data[i].key_renewal_response,
license_test_data[i].key_release_url,
license_test_data[i].playback_start_time,
license_test_data[i].last_playback_time));
license_test_data[i].last_playback_time, app_parameters));
}
}
@@ -1603,6 +1846,7 @@ TEST_F(DeviceFilesTest, RetrieveLicenses) {
CdmKeyResponse key_renewal_response;
int64_t playback_start_time, last_playback_time;
std::string release_server_url;
CdmAppParameterMap app_parameters;
for (size_t i = 0; i < kNumberOfLicenses; i++) {
DeviceFiles::LicenseState license_state;
@@ -1610,7 +1854,7 @@ TEST_F(DeviceFilesTest, RetrieveLicenses) {
license_test_data[i].key_set_id, &license_state, &pssh_data,
&key_request, &key_response, &key_renewal_request,
&key_renewal_response, &release_server_url, &playback_start_time,
&last_playback_time));
&last_playback_time, &app_parameters));
EXPECT_EQ(license_test_data[i].license_state, license_state);
EXPECT_EQ(license_test_data[i].pssh_data, pssh_data);
EXPECT_EQ(license_test_data[i].key_request, key_request);
@@ -1619,7 +1863,66 @@ TEST_F(DeviceFilesTest, RetrieveLicenses) {
EXPECT_EQ(license_test_data[i].key_response, key_response);
EXPECT_EQ(license_test_data[i].playback_start_time, playback_start_time);
EXPECT_EQ(license_test_data[i].last_playback_time, last_playback_time);
std::map<std::string, std::string>::iterator itr;
for (itr = app_parameters.begin(); itr != app_parameters.end(); ++itr) {
EXPECT_NE(std::string::npos,
license_test_data[i].app_parameters.find(itr->first));
EXPECT_NE(std::string::npos,
license_test_data[i].app_parameters.find(itr->second));
}
}
}
TEST_F(DeviceFilesTest, AppParametersBackwardCompatibility) {
MockFile file;
LicenseInfo* test_data =
&license_app_parameters_backwards_compatibility_test_data;
std::string license_path = device_base_path_ + test_data->key_set_id +
DeviceFiles::GetLicenseFileNameExtension();
size_t size = test_data->file_data.size();
EXPECT_CALL(file, Exists(StrEq(license_path))).WillOnce(Return(true));
EXPECT_CALL(file, FileSize(StrEq(license_path))).WillOnce(Return(size));
EXPECT_CALL(file, Open(StrEq(license_path), IsBinaryFileFlagSet()))
.WillOnce(Return(true));
EXPECT_CALL(file, Read(NotNull(), Eq(size)))
.WillOnce(DoAll(SetArrayArgument<0>(test_data->file_data.begin(),
test_data->file_data.end()),
Return(size)));
EXPECT_CALL(file, Close()).Times(1);
EXPECT_CALL(file, Write(_, _)).Times(0);
DeviceFiles device_files;
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
device_files.SetTestFile(&file);
DeviceFiles::LicenseState license_state;
CdmInitData pssh_data;
CdmKeyMessage key_request;
CdmKeyResponse key_response;
CdmKeyMessage key_renewal_request;
CdmKeyResponse key_renewal_response;
int64_t playback_start_time, last_playback_time;
std::string release_server_url;
CdmAppParameterMap app_parameters;
EXPECT_TRUE(device_files.RetrieveLicense(
test_data->key_set_id, &license_state, &pssh_data, &key_request,
&key_response, &key_renewal_request, &key_renewal_response,
&release_server_url, &playback_start_time, &last_playback_time,
&app_parameters));
EXPECT_EQ(test_data->license_state, license_state);
EXPECT_EQ(test_data->pssh_data, pssh_data);
EXPECT_EQ(test_data->key_request, key_request);
EXPECT_EQ(test_data->key_response, key_response);
EXPECT_EQ(test_data->key_request, key_request);
EXPECT_EQ(test_data->key_response, key_response);
EXPECT_EQ(test_data->playback_start_time, playback_start_time);
EXPECT_EQ(test_data->last_playback_time, last_playback_time);
EXPECT_EQ(0u, app_parameters.size());
}
TEST_F(DeviceFilesTest, SecurityLevelPathBackwardCompatibility) {
@@ -1654,8 +1957,7 @@ TEST_F(DeviceFilesTest, SecurityLevelPathBackwardCompatibility) {
EXPECT_CALL(file, IsRegularFile(StrEq(old_path))).WillOnce(Return(true));
EXPECT_CALL(file, Remove(StrEq(old_path))).WillOnce(Return(true));
for (size_t i = 0; i < security_dirs.size(); ++i) {
new_path =
base_path + security_dirs[i] +
new_path = base_path + security_dirs[i] +
DeviceFiles::GetCertificateFileName(EMPTY_ORIGIN);
EXPECT_CALL(file, Copy(StrEq(old_path), StrEq(new_path)))
.WillOnce(Return(true));
@@ -1697,8 +1999,7 @@ TEST_F(DeviceFilesTest, SecurityLevelPathBackwardCompatibility) {
Properties::Init();
std::string certificate, wrapped_private_key;
ASSERT_TRUE(
device_files.RetrieveCertificate(EMPTY_ORIGIN, &certificate,
ASSERT_TRUE(device_files.RetrieveCertificate(EMPTY_ORIGIN, &certificate,
&wrapped_private_key));
}
@@ -1738,7 +2039,8 @@ TEST_F(DeviceFilesTest, UpdateLicenseState) {
license_update_test_data[0].key_renewal_response,
license_update_test_data[0].key_release_url,
license_update_test_data[0].playback_start_time,
license_update_test_data[0].last_playback_time));
license_update_test_data[0].last_playback_time,
GetAppParameters(license_test_data[0].app_parameters)));
EXPECT_TRUE(device_files.StoreLicense(
license_update_test_data[0].key_set_id,
@@ -1750,7 +2052,8 @@ TEST_F(DeviceFilesTest, UpdateLicenseState) {
license_update_test_data[0].key_renewal_response,
license_update_test_data[0].key_release_url,
license_update_test_data[0].playback_start_time,
license_update_test_data[0].last_playback_time));
license_update_test_data[0].last_playback_time,
GetAppParameters(license_test_data[0].app_parameters)));
}
TEST_F(DeviceFilesTest, DeleteLicense) {
@@ -1788,11 +2091,13 @@ TEST_F(DeviceFilesTest, DeleteLicense) {
CdmKeyResponse key_renewal_response;
std::string release_server_url;
int64_t playback_start_time, last_playback_time;
CdmAppParameterMap app_parameters;
EXPECT_TRUE(device_files.RetrieveLicense(
license_test_data[0].key_set_id, &license_state, &pssh_data, &key_request,
&key_response, &key_renewal_request, &key_renewal_response,
&release_server_url, &playback_start_time, &last_playback_time));
&release_server_url, &playback_start_time, &last_playback_time,
&app_parameters));
EXPECT_EQ(license_test_data[0].license_state, license_state);
EXPECT_EQ(license_test_data[0].pssh_data, pssh_data);
EXPECT_EQ(license_test_data[0].key_request, key_request);
@@ -1801,6 +2106,13 @@ TEST_F(DeviceFilesTest, DeleteLicense) {
EXPECT_EQ(license_test_data[0].key_response, key_response);
EXPECT_EQ(license_test_data[0].playback_start_time, playback_start_time);
EXPECT_EQ(license_test_data[0].last_playback_time, last_playback_time);
std::map<std::string, std::string>::iterator itr;
for (itr = app_parameters.begin(); itr != app_parameters.end(); ++itr) {
EXPECT_NE(license_test_data[0].app_parameters.find(itr->first),
std::string::npos);
EXPECT_NE(license_test_data[0].app_parameters.find(itr->second),
std::string::npos);
}
EXPECT_TRUE(device_files.DeleteLicense(license_test_data[0].key_set_id));
EXPECT_FALSE(device_files.LicenseExists(license_test_data[0].key_set_id));
@@ -1926,9 +2238,10 @@ TEST_P(DeviceFilesUsageInfoTest, Store) {
EXPECT_CALL(file, Close()).Times(1);
}
EXPECT_CALL(file, Write(Contains(pst, license_request, license, data.size()),
Gt(pst.size() + license_request.size() +
license.size()))).WillOnce(ReturnArg<1>());
EXPECT_CALL(file,
Write(Contains(pst, license_request, license, data.size()),
Gt(pst.size() + license_request.size() + license.size())))
.WillOnce(ReturnArg<1>());
DeviceFiles device_files;
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
@@ -2034,8 +2347,8 @@ TEST_P(DeviceFilesUsageInfoTest, DeleteAll) {
// DeleteAllUsageInfoForApp returns a list of all psts that
// should be deleted by oemcrypto.
EXPECT_EQ(static_cast<unsigned int>(index), psts.size());
for(int i=0; i < index; i++) {
EXPECT_EQ(kUsageInfoTestData[i+1].provider_session_token, psts[i]);
for (int i = 0; i < index; i++) {
EXPECT_EQ(kUsageInfoTestData[i + 1].provider_session_token, psts[i]);
}
}
}

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,8 +720,8 @@ 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_,
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;
@@ -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,14 +832,12 @@ 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,
@@ -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_);
@@ -837,27 +885,25 @@ TEST_F(WvCdmRequestLicenseTest, PropertySetTest) {
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,15 +2253,16 @@ 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 "
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 "
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?";
}
@@ -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) {

View File

@@ -152,14 +152,23 @@ enum {
kUnprovisioningError4 = ERROR_DRM_VENDOR_MIN + 136,
kUnsupportedInitData = ERROR_DRM_VENDOR_MIN + 137,
kUsageInfoNotFound = ERROR_DRM_VENDOR_MIN + 138,
kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 138,
kServiceCertificateRequestGenerateError = ERROR_DRM_VENDOR_MIN + 139,
kParseServiceCertificateError = ERROR_DRM_VENDOR_MIN + 140,
kServiceCertificateTypeError = ERROR_DRM_VENDOR_MIN + 141,
kClientIdGenerateRandomError = ERROR_DRM_VENDOR_MIN + 142,
kClientIdAesInitError = ERROR_DRM_VENDOR_MIN + 143,
kClientIdAesEncryptError = ERROR_DRM_VENDOR_MIN + 144,
kClientIdRsaInitError = ERROR_DRM_VENDOR_MIN + 145,
kClientIdRsaEncryptError = ERROR_DRM_VENDOR_MIN + 146,
kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 146,
// Used by crypto test mode
kErrorTestMode = ERROR_DRM_VENDOR_MAX,
};
static_assert(static_cast<uint32_t>(kErrorWVDrmMaxErrorUsed) <=
static_cast<uint32_t>(ERROR_DRM_VENDOR_MAX), "");
static_cast<uint32_t>(ERROR_DRM_VENDOR_MAX),
"");
} // namespace wvdrm

View File

@@ -289,6 +289,22 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) {
return kUnsupportedInitData;
case wvcdm::USAGE_INFO_NOT_FOUND:
return kUsageInfoNotFound;
case wvcdm::SERVICE_CERTIFICATE_REQUEST_GENERATE_ERROR:
return kServiceCertificateRequestGenerateError;
case wvcdm::PARSE_SERVICE_CERTIFICATE_ERROR:
return kParseServiceCertificateError;
case wvcdm::SERVICE_CERTIFICATE_TYPE_ERROR:
return kServiceCertificateTypeError;
case wvcdm::CLIENT_ID_GENERATE_RANDOM_ERROR:
return kClientIdGenerateRandomError;
case wvcdm::CLIENT_ID_AES_INIT_ERROR:
return kClientIdAesInitError;
case wvcdm::CLIENT_ID_AES_ENCRYPT_ERROR:
return kClientIdAesEncryptError;
case wvcdm::CLIENT_ID_RSA_INIT_ERROR:
return kClientIdRsaInitError;
case wvcdm::CLIENT_ID_RSA_ENCRYPT_ERROR:
return kClientIdRsaEncryptError;
case wvcdm::KEY_ERROR:
// KEY_ERROR is used by the CDM to mean just about any kind of error, not
// just license errors, so it is mapped to the generic response.