/* Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary source code may only be used and distributed under the Widevine Master License Agreement. */ #ifndef OEMCRYPTO_TA_OEMCRYPTO_SESSION_H_ #define OEMCRYPTO_TA_OEMCRYPTO_SESSION_H_ #include "OEMCryptoCENC.h" #include "oemcrypto_config_interface.h" #include "oemcrypto_key.h" #include "oemcrypto_nonce_table.h" /* The different states in which an OEMCrypto session can be in. */ typedef enum OEMCryptoSessionState { SESSION_OPENED = (int)0xc159acf3, SESSION_INVALID = (int)0x23a27071, SESSION_LOAD_OEM_RSA_KEY = (int)0x9d7cae94, SESSION_LOAD_DRM_RSA_KEY = (int)0xbc17f592, SESSION_DERIVED_KEYS = (int)0x6f73d57c, SESSION_DERIVED_KEYS_FROM_SESSION_KEY = (int)0xb852a5ef, SESSION_KEYS_LOADED = (int)0xce93bdc3, SESSION_DECRYPT_KEY_SELECTED = (int)0x9877e0a6, } OEMCryptoSessionState; /* The API being executed for the current session. */ typedef enum OEMCryptoSessionAPI { API_OPENSESSION = (int)0x45956770, API_CLOSESESSION = (int)0xa84dc5a7, API_GETOEMPUBLICCERTIFICATE = (int)0xe6cf7c3e, API_GENERATENONCE = (int)0xb9f80df2, API_GENERATERSASIGNATURE = (int)0x450c7dd0, API_REWRAPDEVICERSAKEY30 = (int)0x76b99787, API_LOADDEVICERSAKEY = (int)0xb0143a2e, API_DERIVEKEYSFROMSESSIONKEY = (int)0xf29462c0, API_LOADKEYS = (int)0x55c0291c, API_REFRESHKEYS = (int)0xc3f785fe, API_GENERATESIGNATURE = (int)0x0c4352f4, API_LOADENTITLEDCONTENTKEYS = (int)0x498bc417, API_SELECTKEY = (int)0xef2e58fb, API_DECRYPTCENC = (int)0xf5ad6301, API_GENERICENCRYPT = (int)0x3bd1f139, API_GENERICDECRYPT = (int)0xcfc2970a, API_GENERICSIGN = (int)0xb721196a, API_GENERICVERIFY = (int)0xe09fa38b, API_SETDECRYPTHASH = (int)0x427f7e9b, API_GETHASHERRORCODE = (int)0xde3477cc, API_QUERYKEYCONTROL = (int)0x7ab3659c, API_GENERATEDERIVEDKEYS = (int)0x59b1e187, API_REWRAPDEVICERSAKEY = (int)0x800fef5d, } OEMCryptoSessionAPI; typedef enum UsageEntryStatus { SESSION_HAS_NO_ENTRY = (int)0xacbad562, SESSION_HAS_NEW_ENTRY = (int)0x4545babc, SESSION_HAS_LOADED_ENTRY = (int)0x766bca12, SESSION_HAS_DEACTIVATED_ENTRY = (int)0xdacba37, } UsageEntryStatus; typedef struct OEMCryptoSession { OEMCrypto_SESSION session_id; OEMCryptoSessionState state; NonceTable nonce_table; CryptoKey* drm_private_key; CryptoKey* mac_key_server; CryptoKey* mac_key_client; CryptoKey* encryption_key; CryptoKey* session_key; bool refresh_valid; OEMCrypto_LicenseType license_type; uint32_t current_content_key_index; CryptoKey* content_keys[CONTENT_KEYS_PER_SESSION]; uint32_t num_content_keys; CryptoKey* entitlement_keys[ENTITLEMENT_KEYS_PER_SESSION]; uint32_t num_entitlement_keys; bool valid_srm_version; uint64_t timer_start; /* These are used when doing full decrypt path testing. */ bool compute_hash; /* True if the current frame needs a hash. */ uint32_t current_hash; /* Running CRC hash of frame. */ uint32_t given_hash; /* True CRC hash of frame. */ uint32_t current_frame_number; /* Current frame for CRC hash. */ uint32_t bad_frame_number; /* Frame number with bad hash. */ OEMCryptoResult hash_error; /* Error code for first bad frame. */ UsageEntryStatus usage_entry_status; uint32_t usage_entry_number; /* If |recent_decrypt| is true, then a usage report cannot be generated * without first updating the usage entry. It should be set to true whenever a * key is used. */ bool recent_decrypt; } OEMCryptoSession; /* Initializes session context. Returns OEMCrypto_SUCCESS. Caller retains ownership of |session| and it must not be NULL. */ OEMCryptoResult InitializeSession(OEMCryptoSession* session, uint32_t index); /* Cleans up a session declaration by freeing any used keys and clearing any state so the session could be reused in a future OpenSession call. Returns the result of freeing the keys in the session. Caller retains ownership of |session| and it must not be NULL. */ OEMCryptoResult TerminateSession(OEMCryptoSession* session); /* Asserts that the session state in |session| is set to the appropriate value that is needed to execute |api|. Returns OEMCrypto_ERROR_UNKNOWN_FAILURE on failure, and OEMCrypto_SUCCESS on success. Caller retains ownership of |session| and it must not be NULL. */ OEMCryptoResult CheckStatePreCall(OEMCryptoSession* session, OEMCryptoSessionAPI api); /* Sets the session state in |session| to the appropriate state for having just executed |api|. Returns OEMCrypto_ERROR_UNKNOWN_FAILURE on failure, and OEMCrypto_SUCCESS on success. Caller retains ownership of |session| and it must not be NULL. */ OEMCryptoResult SetStatePostCall(OEMCryptoSession* session, OEMCryptoSessionAPI api); /* Initializes the timer_start field in the |session| to the current online time. Returns the result of getting the online time. Caller retains ownership of |session| and it must not be NULL. */ OEMCryptoResult StartTimer(OEMCryptoSession* session); /* Calculates the diff of the timer_start field in |session| and the current online time and places it in |diff|. Returns the result of getting the online time or subtracting the times. Caller retains ownership of all pointers and they must not be NULL. */ OEMCryptoResult CurrentTimer(const OEMCryptoSession* session, uint64_t* diff); /* Attempts to deserialize the DRM RSA key and load it into |session|'s drm_private_key field. Returns the result of creating the private key. |rsa_key_length| must be > 0. Caller retains ownership of all pointers and they must not be NULL. */ OEMCryptoResult LoadDRMRSAKey(OEMCryptoSession* session, const uint8_t* pkcs8_rsa_key, uint32_t rsa_key_length); /* Derives mac and encryption keys from the specific key. Uses AES-128-CMAC and |mac_ and enc_key_contexts| to derive and create a mac_key_server, mac_key_client, and encryption_key for the |session|. Returns the result of the derivation if it fails or the result of key creation. All lengths must be > 0. Caller retains ownership of all pointers and they must not be NULL. */ OEMCryptoResult DeriveMacAndEncryptionKeysFromCryptoKey( OEMCryptoSession* session, const CryptoKey* master_key, const uint8_t* mac_key_context, uint32_t mac_key_context_length, const uint8_t* enc_key_context, uint32_t enc_key_context_length); OEMCryptoResult DeriveMacAndEncryptionKeysFromDeviceKey( OEMCryptoSession* session, const uint8_t* mac_key_context, uint32_t mac_key_context_length, const uint8_t* enc_key_context, uint32_t enc_key_context_length); OEMCryptoResult DeriveMacAndEncryptionKeysFromKeybox( OEMCryptoSession* session, const uint8_t* mac_key_context, uint32_t mac_key_context_length, const uint8_t* enc_key_context, uint32_t enc_key_context_length); /* Verifies |signature| of |message| with the mac_key_server stored in |session|. Returns OEMCrypto_ERROR_UNKNOWN_FAILURE if the mac_key_server is invalid, the result of signature calculation if it fails, OEMCrypto_ERROR_SIGNATURE_FAILURE if the calculated and provided signatures don't match, and OEMCrypto_SUCCESS otherwise. |message_length| must be > 0. Caller retains ownership of all pointers and they must not be NULL. */ OEMCryptoResult VerifySignatureWithMacKeyServer(OEMCryptoSession* session, const uint8_t* message, uint32_t message_length, const uint8_t* signature); /* Installs the key using the given data into the |session| depending on the license_type. Decrypts the |key_data| using the encryption_key in the session and then uses the first 128 bits of the decrypted key to decrypt |key_control|. Returns OEMCrypto_ERROR_INSUFFICIENT_RESOURCES if the session cannot hold any more keys, OEMCrypto_ERROR_INVALID_CONTEXT if the key control block is invalid, OEMCrypto_ERROR_INVALID_NONCE if nonce is required and the provided nonce is not in the session's nonce table, OEMCrypto_ERROR_UNKNOWN FAILURE for all other failures, and OEMCrypto_SUCCESS otherwise. All lengths must be > 0. Caller retains ownership of all pointers and they must not be NULL. */ OEMCryptoResult InstallKey(OEMCryptoSession* session, const uint8_t* key_id, uint32_t key_id_length, const uint8_t* key_data, uint32_t key_data_length, const uint8_t* key_data_iv, const uint8_t* key_control, const uint8_t* key_control_iv); /* Updates the mac_key_server and mac_key_client in |session|. Decrypts |enc_mac_keys| using the encryption_key and splits them into the two mac keys. Returns OEMCrypto_ERROR_UNKNOWN_FAILURE if the encryption_key is not valid and the result of creating the mac keys otherwise. Caller retains ownership of all pointers and they must not be NULL. */ OEMCryptoResult UpdateMacKeys(OEMCryptoSession* session, const uint8_t* enc_mac_keys, const uint8_t* mac_keys_iv); /* Given a |session| and either a raw or encrypted |key_control|, refreshes either the key with the matching |key_id| or all keys of the current license type. If |key_id| or |key_control_iv| are NULL, the key control is assumed to be unencrypted. If |key_id| is NULL, all keys of the current license type will have their durations updated. Returns OEMCrypto_ERROR_INVALID_CONTEXT if the key control is invalid, OEMCrypto_ERROR_INVALID_NONCE if there's no matching nonce, OEMCrypto_ERROR_NO_CONTENT_KEY if there is no key with the same key id, OEMCrypto_ERROR_UNKNOWN_FAILURE for all other failures, and OEMCrypto_SUCCESS otheriwse. Caller retains ownership of all pointers, and |session| and |key_control| must not be NULL. */ OEMCryptoResult RefreshKey(OEMCryptoSession* session, const uint8_t* key_id, uint32_t key_id_length, const uint8_t* key_control, const uint8_t* key_control_iv); /* Checks whether the current content key selected in the |session| can be used in the operation given by |use_type| and with the given |buffer_type|. Returns OEMCrypto_ERROR_UNKNOWN_FAILURE if there is no valid current content key, OEMCrypto_ERROR_INVALID_CONTEXT if if |use_type| is not allowed by the key control block or if the replay mask is set in the key control block, OEMCrypto_DECRYPT_FAILED if the |buffer_type| is not allowed on the device, OEMCrypto_ERROR_KEY_EXPIRED if the duration in the key control block has passed, OEMCrypto_ERROR_INSUFFICIENT_HDCP if the HDCP requirements are not met, OEMCrypto_ERROR_ANALOG_OUTPUT if the analog display requirements are not met, and OEMCrypto_SUCCESS otherwise. |buffer_type| is disallowed to be OEMCrypto_BufferType_Direct. Caller retains ownership of |session| and it must not be NULL. */ OEMCryptoResult CheckCurrentContentKeyUsage(const OEMCryptoSession* session, uint32_t use_type, OEMCryptoBufferType buffer_type); /* Decrypts the |cipher_data_length| bytes of given |cipher_data| and places it in |clear_data| using the |session|'s current content key, |initial_iv|, |pattern|, and potentially a |block_offset|. Returns OEMCrypto_ERROR_UNKNOWN_FAILURE if the current content key is invalid, the result of AESDecrypt or AESEncrypt if the fail, and OEMCrypto_SUCCESS otherwise. Lengths must not be 0. Caller retains ownership of all parameters and they must not be NULL. */ OEMCryptoResult DecryptCBC(const OEMCryptoSession* session, const uint8_t* initial_iv, const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data, uint32_t cipher_data_length, uint8_t* clear_data); OEMCryptoResult DecryptCTR(const OEMCryptoSession* session, const uint8_t* initial_iv, uint32_t block_offset, const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data, uint32_t cipher_data_length, uint8_t* clear_data); #endif /* OEMCRYPTO_TA_OEMCRYPTO_SESSION_H_ */