// 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 WVCDM_CORE_POLICY_ENGINE_H_ #define WVCDM_CORE_POLICY_ENGINE_H_ #include #include #include #include "clock.h" #include "disallow_copy_and_assign.h" #include "license_key_status.h" #include "license_protocol.pb.h" #include "wv_cdm_types.h" namespace wvcdm { using video_widevine::LicenseIdentification; using video_widevine::WidevinePsshData_EntitledKey; class Clock; class CryptoSession; class PolicyTimers; class WvCdmEventListener; // This acts as an oracle that basically says "Yes(true) you may still decrypt // or no(false) you may not decrypt this data anymore." class PolicyEngine { public: PolicyEngine(CdmSessionId session_id, WvCdmEventListener* event_listener, CryptoSession* crypto_session); virtual ~PolicyEngine(); // 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); // Returns the current CdmKeyStatus for the given key, or // kKeyStatusKeyUnknown if the key is not found. This is useful for finding // out why a key is not usable. virtual CdmKeyStatus GetKeyStatus(const KeyId& key_id); // Verifies whether the policy allows use of the specified key of // a given security level for content decryption. virtual bool CanUseKeyForSecurityLevel(const KeyId& key_id); // 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(); // SetLicense is used in handling the initial license response. It stores // an exact copy of the policy information stored in the license. // License state transitions and notifications may occur if // |defer_license_state_update| is not set. If set, the license is likely // being restored and transitions and notifications will be deferred until // stored playback times are restored. virtual void SetLicense(const video_widevine::License& license, bool supports_core_messages, bool defer_license_state_update); // Used to update the currently loaded entitled content keys. virtual void SetEntitledLicenseKeys( const std::vector& entitled_keys); // SetLicenseForRelease is used when releasing a license. The keys in this // license will be ignored, and any old keys will be expired. virtual void SetLicenseForRelease(const video_widevine::License& license, bool supports_core_messages); // Call this on first decrypt to set the start of playback. virtual bool BeginDecryption(void); // Call this periodically to update the most recent playback time. virtual void DecryptionEvent(void); // 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. // License state transitions and notifications may occur if // |defer_license_state_update| is not set. If set, the license is likely // being restored and transitions and notifications will be deferred until // stored playback times are restored. virtual void UpdateLicense(const video_widevine::License& license, bool defer_license_state_update); // This method updates license state and sends appropriate notifications // to event listeners. virtual void UpdateLicenseState(int64_t current_time); // Used for notifying the Policy Engine of resolution changes virtual void NotifyResolution(uint32_t width, uint32_t height); virtual void NotifySessionExpiration(); virtual CdmResponseType Query(CdmQueryMap* query_response); virtual CdmResponseType QueryKeyAllowedUsage(const KeyId& key_id, CdmKeyAllowedUsage* key_usage); virtual const LicenseIdentification& license_id() { return license_id_; } bool GetSecondsSinceStarted(int64_t* seconds_since_started); bool GetSecondsSinceLastPlayed(int64_t* seconds_since_started); // For offline save and restore int64_t GetPlaybackStartTime(); int64_t GetLastPlaybackTime(); int64_t GetGracePeriodEndTime(); // This method will also update license state and sends appropriate // notifications to event listeners. void RestorePlaybackTimes(int64_t playback_start_time, int64_t last_playback_time, int64_t grace_period_end_time); bool IsLicenseForFuture() { return license_state_ == kLicenseStatePending; } bool HasLicenseOrRentalOrPlaybackDurationExpired(int64_t current_time); int64_t GetLicenseOrRentalOrPlaybackDurationRemaining(); bool CanRenew() const; bool IsSufficientOutputProtection(const KeyId& key_id) { return license_keys_->MeetsConstraints(key_id); } private: friend class PolicyEngineTest; friend class PolicyEngineConstraintsTest; void InitDevice(CryptoSession* crypto_session); void SetDeviceResolution(uint32_t width, uint32_t height); void CheckDeviceHdcpStatusOnTimer(int64_t current_time); void CheckDeviceHdcpStatus(); typedef enum { kLicenseStateInitial, kLicenseStatePending, // if license is issued for sometime in the future kLicenseStateCanPlay, kLicenseStateNeedRenewal, kLicenseStateWaitingLicenseUpdate, kLicenseStateExpired } LicenseState; // Notifies updates in keys information and fire OnKeysChange event if // key changes. void NotifyKeysChange(CdmKeyStatus new_status); // Notifies updates in expiry time and fire OnExpirationUpdate event if // expiry time changes. void NotifyExpirationUpdate(int64_t current_time); void UpdateRenewalRequest(int64_t current_time); int64_t GetCurrentTime(); // Test only methods // set_clock alters ownership of the passed-in pointer. void set_clock(Clock* clock); void SetSecurityLevelForTest(CdmSecurityLevel security_level); LicenseState license_state_; int64_t license_state_update_deadline_; // 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_; // to assist in clock rollback checks int64_t last_recorded_current_time_; // Used to dispatch CDM events. CdmSessionId session_id_; WvCdmEventListener* event_listener_; // Keys associated with license - holds allowed usage, usage constraints, // and current status (CdmKeyStatus) std::unique_ptr license_keys_; // This is the current policy information for this license. This gets updated // as license renewals occur. video_widevine::License::Policy policy_; // Device checks int64_t next_device_check_; uint32_t current_resolution_; CryptoSession* crypto_session_; std::unique_ptr policy_timers_; std::unique_ptr clock_; CORE_DISALLOW_COPY_AND_ASSIGN(PolicyEngine); }; } // namespace wvcdm #endif // WVCDM_CORE_POLICY_ENGINE_H_