Merge "Corrections for license release on fallback to L3" into lmp-dev

This commit is contained in:
Rahul Frias
2014-09-04 18:35:03 +00:00
committed by Android (Google) Code Review
10 changed files with 158 additions and 46 deletions

View File

@@ -34,7 +34,9 @@ class CdmEngine {
CdmSessionId* session_id);
virtual CdmResponseType CloseSession(const CdmSessionId& session_id);
virtual CdmResponseType OpenKeySetSession(const CdmKeySetId& key_set_id);
virtual CdmResponseType OpenKeySetSession(
const CdmKeySetId& key_set_id,
const CdmClientPropertySet* property_set);
virtual CdmResponseType CloseKeySetSession(const CdmKeySetId& key_set_id);
// License related methods

View File

@@ -108,7 +108,9 @@ CdmResponseType CdmEngine::OpenSession(
return NO_ERROR;
}
CdmResponseType CdmEngine::OpenKeySetSession(const CdmKeySetId& key_set_id) {
CdmResponseType CdmEngine::OpenKeySetSession(
const CdmKeySetId& key_set_id,
const CdmClientPropertySet* property_set) {
LOGI("CdmEngine::OpenKeySetSession");
if (key_set_id.empty()) {
@@ -117,7 +119,7 @@ CdmResponseType CdmEngine::OpenKeySetSession(const CdmKeySetId& key_set_id) {
}
CdmSessionId session_id;
CdmResponseType sts = OpenSession(KEY_SYSTEM, NULL, &session_id);
CdmResponseType sts = OpenSession(KEY_SYSTEM, property_set, &session_id);
if (sts != NO_ERROR)
return sts;

View File

@@ -869,7 +869,11 @@ bool CdmLicense::RestoreLicenseForRelease(
return false;
}
key_request_ = signed_request.msg();
if (Properties::use_certificates_as_identification()) {
key_request_ = signed_request.msg();
} else {
if (!session_->GenerateDerivedKeys(signed_request.msg())) return false;
}
SignedMessage signed_response;
if (!signed_response.ParseFromString(license_response)) {
@@ -885,19 +889,6 @@ bool CdmLicense::RestoreLicenseForRelease(
return false;
}
if (Properties::use_certificates_as_identification()) {
if (!signed_response.has_session_key()) {
LOGE("CdmLicense::RestoreLicenseForRelease: no session keys present");
return false;
}
if (!session_->GenerateDerivedKeys(key_request_,
signed_response.session_key()))
return false;
} else {
if (!session_->GenerateDerivedKeys(key_request_)) return false;
}
if (!signed_response.has_signature()) {
LOGE("CdmLicense::RestoreLicenseForRelease: license response is not"
" signed");
@@ -914,6 +905,21 @@ bool CdmLicense::RestoreLicenseForRelease(
if (license.id().has_provider_session_token())
provider_session_token_ = license.id().provider_session_token();
if (Properties::use_certificates_as_identification()) {
if (!signed_response.has_session_key()) {
LOGE("CdmLicense::RestoreLicenseForRelease: no session keys present");
return false;
}
if (license.id().has_provider_session_token()) {
if (!session_->GenerateDerivedKeys(key_request_,
signed_response.session_key()))
return false;
} else {
return KEY_ADDED == HandleKeyResponse(license_response);
}
}
if (license.policy().has_renewal_server_url())
server_url_ = license.policy().renewal_server_url();

View File

@@ -778,12 +778,14 @@ extern "C" OEMCryptoResult OEMCrypto_DeactivateUsageEntry(const uint8_t *pst,
const FunctionPointers* fcn1 = kAdapter->get(kLevelDefault);
const FunctionPointers* fcn3 = kAdapter->get(kLevel3);
OEMCryptoResult sts = OEMCrypto_ERROR_NOT_IMPLEMENTED;
if (fcn3 && fcn3->version > 8) {
sts = fcn3->DeactivateUsageEntry(pst, pst_length);
}
if (fcn1 && fcn1 != fcn3 && fcn1->version > 8) {
if (fcn1 && fcn1->version > 8) {
sts = fcn1->DeactivateUsageEntry(pst, pst_length);
}
if (OEMCrypto_SUCCESS != sts) {
if (fcn3 && fcn1 != fcn3 && fcn3->version > 8) {
sts = fcn3->DeactivateUsageEntry(pst, pst_length);
}
}
return sts;
}

View File

@@ -39,6 +39,7 @@ class WvContentDecryptionModule : public TimerHandler {
const CdmInitData& init_data,
const CdmLicenseType license_type,
CdmAppParameterMap& app_parameters,
CdmClientPropertySet* property_set,
CdmKeyMessage* key_request,
std::string* server_url);

View File

@@ -66,11 +66,12 @@ CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
const CdmInitData& init_data,
const CdmLicenseType license_type,
CdmAppParameterMap& app_parameters,
CdmClientPropertySet* property_set,
CdmKeyMessage* key_request,
std::string* server_url) {
CdmResponseType sts;
if (license_type == kLicenseTypeRelease) {
sts = cdm_engine_->OpenKeySetSession(key_set_id);
sts = cdm_engine_->OpenKeySetSession(key_set_id, property_set);
if (sts != NO_ERROR)
return sts;
}

View File

@@ -243,7 +243,7 @@ class WvCdmExtendedDurationTest : public testing::Test {
EXPECT_EQ(wvcdm::KEY_MESSAGE,
decryptor_.GenerateKeyRequest(
session_id_, key_set_id_, "video/mp4", init_data,
license_type, app_parameters, &key_msg_, &server_url));
license_type, app_parameters, NULL, &key_msg_, &server_url));
EXPECT_EQ(0u, server_url.size());
}
@@ -256,7 +256,7 @@ class WvCdmExtendedDurationTest : public testing::Test {
EXPECT_EQ(wvcdm::KEY_MESSAGE,
decryptor_.GenerateKeyRequest(
session_id_, key_set_id_, "video/mp4", init_data,
license_type, app_parameters, &key_msg_, server_url));
license_type, app_parameters, NULL, &key_msg_, server_url));
// TODO(edwinwong, rfrias): Add tests cases for when license server url
// is empty on renewal. Need appropriate key id at the server.
EXPECT_NE(0u, server_url->size());
@@ -270,7 +270,8 @@ class WvCdmExtendedDurationTest : public testing::Test {
EXPECT_EQ(wvcdm::KEY_MESSAGE,
decryptor_.GenerateKeyRequest(
session_id, key_set_id, "video/mp4", init_data,
kLicenseTypeRelease, app_parameters, &key_msg_, &server_url));
kLicenseTypeRelease, app_parameters, NULL, &key_msg_,
&server_url));
}
// Post a request and extract the drm message from the response

View File

@@ -371,12 +371,16 @@ SessionSharingSubSampleInfo session_sharing_sub_samples[] = {
struct UsageInfoSubSampleInfo {
SubSampleInfo* sub_sample;
uint32_t usage_info;
wvcdm::SecurityLevel security_level;
};
UsageInfoSubSampleInfo usage_info_sub_sample_info[] = {
{&usage_info_sub_samples_icp[0], 1},
{&usage_info_sub_samples_icp[0], 3},
{&usage_info_sub_samples_icp[0], 5}};
{&usage_info_sub_samples_icp[0], 1, wvcdm::kLevelDefault},
{&usage_info_sub_samples_icp[0], 3, wvcdm::kLevelDefault},
{&usage_info_sub_samples_icp[0], 5, wvcdm::kLevelDefault},
{&usage_info_sub_samples_icp[0], 1, wvcdm::kLevel3},
{&usage_info_sub_samples_icp[0], 3, wvcdm::kLevel3},
{&usage_info_sub_samples_icp[0], 5, wvcdm::kLevel3}};
} // namespace
@@ -460,18 +464,30 @@ class WvCdmRequestLicenseTest : public testing::Test {
void GenerateKeyRequest(const std::string& init_data,
CdmLicenseType license_type) {
GenerateKeyRequest(init_data, license_type, NULL);
}
void GenerateKeyRequest(const std::string& init_data,
CdmLicenseType license_type,
CdmClientPropertySet* property_set) {
wvcdm::CdmAppParameterMap app_parameters;
std::string server_url;
std::string key_set_id;
EXPECT_EQ(wvcdm::KEY_MESSAGE,
decryptor_.GenerateKeyRequest(
session_id_, key_set_id, "video/mp4", init_data, license_type,
app_parameters, &key_msg_, &server_url));
app_parameters, property_set, &key_msg_, &server_url));
EXPECT_EQ(0u, server_url.size());
}
void GenerateRenewalRequest(CdmLicenseType license_type,
std::string* server_url) {
GenerateRenewalRequest(license_type, server_url, NULL);
}
void GenerateRenewalRequest(CdmLicenseType license_type,
std::string* server_url,
CdmClientPropertySet* property_set) {
// TODO application makes a license request, CDM will renew the license
// when appropriate.
std::string init_data;
@@ -479,13 +495,19 @@ class WvCdmRequestLicenseTest : public testing::Test {
EXPECT_EQ(wvcdm::KEY_MESSAGE,
decryptor_.GenerateKeyRequest(
session_id_, key_set_id_, "video/mp4", init_data,
license_type, app_parameters, &key_msg_, server_url));
license_type, app_parameters, property_set, &key_msg_,
server_url));
// TODO(edwinwong, rfrias): Add tests cases for when license server url
// is empty on renewal. Need appropriate key id at the server.
EXPECT_NE(0u, server_url->size());
}
void GenerateKeyRelease(CdmKeySetId key_set_id) {
GenerateKeyRelease(key_set_id, NULL);
}
void GenerateKeyRelease(CdmKeySetId key_set_id,
CdmClientPropertySet* property_set) {
CdmSessionId session_id;
CdmInitData init_data;
wvcdm::CdmAppParameterMap app_parameters;
@@ -493,7 +515,8 @@ class WvCdmRequestLicenseTest : public testing::Test {
EXPECT_EQ(wvcdm::KEY_MESSAGE,
decryptor_.GenerateKeyRequest(
session_id, key_set_id, "video/mp4", init_data,
kLicenseTypeRelease, app_parameters, &key_msg_, &server_url));
kLicenseTypeRelease, app_parameters, property_set, &key_msg_,
&server_url));
}
// Post a request and extract the drm message from the response
@@ -1019,6 +1042,70 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseRetryOfflineKeyTest) {
VerifyKeyRequestResponse(g_license_server, client_auth, false);
}
TEST_F(WvCdmRequestLicenseTest, ReleaseRetryL3OfflineKeyTest) {
Unprovision();
TestWvCdmClientPropertySet property_set;
property_set.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
// override default settings unless configured through the command line
std::string key_id;
std::string client_auth;
GetOfflineConfiguration(&key_id, &client_auth);
CdmResponseType sts =
decryptor_.OpenSession(g_key_system, &property_set, &session_id_);
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, &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(response, &cert,
&wrapped_key));
EXPECT_EQ(NO_ERROR, decryptor_.OpenSession(g_key_system, &property_set,
&session_id_));
} else {
EXPECT_EQ(NO_ERROR, sts);
}
decryptor_.OpenSession(g_key_system, &property_set, &session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline, &property_set);
VerifyKeyRequestResponse(g_license_server, client_auth, false);
CdmKeySetId key_set_id = key_set_id_;
EXPECT_FALSE(key_set_id_.empty());
decryptor_.CloseSession(session_id_);
session_id_.clear();
key_set_id_.clear();
decryptor_.OpenSession(g_key_system, &property_set, &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();
GenerateKeyRelease(key_set_id, &property_set);
session_id_.clear();
decryptor_.OpenSession(g_key_system, &property_set, &session_id_);
EXPECT_EQ(
wvcdm::UNKNOWN_ERROR, decryptor_.RestoreKey(session_id_, key_set_id));
decryptor_.CloseSession(session_id_);
session_id_.clear();
key_set_id_.clear();
GenerateKeyRelease(key_set_id, &property_set);
key_set_id_ = key_set_id;
VerifyKeyRequestResponse(g_license_server, client_auth, false);
}
TEST_F(WvCdmRequestLicenseTest, ExpiryOnReleaseOfflineKeyTest) {
Unprovision();
Provision(kLevelDefault);
@@ -1101,6 +1188,15 @@ class WvCdmUsageInfoTest
TEST_P(WvCdmUsageInfoTest, UsageInfo) {
Unprovision();
Provision(kLevelDefault);
UsageInfoSubSampleInfo* usage_info_data = GetParam();
TestWvCdmClientPropertySet client_property_set;
TestWvCdmClientPropertySet* property_set = NULL;
if (kLevel3 == usage_info_data->security_level) {
client_property_set.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
property_set = &client_property_set;
}
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
DeviceFiles handle;
EXPECT_TRUE(handle.Init(security_level));
@@ -1108,10 +1204,9 @@ TEST_P(WvCdmUsageInfoTest, UsageInfo) {
handle.SetTestFile(&file);
EXPECT_TRUE(handle.DeleteUsageInfo());
UsageInfoSubSampleInfo* usage_info_data = GetParam();
for (size_t i = 0; i < usage_info_data->usage_info; ++i) {
SubSampleInfo* data = usage_info_data->sub_sample + i;
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
decryptor_.OpenSession(g_key_system, property_set, &session_id_);
std::string key_id = a2bs_hex(
"000000427073736800000000" // blob size and pssh
"EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id
@@ -1121,7 +1216,7 @@ TEST_P(WvCdmUsageInfoTest, UsageInfo) {
char ch = 0x33 + i;
key_id.append(1, ch);
GenerateKeyRequest(key_id, kLicenseTypeStreaming);
GenerateKeyRequest(key_id, kLicenseTypeStreaming, property_set);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());

View File

@@ -209,7 +209,8 @@ status_t WVDrmPlugin::getKeyRequest(
cdmInitDataType,
processedInitData,
cdmLicenseType, cdmParameters,
&keyRequest, &cdmDefaultUrl);
&mPropertySet, &keyRequest,
&cdmDefaultUrl);
if (isCdmResponseTypeSuccess(res)) {
defaultUrl.clear();

View File

@@ -31,12 +31,13 @@ class MockCDM : public WvContentDecryptionModule {
MOCK_METHOD1(CloseSession, CdmResponseType(const CdmSessionId&));
MOCK_METHOD8(GenerateKeyRequest, CdmResponseType(const CdmSessionId&,
MOCK_METHOD9(GenerateKeyRequest, CdmResponseType(const CdmSessionId&,
const CdmKeySetId&,
const std::string&,
const CdmInitData&,
const CdmLicenseType,
CdmAppParameterMap&,
CdmClientPropertySet*,
CdmKeyMessage*, string*));
MOCK_METHOD3(AddKey, CdmResponseType(const CdmSessionId&,
@@ -272,23 +273,23 @@ TEST_F(WVDrmPluginTest, GeneratesKeyRequests) {
EXPECT_CALL(cdm, GenerateKeyRequest(cdmSessionId, "", mimeType, initData,
kLicenseTypeOffline, cdmParameters, _,
_))
.WillOnce(DoAll(SetArgPointee<6>(cdmRequest),
SetArgPointee<7>(kDefaultUrl),
_, _))
.WillOnce(DoAll(SetArgPointee<7>(cdmRequest),
SetArgPointee<8>(kDefaultUrl),
Return(wvcdm::KEY_MESSAGE)));
EXPECT_CALL(cdm, GenerateKeyRequest(cdmSessionId, "", mimeType, initData,
kLicenseTypeStreaming, cdmParameters, _,
_))
.WillOnce(DoAll(SetArgPointee<6>(cdmRequest),
SetArgPointee<7>(kDefaultUrl),
_, _))
.WillOnce(DoAll(SetArgPointee<7>(cdmRequest),
SetArgPointee<8>(kDefaultUrl),
Return(wvcdm::KEY_MESSAGE)));
EXPECT_CALL(cdm, GenerateKeyRequest("", cdmKeySetId, mimeType, initData,
kLicenseTypeRelease, cdmParameters, _,
_))
.WillOnce(DoAll(SetArgPointee<6>(cdmRequest),
SetArgPointee<7>(kDefaultUrl),
kLicenseTypeRelease, cdmParameters,
NotNull(), _, _))
.WillOnce(DoAll(SetArgPointee<7>(cdmRequest),
SetArgPointee<8>(kDefaultUrl),
Return(wvcdm::KEY_MESSAGE)));
}
}