// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine License // Agreement. #ifndef WVCDM_CORE_CDM_SESSION_H_ #define WVCDM_CORE_CDM_SESSION_H_ #include #include #include #include #include "crypto_session.h" #include "device_files.h" #include "file_store.h" #include "initialization_data.h" #include "license.h" #include "metrics_collections.h" #include "oemcrypto_adapter.h" #include "policy_engine.h" #include "timer_metric.h" #include "wv_cdm_types.h" #include "wv_class_utils.h" namespace wvcdm { class CdmClientPropertySet; class ServiceCertificate; class WvCdmEventListener; class CdmUsageTable; class SystemIdExtractor; class CdmSession { public: CdmSession() = delete; WVCDM_DISALLOW_COPY_AND_MOVE(CdmSession); // Creates a new instance of the CdmSession with the given |file_system| // and |metrics| parameters. Both parameters are owned by the caller and // must remain in scope throughout the scope of the new instance. |metrics| // must not be null. CdmSession(wvutil::FileSystem* file_system, std::shared_ptr metrics); virtual ~CdmSession(); void Close() { closed_ = true; } bool IsClosed() { return closed_; } // Initializes this instance of CdmSession with the given property set. // // |cdm_client_property_set| is caller owned, may be null, but must be in // scope as long as the session is in scope. The service certificate field is // cached at the time Init() is called. virtual CdmResponseType Init(CdmClientPropertySet* cdm_client_property_set); // Initializes this instance of CdmSession with the given parameters. // All parameters are owned by the caller. // // |cdm_client_property_set| is caller owned, may be null, but must be in // scope as long as the session is in scope. The service certificate field is // cached at the time Init() is called. // // |forced_session_id| is caller owned and may be null. // // |event_listener| is caller owned, may be null, but must be in scope as long // as the session is in scope. // // |forced_level3|_is used to specify whether the "default" security level // should always use L3 even if L1 is available. virtual CdmResponseType Init(CdmClientPropertySet* cdm_client_property_set, const CdmSessionId* forced_session_id, WvCdmEventListener* event_listener, bool forced_level3); // Restores an offline session identified by the |key_set_id| and // |license_type|. The |error_detail| will be filled with an internal error // code. The |error_detail| may be a CdmResponseType or other error code type. // It is only suitable for additional logging or debugging. virtual CdmResponseType RestoreOfflineSession(const CdmKeySetId& key_set_id, CdmLicenseType license_type, int* error_detail); // Restores an usage session from the provided |usage_data|. // The |error_detail| will be filled with an internal error code. The // |error_detail| may be a CdmResponseType or other error code type. It is // only suitable for additional logging or debugging. virtual CdmResponseType RestoreUsageSession( const DeviceFiles::CdmUsageData& usage_data, int* error_detail); virtual const CdmSessionId& session_id() { return session_id_; } virtual const CdmKeySetId& key_set_id() { return key_set_id_; } virtual CdmResponseType GenerateKeyRequest( const InitializationData& init_data, CdmLicenseType license_type, const CdmAppParameterMap& app_parameters, CdmKeyRequest* key_request); // AddKey() - Accept license response and extract key info. virtual CdmResponseType AddKey(const CdmKeyResponse& key_response); // Override the currently-installed service certificate with a new service // certificate. virtual CdmResponseType SetServiceCertificate( const std::string& service_certificate); // Query session status virtual CdmResponseType QueryStatus(CdmQueryMap* query_response); // Query license information virtual CdmResponseType QueryKeyStatus(CdmQueryMap* query_response); // Query allowed usages for key virtual CdmResponseType QueryKeyAllowedUsage(const std::string& key_id, CdmKeyAllowedUsage* key_usage); // Query OEMCrypto session ID virtual CdmResponseType QueryOemCryptoSessionId(CdmQueryMap* query_response); // Decrypt() - Accept encrypted buffer and return decrypted data. virtual CdmResponseType Decrypt(const CdmDecryptionParametersV16& parameters); // License renewal // GenerateRenewalRequest() - Construct valid renewal request for the current // session keys. virtual CdmResponseType GenerateRenewalRequest(CdmKeyRequest* key_request); // RenewKey() - Accept renewal response and update key info. virtual CdmResponseType RenewKey(const CdmKeyResponse& key_response); // License release // GenerateReleaseRequest() - Construct valid release request for the current // session keys. virtual CdmResponseType GenerateReleaseRequest(CdmKeyRequest* key_request); // ReleaseKey() - Accept response and release key. virtual CdmResponseType ReleaseKey(const CdmKeyResponse& key_response); virtual CdmResponseType DeleteUsageEntry(UsageEntryIndex entry_index); virtual bool IsKeyLoaded(const KeyId& key_id); virtual int64_t GetDurationRemaining(); // Used for notifying the Policy Engine of resolution changes virtual void NotifyResolution(uint32_t width, uint32_t height); virtual void OnTimerEvent(bool update_usage); virtual void OnKeyReleaseEvent(const CdmKeySetId& key_set_id); virtual void GetApplicationId(std::string* app_id); virtual RequestedSecurityLevel GetRequestedSecurityLevel() { return requested_security_level_; } virtual CdmSecurityLevel GetSecurityLevel() { return security_level_; } virtual CdmResponseType UpdateUsageEntryInformation(); virtual bool is_initial_usage_update() { return is_initial_usage_update_; } virtual bool is_usage_update_needed() { return is_usage_update_needed_; } virtual void reset_usage_flags() { is_initial_usage_update_ = false; is_usage_update_needed_ = false; } virtual bool is_release() { return is_release_; } virtual bool is_offline() { return is_offline_; } virtual bool is_temporary() { return is_temporary_; } virtual bool license_received() { return license_received_; } virtual bool has_provider_session_token() { return (license_parser_ && license_parser_->provider_session_token().size() > 0); } virtual bool SupportsUsageTable() const { return usage_table_ != nullptr; } // This method will remove keys by resetting crypto resources and // policy information. This renders the session mostly useless and it is // preferable to simply delete this object rather than call this method. virtual CdmResponseType RemoveKeys(); // Remove the current offline license and/or matching usage record, if any // exist. CdmResponseType RemoveLicense(); // Delete this session's associated license or usage record file. Note that, // unlike RemoveLicense(), this method ONLY affects the file system and does // not touch the usage table headers. bool DeleteLicenseFile(); // Generate unique ID for each new session. CdmSessionId GenerateSessionId(); // Generic crypto operations - provides basic crypto operations that an // application can use outside of content stream processing // Encrypts a buffer of app-level data. virtual CdmResponseType GenericEncrypt(const std::string& in_buffer, const std::string& key_id, const std::string& iv, CdmEncryptionAlgorithm algorithm, std::string* out_buffer); // Decrypts a buffer of app-level data. virtual CdmResponseType GenericDecrypt(const std::string& in_buffer, const std::string& key_id, const std::string& iv, CdmEncryptionAlgorithm algorithm, std::string* out_buffer); // Computes the signature for a message. virtual CdmResponseType GenericSign(const std::string& message, const std::string& key_id, CdmSigningAlgorithm algorithm, std::string* signature); // Verifies the signature on a buffer of app-level data. virtual CdmResponseType GenericVerify(const std::string& message, const std::string& key_id, CdmSigningAlgorithm algorithm, const std::string& signature); virtual CdmResponseType SetDecryptHash(uint32_t frame_number, const std::string& hash); virtual CdmResponseType GetDecryptHashError(std::string* hash_error_string); virtual metrics::SessionMetrics* GetMetrics() { return metrics_.get(); } virtual CdmResponseType LoadCastPrivateKey( const CryptoWrappedKey& private_key); virtual CdmResponseType GenerateRsaSignature(const std::string& message, std::string* signature, RSA_Padding_Scheme scheme); private: friend class CdmSessionTest; // Both these methods will attempt to load wrapped key material and // cache values in |drm_certificate_| and |wrapped_private_key_| // if successful. // This method will load the key from persistent storage. CdmResponseType LoadPrivateKey(); // This method will load the specified key if valid or otherwise load // the information from the legacy certificate. CdmResponseType LoadPrivateOrLegacyKey( const std::string& certificate, const CryptoWrappedKey& wrapped_private_key); CdmResponseType LoadPrivateKey(const std::string& certificate, const CryptoWrappedKey& wrapped_private_key); bool GenerateKeySetId(bool atsc_mode_enabled, CdmKeySetId* key_set_id); CdmResponseType StoreLicense(); bool StoreLicense(CdmOfflineLicenseState state, int* error_detail); bool UpdateUsageInfo(); CdmResponseType GenerateKeyRequestInternal( const InitializationData& init_data, CdmLicenseType license_type, const CdmAppParameterMap& app_parameters, CdmKeyRequest* key_request); virtual CdmResponseType AddKeyInternal(const CdmKeyResponse& key_response); void UpdateRequestLatencyTiming(CdmResponseType sts); // Checks that the usage entry in the usage table header matches the // information of the currently loaded license for this session. // Returns false if there is any unexpected mismatch of information, // true otherwise. bool VerifyOfflineUsageEntry(); bool HasRootOfTrustBeenRenewed(bool is_load); CdmResponseType ResetCryptoSession(); // These setters are for testing only. Takes ownership of the pointers. void set_license_parser(CdmLicense* license_parser); void set_crypto_session(CryptoSession* crypto_session); void set_policy_engine(PolicyEngine* policy_engine); void set_file_handle(DeviceFiles* file_handle); void set_system_id_extractor(SystemIdExtractor* extractor); // instance variables std::shared_ptr metrics_; metrics::CryptoMetrics* crypto_metrics_; metrics::Timer life_span_; metrics::Timer license_request_latency_; CdmKeyRequestType key_request_type_; bool initialized_; bool closed_; // Session closed, but final shared_ptr has not been released. CdmSessionId session_id_; wvutil::FileSystem* file_system_; std::unique_ptr license_parser_; std::unique_ptr crypto_session_; std::unique_ptr policy_engine_; std::unique_ptr file_handle_; std::unique_ptr mock_system_id_extractor_; bool license_received_; bool is_offline_; bool is_release_; bool is_temporary_; CdmSecurityLevel security_level_; RequestedSecurityLevel requested_security_level_; // If |forced_level3_|, |security_level_| and |requested_security_level_| // MUST be set to kSecurityLevelL3 and kLevel3, respectively. bool forced_level3_ = false; CdmAppParameterMap app_parameters_; bool atsc_mode_enabled_ = false; std::string drm_certificate_; CryptoWrappedKey wrapped_private_key_; // Decryption flags. // Indiates that the next call to Decrypt will be the first for this // license. bool is_initial_decryption_ = true; // Set to true if a successful call to Decrypt has occurred. Cleared // when the policy engine has been notified about successful // decryption. bool has_decrypted_since_last_report_ = false; // Set to true if the last call to Decrypt resulted in a failure. // Cleared when the call to decrypt has succeeded. bool last_decrypt_failed_ = false; // Usage related flags and data bool is_initial_usage_update_; bool is_usage_update_needed_; // Only assign |usage_table_| if capable of supporting usage // information. CdmUsageTable* usage_table_ = nullptr; UsageEntryIndex usage_entry_index_ = 0; UsageEntry usage_entry_; std::string usage_provider_session_token_; std::string exported_license_data_; // information useful for offline and usage scenarios CdmKeyMessage key_request_; CdmKeyResponse key_response_; // license type offline related information CdmInitData offline_init_data_; CdmKeyMessage offline_key_renewal_request_; CdmKeyResponse offline_key_renewal_response_; std::string offline_release_server_url_; // license type release and offline related information CdmKeySetId key_set_id_; bool has_license_been_loaded_ = false; bool has_license_been_restored_ = false; bool mock_crypto_session_in_use_ = false; bool mock_license_parser_in_use_ = false; bool mock_policy_engine_in_use_ = false; }; // class CdmSession } // namespace wvcdm #endif // WVCDM_CORE_CDM_SESSION_H_