// 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. // // Reference implementation of OEMCrypto APIs // #ifndef REF_OEMCRYPTO_SESSION_H_ #define REF_OEMCRYPTO_SESSION_H_ #include #include #include #include #include #include "OEMCryptoCENC.h" #include "odk_structs.h" #include "oemcrypto_auth_ref.h" #include "oemcrypto_key_ref.h" #include "oemcrypto_rsa_key.h" #include "oemcrypto_session_key_table.h" #include "oemcrypto_types.h" #include "oemcrypto_usage_table_ref.h" namespace wvoec_ref { class CryptoEngine; typedef uint32_t SessionId; enum SRMVersionStatus { NoSRMVersion, ValidSRMVersion, InvalidSRMVersion }; // TODO(jfore): Is there a better name? class SessionContextKeys { public: virtual OEMCrypto_LicenseType type() = 0; virtual size_t size() = 0; virtual bool Insert(const KeyId& key_id, const Key& key_data) = 0; virtual Key* Find(const KeyId& key_id) = 0; virtual Key* FirstKey() = 0; virtual void Remove(const KeyId& key_id) = 0; virtual void UpdateDuration(const KeyControlBlock& control) = 0; // Methods supported exclusively for entitlement keys. Returns false if // entitlement keys are not found or not supported by the current key table. // It is the caller's responsibility to check the context. virtual bool SetContentKey(const KeyId& entitlement_id, const KeyId& content_key_id, const std::vector& content_key) = 0; virtual EntitlementKey* GetEntitlementKey(const KeyId& entitlement_id) = 0; virtual ~SessionContextKeys() {} protected: SessionContextKeys() {} private: CORE_DISALLOW_COPY_AND_ASSIGN(SessionContextKeys); }; class SessionContext { public: SessionContext(CryptoEngine* ce, SessionId sid); SessionContext(CryptoEngine* ce, SessionId sid, std::shared_ptr&& rsa_key); SessionContext() = delete; virtual ~SessionContext(); bool isValid() const { return valid_; } virtual OEMCryptoResult DeriveKeys(const std::vector& master_key, const std::vector& mac_context, const std::vector& enc_context); virtual OEMCryptoResult RSADeriveKeys( const std::vector& enc_session_key, const std::vector& mac_context, const std::vector& enc_context); virtual OEMCryptoResult LoadOemPrivateKey(); virtual OEMCryptoResult PrepAndSignLicenseRequest(uint8_t* message, size_t message_length, size_t* core_message_length, uint8_t* signature, size_t* signature_length); virtual OEMCryptoResult PrepAndSignRenewalRequest(uint8_t* message, size_t message_length, size_t* core_message_length, uint8_t* signature, size_t* signature_length); virtual OEMCryptoResult PrepAndSignProvisioningRequest( uint8_t* message, size_t message_length, size_t* core_message_length, uint8_t* signature, size_t* signature_length); // Restricted to CAST receivers using PKCS1 block padding only. virtual OEMCryptoResult GenerateRSASignature( const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length, RSA_Padding_Scheme padding_scheme); virtual bool ValidateMessage(const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length); OEMCryptoResult DecryptSamples( const OEMCrypto_SampleDescription* samples, size_t samples_length, const OEMCrypto_CENCEncryptPatternDesc* pattern); OEMCryptoResult Generic_Encrypt(const uint8_t* in_buffer, size_t buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer); OEMCryptoResult Generic_Decrypt(const uint8_t* in_buffer, size_t buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer); OEMCryptoResult Generic_Sign(const uint8_t* in_buffer, size_t buffer_length, OEMCrypto_Algorithm algorithm, uint8_t* signature, size_t* signature_length); OEMCryptoResult Generic_Verify(const uint8_t* in_buffer, size_t buffer_length, OEMCrypto_Algorithm algorithm, const uint8_t* signature, size_t signature_length); virtual OEMCryptoResult LoadLicense(const uint8_t* message, size_t message_length, size_t core_message_length, const uint8_t* signature, size_t signature_length); virtual OEMCryptoResult LoadKeys( const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length, OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys, size_t num_keys, const OEMCrypto_KeyObject* key_array, OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data, OEMCrypto_LicenseType license_type); virtual OEMCryptoResult LoadKeysNoSignature( const uint8_t* message, size_t message_length, OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys, size_t num_keys, const OEMCrypto_KeyObject* key_array, OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data, OEMCrypto_LicenseType license_type); virtual OEMCryptoResult LoadEntitledContentKeys( const uint8_t* message, size_t message_length, size_t key_array_length, const OEMCrypto_EntitledContentKeyObject* key_array); virtual OEMCryptoResult InstallKey( const KeyId& key_id, const std::vector& key_data, const std::vector& key_data_iv, const std::vector& key_control, const std::vector& key_control_iv); bool InstallRSAEncryptedKey(const std::vector& enc_encryption_key); bool DecryptRSAKey(const uint8_t* enc_rsa_key, size_t enc_rsa_key_length, const uint8_t* wrapped_rsa_key_iv, uint8_t* pkcs8_rsa_key); bool EncryptRSAKey(const uint8_t* pkcs8_rsa_key, size_t enc_rsa_key_length, const uint8_t* enc_rsa_key_iv, uint8_t* enc_rsa_key); bool LoadRsaDrmKey(const uint8_t* pkcs8_rsa_key, size_t rsa_key_length); virtual OEMCryptoResult LoadRenewal(const uint8_t* message, size_t message_length, size_t core_message_length, const uint8_t* signature, size_t signature_length); virtual OEMCryptoResult RefreshKey( const KeyId& key_id, const std::vector& key_control, const std::vector& key_control_iv); virtual bool UpdateMacKeys(const std::vector& mac_keys, const std::vector& iv); virtual bool QueryKeyControlBlock(const KeyId& key_id, uint32_t* data); virtual OEMCryptoResult SelectContentKey(const KeyId& key_id, OEMCryptoCipherMode cipher_mode); virtual OEMCryptoResult SetDecryptHash(uint32_t frame_number, const uint8_t* hash, size_t hash_length); virtual OEMCryptoResult GetHashErrorCode(uint32_t* failed_frame_number); const Key* current_content_key(void) { return current_content_key_; } void set_mac_key_server(const std::vector& mac_key_server) { mac_key_server_ = mac_key_server; } const std::vector& mac_key_server() { return mac_key_server_; } void set_mac_key_client(const std::vector& mac_key_client) { mac_key_client_ = mac_key_client; } const std::vector& mac_key_client() { return mac_key_client_; } void set_encryption_key(const std::vector& enc_key) { encryption_key_ = enc_key; } const std::vector& encryption_key() { return encryption_key_; } // Return true if nonce was set. bool set_nonce(uint32_t nonce); uint32_t nonce() const { return nonce_values_.nonce; } ODK_NonceValues& nonce_values() { return nonce_values_; } bool CheckNonce(uint32_t nonce) const { return nonce != 0 && nonce == nonce_values_.nonce; }; virtual OEMCryptoResult CreateNewUsageEntry(uint32_t* usage_entry_number); virtual OEMCryptoResult LoadUsageEntry(uint32_t index, const std::vector& buffer); virtual OEMCryptoResult UpdateUsageEntry(uint8_t* header_buffer, size_t* header_buffer_length, uint8_t* entry_buffer, size_t* entry_buffer_length); virtual OEMCryptoResult DeactivateUsageEntry(const std::vector& pst); virtual OEMCryptoResult ReportUsage(const std::vector& pst, uint8_t* buffer, size_t* buffer_length); OEMCryptoResult MoveEntry(uint32_t new_index); bool usage_entry_present() const { return usage_entry_ != nullptr; } protected: // Signature size of the currently loaded private key. size_t CertSignatureSize() const; // Signature size when using a keybox or OEM Cert's private key. size_t ROTSignatureSize() const; virtual OEMCryptoResult GenerateCertSignature(const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length); virtual OEMCryptoResult GenerateSignature(const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length); bool DeriveKey(const std::vector& key, const std::vector& context, int counter, std::vector* out); bool DecryptMessage(const std::vector& key, const std::vector& iv, const std::vector& message, std::vector* decrypted, uint32_t key_size); // AES key size, in bits. // Either verify the nonce or usage entry, as required by the key control // block. OEMCryptoResult CheckNonceOrEntry(const KeyControlBlock& key_control_block); // If there is a usage entry, check that it is not inactive. // It also updates the status of the entry if needed. bool CheckUsageEntry(); // Check that the usage entry status is valid for online use. OEMCryptoResult CheckStatusOnline(uint32_t nonce, uint32_t control); // Check that the usage entry status is valid for offline use. OEMCryptoResult CheckStatusOffline(uint32_t nonce, uint32_t control); OEMCryptoResult DecryptSubsample( const OEMCrypto_SubSampleDescription& subsample, const uint8_t* cipher_data, uint8_t* clear_data, OEMCryptoBufferType buffer_type, const uint8_t (&iv)[wvoec::KEY_IV_SIZE], const OEMCrypto_CENCEncryptPatternDesc* pattern); OEMCryptoResult ChooseDecrypt(const uint8_t* iv, size_t block_offset, const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data, size_t cipher_data_length, uint8_t* clear_data, OEMCryptoBufferType buffer_type); OEMCryptoResult PatternDecryptCBC( const uint8_t* key, const uint8_t* iv, const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data, size_t cipher_data_length, uint8_t* clear_data); OEMCryptoResult DecryptCTR(const uint8_t* key_u8, const uint8_t* iv, size_t block_offset, const uint8_t* cipher_data, size_t cipher_data_length, uint8_t* clear_data); // Checks if the key is allowed for the specified type. If there is a usage // entry, it also checks the usage entry. OEMCryptoResult CheckKeyUse(const std::string& log_string, uint32_t use_type, OEMCryptoBufferType buffer_type); bool valid_ = false; CryptoEngine* ce_ = nullptr; SessionId id_; // Message keys. std::shared_ptr rsa_key_; std::vector mac_key_server_; std::vector mac_key_client_; std::vector encryption_key_; std::vector session_key_; ODK_NonceValues nonce_values_; uint8_t license_request_hash_[ODK_SHA256_HASH_SIZE]; // Content/entitlement keys. const Key* current_content_key_ = nullptr; std::unique_ptr session_keys_; bool decrypt_started_ = false; // If the license has been used in this session. ODK_TimerLimits timer_limits_; ODK_ClockValues clock_values_; std::unique_ptr usage_entry_; SRMVersionStatus srm_requirements_status_ = NoSRMVersion; enum UsageEntryStatus { kNoUsageEntry, // No entry loaded for this session. kUsageEntryNew, // After entry was created. kUsageEntryLoaded, // After loading entry or loading keys. }; UsageEntryStatus usage_entry_status_ = kNoUsageEntry; // These are used when doing full decrypt path testing. bool compute_hash_ = false; // True if the current frame needs a hash. uint32_t current_hash_ = 0; // Running CRC hash of frame. uint32_t given_hash_ = 0; // True CRC hash of frame. uint32_t current_frame_number_ = 0; // Current frame for CRC hash. uint32_t bad_frame_number_ = 0; // Frame number with bad hash. OEMCryptoResult hash_error_ = OEMCrypto_SUCCESS; // Error code for first bad frame. // The bare minimum state machine is to only call each of these function // categories at most once. bool state_nonce_created_ = false; bool state_request_signed_ = false; bool state_response_loaded_ = false; CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext); }; } // namespace wvoec_ref #endif // REF_OEMCRYPTO_SESSION_H_