Save and retrieve key information from licenses and usage records
[ Merge of http://go/wvgerrit/120512 ] Wrapped DRM private keys are loaded when a key request is made or when offline/usage sessions are restored. They were earlier loaded when a session was opened. For streaming sessions, key material will be fetched from the default or legacy certificates and loaded when a key request is made. For offline and usage sessions, key material may be retrieved from license or usage records if available. If not available, information associated with the legacy certificate will be loaded. Certificate and wrapped keys are also written out when an offline license or usage record is saved. Bug: 169740403 Test: WV unit/integration tests WvCdmRequestLicenseTest.ProvisioningWithExpiringCertTest WvCdmRequestLicenseTest.StreamingWithExpiringCertTest WvCdmRequestLicenseTest.RestoreOfflineKeysWithExpiringCertTest Change-Id: Ice0154c632170c46da171cbbb23a97380c610a98
This commit is contained in:
@@ -169,56 +169,16 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
|
||||
usage_support_type_ = kNonSecureUsageSupport;
|
||||
}
|
||||
|
||||
// Device Provisioning state is not yet known.
|
||||
// If not using certificates, then Keybox is client token for license
|
||||
// requests.
|
||||
// Otherwise, try to fetch device certificate. If not successful and
|
||||
// provisioning is supported, return NEED_PROVISIONING. Otherwise, return
|
||||
// an error.
|
||||
// client_token and client_token_type are determined here; they are needed
|
||||
// to initialize the license parser.
|
||||
std::string client_token;
|
||||
std::string serial_number;
|
||||
CdmClientTokenType client_token_type =
|
||||
crypto_session_->GetPreProvisionTokenType();
|
||||
|
||||
// License server client ID token is a stored certificate. Stage it or
|
||||
// indicate that provisioning is needed. Get token from stored certificate
|
||||
CryptoWrappedKey private_key;
|
||||
bool atsc_mode_enabled = false;
|
||||
if (cdm_client_property_set != nullptr)
|
||||
atsc_mode_enabled = cdm_client_property_set->use_atsc_mode();
|
||||
if (file_handle_->RetrieveCertificate(
|
||||
atsc_mode_enabled, &client_token, &private_key, &serial_number,
|
||||
nullptr) != DeviceFiles::kCertificateValid) {
|
||||
atsc_mode_enabled_ = cdm_client_property_set->use_atsc_mode();
|
||||
|
||||
if (!file_handle_->HasCertificate(atsc_mode_enabled_))
|
||||
return NEED_PROVISIONING;
|
||||
}
|
||||
CdmResponseType load_cert_sts;
|
||||
M_TIME(
|
||||
load_cert_sts = crypto_session_->LoadCertificatePrivateKey(private_key),
|
||||
crypto_metrics_, crypto_session_load_certificate_private_key_,
|
||||
load_cert_sts);
|
||||
switch (load_cert_sts) {
|
||||
case NO_ERROR:
|
||||
metrics_->drm_certificate_key_type_.Record(
|
||||
DrmKeyTypeToMetricValue(private_key.type()));
|
||||
break;
|
||||
case SESSION_LOST_STATE_ERROR:
|
||||
case SYSTEM_INVALIDATED_ERROR:
|
||||
return load_cert_sts;
|
||||
default:
|
||||
return NEED_PROVISIONING;
|
||||
}
|
||||
|
||||
client_token_type = kClientTokenDrmCert;
|
||||
|
||||
// Session is provisioned with certificate needed to construct
|
||||
// license request (or with keybox).
|
||||
|
||||
if (forced_session_id) {
|
||||
key_set_id_ = *forced_session_id;
|
||||
} else {
|
||||
const bool ok = GenerateKeySetId(atsc_mode_enabled, &key_set_id_);
|
||||
const bool ok = GenerateKeySetId(atsc_mode_enabled_, &key_set_id_);
|
||||
assert(ok);
|
||||
if (!ok) {
|
||||
// Assertions may be disabled
|
||||
@@ -247,8 +207,7 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
|
||||
if (!Properties::GetServiceCertificate(session_id_, &service_certificate))
|
||||
service_certificate.clear();
|
||||
|
||||
if (!license_parser_->Init(client_token, client_token_type,
|
||||
Properties::UsePrivacyMode(session_id_),
|
||||
if (!license_parser_->Init(Properties::UsePrivacyMode(session_id_),
|
||||
service_certificate, crypto_session_.get(),
|
||||
policy_engine_.get()))
|
||||
return LICENSE_PARSER_INIT_ERROR;
|
||||
@@ -337,6 +296,10 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id,
|
||||
usage_entry_ = std::move(license_data.usage_entry);
|
||||
usage_entry_number_ = license_data.usage_entry_number;
|
||||
|
||||
CdmResponseType status = LoadPrivateOrLegacyKey(
|
||||
license_data.drm_certificate, license_data.wrapped_private_key);
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
// Attempts to restore a released offline license are treated as a release
|
||||
// retry.
|
||||
if (Properties::allow_restore_of_offline_licenses_with_release()) {
|
||||
@@ -396,8 +359,8 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id,
|
||||
|
||||
CdmResponseType result;
|
||||
if (license_type == kLicenseTypeRelease) {
|
||||
result =
|
||||
license_parser_->RestoreLicenseForRelease(key_request_, key_response_);
|
||||
result = license_parser_->RestoreLicenseForRelease(
|
||||
license_data.drm_certificate, key_request_, key_response_);
|
||||
|
||||
if (result != NO_ERROR) {
|
||||
SetErrorDetail(error_detail, result);
|
||||
@@ -405,9 +368,10 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id,
|
||||
}
|
||||
} else {
|
||||
result = license_parser_->RestoreOfflineLicense(
|
||||
key_request_, key_response_, offline_key_renewal_response_,
|
||||
license_data.playback_start_time, license_data.last_playback_time,
|
||||
license_data.grace_period_end_time, this);
|
||||
license_data.drm_certificate, key_request_, key_response_,
|
||||
offline_key_renewal_response_, license_data.playback_start_time,
|
||||
license_data.last_playback_time, license_data.grace_period_end_time,
|
||||
this);
|
||||
if (result != NO_ERROR) {
|
||||
SetErrorDetail(error_detail, result);
|
||||
return RESTORE_OFFLINE_LICENSE_ERROR_2;
|
||||
@@ -449,6 +413,10 @@ CdmResponseType CdmSession::RestoreUsageSession(
|
||||
usage_entry_number_ = usage_data.usage_entry_number;
|
||||
usage_provider_session_token_ = usage_data.provider_session_token;
|
||||
|
||||
CdmResponseType status = LoadPrivateOrLegacyKey(
|
||||
usage_data.drm_certificate, usage_data.wrapped_private_key);
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
CdmResponseType sts = NO_ERROR;
|
||||
if (usage_support_type_ == kUsageEntrySupport &&
|
||||
usage_table_header_ != nullptr) {
|
||||
@@ -461,7 +429,8 @@ CdmResponseType CdmSession::RestoreUsageSession(
|
||||
}
|
||||
}
|
||||
|
||||
sts = license_parser_->RestoreLicenseForRelease(key_request_, key_response_);
|
||||
sts = license_parser_->RestoreLicenseForRelease(usage_data.drm_certificate,
|
||||
key_request_, key_response_);
|
||||
|
||||
if (sts != NO_ERROR) {
|
||||
SetErrorDetail(error_detail, sts);
|
||||
@@ -568,10 +537,13 @@ CdmResponseType CdmSession::GenerateKeyRequestInternal(
|
||||
return KEY_REQUEST_ERROR_1;
|
||||
}
|
||||
|
||||
CdmResponseType status = LoadPrivateKey();
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
app_parameters_ = app_parameters;
|
||||
CdmResponseType status = license_parser_->PrepareKeyRequest(
|
||||
init_data, license_type, app_parameters, &key_request->message,
|
||||
&key_request->url);
|
||||
status = license_parser_->PrepareKeyRequest(
|
||||
init_data, drm_certificate_, license_type, app_parameters,
|
||||
&key_request->message, &key_request->url);
|
||||
if (status != KEY_MESSAGE) return status;
|
||||
|
||||
key_request_ = key_request->message;
|
||||
@@ -1018,12 +990,10 @@ CdmResponseType CdmSession::StoreLicense() {
|
||||
|
||||
std::string app_id;
|
||||
GetApplicationId(&app_id);
|
||||
std::string drm_certificate;
|
||||
CryptoWrappedKey wrapped_private_key;
|
||||
if (!file_handle_->StoreUsageInfo(
|
||||
provider_session_token, key_request_, key_response_,
|
||||
DeviceFiles::GetUsageInfoFileName(app_id), key_set_id_, usage_entry_,
|
||||
usage_entry_number_, drm_certificate, wrapped_private_key)) {
|
||||
usage_entry_number_, drm_certificate_, wrapped_private_key_)) {
|
||||
LOGE("Unable to store usage info");
|
||||
// Usage info file is corrupt. Delete current usage entry and file.
|
||||
if (usage_support_type_ == kUsageEntrySupport) {
|
||||
@@ -1044,7 +1014,6 @@ CdmResponseType CdmSession::StoreLicense() {
|
||||
bool CdmSession::StoreLicense(DeviceFiles::LicenseState state,
|
||||
int* error_detail) {
|
||||
DeviceFiles::ResponseType error_detail_alt = DeviceFiles::kNoError;
|
||||
std::string drm_certificate;
|
||||
DeviceFiles::CdmLicenseData license_data{
|
||||
key_set_id_,
|
||||
state,
|
||||
@@ -1060,8 +1029,8 @@ bool CdmSession::StoreLicense(DeviceFiles::LicenseState state,
|
||||
app_parameters_,
|
||||
usage_entry_,
|
||||
usage_entry_number_,
|
||||
drm_certificate,
|
||||
CryptoWrappedKey()};
|
||||
drm_certificate_,
|
||||
wrapped_private_key_};
|
||||
|
||||
bool result = file_handle_->StoreLicense(license_data, &error_detail_alt);
|
||||
if (error_detail != nullptr) {
|
||||
@@ -1271,6 +1240,83 @@ bool CdmSession::VerifyOfflineUsageEntry() {
|
||||
return true;
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::LoadPrivateKey() {
|
||||
std::string drm_certificate;
|
||||
CryptoWrappedKey private_key;
|
||||
uint32_t system_id;
|
||||
|
||||
if (file_handle_->RetrieveCertificate(atsc_mode_enabled_, &drm_certificate,
|
||||
&private_key, nullptr, &system_id) !=
|
||||
DeviceFiles::kCertificateValid) {
|
||||
return NEED_PROVISIONING;
|
||||
}
|
||||
|
||||
CdmResponseType status = LoadPrivateKey(private_key);
|
||||
|
||||
if (status == NO_ERROR) {
|
||||
drm_certificate_ = drm_certificate;
|
||||
wrapped_private_key_.set_type(private_key.type());
|
||||
wrapped_private_key_.set_key(private_key.key());
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::LoadPrivateOrLegacyKey(
|
||||
const std::string& certificate, const CryptoWrappedKey& private_key) {
|
||||
// Use provided key if valid
|
||||
if (!certificate.empty() && private_key.IsValid()) {
|
||||
CdmResponseType status = LoadPrivateKey(private_key);
|
||||
|
||||
if (status == NO_ERROR) {
|
||||
drm_certificate_ = certificate;
|
||||
wrapped_private_key_.set_type(private_key.type());
|
||||
wrapped_private_key_.set_key(private_key.key());
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Otherwise use key from legacy certificate
|
||||
std::string drm_certificate;
|
||||
CryptoWrappedKey wrapped_private_key;
|
||||
if (file_handle_->RetrieveLegacyCertificate(
|
||||
&drm_certificate, &wrapped_private_key, nullptr, nullptr) !=
|
||||
DeviceFiles::kCertificateValid)
|
||||
return NEED_PROVISIONING;
|
||||
|
||||
CdmResponseType status = LoadPrivateKey(wrapped_private_key);
|
||||
|
||||
if (status == NO_ERROR) {
|
||||
drm_certificate_ = drm_certificate;
|
||||
wrapped_private_key_.set_type(wrapped_private_key.type());
|
||||
wrapped_private_key_.set_key(wrapped_private_key.key());
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::LoadPrivateKey(
|
||||
const CryptoWrappedKey& private_key) {
|
||||
CdmResponseType load_cert_sts;
|
||||
M_TIME(
|
||||
load_cert_sts = crypto_session_->LoadCertificatePrivateKey(private_key),
|
||||
crypto_metrics_, crypto_session_load_certificate_private_key_,
|
||||
load_cert_sts);
|
||||
|
||||
switch (load_cert_sts) {
|
||||
case NO_ERROR:
|
||||
metrics_->drm_certificate_key_type_.Record(
|
||||
DrmKeyTypeToMetricValue(private_key.type()));
|
||||
return NO_ERROR;
|
||||
case SESSION_LOST_STATE_ERROR:
|
||||
case SYSTEM_INVALIDATED_ERROR:
|
||||
return load_cert_sts;
|
||||
default:
|
||||
return NEED_PROVISIONING;
|
||||
}
|
||||
}
|
||||
|
||||
// For testing only - takes ownership of pointers
|
||||
|
||||
void CdmSession::set_license_parser(CdmLicense* license_parser) {
|
||||
|
||||
Reference in New Issue
Block a user