// 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_POLICY_ENGINE_H_ #define WIDEVINE_CAS_POLICY_ENGINE_H_ #include #include #include #include "cas_util.h" #include "clock.h" #include "crypto_session.h" #include "license_key_status.h" #include "license_protocol.pb.h" #include "timer.h" namespace wvcas { // This acts as an oracle that basically says "Yes(true) you may still decrypt // or no(false) you may not decrypt this data anymore." // TODO(jfore): Just pass in a function object? OnTimerEvent can be a class PolicyEngine : public wvutil::TimerHandler { typedef enum { kLicenseStateInitial, kLicenseStatePending, // if license is issued for sometime in the future kLicenseStateCanPlay, kLicenseStateNeedRenewal, kLicenseStateWaitingLicenseUpdate, kLicenseStateExpired } LicenseState; public: // The default constructor. PolicyEngine() {} virtual ~PolicyEngine() {} virtual void initialize(std::shared_ptr crypto_session, CasEventListener* event_listener) { license_keys_ = CreateLicenseKeys(); clock_ = CreateClock(); event_listener_ = event_listener; crypto_session_ = crypto_session; } // The value returned should be taken as a hint rather than an absolute // status. It is computed during the last call to either SetLicense/ // UpdateLicense/OnTimerEvent/BeginDecryption and may be out of sync // depending on the amount of time elapsed. The current decryption // status is not calculated to avoid overhead in the decryption path. virtual bool CanDecryptContent(const KeyId& key_id) const; // The value returned indicates if a license renewal is allowed under the // current policy. virtual bool CanRenew() const { return policy_.can_renew(); } // The value returned indicates if the license is persisted to non-volatile // storage for offline use. virtual bool CanPersist() const { return policy_.can_persist(); } // The value returned indicates whether or not the client id should be // included in renewal requests. virtual bool always_include_client_id() const { return policy_.always_include_client_id(); } // The value returned is the current license id. virtual const video_widevine::LicenseIdentification& license_id() const { return license_id_; } virtual const std::string& renewal_server_url() const { return policy_.renewal_server_url(); } // SetLicense is used in handling the initial license response. It stores // 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); // UpdateLicense is used in handling a license response for a renewal request. // The response may only contain any policy fields that have changed. In this // case an exact copy is not what we want to happen. We also will receive an // updated license_start_time from the server. The license will transition to // kLicenseStateCanPlay if the license permits playback. virtual void UpdateLicense(const video_widevine::License& license); // Call this on first decrypt to set the start of playback. virtual void BeginDecryption(void); // OnTimerEvent is called when a timer fires. It notifies the Policy Engine // that the timer has fired and dispatches the relevant events through // |event_listener_|. virtual void OnTimerEvent() override; // Used to update the currently loaded entitled content keys. virtual void SetEntitledLicenseKeys( const std::vector& entitled_keys); // Used to query if the current license state is expired. virtual bool IsExpired() const { return license_state_ == kLicenseStateExpired; } // for offline save and restore int64_t GetPlaybackStartTime() const { return playback_start_time_; } int64_t GetLastPlaybackTime() const { return last_playback_time_; } int64_t GetGracePeriodEndTime() const { return grace_period_end_time_; } void RestorePlaybackTimes(int64_t playback_start_time, int64_t last_playback_time, int64_t grace_period_end_time); PolicyEngine(const PolicyEngine&) = delete; PolicyEngine& operator=(const PolicyEngine&) = delete; private: // Notifies updates in keys information and fire OnKeysChange event if // key changes. void NotifyKeysChange(KeyStatus new_status); void NotifyLicenseExpired(LicenseState key_status); bool HasLicenseOrPlaybackDurationExpired(int64_t current_time); // Notifies updates in expiry time and fire OnExpirationUpdate event if // expiry time changes. void NotifyExpirationUpdate(int64_t current_time); // Notify listeners of the current renewal url. void NotifyRenewalServerUpdate(); // Guard against clock rollbacks int64_t GetCurrentTime(); LicenseState license_state_ = kLicenseStateInitial; void CheckDeviceHdcpStatus(); // 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); void CheckDeviceHdcpStatusOnTimer(int64_t current_time); 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(); } // 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. This is the hard limit that // all license types must obey at all times. int64_t GetHardLicenseExpiryTime(); bool HasRenewalDelayExpired(int64_t current_time); bool HasRenewalRetryIntervalExpired(int64_t current_time); void UpdateRenewalRequest(int64_t current_time); virtual std::unique_ptr CreateLicenseKeys(); virtual std::unique_ptr CreateClock(); // 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_ = 0; int64_t playback_start_time_ = 0; int64_t last_playback_time_ = 0; int64_t grace_period_end_time_ = 0; bool last_expiry_time_set_ = false; bool was_expired_on_load_ = false; // 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_ = 0; CasEventListener* event_listener_ = nullptr; // Keys associated with license - holds allowed usage, usage constraints, // and current status (KeyStatus) std::unique_ptr license_keys_; std::unique_ptr clock_; // to assist in clock rollback checks int64_t last_recorded_current_time_ = 0; int64_t last_expiry_time_ = 0; int64_t next_device_check_ = 0; std::shared_ptr crypto_session_; uint32_t current_resolution_ = 0; std::string renewal_server_url_; }; } // namespace wvcas #endif // WIDEVINE_CAS_POLICY_ENGINE_H_