Source release 16.2.0

This commit is contained in:
John W. Bruce
2020-04-10 16:13:07 -07:00
parent 1ff9f8588a
commit b830b1d1fb
883 changed files with 509706 additions and 143739 deletions

View File

@@ -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_; }

View File

@@ -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_;

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);
};

View File

@@ -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_;

View File

@@ -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:

View File

@@ -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);

View File

@@ -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;

View File

@@ -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,

View File

@@ -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_;

View File

@@ -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_;

View File

@@ -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"

View File

@@ -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);

View 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_

View 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_

View 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_

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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";

View File

@@ -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;