Initial LoadRenewal unit tests.
This commit is contained in:
@@ -23,84 +23,14 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "OEMCryptoCENCCommon.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef uint32_t OEMCrypto_SESSION;
|
||||
|
||||
// clang-format off
|
||||
typedef enum OEMCryptoResult {
|
||||
OEMCrypto_SUCCESS = 0,
|
||||
OEMCrypto_ERROR_INIT_FAILED = 1,
|
||||
OEMCrypto_ERROR_TERMINATE_FAILED = 2,
|
||||
OEMCrypto_ERROR_OPEN_FAILURE = 3,
|
||||
OEMCrypto_ERROR_CLOSE_FAILURE = 4,
|
||||
OEMCrypto_ERROR_ENTER_SECURE_PLAYBACK_FAILED = 5, // deprecated
|
||||
OEMCrypto_ERROR_EXIT_SECURE_PLAYBACK_FAILED = 6, // deprecated
|
||||
OEMCrypto_ERROR_SHORT_BUFFER = 7,
|
||||
OEMCrypto_ERROR_NO_DEVICE_KEY = 8, // no keybox device key.
|
||||
OEMCrypto_ERROR_NO_ASSET_KEY = 9,
|
||||
OEMCrypto_ERROR_KEYBOX_INVALID = 10,
|
||||
OEMCrypto_ERROR_NO_KEYDATA = 11,
|
||||
OEMCrypto_ERROR_NO_CW = 12,
|
||||
OEMCrypto_ERROR_DECRYPT_FAILED = 13,
|
||||
OEMCrypto_ERROR_WRITE_KEYBOX = 14,
|
||||
OEMCrypto_ERROR_WRAP_KEYBOX = 15,
|
||||
OEMCrypto_ERROR_BAD_MAGIC = 16,
|
||||
OEMCrypto_ERROR_BAD_CRC = 17,
|
||||
OEMCrypto_ERROR_NO_DEVICEID = 18,
|
||||
OEMCrypto_ERROR_RNG_FAILED = 19,
|
||||
OEMCrypto_ERROR_RNG_NOT_SUPPORTED = 20,
|
||||
OEMCrypto_ERROR_SETUP = 21,
|
||||
OEMCrypto_ERROR_OPEN_SESSION_FAILED = 22,
|
||||
OEMCrypto_ERROR_CLOSE_SESSION_FAILED = 23,
|
||||
OEMCrypto_ERROR_INVALID_SESSION = 24,
|
||||
OEMCrypto_ERROR_NOT_IMPLEMENTED = 25,
|
||||
OEMCrypto_ERROR_NO_CONTENT_KEY = 26,
|
||||
OEMCrypto_ERROR_CONTROL_INVALID = 27,
|
||||
OEMCrypto_ERROR_UNKNOWN_FAILURE = 28,
|
||||
OEMCrypto_ERROR_INVALID_CONTEXT = 29,
|
||||
OEMCrypto_ERROR_SIGNATURE_FAILURE = 30,
|
||||
OEMCrypto_ERROR_TOO_MANY_SESSIONS = 31,
|
||||
OEMCrypto_ERROR_INVALID_NONCE = 32,
|
||||
OEMCrypto_ERROR_TOO_MANY_KEYS = 33,
|
||||
OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED = 34,
|
||||
OEMCrypto_ERROR_INVALID_RSA_KEY = 35,
|
||||
OEMCrypto_ERROR_KEY_EXPIRED = 36,
|
||||
OEMCrypto_ERROR_INSUFFICIENT_RESOURCES = 37,
|
||||
OEMCrypto_ERROR_INSUFFICIENT_HDCP = 38,
|
||||
OEMCrypto_ERROR_BUFFER_TOO_LARGE = 39,
|
||||
OEMCrypto_WARNING_GENERATION_SKEW = 40, // Warning, not an error.
|
||||
OEMCrypto_ERROR_GENERATION_SKEW = 41,
|
||||
OEMCrypto_LOCAL_DISPLAY_ONLY = 42, // Info, not an error.
|
||||
OEMCrypto_ERROR_ANALOG_OUTPUT = 43,
|
||||
OEMCrypto_ERROR_WRONG_PST = 44,
|
||||
OEMCrypto_ERROR_WRONG_KEYS = 45,
|
||||
OEMCrypto_ERROR_MISSING_MASTER = 46,
|
||||
OEMCrypto_ERROR_LICENSE_INACTIVE = 47,
|
||||
OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE = 48,
|
||||
OEMCrypto_ERROR_ENTRY_IN_USE = 49,
|
||||
OEMCrypto_ERROR_USAGE_TABLE_UNRECOVERABLE = 50, // Reserved. Do not use.
|
||||
OEMCrypto_KEY_NOT_LOADED = 51, // obsolete. use error 26.
|
||||
OEMCrypto_KEY_NOT_ENTITLED = 52,
|
||||
OEMCrypto_ERROR_BAD_HASH = 53,
|
||||
OEMCrypto_ERROR_OUTPUT_TOO_LARGE = 54,
|
||||
OEMCrypto_ERROR_SESSION_LOST_STATE = 55,
|
||||
OEMCrypto_ERROR_SYSTEM_INVALIDATED = 56,
|
||||
OEMCrypto_ERROR_LICENSE_RELOAD = 57,
|
||||
OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES = 58,
|
||||
OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION = 59,
|
||||
/* ODK return values */
|
||||
ODK_ERROR_BASE = 1000,
|
||||
ODK_ERROR_CORE_MESSAGE = ODK_ERROR_BASE,
|
||||
ODK_SET_TIMER = ODK_ERROR_BASE + 1,
|
||||
ODK_DISABLE_TIMER = ODK_ERROR_BASE + 2,
|
||||
ODK_TIMER_EXPIRED = ODK_ERROR_BASE + 3,
|
||||
ODK_UNSUPPORTED_API = ODK_ERROR_BASE + 4,
|
||||
} OEMCryptoResult;
|
||||
// clang-format on
|
||||
|
||||
/*
|
||||
* The memory referenced by OEMCrypto_SharedMemory* is safe to be placed in
|
||||
* shared memory. The only data that should be placed into shared
|
||||
@@ -208,7 +138,7 @@ typedef struct {
|
||||
* This struct changed in API version 16.
|
||||
*/
|
||||
typedef struct {
|
||||
OEMCrypto_SharedMemory* input_data; // source for encrypted data.
|
||||
const OEMCrypto_SharedMemory* input_data; // source for encrypted data.
|
||||
size_t input_data_length; // length of encrypted data.
|
||||
OEMCrypto_DestBufferDesc output_descriptor; // destination for clear data.
|
||||
} OEMCrypto_InputOutputPair;
|
||||
@@ -266,12 +196,12 @@ typedef struct {
|
||||
* subsamples parameter.
|
||||
*
|
||||
* Version:
|
||||
* This method changed in API version 16.
|
||||
* This struct changed in API version 16.
|
||||
*/
|
||||
typedef struct {
|
||||
OEMCrypto_InputOutputPair buffers; // The source and destination buffers.
|
||||
uint8_t iv[16]; // The IV for the initial subsample.
|
||||
OEMCrypto_SubSampleDescription* subsamples; // subsamples array.
|
||||
const OEMCrypto_SubSampleDescription* subsamples; // subsamples array.
|
||||
size_t subsamples_length; // the number of subsamples in the sample.
|
||||
} OEMCrypto_SampleDescription;
|
||||
|
||||
@@ -309,48 +239,6 @@ typedef enum OEMCrypto_LicenseType {
|
||||
OEMCrypto_EntitlementLicense = 1
|
||||
} OEMCrypto_LicenseType;
|
||||
|
||||
/*
|
||||
* OEMCrypto_Substring
|
||||
*
|
||||
* Used to indicate a substring of a signed message in OEMCrypto_LoadKeys and
|
||||
* other functions which must verify that a parameter is contained within a
|
||||
* signed message.
|
||||
*/
|
||||
typedef struct {
|
||||
size_t offset;
|
||||
size_t length;
|
||||
} OEMCrypto_Substring;
|
||||
|
||||
/*
|
||||
* OEMCrypto_KeyObject
|
||||
* Points to the relevant fields for a content key. The fields are extracted
|
||||
* from the License Response message offered to OEMCrypto_LoadKeys(). Each
|
||||
* field points to one of the components of the key. Key data, key control,
|
||||
* and both IV fields are 128 bits (16 bytes):
|
||||
* key_id - the unique id of this key.
|
||||
* key_id_length - the size of key_id. OEMCrypto may assume this is at
|
||||
* most 16. However, OEMCrypto shall correctly handle key id lengths
|
||||
* from 1 to 16 bytes.
|
||||
* key_data_iv - the IV for performing AES-128-CBC decryption of the
|
||||
* key_data field.
|
||||
* key_data - the key data. It is encrypted (AES-128-CBC) with the
|
||||
* session's derived encrypt key and the key_data_iv.
|
||||
* key_control_iv - the IV for performing AES-128-CBC decryption of the
|
||||
* key_control field.
|
||||
* key_control - the key control block. It is encrypted (AES-128-CBC) with
|
||||
* the content key from the key_data field.
|
||||
*
|
||||
* The memory for the OEMCrypto_KeyObject fields is allocated and freed
|
||||
* by the caller of OEMCrypto_LoadKeys().
|
||||
*/
|
||||
typedef struct {
|
||||
OEMCrypto_Substring key_id;
|
||||
OEMCrypto_Substring key_data_iv;
|
||||
OEMCrypto_Substring key_data;
|
||||
OEMCrypto_Substring key_control_iv;
|
||||
OEMCrypto_Substring key_control;
|
||||
} OEMCrypto_KeyObject;
|
||||
|
||||
/*
|
||||
* OEMCrypto_EntitledContentKeyObject
|
||||
* Contains encrypted content key data for loading into the sessions keytable.
|
||||
@@ -371,6 +259,32 @@ typedef struct {
|
||||
OEMCrypto_Substring content_key_data;
|
||||
} OEMCrypto_EntitledContentKeyObject;
|
||||
|
||||
/*
|
||||
* OEMCrypto_KeyRefreshObject
|
||||
* This structure is being deprecated. It is only used for legacy licenses.
|
||||
* Points to the relevant fields for renewing a content key. The fields are
|
||||
* extracted from the License Renewal Response message offered to
|
||||
* OEMCrypto_RefreshKeys(). Each field points to one of the components of
|
||||
* the key.
|
||||
* key_id - the unique id of this key.
|
||||
* key_control_iv - the IV for performing AES-128-CBC decryption of the
|
||||
* key_control field. 16 bytes.
|
||||
* key_control - the key control block. It is encrypted (AES-128-CBC) with
|
||||
* the content key from the key_data field. 16 bytes.
|
||||
*
|
||||
* The key_data is unchanged from the original OEMCrypto_LoadKeys() call. Some
|
||||
* Key Control Block fields, especially those related to key lifetime, may
|
||||
* change.
|
||||
*
|
||||
* The memory for the OEMCrypto_KeyRefreshObject fields is allocated and freed
|
||||
* by the caller of OEMCrypto_RefreshKeys().
|
||||
*/
|
||||
typedef struct {
|
||||
OEMCrypto_Substring key_id;
|
||||
OEMCrypto_Substring key_control_iv;
|
||||
OEMCrypto_Substring key_control;
|
||||
} OEMCrypto_KeyRefreshObject;
|
||||
|
||||
/*
|
||||
* OEMCrypto_Algorithm
|
||||
* This is a list of valid algorithms for OEMCrypto_Generic_* functions.
|
||||
@@ -381,18 +295,6 @@ typedef enum OEMCrypto_Algorithm {
|
||||
OEMCrypto_HMAC_SHA256 = 1,
|
||||
} OEMCrypto_Algorithm;
|
||||
|
||||
/*
|
||||
* OEMCrypto_Usage_Entry_Status.
|
||||
* Valid values for status in the usage table.
|
||||
*/
|
||||
typedef enum OEMCrypto_Usage_Entry_Status {
|
||||
kUnused = 0,
|
||||
kActive = 1,
|
||||
kInactive = 2, // Deprecated. Used kInactiveUsed or kInactiveUnused.
|
||||
kInactiveUsed = 3,
|
||||
kInactiveUnused = 4,
|
||||
} OEMCrypto_Usage_Entry_Status;
|
||||
|
||||
/*
|
||||
* OEMCrypto_PST_Report is used to report an entry from the Usage Table.
|
||||
*
|
||||
@@ -456,7 +358,7 @@ typedef enum OEMCrypto_ProvisioningMethod {
|
||||
OEMCrypto_OEMCertificate = 3 // Device has factory installed OEM certificate.
|
||||
} OEMCrypto_ProvisioningMethod;
|
||||
|
||||
/* Private key type used in OEMCrypto_LoadDevicePrivateKey. */
|
||||
/* Private key type used in OEMCrypto_LoadDRMPrivateKey. */
|
||||
typedef enum OEMCrypto_PrivateKeyType {
|
||||
OEMCrypto_RSA_Private_Key,
|
||||
OEMCrypto_ECC_Private_Key,
|
||||
@@ -596,7 +498,7 @@ typedef enum OEMCrypto_PrivateKeyType {
|
||||
#define OEMCrypto_LoadOEMPrivateKey _oecc103
|
||||
#define OEMCrypto_GetOEMPublicCertificate _oecc104
|
||||
#define OEMCrypto_DecryptCENC _oecc105
|
||||
#define OEMCrypto_LoadDevicePrivateKey _oecc107
|
||||
#define OEMCrypto_LoadDRMPrivateKey _oecc107
|
||||
// clang-format on
|
||||
|
||||
/*
|
||||
@@ -801,8 +703,8 @@ OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session);
|
||||
* OEMCrypto_ERROR_SYSTEM_INVALIDATED
|
||||
*
|
||||
* Buffer Sizes:
|
||||
* OEMCrypto shall support mac_key_context and enc_key_context sizes of at
|
||||
* least 8 KiB.
|
||||
* OEMCrypto shall support mac_key_context and enc_key_context sizes as
|
||||
* described in the section OEMCrypto_ResourceRatingTier.
|
||||
* OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffers are
|
||||
* too large.
|
||||
*
|
||||
@@ -845,7 +747,7 @@ OEMCryptoResult OEMCrypto_GenerateDerivedKeys(
|
||||
* Elliptic Curve Support" for details.
|
||||
*
|
||||
* Once the enc_key and mac_keys have been generated, all calls to LoadKeys
|
||||
* and RefreshKeys proceed in the same manner for license requests using RSA
|
||||
* or LoadLicense proceed in the same manner for license requests using RSA
|
||||
* or using a Widevine keybox token.
|
||||
*
|
||||
* Verification:
|
||||
@@ -887,8 +789,8 @@ OEMCryptoResult OEMCrypto_GenerateDerivedKeys(
|
||||
* OEMCrypto_ERROR_SYSTEM_INVALIDATED
|
||||
*
|
||||
* Buffer Sizes:
|
||||
* OEMCrypto shall support mac_key_context and enc_key_context sizes of at
|
||||
* least 8 KiB.
|
||||
* OEMCrypto shall support mac_key_context and enc_key_context sizes as
|
||||
* described in the section OEMCrypto_ResourceRatingTier.
|
||||
* OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffers are
|
||||
* too large.
|
||||
*
|
||||
@@ -919,12 +821,12 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(
|
||||
*
|
||||
* Because the nonce will be used to prevent replay attacks, it is desirable
|
||||
* that a rogue application cannot rapidly call this function until a
|
||||
* repeated nonce is created randomly. With this in mind, if more than 20
|
||||
* nonces are requested within one second, OEMCrypto will return an error
|
||||
* after the 20th and not generate any more nonces for the rest of the
|
||||
* second. After an error, if the application waits at least one second
|
||||
* before requesting more nonces, then OEMCrypto will reset the error
|
||||
* condition and generate valid nonces again.
|
||||
* repeated nonce is created randomly. This is called a nonce flood. With
|
||||
* this in mind, if more than 200 nonces are requested within one second,
|
||||
* OEMCrypto will return an error after the 200th and not generate any more
|
||||
* nonces for the rest of the second. After an error, if the application
|
||||
* waits at least one second before requesting more nonces, then OEMCrypto
|
||||
* will reset the error condition and generate valid nonces again.
|
||||
*
|
||||
* The nonce should be stored in the sessions ODK_NonceValue field by calling
|
||||
* the function ODK_SetNonceValue(&nonce_values, nonce). The ODK functions
|
||||
@@ -1017,7 +919,8 @@ OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session,
|
||||
* OEMCrypto_ERROR_SYSTEM_INVALIDATED
|
||||
*
|
||||
* Buffer Sizes:
|
||||
* OEMCrypto shall support message sizes of at least 8 KiB.
|
||||
* OEMCrypto shall support message sizes as described in the section
|
||||
* OEMCrypto_ResourceRatingTier.
|
||||
* OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is
|
||||
* larger than the supported size.
|
||||
*
|
||||
@@ -1055,8 +958,8 @@ OEMCryptoResult OEMCrypto_PrepAndSignLicenseRequest(
|
||||
*
|
||||
* If nonce_values.api_level is 15, then OEMCrypto shall compute the
|
||||
* signature of the message body using the session's client renewal mac key.
|
||||
* The entire message is the buffer starting at message+core_message_size
|
||||
* with length message_length-core_message_size.
|
||||
* The message body is the buffer starting at message+core_message_size with
|
||||
* length message_length-core_message_size.
|
||||
*
|
||||
* This function generates a HMAC-SHA256 signature using the mac_key[client]
|
||||
* for license request signing under the license server protocol for CENC.
|
||||
@@ -1100,7 +1003,8 @@ OEMCryptoResult OEMCrypto_PrepAndSignLicenseRequest(
|
||||
* OEMCrypto_ERROR_SYSTEM_INVALIDATED
|
||||
*
|
||||
* Buffer Sizes:
|
||||
* OEMCrypto shall support message sizes of at least 8 KiB.
|
||||
* OEMCrypto shall support message sizes as described in the section
|
||||
* OEMCrypto_ResourceRatingTier.
|
||||
* OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is
|
||||
* larger than the supported size.
|
||||
*
|
||||
@@ -1136,7 +1040,7 @@ OEMCryptoResult OEMCrypto_PrepAndSignRenewalRequest(
|
||||
* For a device that has an OEM Certificate, i.e. Provisioning 3.0, OEMCrypto
|
||||
* will sign the response with the private key associated with the OEM
|
||||
* Certificate. The key shall have been loaded by a previous call to
|
||||
* OEMCrypto_LoadPrivateDRMKey.
|
||||
* OEMCrypto_LoadDRMPrivateKey.
|
||||
*
|
||||
* Refer to the Signing Messages Sent to a Server section above for more
|
||||
* details.
|
||||
@@ -1168,7 +1072,8 @@ OEMCryptoResult OEMCrypto_PrepAndSignRenewalRequest(
|
||||
* OEMCrypto_ERROR_SYSTEM_INVALIDATED
|
||||
*
|
||||
* Buffer Sizes:
|
||||
* OEMCrypto shall support message sizes of at least 8 KiB.
|
||||
* OEMCrypto shall support message sizes as described in the section
|
||||
* OEMCrypto_ResourceRatingTier.
|
||||
* OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is
|
||||
* larger than the supported size.
|
||||
*
|
||||
@@ -1251,9 +1156,7 @@ OEMCryptoResult OEMCrypto_LoadSRM(const uint8_t* buffer, size_t buffer_length);
|
||||
* The new mac_keys replaces the current mac_keys for future calls to
|
||||
* OEMCrypto_RefreshKeys(). The first 256 bits of the mac_keys become the
|
||||
* mac_key[server] and the following 256 bits of the mac_keys become the
|
||||
* mac_key[client]. If enc_mac_keys is null, then there will not be a call to
|
||||
* OEMCrypto_RefreshKeys for this session and the current mac_keys should
|
||||
* remain unchanged.
|
||||
* mac_key[client].
|
||||
*
|
||||
* The mac_key and encrypt_key were generated and stored by the previous call
|
||||
* to OEMCrypto_GenerateDerivedKeys() or
|
||||
@@ -1453,7 +1356,8 @@ OEMCryptoResult OEMCrypto_LoadSRM(const uint8_t* buffer, size_t buffer_length);
|
||||
* OEMCrypto_ERROR_LICENSE_RELOAD
|
||||
*
|
||||
* Buffer Sizes:
|
||||
* OEMCrypto shall support message sizes of at least 8 KiB.
|
||||
* OEMCrypto shall support message sizes as described in the section
|
||||
* OEMCrypto_ResourceRatingTier.
|
||||
* OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is
|
||||
* larger than the supported size.
|
||||
*
|
||||
@@ -1704,7 +1608,8 @@ OEMCryptoResult OEMCrypto_LoadKeys(
|
||||
* OEMCrypto_ERROR_LICENSE_RELOAD
|
||||
*
|
||||
* Buffer Sizes:
|
||||
* OEMCrypto shall support message sizes of at least 8 KiB.
|
||||
* OEMCrypto shall support message sizes as described in the section
|
||||
* OEMCrypto_ResourceRatingTier.
|
||||
* OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is
|
||||
* larger than the supported size.
|
||||
*
|
||||
@@ -1791,6 +1696,84 @@ OEMCryptoResult OEMCrypto_LoadEntitledContentKeys(
|
||||
size_t key_array_length,
|
||||
const OEMCrypto_EntitledContentKeyObject* key_array);
|
||||
|
||||
/*
|
||||
* OEMCrypto_RefreshKeys
|
||||
*
|
||||
* Description:
|
||||
* Updates the license clock values to allow playback to continue. This
|
||||
* function is being deprecated and is only used for version v15 licenses --
|
||||
* i.e. offline license saved before an update or licenses from a server that
|
||||
* has not update to the v16 license server SDK.
|
||||
*
|
||||
* OEMCrypto shall compute the signature of the message using
|
||||
* mac_key[server], and shall verify the computed signature matches the
|
||||
* signature passed in. If not, return OEMCrypto_ERROR_SIGNATURE_FAILURE. The
|
||||
* signature verification shall use a constant-time algorithm (a signature
|
||||
* mismatch will always take the same time as a successful comparison).
|
||||
*
|
||||
* The function ODK_RefreshV15Values shall be called to update the clock
|
||||
* values. See the document "Widevine Core Message Serialization" for the
|
||||
* documentation of the ODK library functions.
|
||||
*
|
||||
* If ODK_RefreshV15Values returns
|
||||
*
|
||||
* - ODK_SET_TIMER: Success. The timer should be reset to the specified
|
||||
* timer value.
|
||||
* - ODK_DISABLE_TIMER: Success, but disable timer. Unlimited playback is
|
||||
* allowed.
|
||||
* - ODK_TIMER_EXPIRED: Set timer as diabled. Playback is not allowed.
|
||||
* - ODK_STALE_RENEWAL: This renewal is not the most recently signed. It is
|
||||
* rejected. Return this error
|
||||
* - Any other error - OEMCrypto shall pass any other error up to the
|
||||
* caller of OEMCrypto_RefreshKeys.
|
||||
*
|
||||
* NOTE: OEMCrypto_LoadKeys() must be called first to load the keys into the
|
||||
* session.
|
||||
*
|
||||
* Parameters:
|
||||
* [in] session: handle for the session to be used.
|
||||
* [in] message: pointer to memory containing message to be verified.
|
||||
* [in] message_length: length of the message, in bytes.
|
||||
* [in] signature: pointer to memory containing the signature.
|
||||
* [in] signature_length: length of the signature, in bytes.
|
||||
* [in] num_keys: number of keys present.
|
||||
* [in] key_array: set of key updates.
|
||||
*
|
||||
* Returns:
|
||||
* OEMCrypto_SUCCESS success
|
||||
* OEMCrypto_ERROR_NO_DEVICE_KEY
|
||||
* OEMCrypto_ERROR_INVALID_SESSION
|
||||
* OEMCrypto_ERROR_INVALID_CONTEXT
|
||||
* OEMCrypto_ERROR_SIGNATURE_FAILURE
|
||||
* OEMCrypto_ERROR_INVALID_NONCE
|
||||
* OEMCrypto_ERROR_INSUFFICIENT_RESOURCES
|
||||
* OEMCrypto_ERROR_UNKNOWN_FAILURE
|
||||
* OEMCrypto_ERROR_BUFFER_TOO_LARGE
|
||||
* OEMCrypto_ERROR_NO_CONTENT_KEY
|
||||
* OEMCrypto_ERROR_SESSION_LOST_STATE
|
||||
* OEMCrypto_ERROR_SYSTEM_INVALIDATED
|
||||
*
|
||||
* Buffer Sizes:
|
||||
* OEMCrypto shall support message sizes as described in the section
|
||||
* OEMCrypto_ResourceRatingTier.
|
||||
* OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is
|
||||
* larger than the supported size.
|
||||
*
|
||||
* Threading:
|
||||
* This is a "Session Function" and may be called simultaneously with session
|
||||
* functions for other sessions but not simultaneously with other functions
|
||||
* for this session. It will not be called simultaneously with initialization
|
||||
* or usage table functions. It is as if the CDM holds a write lock for this
|
||||
* session, and a read lock on the OEMCrypto system.
|
||||
*
|
||||
* Version:
|
||||
* This method changed in API version 16.
|
||||
*/
|
||||
OEMCryptoResult OEMCrypto_RefreshKeys(
|
||||
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
||||
const uint8_t* signature, size_t signature_length, size_t num_keys,
|
||||
const OEMCrypto_KeyRefreshObject* key_array);
|
||||
|
||||
/*
|
||||
* OEMCrypto_LoadRenewal
|
||||
*
|
||||
@@ -1822,8 +1805,8 @@ OEMCryptoResult OEMCrypto_LoadEntitledContentKeys(
|
||||
* success. These values shall be handled by OEMCrypto, as discussed in the
|
||||
* document "License Duration and Renewal".
|
||||
*
|
||||
* NOTE: OEMCrypto_LoadKeys() or OEMCrypto_LoadLicense() must be called first
|
||||
* to load the keys into the session.
|
||||
* NOTE: OEMCrypto_LoadLicense() must be called first to load the keys into
|
||||
* the session.
|
||||
*
|
||||
* Verification:
|
||||
* The following checks should be performed. If any check fails, an error is
|
||||
@@ -1868,9 +1851,11 @@ OEMCryptoResult OEMCrypto_LoadEntitledContentKeys(
|
||||
* OEMCrypto_ERROR_NO_CONTENT_KEY
|
||||
* OEMCrypto_ERROR_SESSION_LOST_STATE
|
||||
* OEMCrypto_ERROR_SYSTEM_INVALIDATED
|
||||
* ODK_STALE_RENEWAL
|
||||
*
|
||||
* Buffer Sizes:
|
||||
* OEMCrypto shall support message sizes of at least 8 KiB.
|
||||
* OEMCrypto shall support message sizes as described in the section
|
||||
* OEMCrypto_ResourceRatingTier.
|
||||
* OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is
|
||||
* larger than the supported size.
|
||||
*
|
||||
@@ -1958,7 +1943,8 @@ OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session,
|
||||
* Select a content key and install it in the hardware key ladder for
|
||||
* subsequent decryption operations (OEMCrypto_DecryptCENC()) for this
|
||||
* session. The specified key must have been previously "installed" via
|
||||
* OEMCrypto_LoadKeys() or OEMCrypto_RefreshKeys().
|
||||
* OEMCrypto_LoadKeys(), OEMCrypto_LoadLicense, or
|
||||
* OEMCrypto_LoadEntitledContentKeys().
|
||||
*
|
||||
* A key control block is associated with the key and the session, and is
|
||||
* used to configure the session context. The Key Control data is documented
|
||||
@@ -1983,24 +1969,18 @@ OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session,
|
||||
* 1. If the key id is not found in the keytable for this session, then the
|
||||
* key state is not changed and OEMCrypto shall return
|
||||
* OEMCrypto_ERROR_NO_CONTENT_KEY.
|
||||
* 2. If the current key's control block has a nonzero Duration field, then
|
||||
* the API shall verify that the duration is greater than the session's
|
||||
* elapsed time clock before the key is used. OEMCrypto may return
|
||||
* OEMCrypto_ERROR_KEY_EXPIRED from OEMCrypto_SelectKey, or SelectKey
|
||||
* may return success from select key and the decrypt or generic crypto
|
||||
* call will return OEMCrypto_ERROR_KEY_EXPIRED.
|
||||
* 3. If the key control block has the bit Disable_Analog_Output set, then
|
||||
* 2. If the key control block has the bit Disable_Analog_Output set, then
|
||||
* the device should disable analog video output. If the device has
|
||||
* analog video output that cannot be disabled, then the key is not
|
||||
* selected, and OEMCrypto_ERROR_ANALOG_OUTPUT is returned. This step is
|
||||
* optional -- SelectKey may return OEMCrypto_SUCCESS and delay the
|
||||
* error until a call to OEMCrypto_DecryptCENC.
|
||||
* 4. If the key control block has HDCP required, and the device cannot
|
||||
* 3. If the key control block has HDCP required, and the device cannot
|
||||
* enforce HDCP, then the key is not selected, and
|
||||
* OEMCrypto_ERROR_INSUFFICIENT_HDCP is returned. This step is optional
|
||||
* -- SelectKey may return OEMCrypto_SUCCESS and delay the error until a
|
||||
* call to OEMCrypto_DecryptCENC.
|
||||
* 5. If the key control block has a nonzero value for HDCP_Version, and
|
||||
* 4. If the key control block has a nonzero value for HDCP_Version, and
|
||||
* the device cannot enforce at least that version of HDCP, then the key
|
||||
* is not selected, and OEMCrypto_ERROR_INSUFFICIENT_HDCP is returned.
|
||||
*
|
||||
@@ -2015,7 +1995,7 @@ OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session,
|
||||
*
|
||||
* Returns:
|
||||
* OEMCrypto_SUCCESS success
|
||||
* OEMCrypto_ERROR_KEY_EXPIRED - if the key's timer has expired
|
||||
* OEMCrypto_ERROR_KEY_EXPIRED - if the session's timer has expired
|
||||
* OEMCrypto_ERROR_INVALID_SESSION crypto session ID invalid or not open
|
||||
* OEMCrypto_ERROR_NO_DEVICE_KEY failed to decrypt device key
|
||||
* OEMCrypto_ERROR_NO_CONTENT_KEY failed to decrypt content key
|
||||
@@ -2551,7 +2531,7 @@ OEMCryptoResult OEMCrypto_CopyBuffer(
|
||||
* the time_of_last_decrypt. If the status of the entry is "unused", then
|
||||
* change the status to "active" and set the time_of_first_decrypt.
|
||||
*
|
||||
* OEMCrypto should be able to handle buffers at least 100 KiB long.
|
||||
* OEMCrypto shall be able to handle buffers at least 100 KiB long.
|
||||
*
|
||||
* Verification:
|
||||
* The following checks should be performed. If any check fails, an error is
|
||||
@@ -3775,11 +3755,23 @@ uint32_t OEMCrypto_GetAnalogOutputFlags(void);
|
||||
* Each of these pictures would correspond to a separate playback session
|
||||
* with active decryption.
|
||||
*
|
||||
* The total number of keys for all sessions indicates that the device does
|
||||
* may share key memory over multiple sessions. For example, on a Tier 3
|
||||
* device, the device must support four sessions with 20 keys each (80
|
||||
* total), or 20 sessions with 4 keys each (80 total), but it does not need
|
||||
* to support 20 sessions with 20 keys each.
|
||||
* The total number of keys for all sessions indicates that the device may
|
||||
* share key memory over multiple sessions. For example, on a Tier 3 device,
|
||||
* the device must support four sessions with 20 keys each (80 total), or 20
|
||||
* sessions with 4 keys each (80 total), but it does not need to support 20
|
||||
* sessions with 20 keys each.
|
||||
*
|
||||
* Living room devices refer to devices such as TVs, set top boxes, game
|
||||
* consoles, blu-ray players etc. These devices tend to have reduced UI and
|
||||
* frequently are dedicated to playing video. For these devices, we expect
|
||||
* there to be more memory dedicated to video playback and video
|
||||
* applications. The number of sessions required for living room devices is
|
||||
* larger than for mobile devices.
|
||||
*
|
||||
* The message size that is needed for a license with a large number of keys
|
||||
* is larger than in previous versions. The message size limit applies to all
|
||||
* functions that sign or verify messages. It also applies to the size of
|
||||
* context buffers in the derive key functions.
|
||||
*
|
||||
* Decrypted frames per second -- strictly speaking, OEMCrypto only controls
|
||||
* the decryption part of playback and cannot control the decoding and
|
||||
@@ -3808,6 +3800,10 @@ uint32_t OEMCrypto_GetAnalogOutputFlags(void);
|
||||
* |size | | | | |
|
||||
* +--------------------------------+---------+----------+---------+---------+
|
||||
* |Minimum number of open sessions |10 |20 |20 |30 |
|
||||
* |(mobile devices) | | | | |
|
||||
* +--------------------------------+---------+----------+---------+---------+
|
||||
* |Minimum number of open sessions |10 |100 |100 |100 |
|
||||
* |(living room devices) | | | | |
|
||||
* +--------------------------------+---------+----------+---------+---------+
|
||||
* |Minimum number of keys per |4 |20 |20 |30 |
|
||||
* |session | | | | |
|
||||
@@ -3815,6 +3811,8 @@ uint32_t OEMCrypto_GetAnalogOutputFlags(void);
|
||||
* |Minimum total number of keys |16 |40 |80 |90 |
|
||||
* | (all sessions) | | | | |
|
||||
* +--------------------------------+---------+----------+---------+---------+
|
||||
* |Minimum Message Size |8 KiB |8 KiB |16 KiB |32 KiB |
|
||||
* +--------------------------------+---------+----------+---------+---------+
|
||||
* |Decrypted Frames per Second |30 fps SD|30 fps HD |60 fps HD|60 fps 8k|
|
||||
* +--------------------------------+---------+----------+---------+---------+
|
||||
*
|
||||
@@ -3953,7 +3951,8 @@ uint32_t OEMCrypto_ResourceRatingTier(void);
|
||||
* OEMCrypto_ERROR_SYSTEM_INVALIDATED
|
||||
*
|
||||
* Buffer Sizes:
|
||||
* OEMCrypto shall support message sizes of at least 8 KiB.
|
||||
* OEMCrypto shall support message sizes as described in the section
|
||||
* OEMCrypto_ResourceRatingTier.
|
||||
* OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is
|
||||
* larger than the supported size.
|
||||
*
|
||||
@@ -3974,7 +3973,7 @@ OEMCryptoResult OEMCrypto_LoadProvisioning(
|
||||
size_t* wrapped_private_key_length);
|
||||
|
||||
/*
|
||||
* OEMCrypto_LoadDevicePrivateKey
|
||||
* OEMCrypto_LoadDRMPrivateKey
|
||||
*
|
||||
* Description:
|
||||
* Loads a wrapped RSA or ECC private key to secure memory for use by this
|
||||
@@ -4028,9 +4027,10 @@ OEMCryptoResult OEMCrypto_LoadProvisioning(
|
||||
* Version:
|
||||
* This method changed in API version 16.
|
||||
*/
|
||||
OEMCryptoResult OEMCrypto_LoadDevicePrivateKey(
|
||||
OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type,
|
||||
const uint8_t* wrapped_rsa_key, size_t wrapped_rsa_key_length);
|
||||
OEMCryptoResult OEMCrypto_LoadDRMPrivateKey(OEMCrypto_SESSION session,
|
||||
OEMCrypto_PrivateKeyType key_type,
|
||||
const uint8_t* wrapped_rsa_key,
|
||||
size_t wrapped_rsa_key_length);
|
||||
|
||||
/*
|
||||
* OEMCrypto_LoadTestRSAKey
|
||||
@@ -4076,7 +4076,7 @@ OEMCryptoResult OEMCrypto_LoadTestRSAKey(void);
|
||||
* Description:
|
||||
* The OEMCrypto_GenerateRSASignature method is only used for devices that
|
||||
* are CAST receivers. This function is called after
|
||||
* OEMCrypto_LoadDevicePrivateKey for the same session.
|
||||
* OEMCrypto_LoadDRMPrivateKey for the same session.
|
||||
*
|
||||
* The parameter padding_scheme has two possible legacy values:
|
||||
*
|
||||
@@ -4129,7 +4129,8 @@ OEMCryptoResult OEMCrypto_LoadTestRSAKey(void);
|
||||
* OEMCrypto_ERROR_SYSTEM_INVALIDATED
|
||||
*
|
||||
* Buffer Sizes:
|
||||
* OEMCrypto shall support message sizes of at least 8 KiB.
|
||||
* OEMCrypto shall support message sizes as described in the section
|
||||
* OEMCrypto_ResourceRatingTier.
|
||||
* OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is
|
||||
* larger than the supported size.
|
||||
*
|
||||
@@ -4738,14 +4739,15 @@ uint32_t OEMCrypto_SupportsDecryptHash(void);
|
||||
* Description:
|
||||
* Set the hash value for the next frame to be decrypted. This function is
|
||||
* called before the first subsample is passed to OEMCrypto_DecryptCENC, when
|
||||
* the subsample_flag has the bit OEMCrytpo_FirstSubsample set. The hash is
|
||||
* the subsample_flag has the bit OEMCrypto_FirstSubsample set. The hash is
|
||||
* over all of the frame or sample: encrypted and clear subsamples
|
||||
* concatenated together, up to, and including the subsample with the
|
||||
* subsample_flag having the bit OEMCrypto_LastSubsample set. If hashing the
|
||||
* output is not supported, then this will return
|
||||
* OEMCrypto_ERROR_NOT_IMPLEMENTED. If the hash is ill formed or there are
|
||||
* other error conditions, this returns OEMCrypto_ERROR_UNKNOWN_FAILURE. The
|
||||
* length of the hash will be at most 128 bytes.
|
||||
* length of the hash will be at most 128 bytes, and will be 4 bytes (32
|
||||
* bits) for the default CRC32 hash.
|
||||
*
|
||||
* This may be called before the first call to SelectKey. In that case, this
|
||||
* function cannot verify that the key control block allows hash
|
||||
@@ -4931,16 +4933,6 @@ OEMCryptoResult OEMCrypto_GenerateSignature(OEMCrypto_SESSION session,
|
||||
size_t message_length,
|
||||
uint8_t* signature,
|
||||
size_t* signature_length);
|
||||
typedef struct {
|
||||
OEMCrypto_Substring key_id;
|
||||
OEMCrypto_Substring key_control_iv;
|
||||
OEMCrypto_Substring key_control;
|
||||
} OEMCrypto_KeyRefreshObject;
|
||||
|
||||
OEMCryptoResult OEMCrypto_RefreshKeys(
|
||||
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
||||
const uint8_t* signature, size_t signature_length, size_t num_keys,
|
||||
const OEMCrypto_KeyRefreshObject* key_array);
|
||||
OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30(
|
||||
OEMCrypto_SESSION session, const uint32_t* unaligned_nonce,
|
||||
const uint8_t* encrypted_message_key, size_t encrypted_message_key_length,
|
||||
|
||||
1
oemcrypto/include/OEMCryptoCENCCommon.h
Symbolic link
1
oemcrypto/include/OEMCryptoCENCCommon.h
Symbolic link
@@ -0,0 +1 @@
|
||||
../../oemcrypto/odk/include/OEMCryptoCENCCommon.h
|
||||
@@ -89,11 +89,9 @@ class CryptoEngine {
|
||||
return kMaxSupportedOEMCryptoSessions;
|
||||
}
|
||||
|
||||
// System clock, measuring time in seconds.
|
||||
int64_t OnlineTime();
|
||||
|
||||
// System clock with antirollback protection, measuring time in seconds.
|
||||
int64_t RollbackCorrectedOfflineTime();
|
||||
// The OEMCrypto system time. Prevents time rollback.
|
||||
// TODO(b/145836634): Combine RollbackCorrectedOfflineTime with OnlineTime().
|
||||
int64_t SystemTime() { return RollbackCorrectedOfflineTime(); }
|
||||
|
||||
// Verify that this nonce does not collide with another nonce in any session.
|
||||
virtual bool NonceCollision(uint32_t nonce);
|
||||
@@ -212,6 +210,12 @@ class CryptoEngine {
|
||||
}
|
||||
|
||||
protected:
|
||||
// System clock, measuring time in seconds.
|
||||
int64_t OnlineTime();
|
||||
|
||||
// System clock with antirollback protection, measuring time in seconds.
|
||||
int64_t RollbackCorrectedOfflineTime();
|
||||
|
||||
explicit CryptoEngine(std::unique_ptr<wvcdm::FileSystem>&& file_system);
|
||||
virtual SessionContext* MakeSession(SessionId sid);
|
||||
virtual UsageTable* MakeUsageTable();
|
||||
|
||||
@@ -407,38 +407,69 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadEntitledContentKeys(
|
||||
key_array_length, key_array);
|
||||
}
|
||||
|
||||
OEMCRYPTO_API OEMCryptoResult OEMCrypto_RefreshKeys(
|
||||
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
||||
const uint8_t* signature, size_t signature_length, size_t num_keys,
|
||||
const OEMCrypto_KeyRefreshObject* key_array) {
|
||||
OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadRenewal(OEMCrypto_SESSION session,
|
||||
const uint8_t* message,
|
||||
size_t message_length,
|
||||
size_t core_message_length,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length) {
|
||||
if (crypto_engine == nullptr) {
|
||||
LOGE("OEMCrypto_RefreshKeys: OEMCrypto Not Initialized.");
|
||||
LOGE("OEMCrypto Not Initialized.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
|
||||
if (!crypto_engine->ValidRootOfTrust()) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): ERROR_KEYBOX_INVALID]");
|
||||
LOGE("ERROR_KEYBOX_INVALID");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (session_ctx == nullptr || !session_ctx->isValid()) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): ERROR_INVALID_SESSION]");
|
||||
LOGE("ERROR_INVALID_SESSION");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
if (message == nullptr || message_length == 0 || signature == nullptr ||
|
||||
signature_length == 0) {
|
||||
LOGE("ERROR_INVALID_CONTEXT");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
return session_ctx->LoadRenewal(message, message_length, core_message_length,
|
||||
signature, signature_length);
|
||||
}
|
||||
|
||||
OEMCRYPTO_API OEMCryptoResult OEMCrypto_RefreshKeys(
|
||||
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
||||
const uint8_t* signature, size_t signature_length, size_t num_keys,
|
||||
const OEMCrypto_KeyRefreshObject* key_array) {
|
||||
if (crypto_engine == nullptr) {
|
||||
LOGE("OEMCrypto Not Initialized.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
|
||||
if (!crypto_engine->ValidRootOfTrust()) {
|
||||
LOGE("ERROR_KEYBOX_INVALID");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (session_ctx == nullptr || !session_ctx->isValid()) {
|
||||
LOGE("ERROR_INVALID_SESSION");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
if (message == nullptr || message_length == 0 || signature == nullptr ||
|
||||
signature_length == 0 || num_keys == 0) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
LOGE("ERROR_INVALID_CONTEXT");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
// Range check
|
||||
for (unsigned int i = 0; i < num_keys; i++) {
|
||||
for (size_t i = 0; i < num_keys; i++) {
|
||||
if (!RangeCheck(message_length, key_array[i].key_id, true) ||
|
||||
!RangeCheck(message_length, key_array[i].key_control, false) ||
|
||||
!RangeCheck(message_length, key_array[i].key_control_iv, true)) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): Range Check %d]", i);
|
||||
LOGE("Range Check %zu", i);
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
}
|
||||
@@ -446,7 +477,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_RefreshKeys(
|
||||
// Validate message signature
|
||||
if (!session_ctx->ValidateMessage(message, message_length, signature,
|
||||
signature_length)) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): signature was invalid]");
|
||||
LOGE("Signature was invalid");
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
|
||||
@@ -455,7 +486,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_RefreshKeys(
|
||||
std::vector<uint8_t> key_id;
|
||||
std::vector<uint8_t> key_control;
|
||||
std::vector<uint8_t> key_control_iv;
|
||||
for (unsigned int i = 0; i < num_keys; i++) {
|
||||
for (size_t i = 0; i < num_keys; i++) {
|
||||
if (key_array[i].key_id.length != 0) {
|
||||
key_id.assign(
|
||||
message + key_array[i].key_id.offset,
|
||||
@@ -482,16 +513,13 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_RefreshKeys(
|
||||
|
||||
status = session_ctx->RefreshKey(key_id, key_control, key_control_iv);
|
||||
if (status != OEMCrypto_SUCCESS) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): error %u in key %i]", status, i);
|
||||
LOGE("error %d in key %zu", status, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (status != OEMCrypto_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
session_ctx->StartTimer();
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -172,6 +172,7 @@ SessionContext::SessionContext(CryptoEngine* ce, SessionId sid,
|
||||
session_keys_(nullptr),
|
||||
rsa_key_(rsa_key),
|
||||
allowed_schemes_(kSign_RSASSA_PSS),
|
||||
decrypt_started_(false),
|
||||
timer_limits_(),
|
||||
clock_values_(),
|
||||
usage_entry_(nullptr),
|
||||
@@ -353,7 +354,7 @@ OEMCryptoResult SessionContext::PrepAndSignLicenseRequest(
|
||||
result = GenerateCertSignature(message_body, message_body_length, signature,
|
||||
signature_length);
|
||||
if (result == OEMCrypto_SUCCESS) state_request_signed_ = true;
|
||||
ODK_InitializeClockValues(&clock_values_, ce_->OnlineTime());
|
||||
ODK_InitializeClockValues(&clock_values_, ce_->SystemTime());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -371,7 +372,7 @@ OEMCryptoResult SessionContext::PrepAndSignRenewalRequest(
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
const size_t required_signature_size = SHA256_DIGEST_LENGTH;
|
||||
const uint64_t now = CurrentTimer();
|
||||
const uint64_t now = ce_->SystemTime();
|
||||
const OEMCryptoResult result = ODK_PrepareCoreRenewalRequest(
|
||||
message, message_length, core_message_length, &nonce_values_,
|
||||
&clock_values_, now);
|
||||
@@ -679,13 +680,6 @@ OEMCryptoResult SessionContext::CheckNonceOrEntry(
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
void SessionContext::StartTimer() { timer_start_ = ce_->OnlineTime(); }
|
||||
|
||||
uint32_t SessionContext::CurrentTimer() {
|
||||
int64_t now = ce_->OnlineTime();
|
||||
return static_cast<uint32_t>((now >= timer_start_) ? now - timer_start_ : 0);
|
||||
}
|
||||
|
||||
OEMCryptoResult SessionContext::LoadLicense(const uint8_t* message,
|
||||
size_t message_length,
|
||||
size_t core_message_length,
|
||||
@@ -697,8 +691,7 @@ OEMCryptoResult SessionContext::LoadLicense(const uint8_t* message,
|
||||
return OEMCrypto_ERROR_LICENSE_RELOAD;
|
||||
}
|
||||
ODK_ParsedLicense parsed_response;
|
||||
// TODO(b/140765227): handle license reload.
|
||||
constexpr bool initial_license_load = true;
|
||||
const bool initial_license_load = (usage_entry_status_ != kUsageEntryLoaded);
|
||||
const OEMCryptoResult result = ODK_ParseLicense(
|
||||
message, message_length, core_message_length, initial_license_load,
|
||||
usage_entry_present(), license_request_hash_, &timer_limits_,
|
||||
@@ -741,11 +734,10 @@ OEMCryptoResult SessionContext::LoadKeys(
|
||||
message, message_length, enc_mac_keys_iv, enc_mac_keys, num_keys,
|
||||
key_array, pst, srm_restriction_data, license_type);
|
||||
if (result != OEMCrypto_SUCCESS) return result;
|
||||
if (num_keys < 1) return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
Key* key = session_keys_->FirstKey();
|
||||
uint32_t duration = key ? key->control().duration() : 0;
|
||||
result = ODK_InitializeV15Values(&timer_limits_, &clock_values_,
|
||||
&nonce_values_, duration, ce_->OnlineTime());
|
||||
&nonce_values_, duration, ce_->SystemTime());
|
||||
// TODO(b/140765227): clear session on errors
|
||||
return result;
|
||||
}
|
||||
@@ -760,6 +752,7 @@ OEMCryptoResult SessionContext::LoadKeysNoSignature(
|
||||
return OEMCrypto_ERROR_LICENSE_RELOAD;
|
||||
}
|
||||
state_response_loaded_ = true;
|
||||
if (num_keys < 1) return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
|
||||
if (session_keys_ == nullptr) {
|
||||
switch (license_type) {
|
||||
@@ -779,9 +772,6 @@ OEMCryptoResult SessionContext::LoadKeysNoSignature(
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
}
|
||||
|
||||
StartTimer();
|
||||
|
||||
if (srm_restriction_data.length != 0) {
|
||||
const std::string kSRMVerificationString = "HDCPDATA";
|
||||
if (memcmp(message + srm_restriction_data.offset,
|
||||
@@ -1041,64 +1031,45 @@ bool SessionContext::InstallRSAEncryptedKey(
|
||||
return true;
|
||||
}
|
||||
|
||||
OEMCryptoResult SessionContext::LoadRenewal(const uint8_t* message,
|
||||
size_t message_length,
|
||||
size_t core_message_length,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length) {
|
||||
if (session_keys_ == nullptr) {
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if (!ValidateMessage(message, message_length, signature, signature_length)) {
|
||||
LOGE("signature was invalid");
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
|
||||
// The reference implementation does not use a hardware timer.
|
||||
uint64_t* timer_value = nullptr;
|
||||
const OEMCryptoResult result = ODK_ParseRenewal(
|
||||
message, message_length, core_message_length, &nonce_values_,
|
||||
ce_->SystemTime(), &timer_limits_, &clock_values_, timer_value);
|
||||
if (result == ODK_SET_TIMER || result == ODK_DISABLE_TIMER)
|
||||
return OEMCrypto_SUCCESS;
|
||||
if (result == ODK_TIMER_EXPIRED) return OEMCrypto_ERROR_KEY_EXPIRED;
|
||||
// All other errors are returned to the caller.
|
||||
return result;
|
||||
}
|
||||
|
||||
OEMCryptoResult SessionContext::RefreshKey(
|
||||
const KeyId& key_id, const std::vector<uint8_t>& key_control,
|
||||
const std::vector<uint8_t>& key_control_iv) {
|
||||
if (session_keys_ == nullptr) {
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if (key_id.empty()) {
|
||||
// Key control is not encrypted if key id is nullptr
|
||||
KeyControlBlock key_control_block(key_control);
|
||||
if (!key_control_block.valid()) {
|
||||
LOGE("Parse key control error");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if ((key_control_block.control_bits() & wvoec::kControlNonceEnabled) &&
|
||||
(!CheckNonce(key_control_block.nonce()))) {
|
||||
LOGE("KCB: BAD Nonce");
|
||||
return OEMCrypto_ERROR_INVALID_NONCE;
|
||||
}
|
||||
// Apply duration to all keys in this session
|
||||
session_keys_->UpdateDuration(key_control_block);
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
Key* content_key = session_keys_->Find(key_id);
|
||||
|
||||
if (content_key == nullptr) {
|
||||
LOGE("Key ID not found");
|
||||
return OEMCrypto_ERROR_NO_CONTENT_KEY;
|
||||
}
|
||||
|
||||
if (key_control.empty()) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t> content_key_value = content_key->value();
|
||||
|
||||
// Decrypt encrypted key control block
|
||||
std::vector<uint8_t> control;
|
||||
if (key_control_iv.empty()) {
|
||||
control = key_control;
|
||||
} else {
|
||||
if (!DecryptMessage(content_key_value, key_control_iv, key_control,
|
||||
&control, 128 /* key size */)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
KeyControlBlock key_control_block(control);
|
||||
if (!key_control_block.valid()) {
|
||||
LOGE("Error parsing key control");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if ((key_control_block.control_bits() & wvoec::kControlNonceEnabled) &&
|
||||
(!CheckNonce(key_control_block.nonce()))) {
|
||||
return OEMCrypto_ERROR_INVALID_NONCE;
|
||||
}
|
||||
content_key->UpdateDuration(key_control_block);
|
||||
uint64_t* timer_value = nullptr;
|
||||
const OEMCryptoResult result =
|
||||
ODK_RefreshV15Values(&timer_limits_, &clock_values_, &nonce_values_,
|
||||
ce_->SystemTime(), timer_value);
|
||||
if (result == ODK_SET_TIMER || result == ODK_DISABLE_TIMER)
|
||||
return OEMCrypto_SUCCESS;
|
||||
if (result == ODK_TIMER_EXPIRED) return OEMCrypto_ERROR_KEY_EXPIRED;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SessionContext::DecryptRSAKey(const uint8_t* enc_rsa_key,
|
||||
@@ -1163,19 +1134,19 @@ OEMCryptoResult SessionContext::CheckKeyUse(const std::string& log_string,
|
||||
return OEMCrypto_ERROR_DECRYPT_FAILED;
|
||||
}
|
||||
}
|
||||
if (control.control_bits() & wvoec::kControlReplayMask) {
|
||||
if (!CheckUsageEntry()) {
|
||||
LOGE("[%s(): usage entry not valid]", log_string.c_str());
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
if (control.duration() > 0) {
|
||||
if (control.duration() < CurrentTimer()) {
|
||||
LOGE("%s: key expired. duration=%d, timer=%d, now=%ld",
|
||||
log_string.c_str(), control.duration(), CurrentTimer(),
|
||||
ce_->OnlineTime());
|
||||
return OEMCrypto_ERROR_KEY_EXPIRED;
|
||||
}
|
||||
if (!decrypt_started_) {
|
||||
// The reference implementation does not have a hardware timer.
|
||||
uint64_t* timer_expiration = nullptr;
|
||||
const OEMCryptoResult result = ODK_AttemptFirstPlayback(
|
||||
ce_->SystemTime(), &timer_limits_, &clock_values_, timer_expiration);
|
||||
if (result == ODK_TIMER_EXPIRED) return OEMCrypto_ERROR_KEY_EXPIRED;
|
||||
if (usage_entry_ != nullptr) usage_entry_->ForbidReport();
|
||||
} else {
|
||||
// Continued playback.
|
||||
const OEMCryptoResult result = ODK_UpdateLastPlaybackTime(
|
||||
ce_->SystemTime(), &timer_limits_, &clock_values_);
|
||||
if (result == ODK_TIMER_EXPIRED) return OEMCrypto_ERROR_KEY_EXPIRED;
|
||||
if (usage_entry_ != nullptr) usage_entry_->set_recent_decrypt(true);
|
||||
}
|
||||
if (!ce_->config_local_display_only()) {
|
||||
// Only look at HDCP restrictions if the display can be non-local.
|
||||
@@ -1215,6 +1186,7 @@ OEMCryptoResult SessionContext::CheckKeyUse(const std::string& log_string,
|
||||
return OEMCrypto_ERROR_ANALOG_OUTPUT;
|
||||
}
|
||||
}
|
||||
decrypt_started_ = true; // First playback for session.
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1421,23 +1393,9 @@ OEMCryptoResult SessionContext::SelectContentKey(
|
||||
}
|
||||
content_key->set_ctr_mode(cipher_mode == OEMCrypto_CipherMode_CTR);
|
||||
current_content_key_ = content_key;
|
||||
const KeyControlBlock& control = current_content_key()->control();
|
||||
|
||||
if (control.duration() > 0) {
|
||||
if (control.duration() < CurrentTimer()) {
|
||||
LOGE("KEY_EXPIRED duration=%d, timer=%d, now=%ld", control.duration(),
|
||||
CurrentTimer(), ce_->OnlineTime());
|
||||
return OEMCrypto_ERROR_KEY_EXPIRED;
|
||||
}
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
bool SessionContext::CheckUsageEntry() {
|
||||
if (!usage_entry_) return false;
|
||||
return usage_entry_->CheckForUse();
|
||||
}
|
||||
|
||||
OEMCryptoResult SessionContext::CreateNewUsageEntry(
|
||||
uint32_t* usage_entry_number) {
|
||||
if (usage_entry_) {
|
||||
@@ -1458,9 +1416,11 @@ OEMCryptoResult SessionContext::LoadUsageEntry(
|
||||
// Can only load one entry per session.
|
||||
return OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES;
|
||||
}
|
||||
OEMCryptoResult result =
|
||||
ce_->usage_table().LoadUsageEntry(this, &usage_entry_, index, buffer);
|
||||
if (usage_entry_) {
|
||||
const OEMCryptoResult result = ce_->usage_table().LoadUsageEntry(
|
||||
this, &usage_entry_, index, buffer, &clock_values_);
|
||||
if (result != OEMCrypto_SUCCESS) return result;
|
||||
if (!usage_entry_) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
|
||||
usage_entry_status_ = kUsageEntryLoaded;
|
||||
// Copy the mac keys to the current session.
|
||||
mac_key_server_ = std::vector<uint8_t>(
|
||||
@@ -1469,8 +1429,7 @@ OEMCryptoResult SessionContext::LoadUsageEntry(
|
||||
mac_key_client_ = std::vector<uint8_t>(
|
||||
usage_entry_->mac_key_client(),
|
||||
usage_entry_->mac_key_client() + wvoec::MAC_KEY_SIZE);
|
||||
}
|
||||
return result;
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
OEMCryptoResult SessionContext::UpdateUsageEntry(uint8_t* header_buffer,
|
||||
@@ -1481,16 +1440,16 @@ OEMCryptoResult SessionContext::UpdateUsageEntry(uint8_t* header_buffer,
|
||||
LOGE("UpdateUsageEntry: Session has no entry");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
return ce_->usage_table().UpdateUsageEntry(this, usage_entry_, header_buffer,
|
||||
header_buffer_length, entry_buffer,
|
||||
entry_buffer_length);
|
||||
return ce_->usage_table().UpdateUsageEntry(
|
||||
this, usage_entry_, header_buffer, header_buffer_length, entry_buffer,
|
||||
entry_buffer_length, &clock_values_);
|
||||
}
|
||||
|
||||
OEMCryptoResult SessionContext::DeactivateUsageEntry(
|
||||
const std::vector<uint8_t>& pst) {
|
||||
if (!usage_entry_) return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
usage_entry_->Deactivate(pst);
|
||||
return OEMCrypto_SUCCESS;
|
||||
usage_entry_->ForbidReport();
|
||||
return ODK_DeactivateUsageEntry(&clock_values_);
|
||||
}
|
||||
|
||||
OEMCryptoResult SessionContext::ReportUsage(const std::vector<uint8_t>& pst,
|
||||
|
||||
@@ -118,8 +118,6 @@ class SessionContext {
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length);
|
||||
void StartTimer();
|
||||
uint32_t CurrentTimer(); // (seconds).
|
||||
virtual OEMCryptoResult LoadLicense(const uint8_t* message,
|
||||
size_t message_length,
|
||||
size_t core_message_length,
|
||||
@@ -153,6 +151,11 @@ class SessionContext {
|
||||
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 LoadRSAKey(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<uint8_t>& key_control,
|
||||
const std::vector<uint8_t>& key_control_iv);
|
||||
@@ -271,7 +274,7 @@ class SessionContext {
|
||||
uint8_t license_request_hash_[ODK_SHA256_HASH_SIZE];
|
||||
RSA_shared_ptr rsa_key_;
|
||||
uint32_t allowed_schemes_; // for RSA signatures.
|
||||
int64_t timer_start_; // TODO(b/140764222): delete.
|
||||
bool decrypt_started_; // If the license has been used in this session.
|
||||
ODK_TimerLimits timer_limits_;
|
||||
ODK_ClockValues clock_values_;
|
||||
UsageTableEntry* usage_entry_;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "file_store.h"
|
||||
#include "log.h"
|
||||
#include "odk.h"
|
||||
#include "oemcrypto_engine_ref.h"
|
||||
// TODO(fredgc): Setting the device files base bath is currently broken as
|
||||
// wvcdm::Properties is no longer used by the reference code.
|
||||
@@ -70,8 +71,7 @@ OEMCryptoResult UsageTableEntry::SetPST(const uint8_t* pst, size_t pst_length) {
|
||||
data_.pst_length = pst_length;
|
||||
if (!pst || !pst_length) return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
memcpy(data_.pst, pst, pst_length);
|
||||
data_.time_of_license_received =
|
||||
usage_table_->ce_->RollbackCorrectedOfflineTime();
|
||||
data_.time_of_license_received = usage_table_->ce_->SystemTime();
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -100,25 +100,7 @@ bool UsageTableEntry::SetMacKeys(const std::vector<uint8_t>& server,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UsageTableEntry::CheckForUse() {
|
||||
if (Inactive()) return false;
|
||||
recent_decrypt_ = true;
|
||||
if (data_.status == kUnused) {
|
||||
data_.status = kActive;
|
||||
data_.time_of_first_decrypt =
|
||||
usage_table_->ce_->RollbackCorrectedOfflineTime();
|
||||
data_.generation_number++;
|
||||
usage_table_->IncrementGeneration();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void UsageTableEntry::Deactivate(const std::vector<uint8_t>& pst) {
|
||||
if (data_.status == kUnused) {
|
||||
data_.status = kInactiveUnused;
|
||||
} else if (data_.status == kActive) {
|
||||
data_.status = kInactiveUsed;
|
||||
}
|
||||
void UsageTableEntry::ForbidReport() {
|
||||
forbid_report_ = true;
|
||||
data_.generation_number++;
|
||||
usage_table_->IncrementGeneration();
|
||||
@@ -150,7 +132,7 @@ OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector<uint8_t>& pst,
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
wvcdm::Unpacked_PST_Report pst_report(buffer);
|
||||
int64_t now = usage_table_->ce_->RollbackCorrectedOfflineTime();
|
||||
int64_t now = usage_table_->ce_->SystemTime();
|
||||
pst_report.set_seconds_since_license_received(now -
|
||||
data_.time_of_license_received);
|
||||
pst_report.set_seconds_since_first_decrypt(now - data_.time_of_first_decrypt);
|
||||
@@ -169,12 +151,29 @@ OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector<uint8_t>& pst,
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
void UsageTableEntry::UpdateAndIncrement() {
|
||||
void UsageTableEntry::UpdateAndIncrement(ODK_ClockValues* clock_values) {
|
||||
if (recent_decrypt_) {
|
||||
data_.time_of_last_decrypt =
|
||||
usage_table_->ce_->RollbackCorrectedOfflineTime();
|
||||
data_.time_of_last_decrypt = usage_table_->ce_->SystemTime();
|
||||
recent_decrypt_ = false;
|
||||
}
|
||||
data_.time_of_license_received = clock_values->time_of_license_signed;
|
||||
data_.time_of_first_decrypt = clock_values->time_of_first_decrypt;
|
||||
// Use the most recent time_of_last_decrypt.
|
||||
if (static_cast<uint64_t>(data_.time_of_last_decrypt) <
|
||||
clock_values->time_of_last_decrypt) {
|
||||
// For the reference implementation, we update the clock_values on every
|
||||
// decrypt.
|
||||
data_.time_of_last_decrypt = clock_values->time_of_last_decrypt;
|
||||
} else {
|
||||
// For this reference implementation of OEMCrypto, we regularly update
|
||||
// clock_values->time_of_last_decrypt and we could just update
|
||||
// data_.time_of_last_decrypt here. However, I'm including the line below to
|
||||
// make it clear that you could do it the other way around. When this
|
||||
// function is called, the two values should be synced so that the usage
|
||||
// entry can be saved with the correct value.
|
||||
clock_values->time_of_last_decrypt = data_.time_of_last_decrypt;
|
||||
}
|
||||
data_.status = clock_values->status;
|
||||
data_.generation_number++;
|
||||
usage_table_->IncrementGeneration();
|
||||
forbid_report_ = false;
|
||||
@@ -193,7 +192,7 @@ OEMCryptoResult UsageTableEntry::SaveData(CryptoEngine* ce,
|
||||
reinterpret_cast<SignedEntryBlock*>(&clear_buffer[0]);
|
||||
SignedEntryBlock* encrypted =
|
||||
reinterpret_cast<SignedEntryBlock*>(signed_buffer);
|
||||
clear->data = this->data_; // Copy the current data.
|
||||
clear->data = data_; // Copy the current data.
|
||||
memcpy(clear->verification, kEntryVerification, kMagicLength);
|
||||
|
||||
// This should be encrypted and signed with a device specific key.
|
||||
@@ -227,7 +226,8 @@ OEMCryptoResult UsageTableEntry::SaveData(CryptoEngine* ce,
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index,
|
||||
const std::vector<uint8_t>& buffer) {
|
||||
const std::vector<uint8_t>& buffer,
|
||||
ODK_ClockValues* clock_values) {
|
||||
if (buffer.size() < SignedEntrySize()) return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
if (buffer.size() > SignedEntrySize())
|
||||
LOGW("LoadUsageTableEntry: buffer is large. %d > %d", buffer.size(),
|
||||
@@ -294,8 +294,10 @@ OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index,
|
||||
LOGE("LoadUsageEntry: entry has bad status %d", clear->data.status);
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
this->data_ = clear->data;
|
||||
return OEMCrypto_SUCCESS;
|
||||
data_ = clear->data;
|
||||
return ODK_ReloadClockValues(
|
||||
clock_values, data_.time_of_license_received, data_.time_of_first_decrypt,
|
||||
data_.time_of_last_decrypt, data_.status, ce->SystemTime());
|
||||
}
|
||||
|
||||
size_t UsageTableEntry::SignedEntrySize() {
|
||||
@@ -314,12 +316,10 @@ size_t UsageTable::SignedHeaderSize(size_t count) {
|
||||
return blocks * wvoec::KEY_IV_SIZE;
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTable::UpdateUsageEntry(SessionContext* session,
|
||||
UsageTableEntry* entry,
|
||||
uint8_t* header_buffer,
|
||||
size_t* header_buffer_length,
|
||||
uint8_t* entry_buffer,
|
||||
size_t* entry_buffer_length) {
|
||||
OEMCryptoResult UsageTable::UpdateUsageEntry(
|
||||
SessionContext* session, UsageTableEntry* entry, uint8_t* header_buffer,
|
||||
size_t* header_buffer_length, uint8_t* entry_buffer,
|
||||
size_t* entry_buffer_length, ODK_ClockValues* clock_values) {
|
||||
size_t signed_header_size = SignedHeaderSize(generation_numbers_.size());
|
||||
if (*entry_buffer_length < UsageTableEntry::SignedEntrySize() ||
|
||||
*header_buffer_length < signed_header_size) {
|
||||
@@ -331,7 +331,7 @@ OEMCryptoResult UsageTable::UpdateUsageEntry(SessionContext* session,
|
||||
*header_buffer_length = signed_header_size;
|
||||
if ((!header_buffer) || (!entry_buffer))
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
entry->UpdateAndIncrement();
|
||||
entry->UpdateAndIncrement(clock_values);
|
||||
generation_numbers_[entry->index()] = entry->generation_number();
|
||||
OEMCryptoResult result =
|
||||
entry->SaveData(ce_, session, entry_buffer, *entry_buffer_length);
|
||||
@@ -371,7 +371,8 @@ OEMCryptoResult UsageTable::CreateNewUsageEntry(SessionContext* session,
|
||||
OEMCryptoResult UsageTable::LoadUsageEntry(SessionContext* session,
|
||||
UsageTableEntry** entry,
|
||||
uint32_t index,
|
||||
const std::vector<uint8_t>& buffer) {
|
||||
const std::vector<uint8_t>& buffer,
|
||||
ODK_ClockValues* clock_values) {
|
||||
if (!header_loaded_) {
|
||||
LOGE("CreateNewUsageEntry: Header not loaded.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
@@ -390,7 +391,8 @@ OEMCryptoResult UsageTable::LoadUsageEntry(SessionContext* session,
|
||||
}
|
||||
UsageTableEntry* new_entry = MakeEntry(index);
|
||||
|
||||
OEMCryptoResult status = new_entry->LoadData(ce_, index, buffer);
|
||||
OEMCryptoResult status =
|
||||
new_entry->LoadData(ce_, index, buffer, clock_values);
|
||||
if (status != OEMCrypto_SUCCESS) {
|
||||
delete new_entry;
|
||||
return status;
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
#include <vector>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "openssl/sha.h"
|
||||
#include "odk_structs.h"
|
||||
#include "oemcrypto_types.h"
|
||||
#include "openssl/sha.h"
|
||||
|
||||
namespace wvoec_ref {
|
||||
|
||||
@@ -42,28 +43,34 @@ class UsageTableEntry {
|
||||
UsageTableEntry(UsageTable* table, uint32_t index, int64_t generation);
|
||||
virtual ~UsageTableEntry(); // Free memory, remove reference in header.
|
||||
bool Inactive() { return data_.status >= kInactive; }
|
||||
// Mark this entry as modified and forbid a usage report until the data has
|
||||
// been saved. This is done on important events like first decrypt and
|
||||
// deactivation.
|
||||
void ForbidReport();
|
||||
OEMCryptoResult SetPST(const uint8_t* pst, size_t pst_length);
|
||||
bool VerifyPST(const uint8_t* pst, size_t pst_length);
|
||||
bool VerifyMacKeys(const std::vector<uint8_t>& server,
|
||||
const std::vector<uint8_t>& client);
|
||||
bool SetMacKeys(const std::vector<uint8_t>& server,
|
||||
const std::vector<uint8_t>& client);
|
||||
// Returns false if the entry is inactive. Otherwise, returns true.
|
||||
// If the status was unused, it is updated, and decrypt times are flaged
|
||||
// for update.
|
||||
bool CheckForUse();
|
||||
void Deactivate(const std::vector<uint8_t>& pst);
|
||||
virtual OEMCryptoResult ReportUsage(const std::vector<uint8_t>& pst,
|
||||
uint8_t* buffer, size_t* buffer_length);
|
||||
virtual void UpdateAndIncrement();
|
||||
virtual void UpdateAndIncrement(ODK_ClockValues* clock_values);
|
||||
// Save all data to the give buffer. This should be called after updating the
|
||||
// data.
|
||||
OEMCryptoResult SaveData(CryptoEngine* ce, SessionContext* session,
|
||||
uint8_t* signed_buffer, size_t buffer_size);
|
||||
// Load all data from the buffer, and then update clock_values.
|
||||
OEMCryptoResult LoadData(CryptoEngine* ce, uint32_t index,
|
||||
const std::vector<uint8_t>& buffer);
|
||||
const std::vector<uint8_t>& buffer,
|
||||
ODK_ClockValues* clock_values);
|
||||
int64_t generation_number() { return data_.generation_number; }
|
||||
void set_generation_number(int64_t value) { data_.generation_number = value; }
|
||||
void set_index(int32_t index) { data_.index = index; }
|
||||
uint32_t index() { return data_.index; }
|
||||
void set_recent_decrypt(bool recent_decrypt) {
|
||||
recent_decrypt_ = recent_decrypt;
|
||||
}
|
||||
static size_t SignedEntrySize();
|
||||
const uint8_t* mac_key_server() { return data_.mac_key_server; }
|
||||
const uint8_t* mac_key_client() { return data_.mac_key_client; }
|
||||
@@ -85,13 +92,12 @@ class UsageTable {
|
||||
uint32_t* usage_entry_number);
|
||||
OEMCryptoResult LoadUsageEntry(SessionContext* session,
|
||||
UsageTableEntry** entry, uint32_t index,
|
||||
const std::vector<uint8_t>& buffer);
|
||||
OEMCryptoResult UpdateUsageEntry(SessionContext* session,
|
||||
UsageTableEntry* entry,
|
||||
uint8_t* header_buffer,
|
||||
size_t* header_buffer_length,
|
||||
uint8_t* entry_buffer,
|
||||
size_t* entry_buffer_length);
|
||||
const std::vector<uint8_t>& buffer,
|
||||
ODK_ClockValues* clock_values);
|
||||
OEMCryptoResult UpdateUsageEntry(
|
||||
SessionContext* session, UsageTableEntry* entry, uint8_t* header_buffer,
|
||||
size_t* header_buffer_length, uint8_t* entry_buffer,
|
||||
size_t* entry_buffer_length, ODK_ClockValues* clock_values);
|
||||
OEMCryptoResult MoveEntry(UsageTableEntry* entry, uint32_t new_index);
|
||||
OEMCryptoResult CreateUsageTableHeader(uint8_t* header_buffer,
|
||||
size_t* header_buffer_length);
|
||||
|
||||
@@ -319,7 +319,9 @@ void LicenseRoundTrip::FillAndVerifyCoreRequest(
|
||||
EXPECT_TRUE(
|
||||
oec_util::ParseLicenseRequest(core_message_string, &core_request_));
|
||||
EXPECT_EQ(global_features.api_version, core_request_.api_version);
|
||||
if (expect_request_has_correct_nonce_) {
|
||||
EXPECT_EQ(session()->nonce(), core_request_.nonce);
|
||||
}
|
||||
EXPECT_EQ(session()->session_id(), core_request_.session_id);
|
||||
if (api_version_ == 0) api_version_ = core_request_.api_version;
|
||||
}
|
||||
@@ -442,6 +444,7 @@ void LicenseRoundTrip::EncryptAndSignResponse() {
|
||||
for (size_t i = 0; i < encrypted_response_.size(); i++) {
|
||||
encrypted_response_[i] = i % 0x100;
|
||||
}
|
||||
ASSERT_GE(kMaxCoreMessage, serialized_core_message_.size());
|
||||
ASSERT_GE(encrypted_response_.size(), serialized_core_message_.size());
|
||||
memcpy(encrypted_response_.data(), serialized_core_message_.data(),
|
||||
serialized_core_message_.size());
|
||||
@@ -459,10 +462,20 @@ void LicenseRoundTrip::EncryptAndSignResponse() {
|
||||
}
|
||||
|
||||
OEMCryptoResult LicenseRoundTrip::LoadResponse() {
|
||||
// Some tests adjust the offset to be beyond the length of the message. Here,
|
||||
// we create a duplicate of the message buffer so that these offsets do not
|
||||
// point to garbage data. The goal is to make sure OEMCrypto is verifying that
|
||||
// the offset points outside of the message -- we don't want OEMCrypto to look
|
||||
// at what offset points to and return an error if the data is garbage. Since
|
||||
// the memory after the message buffer is an exact copy of the message, we can
|
||||
// increment the offset by the message size and get valid data.
|
||||
std::vector<uint8_t> double_message = encrypted_response_;
|
||||
double_message.insert(double_message.end(), encrypted_response_.begin(),
|
||||
encrypted_response_.end());
|
||||
OEMCryptoResult result;
|
||||
if (api_version_ < kCoreMessagesAPI) {
|
||||
result = OEMCrypto_LoadKeys(
|
||||
session_->session_id(), encrypted_response_.data(),
|
||||
session_->session_id(), double_message.data(),
|
||||
encrypted_response_.size(), response_signature_.data(),
|
||||
response_signature_.size(), core_response_.enc_mac_keys_iv,
|
||||
core_response_.enc_mac_keys, core_response_.key_array_length,
|
||||
@@ -471,7 +484,7 @@ OEMCryptoResult LicenseRoundTrip::LoadResponse() {
|
||||
static_cast<OEMCrypto_LicenseType>(core_response_.license_type));
|
||||
} else {
|
||||
result = OEMCrypto_LoadLicense(
|
||||
session_->session_id(), encrypted_response_.data(),
|
||||
session_->session_id(), double_message.data(),
|
||||
encrypted_response_.size(), serialized_core_message_.size(),
|
||||
response_signature_.data(), response_signature_.size());
|
||||
}
|
||||
@@ -480,15 +493,22 @@ OEMCryptoResult LicenseRoundTrip::LoadResponse() {
|
||||
// call SelectKey, use key control information, and so that it has key data
|
||||
// to verify decrypt operations.
|
||||
session_->set_license(response_data_);
|
||||
VerifyTestKeys();
|
||||
// Also, if the license has new mac keys, then install them now.
|
||||
if (core_response_.enc_mac_keys.length > 0) {
|
||||
session_->set_mac_keys(response_data_.mac_keys);
|
||||
}
|
||||
|
||||
// Note: we verify content licenses here. For entitlement license, we verify
|
||||
// the key control blocks after loading entitled content keys.
|
||||
if (license_type_ == OEMCrypto_ContentLicense) VerifyTestKeys();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// This function verifies that the key control block reported by OEMCrypto agree
|
||||
// with the truth key control block. Failures in this function probably
|
||||
// indicate the OEMCrypto_LoadKeys did not correctly process the key control
|
||||
// block.
|
||||
// indicate the OEMCrypto_LoadLicense/LoadKeys did not correctly process the key
|
||||
// control block.
|
||||
void LicenseRoundTrip::VerifyTestKeys() {
|
||||
for (unsigned int i = 0; i < num_keys_; i++) {
|
||||
KeyControlBlock block;
|
||||
@@ -512,6 +532,253 @@ void LicenseRoundTrip::VerifyTestKeys() {
|
||||
}
|
||||
}
|
||||
|
||||
void LicenseRoundTrip::SetKeyId(size_t index, const string& key_id) {
|
||||
ASSERT_LT(index, num_keys_);
|
||||
MessageKeyData& key = response_data_.keys[index];
|
||||
key.key_id_length = key_id.length();
|
||||
ASSERT_LE(key.key_id_length, kTestKeyIdMaxLength);
|
||||
memcpy(key.key_id, key_id.data(), key.key_id_length);
|
||||
}
|
||||
|
||||
void EntitledMessage::FillKeyArray() {
|
||||
for (size_t i = 0; i < license_messages_->num_keys(); ++i) {
|
||||
MakeOneKey(i);
|
||||
}
|
||||
}
|
||||
|
||||
void EntitledMessage::MakeOneKey(size_t entitlement_key_index) {
|
||||
ASSERT_LT(entitlement_key_index, kMaxNumKeys);
|
||||
ASSERT_LT(num_keys_, kMaxNumKeys);
|
||||
EntitledContentKeyData* key_data = &entitled_key_data_[num_keys_];
|
||||
MessageKeyData* entitlement_key =
|
||||
&license_messages_->response_data().keys[entitlement_key_index];
|
||||
OEMCrypto_EntitledContentKeyObject* offsets = &entitled_key_array_[num_keys_];
|
||||
num_keys_++;
|
||||
|
||||
key_data->key_index = entitlement_key_index;
|
||||
ASSERT_LE(entitlement_key->key_id_length, kTestKeyIdMaxLength);
|
||||
memcpy(key_data->entitlement_key_id, entitlement_key->key_id,
|
||||
entitlement_key->key_id_length);
|
||||
key_data->entitlement_key_id_length = entitlement_key->key_id_length;
|
||||
offsets->entitlement_key_id = FindSubstring(key_data->entitlement_key_id,
|
||||
entitlement_key->key_id_length);
|
||||
|
||||
key_data->content_key_id_length = kDefaultKeyIdLength;
|
||||
// Fill the key ID as CnCnCnCn... so it's easy to see in debug logs.
|
||||
memset(key_data->content_key_id, 0xC0 + num_keys_,
|
||||
key_data->content_key_id_length);
|
||||
offsets->content_key_id =
|
||||
FindSubstring(key_data->content_key_id, key_data->content_key_id_length);
|
||||
|
||||
EXPECT_EQ(1, GetRandBytes(key_data->content_key_data,
|
||||
sizeof(key_data->content_key_data)));
|
||||
// Note: we give the encrypted content key to OEMCrypto, not the clear
|
||||
// content key.
|
||||
offsets->content_key_data =
|
||||
FindSubstring(key_data->encrypted_content_key_data,
|
||||
sizeof(key_data->encrypted_content_key_data));
|
||||
|
||||
EXPECT_EQ(1, GetRandBytes(key_data->content_key_data_iv,
|
||||
sizeof(key_data->content_key_data_iv)));
|
||||
offsets->content_key_data_iv = FindSubstring(
|
||||
key_data->content_key_data_iv, sizeof(key_data->content_key_data_iv));
|
||||
}
|
||||
|
||||
void EntitledMessage::SetEntitlementKeyId(unsigned int index,
|
||||
const std::string& key_id) {
|
||||
ASSERT_LT(index, num_keys_);
|
||||
ASSERT_LE(key_id.size(), kTestKeyIdMaxLength);
|
||||
entitled_key_data_[index].entitlement_key_id_length = key_id.size();
|
||||
memcpy(entitled_key_data_[index].entitlement_key_id,
|
||||
reinterpret_cast<const uint8_t*>(key_id.c_str()), key_id.length());
|
||||
entitled_key_array_[index].entitlement_key_id = FindSubstring(
|
||||
entitled_key_data_[index].entitlement_key_id, key_id.length());
|
||||
}
|
||||
|
||||
OEMCrypto_Substring EntitledMessage::FindSubstring(const void* ptr,
|
||||
size_t size) {
|
||||
OEMCrypto_Substring substring{0, 0};
|
||||
if (ptr != nullptr) {
|
||||
substring.offset = reinterpret_cast<const uint8_t*>(ptr) -
|
||||
reinterpret_cast<const uint8_t*>(entitled_key_data_);
|
||||
substring.length = size;
|
||||
}
|
||||
return substring;
|
||||
}
|
||||
|
||||
void EntitledMessage::LoadKeys(OEMCryptoResult expected_sts) {
|
||||
for (size_t i = 0; i < num_keys_; ++i) {
|
||||
EntitledContentKeyData* key_data = &entitled_key_data_[i];
|
||||
const size_t entitlement_key_index = key_data->key_index;
|
||||
MessageKeyData* entitlement_key =
|
||||
&license_messages_->response_data().keys[entitlement_key_index];
|
||||
|
||||
// Load the entitlement key from |key_array_|.
|
||||
AES_KEY aes_key;
|
||||
AES_set_encrypt_key(entitlement_key->key_data, 256, &aes_key);
|
||||
|
||||
// Encrypt the content key with the entitlement key.
|
||||
uint8_t iv[16];
|
||||
memcpy(&iv[0], key_data->content_key_data_iv, KEY_IV_SIZE);
|
||||
AES_cbc_encrypt(key_data->content_key_data,
|
||||
key_data->encrypted_content_key_data, KEY_SIZE, &aes_key,
|
||||
iv, AES_ENCRYPT);
|
||||
}
|
||||
ASSERT_EQ(expected_sts,
|
||||
OEMCrypto_LoadEntitledContentKeys(
|
||||
license_messages_->session()->session_id(),
|
||||
reinterpret_cast<const uint8_t*>(entitled_key_data_),
|
||||
sizeof(entitled_key_data_), num_keys_, entitled_key_array_));
|
||||
if (expected_sts != OEMCrypto_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
VerifyEntitlementTestKeys();
|
||||
}
|
||||
|
||||
// This function verifies that the key control block reported by OEMCrypto agree
|
||||
// with the truth key control block. Failures in this function probably
|
||||
// indicate the OEMCrypto_LoadEntitledKeys did not correctly process the key
|
||||
// control block.
|
||||
void EntitledMessage::VerifyEntitlementTestKeys() {
|
||||
for (unsigned int i = 0; i < num_keys_; i++) {
|
||||
EntitledContentKeyData* key_data = &entitled_key_data_[i];
|
||||
const size_t entitlement_key_index = key_data->key_index;
|
||||
MessageKeyData* entitlement_key =
|
||||
&license_messages_->response_data().keys[entitlement_key_index];
|
||||
KeyControlBlock block;
|
||||
size_t size = sizeof(block);
|
||||
OEMCryptoResult sts = OEMCrypto_QueryKeyControl(
|
||||
license_messages_->session()->session_id(), key_data->content_key_id,
|
||||
key_data->content_key_id_length, reinterpret_cast<uint8_t*>(&block),
|
||||
&size);
|
||||
if (sts != OEMCrypto_ERROR_NOT_IMPLEMENTED) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
ASSERT_EQ(sizeof(block), size);
|
||||
// control duration and bits stored in network byte order. For printing
|
||||
// we change to host byte order.
|
||||
ASSERT_EQ((htonl_fnc(entitlement_key->control.duration)),
|
||||
(htonl_fnc(block.duration)))
|
||||
<< "For key " << i;
|
||||
ASSERT_EQ(htonl_fnc(entitlement_key->control.control_bits),
|
||||
htonl_fnc(block.control_bits))
|
||||
<< "For key " << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenewalRoundTrip::VerifyRequestSignature(
|
||||
const vector<uint8_t>& data, const vector<uint8_t>& generated_signature,
|
||||
size_t core_message_length) {
|
||||
ASSERT_EQ(HMAC_SHA256_SIGNATURE_SIZE, generated_signature.size());
|
||||
std::vector<uint8_t> expected_signature;
|
||||
if (license_messages_->api_version() < kCoreMessagesAPI) {
|
||||
// For v15 or earlier, we only sign the message body. Ignore the core
|
||||
// message.
|
||||
std::vector<uint8_t> subdata(data.begin() + core_message_length,
|
||||
data.end());
|
||||
session()->key_deriver().ClientSignBuffer(subdata, &expected_signature);
|
||||
} else {
|
||||
session()->key_deriver().ClientSignBuffer(data, &expected_signature);
|
||||
}
|
||||
ASSERT_EQ(expected_signature, generated_signature);
|
||||
}
|
||||
|
||||
void RenewalRoundTrip::FillAndVerifyCoreRequest(
|
||||
const std::string& core_message_string) {
|
||||
if (license_messages_->api_version() < kCoreMessagesAPI) {
|
||||
// For v15, we expect that no core request was created.
|
||||
EXPECT_FALSE(
|
||||
oec_util::ParseRenewalRequest(core_message_string, &core_request_));
|
||||
} else {
|
||||
EXPECT_TRUE(
|
||||
oec_util::ParseRenewalRequest(core_message_string, &core_request_));
|
||||
EXPECT_EQ(license_messages_->core_request().api_version,
|
||||
core_request_.api_version);
|
||||
EXPECT_EQ(license_messages_->core_request().nonce, core_request_.nonce);
|
||||
EXPECT_EQ(license_messages_->core_request().session_id,
|
||||
core_request_.session_id);
|
||||
}
|
||||
}
|
||||
|
||||
void RenewalRoundTrip::CreateDefaultResponse() {
|
||||
if (license_messages_->api_version() < kCoreMessagesAPI) {
|
||||
uint32_t control = 0;
|
||||
uint32_t nonce = 0;
|
||||
// If this is a v15 device, and a v15 license, and the license used a nonce,
|
||||
// then the response should require a new nonce, too.
|
||||
if (global_features.api_version < kCoreMessagesAPI &&
|
||||
(license_messages_->control() & wvoec::kControlNonceEnabled)) {
|
||||
control = wvoec::kControlNonceEnabled;
|
||||
session_->GenerateNonce();
|
||||
nonce = session_->nonce();
|
||||
}
|
||||
// A single key object with no key id should update all keys.
|
||||
constexpr size_t index = 0;
|
||||
response_data_.keys[index].key_id_length = 0;
|
||||
response_data_.keys[index].key_id[0] = '\0';
|
||||
std::string kcVersion = "kc" + std::to_string(core_request_.api_version);
|
||||
memcpy(response_data_.keys[index].control.verification, kcVersion.c_str(),
|
||||
4);
|
||||
const uint32_t duration = static_cast<uint32_t>(
|
||||
license_messages_->core_response()
|
||||
.timer_limits.renewal_playback_duration_seconds);
|
||||
response_data_.keys[index].control.duration = htonl(duration);
|
||||
response_data_.keys[index].control.nonce = htonl(nonce);
|
||||
response_data_.keys[index].control.control_bits = htonl(control);
|
||||
}
|
||||
}
|
||||
|
||||
void RenewalRoundTrip::EncryptAndSignResponse() {
|
||||
// Renewal messages are not encrypted.
|
||||
encrypted_response_data_ = response_data_;
|
||||
|
||||
// Stripe the encrypted message.
|
||||
encrypted_response_.resize(message_size_);
|
||||
for (size_t i = 0; i < encrypted_response_.size(); i++) {
|
||||
encrypted_response_[i] = i % 0x100;
|
||||
}
|
||||
// Either create a KeyRefreshObject for a call to RefreshKeys or a core
|
||||
// response for a call to LoadRenewal.
|
||||
if (license_messages_->api_version() < kCoreMessagesAPI) {
|
||||
refresh_object_.key_id = FindSubstring(nullptr, 0);
|
||||
refresh_object_.key_control_iv = FindSubstring(nullptr, 0);
|
||||
refresh_object_.key_control =
|
||||
FindSubstring(&response_data_.keys[0].control,
|
||||
sizeof(response_data_.keys[0].control));
|
||||
serialized_core_message_.resize(0);
|
||||
} else {
|
||||
ASSERT_TRUE(
|
||||
CreateCoreRenewalResponse(core_request_, &serialized_core_message_));
|
||||
}
|
||||
// Concatenate the core message and the response.
|
||||
ASSERT_GE(kMaxCoreMessage, serialized_core_message_.size());
|
||||
ASSERT_GE(encrypted_response_.size(), serialized_core_message_.size());
|
||||
memcpy(encrypted_response_.data(), serialized_core_message_.data(),
|
||||
serialized_core_message_.size());
|
||||
ASSERT_GE(encrypted_response_.size(),
|
||||
serialized_core_message_.size() + sizeof(encrypted_response_data_));
|
||||
memcpy(encrypted_response_.data() + serialized_core_message_.size(),
|
||||
reinterpret_cast<const uint8_t*>(&encrypted_response_data_),
|
||||
sizeof(encrypted_response_data_));
|
||||
session()->key_deriver().ServerSignBuffer(encrypted_response_.data(),
|
||||
encrypted_response_.size(),
|
||||
&response_signature_);
|
||||
}
|
||||
|
||||
OEMCryptoResult RenewalRoundTrip::LoadResponse() {
|
||||
if (license_messages_->api_version() < kCoreMessagesAPI) {
|
||||
return OEMCrypto_RefreshKeys(
|
||||
session_->session_id(), encrypted_response_.data(),
|
||||
encrypted_response_.size(), response_signature_.data(),
|
||||
response_signature_.size(), 1, &refresh_object_);
|
||||
} else {
|
||||
return OEMCrypto_LoadRenewal(
|
||||
session_->session_id(), encrypted_response_.data(),
|
||||
encrypted_response_.size(), serialized_core_message_.size(),
|
||||
response_signature_.data(), response_signature_.size());
|
||||
}
|
||||
}
|
||||
|
||||
Session::Session()
|
||||
: open_(false),
|
||||
forced_session_id_(false),
|
||||
@@ -859,13 +1126,6 @@ void Session::RefreshTestKeys(const size_t key_count, uint32_t control_bits,
|
||||
}
|
||||
}
|
||||
|
||||
void Session::SetKeyId(int index, const string& key_id) {
|
||||
MessageKeyData& key = license_.keys[index];
|
||||
key.key_id_length = key_id.length();
|
||||
ASSERT_LE(key.key_id_length, kTestKeyIdMaxLength);
|
||||
memcpy(key.key_id, key_id.data(), key.key_id_length);
|
||||
}
|
||||
|
||||
void Session::FillSimpleMessage(uint32_t duration, uint32_t control,
|
||||
uint32_t nonce, const std::string& pst) {
|
||||
EXPECT_EQ(
|
||||
|
||||
@@ -104,10 +104,14 @@ struct Test_PST_Report {
|
||||
};
|
||||
|
||||
struct EntitledContentKeyData {
|
||||
uint8_t entitlement_key_id[KEY_SIZE];
|
||||
uint8_t content_key_id[KEY_SIZE];
|
||||
uint8_t content_key_data_iv[KEY_SIZE];
|
||||
uint8_t entitlement_key_id[kTestKeyIdMaxLength];
|
||||
size_t entitlement_key_id_length;
|
||||
uint8_t content_key_id[kTestKeyIdMaxLength];
|
||||
size_t content_key_id_length;
|
||||
uint8_t content_key_data_iv[KEY_IV_SIZE];
|
||||
uint8_t content_key_data[KEY_SIZE];
|
||||
uint8_t encrypted_content_key_data[KEY_SIZE];
|
||||
size_t key_index; // Index into the license's key array. Only for testing.
|
||||
};
|
||||
|
||||
// returns 1 on success, -1 if not supported, or 0 if other failure.
|
||||
@@ -219,9 +223,10 @@ class RoundTrip {
|
||||
};
|
||||
|
||||
class ProvisioningRoundTrip
|
||||
: public RoundTrip<oec_util::ODK_ProvisioningRequest,
|
||||
: public RoundTrip</* CoreRequest */ oec_util::ODK_ProvisioningRequest,
|
||||
OEMCrypto_PrepAndSignProvisioningRequest,
|
||||
ODK_ParsedProvisioning, RSAPrivateKeyMessage> {
|
||||
/* CoreResponse */ ODK_ParsedProvisioning,
|
||||
/* ResponseData */ RSAPrivateKeyMessage> {
|
||||
public:
|
||||
ProvisioningRoundTrip(Session* session,
|
||||
const std::vector<uint8_t>& encoded_rsa_key)
|
||||
@@ -257,20 +262,21 @@ class ProvisioningRoundTrip
|
||||
std::vector<uint8_t> wrapped_rsa_key_;
|
||||
};
|
||||
|
||||
class LicenseRoundTrip : public RoundTrip<oec_util::ODK_LicenseRequest,
|
||||
class LicenseRoundTrip
|
||||
: public RoundTrip</* CoreRequest */ oec_util::ODK_LicenseRequest,
|
||||
OEMCrypto_PrepAndSignLicenseRequest,
|
||||
ODK_ParsedLicense, MessageData> {
|
||||
/* CoreResponse */ ODK_ParsedLicense,
|
||||
/* ResponseData */ MessageData> {
|
||||
public:
|
||||
LicenseRoundTrip(Session* session)
|
||||
: RoundTrip(session),
|
||||
key_array_(),
|
||||
license_request_hash_(),
|
||||
control_(wvoec::kControlNonceEnabled),
|
||||
num_keys_(4),
|
||||
pst_(""),
|
||||
minimum_srm_version_(0),
|
||||
update_mac_keys_(true),
|
||||
api_version_(0),
|
||||
expect_request_has_correct_nonce_(true),
|
||||
license_type_(OEMCrypto_ContentLicense) {}
|
||||
void CreateDefaultResponse() override;
|
||||
// Fill the |core_response| substrings.
|
||||
@@ -278,7 +284,6 @@ class LicenseRoundTrip : public RoundTrip<oec_util::ODK_LicenseRequest,
|
||||
void EncryptAndSignResponse() override;
|
||||
OEMCryptoResult LoadResponse() override;
|
||||
void VerifyTestKeys();
|
||||
const OEMCrypto_KeyObject* key_array() { return key_array_; }
|
||||
// Set the default key control block for all keys. This is used in
|
||||
// CreateDefaultResponse. The key control block determines the restrictions
|
||||
// that OEMCrypto should place on a key's use. For example, it specifies the
|
||||
@@ -286,24 +291,34 @@ class LicenseRoundTrip : public RoundTrip<oec_util::ODK_LicenseRequest,
|
||||
// video path. See the section "Key Control Block" in the document "Widevine
|
||||
// Modular DRM Security Integration Guide for CENC".
|
||||
void set_control(uint32_t control) { control_ = control; }
|
||||
uint32_t control() const { return control_; }
|
||||
// Set the number of keys to use in the license.
|
||||
void set_num_keys(uint32_t num_keys) { num_keys_ = num_keys; }
|
||||
uint32_t num_keys() { return num_keys_; }
|
||||
uint32_t num_keys() const { return num_keys_; }
|
||||
// Set the pst for the license.
|
||||
void set_pst(const std::string& pst) { pst_ = pst; }
|
||||
// Set the minimum SRM version for the license.
|
||||
void set_minimum_srm_version(uint32_t minimum_srm_version) {
|
||||
minimum_srm_version_ = minimum_srm_version;
|
||||
}
|
||||
// Change the hash of the core request. This should cause the response to be
|
||||
// rejected.
|
||||
void BreakRequestHash() { core_response_.request_hash[3] ^= 42; }
|
||||
// Set the API version for the license itself. This will be used in
|
||||
// CreateDefaultResponse.
|
||||
void set_api_version(uint32_t api_version) { api_version_ = api_version; }
|
||||
uint32_t api_version() const { return api_version_; }
|
||||
void set_update_mac_keys(bool update_mac_keys) {
|
||||
update_mac_keys_ = update_mac_keys;
|
||||
}
|
||||
void set_license_type(OEMCrypto_LicenseType license_type) {
|
||||
license_type_ = license_type;
|
||||
}
|
||||
// Skip the nonce check when verifying the license request.
|
||||
void skip_nonce_check() { expect_request_has_correct_nonce_ = false; }
|
||||
// This sets the key id of the specified key to the specified string.
|
||||
// This is used to test with different key id lengths.
|
||||
void SetKeyId(size_t index, const string& key_id);
|
||||
|
||||
protected:
|
||||
void VerifyRequestSignature(const vector<uint8_t>& data,
|
||||
@@ -313,10 +328,6 @@ class LicenseRoundTrip : public RoundTrip<oec_util::ODK_LicenseRequest,
|
||||
virtual void FillAndVerifyCoreRequest(
|
||||
const std::string& core_message_string) override;
|
||||
|
||||
// Array of key objects for this license.
|
||||
OEMCrypto_KeyObject key_array_[kMaxNumKeys];
|
||||
// The server's computed hash of the core license request.
|
||||
uint8_t license_request_hash_[ODK_SHA256_HASH_SIZE];
|
||||
// The default key control bits used with CreateDefaultResponse.
|
||||
uint32_t control_;
|
||||
// The number of keys in the license response.
|
||||
@@ -331,19 +342,29 @@ class LicenseRoundTrip : public RoundTrip<oec_util::ODK_LicenseRequest,
|
||||
// is signed, it will be set to the same as OEMCrypto's API version. It may
|
||||
// be set to a lower value in order to test backwards compatibility.
|
||||
uint32_t api_version_;
|
||||
// If true, then we expect the nonce in the core request to match that in
|
||||
// session. This is usually true, but when we are testing how OEMCrypto
|
||||
// handles a bad nonce, we don't want to.
|
||||
bool expect_request_has_correct_nonce_;
|
||||
// Whether this is a content license or an entitlement license. Used in
|
||||
// CreateDefaultResponse.
|
||||
OEMCrypto_LicenseType license_type_;
|
||||
};
|
||||
|
||||
class RenewalRoundTrip
|
||||
: public RoundTrip<oec_util::ODK_RenewalRequest,
|
||||
class RenewalRoundTrip : public RoundTrip<
|
||||
/* CoreRequest */ oec_util::ODK_RenewalRequest,
|
||||
OEMCrypto_PrepAndSignRenewalRequest,
|
||||
oec_util::ODK_RenewalRequest, // Response has same
|
||||
// information as request.
|
||||
MessageData> {
|
||||
// Renewal response info is same as request:
|
||||
/* CoreResponse */ oec_util::ODK_RenewalRequest,
|
||||
/* ResponseData */ MessageData> {
|
||||
public:
|
||||
RenewalRoundTrip(Session* session) : RoundTrip(session) {}
|
||||
RenewalRoundTrip(LicenseRoundTrip* license_messages)
|
||||
: RoundTrip(license_messages->session()),
|
||||
license_messages_(license_messages),
|
||||
refresh_object_() {}
|
||||
void CreateDefaultResponse() override;
|
||||
void EncryptAndSignResponse() override;
|
||||
OEMCryptoResult LoadResponse() override;
|
||||
|
||||
protected:
|
||||
void VerifyRequestSignature(const vector<uint8_t>& data,
|
||||
@@ -352,6 +373,34 @@ class RenewalRoundTrip
|
||||
// Verify the values of the core response.
|
||||
virtual void FillAndVerifyCoreRequest(
|
||||
const std::string& core_message_string) override;
|
||||
LicenseRoundTrip* license_messages_;
|
||||
OEMCrypto_KeyRefreshObject refresh_object_;
|
||||
};
|
||||
|
||||
class EntitledMessage {
|
||||
public:
|
||||
EntitledMessage(LicenseRoundTrip* license_messages)
|
||||
: license_messages_(license_messages), num_keys_() {}
|
||||
void FillKeyArray();
|
||||
void MakeOneKey(size_t entitlement_key_index);
|
||||
void LoadKeys(OEMCryptoResult expected_sts);
|
||||
void set_num_keys(uint32_t num_keys) { num_keys_ = num_keys; }
|
||||
uint32_t num_keys() const { return num_keys_; }
|
||||
void SetEntitlementKeyId(unsigned int index, const std::string& key_id);
|
||||
// Verify that key control blocks of the loaded keys.
|
||||
void VerifyEntitlementTestKeys();
|
||||
|
||||
private:
|
||||
// Find the offset of the give pointer, relative to |entitled_key_data_|.
|
||||
OEMCrypto_Substring FindSubstring(const void* ptr, size_t size);
|
||||
|
||||
LicenseRoundTrip* license_messages_;
|
||||
uint32_t num_keys_;
|
||||
// Clear Entitlement key data. This is the backing data for
|
||||
// |entitled_key_array_|.
|
||||
EntitledContentKeyData entitled_key_data_[kMaxNumKeys];
|
||||
// Entitled key object. Pointers are backed by |entitled_key_data_|.
|
||||
OEMCrypto_EntitledContentKeyObject entitled_key_array_[kMaxNumKeys];
|
||||
};
|
||||
|
||||
class Session {
|
||||
@@ -415,9 +464,6 @@ class Session {
|
||||
// server's mac key, and calls OEMCrypto_RefreshKeys.
|
||||
void RefreshTestKeys(const size_t key_count, uint32_t control_bits,
|
||||
uint32_t nonce, OEMCryptoResult expected_result);
|
||||
// This sets the key id in the current message data to the specified string.
|
||||
// This is used to test with different key id lengths.
|
||||
void SetKeyId(int index, const string& key_id);
|
||||
// This fills the data structure license_ with key information. This data
|
||||
// can be modified, and then should be encrypted and signed in EncryptAndSign
|
||||
// before being loaded in LoadTestKeys.
|
||||
@@ -622,6 +668,9 @@ class Session {
|
||||
// Pointer to buffer holding |encrypted_entitled_message_|
|
||||
const uint8_t* encrypted_entitled_message_ptr();
|
||||
const KeyDeriver& key_deriver() const { return key_deriver_; }
|
||||
void set_mac_keys(const uint8_t* mac_keys) {
|
||||
key_deriver_.set_mac_keys(mac_keys);
|
||||
}
|
||||
|
||||
private:
|
||||
bool open_;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user