diff --git a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp index 3b5f7ead..9fe77a7b 100644 --- a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp +++ b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp @@ -71,6 +71,9 @@ typedef OEMCryptoResult (*L1_GenerateSignature_t)(OEMCrypto_SESSION session, typedef OEMCryptoResult (*L1_PrepAndSignLicenseRequest_t)( OEMCrypto_SESSION session, uint8_t* message, size_t message_length, size_t* core_message_length, uint8_t* signature, size_t* signature_length); +typedef OEMCryptoResult (*L1_PrepAndSignLicenseRelease_t)( + OEMCrypto_SESSION session, uint8_t* message, size_t message_length, + size_t* core_message_length, uint8_t* signature, size_t* signature_length); typedef OEMCryptoResult (*L1_PrepAndSignRenewalRequest_t)( OEMCrypto_SESSION session, uint8_t* message, size_t message_length, size_t* core_message_length, uint8_t* signature, size_t* signature_length); @@ -185,6 +188,10 @@ typedef OEMCryptoResult (*L1_ReportUsage_t)(OEMCrypto_SESSION session, const uint8_t* pst, size_t pst_length, uint8_t* buffer, size_t* buffer_length); +typedef OEMCryptoResult (*L1_GetUsageEntryInfo_t)( + OEMCrypto_SESSION session, OEMCrypto_Usage_Entry_Status* status, + int64_t* seconds_since_license_received, + int64_t* seconds_since_first_decrypt); typedef OEMCrypto_ProvisioningMethod (*L1_GetProvisioningMethod_t)(); typedef OEMCryptoResult (*L1_GetOEMPublicCertificate_t)( uint8_t* public_cert, size_t* public_cert_length); @@ -349,6 +356,7 @@ struct FunctionPointers { L1_GenerateNonce_t GenerateNonce; L1_GenerateSignature_t GenerateSignature; L1_PrepAndSignLicenseRequest_t PrepAndSignLicenseRequest; + L1_PrepAndSignLicenseRelease_t PrepAndSignLicenseRelease; L1_PrepAndSignRenewalRequest_t PrepAndSignRenewalRequest; L1_PrepAndSignProvisioningRequest_t PrepAndSignProvisioningRequest; L1_LoadLicense_t LoadLicense; @@ -388,6 +396,7 @@ struct FunctionPointers { L1_UpdateUsageTable_t UpdateUsageTable; L1_DeactivateUsageEntry_t DeactivateUsageEntry; L1_ReportUsage_t ReportUsage; + L1_GetUsageEntryInfo_t GetUsageEntryInfo; L1_GetProvisioningMethod_t GetProvisioningMethod; L1_GetOEMPublicCertificate_t GetOEMPublicCertificate; L1_LoadOEMPrivateKey_t LoadOEMPrivateKey; @@ -976,6 +985,7 @@ class Adapter { LOOKUP_ALL( 9, GenerateRSASignature, OEMCrypto_GenerateRSASignature); LOOKUP( 8, 15, GenerateSignature, OEMCrypto_GenerateSignature); LOOKUP_ALL(16, PrepAndSignLicenseRequest, OEMCrypto_PrepAndSignLicenseRequest); + LOOKUP_ALL(16, PrepAndSignLicenseRelease, OEMCrypto_PrepAndSignLicenseRelease); LOOKUP_ALL(16, PrepAndSignRenewalRequest, OEMCrypto_PrepAndSignRenewalRequest); LOOKUP_ALL(16, PrepAndSignProvisioningRequest, OEMCrypto_PrepAndSignProvisioningRequest); LOOKUP_ALL( 8, Generic_Decrypt_V17, OEMCrypto_Generic_Decrypt_V17); @@ -1014,6 +1024,7 @@ class Adapter { LOOKUP_ALL(10, QueryKeyControl, OEMCrypto_QueryKeyControl); LOOKUP_ALL(16, LoadRenewal, OEMCrypto_LoadRenewal); LOOKUP_ALL( 9, ReportUsage, OEMCrypto_ReportUsage); + LOOKUP_ALL(19, GetUsageEntryInfo, OEMCrypto_GetUsageEntryInfo); LOOKUP_ALL( 8, SecurityLevel_V16, OEMCrypto_SecurityLevel_V16); LOOKUP_ALL(11, SecurityPatchLevel, OEMCrypto_Security_Patch_Level); LOOKUP_ALL(14, SelectKey, OEMCrypto_SelectKey); @@ -1139,6 +1150,7 @@ class Adapter { level3_.Generic_Verify_V17 = Level3_Generic_Verify_V17; level3_.DeactivateUsageEntry = Level3_DeactivateUsageEntry; level3_.ReportUsage = Level3_ReportUsage; + level3_GetUsageEntryInfo = Level3_GetUsageEntryInfo; level3_.GetProvisioningMethod = Level3_GetProvisioningMethod; level3_.GetOEMPublicCertificate = Level3_GetOEMPublicCertificate; level3_.SupportedCertificates = Level3_SupportedCertificates; @@ -1156,6 +1168,7 @@ class Adapter { level3_.LoadProvisioning_V18 = Level3_LoadProvisioning; level3_.PrepAndSignProvisioningRequest = Level3_PrepAndSignProvisioningRequest; level3_.PrepAndSignLicenseRequest = Level3_PrepAndSignLicenseRequest; + level3_.PrepAndSignLicenseRelease = Level3_PrepAndSignLicenseRelease; level3_.PrepAndSignRenewalRequest = Level3_PrepAndSignRenewalRequest; level3_.MaximumUsageTableHeaderSize = Level3_MaximumUsageTableHeaderSize; level3_.AllocateSecureBuffer = Level3_AllocateSecureBuffer; @@ -2066,6 +2079,12 @@ extern "C" OEMCryptoResult OEMCrypto_PrepAndSignLicenseRequest( return OEMCrypto_ERROR_NOT_IMPLEMENTED; } +extern "C" OEMCryptoResult OEMCrypto_PrepAndSignLicenseRelease( + OEMCrypto_SESSION session, uint8_t* message, size_t message_length, + size_t* core_message_length, uint8_t* signature, size_t* signature_length) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + extern "C" OEMCryptoResult OEMCrypto_PrepAndSignRenewalRequest( OEMCrypto_SESSION session, uint8_t* message, size_t message_length, size_t* core_message_length, uint8_t* signature, size_t* signature_length) { @@ -2720,6 +2739,13 @@ extern "C" OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session, buffer_length); } +extern "C" OEMCryptoResult OEMCrypto_GetUsageEntryInfo( + OEMCrypto_SESSION session, OEMCrypto_Usage_Entry_Status* status, + int64_t* seconds_since_license_received, + int64_t* seconds_since_first_decrypt) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + extern "C" OEMCryptoResult OEMCrypto_GetCurrentSRMVersion(uint16_t* version) { if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; // Level 3 can't load an SRM, so this just checkes Level 1. diff --git a/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h b/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h index 80be4662..0f086693 100644 --- a/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h +++ b/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h @@ -719,6 +719,8 @@ typedef enum OEMCrypto_SignatureHashAlgorithm { #define OEMCrypto_LoadLicense _oecc144 #define OEMCrypto_LoadProvisioning _oecc145 #define OEMCrypto_LoadProvisioningCast _oecc146 +#define OEMCrypto_PrepAndSignLicenseRelease _oecc147 +#define OEMCrypto_GetUsageEntryInfo _oecc148 // clang-format on /// @addtogroup initcontrol @@ -1076,6 +1078,80 @@ OEMCryptoResult OEMCrypto_PrepAndSignLicenseRequest( OEMCrypto_SESSION session, uint8_t* message, size_t message_length, size_t* core_message_size, uint8_t* signature, size_t* signature_length); +/** + * This function replaces both OEMCrypto_DeactivateUsageEntry and + * OEMCrypto_ReportUsage. As with other OEMCrypto_PrepAndSign* functions, it + * first verifies that the core_message_size is the right size. If not, it + * returns OEMCrypto_ERROR_SHORT_BUFFER. + + * OEMCrypto will change the status of the usage entry to InactiveUsed if it was + * Active, or InactiveUnused if it was Unused. This also increments the entry's + * generation number by 2, and the header's master generation number. The + * corresponding generation number in the usage table header is also incremented + * so that it matches the one in the entry. + * + * OEMCrypto will use ODK_PrepareCoreLicenseRelease to prepare the core + * message. If it returns OEMCrypto_SUCCESS, then OEMCrypto shall sign the + * message body using the DRM certificate's private key. If it returns an + * error, the error should be returned by OEMCrypto to the CDM layer. + * ODK_PrepareCoreLicenseRelease is described in the document "Widevine Core + * Message Serialization". + * + * This function generates a HMAC-SHA256 signature using the mac_key[client] + * for license release signing under the license server protocol for CENC. + * + * The key used for signing should be the mac_key[client] that was generated + * for this session or loaded for this session by + * OEMCrypto_LoadLicense() or OEMCrypto_LoadUsageEntry(). + * + * NOTE: if signature pointer is null and/or input signature_length is zero, + * this function returns OEMCrypto_ERROR_SHORT_BUFFER and sets output + * signature_length to the size needed to receive the output signature. + * + * @param[in] session: handle for the session to be used. + * @param[in,out] message: Pointer to memory for the entire message. Modified by + * OEMCrypto via the ODK library. + * @param[in] message_length: length of the entire message buffer. + * @param[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. + * @param[out] signature: pointer to memory to receive the computed signature. + * @param[in,out] signature_length: (in) length of the signature buffer, in + * bytes. (out) actual length of the signature, in bytes. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_INVALID_SESSION + * @retval OEMCrypto_ERROR_SHORT_BUFFER if signature buffer is not large enough + * to hold the signature. + * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED since OEMCrypto does not implement + * license release before v19 + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * @retval OEMCrypto_ERROR_SIGNATURE_FAILURE + * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE + * @retval OEMCrypto_ERROR_SESSION_LOST_STATE + * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * @buffer_size + * 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 is new in API version 19. + */ +OEMCryptoResult OEMCrypto_PrepAndSignLicenseRelease( + OEMCrypto_SESSION session, uint8_t* message, size_t message_length, + size_t* core_message_size, uint8_t* signature, size_t* signature_length); + /** * OEMCrypto will use ODK_PrepareCoreRenewalRequest, as described in the * document "Widevine Core Message Serialization", to prepare the core @@ -4647,6 +4723,36 @@ OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session, const uint8_t* pst, size_t pst_length, uint8_t* buffer, size_t* buffer_length); +/** + * Fetches information from a license release without performing any signatures + * or deactivating the license. + * + * @param[in] session: handle for the session to be used. + * @param[out] status: the enumeration of OEMCrypto_Usage_Entry_Status. + * @param[out] seconds_since_license_received: the time since the license being + * requested in seconds. + * @param[out] seconds_since_first_decrypt: the time since playback has + * started in seconds. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_INVALID_SESSION no open session with that id. + * @retval OEMCrypto_ERROR_INVALID_CONTEXT + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * + * @threading + * This is a "Usage Table Function" and will not be called simultaneously + * with any other function, as if the CDM holds a write lock on the OEMCrypto + * system. + * + * @version + * This method is new in API version 19. + */ +OEMCryptoResult OEMCrypto_GetUsageEntryInfo( + OEMCrypto_SESSION session, OEMCrypto_Usage_Entry_Status* status, + int64_t* seconds_since_license_received, + int64_t* seconds_since_first_decrypt); + /** * Moves the entry associated with the current session from one location in * the usage table header to another. This function is used by the CDM layer