Cas Client repo update-2.
-Parse EMM in Cas plugin -Entitlement key rotation support -Multi_content_license support
This commit is contained in:
@@ -37,6 +37,9 @@ typedef enum {
|
||||
LICENSE_NEW_EXPIRY_TIME,
|
||||
MULTI_CONTENT_LICENSE_INFO,
|
||||
GROUP_LICENSE_INFO,
|
||||
LICENSE_ENTITLEMENT_PERIOD_UPDATE_REQUEST,
|
||||
LICENSE_ENTITLEMENT_PERIOD_UPDATE_RESPONSE,
|
||||
LICENSE_ENTITLEMENT_PERIOD_UPDATED,
|
||||
|
||||
// TODO(jfore): Evaluate removing this event in favor of return status codes
|
||||
// from
|
||||
@@ -49,6 +52,8 @@ typedef enum {
|
||||
|
||||
UNIQUE_ID = CAS_QUERY_EVENT_START,
|
||||
QUERY_UNIQUE_ID,
|
||||
WV_CAS_PLUGIN_VERSION,
|
||||
QUERY_WV_CAS_PLUGIN_VERSION,
|
||||
|
||||
SET_PARENTAL_CONTROL_AGE = CAS_PARENTAL_CONTROL_EVENT_START,
|
||||
DEPRECATED_PARENTAL_CONTROL_AGE_UPDATED,
|
||||
@@ -82,14 +87,30 @@ typedef enum {
|
||||
ECHO, // Respond to TEST_FOR_ECHO.
|
||||
} CasEventId;
|
||||
|
||||
// Types used inside an FINGERPRINTING_INFO event.
|
||||
typedef enum {
|
||||
FINGERPRINTING_CHANNEL = 0,
|
||||
FINGERPRINTING_CONTROL,
|
||||
} FingerprintingFieldType;
|
||||
|
||||
// Types used inside an SERVICE_BLOCKING_INFO event.
|
||||
typedef enum {
|
||||
SERVICE_BLOCKING_CHANNEL = 0,
|
||||
SERVICE_BLOCKING_DEVICE_GROUP,
|
||||
// Epoch time in seconds. Missing of this field or a value of 0 means
|
||||
// immediate start.
|
||||
SERVICE_BLOCKING_START_TIME_SECONDS,
|
||||
SERVICE_BLOCKING_END_TIME_SECONDS, // Epoch time in seconds.
|
||||
} ServiceBlockingFieldType;
|
||||
|
||||
// Types used inside an SESSION_FINGERPRINTING_CONTROL event.
|
||||
typedef enum {
|
||||
FINGERPRINTING_CONTROL = 0,
|
||||
SESSION_FINGERPRINTING_CONTROL = 0,
|
||||
} SessionFingerprintingFieldType;
|
||||
|
||||
// Types used inside an SESSION_SERVICE_BLOCKING_GROUPS event.
|
||||
typedef enum {
|
||||
SERVICE_BLOCKING_DEVICE_GROUP = 0,
|
||||
SESSION_SERVICE_BLOCKING_DEVICE_GROUP = 0,
|
||||
} SessionServiceBlockingFieldType;
|
||||
|
||||
// Types used inside a MULTI_CONTENT_LICENSE_INFO event.
|
||||
|
||||
@@ -53,22 +53,16 @@ class CasLicense : public wvutil::TimerHandler, public wvcas::CasEventListener {
|
||||
std::string* signed_license_request);
|
||||
|
||||
// Restores a stored license making the keys available for use.
|
||||
// If |content_id_filter| is not null, only matching entitlement keys (as
|
||||
// specified in KeyCategory) will be installed.
|
||||
virtual CasStatus HandleStoredLicense(const std::string& wrapped_rsa_key,
|
||||
const std::string& license_file,
|
||||
const std::string* content_id_filter);
|
||||
const std::string& license_file);
|
||||
|
||||
// Process a server response containing a EMM for use in the processing of
|
||||
// ECM(s).
|
||||
// If |content_id_filter| is not null, only matching entitlement keys (as
|
||||
// specified in KeyCategory) will be installed.
|
||||
// If |device_file| is not nullptr and the license policy allows a license to
|
||||
// be stored |device_file| is populated with the bytes of the license secured
|
||||
// for storage.
|
||||
virtual CasStatus HandleEntitlementResponse(
|
||||
const std::string& entitlement_response,
|
||||
const std::string* content_id_filter, std::string* device_file);
|
||||
const std::string& entitlement_response, std::string* device_file);
|
||||
|
||||
// Process a previously stored device |certificate| and make it available
|
||||
// for use in an EMM request.
|
||||
@@ -132,6 +126,8 @@ class CasLicense : public wvutil::TimerHandler, public wvcas::CasEventListener {
|
||||
|
||||
void OnAgeRestrictionUpdated(const WvCasSessionId& sessionId,
|
||||
uint8_t ecm_age_restriction) override;
|
||||
void OnFingerprintingUpdated(const CasData& fingerprinting) override;
|
||||
void OnServiceBlockingUpdated(const CasData& service_blocking) override;
|
||||
|
||||
void OnSessionFingerprintingUpdated(const WvCasSessionId& sessionId,
|
||||
const CasData& fingerprinting) override;
|
||||
@@ -140,12 +136,20 @@ class CasLicense : public wvutil::TimerHandler, public wvcas::CasEventListener {
|
||||
const WvCasSessionId& sessionId,
|
||||
const CasData& service_blocking) override;
|
||||
|
||||
void OnEntitlementPeriodUpdateNeeded(
|
||||
const std::string& signed_license_request) override;
|
||||
|
||||
// Query to see if the license is expired.
|
||||
virtual bool IsExpired() const;
|
||||
|
||||
// Notify the license that playback decryption has begun.
|
||||
virtual void BeginDecryption();
|
||||
|
||||
// Returns NoError if a valid entitlement period index exists in
|
||||
// |license_file|. The index will be assigned to |entitlement_period_index|.
|
||||
static CasStatus GetEntitlementPeriodIndexFromStoredLicense(
|
||||
const std::string& license_file, uint32_t& entitlement_period_index);
|
||||
|
||||
CasLicense(const CasLicense&) = delete;
|
||||
CasLicense& operator=(const CasLicense&) = delete;
|
||||
|
||||
@@ -156,8 +160,7 @@ class CasLicense : public wvutil::TimerHandler, public wvcas::CasEventListener {
|
||||
CasStatus InstallLicense(const std::string& session_key,
|
||||
const std::string& serialized_license,
|
||||
const std::string& core_message,
|
||||
const std::string& signature,
|
||||
const std::string* content_id_filter);
|
||||
const std::string& signature);
|
||||
CasStatus InstallLicenseRenewal(const std::string& serialized_license,
|
||||
const std::string& core_message,
|
||||
const std::string& signature);
|
||||
|
||||
@@ -15,6 +15,9 @@ class CasMediaId {
|
||||
virtual CasStatus initialize(const std::string& init_data) = 0;
|
||||
virtual const std::string content_id() = 0;
|
||||
virtual const std::string provider_id() = 0;
|
||||
virtual bool is_entitlement_rotation_enabled() { return false; }
|
||||
virtual uint32_t entitlement_period_index() = 0;
|
||||
virtual std::string get_init_data() = 0;
|
||||
};
|
||||
|
||||
} // namespace wvcas
|
||||
|
||||
@@ -89,14 +89,23 @@ class CasEventListener {
|
||||
virtual void OnAgeRestrictionUpdated(const WvCasSessionId& sessionId,
|
||||
uint8_t ecm_age_restriction) = 0;
|
||||
|
||||
// Notifies listeners of new fingerprinting info.
|
||||
// Notifies listeners of new session fingerprinting info.
|
||||
virtual void OnSessionFingerprintingUpdated(
|
||||
const WvCasSessionId& sessionId, const CasData& fingerprinting) = 0;
|
||||
|
||||
// Notifies listeners of new service blocking info.
|
||||
// Notifies listeners of new session service blocking info.
|
||||
virtual void OnSessionServiceBlockingUpdated(
|
||||
const WvCasSessionId& sessionId, const CasData& service_blocking) = 0;
|
||||
|
||||
// Notifies listeners of new fingerprinting info.
|
||||
virtual void OnFingerprintingUpdated(const CasData& fingerprinting) = 0;
|
||||
|
||||
// Notifies listeners of new service blocking info.
|
||||
virtual void OnServiceBlockingUpdated(const CasData& service_blocking) = 0;
|
||||
|
||||
virtual void OnEntitlementPeriodUpdateNeeded(
|
||||
const std::string& signed_license_request) = 0;
|
||||
|
||||
CasEventListener(const CasEventListener&) = delete;
|
||||
CasEventListener& operator=(const CasEventListener&) = delete;
|
||||
};
|
||||
|
||||
@@ -172,6 +172,8 @@ class CryptoInterface {
|
||||
OEMCrypto_SESSION session, OEMCrypto_SESSION* entitled_key_session_id);
|
||||
virtual OEMCryptoResult OEMCrypto_RemoveEntitledKeySession(
|
||||
OEMCrypto_SESSION entitled_key_session_id);
|
||||
virtual OEMCryptoResult OEMCrypto_ReassociateEntitledKeySession(
|
||||
OEMCrypto_SESSION key_sid, OEMCrypto_SESSION oec_sid);
|
||||
virtual uint32_t OEMCrypto_APIVersion();
|
||||
|
||||
// This is the factory method used to enable the oemcrypto interface.
|
||||
@@ -284,6 +286,8 @@ class CryptoSession {
|
||||
OEMCrypto_SESSION* entitled_key_session_id);
|
||||
virtual CasStatus RemoveEntitledKeySession(
|
||||
OEMCrypto_SESSION entitled_key_session_id);
|
||||
virtual CasStatus ReassociateEntitledKeySession(
|
||||
OEMCrypto_SESSION entitled_key_session_id);
|
||||
virtual CasStatus APIVersion(uint32_t* api_version);
|
||||
|
||||
CryptoSession(const CryptoSession&) = delete;
|
||||
|
||||
@@ -48,6 +48,10 @@ class EcmParser {
|
||||
// The serialized payload that the signature is calculated on.
|
||||
virtual std::string ecm_serialized_payload() const = 0;
|
||||
virtual std::string signature() const = 0;
|
||||
|
||||
virtual bool is_entitlement_rotation_enabled() const = 0;
|
||||
virtual uint32_t entitlement_period_index() const = 0;
|
||||
virtual uint32_t entitlement_rotation_window_left() const = 0;
|
||||
};
|
||||
|
||||
} // namespace wvcas
|
||||
|
||||
@@ -63,6 +63,10 @@ class EcmParserV2 : public EcmParser {
|
||||
std::string ecm_serialized_payload() const override { return ""; }
|
||||
std::string signature() const override { return ""; }
|
||||
|
||||
bool is_entitlement_rotation_enabled() const override { return false; }
|
||||
uint32_t entitlement_period_index() const override { return 0; }
|
||||
uint32_t entitlement_rotation_window_left() const override { return 0; }
|
||||
|
||||
private:
|
||||
// Constructs an EcmParserV2 using |ecm|.
|
||||
explicit EcmParserV2(const CasEcm& ecm);
|
||||
|
||||
@@ -49,6 +49,10 @@ class EcmParserV3 : public EcmParser {
|
||||
std::string ecm_serialized_payload() const override;
|
||||
std::string signature() const override;
|
||||
|
||||
bool is_entitlement_rotation_enabled() const override;
|
||||
uint32_t entitlement_period_index() const override;
|
||||
uint32_t entitlement_rotation_window_left() const override;
|
||||
|
||||
private:
|
||||
// Constructs an EcmParserV3 using |ecm|.
|
||||
EcmParserV3(video_widevine::SignedEcmPayload signed_ecm_payload,
|
||||
|
||||
@@ -118,6 +118,8 @@ class OEMCryptoInterface {
|
||||
OEMCrypto_SESSION oec_session, OEMCrypto_SESSION* key_session);
|
||||
virtual OEMCryptoResult OEMCrypto_RemoveEntitledKeySession(
|
||||
OEMCrypto_SESSION key_session);
|
||||
virtual OEMCryptoResult OEMCrypto_ReassociateEntitledKeySession(
|
||||
OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session);
|
||||
virtual uint32_t OEMCrypto_APIVersion() const;
|
||||
|
||||
OEMCryptoInterface(const OEMCryptoInterface&) = delete;
|
||||
|
||||
@@ -7,13 +7,17 @@
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
|
||||
#include "cas_license.h"
|
||||
#include "cas_media_id.h"
|
||||
#include "cas_status.h"
|
||||
#include "cas_types.h"
|
||||
#include "crypto_session.h"
|
||||
#include "ecm_parser.h"
|
||||
#include "emm_parser.h"
|
||||
#include "file_store.h"
|
||||
#include "media_cas.pb.h"
|
||||
#include "timer.h"
|
||||
#include "widevine_cas_session.h"
|
||||
|
||||
@@ -36,6 +40,9 @@ class WidevineCas : public wvutil::TimerHandler {
|
||||
// Close a previously opened session.
|
||||
virtual CasStatus closeSession(WvCasSessionId sessionId);
|
||||
|
||||
// Process an EMM which may contain fingerprinting and service blocking info.
|
||||
virtual CasStatus processEmm(const CasEmm& emm);
|
||||
|
||||
// Process an ECM from the ECM stream for this session’s elementary
|
||||
// stream.
|
||||
virtual CasStatus processEcm(WvCasSessionId sessionId, const CasEcm& ecm);
|
||||
@@ -74,6 +81,16 @@ class WidevineCas : public wvutil::TimerHandler {
|
||||
virtual CasStatus handleEntitlementRenewalResponse(
|
||||
const std::string& response, std::string& license_id);
|
||||
|
||||
// Generates an entitlement license request in a new crypto session, and send
|
||||
// the license request as an event to the app.
|
||||
virtual CasStatus generateEntitlementPeriodUpdateRequest(
|
||||
const std::string& init_data);
|
||||
|
||||
// Processes the license |response| to switch the current license to this
|
||||
// new one.
|
||||
virtual CasStatus handleEntitlementPeriodUpdateResponse(
|
||||
const std::string& response, std::string& license_id);
|
||||
|
||||
// Returns true if the device has been provisioned with a device certificate.
|
||||
virtual bool is_provisioned() const;
|
||||
|
||||
@@ -97,7 +114,8 @@ class WidevineCas : public wvutil::TimerHandler {
|
||||
// Remove the license file given the filename user provides.
|
||||
virtual CasStatus RemoveLicense(const std::string& file_name);
|
||||
|
||||
// Record the license id that user provides.
|
||||
// Record the license id that user provides. This license id will be used to
|
||||
// select license if multiple licenses exist.
|
||||
virtual CasStatus RecordLicenseId(const std::string& license_id);
|
||||
|
||||
void OnTimerEvent() override;
|
||||
@@ -107,11 +125,30 @@ class WidevineCas : public wvutil::TimerHandler {
|
||||
virtual CasStatus HandleProcessEcm(const WvCasSessionId& sessionId,
|
||||
const CasEcm& ecm);
|
||||
virtual CasStatus HandleDeferredECMs();
|
||||
// Extracts the entitlement rotation period index from ECM if specified, and
|
||||
// store it. The function should be called before any license request and the
|
||||
// extracted index will be included in the license request.
|
||||
virtual void TryExtractEntitlementPeriodIndex(const CasEcm& ecm);
|
||||
// Returns true if an offline license with |filename| is successfully loaded.
|
||||
virtual bool TryReuseStoredLicense(const std::string& filename);
|
||||
// Check if a new license is needed due to entitlement period changes. If so,
|
||||
// it will call generateEntitlementPeriodUpdateRequest().
|
||||
void CheckEntitlementPeriodUpdate(uint32_t period_index,
|
||||
uint32_t window_left);
|
||||
|
||||
virtual std::shared_ptr<CryptoSession> getCryptoSession();
|
||||
virtual std::unique_ptr<CasLicense> getCasLicense();
|
||||
virtual std::unique_ptr<wvutil::FileSystem> getFileSystem();
|
||||
virtual std::shared_ptr<WidevineCasSession> newCasSession();
|
||||
virtual std::unique_ptr<EcmParser> getEcmParser(const CasEcm& ecm) const;
|
||||
|
||||
// Creates an EmmParser. Marked as virtual for easier unit test.
|
||||
virtual std::unique_ptr<const EmmParser> getEmmParser(
|
||||
const CasEmm& emm) const;
|
||||
std::vector<uint8_t> GenerateFingerprintingEventMessage(
|
||||
const video_widevine::Fingerprinting& fingerprinting) const;
|
||||
std::vector<uint8_t> GenerateServiceBlockingEventMessage(
|
||||
const video_widevine::ServiceBlocking& service_blocking) const;
|
||||
|
||||
// The CryptoSession will be shared by the all cas sessions. It is also needed
|
||||
// by the cas api to generate EMM requests.
|
||||
@@ -137,15 +174,31 @@ class WidevineCas : public wvutil::TimerHandler {
|
||||
// The age_restriction field in ECM must be greater or equal to
|
||||
// |parental_control_min_age|. Otherwise, ECM will stop being processed.
|
||||
uint parental_control_age_ = 0;
|
||||
// The assigned_license_id helps to indicate which license file current
|
||||
// The requested_license_id helps to indicate which license file current
|
||||
// content will use if multiple licenses exist.
|
||||
std::string assigned_license_id_;
|
||||
std::string requested_license_id_;
|
||||
// The current in use license_id.
|
||||
std::string license_id_;
|
||||
// The group id of a Group license. Empty if the license is not a Group
|
||||
// license (multi content license is not a group license). Used in processECM
|
||||
// to select group keys that can be decrypted by the license.
|
||||
std::string license_group_id_;
|
||||
// Fingerprinting events sent in processing last ECM/EMM. Used to avoid
|
||||
// sending a same event again.
|
||||
std::set<CasData> last_fingerprinting_events_;
|
||||
// Service blocking events sent in processing last ECM/EMM. Used to avoid
|
||||
// sending a same event again.
|
||||
std::set<CasData> last_service_blocking_events_;
|
||||
// Indicates if |entitlement_period_index_| below is valid or not.
|
||||
bool is_entitlement_rotation_enabled_ = false;
|
||||
// The entitlement period index in the last received ECM.
|
||||
uint32_t entitlement_period_index_;
|
||||
|
||||
// |next_*| used to handle entitlement key rotation. They will be moved to
|
||||
// normal ones once the license switch completed.
|
||||
std::shared_ptr<CryptoSession> next_crypto_session_;
|
||||
std::unique_ptr<CasLicense> next_cas_license_;
|
||||
std::unique_ptr<CasMediaId> next_media_id_;
|
||||
}; // namespace wvcas
|
||||
|
||||
} // namespace wvcas
|
||||
|
||||
@@ -49,6 +49,8 @@ class WidevineCasSession {
|
||||
CasStatus initialize(std::shared_ptr<CryptoSession> crypto_session,
|
||||
CasEventListener* event_listener, uint32_t* session_id);
|
||||
|
||||
CasStatus resetCryptoSession(std::shared_ptr<CryptoSession> crypto_session);
|
||||
|
||||
// Process an ecm and extract the key slot data. Extracted data will be used
|
||||
// to update |current_ecm_| and |entitlement_key_id_| and |keys_|.
|
||||
// |parental_control_age| (if non-zero) must be greater or equal to the
|
||||
@@ -63,7 +65,16 @@ class WidevineCasSession {
|
||||
const char* securityLevel();
|
||||
|
||||
// Returns current ecm age restriction value.
|
||||
uint8_t GetEcmAgeRestriction() { return ecm_age_restriction_; }
|
||||
uint8_t GetEcmAgeRestriction() const { return ecm_age_restriction_; }
|
||||
// Returns the entitlement period index specified in the last received ECM.
|
||||
uint32_t GetEntitlementPeriodIndex() const {
|
||||
return entitlement_period_index_;
|
||||
}
|
||||
// Returns the entitlement rotation window left value specified in the last
|
||||
// received ECM.
|
||||
uint32_t GetEntitlementRotationWindowLeft() const {
|
||||
return entitlement_rotation_window_left_;
|
||||
}
|
||||
|
||||
WidevineCasSession(const WidevineCasSession&) = delete;
|
||||
WidevineCasSession& operator=(const WidevineCasSession&) = delete;
|
||||
@@ -74,7 +85,7 @@ class WidevineCasSession {
|
||||
|
||||
CasKeySlotData keys_; // Odd and even key slots.
|
||||
std::string entitlement_key_id_;
|
||||
std::mutex lock_;
|
||||
std::mutex crypto_lock_;
|
||||
CasEcm current_ecm_;
|
||||
uint8_t ecm_age_restriction_ = 0;
|
||||
std::shared_ptr<CryptoSession> crypto_session_;
|
||||
@@ -87,6 +98,10 @@ class WidevineCasSession {
|
||||
// Service blocking events sent in processing last ECM/EMM. Used to avoid
|
||||
// sending a same event again.
|
||||
std::vector<uint8_t> last_service_blocking_message_;
|
||||
// The entitlement period index in the last received ECM.
|
||||
uint32_t entitlement_period_index_;
|
||||
// The entitlement rotation window left in the last received ECM.
|
||||
uint32_t entitlement_rotation_window_left_;
|
||||
};
|
||||
|
||||
} // namespace wvcas
|
||||
|
||||
@@ -34,6 +34,8 @@ class WidevineCasSessionMap {
|
||||
CasSessionPtr GetSession(WvCasSessionId cas_session_id) const;
|
||||
// Remove an entry in the map.
|
||||
void RemoveSession(WvCasSessionId cas_session_id);
|
||||
// Retrieves all the session ids.
|
||||
std::vector<CasSessionPtr> GetAllSessions() const;
|
||||
|
||||
// Returns a reference to the map.
|
||||
static WidevineCasSessionMap& instance();
|
||||
|
||||
@@ -105,9 +105,11 @@ class WidevineCasPlugin : public CasPlugin, public CasEventListener {
|
||||
CasStatus HandleSetParentalControlAge(const CasData& data);
|
||||
CasStatus HandleLicenseRemoval(const CasData& license_id);
|
||||
CasStatus HandleAssignLicenseID(const CasData& license_id);
|
||||
CasStatus HandlePluginVersionQuery();
|
||||
CasStatus HandleEntitlementPeriodUpdateResponse(const CasData& response);
|
||||
|
||||
// Returns true if the device has been provisioned with a device certificate.
|
||||
bool is_provisioned() const;
|
||||
|
||||
// Event listener implementation
|
||||
void OnSessionRenewalNeeded() override;
|
||||
void OnSessionKeysChange(const KeyStatusMap& keys_status,
|
||||
@@ -123,6 +125,10 @@ class WidevineCasPlugin : public CasPlugin, public CasEventListener {
|
||||
void OnSessionServiceBlockingUpdated(
|
||||
const WvCasSessionId& sessionId,
|
||||
const CasData& service_blocking) override;
|
||||
void OnFingerprintingUpdated(const CasData& fingerprinting) override;
|
||||
void OnServiceBlockingUpdated(const CasData& service_blocking) override;
|
||||
void OnEntitlementPeriodUpdateNeeded(
|
||||
const std::string& signed_license_request) override;
|
||||
|
||||
// Choose to use |callback_| or |callback_ext_| to send back information.
|
||||
// |sessionId| is ignored if |callback_ext_| is null,
|
||||
@@ -138,7 +144,8 @@ class WidevineCasPlugin : public CasPlugin, public CasEventListener {
|
||||
// Otherwise, first CA descriptor available to the plugin
|
||||
// is used to build a PSSH, and others are discarded.
|
||||
bool is_emm_request_sent_ = false;
|
||||
std::string provision_data_;
|
||||
// This is always the serialized PSSH data.
|
||||
std::string init_data_;
|
||||
std::unique_ptr<WidevineCas> widevine_cas_api_;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user