diff --git a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp index 7f87950b..d4b07738 100644 --- a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp +++ b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp @@ -605,7 +605,7 @@ extern "C" OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session, extern "C" OEMCryptoResult OEMCrypto_DecryptCTR( OEMCrypto_SESSION session, const uint8_t* data_addr, size_t data_length, bool is_encrypted, const uint8_t* iv, size_t offset, - const OEMCrypto_DestBufferDesc* out_buffer, uint8_t subsample_flags) { + OEMCrypto_DestBufferDesc* out_buffer, uint8_t subsample_flags) { if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; diff --git a/libwvdrmengine/docs/WidevineModularDRMSecurityIntegrationGuideforCENC.pdf b/libwvdrmengine/docs/WidevineModularDRMSecurityIntegrationGuideforCENC.pdf index 6da38c8d..f9173377 100644 Binary files a/libwvdrmengine/docs/WidevineModularDRMSecurityIntegrationGuideforCENC.pdf and b/libwvdrmengine/docs/WidevineModularDRMSecurityIntegrationGuideforCENC.pdf differ diff --git a/libwvdrmengine/docs/WidevineSecurityIntegrationGuideforCENCAndroidSupplement.pdf b/libwvdrmengine/docs/WidevineSecurityIntegrationGuideforCENCAndroidSupplement.pdf index a85247da..5bb966da 100644 Binary files a/libwvdrmengine/docs/WidevineSecurityIntegrationGuideforCENCAndroidSupplement.pdf and b/libwvdrmengine/docs/WidevineSecurityIntegrationGuideforCENCAndroidSupplement.pdf differ diff --git a/libwvdrmengine/level3/arm/libwvlevel3.a b/libwvdrmengine/level3/arm/libwvlevel3.a index fbffe0cd..101a2c7d 100644 Binary files a/libwvdrmengine/level3/arm/libwvlevel3.a and b/libwvdrmengine/level3/arm/libwvlevel3.a differ diff --git a/libwvdrmengine/level3/x86/libwvlevel3.a b/libwvdrmengine/level3/x86/libwvlevel3.a index a7b3fc3f..d85fb29e 100644 Binary files a/libwvdrmengine/level3/x86/libwvlevel3.a and b/libwvdrmengine/level3/x86/libwvlevel3.a differ diff --git a/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h b/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h index f55a3c6f..3a268acb 100644 --- a/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h +++ b/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h @@ -234,6 +234,18 @@ typedef enum RSA_Padding_Scheme { kSign_PKCS1_Block1 = 0x2, // PKCS1 with block type 1 padding (only). } RSA_Padding_Scheme; +/* + * OEMCrypto_HDCP_Capability is used in the key control block to enforce HDCP + * level, and in GetHDCPCapability for reporting. + */ +typedef enum OEMCrypto_HDCP_Capability { + HDCP_NONE = 0, // No HDCP supported, no secure data path. + HDCP_V1 = 1, // HDCP version 1.0 + HDCP_V2 = 2, // HDCP version 2.0 + HDCP_V2_1 = 3, // HDCP version 2.1 + HDCP_V2_2 = 4, // HDCP version 2.2 + HDCP_NO_DIGITAL_OUTPUT = 0xff // No digital output. +} OEMCrypto_HDCP_Capability; /* * Obfuscation Renames. @@ -265,7 +277,7 @@ typedef enum RSA_Padding_Scheme { #define OEMCrypto_Generic_Decrypt _oecc25 #define OEMCrypto_Generic_Sign _oecc26 #define OEMCrypto_Generic_Verify _oecc27 -#define OEMCrypto_GetHDCPCapability _oecc28 +#define OEMCrypto_GetHDCPCapability_V9 _oecc28 #define OEMCrypto_SupportsUsageTable _oecc29 #define OEMCrypto_UpdateUsageTable _oecc30 #define OEMCrypto_DeactivateUsageEntry _oecc31 @@ -275,6 +287,14 @@ typedef enum RSA_Padding_Scheme { #define OEMCrypto_LoadKeys _oecc35 #define OEMCrypto_GenerateRSASignature _oecc36 #define OEMCrypto_GetMaxNumberOfSessions _oecc37 +#define OEMCrypto_GetNumberOfOpenSessions _oecc38 +#define OEMCrypto_IsAntiRollbackHwPresent _oecc39 +#define OEMCrypto_CopyBuffer _oecc40 +#define OEMCrypto_QueryKeyControl _oecc41 +#define OEMCrypto_LoadTestKeybox _oecc42 +#define OEMCrypto_ForceDeleteUsageEntry _oecc43 +#define OEMCrypto_GetHDCPCapability _oecc44 + /* * OEMCrypto_Initialize @@ -769,6 +789,60 @@ OEMCrypto_RefreshKeys(OEMCrypto_SESSION session, size_t num_keys, const OEMCrypto_KeyRefreshObject* key_array); +/* + * OEMCrypto_QueryKeyControl + * + * Description: + * Returns the decrypted key control block for the given key_id. This function + * is for application developers to debug license server and key timelines. + * It only returns a key control block if LoadKeys was successful, otherwise + * it returns OEMCrypto_ERROR_NO_CONTENT_KEY. The developer of the OEMCrypto + * library must be careful that the keys themselves are not accidentally + * revealed. + * + * Note: + * Returns control block in original, network byte order. If OEMCrypto + * converts fields to host byte order internally for storage, it should + * convert them back. Since OEMCrypto might not store the nonce or validation + * fields, values of 0 may be used instead. + * + * Verification + * The following checks should be performed. + * 1) If key_id is null, return OEMCrypto_ERROR_INVALID_CONTEXT. + * 2) If key_control_block_length is null, return OEMCrypto_ERROR_INVALID_CONTEXT. + * 3) If *key_control_block_length is less than the length of a key control block, + * set it to the correct value, and return OEMCrypto_ERROR_SHORT_BUFFER. + * 4) If key_control_block is null, return OEMCrypto_ERROR_INVALID_CONTEXT. + * 5) If the specified key has not been loaded, return + * OEMCrypto_ERROR_NO_CONTENT_KEY. + * + * Parameters + * key_id (in) - The unique id of the key of interest. + * key_id_length (in) - The length of key_id, in bytes. + * key_control_block(out) - A caller-owned buffer. + * key_control_block_length (in/out) - The length of key_control_block buffer. + * + * Returns + * OEMCrypto_SUCCESS + * OEMCrypto_ERROR_INVALID_CONTEXT + * OEMCrypto_ERROR_SHORT_BUFFER + * OEMCrypto_ERROR_NO_CONTENT_KEY + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * + * Threading + * This function may be called simultaneously with functions on other sessions, + * but not with other functions on this session. + * + * Version + * This method is added in API version 10. + */ +OEMCryptoResult +OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session, + const uint8_t* key_id, + size_t key_id_length, + uint8_t* key_control_block, + size_t* key_control_block_length); + /* * OEMCrypto_SelectKey * @@ -818,7 +892,7 @@ OEMCrypto_RefreshKeys(OEMCrypto_SESSION session, * Version: * This method changed in API version 8. */ -OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session, +OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, const uint8_t* key_id, size_t key_id_length); @@ -922,10 +996,10 @@ OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session, * decrypted byte stream. See OEMCrypto_DestbufferDesc for details. * subsample_flags (in) - bitwise flags indicating if this is the first, middle, * or last subsample in a chunk of data. + * 0 = neither first nor last subsample, * 1 = first subsample, * 2 = last subsample, - * 3 = both first and last subsample, - * 0 = neither first nor last subsample. + * 3 = both first and last subsample. * * Threading: * This function may be called simultaneously with functions on other sessions, @@ -951,7 +1025,70 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session, bool is_encrypted, const uint8_t *iv, size_t block_offset, - const OEMCrypto_DestBufferDesc* out_buffer, + OEMCrypto_DestBufferDesc* out_buffer, + uint8_t subsample_flags); + + +/* + * OEMCrypto_CopyBuffer + * + * Description: + * Copies the payload in the buffer referenced by the *data_addr parameter into + * the buffer referenced by the out_buffer parameter. The data is simply + * copied. The definition of OEMCrypto_DestBufferDesc and subsample_flags are + * the same as in OEMCrypto_DecryptCTR, above. + * + * The main difference between this and DecryptCTR is that this function does + * not need an open session, and it may be called concurrently with other + * session functions on a multithreaded system. In particular, an application + * will use this to copy the clear leader of a video to a secure buffer while + * the license request is being generated, sent to the server, and the response + * is being processed. This functionality is needed because an application may + * not have read or write access to a secure destination buffer. + * + * NOTES: + * + * This method may be called several times before the data is used. The + * first buffer in a chunk of data will have the OEMCrypto_FirstSubsample bit + * set in subsample_flags. The last buffer in a chunk of data will have the + * OEMCrypto_LastSubsample bit set in subsample_flags. The data will not be + * used until after OEMCrypto_LastSubsample has been set. If an + * implementation copies data immediately, it may ignore subsample_flags. + * + * If the destination buffer is secure, an offset may be specified. + * CopyBuffer begins storing data out_buffer->secure.offset bytes after the + * beginning of the secure buffer. + * + * Verification + * The following checks should be performed. + * 1. If either data_addr or out_buffer is null, return + * OEMCrypto_ERROR_INVALID_CONTEXT. + * + * Parameters + * data_addr (in) - An unaligned pointer to the buffer to be copied. + * data_length (in) - The length of the buffer, in bytes. + * out_buffer (out) - A caller-owned descriptor that specifies the handling of + * the byte stream. See OEMCrypto_DestbufferDesc for details. + * subsample_flags (in) - bitwise flags indicating if this is the first, middle, + * or last subsample in a chunk of data. + * 0 = neither first nor last subsample, + * 1 = first subsample, + * 2 = last subsample, + * 3 = both first and last subsample. + * + * Returns + * OEMCrypto_SUCCESS + * OEMCrypto_ERROR_INVALID_CONTEXT + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * + * Threading + * This function may be called simultaneously with any other functions. + * Version + * This method is added in API version 10. + */ +OEMCryptoResult OEMCrypto_CopyBuffer(const uint8_t *data_addr, + size_t data_length, + OEMCrypto_DestBufferDesc* out_buffer, uint8_t subsample_flags); /* @@ -981,8 +1118,8 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session, * wrappedKeybox (out) – Pointer to wrapped keybox * wrappedKeyboxLength (out) – Pointer to the length of the wrapped keybox in bytes * transportKey (in) – Optional. AES transport key. If provided, the keybox - * parameter was previously encrypted with this key. The keybox will be - * decrypted with the transport key using AES-CBC and a null IV. + * parameter was previously encrypted with this key. The keybox will be + * decrypted with the transport key using AES-CBC and a null IV. * transportKeyLength (in) – Optional. Number of bytes in the transportKey, if used. * * Threading: @@ -1038,6 +1175,35 @@ OEMCryptoResult OEMCrypto_WrapKeybox(const uint8_t *keybox, OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t *keybox, size_t keyBoxLength); +/* + * OEMCrypto_LoadTestKeybox + * + * Description: + * Temporarily use the standard test keybox in place of the factory provisioned + * keybox for all functions that use keybox keys or data. This allows a + * standard suite of unit tests to be run on a production device without + * permanently changing the keybox. This keybox will persist until the next + * call to OEMCrypto_Terminate or OEMCrypto_Initialize. Upon initialization, + * revert to using the factory provisioned keybox. + * + * The test keybox can be found in the reference implementation. + * + * Parameters + * none + * + * Returns + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * + * Threading + * This function is not called simultaneously with any other functions. + * It will be called just after OEMCrypto_Initialize(). + * + * Version + * This method is added in API version 10. + */ +OEMCryptoResult OEMCrypto_LoadTestKeybox(); + /* * OEMCrypto_IsKeyboxValid * @@ -1183,7 +1349,7 @@ OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, * 1. Check that all the pointer values passed into it are within the buffer * specified by message and message_length. * 2. Verify that in_wrapped_rsa_key_length is large enough to hold the rewrapped - * key, returning OEMCRYPTO_ERROR_BUFFER_TOO_SMALL otherwise. + * key, returning OEMCrypto_ERROR_SHORT_BUFFER otherwise. * 3. Verify that the nonce matches one generated by a previous call to * OEMCrypto_GenerateNonce(). The matching nonce shall be removed from the nonce * table. If there is no matching nonce, return OEMCRYPTO_ERROR_INVALID_NONCE. @@ -1494,14 +1660,6 @@ const char* OEMCrypto_SecurityLevel(); * Returns the maximum HDCP version supported by the device, and the HDCP version * supported by the device and any connected display. * - * Valid values for HDCP_Capability are: - * 0x0 - No HDCP supported, no secure data path. - * 0x1 - HDCP version 1.0 - * 0x2 - HDCP version 2.0 - * 0x3 - HDCP version 2.1 - * 0x4 - HDCP version 2.2 - * 0xFF - No HDCP device attached/using local display with secure path. - * * Parameters: * current (out) - this is the current HDCP version, based on the device itself, * and the display to which it is connected. @@ -1516,9 +1674,8 @@ const char* OEMCrypto_SecurityLevel(); * OEMCrypto_ERROR_UNKNOWN_FAILURE * * Version: - * This method changed in API version 9. + * This method changed in API version 10. */ -typedef uint8_t OEMCrypto_HDCP_Capability; OEMCryptoResult OEMCrypto_GetHDCPCapability(OEMCrypto_HDCP_Capability *current, OEMCrypto_HDCP_Capability *maximum); @@ -1545,7 +1702,82 @@ OEMCryptoResult OEMCrypto_GetHDCPCapability(OEMCrypto_HDCP_Capability *current, bool OEMCrypto_SupportsUsageTable(); /* - * OEMCryptoResult OEMCrypto_Generic_Encrypt + * OEMCrypto_IsAntiRollbackHwPresent() + * + * Description: + + * Indicate whether there is hardware protection to prevent the rollback of + * the usage table. For example, this is true if the usage table is stored + * entirely on a secure file system that the user cannot read or write to. + * Another example is if the usage table has a generation number and the + * generation number is stored in secure memory that is not user accessible. + * + * Parameters: + * none. + * + * Threading: + * This function may be called simultaneously with any other functions. + * + * Returns: + * Returns true if oemcrypto uses anti-rollback hardware. Returns false + * otherwise. + * + * Version: + * This method is added in API version 10. + */ +bool OEMCrypto_IsAntiRollbackHwPresent(); + +/* + * OEMCRYPTO_GetNumberOfOpenSessions() + * + * Description: + * Returns the current number of open OEMCrypto sessions. The CDM and + * OEMCrypto consumers can query this value so they can use resources more + * effectively. + * + * Parameters: + * count (out) - the current number of OEMCrypto sessions. + * + * Threading: + * This function may be called simultaneously with any other functions. + * + * Returns: + * OEMCrypto_SUCCESS + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * + * Version: + * This method is added in API version 10. + */ +OEMCryptoResult OEMCrypto_GetNumberOfOpenSessions(size_t *count); + +/* + * OEMCRYPTO_GetMaxNumberOfSessions() + * + * Description: + * Returns the maximum number of concurrent OEMCrypto sessions supported by + * the device. The CDM and OEMCrypto consumers can query this value so they + * can use resources more effectively. If the maximum number of sessions + * depends on a dynamically allocated shared resource, the returned value + * should be a best estimate of the maximum number of sessions. + * + * Parameters: + * maximum (out) - the maximum number of OEMCrypto sessions supported by the + * device. + * + * Threading: + * This function may be called simultaneously with any other functions. + * + * Returns: + * OEMCrypto_SUCCESS + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * + * Version: + * This method is added in API version 10. + */ +OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(size_t *max); + +/* + * OEMCrypto_Generic_Encrypt * * Description: * This function encrypts a generic buffer of data using the current key. @@ -1970,6 +2202,44 @@ OEMCryptoResult OEMCrypto_DeleteUsageEntry(OEMCrypto_SESSION session, const uint8_t *signature, size_t signature_length); + +/* + * OEMCrypto_ForceDeleteUsageEntry + * + * Description: + * This function deletes an entry from the session usage table. This will be + * used for stale entries without a signed request from the server. + * + * After performing all verification listed below, and deleting the entry from + * the Usage Table, OEMCrypto will increment the Usage Table’s generation number, + * and then sign, encrypt, and save the Usage Table. + * + * Devices that do not implement a Session Usage Table may return + * OEMCrypto_ERROR_NOT_IMPLEMENTED. + * + * Verification + * The following checks should be performed. If any check fails, an error is + * returned. + * 1) The pointer pst is not null. If not, return OEMCrypto_ERROR_UNKNOWN_FAILURE. + * + * Parameters + * pst (in) - pointer to memory containing Provider Session Token. + * pst_length (in) - length of the pst, in bytes. + * + * Returns + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * + * Threading + * This function will not be called simultaneously with any session functions. + * + * Version + * This method changed in API version 10. + */ +OEMCryptoResult OEMCrypto_ForceDeleteUsageEntry(const uint8_t* pst, + size_t pst_length); + /* * OEMCrypto_DeleteUsageTable * @@ -1994,30 +2264,6 @@ OEMCryptoResult OEMCrypto_DeleteUsageEntry(OEMCrypto_SESSION session, */ OEMCryptoResult OEMCrypto_DeleteUsageTable(); -/* - * OEMCRYPTO_GetMaxNumberOfSessions() - * - * Description: - * Returns the maximum number of concurrent OEMCrypto sessions supported by - * the device. The CDM and OEMCrypto consumers can query this value so they - * can use resources more effectively. - * - * Parameters: - * maximum (out) - the maximum number of OEMCrypto sessions supported by the - * device. - * - * Threading: - * This function may be called simultaneously with any other functions. - * - * Returns: - * OEMCrypto_SUCCESS - * OEMCrypto_ERROR_UNKNOWN_FAILURE - * - * Version: - * This method is added in API version 10. - */ -OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(size_t *max); - #ifdef __cplusplus } #endif diff --git a/libwvdrmengine/oemcrypto/include/level3.h b/libwvdrmengine/oemcrypto/include/level3.h index 11b779f9..535c8ece 100644 --- a/libwvdrmengine/oemcrypto/include/level3.h +++ b/libwvdrmengine/oemcrypto/include/level3.h @@ -51,6 +51,11 @@ namespace wvoec3 { #define Level3_DeleteUsageEntry _lcc33 #define Level3_DeleteUsageTable _lcc34 #define Level3_GetMaxNumberOfSessions _lcc37 +#define Level3_GetNumberOfOpenSessions _lcc38 +#define Level3_CopyBuffer _lcc40 +#define Level3_QueryKeyControl _lcc41 +#define Level3_LoadTestKeybox _lcc42 +#define Level3_ForceDeleteUsageEntry _lcc43 extern "C" { @@ -168,25 +173,38 @@ OEMCryptoResult Level3_Generic_Verify(OEMCrypto_SESSION session, const uint8_t* signature, size_t signature_length); OEMCryptoResult Level3_GetHDCPCapability(OEMCrypto_HDCP_Capability *current, - OEMCrypto_HDCP_Capability *maximum); + OEMCrypto_HDCP_Capability *maximum); bool Level3_SupportsUsageTable(); OEMCryptoResult Level3_UpdateUsageTable(); OEMCryptoResult Level3_DeactivateUsageEntry(const uint8_t *pst, - size_t pst_length); + size_t pst_length); OEMCryptoResult Level3_ReportUsage(OEMCrypto_SESSION session, - const uint8_t *pst, - size_t pst_length, - OEMCrypto_PST_Report *buffer, - size_t *buffer_length); + const uint8_t *pst, + size_t pst_length, + OEMCrypto_PST_Report *buffer, + size_t *buffer_length); OEMCryptoResult Level3_DeleteUsageEntry(OEMCrypto_SESSION session, - const uint8_t* pst, - size_t pst_length, - const uint8_t *message, - size_t message_length, - const uint8_t *signature, - size_t signature_length); + const uint8_t* pst, + size_t pst_length, + const uint8_t *message, + size_t message_length, + const uint8_t *signature, + size_t signature_length); OEMCryptoResult Level3_DeleteUsageTable(); OEMCryptoResult Level3_GetMaxNumberOfSessions(size_t *maximum); +OEMCryptoResult Level3_GetCurrentNumberOfSessions(size_t *count); +OEMCryptoResult Level3_LoadTestKeybox(); +OEMCryptoResult Level3_CopyBuffer(const uint8_t *data_addr, + size_t data_length, + OEMCrypto_DestBufferDesc* out_buffer, + uint8_t subsample_flags); +OEMCryptoResult Level3_QueryKeyControl(OEMCrypto_SESSION session, + const uint8_t* key_id, + size_t key_id_length, + uint8_t* key_control_block, + size_t* key_control_block_length); +OEMCryptoResult Level3_ForceDeleteUsageEntry(const uint8_t* pst, + size_t pst_length); }; } #endif // LEVEL3_OEMCRYPTO_H_ diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties.cpp index 17aedd37..6859f936 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties.cpp @@ -19,12 +19,12 @@ bool CryptoEngine::closed_platform() { // Returns the HDCP version currently in use. OEMCrypto_HDCP_Capability CryptoEngine::current_hdcp_capability() { - return local_display() ? 0xFF : 0x01; + return local_display() ? HDCP_NO_DIGITAL_OUTPUT : HDCP_V1; } // Returns the max HDCP version supported. OEMCrypto_HDCP_Capability CryptoEngine::maximum_hdcp_capability() { - return 0x02; + return HDCP_V2; } // Returns true if the client supports persistent storage of diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp index 81b01775..58aa1b36 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp @@ -1622,17 +1622,17 @@ TEST_F(OEMCryptoClientTest, NormalGetKeyData) { const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value) { switch (value) { - case 0x0: + case HDCP_NONE: return "No HDCP supported, no secure data path"; - case 0x1: + case HDCP_V1: return "HDCP version 1.0"; - case 0x2: + case HDCP_V2: return "HDCP version 2.0"; - case 0x3: + case HDCP_V2_1: return "HDCP version 2.1"; - case 0x4: + case HDCP_V2_2: return "HDCP version 2.2"; - case 0xFF: + case HDCP_NO_DIGITAL_OUTPUT: return "No HDCP device attached/using local display with secure path"; default: return "";