251 lines
12 KiB
C
251 lines
12 KiB
C
/* 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_ */
|