Source release 16.2.0
This commit is contained in:
@@ -27,7 +27,7 @@ namespace wvcdm {
|
||||
class BufferReader {
|
||||
public:
|
||||
BufferReader(const uint8_t* buf, size_t size)
|
||||
: buf_(buf), size_(buf != NULL ? size : 0), pos_(0) {}
|
||||
: buf_(buf), size_(buf != nullptr ? size : 0), pos_(0) {}
|
||||
|
||||
bool HasBytes(size_t count) const { return pos_ + count <= size_; }
|
||||
bool IsEOF() const { return pos_ >= size_; }
|
||||
|
||||
@@ -195,9 +195,6 @@ class CdmEngine {
|
||||
// system. This will force the device to reprovision itself.
|
||||
virtual CdmResponseType Unprovision(CdmSecurityLevel security_level);
|
||||
|
||||
// Delete OEMCrypto usage tables. Used by Unprovision().
|
||||
virtual CdmResponseType DeleteUsageTable(CdmSecurityLevel security_level);
|
||||
|
||||
// Return the list of key_set_ids stored on the current (origin-specific)
|
||||
// file system.
|
||||
virtual CdmResponseType ListStoredLicenses(
|
||||
@@ -261,8 +258,9 @@ class CdmEngine {
|
||||
|
||||
// Decryption and key related methods
|
||||
// Accept encrypted buffer and return decrypted data.
|
||||
virtual CdmResponseType Decrypt(const CdmSessionId& session_id,
|
||||
const CdmDecryptionParameters& parameters);
|
||||
virtual CdmResponseType DecryptV16(
|
||||
const CdmSessionId& session_id,
|
||||
const CdmDecryptionParametersV16& parameters);
|
||||
|
||||
// Generic crypto operations - provides basic crypto operations that an
|
||||
// application can use outside of content stream processing
|
||||
@@ -343,6 +341,7 @@ class CdmEngine {
|
||||
app_package_name_ = app_package_name;
|
||||
}
|
||||
virtual const std::string& GetAppPackageName() { return app_package_name_; }
|
||||
virtual void SetSpoid(const std::string& spoid) { spoid_ = spoid; }
|
||||
|
||||
protected:
|
||||
friend class CdmEngineFactory;
|
||||
@@ -353,8 +352,7 @@ class CdmEngine {
|
||||
friend class TestLicenseHolder;
|
||||
|
||||
CdmEngine(FileSystem* file_system,
|
||||
std::shared_ptr<metrics::EngineMetrics> metrics,
|
||||
const std::string& spoid = EMPTY_SPOID);
|
||||
std::shared_ptr<metrics::EngineMetrics> metrics);
|
||||
|
||||
private:
|
||||
// private methods
|
||||
@@ -364,7 +362,6 @@ class CdmEngine {
|
||||
const CdmSessionId* forced_session_id,
|
||||
CdmSessionId* session_id);
|
||||
|
||||
void DeleteAllUsageReportsUponFactoryReset();
|
||||
bool ValidateKeySystem(const CdmKeySystem& key_system);
|
||||
CdmResponseType GetUsageInfo(const std::string& app_id,
|
||||
SecurityLevel requested_security_level,
|
||||
@@ -396,9 +393,10 @@ class CdmEngine {
|
||||
Clock clock_;
|
||||
std::string spoid_;
|
||||
|
||||
static bool seeded_;
|
||||
|
||||
// usage related variables
|
||||
// Usage related variables
|
||||
// Used to isolate a single active usage information license. Loading,
|
||||
// creating or releasing a different usage licenses through the engine
|
||||
// API will release the handle to previously active secure stop license.
|
||||
std::unique_ptr<CdmSession> usage_session_;
|
||||
std::unique_ptr<UsagePropertySet> usage_property_set_;
|
||||
int64_t last_usage_information_update_time_;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "disallow_copy_and_assign.h"
|
||||
#include "file_store.h"
|
||||
#include "initialization_data.h"
|
||||
#include "log.h"
|
||||
#include "metrics_collections.h"
|
||||
#include "oemcrypto_adapter.h"
|
||||
#include "properties.h"
|
||||
@@ -47,9 +48,8 @@ class CdmEngineMetricsImpl : public T {
|
||||
// |metrics| is used within the base class constructor. So, it must be
|
||||
// passed in as a dependency and provided to the base constructor.
|
||||
CdmEngineMetricsImpl(FileSystem* file_system,
|
||||
std::shared_ptr<metrics::EngineMetrics> metrics,
|
||||
const std::string& spoid = EMPTY_SPOID)
|
||||
: T(file_system, metrics, spoid), metrics_(metrics) {
|
||||
std::shared_ptr<metrics::EngineMetrics> metrics)
|
||||
: T(file_system, metrics), metrics_(metrics) {
|
||||
metrics_->cdm_engine_creation_time_millis_.Record(clock_.GetCurrentTime());
|
||||
std::string cdm_version;
|
||||
if (Properties::GetWVCdmVersion(&cdm_version)) {
|
||||
@@ -121,7 +121,7 @@ class CdmEngineMetricsImpl : public T {
|
||||
CdmLicenseType* license_type,
|
||||
CdmKeySetId* key_set_id) override {
|
||||
if (license_type == nullptr) {
|
||||
LOGE("CdmEngine::AddKey: license_type cannot be null.");
|
||||
LOGE("|license_type| cannot be null");
|
||||
return PARAMETER_NULL;
|
||||
}
|
||||
|
||||
@@ -251,12 +251,17 @@ class CdmEngineMetricsImpl : public T {
|
||||
return status;
|
||||
}
|
||||
|
||||
CdmResponseType Decrypt(const CdmSessionId& session_id,
|
||||
const CdmDecryptionParameters& parameters) override {
|
||||
CdmResponseType DecryptV16(
|
||||
const CdmSessionId& session_id,
|
||||
const CdmDecryptionParametersV16& parameters) override {
|
||||
size_t total_size = 0;
|
||||
for (const CdmDecryptionSample& sample : parameters.samples) {
|
||||
total_size += sample.encrypt_buffer_length;
|
||||
}
|
||||
|
||||
CdmResponseType sts;
|
||||
M_TIME(sts = T::Decrypt(session_id, parameters), metrics_,
|
||||
cdm_engine_decrypt_, sts,
|
||||
metrics::Pow2Bucket(parameters.encrypt_length));
|
||||
M_TIME(sts = T::DecryptV16(session_id, parameters), metrics_,
|
||||
cdm_engine_decrypt_, sts, metrics::Pow2Bucket(total_size));
|
||||
return sts;
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ class CdmSession {
|
||||
virtual CdmResponseType QueryOemCryptoSessionId(CdmQueryMap* query_response);
|
||||
|
||||
// Decrypt() - Accept encrypted buffer and return decrypted data.
|
||||
virtual CdmResponseType Decrypt(const CdmDecryptionParameters& parameters);
|
||||
virtual CdmResponseType Decrypt(const CdmDecryptionParametersV16& parameters);
|
||||
|
||||
// License renewal
|
||||
// GenerateRenewalRequest() - Construct valid renewal request for the current
|
||||
@@ -142,10 +142,6 @@ class CdmSession {
|
||||
}
|
||||
virtual CdmSecurityLevel GetSecurityLevel() { return security_level_; }
|
||||
|
||||
// Delete usage information for the list of tokens, |provider_session_tokens|.
|
||||
virtual CdmResponseType DeleteMultipleUsageInformation(
|
||||
const std::vector<std::string>& provider_session_tokens);
|
||||
virtual CdmResponseType UpdateUsageTableInformation();
|
||||
virtual CdmResponseType UpdateUsageEntryInformation();
|
||||
|
||||
virtual bool is_initial_usage_update() { return is_initial_usage_update_; }
|
||||
@@ -160,7 +156,7 @@ class CdmSession {
|
||||
virtual bool is_temporary() { return is_temporary_; }
|
||||
virtual bool license_received() { return license_received_; }
|
||||
virtual bool has_provider_session_token() {
|
||||
return (license_parser_.get() != NULL &&
|
||||
return (license_parser_ &&
|
||||
license_parser_->provider_session_token().size() > 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,21 @@ class CertificateProvisioning {
|
||||
FileSystem* file_system, const CdmProvisioningResponse& response,
|
||||
std::string* cert, std::string* wrapped_key);
|
||||
|
||||
bool supports_core_messages() const { return supports_core_messages_; }
|
||||
|
||||
// Helper methods
|
||||
|
||||
// Extract serial number and system ID from a DRM Device certificate.
|
||||
// Either |serial_number| or |system_id| may be null, but not both.
|
||||
static bool ExtractDeviceInfo(const std::string& device_certificate,
|
||||
std::string* serial_number,
|
||||
uint32_t* system_id);
|
||||
|
||||
// Removes json wrapping if applicable to extract the
|
||||
// SignedProvisioningMessage
|
||||
static bool ExtractAndDecodeSignedMessageForTesting(
|
||||
const std::string& provisioning_response, std::string* result);
|
||||
|
||||
private:
|
||||
CdmResponseType SetSpoidParameter(
|
||||
const std::string& origin, const std::string& spoid,
|
||||
@@ -60,6 +75,13 @@ class CertificateProvisioning {
|
||||
CdmCertificateType cert_type_;
|
||||
std::unique_ptr<ServiceCertificate> service_certificate_;
|
||||
|
||||
// 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);
|
||||
};
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@ class ContentKeySession : public KeySession {
|
||||
const std::string& mac_key,
|
||||
const std::vector<CryptoKey>& keys,
|
||||
const std::string& provider_session_token,
|
||||
CdmCipherMode* cipher_mode,
|
||||
const std::string& srm_requirement) override;
|
||||
|
||||
OEMCryptoResult LoadEntitledContentKeys(
|
||||
@@ -50,16 +49,15 @@ class ContentKeySession : public KeySession {
|
||||
|
||||
// Decrypt for ContentKeySession
|
||||
OEMCryptoResult Decrypt(
|
||||
const CdmDecryptionParameters& params,
|
||||
OEMCrypto_DestBufferDesc& buffer_descriptor,
|
||||
OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor) override;
|
||||
const OEMCrypto_SampleDescription* samples, size_t samples_length,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern) override;
|
||||
|
||||
protected:
|
||||
virtual OEMCryptoResult LoadKeysAsLicenseType(
|
||||
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, CdmCipherMode* cipher_mode,
|
||||
const std::string& provider_session_token,
|
||||
const std::string& srm_requirement, OEMCrypto_LicenseType license_type);
|
||||
|
||||
CryptoSessionId oec_session_id_;
|
||||
|
||||
@@ -44,11 +44,11 @@ class CryptoSessionFactory;
|
||||
class CryptoSession {
|
||||
public:
|
||||
using HdcpCapability = OEMCrypto_HDCP_Capability;
|
||||
typedef enum {
|
||||
enum UsageDurationStatus {
|
||||
kUsageDurationsInvalid = 0,
|
||||
kUsageDurationPlaybackNotBegun = 1,
|
||||
kUsageDurationsValid = 2,
|
||||
} UsageDurationStatus;
|
||||
};
|
||||
|
||||
struct SupportedCertificateTypes {
|
||||
bool rsa_2048_bit;
|
||||
@@ -64,6 +64,17 @@ class CryptoSession {
|
||||
|
||||
virtual ~CryptoSession();
|
||||
|
||||
// This method will try to terminate OEMCrypto if |session_size_| is 0.
|
||||
// A platform configured property |delay_oem_crypto_termination| will
|
||||
// determine if termination occurs immediately or after a delay.
|
||||
// If termination is delayed, a countdown mechanism is employed.
|
||||
// Call |TryTerminate| periodically until it no longer returns true.
|
||||
// To immediately terminate call |DisableDelayedTermination| before calling
|
||||
// |TryTerminate|.
|
||||
static bool TryTerminate();
|
||||
|
||||
static void DisableDelayedTermination();
|
||||
|
||||
virtual CdmResponseType GetProvisioningToken(std::string* client_token);
|
||||
virtual CdmClientTokenType GetPreProvisionTokenType() {
|
||||
return pre_provision_token_type_;
|
||||
@@ -75,6 +86,8 @@ class CryptoSession {
|
||||
virtual CdmSecurityLevel GetSecurityLevel(SecurityLevel requested_level);
|
||||
virtual bool GetApiVersion(uint32_t* version);
|
||||
virtual bool GetApiVersion(SecurityLevel requested_level, uint32_t* version);
|
||||
virtual bool GetApiMinorVersion(SecurityLevel requested_level,
|
||||
uint32_t* minor_version);
|
||||
|
||||
virtual CdmResponseType GetInternalDeviceUniqueId(std::string* device_id);
|
||||
virtual CdmResponseType GetExternalDeviceUniqueId(std::string* device_id);
|
||||
@@ -89,13 +102,15 @@ class CryptoSession {
|
||||
virtual bool IsOpen() { return open_; }
|
||||
virtual CryptoSessionId oec_session_id() { return oec_session_id_; }
|
||||
|
||||
// Key request/response
|
||||
// All request/responses
|
||||
virtual const std::string& request_id() { return request_id_; }
|
||||
virtual CdmResponseType PrepareRequest(const std::string& key_deriv_message,
|
||||
bool is_provisioning,
|
||||
std::string* signature);
|
||||
virtual CdmResponseType PrepareRenewalRequest(const std::string& message,
|
||||
std::string* signature);
|
||||
virtual CdmResponseType GenerateNonce(uint32_t* nonce);
|
||||
|
||||
// License request/responses
|
||||
virtual CdmResponseType PrepareAndSignLicenseRequest(
|
||||
const std::string& message, std::string* core_message,
|
||||
std::string* signature);
|
||||
// V15 licenses.
|
||||
virtual CdmResponseType LoadKeys(const std::string& message,
|
||||
const std::string& signature,
|
||||
const std::string& mac_key_iv,
|
||||
@@ -104,52 +119,46 @@ class CryptoSession {
|
||||
const std::string& provider_session_token,
|
||||
const std::string& srm_requirement,
|
||||
CdmLicenseKeyType key_type);
|
||||
virtual CdmResponseType LoadEntitledContentKeys(
|
||||
const std::vector<CryptoKey>& key_array);
|
||||
virtual CdmResponseType LoadCertificatePrivateKey(std::string& wrapped_key);
|
||||
// V16 licenses.
|
||||
virtual CdmResponseType LoadLicense(const std::string& signed_message,
|
||||
const std::string& core_message,
|
||||
const std::string& signature,
|
||||
CdmLicenseKeyType key_type);
|
||||
|
||||
// Renewal request/responses
|
||||
virtual CdmResponseType PrepareAndSignRenewalRequest(
|
||||
const std::string& message, std::string* core_message,
|
||||
std::string* signature);
|
||||
// V15 licenses.
|
||||
virtual CdmResponseType RefreshKeys(const std::string& message,
|
||||
const std::string& signature,
|
||||
int num_keys, const CryptoKey* key_array);
|
||||
virtual CdmResponseType GenerateNonce(uint32_t* nonce);
|
||||
const std::vector<CryptoKey>& key_array);
|
||||
// V16 licenses.
|
||||
virtual CdmResponseType LoadRenewal(const std::string& signed_message,
|
||||
const std::string& core_message,
|
||||
const std::string& signature);
|
||||
|
||||
// Entitled content Keys.
|
||||
virtual CdmResponseType LoadEntitledContentKeys(
|
||||
const std::vector<CryptoKey>& key_array);
|
||||
|
||||
// Provisioning request/responses
|
||||
virtual CdmResponseType GenerateDerivedKeys(const std::string& message);
|
||||
virtual CdmResponseType GenerateDerivedKeys(const std::string& message,
|
||||
const std::string& session_key);
|
||||
virtual CdmResponseType RewrapCertificate(const std::string& signed_message,
|
||||
const std::string& signature,
|
||||
const std::string& nonce,
|
||||
const std::string& private_key,
|
||||
const std::string& iv,
|
||||
const std::string& wrapping_key,
|
||||
std::string* wrapped_private_key);
|
||||
virtual CdmResponseType PrepareAndSignProvisioningRequest(
|
||||
const std::string& message, std::string* core_message,
|
||||
std::string* signature);
|
||||
virtual CdmResponseType LoadProvisioning(const std::string& signed_message,
|
||||
const std::string& core_message,
|
||||
const std::string& signature,
|
||||
std::string* wrapped_private_key);
|
||||
virtual CdmResponseType LoadCertificatePrivateKey(
|
||||
const std::string& wrapped_key);
|
||||
|
||||
// Media data path
|
||||
virtual CdmResponseType Decrypt(const CdmDecryptionParameters& params);
|
||||
virtual CdmResponseType Decrypt(const CdmDecryptionParametersV16& params);
|
||||
|
||||
// Usage related methods
|
||||
// The overloaded method with |security_level| may be called without a
|
||||
// preceding call to Open. The other method must call Open first.
|
||||
virtual bool UsageInformationSupport(bool* has_support);
|
||||
virtual bool UsageInformationSupport(SecurityLevel security_level,
|
||||
bool* has_support);
|
||||
virtual CdmResponseType UpdateUsageInformation(); // only for OEMCrypto v9-12
|
||||
virtual CdmResponseType DeactivateUsageInformation(
|
||||
const std::string& provider_session_token);
|
||||
virtual CdmResponseType GenerateUsageReport(
|
||||
const std::string& provider_session_token, std::string* usage_report,
|
||||
UsageDurationStatus* usage_duration_status,
|
||||
int64_t* seconds_since_started, int64_t* seconds_since_last_played);
|
||||
virtual CdmResponseType ReleaseUsageInformation(
|
||||
const std::string& message, const std::string& signature,
|
||||
const std::string& provider_session_token);
|
||||
// Delete a usage information for a single token. This does not require
|
||||
// a signed message from the server.
|
||||
virtual CdmResponseType DeleteUsageInformation(
|
||||
const std::string& provider_session_token);
|
||||
// Delete usage information for a list of tokens. This does not require
|
||||
// a signed message from the server.
|
||||
virtual CdmResponseType DeleteMultipleUsageInformation(
|
||||
const std::vector<std::string>& provider_session_tokens);
|
||||
virtual CdmResponseType DeleteAllUsageReports();
|
||||
virtual bool IsAntiRollbackHwPresent();
|
||||
|
||||
// The overloaded methods with |security_level| may be called without a
|
||||
@@ -178,7 +187,11 @@ class CryptoSession {
|
||||
std::string* info);
|
||||
virtual bool GetBuildInformation(std::string* info);
|
||||
|
||||
virtual uint32_t IsDecryptHashSupported(SecurityLevel security_level);
|
||||
virtual bool GetMaximumUsageTableEntries(SecurityLevel security_level,
|
||||
size_t* number_of_entries);
|
||||
|
||||
virtual bool GetDecryptHashSupport(SecurityLevel security_level,
|
||||
uint32_t* hash_support);
|
||||
|
||||
virtual CdmResponseType SetDecryptHash(uint32_t frame_number,
|
||||
const std::string& hash);
|
||||
@@ -204,32 +217,49 @@ class CryptoSession {
|
||||
CdmSigningAlgorithm algorithm,
|
||||
const std::string& signature);
|
||||
|
||||
// Usage table header and usage entry related methods
|
||||
// Usage table API related methods.
|
||||
// Used to manipulate the CDM managed usage table header & entries,
|
||||
// delegating calls to OEMCrypto.
|
||||
|
||||
// Usage support.
|
||||
virtual CdmResponseType GetUsageSupportType(CdmUsageSupportType* type);
|
||||
|
||||
// The overloaded method with |security_level| may be called without a
|
||||
// preceding call to Open. The other method must call Open first.
|
||||
virtual bool UsageInformationSupport(bool* has_support);
|
||||
virtual bool UsageInformationSupport(SecurityLevel security_level,
|
||||
bool* has_support);
|
||||
|
||||
// Usage report.
|
||||
virtual CdmResponseType DeactivateUsageInformation(
|
||||
const std::string& provider_session_token);
|
||||
virtual CdmResponseType GenerateUsageReport(
|
||||
const std::string& provider_session_token, std::string* usage_report,
|
||||
UsageDurationStatus* usage_duration_status,
|
||||
int64_t* seconds_since_started, int64_t* seconds_since_last_played);
|
||||
|
||||
// Usage table header.
|
||||
virtual UsageTableHeader* GetUsageTableHeader() {
|
||||
return usage_table_header_;
|
||||
}
|
||||
virtual CdmResponseType GetUsageSupportType(CdmUsageSupportType* type);
|
||||
|
||||
virtual CdmResponseType CreateUsageTableHeader(
|
||||
CdmUsageTableHeader* usage_table_header);
|
||||
virtual CdmResponseType LoadUsageTableHeader(
|
||||
const CdmUsageTableHeader& usage_table_header);
|
||||
|
||||
// Usage entry.
|
||||
virtual CdmResponseType CreateUsageEntry(uint32_t* entry_number);
|
||||
virtual CdmResponseType LoadUsageEntry(uint32_t entry_number,
|
||||
const CdmUsageEntry& usage_entry);
|
||||
virtual CdmResponseType UpdateUsageEntry(
|
||||
CdmUsageTableHeader* usage_table_header, CdmUsageEntry* usage_entry);
|
||||
|
||||
// Adjust usage entries in usage table header.
|
||||
virtual CdmResponseType ShrinkUsageTableHeader(
|
||||
uint32_t new_entry_count, CdmUsageTableHeader* usage_table_header);
|
||||
virtual CdmResponseType MoveUsageEntry(uint32_t new_entry_number);
|
||||
virtual bool CreateOldUsageEntry(uint64_t time_since_license_received,
|
||||
uint64_t time_since_first_decrypt,
|
||||
uint64_t time_since_last_decrypt,
|
||||
UsageDurationStatus status,
|
||||
const std::string& server_mac_key,
|
||||
const std::string& client_mac_key,
|
||||
const std::string& provider_session_token);
|
||||
virtual CdmResponseType CopyOldUsageEntry(
|
||||
const std::string& provider_session_token);
|
||||
|
||||
virtual bool GetAnalogOutputCapabilities(bool* can_support_output,
|
||||
bool* can_disable_output,
|
||||
bool* can_support_cgms_a);
|
||||
@@ -249,7 +279,10 @@ class CryptoSession {
|
||||
private:
|
||||
friend class CryptoSessionForTest;
|
||||
friend class CryptoSessionFactory;
|
||||
#if defined(UNIT_TEST)
|
||||
friend class CertificateProvisioningTest;
|
||||
friend class WvCdmTestBase;
|
||||
#endif
|
||||
|
||||
// The global factory method can be set to generate special crypto sessions
|
||||
// just for testing. These sessions will avoid nonce floods and will ask
|
||||
@@ -261,33 +294,17 @@ class CryptoSession {
|
||||
}
|
||||
|
||||
void Init();
|
||||
void Terminate();
|
||||
CdmResponseType GetTokenFromKeybox(std::string* token);
|
||||
CdmResponseType GetTokenFromOemCert(std::string* token);
|
||||
static bool ExtractSystemIdFromOemCert(const std::string& oem_cert,
|
||||
uint32_t* system_id);
|
||||
CdmResponseType GetSystemIdInternal(uint32_t* system_id);
|
||||
CdmResponseType GenerateSignature(const std::string& message,
|
||||
std::string* signature);
|
||||
CdmResponseType GenerateRsaSignature(const std::string& message,
|
||||
std::string* signature);
|
||||
size_t GetMaxSubsampleRegionSize();
|
||||
|
||||
bool SetDestinationBufferType();
|
||||
|
||||
CdmResponseType RewrapDeviceRSAKey(const std::string& message,
|
||||
const std::string& signature,
|
||||
const std::string& nonce,
|
||||
const std::string& enc_rsa_key,
|
||||
const std::string& rsa_key_iv,
|
||||
std::string* wrapped_rsa_key);
|
||||
|
||||
CdmResponseType RewrapDeviceRSAKey30(const std::string& message,
|
||||
const std::string& nonce,
|
||||
const std::string& private_key,
|
||||
const std::string& iv,
|
||||
const std::string& wrapping_key,
|
||||
std::string* wrapped_private_key);
|
||||
|
||||
CdmResponseType SelectKey(const std::string& key_id,
|
||||
CdmCipherMode cipher_mode);
|
||||
|
||||
@@ -299,17 +316,24 @@ class CryptoSession {
|
||||
CdmEncryptionAlgorithm algorithm);
|
||||
size_t GenericEncryptionBlockSize(CdmEncryptionAlgorithm algorithm);
|
||||
|
||||
// These methods are used when a subsample exceeds the maximum buffer size
|
||||
// that the device can handle.
|
||||
OEMCryptoResult CopyBufferInChunks(
|
||||
const CdmDecryptionParameters& params,
|
||||
OEMCrypto_DestBufferDesc buffer_descriptor);
|
||||
OEMCryptoResult DecryptInChunks(
|
||||
const CdmDecryptionParameters& params,
|
||||
const OEMCrypto_DestBufferDesc& full_buffer_descriptor,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor,
|
||||
size_t max_chunk_size);
|
||||
static void IncrementIV(uint64_t increase_by, std::vector<uint8_t>* iv_out);
|
||||
// These methods fall back into each other in the order given, depending on
|
||||
// how much data they were given and how much data OEMCrypto can accept in one
|
||||
// call.
|
||||
OEMCryptoResult DecryptMultipleSamples(
|
||||
const std::vector<OEMCrypto_SampleDescription>& samples,
|
||||
CdmCipherMode cipher_mode,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern);
|
||||
OEMCryptoResult DecryptSample(
|
||||
const OEMCrypto_SampleDescription& sample, CdmCipherMode cipher_mode,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern);
|
||||
OEMCryptoResult LegacyDecrypt(
|
||||
const OEMCrypto_SampleDescription& sample, CdmCipherMode cipher_mode,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern);
|
||||
OEMCryptoResult LegacyCopyBufferInChunks(
|
||||
const OEMCrypto_SampleDescription& sample, size_t max_chunk_size);
|
||||
OEMCryptoResult LegacyDecryptInChunks(
|
||||
const OEMCrypto_SampleDescription& sample, CdmCipherMode cipher_mode,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern, size_t max_chunk_size);
|
||||
|
||||
// These methods should be used to take the various CryptoSession mutexes in
|
||||
// preference to taking the mutexes directly.
|
||||
@@ -332,7 +356,7 @@ class CryptoSession {
|
||||
// Initialization & Termination | WithOecWriteLock()
|
||||
// Property | WithOecReadLock()
|
||||
// Session Initialization | WithOecWriteLock()
|
||||
// Usage Table | WithOecWriteLock()
|
||||
// Usage Table Header & Entries | WithOecWriteLock()
|
||||
// Session | WithOecSessionLock()
|
||||
//
|
||||
// Note that accessing |key_session_| often accesses the OEMCrypto session, so
|
||||
@@ -380,6 +404,7 @@ class CryptoSession {
|
||||
|
||||
static bool initialized_;
|
||||
static int session_count_;
|
||||
static int termination_counter_;
|
||||
|
||||
metrics::CryptoMetrics* metrics_;
|
||||
metrics::TimerMetric life_span_;
|
||||
@@ -396,7 +421,6 @@ class CryptoSession {
|
||||
bool is_destination_buffer_type_valid_;
|
||||
SecurityLevel requested_security_level_;
|
||||
|
||||
bool is_usage_support_type_valid_;
|
||||
CdmUsageSupportType usage_support_type_;
|
||||
UsageTableHeader* usage_table_header_;
|
||||
static UsageTableHeader* usage_table_header_l1_;
|
||||
@@ -405,8 +429,15 @@ class CryptoSession {
|
||||
std::string request_id_;
|
||||
static std::atomic<uint64_t> request_id_index_source_;
|
||||
|
||||
CdmCipherMode cipher_mode_;
|
||||
uint32_t api_version_;
|
||||
size_t max_subsample_region_size_;
|
||||
|
||||
// Stores the most recent error code returned from a call to
|
||||
// OEMCrypto_DecryptCENC. This is used to reduce the total number of
|
||||
// error logs for decrypt calls, as there could be a large number of
|
||||
// same error code in sequence of each other. A value of
|
||||
// OEMCrypto_SUCCESS indicates that no error have yet occurred.
|
||||
OEMCryptoResult last_decrypt_error_ = OEMCrypto_SUCCESS;
|
||||
|
||||
// In order to avoid creating a deadlock if instantiation needs to take any
|
||||
// of the CryptoSession static mutexes, |factory_| is protected by its own
|
||||
@@ -415,7 +446,7 @@ class CryptoSession {
|
||||
static std::unique_ptr<CryptoSessionFactory> factory_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(CryptoSession);
|
||||
};
|
||||
}; // class CryptoSession
|
||||
|
||||
class CryptoSessionFactory {
|
||||
public:
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
#if defined(UNIT_TEST)
|
||||
#include <gtest/gtest_prod.h>
|
||||
# include <gtest/gtest_prod.h>
|
||||
#endif
|
||||
|
||||
namespace wvcdm {
|
||||
@@ -53,6 +53,31 @@ class DeviceFiles {
|
||||
kLicenseNotPresent = kResponseTypeBase + 16,
|
||||
};
|
||||
|
||||
// CdmLicenseData represents all of the data that is stored in CDM
|
||||
// license file. License data is uniquely keyed using |key_set_id|.
|
||||
struct CdmLicenseData {
|
||||
std::string key_set_id;
|
||||
LicenseState state;
|
||||
CdmInitData pssh_data;
|
||||
// License request / response.
|
||||
CdmKeyMessage license_request;
|
||||
CdmKeyResponse license;
|
||||
// License renewal request / response.
|
||||
CdmKeyMessage license_renewal_request;
|
||||
CdmKeyResponse license_renewal;
|
||||
// License release.
|
||||
std::string release_server_url;
|
||||
// License times.
|
||||
int64_t playback_start_time;
|
||||
int64_t last_playback_time;
|
||||
int64_t grace_period_end_time;
|
||||
// App parameters.
|
||||
CdmAppParameterMap app_parameters;
|
||||
// Usage entry and index.
|
||||
CdmUsageEntry usage_entry;
|
||||
uint32_t usage_entry_number;
|
||||
};
|
||||
|
||||
struct CdmUsageData {
|
||||
std::string provider_session_token;
|
||||
CdmKeyMessage license_request;
|
||||
@@ -79,27 +104,13 @@ class DeviceFiles {
|
||||
virtual bool HasCertificate();
|
||||
virtual bool RemoveCertificate();
|
||||
|
||||
virtual bool StoreLicense(
|
||||
const std::string& key_set_id, const LicenseState state,
|
||||
const CdmInitData& pssh_data, const CdmKeyMessage& key_request,
|
||||
const CdmKeyResponse& key_response,
|
||||
const CdmKeyMessage& key_renewal_request,
|
||||
const CdmKeyResponse& key_renewal_response,
|
||||
const std::string& release_server_url, int64_t playback_start_time,
|
||||
int64_t last_playback_time, int64_t grace_period_end_time,
|
||||
const CdmAppParameterMap& app_parameters,
|
||||
const CdmUsageEntry& usage_entry, uint32_t usage_entry_number,
|
||||
ResponseType* result);
|
||||
virtual bool StoreLicense(const CdmLicenseData& license_data,
|
||||
ResponseType* result);
|
||||
|
||||
virtual bool RetrieveLicense(const std::string& key_set_id,
|
||||
CdmLicenseData* license_data,
|
||||
ResponseType* result);
|
||||
|
||||
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* grace_period_end_time, CdmAppParameterMap* app_parameters,
|
||||
CdmUsageEntry* usage_entry, uint32_t* usage_entry_number,
|
||||
ResponseType* result);
|
||||
virtual bool DeleteLicense(const std::string& key_set_id);
|
||||
virtual bool ListLicenses(std::vector<std::string>* key_set_ids);
|
||||
virtual bool DeleteAllFiles();
|
||||
@@ -143,6 +154,27 @@ class DeviceFiles {
|
||||
virtual bool DeleteUsageInfo(const std::string& usage_info_file_name,
|
||||
const std::string& provider_session_token);
|
||||
|
||||
// Deletes a set of provider sessions from the specified usage info.
|
||||
// Sessions removed are based on the provided |key_set_ids|. If
|
||||
// there are no remaining sessions associated with the usage info
|
||||
// then the file will be deleted; otherwise, the remaining sessions
|
||||
// are written back to the usage info file.
|
||||
//
|
||||
// Args:
|
||||
// usage_info_file_name: name of the file containing the usage info
|
||||
// message. This name should _not_ be the complete path, just
|
||||
// the file name.
|
||||
// key_set_ids: The list of key set IDs to be removed from the
|
||||
// usage info. Note that any key set ids that are not present
|
||||
// in the usage info are silently ignored.
|
||||
// Returns:
|
||||
// `true` if the file existed, and operations were completed as
|
||||
// expected. `false` if the file does not exist or if there is an
|
||||
// issue writing the result back to file.
|
||||
virtual bool DeleteMultipleUsageInfoByKeySetIds(
|
||||
const std::string& usage_info_file_name,
|
||||
const std::vector<std::string>& key_set_ids);
|
||||
|
||||
// Delete usage information from the file system. Puts a list of all the
|
||||
// psts that were deleted from the file into |provider_session_tokens|.
|
||||
virtual bool DeleteAllUsageInfoForApp(
|
||||
@@ -201,17 +233,16 @@ class DeviceFiles {
|
||||
const CdmUsageTableHeader& usage_table_header,
|
||||
const std::vector<CdmUsageEntryInfo>& usage_entry_info);
|
||||
|
||||
// When retrieving usage table information from the file system; any
|
||||
// table that has yet to be updated for the LRU attributes will be
|
||||
// indicated by |lru_upgrade|.
|
||||
virtual bool RetrieveUsageTableInfo(
|
||||
CdmUsageTableHeader* usage_table_header,
|
||||
std::vector<CdmUsageEntryInfo>* usage_entry_info);
|
||||
std::vector<CdmUsageEntryInfo>* usage_entry_info, bool* lru_upgrade);
|
||||
|
||||
virtual bool DeleteUsageTableInfo();
|
||||
|
||||
private:
|
||||
// Extract serial number and system ID from DRM Device certificate
|
||||
bool ExtractDeviceInfo(const std::string& device_certificate,
|
||||
std::string* serial_number, uint32_t* system_id);
|
||||
|
||||
// Helpers that wrap the File interface and automatically handle hashing, as
|
||||
// well as adding the device files base path to to the file name.
|
||||
ResponseType StoreFileWithHash(const std::string& name,
|
||||
@@ -252,6 +283,7 @@ class DeviceFiles {
|
||||
FRIEND_TEST(DeviceFilesUsageInfoTest, Store);
|
||||
FRIEND_TEST(DeviceFilesUsageTableTest, Read);
|
||||
FRIEND_TEST(DeviceFilesUsageTableTest, Store);
|
||||
FRIEND_TEST(DeviceFilesUsageTableTest, ReadWithoutLruData);
|
||||
FRIEND_TEST(WvCdmRequestLicenseTest, UnprovisionTest);
|
||||
FRIEND_TEST(WvCdmRequestLicenseTest, ForceL3Test);
|
||||
FRIEND_TEST(WvCdmRequestLicenseTest, UsageInfoRetryTest);
|
||||
|
||||
@@ -30,7 +30,6 @@ class EntitlementKeySession : public ContentKeySession {
|
||||
const std::string& mac_key,
|
||||
const std::vector<CryptoKey>& keys,
|
||||
const std::string& provider_session_token,
|
||||
CdmCipherMode* cipher_mode,
|
||||
const std::string& srm_requirement) override;
|
||||
OEMCryptoResult LoadEntitledContentKeys(
|
||||
const std::vector<CryptoKey>& keys) override;
|
||||
|
||||
@@ -35,6 +35,11 @@ class InitializationData {
|
||||
std::vector<video_widevine::WidevinePsshData_EntitledKey> ExtractWrappedKeys()
|
||||
const;
|
||||
bool contains_entitled_keys() const { return contains_entitled_keys_; }
|
||||
// Dump information to the logs for debugging.
|
||||
void DumpToLogs() const;
|
||||
|
||||
// The static system ID for PSSH boxes indicating Widevine content.
|
||||
static const std::string WidevineSystemID();
|
||||
|
||||
private:
|
||||
bool SelectWidevinePssh(const CdmInitData& init_data,
|
||||
|
||||
@@ -32,16 +32,14 @@ class KeySession {
|
||||
const std::string& mac_key,
|
||||
const std::vector<CryptoKey>& keys,
|
||||
const std::string& provider_session_token,
|
||||
CdmCipherMode* cipher_mode,
|
||||
const std::string& srm_requirement) = 0;
|
||||
virtual OEMCryptoResult LoadEntitledContentKeys(
|
||||
const std::vector<CryptoKey>& keys) = 0;
|
||||
virtual OEMCryptoResult SelectKey(const std::string& key_id,
|
||||
CdmCipherMode cipher_mode) = 0;
|
||||
virtual OEMCryptoResult Decrypt(
|
||||
const CdmDecryptionParameters& params,
|
||||
OEMCrypto_DestBufferDesc& buffer_descriptor,
|
||||
OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor) = 0;
|
||||
const OEMCrypto_SampleDescription* samples, size_t samples_length,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern) = 0;
|
||||
|
||||
protected:
|
||||
metrics::CryptoMetrics* metrics_;
|
||||
|
||||
@@ -73,14 +73,18 @@ class CdmLicense {
|
||||
virtual CdmResponseType RestoreLicenseForRelease(
|
||||
const CdmKeyMessage& license_request,
|
||||
const CdmKeyResponse& license_response);
|
||||
virtual bool HasInitData() { return stored_init_data_.get(); }
|
||||
virtual bool HasInitData() { return static_cast<bool>(stored_init_data_); }
|
||||
virtual bool IsKeyLoaded(const KeyId& key_id);
|
||||
|
||||
virtual std::string provider_session_token() {
|
||||
return provider_session_token_;
|
||||
}
|
||||
|
||||
virtual bool is_offline() { 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() {
|
||||
return latest_service_version_;
|
||||
@@ -105,18 +109,18 @@ class CdmLicense {
|
||||
video_widevine::LicenseRequest* license_request);
|
||||
|
||||
CdmResponseType HandleContentKeyResponse(
|
||||
const std::string& msg, const std::string& signature,
|
||||
const std::string& mac_key_iv, const std::string& mac_key,
|
||||
const std::vector<CryptoKey>& key_array,
|
||||
const std::string& msg, const std::string& core_message,
|
||||
const std::string& signature, const std::string& mac_key_iv,
|
||||
const std::string& mac_key, const std::vector<CryptoKey>& key_array,
|
||||
const video_widevine::License& license);
|
||||
|
||||
// HandleEntitlementKeyResponse loads the entitlement keys in |key_array| into
|
||||
// the crypto session. In addition, it also extracts content keys from
|
||||
// |wrapped_keys_| and loads them for use.
|
||||
CdmResponseType HandleEntitlementKeyResponse(
|
||||
const std::string& msg, const std::string& signature,
|
||||
const std::string& mac_key_iv, const std::string& mac_key,
|
||||
const std::vector<CryptoKey>& key_array,
|
||||
const std::string& msg, const std::string& core_message,
|
||||
const std::string& signature, const std::string& mac_key_iv,
|
||||
const std::string& mac_key, const std::vector<CryptoKey>& key_array,
|
||||
const video_widevine::License& license);
|
||||
|
||||
CdmResponseType HandleNewEntitledKeys(
|
||||
@@ -139,6 +143,11 @@ class CdmLicense {
|
||||
std::string provider_session_token_;
|
||||
bool renew_with_client_id_;
|
||||
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
|
||||
bool use_privacy_mode_;
|
||||
|
||||
@@ -23,6 +23,7 @@ OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, size_t* idLength,
|
||||
OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, size_t* keyDataLength,
|
||||
SecurityLevel level);
|
||||
uint32_t OEMCrypto_APIVersion(SecurityLevel level);
|
||||
uint32_t OEMCrypto_MinorAPIVersion(SecurityLevel level);
|
||||
const char* OEMCrypto_SecurityLevel(SecurityLevel level);
|
||||
OEMCryptoResult OEMCrypto_GetHDCPCapability(SecurityLevel level,
|
||||
OEMCrypto_HDCP_Capability* current,
|
||||
@@ -47,15 +48,14 @@ OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader(SecurityLevel level,
|
||||
uint32_t new_table_size,
|
||||
uint8_t* header_buffer,
|
||||
size_t* header_buffer_length);
|
||||
OEMCryptoResult OEMCrypto_CreateOldUsageEntry(
|
||||
SecurityLevel level, uint64_t time_since_license_received,
|
||||
uint64_t time_since_first_decrypt, uint64_t time_since_last_decrypt,
|
||||
OEMCrypto_Usage_Entry_Status status, uint8_t* server_mac_key,
|
||||
uint8_t* client_mac_key, const uint8_t* pst, size_t pst_length);
|
||||
uint32_t OEMCrypto_GetAnalogOutputFlags(SecurityLevel level);
|
||||
const char* OEMCrypto_BuildInformation(SecurityLevel level);
|
||||
uint32_t OEMCrypto_ResourceRatingTier(SecurityLevel level);
|
||||
uint32_t OEMCrypto_SupportsDecryptHash(SecurityLevel level);
|
||||
size_t OEMCrypto_MaximumUsageTableHeaderSize(SecurityLevel level);
|
||||
OEMCryptoResult OEMCrypto_GetOEMPublicCertificate(uint8_t* public_cert,
|
||||
size_t* public_cert_length,
|
||||
SecurityLevel level);
|
||||
} // namespace wvcdm
|
||||
|
||||
/* The following functions are deprecated in OEMCrypto v13. They are defined
|
||||
@@ -104,18 +104,8 @@ OEMCryptoResult OEMCrypto_LoadKeys_Back_Compat(
|
||||
OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data,
|
||||
OEMCrypto_LicenseType license_type, OEMCryptoCipherMode* cipher_modes);
|
||||
|
||||
OEMCryptoResult OEMCrypto_UpdateUsageTable();
|
||||
|
||||
OEMCryptoResult OEMCrypto_DeactivateUsageEntry_V12(const uint8_t* pst,
|
||||
size_t pst_length);
|
||||
OEMCryptoResult OEMCrypto_DeleteUsageEntry(
|
||||
OEMCrypto_SESSION session, const uint8_t* pst, size_t pst_length,
|
||||
const uint8_t* message, size_t message_length, const uint8_t* signature,
|
||||
size_t signature_length);
|
||||
|
||||
OEMCryptoResult OEMCrypto_ForceDeleteUsageEntry(const uint8_t* pst,
|
||||
size_t pst_length);
|
||||
|
||||
typedef struct {
|
||||
const uint8_t* entitlement_key_id;
|
||||
size_t entitlement_key_id_length;
|
||||
@@ -150,10 +140,9 @@ OEMCryptoResult OEMCrypto_RefreshKeys_V14(
|
||||
const uint8_t* signature, size_t signature_length, size_t num_keys,
|
||||
const OEMCrypto_KeyRefreshObject_V14* key_array);
|
||||
|
||||
OEMCryptoResult OEMCrypto_CopyBuffer_V14(const uint8_t* data_addr,
|
||||
size_t data_length,
|
||||
OEMCrypto_DestBufferDesc* out_buffer,
|
||||
uint8_t subsample_flags);
|
||||
OEMCryptoResult OEMCrypto_CopyBuffer_V14(
|
||||
const uint8_t* data_addr, size_t data_length,
|
||||
OEMCrypto_DestBufferDesc* out_buffer_descriptor, uint8_t subsample_flags);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "clock.h"
|
||||
#include "disallow_copy_and_assign.h"
|
||||
#include "license_key_status.h"
|
||||
#include "license_protocol.pb.h"
|
||||
@@ -21,6 +22,7 @@ using video_widevine::WidevinePsshData_EntitledKey;
|
||||
|
||||
class Clock;
|
||||
class CryptoSession;
|
||||
class PolicyTimers;
|
||||
class WvCdmEventListener;
|
||||
|
||||
// This acts as an oracle that basically says "Yes(true) you may still decrypt
|
||||
@@ -56,7 +58,8 @@ class PolicyEngine {
|
||||
// an exact copy of the policy information stored in the license.
|
||||
// The license state transitions to kLicenseStateCanPlay if the license
|
||||
// permits playback.
|
||||
virtual void SetLicense(const video_widevine::License& license);
|
||||
virtual void SetLicense(const video_widevine::License& license,
|
||||
bool supports_core_messages);
|
||||
|
||||
// Used to update the currently loaded entitled content keys.
|
||||
virtual void SetEntitledLicenseKeys(
|
||||
@@ -64,10 +67,12 @@ class PolicyEngine {
|
||||
|
||||
// SetLicenseForRelease is used when releasing a license. The keys in this
|
||||
// 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.
|
||||
virtual bool BeginDecryption(void);
|
||||
// Call this periodically to update the most recent playback time.
|
||||
virtual void DecryptionEvent(void);
|
||||
|
||||
// UpdateLicense is used in handling a license response for a renewal request.
|
||||
@@ -92,26 +97,20 @@ class PolicyEngine {
|
||||
bool GetSecondsSinceStarted(int64_t* seconds_since_started);
|
||||
bool GetSecondsSinceLastPlayed(int64_t* seconds_since_started);
|
||||
|
||||
// for offline save and restore
|
||||
int64_t GetPlaybackStartTime() { return playback_start_time_; }
|
||||
int64_t GetLastPlaybackTime() { return last_playback_time_; }
|
||||
int64_t GetGracePeriodEndTime() { return grace_period_end_time_; }
|
||||
// For offline save and restore
|
||||
int64_t GetPlaybackStartTime();
|
||||
int64_t GetLastPlaybackTime();
|
||||
int64_t GetGracePeriodEndTime();
|
||||
void RestorePlaybackTimes(int64_t playback_start_time,
|
||||
int64_t last_playback_time,
|
||||
int64_t grace_period_end_time);
|
||||
|
||||
bool IsLicenseForFuture() { return license_state_ == kLicenseStatePending; }
|
||||
bool HasPlaybackStarted(int64_t current_time) {
|
||||
if (playback_start_time_ == 0) return false;
|
||||
|
||||
const int64_t playback_time = current_time - playback_start_time_;
|
||||
return playback_time >= policy_.play_start_grace_period_seconds();
|
||||
}
|
||||
bool HasLicenseOrRentalOrPlaybackDurationExpired(int64_t current_time);
|
||||
int64_t GetLicenseOrRentalOrPlaybackDurationRemaining();
|
||||
|
||||
bool HasLicenseOrPlaybackDurationExpired(int64_t current_time);
|
||||
int64_t GetLicenseOrPlaybackDurationRemaining();
|
||||
|
||||
bool CanRenew() { return policy_.can_renew(); }
|
||||
bool CanRenew() const;
|
||||
|
||||
bool IsSufficientOutputProtection(const KeyId& key_id) {
|
||||
return license_keys_->MeetsConstraints(key_id);
|
||||
@@ -135,26 +134,6 @@ class PolicyEngine {
|
||||
kLicenseStateExpired
|
||||
} LicenseState;
|
||||
|
||||
// Gets the clock time that the license expires. This is the hard limit that
|
||||
// all license types must obey at all times.
|
||||
int64_t GetHardLicenseExpiryTime();
|
||||
// Gets the clock time that the rental duration will expire, using the license
|
||||
// duration if one is not present.
|
||||
int64_t GetRentalExpiryTime();
|
||||
// Gets the clock time that the license expires based on whether we have
|
||||
// started playing. This takes into account GetHardLicenseExpiryTime.
|
||||
int64_t GetExpiryTime(int64_t current_time,
|
||||
bool ignore_soft_enforce_playback_duration);
|
||||
|
||||
int64_t GetLicenseOrRentalDurationRemaining(int64_t current_time);
|
||||
int64_t GetPlaybackDurationRemaining(int64_t current_time);
|
||||
|
||||
bool HasRenewalDelayExpired(int64_t current_time);
|
||||
bool HasRenewalRecoveryDurationExpired(int64_t current_time);
|
||||
bool HasRenewalRetryIntervalExpired(int64_t current_time);
|
||||
|
||||
void UpdateRenewalRequest(int64_t current_time);
|
||||
|
||||
// Notifies updates in keys information and fire OnKeysChange event if
|
||||
// key changes.
|
||||
void NotifyKeysChange(CdmKeyStatus new_status);
|
||||
@@ -163,7 +142,8 @@ class PolicyEngine {
|
||||
// expiry time changes.
|
||||
void NotifyExpirationUpdate(int64_t current_time);
|
||||
|
||||
// Guard against clock rollbacks
|
||||
void UpdateRenewalRequest(int64_t current_time);
|
||||
|
||||
int64_t GetCurrentTime();
|
||||
|
||||
// Test only methods
|
||||
@@ -174,31 +154,11 @@ class PolicyEngine {
|
||||
|
||||
LicenseState license_state_;
|
||||
|
||||
// This is the current policy information for this license. This gets updated
|
||||
// as license renewals occur.
|
||||
video_widevine::License::Policy policy_;
|
||||
|
||||
// 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
|
||||
// from the license server we will get an updated id field.
|
||||
video_widevine::LicenseIdentification license_id_;
|
||||
|
||||
// The server returns the license start time in the license/license renewal
|
||||
// response based off the request time sent by the client in the
|
||||
// license request/renewal
|
||||
int64_t license_start_time_;
|
||||
int64_t playback_start_time_;
|
||||
int64_t last_playback_time_;
|
||||
int64_t last_expiry_time_;
|
||||
int64_t grace_period_end_time_;
|
||||
bool last_expiry_time_set_;
|
||||
bool was_expired_on_load_;
|
||||
|
||||
// This is used as a reference point for policy management. This value
|
||||
// represents an offset from license_start_time_. This is used to
|
||||
// calculate the time where renewal retries should occur.
|
||||
int64_t next_renewal_time_;
|
||||
|
||||
// to assist in clock rollback checks
|
||||
int64_t last_recorded_current_time_;
|
||||
|
||||
@@ -210,11 +170,16 @@ class PolicyEngine {
|
||||
// and current status (CdmKeyStatus)
|
||||
std::unique_ptr<LicenseKeys> license_keys_;
|
||||
|
||||
// This is the current policy information for this license. This gets updated
|
||||
// as license renewals occur.
|
||||
video_widevine::License::Policy policy_;
|
||||
|
||||
// Device checks
|
||||
int64_t next_device_check_;
|
||||
uint32_t current_resolution_;
|
||||
CryptoSession* crypto_session_;
|
||||
|
||||
std::unique_ptr<PolicyTimers> policy_timers_;
|
||||
std::unique_ptr<Clock> clock_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(PolicyEngine);
|
||||
|
||||
119
core/include/policy_timers.h
Normal file
119
core/include/policy_timers.h
Normal file
@@ -0,0 +1,119 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
|
||||
#ifndef WVCDM_CORE_POLICY_TIMERS_H_
|
||||
#define WVCDM_CORE_POLICY_TIMERS_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "disallow_copy_and_assign.h"
|
||||
#include "license_protocol.pb.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
// This is driven by the Policy Engine and maintains timer related
|
||||
// information from the policy such as duration windows and renewals.
|
||||
// Timer expiration behavior has changed with the introduction of core
|
||||
// messages in OEMCrypto v16. Handling of behavior that differs between
|
||||
// a OEMCrypto v16 license with core messages and one without is left to
|
||||
// a class that derives from this interface.
|
||||
|
||||
class PolicyTimers {
|
||||
public:
|
||||
virtual ~PolicyTimers() {}
|
||||
|
||||
// SetLicense is used in handling the initial license response.
|
||||
virtual void SetLicense(const video_widevine::License& license);
|
||||
|
||||
// UpdateLicense is used in handling a license response, a renewal response,
|
||||
// or when restoring or releasing a persistent license.
|
||||
// In a renewal the response may only contain policy fields that have
|
||||
// changed. In this case an exact copy is not what we want to happen.
|
||||
virtual bool UpdateLicense(int64_t current_time,
|
||||
const video_widevine::License& license) = 0;
|
||||
|
||||
// Call this on first decrypt to set the start of playback.
|
||||
virtual void BeginDecryption(int64_t current_time) = 0;
|
||||
// Call this periodically to update the most recent playback time.
|
||||
virtual void DecryptionEvent(int64_t current_time);
|
||||
|
||||
// For offline save and restore
|
||||
virtual int64_t GetPlaybackStartTime() { return playback_start_time_; }
|
||||
virtual int64_t GetLastPlaybackTime() { return last_playback_time_; }
|
||||
virtual int64_t GetGracePeriodEndTime() = 0;
|
||||
virtual void RestorePlaybackTimes(int64_t current_time,
|
||||
int64_t playback_start_time,
|
||||
int64_t last_playback_time,
|
||||
int64_t grace_period_end_time) = 0;
|
||||
|
||||
virtual bool HasPlaybackStarted(int64_t current_time) = 0;
|
||||
virtual bool HasLicenseOrRentalOrPlaybackDurationExpired(
|
||||
int64_t current_time) = 0;
|
||||
virtual bool HasPassedGracePeriod(int64_t current_time) = 0;
|
||||
|
||||
virtual int64_t GetLicenseOrRentalOrPlaybackDurationRemaining(
|
||||
int64_t current_time) = 0;
|
||||
virtual int64_t GetLicenseOrRentalDurationRemaining(int64_t current_time) = 0;
|
||||
// This is only used in Query. This should return |playback_duration_seconds|
|
||||
// before playback begins or the time remaining on
|
||||
// |playback_duration_seconds| after playback begins.
|
||||
virtual int64_t GetPlaybackDurationRemaining(int64_t current_time);
|
||||
|
||||
virtual bool GetSecondsSinceStarted(int64_t current_time,
|
||||
int64_t* seconds_since_started);
|
||||
virtual bool GetSecondsSinceLastPlayed(int64_t current_time,
|
||||
int64_t* seconds_since_started);
|
||||
|
||||
virtual bool IsLicenseForFuture(int64_t current_time);
|
||||
|
||||
virtual bool UpdateExpirationTime(int64_t current_time, int64_t* expiry_time);
|
||||
|
||||
// Renewal related methods
|
||||
virtual bool HasRenewalDelayExpired(int64_t current_time);
|
||||
virtual bool HasRenewalRetryIntervalExpired(int64_t current_time);
|
||||
virtual void UpdateRenewalRequest(int64_t current_time);
|
||||
virtual bool HasRenewalRecoveryDurationExpired(int64_t current_time);
|
||||
|
||||
const video_widevine::License::Policy& get_policy() { return policy_; }
|
||||
|
||||
protected:
|
||||
PolicyTimers()
|
||||
: license_start_time_(0),
|
||||
playback_start_time_(0),
|
||||
last_playback_time_(0),
|
||||
last_expiry_time_(0),
|
||||
last_expiry_time_set_(false),
|
||||
next_renewal_time_(0),
|
||||
was_expired_on_load_(false) {}
|
||||
|
||||
// Gets the clock time that the license expires based on whether we have
|
||||
// started playing.
|
||||
virtual int64_t GetExpiryTime(int64_t current_time,
|
||||
bool ignore_soft_enforce_playback_duration) = 0;
|
||||
|
||||
virtual int64_t GetRenewalStartTime() = 0;
|
||||
|
||||
// This is the current policy information for this license. This gets updated
|
||||
// as license renewals occur.
|
||||
video_widevine::License::Policy policy_;
|
||||
|
||||
int64_t license_start_time_;
|
||||
int64_t playback_start_time_;
|
||||
int64_t last_playback_time_;
|
||||
int64_t last_expiry_time_;
|
||||
int64_t last_expiry_time_set_;
|
||||
int64_t next_renewal_time_;
|
||||
|
||||
// Indicates whether a persistent license was expired when loaded
|
||||
bool was_expired_on_load_;
|
||||
|
||||
private:
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(PolicyTimers);
|
||||
};
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // WVCDM_CORE_POLICY_TIMERS_H_
|
||||
97
core/include/policy_timers_v15.h
Normal file
97
core/include/policy_timers_v15.h
Normal file
@@ -0,0 +1,97 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
|
||||
#ifndef WVCDM_CORE_POLICY_TIMERS_V15_H_
|
||||
#define WVCDM_CORE_POLICY_TIMERS_V15_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "disallow_copy_and_assign.h"
|
||||
#include "license_protocol.pb.h"
|
||||
#include "policy_timers.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
// OEMCrypto v16 and core messages introduced changes to how duration values
|
||||
// and clocks should be evaluated. This class provides backward compatibility
|
||||
// for licenses that do not include a core message. Durations are handled
|
||||
// in the same way as in earlier releases.
|
||||
//
|
||||
// Backward compatibility may be needed if
|
||||
// * OEMCrypto has not been upgraded to v16
|
||||
// * Licenses were persisted before the device was upgraded to v16
|
||||
// * License service does not yet support core messages
|
||||
|
||||
class PolicyTimersV15 : public PolicyTimers {
|
||||
public:
|
||||
PolicyTimersV15() : grace_period_end_time_(0) {}
|
||||
|
||||
virtual ~PolicyTimersV15() {}
|
||||
|
||||
// UpdateLicense is used in handling a license response, a renewal response,
|
||||
// or when restoring or releasing a persistent license.
|
||||
// In a renewal the response may only contain policy fields that have
|
||||
// changed. In this case an exact copy is not what we want to happen.
|
||||
// |license_start_time_| is updated to the time mentioned in the renewal
|
||||
// response.
|
||||
// UpdateLicense will return false if |license_start_time| is not
|
||||
// present or playback is not allowed due to policy or timer duration
|
||||
// expiration.
|
||||
bool UpdateLicense(int64_t current_time,
|
||||
const video_widevine::License& license) override;
|
||||
|
||||
// Call this on first decrypt to set the start of playback.
|
||||
void BeginDecryption(int64_t current_time) override;
|
||||
|
||||
// for offline save and restore
|
||||
int64_t GetGracePeriodEndTime() override { return grace_period_end_time_; }
|
||||
|
||||
// for offline save and restore
|
||||
void RestorePlaybackTimes(int64_t current_time, int64_t playback_start_time,
|
||||
int64_t last_playback_time,
|
||||
int64_t grace_period_end_time) override;
|
||||
|
||||
bool HasPlaybackStarted(int64_t current_time) override;
|
||||
bool HasLicenseOrRentalOrPlaybackDurationExpired(
|
||||
int64_t current_time) override;
|
||||
bool HasPassedGracePeriod(int64_t current_time) override;
|
||||
|
||||
// This returns
|
||||
// * for streaming licenses: the time remaining on |license_duration_seconds|
|
||||
// * for persistent licenses: the time remaining on |rental_duration_seconds|
|
||||
// before playback begins or the time remaining on
|
||||
// |playback_duration_seconds| after.
|
||||
int64_t GetLicenseOrRentalOrPlaybackDurationRemaining(
|
||||
int64_t current_time) override;
|
||||
// This is only used in Query. This should return the time remaining on
|
||||
// |license_duration_seconds| for streaming licenses and
|
||||
// |rental_duration_seconds| for persistent licenses.
|
||||
int64_t GetLicenseOrRentalDurationRemaining(int64_t current_time) override;
|
||||
|
||||
protected:
|
||||
// Gets the clock time that the license expires based on whether we have
|
||||
// started playing. This takes into account GetHardLicenseExpiryTime.
|
||||
int64_t GetExpiryTime(int64_t current_time,
|
||||
bool ignore_soft_enforce_playback_duration) override;
|
||||
|
||||
int64_t GetRenewalStartTime() override { return license_start_time_; }
|
||||
|
||||
private:
|
||||
// Gets the clock time that the license expires. This is the hard limit that
|
||||
// all license types must obey at all times.
|
||||
int64_t GetHardLicenseExpiryTime();
|
||||
// Gets the clock time that the rental duration will expire, using the license
|
||||
// duration if one is not present.
|
||||
int64_t GetRentalExpiryTime();
|
||||
|
||||
int64_t grace_period_end_time_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(PolicyTimersV15);
|
||||
};
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // WVCDM_CORE_POLICY_TIMERS_V15_H_
|
||||
111
core/include/policy_timers_v16.h
Normal file
111
core/include/policy_timers_v16.h
Normal file
@@ -0,0 +1,111 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
|
||||
#ifndef WVCDM_CORE_POLICY_TIMERS_V16_H_
|
||||
#define WVCDM_CORE_POLICY_TIMERS_V16_H_
|
||||
|
||||
#include "disallow_copy_and_assign.h"
|
||||
#include "license_protocol.pb.h"
|
||||
#include "policy_timers.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
// OEMCrypto v16 and core messages introduced changes to how duration values
|
||||
// and clocks should be evaluated. This class provides backward compatibility
|
||||
// for licenses that do not include a core message. Durations are handled
|
||||
// in the same way as in earlier releases.
|
||||
//
|
||||
// Backward compatibility may be needed if
|
||||
// * OEMCrypto has not been upgraded to v16
|
||||
// * Licenses were persisted before the device was upgraded to v16
|
||||
// * License service does not yet support core messages
|
||||
|
||||
class PolicyTimersV16 : public PolicyTimers {
|
||||
public:
|
||||
PolicyTimersV16() {}
|
||||
|
||||
virtual ~PolicyTimersV16() {}
|
||||
|
||||
// UpdateLicense is used in handling a license response, a renewal response,
|
||||
// or when restoring or releasing a persistent license.
|
||||
// In a renewal the response may only contain policy fields that have
|
||||
// changed. In this case an exact copy is not what we want to happen.
|
||||
// |renewal_start_time_| is set to the time mentioned in the renewal
|
||||
// response.
|
||||
// UpdateLicense will return false if |license_start_time| is not
|
||||
// present or playback is not allowed due to policy or timer duration
|
||||
// expiration.
|
||||
bool UpdateLicense(int64_t current_time,
|
||||
const video_widevine::License& license) override;
|
||||
|
||||
// Call this on first decrypt to set the start of playback.
|
||||
void BeginDecryption(int64_t current_time) override;
|
||||
|
||||
// This is a legacy field for offline licenses. Since no grace period is
|
||||
// supported return a default value.
|
||||
int64_t GetGracePeriodEndTime() override { return 0; }
|
||||
|
||||
// For offline save and restore.
|
||||
void RestorePlaybackTimes(int64_t current_time, int64_t playback_start_time,
|
||||
int64_t last_playback_time,
|
||||
int64_t grace_period_end_time) override;
|
||||
|
||||
bool HasPlaybackStarted(int64_t /* current_time */) override {
|
||||
return playback_start_time_ != 0;
|
||||
}
|
||||
// For licenses that support core messages, evaluation of only rental and
|
||||
// playback durations are needed.
|
||||
bool HasLicenseOrRentalOrPlaybackDurationExpired(
|
||||
int64_t current_time) override {
|
||||
return HasRentalOrPlaybackDurationExpired(current_time);
|
||||
}
|
||||
bool HasPassedGracePeriod(int64_t /* current_time */) override {
|
||||
return true;
|
||||
}
|
||||
|
||||
// This returns
|
||||
// * before playback begins: the time remaining on |rental_duration_seconds|
|
||||
// * after playback begins:
|
||||
// - |soft_enforce_playback_duration| is true: the time remaining on
|
||||
// |playback_duration_seconds|
|
||||
// - |soft_enforce_playback_duration| is false: the minimum
|
||||
// of the time remaining on |rental_duration_seconds| or
|
||||
// |playback_duration_seconds|
|
||||
//
|
||||
// |license_duration_seconds| is ignored with the introduction of core
|
||||
// messages
|
||||
int64_t GetLicenseOrRentalOrPlaybackDurationRemaining(
|
||||
int64_t current_time) override;
|
||||
// This is only used in Query. This should return the time remaining on
|
||||
// |rental_duration_seconds|.
|
||||
int64_t GetLicenseOrRentalDurationRemaining(int64_t current_time) override {
|
||||
return GetRentalDurationRemaining(current_time);
|
||||
};
|
||||
|
||||
protected:
|
||||
// Gets the clock time that the license expires based on whether we have
|
||||
// started playing. This takes into account GetHardLicenseExpiryTime.
|
||||
int64_t GetExpiryTime(int64_t current_time,
|
||||
bool ignore_soft_enforce_playback_duration) override;
|
||||
|
||||
int64_t GetRenewalStartTime() override { return renewal_start_time_; }
|
||||
|
||||
private:
|
||||
// Gets the clock time that the rental duration or playback will expire.
|
||||
int64_t GetRentalExpiryTime(int64_t current_time);
|
||||
int64_t GetPlaybackExpiryTime(int64_t current_time,
|
||||
bool ignore_soft_enforce_playback_duration);
|
||||
|
||||
bool HasRentalOrPlaybackDurationExpired(int64_t current_time);
|
||||
int64_t GetRentalDurationRemaining(int64_t current_time);
|
||||
|
||||
int64_t renewal_start_time_ = 0;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(PolicyTimersV16);
|
||||
};
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // WVCDM_CORE_POLICY_TIMERS_V16_H_
|
||||
@@ -55,9 +55,15 @@ class Properties {
|
||||
static inline bool device_files_is_a_real_filesystem() {
|
||||
return device_files_is_a_real_filesystem_;
|
||||
}
|
||||
static inline bool allow_restore_of_offline_licenses_with_release() {
|
||||
return allow_restore_of_offline_licenses_with_release_;
|
||||
}
|
||||
static void set_provisioning_messages_are_binary(bool flag) {
|
||||
provisioning_messages_are_binary_ = flag;
|
||||
}
|
||||
static inline bool delay_oem_crypto_termination() {
|
||||
return delay_oem_crypto_termination_;
|
||||
}
|
||||
static bool GetCompanyName(std::string* company_name);
|
||||
static bool GetModelName(std::string* model_name);
|
||||
static bool GetArchitectureName(std::string* arch_name);
|
||||
@@ -143,6 +149,8 @@ class Properties {
|
||||
static bool provisioning_messages_are_binary_;
|
||||
static bool allow_service_certificate_requests_;
|
||||
static bool device_files_is_a_real_filesystem_;
|
||||
static bool allow_restore_of_offline_licenses_with_release_;
|
||||
static bool delay_oem_crypto_termination_;
|
||||
static std::unique_ptr<CdmClientPropertySetMap> session_property_set_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(Properties);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "clock.h"
|
||||
#include "crypto_session.h"
|
||||
#include "device_files.h"
|
||||
#include "disallow_copy_and_assign.h"
|
||||
@@ -17,6 +18,10 @@
|
||||
#include "metrics_collections.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
#if defined(UNIT_TEST)
|
||||
# include <gtest/gtest_prod.h>
|
||||
#endif
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
// Offline licenses/secure stops may be securely tracked using usage
|
||||
@@ -57,11 +62,13 @@ class UsageTableHeader {
|
||||
bool persistent_license,
|
||||
const CdmKeySetId& key_set_id,
|
||||
const std::string& usage_info_filename,
|
||||
const CdmKeyResponse& license_message,
|
||||
uint32_t* usage_entry_number);
|
||||
virtual CdmResponseType LoadEntry(CryptoSession* crypto_session,
|
||||
const CdmUsageEntry& usage_entry,
|
||||
uint32_t usage_entry_number);
|
||||
virtual CdmResponseType UpdateEntry(CryptoSession* crypto_session,
|
||||
virtual CdmResponseType UpdateEntry(uint32_t usage_entry_number,
|
||||
CryptoSession* crypto_session,
|
||||
CdmUsageEntry* usage_entry);
|
||||
|
||||
// The licenses or usage info records specified by |usage_entry_number|
|
||||
@@ -79,12 +86,31 @@ class UsageTableHeader {
|
||||
// for the objects that DeleteEntry depends on.
|
||||
void DeleteEntryForTest(uint32_t usage_entry_number);
|
||||
|
||||
// TODO(rfrias): Move to utility class
|
||||
static int64_t GetRandomInRange(size_t upper_bound_exclusive);
|
||||
static int64_t GetRandomInRangeWithExclusion(size_t upper_bound_exclusive,
|
||||
size_t exclude);
|
||||
size_t size() { return usage_entry_info_.size(); }
|
||||
|
||||
size_t potential_table_capacity() const { return potential_table_capacity_; }
|
||||
|
||||
const std::vector<CdmUsageEntryInfo>& usage_entry_info() const {
|
||||
return usage_entry_info_;
|
||||
}
|
||||
|
||||
// Set the reference clock used for the method GetCurrentTime().
|
||||
void SetClock(Clock* clock) {
|
||||
if (clock != nullptr)
|
||||
clock_ref_ = clock;
|
||||
else
|
||||
clock_ref_ = &clock_;
|
||||
}
|
||||
|
||||
static bool DetermineLicenseToRemoveForTesting(
|
||||
const std::vector<CdmUsageEntryInfo>& usage_entry_info_list,
|
||||
int64_t current_time, size_t unexpired_threshold, size_t removal_count,
|
||||
std::vector<uint32_t>* removal_candidates) {
|
||||
return DetermineLicenseToRemove(usage_entry_info_list, current_time,
|
||||
unexpired_threshold, removal_count,
|
||||
removal_candidates);
|
||||
}
|
||||
|
||||
private:
|
||||
CdmResponseType MoveEntry(uint32_t from /* usage entry number */,
|
||||
const CdmUsageEntry& from_usage_entry,
|
||||
@@ -100,16 +126,60 @@ class UsageTableHeader {
|
||||
CdmResponseType Shrink(metrics::CryptoMetrics* metrics,
|
||||
uint32_t number_of_usage_entries_to_delete);
|
||||
|
||||
CdmResponseType UpgradeFromUsageTable(DeviceFiles* handle,
|
||||
metrics::CryptoMetrics* metrics);
|
||||
bool UpgradeLicensesFromUsageTable(DeviceFiles* handle,
|
||||
metrics::CryptoMetrics* metrics);
|
||||
bool UpgradeUsageInfoFromUsageTable(DeviceFiles* handle,
|
||||
metrics::CryptoMetrics* metrics);
|
||||
|
||||
virtual bool is_inited() { return is_inited_; }
|
||||
|
||||
virtual bool CreateDummyOldUsageEntry(CryptoSession* crypto_session);
|
||||
// Performs and LRU upgrade on all loaded CdmUsageEntryInfo from a
|
||||
// device file that had not yet been upgraded to use the LRU data.
|
||||
virtual bool LruUpgradeAllUsageEntries();
|
||||
|
||||
virtual bool GetRemovalCandidates(std::vector<uint32_t>* removal_candidates);
|
||||
|
||||
int64_t GetCurrentTime() { return clock_ref_->GetCurrentTime(); }
|
||||
|
||||
// Uses an LRU-base algorithm to determine which licenses should be
|
||||
// removed. This is intended to be used if the usage table is full
|
||||
// and a new entry needs to be added.
|
||||
//
|
||||
// Algorithm overview:
|
||||
// Given the set of all usage entry infos, the entries which are
|
||||
// of unknown storage type or are the most stale will be returned,
|
||||
// with some exceptions for offline licenses.
|
||||
// 1) Expired licenses will always be considered. Expiration is
|
||||
// determined using the usage entry info's
|
||||
// |offline_license_expiry| compared to the provided
|
||||
// |current_time|.
|
||||
// 2) Unexpired offline licenses will only be considered for
|
||||
// removal if the number of unexpired offline licenses exceeds
|
||||
// |unexpired_threshold|.
|
||||
// The number of licenses to be considered will be less than or
|
||||
// equal to the requested |removal_count|.
|
||||
//
|
||||
// Unknown storage types will be considered above all other entry
|
||||
// types.
|
||||
//
|
||||
// Parameters:
|
||||
// [in] usage_entry_info_list: The complete list of known usage
|
||||
// entries.
|
||||
// [in] current_time: The current time to compare expiration times
|
||||
// against.
|
||||
// [in] unexpired_threshold: The maximum number of unexpired
|
||||
// offline licenses that are present, before offline
|
||||
// licenses would be considered for removal.
|
||||
// [in] removal_count: The desired number of removal candidate to
|
||||
// find. Note that the actual number will be anywhere
|
||||
// between 1 and |removal_count|. Must be greater than or
|
||||
// equal to 1.
|
||||
// [out] removal_candidates: List of usage entry numbers of the
|
||||
// entries to be removed. Assume to be unaffected if the
|
||||
// function returns |false|.
|
||||
//
|
||||
// Returns:
|
||||
// |true| if at least one removal candidate can be determined.
|
||||
// Otherwise returns |false|.
|
||||
static bool DetermineLicenseToRemove(
|
||||
const std::vector<CdmUsageEntryInfo>& usage_entry_info_list,
|
||||
int64_t current_time, size_t unexpired_threshold, size_t removal_count,
|
||||
std::vector<uint32_t>* removal_candidates);
|
||||
|
||||
// This handle and file system is only to be used when accessing
|
||||
// usage_table_header. Usage entries should use the file system provided
|
||||
@@ -133,8 +203,28 @@ class UsageTableHeader {
|
||||
|
||||
metrics::CryptoMetrics alternate_crypto_metrics_;
|
||||
|
||||
// |clock_| represents the system's "wall clock". For the clock's purpose
|
||||
// we do not need a more secure clock.
|
||||
Clock clock_;
|
||||
// |clock_ref_| is a pointer to the clock which is to be used for
|
||||
// obtaining the current time. By default, this points to the internal
|
||||
// |clock_| variable, however, it can be overrided for testing purpose.
|
||||
Clock* clock_ref_;
|
||||
|
||||
// The maximum number of entries that the underlying OEMCrypto
|
||||
// implementation can support. Some implementations might not
|
||||
// support reporting the table capacity, if so, then this value is
|
||||
// assumed to be |kMinimumUsageTableEntriesSupported|.
|
||||
size_t potential_table_capacity_ = 0u;
|
||||
|
||||
#if defined(UNIT_TEST)
|
||||
// Test related declarations
|
||||
friend class UsageTableHeaderTest;
|
||||
FRIEND_TEST(UsageTableHeaderTest, Shrink_NoneOfTable);
|
||||
FRIEND_TEST(UsageTableHeaderTest, Shrink_PartOfTable);
|
||||
FRIEND_TEST(UsageTableHeaderTest, Shrink_AllOfTable);
|
||||
FRIEND_TEST(UsageTableHeaderTest, Shrink_MoreThanTable);
|
||||
#endif
|
||||
|
||||
// These setters are for testing only. Takes ownership of the pointers.
|
||||
void SetDeviceFiles(DeviceFiles* device_files) {
|
||||
|
||||
@@ -25,11 +25,19 @@ static const size_t CERTIFICATE_DATA_SIZE = 4 * 1024;
|
||||
// Use 0 to represent never expired license as specified in EME spec
|
||||
// (NaN in JS translates to 0 in unix timestamp).
|
||||
static const int64_t NEVER_EXPIRES = 0;
|
||||
static const int64_t UNLIMITED_DURATION = 0;
|
||||
|
||||
// This is the lower limit. For OEMCrypto v16+ one can query and find how many
|
||||
// are supported
|
||||
static constexpr size_t kMinimumUsageTableEntriesSupported = 200;
|
||||
|
||||
// Resource rating tiers
|
||||
static const uint32_t RESOURCE_RATING_TIER_LOW = 1u;
|
||||
static const uint32_t RESOURCE_RATING_TIER_MEDIUM = 2u;
|
||||
static const uint32_t RESOURCE_RATING_TIER_HIGH = 3u;
|
||||
static const uint32_t RESOURCE_RATING_TIER_VERY_HIGH = 4u;
|
||||
static const uint32_t RESOURCE_RATING_TIER_MIN = RESOURCE_RATING_TIER_LOW;
|
||||
static const uint32_t RESOURCE_RATING_TIER_MAX = RESOURCE_RATING_TIER_VERY_HIGH;
|
||||
|
||||
// OEMCrypto features by version
|
||||
static const uint32_t OEM_CRYPTO_API_VERSION_SUPPORTS_RESOURCE_RATING_TIER = 15;
|
||||
@@ -82,6 +90,10 @@ static const std::string QUERY_KEY_OEMCRYPTO_BUILD_INFORMATION =
|
||||
"OemCryptoBuildInformation";
|
||||
static const std::string QUERY_KEY_DECRYPT_HASH_SUPPORT = "DecryptHashSupport";
|
||||
static const std::string QUERY_KEY_PROVISIONING_MODEL = "ProvisioningModel";
|
||||
static const std::string QUERY_KEY_MAX_USAGE_TABLE_ENTRIES =
|
||||
"MaxNumberOfUsageTableEntries";
|
||||
static const std::string QUERY_KEY_OEMCRYPTO_API_MINOR_VERSION =
|
||||
"OemCryptoApiMinorVersion";
|
||||
|
||||
static const std::string QUERY_VALUE_TRUE = "True";
|
||||
static const std::string QUERY_VALUE_FALSE = "False";
|
||||
|
||||
@@ -72,8 +72,8 @@ enum CdmResponseType {
|
||||
CERT_PROVISIONING_RESPONSE_ERROR_2 = 19,
|
||||
CERT_PROVISIONING_RESPONSE_ERROR_3 = 20,
|
||||
CERT_PROVISIONING_RESPONSE_ERROR_4 = 21,
|
||||
CERT_PROVISIONING_RESPONSE_ERROR_5 = 22,
|
||||
CERT_PROVISIONING_RESPONSE_ERROR_6 = 23,
|
||||
/* previously CERT_PROVISIONING_RESPONSE_ERROR_5 = 22 */
|
||||
/* previously CERT_PROVISIONING_RESPONSE_ERROR_6 = 23 */
|
||||
CERT_PROVISIONING_RESPONSE_ERROR_7 = 24,
|
||||
CERT_PROVISIONING_RESPONSE_ERROR_8 = 25,
|
||||
/* previously CRYPTO_SESSION_OPEN_ERROR_1 = 26 */
|
||||
@@ -270,17 +270,17 @@ enum CdmResponseType {
|
||||
LOAD_USAGE_HEADER_SIGNATURE_FAILURE = 216,
|
||||
LOAD_USAGE_HEADER_BAD_MAGIC = 217,
|
||||
LOAD_USAGE_HEADER_UNKNOWN_ERROR = 218,
|
||||
INVALID_PARAMETERS_ENG_17 = 219,
|
||||
INVALID_PARAMETERS_ENG_18 = 220,
|
||||
/* previously INVALID_PARAMETERS_ENG_17 = 219, */
|
||||
/* preivously INVALID_PARAMETERS_ENG_18 = 220, */
|
||||
INSUFFICIENT_CRYPTO_RESOURCES_3 = 221,
|
||||
CREATE_USAGE_ENTRY_UNKNOWN_ERROR = 222,
|
||||
LOAD_USAGE_ENTRY_GENERATION_SKEW = 223,
|
||||
LOAD_USAGE_ENTRY_SIGNATURE_FAILURE = 224,
|
||||
LOAD_USAGE_ENTRY_UNKNOWN_ERROR = 225,
|
||||
INVALID_PARAMETERS_ENG_19 = 226,
|
||||
INVALID_PARAMETERS_ENG_20 = 227,
|
||||
/* previously INVALID_PARAMETERS_ENG_19 = 226, */
|
||||
/* previsouly INVALID_PARAMETERS_ENG_20 = 227, */
|
||||
UPDATE_USAGE_ENTRY_UNKNOWN_ERROR = 228,
|
||||
INVALID_PARAMETERS_ENG_21 = 229,
|
||||
/* previously INVALID_PARAMETERS_ENG_21 = 229, */
|
||||
SHRINK_USAGE_TABLER_HEADER_UNKNOWN_ERROR = 230,
|
||||
MOVE_USAGE_ENTRY_UNKNOWN_ERROR = 231,
|
||||
COPY_OLD_USAGE_ENTRY_UNKNOWN_ERROR = 232,
|
||||
@@ -341,7 +341,7 @@ enum CdmResponseType {
|
||||
NO_MATCHING_ENTITLEMENT_KEY = 287,
|
||||
LOAD_ENTITLED_CONTENT_KEYS_ERROR = 288,
|
||||
GET_PROVISIONING_METHOD_ERROR = 289,
|
||||
SESSION_NOT_FOUND_17 = 290,
|
||||
INVALID_SESSION_2 = 290,
|
||||
SESSION_NOT_FOUND_18 = 291,
|
||||
NO_CONTENT_KEY_3 = 292,
|
||||
DEVICE_CANNOT_REPROVISION = 293,
|
||||
@@ -396,10 +396,18 @@ enum CdmResponseType {
|
||||
NOT_IMPLEMENTED_ERROR = 342,
|
||||
GET_SRM_VERSION_ERROR = 343,
|
||||
REWRAP_DEVICE_RSA_KEY_ERROR = 344,
|
||||
REWRAP_DEVICE_RSA_KEY_30_ERROR = 345,
|
||||
LOAD_PROVISIONING_ERROR = 345,
|
||||
INVALID_SRM_LIST = 346,
|
||||
KEYSET_ID_NOT_FOUND_4 = 347,
|
||||
SESSION_NOT_FOUND_22 = 348,
|
||||
USAGE_INVALID_PARAMETERS_2 = 349,
|
||||
CORE_MESSAGE_NOT_FOUND = 350,
|
||||
LOAD_LICENSE_ERROR = 351,
|
||||
LOAD_RENEWAL_ERROR = 352,
|
||||
CANNOT_DECRYPT_ZERO_SAMPLES = 353,
|
||||
CANNOT_DECRYPT_ZERO_SUBSAMPLES = 354,
|
||||
SAMPLE_AND_SUBSAMPLE_SIZE_MISMATCH = 355,
|
||||
INVALID_IV_SIZE = 356,
|
||||
// Don't forget to add new values to
|
||||
// * core/test/test_printers.cpp.
|
||||
// * android/include/mapErrors-inl.h
|
||||
@@ -481,15 +489,12 @@ enum CdmClientTokenType {
|
||||
|
||||
// kNonSecureUsageSupport - TEE does not provide any support for usage
|
||||
// information.
|
||||
// kUsageTableSupport - TEE persists usage information securely in a fixed
|
||||
// size table, commonly 50 entries. (OEMCrypto v9+)
|
||||
// kUsageEntrySupport - usage information (table headers and entries) are
|
||||
// persisted in non-secure storage but are loaded and unloaded from
|
||||
// the TEE during use (OEMCrypto v13+)
|
||||
// kUnknownUsageSupport - usage support type is uninitialized or unavailable
|
||||
enum CdmUsageSupportType {
|
||||
kNonSecureUsageSupport,
|
||||
kUsageTableSupport,
|
||||
kUsageEntrySupport,
|
||||
kUnknownUsageSupport,
|
||||
};
|
||||
@@ -504,11 +509,25 @@ struct CdmUsageEntryInfo {
|
||||
CdmUsageEntryStorageType storage_type;
|
||||
CdmKeySetId key_set_id;
|
||||
std::string usage_info_file_name;
|
||||
int64_t last_use_time;
|
||||
int64_t offline_license_expiry_time; // Only for offline licenses.
|
||||
bool operator==(const CdmUsageEntryInfo& other) const {
|
||||
return storage_type == other.storage_type &&
|
||||
key_set_id == other.key_set_id &&
|
||||
(storage_type != kStorageUsageInfo ||
|
||||
usage_info_file_name == other.usage_info_file_name);
|
||||
if (this == &other) {
|
||||
return true;
|
||||
}
|
||||
if (storage_type != other.storage_type || key_set_id != other.key_set_id ||
|
||||
last_use_time != other.last_use_time) {
|
||||
return false;
|
||||
}
|
||||
// Certain fields only have meaning based on the storage type.
|
||||
if (storage_type == kStorageUsageInfo) {
|
||||
return usage_info_file_name == other.usage_info_file_name;
|
||||
}
|
||||
if (storage_type == kStorageLicense) {
|
||||
return offline_license_expiry_time == other.offline_license_expiry_time;
|
||||
}
|
||||
// else storage_type == kStorageTypeUnknown
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -566,11 +585,13 @@ class CdmKeyAllowedUsage {
|
||||
bool valid_;
|
||||
};
|
||||
|
||||
// For schemes that do not use pattern encryption (cenc and cbc1), encrypt
|
||||
// and skip should be set to 0. For those that do (cens and cbcs), it is
|
||||
// recommended that encrypt+skip bytes sum to 10 and for cbcs that a 1:9
|
||||
// encrypt:skip ratio be used. See ISO/IEC DIS 23001-7, section 10.4.2 for
|
||||
// more information.
|
||||
// For schemes that do not use pattern encryption (cenc), encrypt and skip
|
||||
// must be set to 0. For those that do (cbcs), it is recommended that
|
||||
// encrypt+skip bytes sum to 10. See ISO/IEC DIS 23001-7, section 10.4.2 for
|
||||
// more information. For Widevine, we often use the pattern (1,0) to represent
|
||||
// "encrypt all blocks," but in content, the patterns (0,0) and (10,0) are more
|
||||
// common. Since we are constrained to use (0,0) for "do not use pattern
|
||||
// encryption" — as noted above — we commonly use (1,0) for this case instead.
|
||||
struct CdmCencPatternEncryptionDescriptor {
|
||||
size_t encrypt_blocks; // number of 16 byte blocks to decrypt
|
||||
size_t skip_blocks; // number of 16 byte blocks to leave in clear
|
||||
@@ -596,12 +617,12 @@ struct CdmDecryptionParameters {
|
||||
: is_encrypted(true),
|
||||
is_secure(true),
|
||||
cipher_mode(kCipherModeCtr),
|
||||
key_id(NULL),
|
||||
encrypt_buffer(NULL),
|
||||
key_id(nullptr),
|
||||
encrypt_buffer(nullptr),
|
||||
encrypt_length(0),
|
||||
iv(NULL),
|
||||
iv(nullptr),
|
||||
block_offset(0),
|
||||
decrypt_buffer(NULL),
|
||||
decrypt_buffer(nullptr),
|
||||
decrypt_buffer_length(0),
|
||||
decrypt_buffer_offset(0),
|
||||
subsample_flags(0),
|
||||
@@ -625,6 +646,119 @@ struct CdmDecryptionParameters {
|
||||
is_video(true) {}
|
||||
};
|
||||
|
||||
struct CdmDecryptionSubsample {
|
||||
size_t clear_bytes;
|
||||
size_t protected_bytes;
|
||||
// TODO(b/149524614): These fields are not necessary except for
|
||||
// backwards-compatibility while we are transitioning from the v15 API to the
|
||||
// v16 API.
|
||||
uint8_t flags;
|
||||
size_t block_offset;
|
||||
CdmDecryptionSubsample()
|
||||
: clear_bytes(0), protected_bytes(0), flags(0), block_offset(0) {}
|
||||
CdmDecryptionSubsample(size_t clear_param, size_t protected_param)
|
||||
: clear_bytes(clear_param),
|
||||
protected_bytes(protected_param),
|
||||
flags(0),
|
||||
block_offset(0) {}
|
||||
};
|
||||
|
||||
struct CdmDecryptionSample {
|
||||
const uint8_t* encrypt_buffer;
|
||||
size_t encrypt_buffer_length;
|
||||
void* decrypt_buffer;
|
||||
size_t decrypt_buffer_size;
|
||||
size_t decrypt_buffer_offset;
|
||||
std::vector<CdmDecryptionSubsample> subsamples;
|
||||
std::vector<uint8_t> iv;
|
||||
CdmDecryptionSample()
|
||||
: encrypt_buffer(nullptr),
|
||||
encrypt_buffer_length(0),
|
||||
decrypt_buffer(nullptr),
|
||||
decrypt_buffer_size(0),
|
||||
decrypt_buffer_offset(0),
|
||||
subsamples(),
|
||||
iv() {}
|
||||
CdmDecryptionSample(const uint8_t* encrypt_buffer_param,
|
||||
void* decrypt_buffer_param,
|
||||
size_t decrypt_buffer_offset_param, size_t length,
|
||||
const std::vector<uint8_t>& iv_param)
|
||||
: encrypt_buffer(encrypt_buffer_param),
|
||||
encrypt_buffer_length(length),
|
||||
decrypt_buffer(decrypt_buffer_param),
|
||||
decrypt_buffer_size(length),
|
||||
decrypt_buffer_offset(decrypt_buffer_offset_param),
|
||||
subsamples(),
|
||||
iv(iv_param) {}
|
||||
};
|
||||
|
||||
// TODO(b/149524614): This name is a temporary measure for
|
||||
// backwards-compatibility while we are transitioning from the v15 API to the
|
||||
// v16 API.
|
||||
struct CdmDecryptionParametersV16 {
|
||||
KeyId key_id;
|
||||
std::vector<CdmDecryptionSample> samples;
|
||||
bool is_secure;
|
||||
CdmCipherMode cipher_mode;
|
||||
bool is_video;
|
||||
CdmCencPatternEncryptionDescriptor pattern;
|
||||
// TODO(b/149524614): These field is not necessary except for
|
||||
// backwards-compatibility while we are transitioning from the v15 API to the
|
||||
// v16 API.
|
||||
bool observe_legacy_fields;
|
||||
CdmDecryptionParametersV16()
|
||||
: key_id(),
|
||||
samples(),
|
||||
is_secure(true),
|
||||
cipher_mode(kCipherModeCtr),
|
||||
is_video(true),
|
||||
pattern(),
|
||||
observe_legacy_fields(false) {}
|
||||
CdmDecryptionParametersV16(const KeyId& key_id_param)
|
||||
: key_id(key_id_param),
|
||||
samples(),
|
||||
is_secure(true),
|
||||
cipher_mode(kCipherModeCtr),
|
||||
is_video(true),
|
||||
pattern(),
|
||||
observe_legacy_fields(false) {}
|
||||
|
||||
// TODO(b/149524614): This method is a temporary measure for
|
||||
// backwards-compatibility while we are transitioning from the v15 API to the
|
||||
// v16 API.
|
||||
static CdmDecryptionParametersV16 from_v15(
|
||||
const CdmDecryptionParameters& v15_params) {
|
||||
CdmDecryptionParametersV16 new_params;
|
||||
new_params.key_id = *(v15_params.key_id);
|
||||
new_params.is_secure = v15_params.is_secure;
|
||||
new_params.cipher_mode = v15_params.cipher_mode;
|
||||
new_params.is_video = v15_params.is_video;
|
||||
new_params.pattern = v15_params.pattern_descriptor;
|
||||
new_params.observe_legacy_fields = true;
|
||||
|
||||
new_params.samples.emplace_back();
|
||||
CdmDecryptionSample& sample = new_params.samples.back();
|
||||
sample.encrypt_buffer = v15_params.encrypt_buffer;
|
||||
sample.encrypt_buffer_length = v15_params.encrypt_length;
|
||||
sample.decrypt_buffer = v15_params.decrypt_buffer;
|
||||
sample.decrypt_buffer_size = v15_params.decrypt_buffer_length;
|
||||
sample.decrypt_buffer_offset = v15_params.decrypt_buffer_offset;
|
||||
sample.iv = *(v15_params.iv);
|
||||
|
||||
sample.subsamples.emplace_back();
|
||||
CdmDecryptionSubsample& subsample = sample.subsamples.back();
|
||||
if (v15_params.is_encrypted) {
|
||||
subsample.protected_bytes = v15_params.encrypt_length;
|
||||
} else {
|
||||
subsample.clear_bytes = v15_params.encrypt_length;
|
||||
}
|
||||
subsample.flags = v15_params.subsample_flags;
|
||||
subsample.block_offset = v15_params.block_offset;
|
||||
|
||||
return new_params;
|
||||
}
|
||||
};
|
||||
|
||||
struct CdmKeyRequest {
|
||||
CdmKeyMessage message;
|
||||
CdmKeyRequestType type;
|
||||
|
||||
Reference in New Issue
Block a user