// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine Master // License Agreement. #ifndef WIDEVINE_CAS_API_H #define WIDEVINE_CAS_API_H #include #include #include #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" namespace wvcas { // TODO(jfore): Fix the function name inconsistency in this class. These // functions were migrated from the android plugin api implementation. They // should not follow Android's style. class WidevineCas : public wvutil::TimerHandler { public: WidevineCas() {} virtual ~WidevineCas() {} virtual CasStatus initialize(CasEventListener* event_listener); // Open a session for descrambling a program, or one or more elementary // streams. virtual CasStatus openSession(WvCasSessionId* sessionId); // Close a previously opened session. virtual CasStatus closeSession(const 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(const WvCasSessionId& sessionId, const CasEcm& ecm); // Generates a device provisioning request message in |provisioning_request|. virtual CasStatus generateDeviceProvisioningRequest( std::string* provisioning_request); // Processes a |response| to provisioning request. virtual CasStatus handleProvisioningResponse(const std::string& response); // Generates an entitlement license request in |entitlement_request| for the // media described in |init_data|. virtual CasStatus generateEntitlementRequest(const std::string& init_data, std::string* entitlement_request, std::string& license_id); // Processes the entitlement |response| to a entitlement license request. // |license_id| is the id of the license installed. Can be used to select // which license to install. // |multi_content_license_info| contains the message that can be sent to the // app if the installed license is a multi content license. // |group_license_info| contains the message that can be sent to the app if // the installed license is a group license. virtual CasStatus handleEntitlementResponse( const std::string& response, std::string& license_id, std::string& multi_content_license_info, std::string& group_license_info); // Generates an entitlement license request in |entitlement_request| for the // media described in |init_data|. virtual CasStatus generateEntitlementRenewalRequest( std::string* entitlement_renewal_request); // Processes the entitlement renewal |response| to a entitlement license // request. 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; // Processes the CAS |private_data| from a CAT table. If successful a // serialized pssh data is retured in |init_data|. virtual CasStatus ProcessCAPrivateData(const CasData& private_data, std::string* init_data); // Processes the CAS |private_data| from a PMT table. If successful a // serialized pssh data is retured in |init_data|. The CA private data can be // unique to the ecm session indicated by |session_id|. virtual CasStatus ProcessSessionCAPrivateData( const WvCasSessionId& session_id, const CasData& private_data, std::string* init_data); // Returns the device unique identifier. virtual CasStatus GetUniqueID(std::string* buffer); // Set the minimum age required to process ECM. virtual CasStatus HandleSetParentalControlAge(const CasData& data); // Remove the license file given the filename user provides. virtual CasStatus RemoveLicense(const std::string& file_name); // 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; // Stops the timer thread. Called by CAS plugin destructor to avoid race. void StopTimer(); private: virtual CasStatus HandleStoredDrmCert(const std::string& certificate); 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 getCryptoSession(); virtual std::unique_ptr getCasLicense(); virtual std::unique_ptr getFileSystem(); virtual std::shared_ptr newCasSession(); virtual std::unique_ptr getEcmParser(const CasEcm& ecm) const; // Creates an EmmParser. Marked as virtual for easier unit test. virtual std::unique_ptr getEmmParser( const CasEmm& emm) const; std::vector GenerateFingerprintingEventMessage( const video_widevine::Fingerprinting& fingerprinting) const; std::vector 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. std::shared_ptr crypto_session_; std::unique_ptr cas_license_; std::unique_ptr file_system_; std::string device_certificate_; std::unique_ptr wrapped_private_key_; CasEventListener* event_listener_ = nullptr; std::mutex lock_; wvutil::Timer policy_timer_; LicenseType license_type_; std::unique_ptr media_id_; // Sometimes delays in receiving a license or the format in which the content // is encoded my result in ecms being processed before a valid license has // been loaded. In this cas |has_license_| will be false and the ecm will be // stored in |deferred_ecms_|. Once a license has been loaded, the stored ecms // are processed to set the current content keys. std::map deferred_ecms_; // The value |has_license_| will be false when the plugin is created. Once a // license is loaded, |has_license_| will be set to true. bool has_license_ = false; // 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 requested_license_id helps to indicate which license file current // content will use if multiple licenses exist. 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 last_fingerprinting_events_; // Service blocking events sent in processing last ECM/EMM. Used to avoid // sending a same event again. std::set 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 next_crypto_session_; std::unique_ptr next_cas_license_; std::unique_ptr next_media_id_; }; // namespace wvcas } // namespace wvcas #endif // WIDEVINE_CAS_API_H