Note that this version does not have Widevine Provisioning 4.0 support. It is only suitable for device upgrades. A new patch with provisioning 4.0 support will be made later.
211 lines
9.2 KiB
C++
211 lines
9.2 KiB
C++
// 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 <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"
|
||
|
||
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<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.
|
||
std::shared_ptr<CryptoSession> crypto_session_;
|
||
std::unique_ptr<CasLicense> cas_license_;
|
||
std::unique_ptr<wvutil::FileSystem> file_system_;
|
||
std::string device_certificate_;
|
||
std::string wrapped_rsa_key_;
|
||
CasEventListener* event_listener_ = nullptr;
|
||
std::mutex lock_;
|
||
wvutil::Timer policy_timer_;
|
||
LicenseType license_type_;
|
||
std::unique_ptr<CasMediaId> 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<WvCasSessionId, const CasEcm> 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<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
|
||
|
||
#endif // WIDEVINE_CAS_API_H
|