Files
ce_cdm/cdm/include/cdm.h
Googler 6d36a0c93d Source release 19.6.0
GitOrigin-RevId: 13a33e34413c19da1bfe76abcc66be519c9ac9d1
2025-06-09 23:44:53 -07:00

963 lines
41 KiB
C++

// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
// Based on the EME draft spec from 2016 June 10.
// http://www.w3.org/TR/2016/WD-encrypted-media-20160610/"
#ifndef WVCDM_CDM_CDM_H_
#define WVCDM_CDM_CDM_H_
#include <stdint.h>
#include <map>
#include <string>
#include <vector>
#include "cdm_version.h"
// Uncomment this line when making static CDM builds. This will be edited by
// release scripts.
//#define CDM_STATIC 1
// Define CDM_EXPORT to export functionality across shared library boundaries.
#if defined(CDM_STATIC)
# define CDM_EXPORT
#else
# if defined(_WIN32)
# if defined(CDM_IMPLEMENTATION)
# define CDM_EXPORT __declspec(dllexport)
# else
# define CDM_EXPORT __declspec(dllimport)
# endif // defined(CDM_IMPLEMENTATION)
# else // defined(_WIN32)
# if defined(CDM_IMPLEMENTATION)
# define CDM_EXPORT __attribute__((visibility("default")))
# else
# define CDM_EXPORT
# endif
# endif // defined(_WIN32)
#endif // defined(CDM_STATIC)
namespace CDM_NAMESPACE {
class CDM_EXPORT ITimerClient {
public:
virtual ~ITimerClient() {}
// Called by ITimer when a timer expires.
virtual void onTimerExpired(void* context) = 0;
protected:
ITimerClient() {}
};
class CDM_EXPORT Cdm : public ITimerClient {
public:
// Session types defined by EME.
enum SessionType : int32_t {
kTemporary = 0,
kPersistentLicense = 1,
kPersistent = kPersistentLicense, // deprecated name from June 1 draft
// kPersistentUsageRecord = 2, // deprecated, no longer supported.
kUnknownSessionType = -1, // For error conditions
};
// Message types defined by EME.
enum MessageType : int32_t {
kLicenseRequest = 0,
kLicenseRenewal = 1,
kLicenseRelease = 2,
kIndividualizationRequest = 3, // Not used. Direct Individualization
// is used instead of App-Assisted
};
// Status codes returned by CDM functions.
//
enum Status : int32_t {
kSuccess = 0,
// These are analogous to the exceptions defined in the EME specification.
// Client implementations that support the EME API should pass these
// directly to the client application.
// Note: kTypeError replaced kInvalidAccess in the 6/1/2015 EME spec.
kTypeError = 1,
kNotSupported = 2,
kInvalidState = 3,
kQuotaExceeded = 4,
// These are additional codes defined by Widevine. In client implementations
// that support the EME API, these codes should be handled in the system
// layer. If it is necessary to notify the client application of one of
// these statuses, it should be mapped to one of the exception codes defined
// in the EME specification. Some of these errors are considered
// "recoverable" in that there are specific known remedies that the client
// may take in response to them. See the Integration Guide for further
// information.
kNeedsDeviceCertificate = 101, // Recoverable
kSessionNotFound = 102,
kDecryptError = 103,
kNoKey = 104,
kKeyUsageBlockedByPolicy = 105,
kRangeError = 106,
kResourceContention = 107, // Recoverable
kSessionStateLost = 108, // Recoverable
kSystemStateLost = 109, // Recoverable
kOutputTooLarge = 110, // Recoverable
kNeedsServiceCertificate = 111, // Recoverable
kDeviceRevoked = 112,
// This covers errors that we do not expect (see logs for details):
kUnexpectedError = 99999,
};
// These are the init data types defined by EME.
enum InitDataType : int32_t {
kCenc = 0,
kKeyIds = 1, // NOTE: not supported by Widevine at this time
kWebM = 2,
// This type is not defined by EME but is supported by Widevine
kHls = 10000,
};
// These are the crypto schemes supported by CENC 3.0.
enum EncryptionScheme : int32_t {
kClear = 0,
kAesCtr = 1, // AES-CTR, for use with the "cenc" schema
kAesCbc = 2, // AES-CBC, for use with the "cbcs" schema
};
// These are key statuses defined by EME.
enum KeyStatus : int32_t {
kUsable = 0,
kExpired = 1,
kOutputRestricted = 2,
kOutputNotAllowed = kOutputRestricted, // deprecated name from June 1 draft
kStatusPending = 3,
kInternalError = 4,
kReleased = 5,
};
// These are the possible HDCP levels supported by Widevine.
// For ease of comparison, these values are kept in ascending order by version
// number.
enum HdcpVersion : int32_t {
kHdcp1_x = 0, // Any 1.x version
kHdcp1_0 = 100,
kHdcp1_1 = 101,
kHdcp1_2 = 102,
kHdcp1_3 = 103,
kHdcp1_4 = 104,
kHdcp2_0 = 200,
kHdcp2_1 = 201,
kHdcp2_2 = 202,
kHdcp2_3 = 203
};
// Permissible usages for a key. Returned as a set of flags; multiple
// flags may be set. The specific settings are defined in the license
// and the OEMCrypto Key Control Block. The CDM uses settings in the
// license to derive these flags.
typedef uint32_t KeyAllowedUsageFlags;
static const KeyAllowedUsageFlags kAllowNone = 0;
static const KeyAllowedUsageFlags kAllowDecryptToClearBuffer = 1;
static const KeyAllowedUsageFlags kAllowDecryptToSecureBuffer = 2;
static const KeyAllowedUsageFlags kAllowGenericEncrypt = 4;
static const KeyAllowedUsageFlags kAllowGenericDecrypt = 8;
static const KeyAllowedUsageFlags kAllowGenericSign = 16;
static const KeyAllowedUsageFlags kAllowGenericSignatureVerify = 32;
// These are defined by Widevine. The CDM can be configured to decrypt in
// three modes (dependent on OEMCrypto support).
enum SecureOutputType : int32_t {
// Data is decrypted to an opaque handle.
// Translates to OEMCrypto's OEMCrypto_BufferType_Secure.
kOpaqueHandle = 0,
// Decrypted data never returned to the caller, but is decoded and rendered
// by OEMCrypto.
// Translates to OEMCrypto's OEMCrypto_BufferType_Direct.
kDirectRender = 1,
// There is no secure output available, so all data is decrypted into a
// clear buffer in main memory.
// Translates to OEMCrypto's OEMCrypto_BufferType_Clear.
kNoSecureOutput = 2,
};
// Logging levels defined by Widevine.
// See Cdm::initialize().
enum LogLevel : int32_t {
kSilent = -1,
kErrors = 0,
kWarnings = 1,
kInfo = 2,
kDebug = 3,
kVerbose = 4,
};
// Types of service defined by Widevine.
// The service certificate installation methods - Cdm::setServiceCertificate()
// and Cdm::parseAndLoadServiceCertificateResponse() - use these to identify
// which service the certificate is intended for.
enum ServiceRole : int32_t {
kAllServices = 0,
kProvisioningService = 1,
kLicensingService = 2,
};
// These are the available Widevine robustness levels.
enum RobustnessLevel : int32_t {
kL1 = 1,
kL2 = 2,
kL3 = 3,
};
// Status code returned by getProvisioningStatus API.
enum ProvisioningStatus : int32_t {
kProvisioned = 0,
kUnknownProvisionStatus = 1,
kNeedsDrmCertProvisioning = 2,
kNeedsOemCertProvisioning = 3,
};
// A map of key statuses.
// See Cdm::getKeyStatuses().
typedef std::map<std::string, KeyStatus> KeyStatusMap;
// An event listener interface provided by the application and attached to
// each CDM session.
// See Cdm::createSession().
class IEventListener {
public:
virtual ~IEventListener() {}
// A message (license request, renewal, etc.) to be dispatched to the
// application's license server.
// The response, if successful, should be provided back to the CDM via a
// call to Cdm::update().
//
// The |server_url| parameter is not part of EME and may be ignored
// on EME-based integrations. It will be blank for initial license requests
// but filled in for renewal and release messages. It's offered for the use
// of apps that want to know the URL to send renewals and releases to
// without hardcoding it or retrieving it out-of-band.
virtual void onMessage(const std::string& session_id,
MessageType message_type, const std::string& message,
const std::string& server_url) = 0;
// There has been a change in the keys in the session or their status.
virtual void onKeyStatusesChange(const std::string& session_id,
bool has_new_usable_key) = 0;
// Called when the CDM changes the expiration time for a session.
// |new_expiration| is in milliseconds since 1970 UTC. If the license
// doesn't expire, it'll be -1.
virtual void onExpirationChange(const std::string& session_id,
int64_t new_expiration) = 0;
// A remove() operation has been completed.
virtual void onRemoveComplete(const std::string& session_id) = 0;
protected:
IEventListener() {}
};
// A storage interface provided by the application. This defines the "origin"
// that the CDM will operate in by the files it can access. Passing different
// IStorage instances to Cdm::create will cause those CDM instances to be in
// different "origins" as defined by the IStorage instance. For example,
// different IStorage instances could be tied to different folders for
// different origins.
//
// It is important for multi-origin hosts to verify the application's origin.
// This ensures that the application does not access files from another
// origin.
//
// NOTE: It is important for users of your application to be able to clear
// stored data. Also, browsers or other multi-application systems should
// store data separately per-app or per-origin.
// See http://www.w3.org/TR/encrypted-media/#privacy-storedinfo.
class IStorage {
public:
virtual ~IStorage() {}
virtual bool read(const std::string& name, std::string* data) = 0;
virtual bool write(const std::string& name, const std::string& data) = 0;
virtual bool exists(const std::string& name) = 0;
virtual bool remove(const std::string& name) = 0;
// Returns the size of the given file. If the file does not exist or any
// other error occurs, this should return a negative number.
virtual int32_t size(const std::string& name) = 0;
// Populates |file_names| with the name of each file in the file system.
// This is assumed to be a flat filename space (top level directory is
// unnamed, and there are no subdirectories).
virtual bool list(std::vector<std::string>* file_names) = 0;
protected:
IStorage() {}
};
// A clock interface provided by the application, independent of CDM
// instances.
// See Cdm::initialize().
class IClock {
public:
virtual ~IClock() {}
// Returns the current time in milliseconds since 1970 UTC.
virtual int64_t now() = 0;
protected:
IClock() {}
};
// A timer interface provided by the application, independent of CDM
// instances.
// See Cdm::initialize().
// Implementations of this class only need to deal with at most one
// outstanding timer per IClient at a time. It is an error for setTimeout() to
// be called while there is already a timer running for that client. It is
// recommended for implementers of this class to cancel the preexisting timer
// and start the new timer if this erroneous situation occurs.
// Timers are non-repeating. If the CDM wants to repeat a timer, it will call
// setTimeout() again inside the timeout callback.
class ITimer {
public:
virtual ~ITimer() {}
// This typedef is for backward compatibility with v3.0.0.
typedef ITimerClient IClient;
// Call |client->onTimerExpired(context)| after a delay of |delay_ms| ms.
virtual void setTimeout(int64_t delay_ms, IClient* client,
void* context) = 0;
// Cancel the timer associated with |client|.
virtual void cancel(IClient* client) = 0;
protected:
ITimer() {}
};
// A logging interface provided by the application. This will be called any
// time the CE CDM wants to log a message.
// See Cdm::initialize().
//
// A reference implementation that logs to stderr is provided in
// stderr_logger.h. Its behavior is identical to the behavior of previous
// CE CDM releases.
class ILogger {
public:
virtual ~ILogger() {}
// Log the provided message.
virtual void log(const std::string& message) = 0;
protected:
ILogger() {}
};
// The CE CDM has various pieces of client information baked into it at
// compile-time. These can be retrieved at runtime by Cdm::getClientInfo(),
// which returns them in this struct.
// These parameters match the client identification in license requests.
struct ClientInfo {
// The name of the company who makes the client, e.g. "KubrickTech".
// This matches the "Make" field in the Widevine Integration Console.
std::string company_name;
// The client's model name, e.g. "HAL 9000".
// This matches the "Model" field in the Widevine Integration Console.
std::string model_name;
// The client's model year, e.g. "2001".
// Can be used to distinguish different devices with the same model name.
// This matches the "Year" field in the Widevine Integration Console.
std::string model_year;
// The name or codename of the product or application, e.g. "clarke".
// This may be the same as "model_name".
std::string product_name;
// The name or codename of the client, e.g. "HAL".
// This may be the same as "model_name" or "product_name".
std::string device_name;
// The CPU architecture of the client, e.g. "ARMv7".
std::string arch_name;
// A string containing build information about the CE CDM and the client
// it's integrated into. Consists of multiple values separated by spaces
// and vertical pipes. (e.g. " | ")
std::string build_info;
};
// Initialize the CDM library and provide access to platform services.
// All platform interfaces are required. It is the responsibility of the host
// platform to ensure that the objects passed into this method remain valid
// for the lifetime of the CDM library.
// Logging is controlled by |verbosity|.
// Must be called and must return kSuccess before create() is called.
static Status initialize(SecureOutputType secure_output_type,
IStorage* storage, IClock* clock, ITimer* timer,
ILogger* logger, LogLevel verbosity);
// This is a variant of the above function that allows the caller to pass a
// Sandbox ID. Platforms that use Sandbox IDs should use this initalize()
// function instead of the previous one. Platforms that do not use Sandbox IDs
// should not use this version of initialize().
static Status initialize(SecureOutputType secure_output_type,
IStorage* storage, IClock* clock, ITimer* timer,
ILogger* logger, LogLevel verbosity,
const std::string& sandbox_id);
// Query the CDM library version.
static const char* version();
// Retrieves the client information for this CE CDM integration.
static Status getClientInfo(ClientInfo* client_info);
// Constructs a new CDM instance.
// initialize() must be called first and must return kSuccess before a CDM
// instance may be constructed.
// The CDM may notify of events at any time via the provided |listener|,
// which may not be NULL.
// |storage| defines the storage to use for this instance. By providing
// different objects here for different origins, this parameter can be used to
// provide per-origin storage. It may not be NULL.
//
// If |privacy_mode| is true, service certificates are required and will be
// used to encrypt messages to the license server.
// By using service certificates to encrypt communication with the license
// server, device-identifying information cannot be extracted from the
// license exchange process by an intermediate layer between the CDM and
// the server.
// This is particularly useful for browser environments, but is recommended
// for use whenever possible.
//
// If |storage_is_read_only| is true, the Widevine CE CDM will treat |storage|
// as read-only and prevent attempts to modify any data in the IStorage. Note
// that this is *not* the expected operation mode for most clients and will
// likely lead to playback failures. It should only be used in cases where
// read-only certificates and licenses have been pre-loaded on a device, such
// as the preloaded licenses in ATSC 3.
// It is not possible to mix read-only and non-read-only files in the same
// IStorage instance. A separate CDM with a separate IStorage pointing to the
// non-read-only files should be created with the read-only flag set to false.
static Cdm* create(IEventListener* listener, IStorage* storage,
bool privacy_mode = false,
bool storage_is_read_only = false);
~Cdm() override {}
// The following three methods relate to service certificates. A service
// certificate holds the RSA public key for a server, as well as other fields
// needed for provisioning. Service certificates are mandatory if privacy mode
// is turned on, as they are used to encrypt portions of outgoing messages to
// the provisioning and licensing servers.
// If a provisioning service certificate has not been installed before
// generating a provisioning request, a default certificate that only works
// with the Widevine-hosted provisioning service will be used.
// It is an error to generate a licensing request while privacy mode is
// turned on without installing a service certificate for the licensing
// service first.
// Installs a service certificate from a data buffer.
// This is used when the system or application already knows the certificate
// of the service it wishes to communicate with, either because it is baked
// into the software or because it was previously cached after a call to
// Cdm::parseAndLoadServiceCertificateResponse().
// If this method returns |Status::kSuccess|, the service certificate was
// installed successfully.
// The certificate is installed only for the service given by |role|. If the
// role |ServiceRole::kAllServices| is given, it is installed for all
// services.
virtual Status setServiceCertificate(ServiceRole role,
const std::string& certificate) = 0;
// Generate a Service Certificate Request message.
// This is used to fetch a service certificate from the license server.
// It is needed in cases where the system or application does not have
// a service certificate for the license server already.
virtual Status getServiceCertificateRequest(std::string* message) = 0;
// Parse a Service Certificate Response message, extracting the certificate
// from the message and installing it into the CDM.
// This is used when fetching a service certificate from the license server.
// A request should be generated by getServiceCertificateRequest() and sent
// to the license server. The server's response should be passed into this
// method.
// If this method returns |Status::kSuccess|, the service certificate was
// installed successfully.
// If a pointer to a string is passed in the |certificate| parameter, this
// method will fill it with the extracted certificate. This certificate
// string may be used with future CDM instances as the input to
// setServiceCertificate(). This avoids needing to make a call to the license
// server to get the certificate. The |certificate| argument may be NULL if
// you do not want to take advantage of this.
// The certificate is installed only for the service given by |role|. If the
// role |ServiceRole::kAllServices| is given, it is installed for all
// services.
virtual Status parseAndLoadServiceCertificateResponse(
ServiceRole role, const std::string& response,
std::string* certificate) = 0;
// Returns the robustness level of the device, as reported by OEMCrypto. Note
// that this function is *not* cryptographically secure and it should only be
// relied upon for informational purposes (e.g. determining which content to
// show in the UI) and not security purposes. (e.g. determining which content
// to allow the device to play) *Only* secure communication between OEMCrypto
// and the license service should be used to make security decisions.
virtual Status getRobustnessLevel(RobustnessLevel* level) = 0;
// Query the underlying OEMCrypto implementation's System ID.
virtual Status getSystemId(uint32_t* id) = 0;
// Returns the resource rating tier of the device, as reported by OEMCrypto.
virtual Status getResourceRatingTier(uint32_t* tier) = 0;
// Retrieves the build information for the underlying OEMCrypto
// implementation.
virtual Status getOemCryptoBuildInfo(std::string* build_info) = 0;
// Retrieves the current provisioning status. The Device Certificate is
// origin-specific, and the origin is determined by the CDM's current IStorage
// object.
virtual ProvisioningStatus getProvisioningStatus() = 0;
// Creates a Provisioning Request message.
// This is used to provision the device. The request should be sent to the
// provisioning server and the response given to handleProvisioningResponse().
virtual Status getProvisioningRequest(std::string* request) = 0;
// Handles a provisioning response and provisions the device. If this returns
// success, the device will now be provisioned.
virtual Status handleProvisioningResponse(const std::string& response) = 0;
// Remove the device's Device Certificate (for the current origin).
// The Device Certificate is origin-specific, and the origin is
// determined by the CDM's current IStorage object.
virtual Status removeProvisioning() = 0;
// Get the current list of offline licenses on the system.
// License storage is origin-specific, and the origin is determined by the
// CDM's current IStorage object.
virtual Status listStoredLicenses(std::vector<std::string>* key_set_ids) = 0;
// Checks whether the device is capable of supporting a given HDCP version.
// If successful, |key_status| is set to either kUsable or kOutputRestricted.
virtual Status getStatusForHdcpVersion(HdcpVersion hdcp,
KeyStatus* key_status) = 0;
// Checks if the given initialization data contains embedded, entitled keys.
// Sets the variable pointed to by |contains_keys| to true if the init data
// contains embedded keys or false if it does not. This function is useful if
// apps choose to handle such initialization data differently, such as in the
// case of key rotation or loading an offline entitlement license.
//
// For PSSH init data, this function accepts the full concatenated blob of
// PSSH boxes from the stream. It will return true if any of the PSSHs contain
// embedded Widevine keys.
virtual Status initDataContainsEmbeddedKeys(InitDataType init_data_type,
const std::string& init_data,
bool* contains_keys) = 0;
// Creates a new session.
// Do not use this to load an existing persistent session (use load()).
// If successful, the session ID is returned via |session_id|.
virtual Status createSession(SessionType session_type,
std::string* session_id) = 0;
// Generates a request based on the provided |init_data|. For PSSH init data,
// the CE CDM can accept the full concatenated blob of PSSH boxes from the
// stream. It will select the correct Widevine PSSH, so callers do not have to
// determine the correct PSSH from the list themselves.
// If the init data contains embedded keys, they will be remembered by the
// session and loaded after the matching entitlement key is provided to
// update().
//
// The request will be provided via a synchronous call to
// IEventListener::onMessage().
// This is done so that license requests and renewals follow the same flow.
virtual Status generateRequest(const std::string& session_id,
InitDataType init_data_type,
const std::string& init_data) = 0;
// Loads an existing persisted session from storage.
virtual Status load(const std::string& session_id) = 0;
// Provides messages, including licenses, to the CDM.
// If the message is a successful response to a release message, stored
// session data will be removed for the session.
virtual Status update(const std::string& session_id,
const std::string& response) = 0;
// Loads the entitled keys embedded in |init_data| into the session identified
// by |session_id|. The matching entitlement key must already be loaded in the
// session via previous calls to update() or load(). For PSSH init data, the
// CE CDM can accept the full concatenated blob of PSSH boxes from the stream.
// It will select the correct Widevine PSSH, so callers do not have to
// determine the correct PSSH from the list themselves.
//
// It is not necessary to call this function after passing PSSHs containing
// entitled keys to generateRequest(). This function is only used when adding
// new entitled keys to an existing session, such as for key rotation or
// after loading a persisted entitlement license.
virtual Status loadEmbeddedKeys(const std::string& session_id,
InitDataType init_data_type,
const std::string& init_data) = 0;
// The time, in milliseconds since 1970 UTC, after which the key(s) in the
// session will no longer be usable to decrypt media data, or -1 if no such
// time exists.
virtual Status getExpiration(const std::string& session_id,
int64_t* expiration) = 0;
// A map of known key IDs to the current status of the associated key.
virtual Status getKeyStatuses(const std::string& session_id,
KeyStatusMap* key_statuses) = 0;
// Gets the permitted usage for a specific key by ID.
virtual Status getKeyAllowedUsages(const std::string& session_id,
const std::string& key_id,
KeyAllowedUsageFlags* usage_flags) = 0;
// Gets the permitted usage for a specific key by ID.
// Search for key across all known sessions. If there are keys in separate
// sessions that match the given key_id, return kTypeError unless all such
// keys have identical Allowed Usage settings.
virtual Status getKeyAllowedUsages(const std::string& key_id,
KeyAllowedUsageFlags* usage_flags) = 0;
// Indicates that the application no longer needs the session and the CDM
// should release any resources associated with it and close it.
// Does not generate release messages for persistent sessions.
// Does not remove stored session data for persistent sessions.
virtual Status close(const std::string& session_id) = 0;
// Removes stored session data associated with the session.
// The session must be loaded before it can be removed.
// Generates release messages, which must be delivered to the license server.
// A reply from the license server must be provided via update() before the
// session is fully removed.
virtual Status remove(const std::string& session_id) = 0;
// Removes stored session data associated with the session.
// The session must be loaded before it can be removed.
// Unlike remove(), this method does not generate a release message. The
// stored data is removed immediately. The session is closed if this function
// returns successfully.
// Generally, callers should not use this method, as it prevents usage data
// from being gathered and it does not allow the license's release to be
// tracked by the server. Most callers will want to use remove(), which
// generates a release request. However, this method is provided for
// applications that have a specific need to release licenses without a server
// roundtrip and are aware of the costs of doing so.
// There is no EME equivalent to this method. EME specifies that removal
// should require a release request, as is done by the remove() method.
virtual Status forceRemove(const std::string& session_id) = 0;
// Describes a repeating pattern as defined by the CENC 3.0 standard. A
// CENC 3.0 pattern consists of a number of encrypted blocks followed by a
// number of clear blocks, after which it repeats.
struct Pattern {
public:
Pattern() : encrypted_blocks(0), clear_blocks(0) {}
Pattern(uint32_t encrypt, uint32_t clear)
: encrypted_blocks(encrypt), clear_blocks(clear) {}
// The number of crypto blocks that are encrypted and therefore need to be
// decrypted.
uint32_t encrypted_blocks;
// The number of crypto blocks that are not encrypted and therefore should
// be skipped when doing decryption.
uint32_t clear_blocks;
};
struct Subsample {
public:
Subsample() : clear_bytes(0), protected_bytes(0) {}
// The number of bytes of data that are not protected and therefore should
// be copied unchanged when doing decryption. The clear bytes come before
// the protected bytes in the subsample.
uint32_t clear_bytes;
// The number of bytes of data that are protected and therefore should be
// considered for decryption. Depending on the pattern, these bytes may all
// be decrypted or only some of them may be. The protected bytes come after
// the clear bytes in the subsample.
uint32_t protected_bytes;
};
struct InputBuffer {
public:
InputBuffer()
: iv(nullptr),
iv_length(0),
data(nullptr),
data_length(0),
subsamples(nullptr),
subsamples_length(0) {}
// These fields are treated as an array of bytes, with the |iv| pointer
// pointing to the first byte and containing |iv_length| number of bytes.
// These should be the bytes of the initial IV that should be used to
// decrypt this sample.
//
// |iv_length| must be 16 if the sample contains any protected data. If the
// content contains an 8-byte IV, it is the responsibility of the caller to
// expand it to 16 bytes following the method in the ISO-CENC standard.
const uint8_t* iv;
uint32_t iv_length;
// These fields are treated as an array of bytes, with the |data| pointer
// pointing to the first byte and containing |data_length| number of bytes.
// This data should be ready to be decrypted with no further processing. If
// the data is coming from a format that requires processing before
// decryption, that processing needs to happen before the data is passed in
// here. For example, content coming from HLS will need to have its extra
// start code emulation prevention removed before it is passed to the
// Widevine CE CDM.
const uint8_t* data;
uint32_t data_length;
// These fields are treated as an array of Subsample structs, with the
// |subsamples| pointer pointing to the first Subsample and containing
// |samples_length| number of entries. These structs describe all the
// ISO-CENC subsamples that make up the sample.
//
// The sum of all the |clear_bytes| and |protected_bytes| in all the
// subsamples must equal the |data_length| field.
const Subsample* subsamples;
uint32_t subsamples_length;
};
struct OutputBuffer {
OutputBuffer() : data(nullptr), data_offset(0), data_length(0) {}
// The type of value stored in this pointer depends on the secure output
// type passed to Cdm::initialize() and the |is_secure| field of the
// DecryptionBatch.
//
// If |is_secure| is false or the secure output type is kNoSecureOutput,
// this is a memory address in main memory.
// If |is_secure| is true and the secure output type is kOpaqueHandle,
// this is an opaque handle.
// If |is_secure| is true and the secure output type is kDirectRender,
// this is ignored.
//
// See also the SecureOutputType argument to initialize().
void* data;
// An offset applied to the output address inside OEMCrypto.
// Useful when |data| is an opaque handle rather than a memory address.
uint32_t data_offset;
// The maximum amount of data that can be decrypted to the |data| buffer.
// Must be at least as large as the input buffer's |data_length| plus the
// bytes that will be skipped by |data_offset|.
uint32_t data_length;
};
struct Sample {
public:
Sample() : input(), output() {}
// These structs describe the protected input data of the sample and the
// output buffer that decrypted data should be written to.
InputBuffer input;
OutputBuffer output;
};
struct DecryptionBatch {
public:
DecryptionBatch()
: samples(nullptr),
samples_length(0),
key_id(nullptr),
key_id_length(0),
pattern(),
is_secure(false),
encryption_scheme(kClear),
is_video(true) {}
// These fields are treated as an array of Sample structs, with the
// |samples| pointer pointing to the first Sample and containing
// |samples_length| number of entries. These structs describe all the data
// that is going to be decrypted. You can pass as many samples to the CDM as
// you want, but be aware that passing more samples than your OEMCrypto
// implementation can handle in one decrypt call is inefficient, as the CDM
// will have to do work to break the data up into smaller pieces.
const Sample* samples;
uint32_t samples_length;
// These fields are treated as an array of bytes, with the |key_id| pointer
// pointing to the first byte and containing |key_id_length| number of
// bytes. These should be the bytes of the Key ID of the key that should be
// used to decrypt the |samples|.
const uint8_t* key_id;
uint32_t key_id_length;
// Describes the repeating pattern with which the content was encrypted. If
// left at its default value of (0,0), patterns will be disabled. Should
// only be changed for content that uses patterns, such as for CENC 3.0
// "cbcs" content or for HLS content.
Pattern pattern;
// Indicates whether the OutputBuffers in the Samples are secure outputs or
// not. False for clear buffers, true otherwise.
// Must be false if the secure output type is kNoSecureOutput.
// See also the SecureOutputType argument to initialize().
bool is_secure;
// Specifies the encryption scheme, if any, to be used to decrypt the data.
// When set to kClear, decryption will copy the input data directly to the
// output buffer. This is necessary for secure output types, where the
// output buffer cannot be directly accessed above the CDM.
EncryptionScheme encryption_scheme;
// Used by secure output type kDirectRender, where the secure hardware must
// decode and render the decrypted content:
bool is_video;
};
// Decrypt the samples contained in the DecryptionBatch |batch| from their
// InputBuffer to their OutputBuffer. The |key_id| field of |batch|
// must refer to a key that is already loaded in some session.
virtual Status decrypt(const DecryptionBatch& batch) = 0;
// Decrypt the samples contained in the DecryptionBatch |batch| from their
// InputBuffer to their OutputBuffer. Decryption will be attempted in the
// session identified by |session_id|, regardless of whether the |key_id|
// field of |batch| refers to a key loaded in that session. If |key_id| refers
// to a key that is not loaded in the given session, decryption will fail.
//
// This overload is used when platforms need to play clear content through the
// secure path before a key is loaded.
virtual Status decrypt(const std::string& session_id,
const DecryptionBatch& batch) = 0;
// Sets a value in the custom app settings. These are settings
// that are sent with any message to the license server. These methods
// should only be used by advanced users maintaining existing systems.
// The |key| cannot be empty.
virtual Status setAppParameter(const std::string& key,
const std::string& value) = 0;
// Gets the current value in the custom app settings. If the key is
// not present, then kTypeError is returned. The |key| cannot be
// empty. |result| cannot be null. See setAppParameter().
virtual Status getAppParameter(const std::string& key,
std::string* result) = 0;
// Removes the value in the custom app settings. If the key is not
// present, then kTypeError is returned. The |key| cannot be empty.
// See setAppParameter().
virtual Status removeAppParameter(const std::string& key) = 0;
// Clears all the values in the custom app settings. See setAppParameter().
virtual Status clearAppParameters() = 0;
// Generic crypto - functions for applying crypto operations to
// app-level data (outside the content stream).
enum GenericEncryptionAlgorithmType : int32_t {
kEncryptionAlgorithmUnknown,
kEncryptionAlgorithmAesCbc128,
};
enum GenericSigningAlgorithmType : int32_t {
kSigningAlgorithmUnknown,
kSigningAlgorithmHmacSha256
};
// Encrypts a buffer of app-level data.
virtual Status genericEncrypt(const std::string& session_id,
const std::string& in_buffer,
const std::string& key_id,
const std::string& iv,
GenericEncryptionAlgorithmType algorithm,
std::string* out_buffer) = 0;
// Decrypts a buffer of app-level data.
virtual Status genericDecrypt(const std::string& session_id,
const std::string& in_buffer,
const std::string& key_id,
const std::string& iv,
GenericEncryptionAlgorithmType algorithm,
std::string* out_buffer) = 0;
// Signs a buffer of app-level data.
virtual Status genericSign(const std::string& session_id,
const std::string& message,
const std::string& key_id,
GenericSigningAlgorithmType algorithm,
std::string* signature) = 0;
// Verifies the signature on a buffer of app-level data.
// Returns kSuccess if signature is verified, otherwise returns kDecryptError.
virtual Status genericVerify(const std::string& session_id,
const std::string& message,
const std::string& key_id,
GenericSigningAlgorithmType algorithm,
const std::string& signature) = 0;
// Enable enforcement of Video Resolution Constraints.
// This function should be called during session startup and any time
// the resolution of the video stream changes. The resolution passed in should
// be the resolution of the content being played, not the output resolution of
// the device.
// Video resolutions in the license policy are stored as 32-bit values
// representing the total number of pixels. If the product of |width| and
// |height| is greater than or equal to 2^32, this will return kRangeError.
virtual Status setVideoResolution(const std::string& session_id,
uint32_t width, uint32_t height) = 0;
// Retrieve the metrics gathered by this CDM instance.
// The Widevine CE CDM gathers metrics about the time taken to perform various
// computations, as well as their error codes. This method allows platforms
// and apps to gather these metrics to send them back to Google for analysis.
virtual Status getMetrics(std::string* serialized_metrics) = 0;
// Creates a Cast Provisioning Request message.
// This method is only useful on devices that implement support for Google
// Cast. Calling this method will generate a provisioning request that can be
// used to provision the device's Cast certificate. The request should be sent
// to the provisioning server just like a request from
// getProvisioningRequest(). However, the response should be given to
// handleCastProvisioningResponse() in order to extract the additional,
// Cast-specific fields.
virtual Status getCastProvisioningRequest(std::string* request) = 0;
// Handles a Cast provisioning response.
// This method is only useful on devices that implement support for Google
// Cast. It returns both the Cast public certificate and a wrapped private key
// that can be used with castSign(). Handling a Cast provisioning response
// does not affect the device's Widevine provisioning status. See
// handleProvisioningResponse() for handling Widevine provisioning.
virtual Status handleCastProvisioningResponse(const std::string& response,
std::string* cert,
std::string* wrapped_key) = 0;
// Signs a method for Cast usage.
// This method is only useful on devices that support Google Cast and after
// receiving a wrapped private key from handleCastProvisioningResponse(). This
// method generates a signature for the message using the given private key in
// PKCS#1 with block type 1 padding.
virtual Status castSign(const std::string& wrapped_key,
const std::string& message,
std::string* signature) = 0;
protected:
Cdm() {}
};
} // namespace CDM_NAMESPACE
#endif // WVCDM_CDM_CDM_H_