/* 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. */ /********************************************************************* * odk.h * * OEMCrypto v16 Core Message Serialization library * * For Widevine Modular DRM, there are six message types between a server and * a client device: license request and response, provisioning request and * response, and renewal request and response. * * In OEMCrypto v15 and earlier, messages from the server were parsed by the * CDM layer above OEMCrypto; the CDM in turn gave OEMCrypto a collection of * pointers to protected data within the message. However, the pointers * themselves were not signed by the server. * * Starting from OEMCrypto v16, all fields used by OEMCrypto in each of these * messages have been identified in the document "Widevine Core Message * Serialization". These fields are called the core of the message. Core * message fields are (de)serialized using the ODK, a C library provided by * Widevine. OEMCrypto will parse and verify the core of the message with * help from the ODK. * * The ODK functions that parse code will fill out structs that have similar * formats to the function parameters of the OEMCrypto v15 functions being * replaced. The ODK will be provided in source code and it is Widevine's * intention that partners can build and link ODK with their implementation * of OEMCrypto with no or few code changes. * * OEMCrypto implementers shall build the ODK library as part of the Trusted * Application (TA) running in the TEE. All memory and buffers used by the * ODK library shall be sanitized by the OEMCrypto implementer to prevent * modification by any process running the REE. * * See the documents "Widevine Core Message Serialization" and "License * Duration and Renewal" for a detailed description of the ODK API. You can * find these documents in the widevine repository as * docs/Widevine_Core_Message_Serialization.pdf and * docs/License_Duration_and_Renewal.pdf * *********************************************************************/ #ifndef WIDEVINE_ODK_INCLUDE_ODK_H_ #define WIDEVINE_ODK_INCLUDE_ODK_H_ #include #include "OEMCryptoCENCCommon.h" #include "odk_structs.h" #ifdef __cplusplus extern "C" { #endif /* * ODK_InitializeSessionValues * * Description: * This function initializes the session's data structures. It shall be * called from OEMCrypto_OpenSession. * * Parameters: * [out] timer_limits: the session's timer limits. * [out] clock_values: the session's clock values. * [out] nonce_values: the session's ODK nonce values. * [in] api_major_version: the API version of OEMCrypto. * [in] session_id: the session id of the newly created session. * * Returns: * OEMCrypto_SUCCESS * OEMCrypto_ERROR_INVALID_CONTEXT * * Version: * This method is new in version 16 of the API. */ OEMCryptoResult ODK_InitializeSessionValues(ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values, ODK_NonceValues* nonce_values, uint32_t api_major_version, uint32_t session_id); /* * ODK_SetNonceValues * * Description: * This function sets the nonce value in the session's nonce structure. It * shall be called from OEMCrypto_GenerateNonce. * * Parameters: * [in/out] nonce_values: the session's nonce data. * [in] nonce: the new nonce that was just generated. * * Returns: * true on success * * Version: * This method is new in version 16 of the API. */ OEMCryptoResult ODK_SetNonceValues(ODK_NonceValues* nonce_values, uint32_t nonce); /* * ODK_InitializeClockValues * * Description: * This function initializes the clock values in the session clock_values * structure. It shall be called from OEMCrypto_PrepAndSignLicenseRequest. * * Parameters: * [in/out] clock_values: the session's clock data. * [in] system_time_seconds: the current time on OEMCrypto's monotonic clock. * * Returns: * OEMCrypto_SUCCESS * OEMCrypto_ERROR_INVALID_CONTEXT * * Version: * This method is new in version 16 of the API. */ OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values, uint64_t system_time_seconds); /* * ODK_ReloadClockValues * * Description: * This function sets the values in the clock_values structure. It shall be * called from OEMCrypto_LoadUsageEntry. When a usage entry from a v15 or * earlier license is loaded, the value time_of_license_loaded shall be used * in place of time_of_license_signed. * * Parameters: * [in/out] clock_values: the session's clock data. * [in] time_of_license_signed: the value time_license_received from the * loaded usage entry. * [in] time_of_first_decrypt: the value time_of_first_decrypt from the * loaded usage entry. * [in] time_of_last_decrypt: the value time_of_last_decrypt from the loaded * usage entry. * [in] status: the value status from the loaded usage entry. * [in] system_time_seconds: the current time on OEMCrypto's monotonic clock. * * Returns: * OEMCrypto_SUCCESS * OEMCrypto_ERROR_INVALID_CONTEXT * * Version: * This method is new in version 16 of the API. */ OEMCryptoResult ODK_ReloadClockValues(ODK_ClockValues* clock_values, uint64_t time_of_license_signed, uint64_t time_of_first_decrypt, uint64_t time_of_last_decrypt, enum OEMCrypto_Usage_Entry_Status status, uint64_t system_time_seconds); /* * ODK_AttemptFirstPlayback * * Description: * This updates the clock values, and determines if playback may start based * on the given system time. It uses the values in clock_values to determine * if this is the first playback for the license or the first playback for * just this session. * * This shall be called from the first call in a session to any of * OEMCrypto_DecryptCENC or any of the OEMCrypto_Generic* functions. * * If OEMCrypto uses a hardware timer, and this function returns * ODK_SET_TIMER, then the timer should be set to the value pointed to by * timer_value. * * Parameters: * [in] system_time_seconds: the current time on OEMCrypto's monotonic clock, * in seconds. * [in] timer_limits: timer limits specified in the license. * [in/out] clock_values: the sessions clock values. * [out] timer_value: set to the new timer value. Only used if the return * value is ODK_SET_TIMER. This must be non-null if OEMCrypto uses a * hardware timer. * * Returns: * ODK_SET_TIMER: Success. The timer should be reset to the specified value * and playback is allowed. * ODK_DISABLE_TIMER: Success, but disable timer. Unlimited playback is * allowed. * ODK_TIMER_EXPIRED: Set timer as disabled. Playback is not allowed. * * Version: * This method is new in version 16 of the API. */ OEMCryptoResult ODK_AttemptFirstPlayback(uint64_t system_time_seconds, const ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values, uint64_t* timer_value); /* * ODK_UpdateLastPlaybackTime * * Description: * Vendors that do not implement their own timer should call * ODK_UpdateLastPlaybackTime regularly during playback. This updates the * clock values, and determines if playback may continue based on the given * system time. This shall be called from any of OEMCrypto_DecryptCENC or any * of the OEMCrypto_Generic* functions. * * All Vendors (i.e. those that do or do not implement their own timer) shall * call ODK_UpdateLastPlaybackTime from the function * OEMCrypto_UpdateUsageEntry before updating the usage entry so that the * clock values are accurate. * * Parameters: * [in] system_time_seconds: the current time on OEMCrypto's monotonic clock, * in seconds. * [in] timer_limits: timer limits specified in the license. * [in/out] clock_values: the sessions clock values. * * Returns: * OEMCrypto_SUCCESS: Success. Playback is allowed. * ODK_TIMER_EXPIRED: Set timer as disabled. Playback is not allowed. * * Version: * This method is new in version 16 of the API. */ OEMCryptoResult ODK_UpdateLastPlaybackTime(uint64_t system_time_seconds, const ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values); /* * ODK_DeactivateUsageEntry * * Description: * This function modifies the session's clock values to indicate that the * license has been deactivated. It shall be called from * OEMCrypto_DeactivateUsageEntry * * Parameters: * [in/out] clock_values: the sessions clock values. * * Returns: * OEMCrypto_SUCCESS * OEMCrypto_ERROR_INVALID_CONTEXT * * Version: * This method is new in version 16 of the API. */ OEMCryptoResult ODK_DeactivateUsageEntry(ODK_ClockValues* clock_values); /* * ODK_PrepareCoreLicenseRequest * * Description: * Modifies the message to include a core license request at the beginning of * the message buffer. The values in nonce_values are used to populate the * message. * * This shall be called by OEMCrypto from OEMCrypto_PrepAndSignLicenseRequest. * * NOTE: if the message pointer is null and/or input core_message_size is * zero, this function returns OEMCrypto_ERROR_SHORT_BUFFER and sets output * core_message_size to the size needed. * * Parameters: * [in/out] message: Pointer to memory for the entire message. Modified by * the ODK library. * [in] message_length: length of the entire message buffer. * [in/out] core_message_size: length of the core message at the beginning of * the message. (in) size of buffer reserved for the core message, in * bytes. (out) actual length of the core message, in bytes. * [in] nonce_values: pointer to the session's nonce data. * * Returns: * OEMCrypto_SUCCESS * OEMCrypto_ERROR_SHORT_BUFFER: core_message_size is too small * OEMCrypto_ERROR_INVALID_CONTEXT * * Version: * This method is new in version 16 of the API. */ OEMCryptoResult ODK_PrepareCoreLicenseRequest( uint8_t* message, size_t message_length, size_t* core_message_size, const ODK_NonceValues* nonce_values); /* * ODK_PrepareCoreRenewalRequest * * Description: * Modifies the message to include a core renewal request at the beginning of * the message buffer. The values in nonce_values, clock_values and * system_time_seconds are used to populate the message. The nonce_values * should match those from the license. * * This shall be called by OEMCrypto from OEMCrypto_PrepAndSignRenewalRequest. * * If status in clock_values indicates that a license has not been loaded, * then this is a license release. The ODK library will change the value of * nonce_values.api_major_version to 15. This will make * OEMCrypto_PrepAndSignRenewalRequest sign just the message body, as it does * for all legacy licenses. * * NOTE: if the message pointer is null and/or input core_message_size is * zero, this function returns OEMCrypto_ERROR_SHORT_BUFFER and sets output * core_message_size to the size needed. * * Parameters: * [in/out] message: Pointer to memory for the entire message. Modified by * the ODK library. * [in] message_length: length of the entire message buffer. * [in/out] core_message_size: length of the core message at the beginning of * the message. (in) size of buffer reserved for the core message, in * bytes. (out) actual length of the core message, in bytes. * [in/out] nonce_values: pointer to the session's nonce data. * [in/out] clock_values: the session's clock values. * [in] system_time_seconds: the current time on OEMCrypto's clock, in * seconds. * * Returns: * OEMCrypto_SUCCESS * OEMCrypto_ERROR_SHORT_BUFFER: core_message_size is too small * OEMCrypto_ERROR_INVALID_CONTEXT * * Version: * This method is new in version 16 of the API. */ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message, size_t message_length, size_t* core_message_size, ODK_NonceValues* nonce_values, ODK_ClockValues* clock_values, uint64_t system_time_seconds); /* * ODK_PrepareCoreProvisioningRequest * * Description: * Modifies the message to include a core provisioning request at the * beginning of the message buffer. The values in nonce_values are used to * populate the message. * * This shall be called by OEMCrypto from * OEMCrypto_PrepAndSignProvisioningRequest. * * The buffer device_id shall be the same string returned by * OEMCrypto_GetDeviceID. The device ID shall be unique to the device, and * stable across reboots and factory resets for an L1 device. * * NOTE: if the message pointer is null and/or input core_message_size is * zero, this function returns OEMCrypto_ERROR_SHORT_BUFFER and sets output * core_message_size to the size needed. * * Parameters: * [in/out] message: Pointer to memory for the entire message. Modified by * the ODK library. * [in] message_length: length of the entire message buffer. * [in/out] core_message_size: length of the core message at the beginning of * the message. (in) size of buffer reserved for the core message, in * bytes. (out) actual length of the core message, in bytes. * [in] nonce_values: pointer to the session's nonce data. * [in] device_id: For devices with a keybox, this is the device ID from the * keybox. For devices with an OEM Certificate, this is a device unique * id string. * [in] device_id_length: length of device_id. The device ID can be at most * 64 bytes. * * Returns: * OEMCrypto_SUCCESS * OEMCrypto_ERROR_SHORT_BUFFER: core_message_size is too small * OEMCrypto_ERROR_INVALID_CONTEXT * * Version: * This method is new in version 16 of the API. */ OEMCryptoResult ODK_PrepareCoreProvisioningRequest( uint8_t* message, size_t message_length, size_t* core_message_size, const ODK_NonceValues* nonce_values, const uint8_t* device_id, size_t device_id_length); /* * ODK_InitializeV15Values * * Description: * This function sets all limits in the timer_limits struct to the * key_duration and initializes the other values. The field * nonce_values.api_major_version will be set to 15. It shall be called from * OEMCrypto_LoadKeys when loading a legacy license. * * Parameters: * [out] timer_limits: The session's timer limits. * [in/out] clock_values: The session's clock values. * [in/out] nonce_values: The session's ODK nonce values. * [in] key_duration: The duration from the first key's key control block. In * practice, the key duration is the same for all keys and is the same * as the license duration. * [in] system_time_seconds: The current time on the system clock, as * described in the document "License Duration and Renewal". * * Returns: * OEMCrypto_SUCCESS * OEMCrypto_ERROR_INVALID_CONTEXT * * Version: * This method is new in version 16 of the API. */ OEMCryptoResult ODK_InitializeV15Values(ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values, ODK_NonceValues* nonce_values, uint32_t key_duration, uint64_t system_time_seconds); /* * ODK_RefreshV15Values * * Description: * This function updates the clock_values as needed if a v15 renewal is * accepted. The field nonce_values.api_major_version is verified to be 15. * * This is called from OEMCrypto_RefreshKeys for a valid license renewal. * OEMCrypto shall pass in the current system time, and the key duration from * the first object in the OEMCrypto_KeyRefreshObject. * * Parameters: * [in] timer_limits: The session's timer limits. * [in/out] clock_values: The session's clock values. * [in] nonce_values: The session's ODK nonce values. * [in] system_time_seconds: The current time on the system clock, as * described in the document "License Duration and Renewal". * [in] new_key_duration: The duration from the first * OEMCrypto_KeyRefreshObject in key_array. * [out] timer_value: set to the new timer value. Only used if the return * value is ODK_SET_TIMER. This must be non-null if OEMCrypto uses a * hardware timer. * * Returns: * OEMCrypto_SUCCESS * OEMCrypto_ERROR_UNKNOWN_FAILURE * ODK_SET_TIMER: Success. The timer should be reset to the specified value * and playback is allowed. * ODK_DISABLE_TIMER: Success, but disable timer. Unlimited playback is * allowed. * ODK_TIMER_EXPIRED: Set timer as disabled. Playback is not allowed. * * Version: * This method is new in version 16 of the API. */ OEMCryptoResult ODK_RefreshV15Values(const ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values, const ODK_NonceValues* nonce_values, uint64_t system_time_seconds, uint32_t new_key_duration, uint64_t* timer_value); /* * ODK_ParseLicense * * Description: * The function ODK_ParseLicense will parse the message and verify fields in * the message. * * If the message does not parse correctly, ODK_VerifyAndParseLicense will * return ODK_ERROR_CORE_MESSAGE that OEMCrypto should return to the CDM * layer above. * * If the API in the message is not 16, then ODK_UNSUPPORTED_API is returned. * * If initial_license_load is true, and nonce_required in the license is * true, then the ODK library shall verify that nonce_values->nonce and * nonce_values->session_id are the same as those in the message. If * verification fails, then it shall return OEMCrypto_ERROR_INVALID_NONCE. * * If initial_license_load is false, and nonce_required is true, then * ODK_ParseLicense will set the values in nonce_values from those in the * message. * * The function ODK_ParseLicense will verify that each substring points to a * location in the message body. The message body is the buffer starting at * message + core_message_length with size message_length - * core_message_length. * * If initial_license_load is true, then ODK_ParseLicense shall verify that * the parameter request_hash matches request_hash in the parsed license. If * verification fails, then it shall return ODK_ERROR_CORE_MESSAGE. This was * computed by OEMCrypto when the license was requested. * * If usage_entry_present is true, then ODK_ParseLicense shall verify that * the pst in the license has a nonzero length. * * Parameters: * [in] message: pointer to the message buffer. * [in] message_length: length of the entire message buffer. * [in] core_message_size: length of the core message, at the beginning of * the message buffer. * [in] initial_license_load: true when called for OEMCrypto_LoadLicense and * false when called for OEMCrypto_ReloadLicense. * [in] usage_entry_present: true if the session has a new usage entry * associated with it created via OEMCrypto_CreateNewUsageEntry. * [in] request_hash: the hash of the license request core message. This was * computed by OEMCrypto when the license request was signed. * [in/out] timer_limits: The session's timer limits. These will be updated. * [in/out] clock_values: The session's clock values. These will be updated. * [in/out] nonce_values: The session's nonce values. These will be updated. * [out] parsed_license: the destination for the data. * * Returns: * OEMCrypto_SUCCESS * ODK_ERROR_CORE_MESSAGE: if the message did not parse correctly, or there * were other incorrect values. An error should be returned to the CDM * layer. * ODK_UNSUPPORTED_API * OEMCrypto_ERROR_INVALID_NONCE * * Version: * This method is new in version 16 of the API. */ OEMCryptoResult ODK_ParseLicense( const uint8_t* message, size_t message_length, size_t core_message_length, bool initial_license_load, bool usage_entry_present, const uint8_t request_hash[ODK_SHA256_HASH_SIZE], ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values, ODK_NonceValues* nonce_values, ODK_ParsedLicense* parsed_license); /* * ODK_ParseRenewal * * Description: * The function ODK_ParseRenewal will parse the message and verify its * contents. If the message does not parse correctly, an error of * ODK_ERROR_CORE_MESSAGE is returned. * * ODK_ParseRenewal shall verify that all fields in nonce_values match those * in the license. Otherwise it shall return OEMCrypto_ERROR_INVALID_NONCE. * * After parsing the message, this function updates the clock_values based on * the timer_limits and the current system time. If playback may not * continue, then ODK_TIMER_EXPIRED is returned. * * If playback may continue, a return value of ODK_SET_TIMER or * ODK_TIMER_EXPIRED is returned. If the return value is ODK_SET_TIMER, then * playback may continue until the timer expires. If the return value is * ODK_DISABLE_TIMER, then playback time is not limited. * * If OEMCrypto uses a hardware timer, and this function returns * ODK_SET_TIMER, then OEMCrypto shall set the timer to the value pointed to * by timer_value. * * Parameters: * [in] message: pointer to the message buffer. * [in] message_length: length of the entire message buffer. * [in] core_message_size: length of the core message, at the beginning of * the message buffer. * [in] nonce_values: pointer to the session's nonce data. * [in] system_time_seconds: the current time on OEMCrypto's clock, in * seconds. * [in] timer_limits: timer limits specified in the license. * [in/out] clock_values: the sessions clock values. * [out] timer_value: set to the new timer value. Only used if the return * value is ODK_SET_TIMER. This must be non-null if OEMCrypto uses a * hardware timer. * * Returns: * ODK_ERROR_CORE_MESSAGE: the message did not parse correctly, or there were * other incorrect values. An error should be returned to the CDM layer. * 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 disabled. Playback is not allowed. * ODK_UNSUPPORTED_API * ODK_STALE_RENEWAL: This renewal is not the most recently signed. It is * rejected. * OEMCrypto_ERROR_INVALID_NONCE * * Version: * This method is new in version 16 of the API. */ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length, size_t core_message_length, const ODK_NonceValues* nonce_values, uint64_t system_time_seconds, const ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values, uint64_t* timer_value); /* * ODK_ParseProvisioning * * Description: * The function ODK_ParseProvisioning will parse the message and verify the * nonce values match those in the license. * * If the message does not parse correctly, ODK_ParseProvisioning will return * an error that OEMCrypto should return to the CDM layer above. * * If the API in the message is larger than 16, then ODK_UNSUPPORTED_API is * returned. * * ODK_ParseProvisioning shall verify that nonce_values->nonce and * nonce_values->session_id are the same as those in the message. Otherwise * it shall return OEMCrypto_ERROR_INVALID_NONCE. * * The function ODK_ParseProvisioning will verify that each substring points * to a location in the message body. The message body is the buffer starting * at message + core_message_length with size message_length - * core_message_length. * * Parameters: * [in] message: pointer to the message buffer. * [in] message_length: length of the entire message buffer. * [in] core_message_size: length of the core message, at the beginning of * the message buffer. * [in] nonce_values: pointer to the session's nonce data. * [in] device_id: a pointer to a buffer containing the device ID of the * device. The ODK function will verify it matches that in the message. * [in] device_id_length: the length of the device ID. * [out] parsed_response: destination for the parse data. * * Returns: * OEMCrypto_SUCCESS * ODK_ERROR_CORE_MESSAGE: the message did not parse correctly, or there were * other incorrect values. An error should be returned to the CDM layer. * ODK_UNSUPPORTED_API * OEMCrypto_ERROR_INVALID_NONCE * * Version: * This method is new in version 16 of the API. */ OEMCryptoResult ODK_ParseProvisioning( const uint8_t* message, size_t message_length, size_t core_message_length, const ODK_NonceValues* nonce_values, const uint8_t* device_id, size_t device_id_length, ODK_ParsedProvisioning* parsed_response); #ifdef __cplusplus } #endif #endif /* WIDEVINE_ODK_INCLUDE_ODK_H_ */