Merge changes I9f51e07c,I3f65a6ec
* changes: CDM core: Removed support for v15 provisioning responses. CDM Core: Removed support for v15 licenses.
This commit is contained in:
@@ -50,8 +50,6 @@ class CertificateProvisioning {
|
|||||||
wvutil::FileSystem* file_system, const CdmProvisioningResponse& response,
|
wvutil::FileSystem* file_system, const CdmProvisioningResponse& response,
|
||||||
std::string* cert, std::string* wrapped_key);
|
std::string* cert, std::string* wrapped_key);
|
||||||
|
|
||||||
bool supports_core_messages() const { return supports_core_messages_; }
|
|
||||||
|
|
||||||
// Helper methods
|
// Helper methods
|
||||||
|
|
||||||
// Extract serial number and system ID from a DRM Device certificate.
|
// Extract serial number and system ID from a DRM Device certificate.
|
||||||
@@ -123,13 +121,6 @@ class CertificateProvisioning {
|
|||||||
// Key type of the generated key pair in provisioning 4.
|
// Key type of the generated key pair in provisioning 4.
|
||||||
CryptoWrappedKey::Type provisioning_40_key_type_;
|
CryptoWrappedKey::Type provisioning_40_key_type_;
|
||||||
|
|
||||||
// Indicates whether OEMCrypto supports core messages, and whether the
|
|
||||||
// CDM should expect a core message in the response. This is primarily
|
|
||||||
// used to distinguish between v16+ OEMCrypto or an earlier version.
|
|
||||||
// Assume core messages are supported, and check if OEMCrypto populates
|
|
||||||
// the core message field when calling PrepAndSignProvisioningRequest().
|
|
||||||
bool supports_core_messages_ = true;
|
|
||||||
|
|
||||||
CORE_DISALLOW_COPY_AND_ASSIGN(CertificateProvisioning);
|
CORE_DISALLOW_COPY_AND_ASSIGN(CertificateProvisioning);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -155,15 +155,6 @@ class CryptoSession {
|
|||||||
const std::string& message, std::string* core_message,
|
const std::string& message, std::string* core_message,
|
||||||
std::string* signature);
|
std::string* signature);
|
||||||
virtual CdmResponseType UseSecondaryKey(bool dual_key);
|
virtual CdmResponseType UseSecondaryKey(bool dual_key);
|
||||||
// V15 licenses.
|
|
||||||
virtual CdmResponseType LoadKeys(const std::string& message,
|
|
||||||
const std::string& signature,
|
|
||||||
const std::string& mac_key_iv,
|
|
||||||
const std::string& mac_key,
|
|
||||||
const std::vector<CryptoKey>& key_array,
|
|
||||||
const std::string& provider_session_token,
|
|
||||||
const std::string& srm_requirement,
|
|
||||||
CdmLicenseKeyType key_type);
|
|
||||||
// V16 licenses.
|
// V16 licenses.
|
||||||
virtual CdmResponseType LoadLicense(const std::string& signed_message,
|
virtual CdmResponseType LoadLicense(const std::string& signed_message,
|
||||||
const std::string& core_message,
|
const std::string& core_message,
|
||||||
@@ -174,10 +165,6 @@ class CryptoSession {
|
|||||||
virtual CdmResponseType PrepareAndSignRenewalRequest(
|
virtual CdmResponseType PrepareAndSignRenewalRequest(
|
||||||
const std::string& message, std::string* core_message,
|
const std::string& message, std::string* core_message,
|
||||||
std::string* signature);
|
std::string* signature);
|
||||||
// V15 licenses.
|
|
||||||
virtual CdmResponseType RefreshKeys(const std::string& message,
|
|
||||||
const std::string& signature,
|
|
||||||
const std::vector<CryptoKey>& key_array);
|
|
||||||
// V16 licenses.
|
// V16 licenses.
|
||||||
virtual CdmResponseType LoadRenewal(const std::string& signed_message,
|
virtual CdmResponseType LoadRenewal(const std::string& signed_message,
|
||||||
const std::string& core_message,
|
const std::string& core_message,
|
||||||
|
|||||||
@@ -82,10 +82,6 @@ class CdmLicense {
|
|||||||
|
|
||||||
virtual bool is_offline() const { return is_offline_; }
|
virtual bool is_offline() const { return is_offline_; }
|
||||||
|
|
||||||
virtual bool supports_core_messages() const {
|
|
||||||
return supports_core_messages_;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual const VersionInfo& GetServiceVersion() {
|
virtual const VersionInfo& GetServiceVersion() {
|
||||||
return latest_service_version_;
|
return latest_service_version_;
|
||||||
}
|
}
|
||||||
@@ -110,8 +106,7 @@ class CdmLicense {
|
|||||||
|
|
||||||
CdmResponseType HandleContentKeyResponse(
|
CdmResponseType HandleContentKeyResponse(
|
||||||
bool is_restore, const std::string& msg, const std::string& core_message,
|
bool is_restore, const std::string& msg, const std::string& core_message,
|
||||||
const std::string& signature, const std::string& mac_key_iv,
|
const std::string& signature, const std::vector<CryptoKey>& key_array,
|
||||||
const std::string& mac_key, const std::vector<CryptoKey>& key_array,
|
|
||||||
const video_widevine::License& license);
|
const video_widevine::License& license);
|
||||||
|
|
||||||
// HandleEntitlementKeyResponse loads the entitlement keys in |key_array| into
|
// HandleEntitlementKeyResponse loads the entitlement keys in |key_array| into
|
||||||
@@ -119,8 +114,7 @@ class CdmLicense {
|
|||||||
// |wrapped_keys_| and loads them for use.
|
// |wrapped_keys_| and loads them for use.
|
||||||
CdmResponseType HandleEntitlementKeyResponse(
|
CdmResponseType HandleEntitlementKeyResponse(
|
||||||
bool is_restore, const std::string& msg, const std::string& core_message,
|
bool is_restore, const std::string& msg, const std::string& core_message,
|
||||||
const std::string& signature, const std::string& mac_key_iv,
|
const std::string& signature, const std::vector<CryptoKey>& key_array,
|
||||||
const std::string& mac_key, const std::vector<CryptoKey>& key_array,
|
|
||||||
const video_widevine::License& license);
|
const video_widevine::License& license);
|
||||||
|
|
||||||
// Prepare to reload a key update message. Some special code is needed to work
|
// Prepare to reload a key update message. Some special code is needed to work
|
||||||
@@ -146,11 +140,6 @@ class CdmLicense {
|
|||||||
std::string provider_session_token_;
|
std::string provider_session_token_;
|
||||||
bool renew_with_client_id_;
|
bool renew_with_client_id_;
|
||||||
bool is_offline_;
|
bool is_offline_;
|
||||||
// Indicates whether the license contains / supports OEMCrypto-level
|
|
||||||
// support for core messages. If the original license was created before
|
|
||||||
// upgrading from V15, or if the licensing server is still running V15,
|
|
||||||
// then the license does not support core messages.
|
|
||||||
bool supports_core_messages_;
|
|
||||||
|
|
||||||
// Associated with ClientIdentification encryption
|
// Associated with ClientIdentification encryption
|
||||||
bool use_privacy_mode_;
|
bool use_privacy_mode_;
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ class PolicyEngine {
|
|||||||
// being restored and transitions and notifications will be deferred until
|
// being restored and transitions and notifications will be deferred until
|
||||||
// stored playback times are restored.
|
// stored playback times are restored.
|
||||||
virtual void SetLicense(const video_widevine::License& license,
|
virtual void SetLicense(const video_widevine::License& license,
|
||||||
bool supports_core_messages,
|
|
||||||
bool defer_license_state_update);
|
bool defer_license_state_update);
|
||||||
|
|
||||||
// Used to update the currently loaded entitled content keys.
|
// Used to update the currently loaded entitled content keys.
|
||||||
@@ -73,8 +72,7 @@ class PolicyEngine {
|
|||||||
|
|
||||||
// SetLicenseForRelease is used when releasing a license. The keys in this
|
// SetLicenseForRelease is used when releasing a license. The keys in this
|
||||||
// license will be ignored, and any old keys will be expired.
|
// license will be ignored, and any old keys will be expired.
|
||||||
virtual void SetLicenseForRelease(const video_widevine::License& license,
|
virtual void SetLicenseForRelease(const video_widevine::License& license);
|
||||||
bool supports_core_messages);
|
|
||||||
|
|
||||||
// Call this on first decrypt to set the start of playback.
|
// Call this on first decrypt to set the start of playback.
|
||||||
virtual bool BeginDecryption(void);
|
virtual bool BeginDecryption(void);
|
||||||
@@ -169,8 +167,8 @@ class PolicyEngine {
|
|||||||
|
|
||||||
void SetSecurityLevelForTest(CdmSecurityLevel security_level);
|
void SetSecurityLevelForTest(CdmSecurityLevel security_level);
|
||||||
|
|
||||||
LicenseState license_state_;
|
LicenseState license_state_ = kLicenseStateInitial;
|
||||||
int64_t license_state_update_deadline_;
|
int64_t license_state_update_deadline_ = 0;
|
||||||
|
|
||||||
// This is the license id field from server response. This data gets passed
|
// This is the license id field from server response. This data gets passed
|
||||||
// back to the server in each renewal request. When we get a renewal response
|
// back to the server in each renewal request. When we get a renewal response
|
||||||
@@ -178,11 +176,11 @@ class PolicyEngine {
|
|||||||
video_widevine::LicenseIdentification license_id_;
|
video_widevine::LicenseIdentification license_id_;
|
||||||
|
|
||||||
// to assist in clock rollback checks
|
// to assist in clock rollback checks
|
||||||
int64_t last_recorded_current_time_;
|
int64_t last_recorded_current_time_ = 0;
|
||||||
|
|
||||||
// Used to dispatch CDM events.
|
// Used to dispatch CDM events.
|
||||||
CdmSessionId session_id_;
|
CdmSessionId session_id_;
|
||||||
WvCdmEventListener* event_listener_;
|
WvCdmEventListener* event_listener_ = nullptr;
|
||||||
|
|
||||||
// Keys associated with license - holds allowed usage, usage constraints,
|
// Keys associated with license - holds allowed usage, usage constraints,
|
||||||
// and current status (CdmKeyStatus)
|
// and current status (CdmKeyStatus)
|
||||||
@@ -193,9 +191,9 @@ class PolicyEngine {
|
|||||||
video_widevine::License::Policy policy_;
|
video_widevine::License::Policy policy_;
|
||||||
|
|
||||||
// Device checks
|
// Device checks
|
||||||
int64_t next_device_check_;
|
int64_t next_device_check_ = 0;
|
||||||
uint32_t current_resolution_;
|
uint32_t current_resolution_ = 0;
|
||||||
CryptoSession* crypto_session_;
|
CryptoSession* crypto_session_ = nullptr;
|
||||||
|
|
||||||
std::unique_ptr<PolicyTimers> policy_timers_;
|
std::unique_ptr<PolicyTimers> policy_timers_;
|
||||||
std::unique_ptr<wvutil::Clock> clock_;
|
std::unique_ptr<wvutil::Clock> clock_;
|
||||||
|
|||||||
@@ -87,8 +87,6 @@ bool RetrieveOemCertificateAndLoadPrivateKey(CryptoSession& crypto_session,
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
// Protobuf generated classes.
|
// Protobuf generated classes.
|
||||||
using video_widevine::ClientIdentification_ClientCapabilities;
|
|
||||||
using video_widevine::ClientIdentification_NameValue;
|
|
||||||
using video_widevine::DrmCertificate;
|
using video_widevine::DrmCertificate;
|
||||||
using video_widevine::EncryptedClientIdentification;
|
using video_widevine::EncryptedClientIdentification;
|
||||||
using video_widevine::ProvisioningOptions;
|
using video_widevine::ProvisioningOptions;
|
||||||
@@ -97,8 +95,6 @@ using video_widevine::ProvisioningResponse;
|
|||||||
using video_widevine::PublicKeyToCertify;
|
using video_widevine::PublicKeyToCertify;
|
||||||
using video_widevine::SignedDrmCertificate;
|
using video_widevine::SignedDrmCertificate;
|
||||||
using video_widevine::SignedProvisioningMessage;
|
using video_widevine::SignedProvisioningMessage;
|
||||||
using video_widevine::
|
|
||||||
SignedProvisioningMessage_ProvisioningProtocolVersion_VERSION_1_1;
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void CertificateProvisioning::GetProvisioningServerUrl(
|
void CertificateProvisioning::GetProvisioningServerUrl(
|
||||||
@@ -112,18 +108,16 @@ void CertificateProvisioning::GetProvisioningServerUrl(
|
|||||||
|
|
||||||
CdmResponseType CertificateProvisioning::Init(
|
CdmResponseType CertificateProvisioning::Init(
|
||||||
const std::string& service_certificate) {
|
const std::string& service_certificate) {
|
||||||
std::string certificate = service_certificate.empty()
|
const std::string certificate = service_certificate.empty()
|
||||||
? kCpProductionServiceCertificate
|
? kCpProductionServiceCertificate
|
||||||
: service_certificate;
|
: service_certificate;
|
||||||
return service_certificate_->Init(certificate);
|
return service_certificate_->Init(certificate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Fill in the appropriate SPOID (Stable Per-Origin IDentifier) option.
|
||||||
* Fill in the appropriate SPOID (Stable Per-Origin IDentifier) option.
|
// One of spoid, provider_id or stable_id will be passed to the provisioning
|
||||||
* One of spoid, provider_id or stable_id will be passed to the provisioning
|
// server for determining a unique per origin ID for the device.
|
||||||
* server for determining a unique per origin ID for the device.
|
// It is also valid (though deprecated) to leave the settings unset.
|
||||||
* It is also valid (though deprecated) to leave the settings unset.
|
|
||||||
*/
|
|
||||||
CdmResponseType CertificateProvisioning::SetSpoidParameter(
|
CdmResponseType CertificateProvisioning::SetSpoidParameter(
|
||||||
const std::string& origin, const std::string& spoid,
|
const std::string& origin, const std::string& spoid,
|
||||||
ProvisioningRequest* request) {
|
ProvisioningRequest* request) {
|
||||||
@@ -135,14 +129,13 @@ CdmResponseType CertificateProvisioning::SetSpoidParameter(
|
|||||||
// Use the SPOID that has been pre-provided
|
// Use the SPOID that has been pre-provided
|
||||||
request->set_spoid(spoid);
|
request->set_spoid(spoid);
|
||||||
} else if (Properties::UseProviderIdInProvisioningRequest()) {
|
} else if (Properties::UseProviderIdInProvisioningRequest()) {
|
||||||
if (!service_certificate_->provider_id().empty()) {
|
if (service_certificate_->provider_id().empty()) {
|
||||||
request->set_provider_id(service_certificate_->provider_id());
|
|
||||||
} else {
|
|
||||||
LOGE(
|
LOGE(
|
||||||
"Failed to set provider ID: "
|
"Failed to set provider ID: "
|
||||||
"Service certificate provider ID is empty");
|
"Service certificate provider ID is empty");
|
||||||
return SERVICE_CERTIFICATE_PROVIDER_ID_EMPTY;
|
return SERVICE_CERTIFICATE_PROVIDER_ID_EMPTY;
|
||||||
}
|
}
|
||||||
|
request->set_provider_id(service_certificate_->provider_id());
|
||||||
} else if (origin != EMPTY_ORIGIN) {
|
} else if (origin != EMPTY_ORIGIN) {
|
||||||
// Legacy behavior - Concatenate Unique ID with Origin
|
// Legacy behavior - Concatenate Unique ID with Origin
|
||||||
std::string device_unique_id;
|
std::string device_unique_id;
|
||||||
@@ -159,10 +152,8 @@ CdmResponseType CertificateProvisioning::SetSpoidParameter(
|
|||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Return the provisioning protocol version - dictated by OEMCrypto
|
||||||
* Return the provisioning protocol version - dictated by OEMCrypto
|
// support for OEM certificates.
|
||||||
* support for OEM certificates.
|
|
||||||
*/
|
|
||||||
SignedProvisioningMessage::ProvisioningType
|
SignedProvisioningMessage::ProvisioningType
|
||||||
CertificateProvisioning::GetProvisioningType() {
|
CertificateProvisioning::GetProvisioningType() {
|
||||||
switch (crypto_session_->GetPreProvisionTokenType()) {
|
switch (crypto_session_->GetPreProvisionTokenType()) {
|
||||||
@@ -175,13 +166,11 @@ CertificateProvisioning::GetProvisioningType() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Compose a device provisioning request and output *request in a
|
||||||
* Compose a device provisioning request and output *request in a
|
// JSON-compatible format (web-safe base64).
|
||||||
* JSON-compatible format (web-safe base64).
|
// Also return *default_url of the provisioning server.
|
||||||
* Also return *default_url of the provisioning server.
|
//
|
||||||
*
|
// Returns NO_ERROR for success and CERT_PROVISIONING_REQUEST_ERROR_? if fails.
|
||||||
* Returns NO_ERROR for success and CERT_PROVISIONING_REQUEST_ERROR_? if fails.
|
|
||||||
*/
|
|
||||||
CdmResponseType CertificateProvisioning::GetProvisioningRequest(
|
CdmResponseType CertificateProvisioning::GetProvisioningRequest(
|
||||||
wvutil::FileSystem* file_system,
|
wvutil::FileSystem* file_system,
|
||||||
RequestedSecurityLevel requested_security_level,
|
RequestedSecurityLevel requested_security_level,
|
||||||
@@ -240,18 +229,17 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
|
|||||||
|
|
||||||
// The provisioning server does not convert the nonce to uint32_t, it just
|
// The provisioning server does not convert the nonce to uint32_t, it just
|
||||||
// passes the binary data to the response message.
|
// passes the binary data to the response message.
|
||||||
std::string the_nonce(reinterpret_cast<char*>(&nonce), sizeof(nonce));
|
const std::string encoded_nonce(reinterpret_cast<char*>(&nonce),
|
||||||
provisioning_request.set_nonce(the_nonce);
|
sizeof(nonce));
|
||||||
|
provisioning_request.set_nonce(encoded_nonce);
|
||||||
|
|
||||||
ProvisioningOptions* options = provisioning_request.mutable_options();
|
ProvisioningOptions* options = provisioning_request.mutable_options();
|
||||||
switch (cert_type) {
|
switch (cert_type) {
|
||||||
case kCertificateWidevine:
|
case kCertificateWidevine:
|
||||||
options->set_certificate_type(
|
options->set_certificate_type(ProvisioningOptions::WIDEVINE_DRM);
|
||||||
video_widevine::ProvisioningOptions_CertificateType_WIDEVINE_DRM);
|
|
||||||
break;
|
break;
|
||||||
case kCertificateX509:
|
case kCertificateX509:
|
||||||
options->set_certificate_type(
|
options->set_certificate_type(ProvisioningOptions::X509);
|
||||||
video_widevine::ProvisioningOptions_CertificateType_X509);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOGE("Unknown certificate type: %d", static_cast<int>(cert_type));
|
LOGE("Unknown certificate type: %d", static_cast<int>(cert_type));
|
||||||
@@ -288,14 +276,9 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
|
|||||||
signed_provisioning_msg.set_message(serialized_message);
|
signed_provisioning_msg.set_message(serialized_message);
|
||||||
signed_provisioning_msg.set_signature(request_signature);
|
signed_provisioning_msg.set_signature(request_signature);
|
||||||
signed_provisioning_msg.set_provisioning_type(GetProvisioningType());
|
signed_provisioning_msg.set_provisioning_type(GetProvisioningType());
|
||||||
if (core_message.empty()) {
|
|
||||||
// OEMCrypto does not support core messages.
|
|
||||||
supports_core_messages_ = false;
|
|
||||||
} else {
|
|
||||||
signed_provisioning_msg.set_oemcrypto_core_message(core_message);
|
signed_provisioning_msg.set_oemcrypto_core_message(core_message);
|
||||||
}
|
|
||||||
signed_provisioning_msg.set_protocol_version(
|
signed_provisioning_msg.set_protocol_version(
|
||||||
SignedProvisioningMessage_ProvisioningProtocolVersion_VERSION_1_1);
|
SignedProvisioningMessage::VERSION_1_1);
|
||||||
|
|
||||||
std::string serialized_request;
|
std::string serialized_request;
|
||||||
signed_provisioning_msg.SerializeToString(&serialized_request);
|
signed_provisioning_msg.SerializeToString(&serialized_request);
|
||||||
@@ -421,7 +404,7 @@ CdmResponseType CertificateProvisioning::GetProvisioning40RequestInternal(
|
|||||||
signed_provisioning_msg.mutable_message());
|
signed_provisioning_msg.mutable_message());
|
||||||
signed_provisioning_msg.set_provisioning_type(GetProvisioningType());
|
signed_provisioning_msg.set_provisioning_type(GetProvisioningType());
|
||||||
signed_provisioning_msg.set_protocol_version(
|
signed_provisioning_msg.set_protocol_version(
|
||||||
SignedProvisioningMessage_ProvisioningProtocolVersion_VERSION_1_1);
|
SignedProvisioningMessage::VERSION_1_1);
|
||||||
|
|
||||||
std::string serialized_request;
|
std::string serialized_request;
|
||||||
signed_provisioning_msg.SerializeToString(&serialized_request);
|
signed_provisioning_msg.SerializeToString(&serialized_request);
|
||||||
@@ -541,13 +524,13 @@ CdmResponseType CertificateProvisioning::HandleProvisioning40Response(
|
|||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// The response message consists of a device certificate and the
|
||||||
* The response message consists of a device certificate and the device RSA key.
|
// wrapped device private key (either RSA or ECC). The wrapped device
|
||||||
* The device RSA key is stored in the T.E.E. The device certificate is stored
|
// private key is loaded into the TEE, unwrapped, verified and
|
||||||
* in the device.
|
// re-wrapped. The device certificate and re-wrapped device private
|
||||||
*
|
// key are stored on the device.
|
||||||
* Returns NO_ERROR for success and CERT_PROVISIONING_RESPONSE_ERROR_? if fails.
|
//
|
||||||
*/
|
// Returns NO_ERROR for success and CERT_PROVISIONING_RESPONSE_ERROR_? if fails.
|
||||||
CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||||
wvutil::FileSystem* file_system,
|
wvutil::FileSystem* file_system,
|
||||||
const CdmProvisioningResponse& response_message, std::string* cert,
|
const CdmProvisioningResponse& response_message, std::string* cert,
|
||||||
@@ -597,30 +580,16 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
|||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (supports_core_messages() &&
|
if (!signed_response.has_oemcrypto_core_message()) {
|
||||||
(!signed_response.has_oemcrypto_core_message() ||
|
|
||||||
signed_response.oemcrypto_core_message().empty())) {
|
|
||||||
LOGE("Signed response does not have core message");
|
LOGE("Signed response does not have core message");
|
||||||
error = true;
|
error = true;
|
||||||
} else if (!supports_core_messages() &&
|
|
||||||
(signed_response.has_oemcrypto_core_message() &&
|
|
||||||
!signed_response.oemcrypto_core_message().empty())) {
|
|
||||||
const std::string& core_message = signed_response.oemcrypto_core_message();
|
|
||||||
// This case should not occur. However, the CDM will let OEMCrypto
|
|
||||||
// fail.
|
|
||||||
LOGW(
|
|
||||||
"Received unexpected core message in provisioning request: "
|
|
||||||
"core_message_size = %zu",
|
|
||||||
core_message.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error) return CERT_PROVISIONING_RESPONSE_ERROR_3;
|
if (error) return CERT_PROVISIONING_RESPONSE_ERROR_3;
|
||||||
|
|
||||||
const std::string& signed_message = signed_response.message();
|
const std::string& signed_message = signed_response.message();
|
||||||
const std::string& signature = signed_response.signature();
|
const std::string& signature = signed_response.signature();
|
||||||
const std::string core_message =
|
const std::string& core_message = signed_response.oemcrypto_core_message();
|
||||||
supports_core_messages() ? signed_response.oemcrypto_core_message()
|
|
||||||
: std::string();
|
|
||||||
|
|
||||||
ProvisioningResponse provisioning_response;
|
ProvisioningResponse provisioning_response;
|
||||||
if (!provisioning_response.ParseFromString(signed_message)) {
|
if (!provisioning_response.ParseFromString(signed_message)) {
|
||||||
@@ -630,7 +599,7 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
|||||||
|
|
||||||
if (provisioning_response.has_status()) {
|
if (provisioning_response.has_status()) {
|
||||||
if (provisioning_response.status() != ProvisioningResponse::NO_ERROR) {
|
if (provisioning_response.status() != ProvisioningResponse::NO_ERROR) {
|
||||||
LOGE("Provisioning Response status: %d", provisioning_response.status());
|
LOGE("Provisioning response status: %d", provisioning_response.status());
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (provisioning_response.status()) {
|
switch (provisioning_response.status()) {
|
||||||
@@ -699,7 +668,6 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
|||||||
|
|
||||||
// The certificate will be stored to the device as the final step in
|
// The certificate will be stored to the device as the final step in
|
||||||
// the device provisioning process.
|
// the device provisioning process.
|
||||||
|
|
||||||
DeviceFiles handle(file_system);
|
DeviceFiles handle(file_system);
|
||||||
if (!handle.Init(security_level)) {
|
if (!handle.Init(security_level)) {
|
||||||
LOGE("Failed to initialize DeviceFiles");
|
LOGE("Failed to initialize DeviceFiles");
|
||||||
@@ -785,7 +753,7 @@ bool CertificateProvisioning::ExtractDeviceInfo(
|
|||||||
DrmCertificate drm_certificate;
|
DrmCertificate drm_certificate;
|
||||||
if (!drm_certificate.ParseFromString(
|
if (!drm_certificate.ParseFromString(
|
||||||
signed_drm_certificate.drm_certificate()) ||
|
signed_drm_certificate.drm_certificate()) ||
|
||||||
(drm_certificate.type() != video_widevine::DrmCertificate::DEVICE)) {
|
(drm_certificate.type() != DrmCertificate::DEVICE)) {
|
||||||
LOGE("Failed to parse DRM device certificate message");
|
LOGE("Failed to parse DRM device certificate message");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -966,6 +966,7 @@ CdmResponseType CryptoSession::PrepareAndSignLicenseRequest(
|
|||||||
LOGV("Preparing and signing license request: id = %u", oec_session_id_);
|
LOGV("Preparing and signing license request: id = %u", oec_session_id_);
|
||||||
RETURN_IF_NULL(signature, PARAMETER_NULL);
|
RETURN_IF_NULL(signature, PARAMETER_NULL);
|
||||||
RETURN_IF_NULL(core_message, PARAMETER_NULL);
|
RETURN_IF_NULL(core_message, PARAMETER_NULL);
|
||||||
|
RETURN_IF_NOT_OPEN(CRYPTO_SESSION_NOT_OPEN);
|
||||||
|
|
||||||
OEMCryptoResult sts;
|
OEMCryptoResult sts;
|
||||||
size_t signature_length = 0;
|
size_t signature_length = 0;
|
||||||
@@ -1045,45 +1046,6 @@ CdmResponseType CryptoSession::UseSecondaryKey(bool dual_key) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType CryptoSession::LoadKeys(
|
|
||||||
const std::string& message, const std::string& signature,
|
|
||||||
const std::string& mac_key_iv, const std::string& mac_key,
|
|
||||||
const std::vector<CryptoKey>& keys,
|
|
||||||
const std::string& provider_session_token,
|
|
||||||
const std::string& srm_requirement, CdmLicenseKeyType key_type) {
|
|
||||||
LOGV("Loading keys: id = %u", oec_session_id_);
|
|
||||||
OEMCryptoResult sts;
|
|
||||||
WithOecSessionLock("LoadKeys", [&] {
|
|
||||||
if (key_type == kLicenseKeyTypeEntitlement &&
|
|
||||||
key_session_->Type() != KeySession::kEntitlement) {
|
|
||||||
key_session_.reset(new EntitlementKeySession(oec_session_id_, metrics_));
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGV("Loading key: id = %u", oec_session_id_);
|
|
||||||
sts = key_session_->LoadKeys(message, signature, mac_key_iv, mac_key, keys,
|
|
||||||
provider_session_token, srm_requirement);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (sts != OEMCrypto_SUCCESS) {
|
|
||||||
LOGE("OEMCrypto_LoadKeys failed: status = %d", static_cast<int>(sts));
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (sts) {
|
|
||||||
case OEMCrypto_SUCCESS:
|
|
||||||
if (!provider_session_token.empty())
|
|
||||||
update_usage_table_after_close_session_ = true;
|
|
||||||
return KEY_ADDED;
|
|
||||||
case OEMCrypto_ERROR_TOO_MANY_KEYS:
|
|
||||||
return INSUFFICIENT_CRYPTO_RESOURCES;
|
|
||||||
case OEMCrypto_ERROR_USAGE_TABLE_UNRECOVERABLE:
|
|
||||||
// Handle vendor specific error
|
|
||||||
return NEED_PROVISIONING;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return MapOEMCryptoResult(sts, LOAD_KEY_ERROR, "LoadKeys");
|
|
||||||
}
|
|
||||||
|
|
||||||
CdmResponseType CryptoSession::LoadLicense(const std::string& signed_message,
|
CdmResponseType CryptoSession::LoadLicense(const std::string& signed_message,
|
||||||
const std::string& core_message,
|
const std::string& core_message,
|
||||||
const std::string& signature,
|
const std::string& signature,
|
||||||
@@ -1183,36 +1145,6 @@ CdmResponseType CryptoSession::PrepareAndSignRenewalRequest(
|
|||||||
"PrepareAndSignRenewalRequest");
|
"PrepareAndSignRenewalRequest");
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType CryptoSession::RefreshKeys(
|
|
||||||
const std::string& message, const std::string& signature,
|
|
||||||
const std::vector<CryptoKey>& key_array) {
|
|
||||||
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
|
|
||||||
std::vector<OEMCrypto_KeyRefreshObject> load_key_array(key_array.size());
|
|
||||||
for (size_t i = 0; i < key_array.size(); ++i) {
|
|
||||||
const CryptoKey* ki = &key_array[i];
|
|
||||||
OEMCrypto_KeyRefreshObject* ko = &load_key_array[i];
|
|
||||||
ko->key_id = GetSubstring(message, ki->key_id());
|
|
||||||
bool has_key_control = ki->HasKeyControl();
|
|
||||||
ko->key_control_iv =
|
|
||||||
GetSubstring(message, ki->key_control_iv(), !has_key_control);
|
|
||||||
ko->key_control =
|
|
||||||
GetSubstring(message, ki->key_control(), !has_key_control);
|
|
||||||
}
|
|
||||||
LOGV("Refreshing keys: id = %u", oec_session_id_);
|
|
||||||
OEMCryptoResult refresh_sts;
|
|
||||||
WithOecSessionLock("RefreshKeys", [&] {
|
|
||||||
M_TIME(refresh_sts = OEMCrypto_RefreshKeys(
|
|
||||||
oec_session_id_, msg, message.size(),
|
|
||||||
reinterpret_cast<const uint8_t*>(signature.data()),
|
|
||||||
signature.size(), key_array.size(), &load_key_array[0]),
|
|
||||||
metrics_, oemcrypto_refresh_keys_, refresh_sts);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (refresh_sts == OEMCrypto_SUCCESS) return KEY_ADDED;
|
|
||||||
|
|
||||||
return MapOEMCryptoResult(refresh_sts, REFRESH_KEYS_ERROR, "RefreshKeys");
|
|
||||||
}
|
|
||||||
|
|
||||||
CdmResponseType CryptoSession::LoadRenewal(const std::string& signed_message,
|
CdmResponseType CryptoSession::LoadRenewal(const std::string& signed_message,
|
||||||
const std::string& core_message,
|
const std::string& core_message,
|
||||||
const std::string& signature) {
|
const std::string& signature) {
|
||||||
|
|||||||
@@ -199,7 +199,6 @@ CdmLicense::CdmLicense(const CdmSessionId& session_id)
|
|||||||
initialized_(false),
|
initialized_(false),
|
||||||
renew_with_client_id_(false),
|
renew_with_client_id_(false),
|
||||||
is_offline_(false),
|
is_offline_(false),
|
||||||
supports_core_messages_(true),
|
|
||||||
use_privacy_mode_(false),
|
use_privacy_mode_(false),
|
||||||
clock_(new wvutil::Clock()),
|
clock_(new wvutil::Clock()),
|
||||||
license_key_type_(kLicenseKeyTypeContent) {}
|
license_key_type_(kLicenseKeyTypeContent) {}
|
||||||
@@ -211,7 +210,6 @@ CdmLicense::CdmLicense(const CdmSessionId& session_id, wvutil::Clock* clock)
|
|||||||
initialized_(false),
|
initialized_(false),
|
||||||
renew_with_client_id_(false),
|
renew_with_client_id_(false),
|
||||||
is_offline_(false),
|
is_offline_(false),
|
||||||
supports_core_messages_(true),
|
|
||||||
use_privacy_mode_(false),
|
use_privacy_mode_(false),
|
||||||
license_key_type_(kLicenseKeyTypeContent) {
|
license_key_type_(kLicenseKeyTypeContent) {
|
||||||
clock_.reset(clock);
|
clock_.reset(clock);
|
||||||
@@ -368,9 +366,7 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
|
|||||||
signed_message.set_type(SignedMessage::LICENSE_REQUEST);
|
signed_message.set_type(SignedMessage::LICENSE_REQUEST);
|
||||||
signed_message.set_signature(license_request_signature);
|
signed_message.set_signature(license_request_signature);
|
||||||
signed_message.set_msg(serialized_license_req);
|
signed_message.set_msg(serialized_license_req);
|
||||||
if (core_message.size() > 0) {
|
|
||||||
signed_message.set_oemcrypto_core_message(core_message);
|
signed_message.set_oemcrypto_core_message(core_message);
|
||||||
}
|
|
||||||
|
|
||||||
signed_message.SerializeToString(signed_request);
|
signed_message.SerializeToString(signed_request);
|
||||||
|
|
||||||
@@ -383,7 +379,7 @@ CdmResponseType CdmLicense::PrepareKeyUpdateReload(CdmSession* cdm_session) {
|
|||||||
uint32_t api_version = 0;
|
uint32_t api_version = 0;
|
||||||
if (!crypto_session_->GetApiVersion(&api_version)) {
|
if (!crypto_session_->GetApiVersion(&api_version)) {
|
||||||
LOGW("Unknown API Version");
|
LOGW("Unknown API Version");
|
||||||
api_version = 15;
|
api_version = 16;
|
||||||
}
|
}
|
||||||
if (api_version != 16) return NO_ERROR;
|
if (api_version != 16) return NO_ERROR;
|
||||||
// To work around b/166010609, we ask OEMCrypto to prepare an unused renewal
|
// To work around b/166010609, we ask OEMCrypto to prepare an unused renewal
|
||||||
@@ -484,27 +480,6 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
|
|||||||
current_license->set_seconds_since_last_played(seconds_since_last_played);
|
current_license->set_seconds_since_last_played(seconds_since_last_played);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t api_version = 0;
|
|
||||||
if (!crypto_session_->GetApiVersion(&api_version)) {
|
|
||||||
LOGW("Unknown API Version");
|
|
||||||
api_version = 15;
|
|
||||||
}
|
|
||||||
if (api_version < 16) {
|
|
||||||
// For a pre-v16 license, get/set the nonce. This value will be reflected
|
|
||||||
// in the Key Control Block of the license response.
|
|
||||||
const CdmResponseType status =
|
|
||||||
crypto_session_->GenerateNonce(&license_nonce_);
|
|
||||||
switch (status) {
|
|
||||||
case NO_ERROR:
|
|
||||||
break;
|
|
||||||
case SESSION_LOST_STATE_ERROR:
|
|
||||||
case SYSTEM_INVALIDATED_ERROR:
|
|
||||||
return status;
|
|
||||||
default:
|
|
||||||
return LICENSE_RENEWAL_NONCE_GENERATION_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
license_request.set_key_control_nonce(license_nonce_);
|
|
||||||
license_request.set_protocol_version(video_widevine::VERSION_2_1);
|
license_request.set_protocol_version(video_widevine::VERSION_2_1);
|
||||||
|
|
||||||
// License request is complete. Serialize it.
|
// License request is complete. Serialize it.
|
||||||
@@ -528,11 +503,7 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
|
|||||||
signed_message.set_type(SignedMessage::LICENSE_REQUEST);
|
signed_message.set_type(SignedMessage::LICENSE_REQUEST);
|
||||||
signed_message.set_signature(license_request_signature);
|
signed_message.set_signature(license_request_signature);
|
||||||
signed_message.set_msg(serialized_license_req);
|
signed_message.set_msg(serialized_license_req);
|
||||||
if (supports_core_messages()) {
|
|
||||||
// Only include the |core_message| in renewal requests if it is
|
|
||||||
// already known that the license is v16.
|
|
||||||
signed_message.set_oemcrypto_core_message(core_message);
|
signed_message.set_oemcrypto_core_message(core_message);
|
||||||
}
|
|
||||||
|
|
||||||
signed_message.SerializeToString(signed_request);
|
signed_message.SerializeToString(signed_request);
|
||||||
*server_url = server_url_;
|
*server_url = server_url_;
|
||||||
@@ -586,20 +557,8 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
|||||||
return LICENSE_RESPONSE_NOT_SIGNED;
|
return LICENSE_RESPONSE_NOT_SIGNED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the server returned a |core_message|. If missing, then
|
|
||||||
// the server is assumed to operate as V15. This will imply that the
|
|
||||||
// |signature| field in the response does not include a core message
|
|
||||||
// either.
|
|
||||||
if (!signed_response.has_oemcrypto_core_message() ||
|
|
||||||
signed_response.oemcrypto_core_message().empty()) {
|
|
||||||
supports_core_messages_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& signed_message = signed_response.msg();
|
const std::string& signed_message = signed_response.msg();
|
||||||
const std::string core_message =
|
const std::string& core_message = signed_response.oemcrypto_core_message();
|
||||||
signed_response.has_oemcrypto_core_message()
|
|
||||||
? signed_response.oemcrypto_core_message()
|
|
||||||
: std::string();
|
|
||||||
const std::string& signature = signed_response.signature();
|
const std::string& signature = signed_response.signature();
|
||||||
|
|
||||||
License license;
|
License license;
|
||||||
@@ -631,7 +590,7 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (license.policy().can_renew() ||
|
if (license.policy().can_renew() ||
|
||||||
(mac_key_iv.size() != 0 || mac_keys.size() != 0)) {
|
(!mac_key_iv.empty() || !mac_keys.empty())) {
|
||||||
if (mac_key_iv.size() != KEY_IV_SIZE ||
|
if (mac_key_iv.size() != KEY_IV_SIZE ||
|
||||||
mac_keys.size() != kLicenseMacKeySize) {
|
mac_keys.size() != kLicenseMacKeySize) {
|
||||||
LOGE(
|
LOGE(
|
||||||
@@ -688,13 +647,12 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
|||||||
|
|
||||||
CdmResponseType resp = NO_CONTENT_KEY;
|
CdmResponseType resp = NO_CONTENT_KEY;
|
||||||
if (kLicenseKeyTypeEntitlement == key_type) {
|
if (kLicenseKeyTypeEntitlement == key_type) {
|
||||||
resp = HandleEntitlementKeyResponse(is_restore, signed_message,
|
resp =
|
||||||
core_message, signature, mac_key_iv,
|
HandleEntitlementKeyResponse(is_restore, signed_message, core_message,
|
||||||
mac_keys, key_array, license);
|
signature, key_array, license);
|
||||||
} else if (kLicenseKeyTypeContent == key_type) {
|
} else if (kLicenseKeyTypeContent == key_type) {
|
||||||
resp = HandleContentKeyResponse(is_restore, signed_message, core_message,
|
resp = HandleContentKeyResponse(is_restore, signed_message, core_message,
|
||||||
signature, mac_key_iv, mac_keys, key_array,
|
signature, key_array, license);
|
||||||
license);
|
|
||||||
}
|
}
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
@@ -727,29 +685,19 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
|
|||||||
return INVALID_LICENSE_TYPE;
|
return INVALID_LICENSE_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point of the license life-cycle (handling a renewal), we should
|
const std::string& signed_message = signed_response.msg();
|
||||||
// already know if the license is v15 or not. If license is v16, then a
|
const std::string& core_message = signed_response.oemcrypto_core_message();
|
||||||
// renewal should have a |core_message| present; otherwise there might have
|
const std::string& signature = signed_response.signature();
|
||||||
// been some tampering with the request or response. On the other hand, a
|
|
||||||
// release is processed without loading the license, so OEMCrypto does not
|
if (is_renewal && core_message.empty()) {
|
||||||
// know if it is v15 or v16, and will not add a core message.
|
|
||||||
if (is_renewal && supports_core_messages() &&
|
|
||||||
(!signed_response.has_oemcrypto_core_message() ||
|
|
||||||
signed_response.oemcrypto_core_message().empty())) {
|
|
||||||
LOGE("Renewal response is missing |core_message| field");
|
LOGE("Renewal response is missing |core_message| field");
|
||||||
return CORE_MESSAGE_NOT_FOUND;
|
return CORE_MESSAGE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!signed_response.has_signature()) {
|
if (signature.empty()) {
|
||||||
LOGE("Update key response is missing signature");
|
LOGE("Update key response is missing signature");
|
||||||
return SIGNATURE_NOT_FOUND;
|
return SIGNATURE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
const std::string& signed_message = signed_response.msg();
|
|
||||||
const std::string core_message =
|
|
||||||
signed_response.has_oemcrypto_core_message()
|
|
||||||
? signed_response.oemcrypto_core_message()
|
|
||||||
: std::string();
|
|
||||||
const std::string& signature = signed_response.signature();
|
|
||||||
|
|
||||||
License license;
|
License license;
|
||||||
if (!license.ParseFromString(signed_message)) {
|
if (!license.ParseFromString(signed_message)) {
|
||||||
@@ -777,19 +725,13 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
|
|||||||
server_url_ = license.policy().renewal_server_url();
|
server_url_ = license.policy().renewal_server_url();
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType status;
|
|
||||||
// If the field is not set, it will default to false.
|
// If the field is not set, it will default to false.
|
||||||
status =
|
CdmResponseType status =
|
||||||
crypto_session_->UseSecondaryKey(signed_response.using_secondary_key());
|
crypto_session_->UseSecondaryKey(signed_response.using_secondary_key());
|
||||||
if (status != NO_ERROR) return status;
|
if (status != NO_ERROR) return status;
|
||||||
|
|
||||||
if (supports_core_messages()) {
|
|
||||||
status =
|
status =
|
||||||
crypto_session_->LoadRenewal(signed_message, core_message, signature);
|
crypto_session_->LoadRenewal(signed_message, core_message, signature);
|
||||||
} else {
|
|
||||||
std::vector<CryptoKey> key_array = ExtractContentKeys(license);
|
|
||||||
status = crypto_session_->RefreshKeys(signed_message, signature, key_array);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status == KEY_ADDED) {
|
if (status == KEY_ADDED) {
|
||||||
policy_engine_->UpdateLicense(license, is_restore);
|
policy_engine_->UpdateLicense(license, is_restore);
|
||||||
@@ -834,13 +776,6 @@ CdmResponseType CdmLicense::RestoreOfflineLicense(
|
|||||||
return INVALID_LICENSE_REQUEST_TYPE_1;
|
return INVALID_LICENSE_REQUEST_TYPE_1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!signed_request.has_oemcrypto_core_message() ||
|
|
||||||
signed_request.oemcrypto_core_message().empty()) {
|
|
||||||
// Pre V16 license did not include |core_message| components.
|
|
||||||
// The license response is checked by HandleKeyResponse().
|
|
||||||
supports_core_messages_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
key_request_ = signed_request.msg();
|
key_request_ = signed_request.msg();
|
||||||
LicenseRequest original_license_request;
|
LicenseRequest original_license_request;
|
||||||
if (!original_license_request.ParseFromString(key_request_)) {
|
if (!original_license_request.ParseFromString(key_request_)) {
|
||||||
@@ -928,11 +863,6 @@ CdmResponseType CdmLicense::RestoreLicenseForRelease(
|
|||||||
return INVALID_LICENSE_REQUEST_TYPE_2;
|
return INVALID_LICENSE_REQUEST_TYPE_2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!signed_request.has_oemcrypto_core_message()) {
|
|
||||||
// Pre V16 license did not include |core_message| components.
|
|
||||||
supports_core_messages_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
key_request_ = signed_request.msg();
|
key_request_ = signed_request.msg();
|
||||||
|
|
||||||
SignedMessage signed_response;
|
SignedMessage signed_response;
|
||||||
@@ -953,12 +883,9 @@ CdmResponseType CdmLicense::RestoreLicenseForRelease(
|
|||||||
return SIGNATURE_NOT_FOUND_2;
|
return SIGNATURE_NOT_FOUND_2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!signed_response.has_oemcrypto_core_message() ||
|
if (!signed_response.has_oemcrypto_core_message()) {
|
||||||
signed_response.oemcrypto_core_message().empty()) {
|
LOGE("License response is missing core message");
|
||||||
// Possible that the request contains a |core_message|, but the
|
return CORE_MESSAGE_NOT_FOUND;
|
||||||
// response does not. This would occur if the licensing server
|
|
||||||
// is v15.
|
|
||||||
supports_core_messages_ = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
License license;
|
License license;
|
||||||
@@ -991,7 +918,7 @@ CdmResponseType CdmLicense::RestoreLicenseForRelease(
|
|||||||
|
|
||||||
// If the policy engine already has keys, they will now expire.
|
// If the policy engine already has keys, they will now expire.
|
||||||
// If the policy engine does not already have keys, this will not add any.
|
// If the policy engine does not already have keys, this will not add any.
|
||||||
policy_engine_->SetLicenseForRelease(license, supports_core_messages());
|
policy_engine_->SetLicenseForRelease(license);
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1137,52 +1064,34 @@ CdmResponseType CdmLicense::PrepareContentId(
|
|||||||
|
|
||||||
CdmResponseType CdmLicense::HandleContentKeyResponse(
|
CdmResponseType CdmLicense::HandleContentKeyResponse(
|
||||||
bool is_restore, const std::string& msg, const std::string& core_message,
|
bool is_restore, const std::string& msg, const std::string& core_message,
|
||||||
const std::string& signature, const std::string& mac_key_iv,
|
const std::string& signature, const std::vector<CryptoKey>& key_array,
|
||||||
const std::string& mac_key, const std::vector<CryptoKey>& key_array,
|
|
||||||
const video_widevine::License& license) {
|
const video_widevine::License& license) {
|
||||||
if (key_array.empty()) {
|
if (key_array.empty()) {
|
||||||
LOGE("No content keys provided");
|
LOGE("No content keys provided");
|
||||||
return NO_CONTENT_KEY;
|
return NO_CONTENT_KEY;
|
||||||
}
|
}
|
||||||
CdmResponseType resp;
|
const CdmResponseType resp = crypto_session_->LoadLicense(
|
||||||
if (supports_core_messages()) {
|
msg, core_message, signature, kLicenseKeyTypeContent);
|
||||||
resp = crypto_session_->LoadLicense(msg, core_message, signature,
|
|
||||||
kLicenseKeyTypeContent);
|
|
||||||
} else {
|
|
||||||
resp = crypto_session_->LoadKeys(
|
|
||||||
msg, signature, mac_key_iv, mac_key, key_array, provider_session_token_,
|
|
||||||
license.srm_requirement(), kLicenseKeyTypeContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (KEY_ADDED == resp) {
|
if (KEY_ADDED == resp) {
|
||||||
loaded_keys_.clear();
|
loaded_keys_.clear();
|
||||||
for (std::vector<CryptoKey>::const_iterator it = key_array.begin();
|
for (const CryptoKey& key : key_array) {
|
||||||
it != key_array.end(); ++it) {
|
loaded_keys_.insert(key.key_id());
|
||||||
loaded_keys_.insert(it->key_id());
|
|
||||||
}
|
}
|
||||||
policy_engine_->SetLicense(license, supports_core_messages(), is_restore);
|
policy_engine_->SetLicense(license, is_restore);
|
||||||
}
|
}
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType CdmLicense::HandleEntitlementKeyResponse(
|
CdmResponseType CdmLicense::HandleEntitlementKeyResponse(
|
||||||
bool is_restore, const std::string& msg, const std::string& core_message,
|
bool is_restore, const std::string& msg, const std::string& core_message,
|
||||||
const std::string& signature, const std::string& mac_key_iv,
|
const std::string& signature, const std::vector<CryptoKey>& key_array,
|
||||||
const std::string& mac_key, const std::vector<CryptoKey>& key_array,
|
|
||||||
const video_widevine::License& license) {
|
const video_widevine::License& license) {
|
||||||
if (key_array.empty()) {
|
if (key_array.empty()) {
|
||||||
LOGE("No entitlement keys provided");
|
LOGE("No entitlement keys provided");
|
||||||
return NO_CONTENT_KEY;
|
return NO_CONTENT_KEY;
|
||||||
}
|
}
|
||||||
CdmResponseType resp;
|
const CdmResponseType resp = crypto_session_->LoadLicense(
|
||||||
if (supports_core_messages()) {
|
msg, core_message, signature, kLicenseKeyTypeEntitlement);
|
||||||
resp = crypto_session_->LoadLicense(msg, core_message, signature,
|
|
||||||
kLicenseKeyTypeEntitlement);
|
|
||||||
} else {
|
|
||||||
resp = crypto_session_->LoadKeys(
|
|
||||||
msg, signature, mac_key_iv, mac_key, key_array, provider_session_token_,
|
|
||||||
license.srm_requirement(), kLicenseKeyTypeEntitlement);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (KEY_ADDED != resp) {
|
if (KEY_ADDED != resp) {
|
||||||
return resp;
|
return resp;
|
||||||
@@ -1190,8 +1099,7 @@ CdmResponseType CdmLicense::HandleEntitlementKeyResponse(
|
|||||||
|
|
||||||
// Save the entitlement keys for future use to handle key changes.
|
// Save the entitlement keys for future use to handle key changes.
|
||||||
entitlement_keys_.CopyFrom(license.key());
|
entitlement_keys_.CopyFrom(license.key());
|
||||||
policy_engine_->SetLicense(license, supports_core_messages(), is_restore);
|
policy_engine_->SetLicense(license, is_restore);
|
||||||
|
|
||||||
return HandleNewEntitledKeys(wrapped_keys_);
|
return HandleNewEntitledKeys(wrapped_keys_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1199,22 +1107,14 @@ CdmResponseType CdmLicense::HandleNewEntitledKeys(
|
|||||||
const std::vector<WidevinePsshData_EntitledKey>& wrapped_keys) {
|
const std::vector<WidevinePsshData_EntitledKey>& wrapped_keys) {
|
||||||
std::vector<CryptoKey> entitled_key_array;
|
std::vector<CryptoKey> entitled_key_array;
|
||||||
entitled_key_array.reserve(wrapped_keys.size());
|
entitled_key_array.reserve(wrapped_keys.size());
|
||||||
|
for (const auto& kc : entitlement_keys_) {
|
||||||
for (RepeatedPtrField<License_KeyContainer>::const_iterator kc =
|
if (kc.type() != video_widevine::License::KeyContainer::ENTITLEMENT) {
|
||||||
entitlement_keys_.begin();
|
|
||||||
kc != entitlement_keys_.end(); ++kc) {
|
|
||||||
if (kc->type() != video_widevine::License::KeyContainer::ENTITLEMENT) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (std::vector<WidevinePsshData_EntitledKey>::const_iterator wk =
|
for (const auto& wk : wrapped_keys) {
|
||||||
wrapped_keys.begin();
|
if (wk.entitlement_key_id() != kc.id()) continue;
|
||||||
wk != wrapped_keys.end(); wk++) {
|
|
||||||
if (wk->entitlement_key_id() == kc->id()) {
|
|
||||||
// Add a new entry to the key array to load oemcrypto.
|
|
||||||
entitled_key_array.resize(entitled_key_array.size() + 1);
|
|
||||||
|
|
||||||
// Strip PKCS#5 padding from entitled content keys.
|
// Strip PKCS#5 padding from entitled content keys.
|
||||||
std::string content_key = wk->key();
|
std::string content_key = wk.key();
|
||||||
if (content_key.size() < CONTENT_KEY_SIZE) {
|
if (content_key.size() < CONTENT_KEY_SIZE) {
|
||||||
LOGE(
|
LOGE(
|
||||||
"Entitled content key too small: "
|
"Entitled content key too small: "
|
||||||
@@ -1225,27 +1125,24 @@ CdmResponseType CdmLicense::HandleNewEntitledKeys(
|
|||||||
content_key.resize(CONTENT_KEY_SIZE);
|
content_key.resize(CONTENT_KEY_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
CryptoKey& this_entry = entitled_key_array.back();
|
CryptoKey this_entry;
|
||||||
this_entry.set_key_id(wk->key_id());
|
this_entry.set_key_id(wk.key_id());
|
||||||
this_entry.set_key_data_iv(wk->iv());
|
this_entry.set_key_data_iv(wk.iv());
|
||||||
this_entry.set_entitlement_key_id(wk->entitlement_key_id());
|
this_entry.set_entitlement_key_id(wk.entitlement_key_id());
|
||||||
this_entry.set_key_data(content_key);
|
this_entry.set_key_data(content_key);
|
||||||
}
|
// Add a new entry to the key array to load oemcrypto.
|
||||||
|
entitled_key_array.push_back(std::move(this_entry));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType resp =
|
const CdmResponseType resp =
|
||||||
crypto_session_->LoadEntitledContentKeys(entitled_key_array);
|
crypto_session_->LoadEntitledContentKeys(entitled_key_array);
|
||||||
if (KEY_ADDED == resp) {
|
if (resp != KEY_ADDED) return resp;
|
||||||
for (std::vector<WidevinePsshData_EntitledKey>::const_iterator it =
|
for (const auto& wk : wrapped_keys) {
|
||||||
wrapped_keys.begin();
|
loaded_keys_.insert(wk.key_id());
|
||||||
it != wrapped_keys.end(); ++it) {
|
|
||||||
loaded_keys_.insert(it->key_id());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
policy_engine_->SetEntitledLicenseKeys(wrapped_keys);
|
policy_engine_->SetEntitledLicenseKeys(wrapped_keys);
|
||||||
}
|
return KEY_ADDED;
|
||||||
return resp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include "clock.h"
|
#include "clock.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "policy_timers_v15.h"
|
|
||||||
#include "policy_timers_v16.h"
|
#include "policy_timers_v16.h"
|
||||||
#include "properties.h"
|
#include "properties.h"
|
||||||
#include "string_conversions.h"
|
#include "string_conversions.h"
|
||||||
@@ -30,14 +29,11 @@ namespace wvcdm {
|
|||||||
PolicyEngine::PolicyEngine(CdmSessionId session_id,
|
PolicyEngine::PolicyEngine(CdmSessionId session_id,
|
||||||
WvCdmEventListener* event_listener,
|
WvCdmEventListener* event_listener,
|
||||||
CryptoSession* crypto_session)
|
CryptoSession* crypto_session)
|
||||||
: license_state_(kLicenseStateInitial),
|
: session_id_(session_id),
|
||||||
license_state_update_deadline_(0),
|
|
||||||
last_recorded_current_time_(0),
|
|
||||||
session_id_(session_id),
|
|
||||||
event_listener_(event_listener),
|
event_listener_(event_listener),
|
||||||
license_keys_(new LicenseKeys(crypto_session->GetSecurityLevel())),
|
license_keys_(new LicenseKeys(crypto_session->GetSecurityLevel())),
|
||||||
policy_timers_(new PolicyTimersV15),
|
policy_timers_(new PolicyTimersV16()),
|
||||||
clock_(new wvutil::Clock) {
|
clock_(new wvutil::Clock()) {
|
||||||
InitDevice(crypto_session);
|
InitDevice(crypto_session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,11 +42,10 @@ PolicyEngine::~PolicyEngine() {}
|
|||||||
bool PolicyEngine::CanDecryptContent(const KeyId& key_id) {
|
bool PolicyEngine::CanDecryptContent(const KeyId& key_id) {
|
||||||
if (license_keys_->IsContentKey(key_id)) {
|
if (license_keys_->IsContentKey(key_id)) {
|
||||||
return license_keys_->CanDecryptContent(key_id);
|
return license_keys_->CanDecryptContent(key_id);
|
||||||
} else {
|
}
|
||||||
LOGE("Provided content key is not in license: key_id = %s",
|
LOGE("Provided content key is not in license: key_id = %s",
|
||||||
wvutil::b2a_hex(key_id).c_str());
|
wvutil::b2a_hex(key_id).c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmKeyStatus PolicyEngine::GetKeyStatus(const KeyId& key_id) {
|
CdmKeyStatus PolicyEngine::GetKeyStatus(const KeyId& key_id) {
|
||||||
@@ -104,7 +99,8 @@ void PolicyEngine::OnTimerEvent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we have passed the grace period, the expiration will update.
|
// If we have passed the grace period, the expiration will update.
|
||||||
if (policy_timers_->HasPassedGracePeriod(current_time)) {
|
if (license_state_ != kLicenseStateInitial &&
|
||||||
|
policy_timers_->HasPassedGracePeriod(current_time)) {
|
||||||
NotifyExpirationUpdate(current_time);
|
NotifyExpirationUpdate(current_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,9 +168,7 @@ void PolicyEngine::OnTimerEvent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PolicyEngine::SetLicense(const License& license,
|
void PolicyEngine::SetLicense(const License& license,
|
||||||
bool supports_core_messages,
|
|
||||||
bool defer_license_state_update) {
|
bool defer_license_state_update) {
|
||||||
if (supports_core_messages) policy_timers_.reset(new PolicyTimersV16());
|
|
||||||
license_id_.CopyFrom(license.id());
|
license_id_.CopyFrom(license.id());
|
||||||
license_keys_->SetFromLicense(license);
|
license_keys_->SetFromLicense(license);
|
||||||
policy_timers_->SetLicense(license);
|
policy_timers_->SetLicense(license);
|
||||||
@@ -186,11 +180,8 @@ void PolicyEngine::SetEntitledLicenseKeys(
|
|||||||
license_keys_->SetEntitledKeys(entitled_keys);
|
license_keys_->SetEntitledKeys(entitled_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PolicyEngine::SetLicenseForRelease(const License& license,
|
void PolicyEngine::SetLicenseForRelease(const License& license) {
|
||||||
bool supports_core_messages) {
|
|
||||||
if (supports_core_messages) policy_timers_.reset(new PolicyTimersV16());
|
|
||||||
license_id_.CopyFrom(license.id());
|
license_id_.CopyFrom(license.id());
|
||||||
|
|
||||||
// Expire any old keys.
|
// Expire any old keys.
|
||||||
NotifyKeysChange(kKeyStatusExpired);
|
NotifyKeysChange(kKeyStatusExpired);
|
||||||
policy_timers_->SetLicense(license);
|
policy_timers_->SetLicense(license);
|
||||||
@@ -211,18 +202,20 @@ void PolicyEngine::UpdateLicense(const License& license,
|
|||||||
|
|
||||||
// if renewal, discard license if version has not been updated
|
// if renewal, discard license if version has not been updated
|
||||||
if (license_state_ != kLicenseStateInitial) {
|
if (license_state_ != kLicenseStateInitial) {
|
||||||
if (license.id().version() > license_id_.version())
|
if (license.id().version() > license_id_.version()) {
|
||||||
license_id_.CopyFrom(license.id());
|
license_id_.CopyFrom(license.id());
|
||||||
else
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const int64_t current_time = GetCurrentTime();
|
const int64_t current_time = GetCurrentTime();
|
||||||
policy_timers_->UpdateLicense(current_time, license);
|
policy_timers_->UpdateLicense(current_time, license);
|
||||||
if (defer_license_state_update)
|
if (defer_license_state_update) {
|
||||||
license_state_update_deadline_ = current_time + kLicenseStateUpdateDelay;
|
license_state_update_deadline_ = current_time + kLicenseStateUpdateDelay;
|
||||||
else
|
} else {
|
||||||
UpdateLicenseState(current_time);
|
UpdateLicenseState(current_time);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PolicyEngine::UpdateLicenseState(int64_t current_time) {
|
void PolicyEngine::UpdateLicenseState(int64_t current_time) {
|
||||||
@@ -410,17 +403,19 @@ void PolicyEngine::NotifyKeysChange(CdmKeyStatus new_status) {
|
|||||||
void PolicyEngine::NotifyExpirationUpdate(int64_t current_time) {
|
void PolicyEngine::NotifyExpirationUpdate(int64_t current_time) {
|
||||||
int64_t expiry_time;
|
int64_t expiry_time;
|
||||||
if (policy_timers_->UpdateExpirationTime(current_time, &expiry_time)) {
|
if (policy_timers_->UpdateExpirationTime(current_time, &expiry_time)) {
|
||||||
if (event_listener_)
|
if (event_listener_) {
|
||||||
event_listener_->OnExpirationUpdate(session_id_, expiry_time);
|
event_listener_->OnExpirationUpdate(session_id_, expiry_time);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t PolicyEngine::GetCurrentTime() {
|
int64_t PolicyEngine::GetCurrentTime() {
|
||||||
int64_t current_time = clock_->GetCurrentTime();
|
int64_t current_time = clock_->GetCurrentTime();
|
||||||
if (current_time + kClockSkewDelta < last_recorded_current_time_)
|
if (current_time + kClockSkewDelta < last_recorded_current_time_) {
|
||||||
current_time = last_recorded_current_time_;
|
current_time = last_recorded_current_time_;
|
||||||
else
|
} else {
|
||||||
last_recorded_current_time_ = current_time;
|
last_recorded_current_time_ = current_time;
|
||||||
|
}
|
||||||
return current_time;
|
return current_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ class HdcpOnlyMockCryptoSession : public TestCryptoSession {
|
|||||||
|
|
||||||
MOCK_METHOD(CdmResponseType, GetHdcpCapabilities,
|
MOCK_METHOD(CdmResponseType, GetHdcpCapabilities,
|
||||||
(HdcpCapability*, HdcpCapability*), (override));
|
(HdcpCapability*, HdcpCapability*), (override));
|
||||||
|
CdmSecurityLevel GetSecurityLevel() override { return kSecurityLevelL1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class MockCdmEventListener : public WvCdmEventListener {
|
class MockCdmEventListener : public WvCdmEventListener {
|
||||||
@@ -241,7 +242,7 @@ TEST_F(PolicyEngineConstraintsTest, IsPermissiveWithoutAResolution) {
|
|||||||
.WillRepeatedly(DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
.WillRepeatedly(DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||||
Return(GET_HDCP_CAPABILITY_FAILED)));
|
Return(GET_HDCP_CAPABILITY_FAILED)));
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_, false, false);
|
policy_engine_->SetLicense(license_, false);
|
||||||
policy_engine_->OnTimerEvent();
|
policy_engine_->OnTimerEvent();
|
||||||
|
|
||||||
EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId1));
|
EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId1));
|
||||||
@@ -273,7 +274,7 @@ TEST_F(PolicyEngineConstraintsTest, HandlesResolutionsBasedOnConstraints) {
|
|||||||
.WillRepeatedly(
|
.WillRepeatedly(
|
||||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT), Return(NO_ERROR)));
|
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT), Return(NO_ERROR)));
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_, false, false);
|
policy_engine_->SetLicense(license_, false);
|
||||||
policy_engine_->NotifyResolution(1, kTargetRes1);
|
policy_engine_->NotifyResolution(1, kTargetRes1);
|
||||||
policy_engine_->OnTimerEvent();
|
policy_engine_->OnTimerEvent();
|
||||||
EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId1));
|
EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId1));
|
||||||
@@ -337,7 +338,7 @@ TEST_F(PolicyEngineConstraintsTest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
policy_engine_->NotifyResolution(1, kTargetRes1);
|
policy_engine_->NotifyResolution(1, kTargetRes1);
|
||||||
policy_engine_->SetLicense(license_, false, false);
|
policy_engine_->SetLicense(license_, false);
|
||||||
policy_engine_->OnTimerEvent();
|
policy_engine_->OnTimerEvent();
|
||||||
policy_engine_->OnTimerEvent();
|
policy_engine_->OnTimerEvent();
|
||||||
policy_engine_->OnTimerEvent();
|
policy_engine_->OnTimerEvent();
|
||||||
@@ -370,7 +371,7 @@ TEST_F(PolicyEngineConstraintsTest, HandlesConstraintOverridingHdcp) {
|
|||||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||||
.WillRepeatedly(DoAll(SetArgPointee<0>(HDCP_V2), Return(NO_ERROR)));
|
.WillRepeatedly(DoAll(SetArgPointee<0>(HDCP_V2), Return(NO_ERROR)));
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_, false, false);
|
policy_engine_->SetLicense(license_, false);
|
||||||
policy_engine_->NotifyResolution(1, kTargetRes1);
|
policy_engine_->NotifyResolution(1, kTargetRes1);
|
||||||
policy_engine_->OnTimerEvent();
|
policy_engine_->OnTimerEvent();
|
||||||
EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId1));
|
EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId1));
|
||||||
@@ -412,7 +413,7 @@ TEST_F(PolicyEngineConstraintsTest, HandlesNoHdcp) {
|
|||||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||||
.WillRepeatedly(DoAll(SetArgPointee<0>(HDCP_NONE), Return(NO_ERROR)));
|
.WillRepeatedly(DoAll(SetArgPointee<0>(HDCP_NONE), Return(NO_ERROR)));
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_, false, false);
|
policy_engine_->SetLicense(license_, false);
|
||||||
|
|
||||||
policy_engine_->NotifyResolution(1, kTargetRes1);
|
policy_engine_->NotifyResolution(1, kTargetRes1);
|
||||||
policy_engine_->OnTimerEvent();
|
policy_engine_->OnTimerEvent();
|
||||||
@@ -456,7 +457,7 @@ TEST_F(PolicyEngineConstraintsTest, UsesDefaultHdcpWhenResolutionNotSet) {
|
|||||||
.WillRepeatedly(DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
.WillRepeatedly(DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||||
Return(GET_HDCP_CAPABILITY_FAILED)));
|
Return(GET_HDCP_CAPABILITY_FAILED)));
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_, false, false);
|
policy_engine_->SetLicense(license_, false);
|
||||||
policy_engine_->OnTimerEvent();
|
policy_engine_->OnTimerEvent();
|
||||||
EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId1));
|
EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId1));
|
||||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId2));
|
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId2));
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user