diff --git a/oemcrypto/include/OEMCryptoCENC.h b/oemcrypto/include/OEMCryptoCENC.h index d6fd79a..2440bea 100644 --- a/oemcrypto/include/OEMCryptoCENC.h +++ b/oemcrypto/include/OEMCryptoCENC.h @@ -8,9 +8,9 @@ * Reference APIs needed to support Widevine's crypto algorithms. * * See the document "WV Modular DRM Security Integration Guide for Common - * Encryption (CENC) -- version 14" for a description of this API. You + * Encryption (CENC) -- version 15" for a description of this API. You * can find this document in the widevine repository as - * docs/WidevineModularDRMSecurityIntegrationGuideforCENC_v14.pdf + * docs/WidevineModularDRMSecurityIntegrationGuideforCENC_v15.pdf * Changes between different versions of this API are documented in the files * docs/Widevine_Modular_DRM_Version_*_Delta.pdf * @@ -81,8 +81,12 @@ typedef enum OEMCryptoResult { 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, + 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, } OEMCryptoResult; /* @@ -164,6 +168,18 @@ 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 @@ -187,15 +203,23 @@ typedef enum OEMCrypto_LicenseType { * by the caller of OEMCrypto_LoadKeys(). */ typedef struct { - const uint8_t* key_id; - size_t key_id_length; - const uint8_t* key_data_iv; - const uint8_t* key_data; - size_t key_data_length; - const uint8_t* key_control_iv; - const uint8_t* key_control; + OEMCrypto_Substring key_id; + OEMCrypto_Substring key_data_iv; + OEMCrypto_Substring key_data; + OEMCrypto_Substring key_control_iv; + OEMCrypto_Substring key_control; } OEMCrypto_KeyObject; +/* + * SRM_Restriction_Data + * + * Structure passed into LoadKeys to specify required SRM version. + */ +typedef struct { + uint8_t verification[8]; // must be "HDCPDATA" + uint32_t minimum_srm_version; // version number in network byte order. +} SRM_Restriction_Data; + /* * OEMCrypto_EntitledContentKeyObject * Contains encrypted content key data for loading into the sessions keytable. @@ -210,13 +234,10 @@ typedef struct { * key_data_length - length of key_data - 16 or 32 depending on intended use. */ typedef struct { - const uint8_t* entitlement_key_id; - size_t entitlement_key_id_length; - const uint8_t* content_key_id; - size_t content_key_id_length; - const uint8_t* content_key_data_iv; - const uint8_t* content_key_data; - size_t content_key_data_length; + OEMCrypto_Substring entitlement_key_id; + OEMCrypto_Substring content_key_id; + OEMCrypto_Substring content_key_data_iv; + OEMCrypto_Substring content_key_data; } OEMCrypto_EntitledContentKeyObject; /* @@ -239,10 +260,9 @@ typedef struct { * by the caller of OEMCrypto_RefreshKeys(). */ typedef struct { - const uint8_t* key_id; - size_t key_id_length; - const uint8_t* key_control_iv; - const uint8_t* key_control; + OEMCrypto_Substring key_id; + OEMCrypto_Substring key_control_iv; + OEMCrypto_Substring key_control; } OEMCrypto_KeyRefreshObject; /* @@ -317,10 +337,11 @@ typedef enum OEMCrypto_Clock_Security_Level { kHardwareSecureClock = 3 } OEMCrypto_Clock_Security_Level; -typedef enum RSA_Padding_Scheme { - kSign_RSASSA_PSS = 0x1, // RSASSA-PSS with SHA1. - kSign_PKCS1_Block1 = 0x2, // PKCS1 with block type 1 padding (only). -} RSA_Padding_Scheme; +typedef uint8_t RSA_Padding_Scheme; +// RSASSA-PSS with SHA1. +const RSA_Padding_Scheme kSign_RSASSA_PSS = 0x1; +// PKCS1 with block type 1 padding (only). +const RSA_Padding_Scheme kSign_PKCS1_Block1 = 0x2; /* * OEMCrypto_HDCP_Capability is used in the key control block to enforce HDCP @@ -332,6 +353,7 @@ typedef enum OEMCrypto_HDCP_Capability { HDCP_V2 = 2, // HDCP version 2.0 Type 1. HDCP_V2_1 = 3, // HDCP version 2.1 Type 1. HDCP_V2_2 = 4, // HDCP version 2.2 Type 1. + HDCP_V2_3 = 5, // HDCP version 2.3 Type 1. HDCP_NO_DIGITAL_OUTPUT = 0xff // No digital output. } OEMCrypto_HDCP_Capability; @@ -354,8 +376,9 @@ typedef enum OEMCrypto_ProvisioningMethod { /* * Flags indicating full decrypt path hash supported. */ -#define OEMCrypto_Hash_Not_Supported 0 -#define OEMCrypto_HMAC_Clear_Buffer 1 +const uint32_t OEMCrypto_Hash_Not_Supported = 0; +const uint32_t OEMCrypto_CRC_Clear_Buffer = 1; +const uint32_t OEMCrypto_Partner_Defined_Hash = 2; /* * Return values from OEMCrypto_GetAnalogOutputFlags. @@ -370,87 +393,141 @@ typedef enum OEMCrypto_ProvisioningMethod { /* * Obfuscation Renames. */ -#define OEMCrypto_Initialize _oecc01 -#define OEMCrypto_Terminate _oecc02 -#define OEMCrypto_InstallKeybox _oecc03 +#define OEMCrypto_Initialize _oecc01 +#define OEMCrypto_Terminate _oecc02 +#define OEMCrypto_InstallKeybox _oecc03 // Rename InstallKeybox to InstallKeyboxOrOEMCert. -#define OEMCrypto_InstallRootKeyCertificate _oecc03 -#define OEMCrypto_InstallKeyboxOrOEMCert _oecc03 -#define OEMCrypto_GetKeyData _oecc04 -#define OEMCrypto_IsKeyboxValid _oecc05 +#define OEMCrypto_InstallRootKeyCertificate _oecc03 +#define OEMCrypto_InstallKeyboxOrOEMCert _oecc03 +#define OEMCrypto_GetKeyData _oecc04 +#define OEMCrypto_IsKeyboxValid _oecc05 // Rename IsKeyboxValid to IsKeyboxOrOEMCertValid. -#define OEMCrypto_IsRootKeyCertificateValid _oecc05 -#define OEMCrypto_IsKeyboxOrOEMCertValid _oecc05 -#define OEMCrypto_GetRandom _oecc06 -#define OEMCrypto_GetDeviceID _oecc07 -#define OEMCrypto_WrapKeybox _oecc08 +#define OEMCrypto_IsRootKeyCertificateValid _oecc05 +#define OEMCrypto_IsKeyboxOrOEMCertValid _oecc05 +#define OEMCrypto_GetRandom _oecc06 +#define OEMCrypto_GetDeviceID _oecc07 +#define OEMCrypto_WrapKeybox _oecc08 // Rename WrapKeybox to WrapKeyboxOrOEMCert -#define OEMCrypto_WrapRootKeyCertificate _oecc08 -#define OEMCrypto_WrapKeyboxOrOEMCert _oecc08 -#define OEMCrypto_OpenSession _oecc09 -#define OEMCrypto_CloseSession _oecc10 -#define OEMCrypto_DecryptCTR_V10 _oecc11 -#define OEMCrypto_GenerateDerivedKeys _oecc12 -#define OEMCrypto_GenerateSignature _oecc13 -#define OEMCrypto_GenerateNonce _oecc14 -#define OEMCrypto_LoadKeys_V8 _oecc15 -#define OEMCrypto_RefreshKeys _oecc16 -#define OEMCrypto_SelectKey_V13 _oecc17 -#define OEMCrypto_RewrapDeviceRSAKey _oecc18 -#define OEMCrypto_LoadDeviceRSAKey _oecc19 -#define OEMCrypto_GenerateRSASignature_V8 _oecc20 -#define OEMCrypto_DeriveKeysFromSessionKey _oecc21 -#define OEMCrypto_APIVersion _oecc22 -#define OEMCrypto_SecurityLevel _oecc23 -#define OEMCrypto_Generic_Encrypt _oecc24 -#define OEMCrypto_Generic_Decrypt _oecc25 -#define OEMCrypto_Generic_Sign _oecc26 -#define OEMCrypto_Generic_Verify _oecc27 -#define OEMCrypto_GetHDCPCapability_V9 _oecc28 -#define OEMCrypto_SupportsUsageTable _oecc29 -#define OEMCrypto_UpdateUsageTable _oecc30 -#define OEMCrypto_DeactivateUsageEntry_V12 _oecc31 -#define OEMCrypto_ReportUsage _oecc32 -#define OEMCrypto_DeleteUsageEntry _oecc33 -#define OEMCrypto_DeleteOldUsageTable _oecc34 -#define OEMCrypto_LoadKeys_V9_or_V10 _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_V13 _oecc42 -#define OEMCrypto_ForceDeleteUsageEntry _oecc43 -#define OEMCrypto_GetHDCPCapability _oecc44 -#define OEMCrypto_LoadTestRSAKey _oecc45 -#define OEMCrypto_Security_Patch_Level _oecc46 -#define OEMCrypto_LoadKeys_V11_or_V12 _oecc47 -#define OEMCrypto_DecryptCENC _oecc48 -#define OEMCrypto_GetProvisioningMethod _oecc49 -#define OEMCrypto_GetOEMPublicCertificate _oecc50 -#define OEMCrypto_RewrapDeviceRSAKey30 _oecc51 -#define OEMCrypto_SupportedCertificates _oecc52 -#define OEMCrypto_IsSRMUpdateSupported _oecc53 -#define OEMCrypto_GetCurrentSRMVersion _oecc54 -#define OEMCrypto_LoadSRM _oecc55 -#define OEMCrypto_LoadKeys_V13 _oecc56 -#define OEMCrypto_RemoveSRM _oecc57 -#define OEMCrypto_CreateUsageTableHeader _oecc61 -#define OEMCrypto_LoadUsageTableHeader _oecc62 -#define OEMCrypto_CreateNewUsageEntry _oecc63 -#define OEMCrypto_LoadUsageEntry _oecc64 -#define OEMCrypto_UpdateUsageEntry _oecc65 -#define OEMCrypto_DeactivateUsageEntry _oecc66 -#define OEMCrypto_ShrinkUsageTableHeader _oecc67 -#define OEMCrypto_MoveEntry _oecc68 -#define OEMCrypto_CopyOldUsageEntry _oecc69 -#define OEMCrypto_CreateOldUsageEntry _oecc70 -#define OEMCrypto_GetAnalogOutputFlags _oecc71 -#define OEMCrypto_LoadTestKeybox _oecc78 -#define OEMCrypto_LoadEntitledContentKeys _oecc79 -#define OEMCrypto_SelectKey _oecc81 -#define OEMCrypto_LoadKeys _oecc82 +#define OEMCrypto_WrapRootKeyCertificate _oecc08 +#define OEMCrypto_WrapKeyboxOrOEMCert _oecc08 +#define OEMCrypto_OpenSession _oecc09 +#define OEMCrypto_CloseSession _oecc10 +#define OEMCrypto_DecryptCTR_V10 _oecc11 +#define OEMCrypto_GenerateDerivedKeys _oecc12 +#define OEMCrypto_GenerateSignature _oecc13 +#define OEMCrypto_GenerateNonce _oecc14 +#define OEMCrypto_LoadKeys_V8 _oecc15 +#define OEMCrypto_RefreshKeys_V14 _oecc16 +#define OEMCrypto_SelectKey_V13 _oecc17 +#define OEMCrypto_RewrapDeviceRSAKey _oecc18 +#define OEMCrypto_LoadDeviceRSAKey _oecc19 +#define OEMCrypto_GenerateRSASignature_V8 _oecc20 +#define OEMCrypto_DeriveKeysFromSessionKey _oecc21 +#define OEMCrypto_APIVersion _oecc22 +#define OEMCrypto_SecurityLevel _oecc23 +#define OEMCrypto_Generic_Encrypt _oecc24 +#define OEMCrypto_Generic_Decrypt _oecc25 +#define OEMCrypto_Generic_Sign _oecc26 +#define OEMCrypto_Generic_Verify _oecc27 +#define OEMCrypto_GetHDCPCapability_V9 _oecc28 +#define OEMCrypto_SupportsUsageTable _oecc29 +#define OEMCrypto_UpdateUsageTable _oecc30 +#define OEMCrypto_DeactivateUsageEntry_V12 _oecc31 +#define OEMCrypto_ReportUsage _oecc32 +#define OEMCrypto_DeleteUsageEntry _oecc33 +#define OEMCrypto_DeleteOldUsageTable _oecc34 +#define OEMCrypto_LoadKeys_V9_or_V10 _oecc35 +#define OEMCrypto_GenerateRSASignature _oecc36 +#define OEMCrypto_GetMaxNumberOfSessions _oecc37 +#define OEMCrypto_GetNumberOfOpenSessions _oecc38 +#define OEMCrypto_IsAntiRollbackHwPresent _oecc39 +#define OEMCrypto_CopyBuffer_V14 _oecc40 +#define OEMCrypto_QueryKeyControl _oecc41 +#define OEMCrypto_LoadTestKeybox_V13 _oecc42 +#define OEMCrypto_ForceDeleteUsageEntry _oecc43 +#define OEMCrypto_GetHDCPCapability _oecc44 +#define OEMCrypto_LoadTestRSAKey _oecc45 +#define OEMCrypto_Security_Patch_Level _oecc46 +#define OEMCrypto_LoadKeys_V11_or_V12 _oecc47 +#define OEMCrypto_DecryptCENC _oecc48 +#define OEMCrypto_GetProvisioningMethod _oecc49 +#define OEMCrypto_GetOEMPublicCertificate _oecc50 +#define OEMCrypto_RewrapDeviceRSAKey30 _oecc51 +#define OEMCrypto_SupportedCertificates _oecc52 +#define OEMCrypto_IsSRMUpdateSupported _oecc53 +#define OEMCrypto_GetCurrentSRMVersion _oecc54 +#define OEMCrypto_LoadSRM _oecc55 +#define OEMCrypto_LoadKeys_V13 _oecc56 +#define OEMCrypto_RemoveSRM _oecc57 +#define OEMCrypto_CreateUsageTableHeader _oecc61 +#define OEMCrypto_LoadUsageTableHeader _oecc62 +#define OEMCrypto_CreateNewUsageEntry _oecc63 +#define OEMCrypto_LoadUsageEntry _oecc64 +#define OEMCrypto_UpdateUsageEntry _oecc65 +#define OEMCrypto_DeactivateUsageEntry _oecc66 +#define OEMCrypto_ShrinkUsageTableHeader _oecc67 +#define OEMCrypto_MoveEntry _oecc68 +#define OEMCrypto_CopyOldUsageEntry _oecc69 +#define OEMCrypto_CreateOldUsageEntry _oecc70 +#define OEMCrypto_GetAnalogOutputFlags _oecc71 +#define OEMCrypto_LoadTestKeybox _oecc78 +#define OEMCrypto_LoadEntitledContentKeys_V14 _oecc79 +#define OEMCrypto_SelectKey _oecc81 +#define OEMCrypto_LoadKeys_V14 _oecc82 +#define OEMCrypto_LoadKeys _oecc83 +#define OEMCrypto_SetSandbox _oecc84 +#define OEMCrypto_ResourceRatingTier _oecc85 +#define OEMCrypto_SupportsDecryptHash _oecc86 +#define OEMCrypto_InitializeDecryptHash _oecc87 +#define OEMCrypto_SetDecryptHash _oecc88 +#define OEMCrypto_GetHashErrorCode _oecc89 +#define OEMCrypto_BuildInformation _oecc90 +#define OEMCrypto_RefreshKeys _oecc91 +#define OEMCrypto_LoadEntitledContentKeys _oecc92 +#define OEMCrypto_CopyBuffer _oecc93 + +/* + * OEMCrypto_SetSandbox + * + * Description: + * This tells OEMCrypto which sandbox the current process belongs to. Any + * persistent memory used to store the generation number should be associated + * with this sandbox id. OEMCrypto can assume that this sandbox will be tied + * to the current process or VM until OEMCrypto_Terminate is called. See the + * section "VM and Sandbox Support" above for more details. + * + * If OEMCrypto does not support sandboxes, it will return + * OEMCrypto_ERROR_NOT_IMPLEMENTED. On most platforms, this function will + * just return OEMCrypto_ERROR_NOT_IMPLEMENTED. If OEMCrypto supports + * sandboxes, this function returns OEMCrypto_SUCCESS on success, and + * OEMCrypto_ERROR_UNKNOWN_FAILURE on failure. + * + * The CDM layer will call OEMCrypto_SetSandbox once before + * OEMCrypto_Initialize. After this function is called and returns success, + * it will be OEMCrypto's responsibility to keep calls to usage table + * functions separate, and to accept a call to OEMCrypto_Terminate for each + * sandbox. + * + * Parameters: + * [in] sandbox_id: a short string unique to the current sandbox. + * [in] sandobx_id_length: length of sandbox_id. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_INIT_FAILED failed to initialize crypto hardware + * OEMCrypto_ERROR_NOT_IMPLEMENTED - sandbox functionality not supported + * + * Threading: + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. It is called once before + * OEMCrypto_Initialize. + * + * Version: + * This method is new in version 15 of the API. + */ +OEMCryptoResult OEMCrypto_SetSandbox(const uint8_t* sandbox_id, + size_t sandbox_id_length); /* * OEMCrypto_Initialize @@ -459,16 +536,17 @@ typedef enum OEMCrypto_ProvisioningMethod { * Initialize the crypto firmware/hardware. * * Parameters: - * N/A - * - * Threading: - * No other function calls will be made while this function is running. This - * function will not be called again before OEMCrypto_Terminate. + * None * * Returns: * OEMCrypto_SUCCESS success * OEMCrypto_ERROR_INIT_FAILED failed to initialize crypto hardware * + * Threading: + * This is an "Initialization and Termination 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 supported by all API versions. */ @@ -481,17 +559,18 @@ OEMCryptoResult OEMCrypto_Initialize(void); * Closes the crypto operation and releases all related resources. * * Parameters: - * N/A - * - * Threading: - * No other OEMCrypto calls are made while this function is running. After - * this function is called, no other OEMCrypto calls will be made until - * another call to OEMCrypto_Initialize is made. + * None * * Returns: * OEMCrypto_SUCCESS success * OEMCrypto_ERROR_TERMINATE_FAILED failed to de-initialize crypto hardware * + * Threading: + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. No other functions will be called before the + * system is re-initialized. + * * Version: * This method is supported by all API versions. */ @@ -501,23 +580,26 @@ OEMCryptoResult OEMCrypto_Terminate(void); * OEMCrypto_OpenSession * * Description: - * Open a new crypto security engine context. The security engine hardware and - * firmware shall acquire resources that are needed to support the session, - * and return a session handle that identifies that session in future calls. + * Open a new crypto security engine context. The security engine hardware + * and firmware shall acquire resources that are needed to support the + * session, and return a session handle that identifies that session in + * future calls. * * Parameters: - * session (out) - an opaque handle that the crypto firmware uses to identify - * the session. - * - * Threading: - * No other Open/Close session calls will be made while this function is - * running. Functions on other existing sessions may be called while this - * function is active. + * [out] session: an opaque handle that the crypto firmware uses to identify + * the session. * * Returns: * OEMCrypto_SUCCESS success * OEMCrypto_ERROR_TOO_MANY_SESSIONS failed because too many sessions are open - * OEMCrypto_ERROR_OPEN_SESSION_FAILED failed to initialize the crypto session + * OEMCrypto_ERROR_OPEN_SESSION_FAILED there is a resource issue or the + * security engine is not properly initialized. + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Session Initialization 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 changed in API version 5. @@ -529,26 +611,28 @@ OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session); * * Description: * Closes the crypto security engine session and frees any associated - * resources. If this session is associated with a Usage Entry, all resident - * memory associated with it will be freed. It is the CDM layer’s + * resources. If this session is associated with a Usage Entry, all resident + * memory associated with it will be freed. It is the CDM layer's * responsibility to call OEMCrypto_UpdateUsageEntry before closing the * session. * * Parameters: - * session (in) - handle for the session to be closed. - * - * Threading: - * No other Open/Close session calls will be made while this function is - * running. Functions on other existing sessions may be called while this - * function is active. + * [in] session: handle for the session to be closed. * * Returns: * OEMCrypto_SUCCESS success * OEMCrypto_ERROR_INVALID_SESSION no open session with that id. - * OEMCrypto_ERROR_CLOSE_SESSION_FAILED failed to terminate the crypto session + * OEMCrypto_ERROR_CLOSE_SESSION_FAILED illegal/unrecognized handle or the + * security engine is not properly initialized. + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Session Initialization 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 changed in API version 5. + * This method changed in API version 13. */ OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session); @@ -556,41 +640,36 @@ OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session); * OEMCrypto_GenerateDerivedKeys * * Description: - * Generates three secondary keys -- mac_key_server, mac_key_client, and - * encrypt_key -- for handling signing and content key decryption under the - * license server protocol for AES CTR mode. + * Generates three secondary keys, mac_key[server], mac_key[client], and + * encrypt_key, for handling signing and content key decryption under the + * license server protocol for CENC. * - * Refer to document "Widevine Modular DRM Security Integration Guide for - * CENC" for details. This function computes the AES-128-CMAC of the - * enc_key_context and stores it in secure memory as the encrypt_key. It - * then computes four cycles of AES-128-CMAC of the mac_key_context and - * stores it in the mac_keys. The first two cycles are used for - * mac_key_server and the second two cycles are used for mac_key_client. - * These three keys will be stored until the next call to LoadKeys. + * Refer to the Key Derivation section above for more details. This function + * computes the AES-128-CMAC of the enc_key_context and stores it in secure + * memory as the encrypt_key. It then computes four cycles of AES-128-CMAC of + * the mac_key_context and stores it in the mac_keys -- the first two cycles + * generate the mac_key[server] and the second two cycles generate the + * mac_key[client]. These two keys will be stored until the next call to + * OEMCrypto_LoadKeys(). The device key from the keybox is used as the key + * for the AES-128-CMAC. * * Parameters: - * session (in) - handle for the session to be used. - * mac_key_context (in) - pointer to memory containing context data for - * computing the HMAC generation key. - * mac_key_context_length (in) - length of the HMAC key context data, in - * bytes. - * enc_key_context (in) - pointer to memory containing context data for - * computing the encryption key. - * enc_key_context_length (in) - length of the encryption key context data, in - * bytes. - * + * [in] session: handle for the session to be used. + * [in] mac_key_context: pointer to memory containing context data for + * computing the HMAC generation key. + * [in] mac_key_context_length: length of the HMAC key context data, in bytes. + * [in] enc_key_context: pointer to memory containing context data for + * computing the encryption key. + * [in] enc_key_context_length: length of the encryption key context data, in + * bytes. * * Results: - * mac_key_server: the 256 bit mac key is generated and stored in secure - * memory. - * mac_key_client: the 256 bit mac key is generated and stored in secure - * memory. - * enc_key: the 128 bit encryption key is generated and stored in secure - * memory. - * - * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. + * mac_key[server]: the 256 bit mac key is generated and stored in secure + * memory. + * mac_key[client]: the 256 bit mac key is generated and stored in secure + * memory. + * enc_key: the 128 bit encryption key is generated and stored in secure + * memory. * * Returns: * OEMCrypto_SUCCESS success @@ -600,14 +679,24 @@ OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session); * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES * OEMCrypto_ERROR_UNKNOWN_FAILURE * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * - * Buffer Sizes - * OEMCrypto shall support message sizes of at least 8 KiB. - * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is - * larger than the supported size. + * Buffer Sizes: + * OEMCrypto shall support mac_key_context and enc_key_context sizes of at + * least 8 KiB. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffers are + * too large. + * + * 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 8. + * This method changed in API version 12. */ OEMCryptoResult OEMCrypto_GenerateDerivedKeys(OEMCrypto_SESSION session, const uint8_t* mac_key_context, @@ -615,13 +704,92 @@ OEMCryptoResult OEMCrypto_GenerateDerivedKeys(OEMCrypto_SESSION session, const uint8_t* enc_key_context, uint32_t enc_key_context_length); +/* + * OEMCrypto_DeriveKeysFromSessionKey + * + * Description: + * Generates three secondary keys, mac_key[server], mac_key[client] and + * encrypt_key, for handling signing and content key decryption under the + * license server protocol for CENC. + * + * This function is similar to OEMCrypto_GenerateDerivedKeys, except that it + * uses a session key to generate the secondary keys instead of the Widevine + * Keybox device key. These three keys will be stored in secure memory until + * the next call to LoadKeys. The session key is passed in encrypted by the + * device RSA public key, and must be decrypted with the RSA private key + * before use. + * + * 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 using a Widevine keybox token. + * + * Verification: + * If the RSA key's allowed_schemes is not kSign_RSASSA_PSS, then no keys are + * derived and the error OEMCrypto_ERROR_INVALID_RSA_KEY is returned. An RSA + * key cannot be used for both deriving session keys and also for PKCS1 + * signatures. + * + * Parameters: + * [in] session: handle for the session to be used. + * [in] enc_session_key: session key, encrypted with the public RSA key (from + * the DRM certifcate) using RSA-OAEP. + * n_key_l[in] enc_sessioength: length of session_key, in bytes. + * [in] mac_key_context: pointer to memory containing context data for + * computing the HMAC generation key. + * [in] mac_key_context_length: length of the HMAC key context data, in bytes. + * [in] enc_key_context: pointer to memory containing context data for + * computing the encryption key. + * [in] enc_key_context_length: length of the encryption key context data, in + * bytes. + * + * Results: + * mac_key[server]: the 256 bit mac key is generated and stored in secure + * memory. + * mac_key[client]: the 256 bit mac key is generated and stored in secure + * memory. + * enc_key: the 128 bit encryption key is generated and stored in secure + * memory. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_INVALID_CONTEXT + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support mac_key_context and enc_key_context sizes of at + * least 8 KiB. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffers are + * too large. + * + * 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 12. + */ +OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( + OEMCrypto_SESSION session, const uint8_t* enc_session_key, + size_t enc_session_key_length, const uint8_t* mac_key_context, + size_t mac_key_context_length, const uint8_t* enc_key_context, + size_t enc_key_context_length); + /* * OEMCrypto_GenerateNonce * * Description: * Generates a 32-bit nonce to detect possible replay attack on the key - * control block. The nonce is stored in secure memory and will be used - * for the next call to LoadKeys. + * control block. The nonce is stored in secure memory and will be used for + * the next call to LoadKeys. * * Because the nonce will be used to prevent replay attacks, it is desirable * that a rogue application cannot rapidly call this function until a @@ -633,22 +801,27 @@ OEMCryptoResult OEMCrypto_GenerateDerivedKeys(OEMCrypto_SESSION session, * condition and generate valid nonces again. * * Parameters: - * session (in) - crypto session identifier. - * nonce (out) - pointer to memory to received the computed nonce. + * [in] session: handle for the session to be used. + * [out] nonce: pointer to memory to receive the computed nonce. * * Results: * nonce: the nonce is also stored in secure memory. At least 4 nonces should * be stored for each session. * - * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. - * * Returns: * OEMCrypto_SUCCESS success * OEMCrypto_ERROR_INVALID_SESSION * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * 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 5. @@ -660,48 +833,63 @@ OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, * OEMCrypto_GenerateSignature * * Description: - * Generates a HMAC-SHA256 signature for license request signing under the - * license server protocol for AES CTR mode. This uses the key mac_key_client. + * Generates a HMAC-SHA256 signature using the mac_key[client] for license + * request signing under the license server protocol for CENC. * - * NOTE: OEMCrypto_GenerateDerivedKeys() must be called first to establish the - * mac_key_client. + * The key used for signing should be the mac_key[client] that was generated + * for this session or loaded for this session by the most recent successful + * call to any one of * - * Refer to document "Widevine Modular DRM Security Integration Guide for - * CENC" for details. + * - OEMCrypto_GenerateDerivedKeys, + * - OEMCrypto_DeriveKeysFromSessionKey, + * - OEMCrypto_LoadKeys, or + * - OEMCrypto_LoadUsageEntry. + * Refer to the Signing Messages Sent to a Server section above for more + * details. + * + * If a usage entry has been loaded, but keys have not been loaded through + * OEMCrypto_LoadKeys, then the derived mac keys and the keys in the usage + * entry may be different. In this case, the mac keys specified in the usage + * entry should be used. * * NOTE: if signature pointer is null and/or input signature_length set to * zero, this function returns OEMCrypto_ERROR_SHORT_BUFFER and sets output * signature_length to the size needed to receive the output signature. * * Parameters: - * session (in) - crypto session identifier. - * message (in) - pointer to memory containing message to be signed. - * message_length (in) - length of the message, in bytes. - * signature (out) - pointer to memory to received the computed signature. May - * be null (see note above). - * signature_length (in/out) - (in) length of the signature buffer, in bytes. + * [in] session: crypto session identifier. + * [in] message: pointer to memory containing message to be signed. + * [in] message_length: length of the message, in bytes. + * [out] signature: pointer to memory to received the computed signature. May + * be null (see note above). + * [in/out] signature_length: (in) length of the signature buffer, in bytes. * (out) actual length of the signature, in bytes. * - * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. - * * Returns: * OEMCrypto_SUCCESS success * OEMCrypto_ERROR_INVALID_SESSION * OEMCrypto_ERROR_SHORT_BUFFER if signature buffer is not large enough to - * hold the buffer. + * hold the signature. * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES * OEMCrypto_ERROR_UNKNOWN_FAILURE * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * - * Buffer Sizes + * Buffer Sizes: * OEMCrypto shall support message sizes of at least 8 KiB. * 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 5. + * This method changed in API version 12. */ OEMCryptoResult OEMCrypto_GenerateSignature(OEMCrypto_SESSION session, const uint8_t* message, @@ -709,6 +897,45 @@ OEMCryptoResult OEMCrypto_GenerateSignature(OEMCrypto_SESSION session, uint8_t* signature, size_t* signature_length); +/* + * OEMCrypto_LoadSRM + * + * Description: + * Verify and install a new SRM file. The device shall install the new file + * only if verification passes. If verification fails, the existing SRM will + * be left in place. Verification is defined by DCP, and includes + * verification of the SRM's signature and verification that the SRM version + * number will not be decreased. See the section HDCP SRM Update above for + * more details about the SRM. This function is for devices that support HDCP + * v2.2 or higher and wish to receive 4k content. + * + * Parameters: + * [in] bufer: buffer containing the SRM + * [in] buffer_length: length of the SRM, in bytes. + * + * Returns: + * OEMCrypto_SUCCESS - if the file was valid and was installed. + * OEMCrypto_ERROR_INVALID_CONTEXT - if the SRM version is too low, or the + * file is corrupted. + * OEMCrypto_ERROR_SIGNATURE_FAILURE - If the signature is invalid. + * OEMCrypto_ERROR_BUFFER_TOO_LARGE - if the buffer is too large for the + * device. + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * The size of the buffer is determined by the HDCP specification. + * + * Threading: + * This is an "Initialization and Termination 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 changed in API version 13. + */ +OEMCryptoResult OEMCrypto_LoadSRM(const uint8_t* buffer, size_t buffer_length); + /* * OEMCrypto_LoadKeys * @@ -718,29 +945,31 @@ OEMCryptoResult OEMCrypto_GenerateSignature(OEMCrypto_SESSION session, * The relevant fields have been extracted from the License Response protocol * message, but the entire message and associated signature are provided so * the message can be verified (using HMAC-SHA256 with the derived - * mac_key_server). If the signature verification fails, ignore all other + * mac_key[server]). If the signature verification fails, ignore all other * arguments and return OEMCrypto_ERROR_SIGNATURE_FAILURE. Otherwise, add the * keys to the session context. * * The keys will be decrypted using the current encrypt_key (AES-128-CBC) and * the IV given in the KeyObject. Each key control block will be decrypted - * using the first 128 bits of the corresponding content key (AES-128-CBC) and - * the IV given in the KeyObject. + * using the first 128 bits of the corresponding content key (AES-128-CBC) + * and the IV given in the KeyObject. * - * If it is not null, enc_mac_keys will be used to create new mac_keys. After - * all keys have been decrypted and validated, the new mac_keys are decrypted - * with the current encrypt_key and the offered IV. 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. + * If its length is not zero, enc_mac_keys will be used to create new + * mac_keys. After all keys have been decrypted and validated, the new + * mac_keys are decrypted with the current encrypt_key and the offered IV. + * 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. * * The mac_key and encrypt_key were generated and stored by the previous call - * to OEMCrypto_GenerateDerivedKeys(). The nonce was generated and stored by - * the previous call to OEMCrypto_GenerateNonce(). + * to OEMCrypto_GenerateDerivedKeys() or + * OEMCrypto_DeriveKeysFromSessionKey(). The nonce was generated and stored + * by the previous call to OEMCrypto_GenerateNonce(). * - * This session’s elapsed time clock is started at 0. The clock will be used + * This session's elapsed time clock is started at 0. The clock will be used * in OEMCrypto_DecryptCENC(). * * NOTE: The calling software must have previously established the mac_keys @@ -748,106 +977,124 @@ OEMCryptoResult OEMCrypto_GenerateSignature(OEMCrypto_SESSION session, * OEMCrypto_DeriveKeysFromSessionKey(), or a previous call to * OEMCrypto_LoadKeys(). * - * Refer to document "Widevine Modular DRM Security Integration Guide for - * CENC" for details. + * Refer to the Verification of Messages from a Server section above for more + * details. * * If the parameter license_type is OEMCrypto_ContentLicense, then the fields * key_id and key_data in an OEMCrypto_KeyObject are loaded in to the - * content_key_id and content_key_data fields of the key table entry. In - * this case, entitlement key ids and entitlement key data is left blank. + * content_key_id and content_key_data fields of the key table entry. In this + * case, entitlement key ids and entitlement key data is left blank. * - * If the parameter license_type is OEMCrypto_EntitlementLicense, then the + * If the parameter license_type is OEMCrypto_EntitlementLicense, then the * fields key_id and key_data in an OEMCrypto_KeyObject are loaded in to the * entitlement_key_id and entitlement_key_data fields of the key table entry. * In this case, content key ids and content key data will be loaded later * with a call to OEMCrypto_LoadEntitledContentKeys(). * - * OEMCrypto may assume that the key_id_length is at most 16. However, + * OEMCrypto may assume that the key_id_length is at most 16. However, * OEMCrypto shall correctly handle key id lengths from 1 to 16 bytes. * - * OEMCrypto shall handle at least 20 keys per session. This allows a - * single license to contain separate keys for 3 key rotations (previous - * interval, current interval, next interval) times 4 content keys (audio, - * SD, HD, UHD) plus up to 8 keys for watermarks. + * OEMCrypto shall handle at least 20 keys per session. This allows a single + * license to contain separate keys for 3 key rotations (previous interval, + * current interval, next interval) times 4 content keys (audio, SD, HD, UHD) + * plus up to 8 keys for watermarks. * * Verification: * The following checks should be performed. If any check fails, an error is * returned, and none of the keys are loaded. * - * 1. The signature of the message shall be computed, and the API 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). - * - * 2. The enc_mac_keys pointer must be either null, or point inside the - * message. If the pointer enc_mac_keys is not null, the API shall verify - * that the two pointers enc_mac_keys_iv and enc_mac_keys point to locations - * in the message. I.e. (message <= p && p < message+message_length)for p in - * each of enc_mac_keys_iv, enc_mac_keys. If not, return - * OEMCrypto_ERROR_INVALID_CONTEXT. - * - * 3. The API shall verify that each pointer in each KeyObject points to a - * location in the message. I.e. (message <= p && p < message+message_length) - * for p in each of key_id, key_data_iv, key_data, key_control_iv, - * key_control. If not, return OEMCrypto_ERROR_INVALID_CONTEXT. - * - * 4. Each key’s control block, after decryption, shall have a valid - * verification field. If not, return OEMCrypto_ERROR_INVALID_CONTEXT. - * - * 5. If any key control block has the Nonce_Enabled bit set, that key’s Nonce - * field shall match the nonce generated by the current nonce. If not, return - * OEMCrypto_ERROR_INVALID_NONCE. If there is a match, remove that nonce from - * the cache. Note that all the key control blocks in a particular call shall - * have the same nonce value. - * - * 6. If any key control block has the Require_AntiRollback_Hardware bit set, - * and the device does not protect the usage table from rollback, then do not - * load the keys and return OEMCrypto_ERROR_UNKNOWN_FAILURE. - * - * 7. If the key control block has a nonzero Replay_Control, then the - * verification described below is also performed. - * - * 8. If num_keys == 0, then return OEMCrypto_ERROR_INVALID_CONTEXT. - * - * Usage Table and Provider Session Token (pst): + * 1. The signature of the message shall be computed, and the API 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). + * 2. The enc_mac_keys substring must either have zero length, or satisfy + * the range check. I.e. (offset < message_length) && (offset + length + * < message_length) && (offset < offset+length),and offset+length does + * not cause an integer overflow. If it does not have zero length, then + * enc_mac_keys_iv must not have zero length, and must also satisfy the + * range check. If not, return OEMCrypto_ERROR_INVALID_CONTEXT. + * 3. The API shall verify that each substring in each KeyObject points to + * a location in the message. I.e. (offset < message_length) && + * (offset + length < message_length) && (offset < offset+length) and + * offset+length does not cause an integer overflow, for each of key_id, + * key_data_iv, key_data, key_control_iv, key_control. If not, return + * OEMCrypto_ERROR_INVALID_CONTEXT. + * 4. Each key's control block, after decryption, shall have a valid + * verification field. If not, return OEMCrypto_ERROR_INVALID_CONTEXT. + * 5. If any key control block has the Nonce_Enabled bit set, that key's + * Nonce field shall match a nonce in the cache. If not, return + * OEMCrypto_ERROR_INVALID_NONCE. If there is a match, remove that + * nonce from the cache. Note that all the key control blocks in a + * particular call shall have the same nonce value. + * 6. If any key control block has the Require_AntiRollback_Hardware bit + * set, and the device does not protect the usage table from rollback, + * then do not load the keys and return OEMCrypto_ERROR_UNKNOWN_FAILURE. + * 7. If the key control block has a nonzero Replay_Control, then the + * verification described below is also performed. + * 8. If the key control block has the bit SRMVersionRequired is set, then + * the verification described below is also performed. If the SRM + * requirement is not met, then the key control block's HDCP_Version + * will be changed to 0xF - local display only. + * 9. If num_keys == 0, then return OEMCrypto_ERROR_INVALID_CONTEXT. + * 10. If any key control block has the Shared_License bit set, and this + * call to LoadKeys is not replacing keys loaded from a previous call to + * LoadKeys, then the keys are not loaded, and the error + * OEMCrypto_ERROR_MISSING_MASTER is returned. This feature is obsolete, + * and no longer used by production license servers. OEMCrypto unit + * tests for this feature have been removed. + * 11. If this session is associated with a usage table entry, and that + * entry is marked as "inactive" (either kInactiveUsed or + * kInactiveUnused), then the keys are not loaded, and the error + * OEMCrypto_ERROR_LICENSE_INACTIVE is returned. + * Usage Table and Provider Session Token (pst) * * If a key control block has a nonzero value for Replay_Control, then all - * keys in this license will have the same value. In this case, the following - * additional checks are performed. - * - * The pointer pst must not be null, and must point to a location in the - * message. If not, return OEMCrypto_ERROR_INVALID_CONTEXT. - * - * - If Replay_Control is 1 = Nonce_Required, then OEMCrypto will perform a - * nonce check as described above. OEMCrypto will verify that the table - * does not already have an entry for the value of pst passed in as a - * parameter. If an entry already exists, an error - * OEMCrypto_ERROR_INVALID_CONTEXT is returned and no keys are - * loaded. OEMCrypto will then create a new entry in the table, and mark - * this session as using this new entry. This prevents the license from - * being loaded more than once, and will be used for online streaming. - * - * - If Replay_Control is 2 = "Require existing Session Usage table entry or - * Nonce", then OEMCrypto will check the Session Usage table for an existing - * entry with the same pst. - * - * --- If the pst is not in the table yet, a new entry will be created in the - * table and this session shall use the new entry. In that case, the nonce - * will be verified for each key. - * - * --- If an existing usage table entry is found, then this session will use - * that entry. In that case, the nonce will not be verified for each key. - * Also, the entry’s mac keys will be verified against the current - * session’s mac keys. This allows an offline license to be reloaded but - * maintain continuity of the playback times from one session to the next. - * - * - If the nonce is not valid and an existing entry is not found, the return - * error is OEMCrypto_ERROR_INVALID_NONCE. + * keys in this license will have the same value for Replay_Control. In this + * case, the following additional checks are performed. * + * - The substring pst must have nonzero length and must satisfy the range + * check described above. If not, return + * OEMCrypto_ERROR_INVALID_CONTEXT. + * - The session must be associated with a usage table entry, either + * created via OEMCrypto_CreateNewUsageEntry or loaded via + * OEMCrypto_LoadUsageEntry. + * - If Replay_Control is 1 = Nonce_Required, then OEMCrypto will perform a + * nonce check as described above. OEMCrypto will verify that the + * usage entry is newly created with OEMCrypto_CreateNewUsageEntry. If + * an existing entry was reloaded, an error + * OEMCrypto_ERROR_INVALID_CONTEXT is returned and no keys are loaded. + * OEMCrypto will then copy the pst and the mac keys to the usage entry, + * and set the status to Unused. This Replay_Control prevents the + * license from being loaded more than once, and will be used for online + * streaming. + * - If Replay_Control is 2 = "Require existing Session Usage table entry + * or Nonce", then OEMCrypto will behave slightly differently on the + * first call to LoadKeys for this license. + * * If the usage entry was created with OEMCrypto_CreateNewUsageEntry + * for this session, then OEMCrypto will verify the nonce for each + * key. OEMCrypto will copy the pst and mac keys to the usage + * entry. The license received time of the entry will be updated + * to the current time, and the status will be set to Unused. + * * If the usage entry was loaded with OEMCrypto_LoadUsageEntry for + * this session, then OEMCrypto will NOT verify the nonce for each + * key. Instead, it will verify that the pst passed in matches + * that in the entry. Also, the entry's mac keys will be verified + * against the current session's mac keys. This allows an offline + * license to be reloaded but maintain continuity of the playback + * times from one session to the next. + * * If the nonce is not valid and a usage entry was not loaded, the + * return error is OEMCrypto_ERROR_INVALID_NONCE. + * * If the loaded usage entry has a pst that does not match, + * OEMCrypto returns the error OEMCrypto_ERROR_WRONG_PST. + * * If the loaded usage entry has mac keys that do not match the + * license, OEMCrypto returns the error OEMCrypto_ERROR_WRONG_KEYS. * Note: If LoadKeys updates the mac keys, then the new updated mac keys will - * be used in the Usage Table. If LoadKeys does not update the mac keys, the - * existing session mac keys are stored in the usage table. + * be used with the Usage Entry -- i.e. the new keys are stored in the + * usage table when creating a new entry, or the new keys are verified + * against those in the usage table if there is an existing entry. If + * LoadKeys does not update the mac keys, the existing session mac keys are + * used. * * Sessions that are associated with an entry will need to be able to update * and verify the status of the entry, and the time stamps in the entry. @@ -855,69 +1102,91 @@ OEMCryptoResult OEMCrypto_GenerateSignature(OEMCrypto_SESSION session, * Devices that do not support the Usage Table will return * OEMCrypto_ERROR_INVALID_CONTEXT if the Replay_Control is nonzero. * - * Note: If LoadKeys creates a new entry in the usage table, OEMCrypto will - * increment the Usage Table’s generation number, and then sign, encrypt, and - * save the Usage Table. + * SRM Restriction Data + * + * If any key control block has the flag SRMVersionRequired set, then the + * following verification is also performed. + * + * 1. The substring srm_restriction_data must have nonzero length and must + * satisfy the range check described above. If not, return + * OEMCrypto_ERROR_INVALID_CONTEXT. + * 2. The first 8 bytes of srm_restriction_data must match the string + * "HDCPDATA". If not, return OEMCrypto_ERROR_INVALID_CONTEXT. + * 3. The next 4 bytes of srm_restriction_data will be converted from + * network byte order. If the current SRM installed on the device has a + * version number less than this, then the SRM requirement is not met. + * If the device does not support SRM files, or OEMCrypto cannot + * determine the current SRM version number, then the SRM requirement is + * not met. + * Note: if the current SRM version requirement is not met, LoadKeys will + * still succeed and the keys will be loaded. However, those keys with the + * SRMVersionRequired bit set will have their HDCP_Version increased to 0xF - + * local display only. Any future call to SelectKey for these keys while + * there is an external display will return OEMCrypto_ERROR_INSUFFICIENT_HDCP + * at that time. * * Parameters: - * session (in) - crypto session identifier. - * message (in) - pointer to memory containing message to be verified. - * message_length (in) - length of the message, in bytes. - * signature (in) - pointer to memory containing the signature. - * signature_length (in) - length of the signature, in bytes. - * enc_mac_keys_iv (in) - IV for decrypting new mac_key. Size is 128 bits. - * enc_mac_keys (in) - encrypted mac_keys for generating new mac_keys. Size is - * 512 bits. - * num_keys (in) - number of keys present. - * key_array (in) - set of keys to be installed. - * pst (in) - the Provider Session Token. - * pst_length (in) - the length of pst. - * srm_restriction_data (in) - optional data specifying the minimum SRM - * version. - * license_type (in) - specifies if the license contains content keys or - * entitlement keys. - - * - * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. + * [in] session: crypto session identifier. + * [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] enc_mac_key_iv: IV for decrypting new mac_key. Size is 128 bits. + * [in] enc_mac_keys: encrypted mac_keys for generating new mac_keys. Size is + * 512 bits. + * [in] num_keys: number of keys present. + * [in] key_array: set of keys to be installed. + * [in] pst: the Provider Session Token. + * [in] srm_restriction_data: optional data specifying the minimum SRM + * version. + * [in] license_type: specifies if the license contains content keys or + * entitlement keys. * * Returns: * OEMCrypto_SUCCESS success * OEMCrypto_ERROR_NO_DEVICE_KEY * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_UNKNOWN_FAILURE * OEMCrypto_ERROR_INVALID_CONTEXT * OEMCrypto_ERROR_SIGNATURE_FAILURE * OEMCrypto_ERROR_INVALID_NONCE * OEMCrypto_ERROR_TOO_MANY_KEYS - * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_NOT_IMPLEMENTED * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * - * Buffer Sizes + * Buffer Sizes: * OEMCrypto shall support message sizes of at least 8 KiB. * 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 14. */ OEMCryptoResult OEMCrypto_LoadKeys( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length, - const uint8_t* enc_mac_keys_iv, const uint8_t* enc_mac_keys, - size_t num_keys, const OEMCrypto_KeyObject* key_array, const uint8_t* pst, - size_t pst_length, const uint8_t* srm_requirement, + OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys, + size_t num_keys, const OEMCrypto_KeyObject* key_array, + OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data, OEMCrypto_LicenseType license_type); - /* * OEMCrypto_LoadEntitledContentKeys * * Description: - * Load content keys into a session which already has entitlement - * keys loaded. This function will only be called for a session after a call - * to OEMCrypto_LoadKeys with the parameter type license_type equal to - * OEMCrypto_EntitlementLicense. This function may be called multiple times + * Load content keys into a session which already has entitlement keys + * loaded. This function will only be called for a session after a call to + * OEMCrypto_LoadKeys with the parameter type license_type equal to + * OEMCrypto_EntitlementLicense. This function may be called multiple times * for the same session. * * If the session does not have license_type equal to @@ -926,55 +1195,59 @@ OEMCryptoResult OEMCrypto_LoadKeys( * * For each key object in key_array, OEMCrypto shall look up the entry in the * key table with the corresponding entitlement_key_id. - * 1) If no entry is found, return OEMCrypto_KEY_NOT_ENTITLED. - * 2) If the entry already has a content_key_id and content_key_data, that id - * and data are erased. - * 3) The content_key_id from the key_array is copied to the entry's - * content_key_id. - * 4) The content_key_data decrypted using the entitlement_key_data as a key - * for AES-256-CBC with an IV of content_key_data_iv, and using PKCS#7 - * padding. Notice that the entitlement key will be an AES 256 bit key. - * The clear content key data will be stored in the entry's - * content_key_data. * + * 1. If no entry is found, return OEMCrypto_KEY_NOT_ENTITLED. + * 2. If the entry already has a content_key_id and content_key_data, that + * id and data are erased. + * 3. The content_key_id from the key_array is copied to the entry's + * content_key_id. + * 4. The content_key_data decrypted using the entitlement_key_data as a + * key for AES-256-CBC with an IV of content_key_data_iv. Wrapped + * content is padded using PKCS#7 padding. Notice that the entitlement + * key will be an AES 256 bit key. The clear content key data will be + * stored in the entry's content_key_data. * Entries in the key table that do not correspond to anything in the * key_array are not modified or removed. * - * For devices that use a hardware key ladder, it may be more appropriate to - * store the encrypted content key data in the key table, and defer decrypting - * it until the function SelectKey is called. + * For devices that use a hardware key ladder, it may be more convenient to + * store the encrypted content key data in the key table, and decrypt it when + * the function SelectKey is called. * * Parameters: - * session (in) - handle for the session to be used. - * num_keys (in) - number of keys present. - * key_array (in) - set of key updates. + * [in] session: handle for the session to be used. + * [in] num_keys: number of keys present. + * [in] key_array: set of key updates. * - * Returns + * Returns: * OEMCrypto_SUCCESS success * OEMCrypto_ERROR_INVALID_SESSION * OEMCrypto_ERROR_INVALID_CONTEXT * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES * OEMCrypto_ERROR_UNKNOWN_FAILURE * OEMCrypto_KEY_NOT_ENTITLED - * Threading + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. + * 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 + * Version: * This method is new in API version 14. */ OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( - OEMCrypto_SESSION session, - size_t num_keys, - const OEMCrypto_EntitledContentKeyObject* key_array); + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + size_t num_keys, const OEMCrypto_EntitledContentKeyObject* key_array); /* * OEMCrypto_RefreshKeys * * Description: - * Updates an existing set of keys for continuing decryption in the - * current session. + * Updates an existing set of keys for continuing decryption in the current + * session. * * The relevant fields have been extracted from the Renewal Response protocol * message, but the entire message and associated signature are provided so @@ -985,37 +1258,38 @@ OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( * nonce, and nonce_enabled fields are used. All other key control bits are * not modified. * - * NOTE: OEMCrypto_GenerateDerivedKeys() or OEMCrypto_LoadKeys() must be - * called first to establish the mac_key[server]. + * NOTE: OEMCrypto_LoadKeys() must be called first to load the keys into the + * session. * - * This session’s elapsed time clock is reset to 0 when this function is - * called. The elapsed time clock is used in OEMCrypto_DecryptCENC(). + * This session's elapsed time clock is reset to 0 when this function is + * called. The elapsed time clock is used in OEMCrypto_DecryptCENC() and the + * other Decryption API functions to determine if the key has expired. * * This function does not add keys to the key table. It is only used to - * update a key control block license duration. Refer to the License Signing - * and Verification section above for more details. This function is used to + * update a key control block license duration. This function is used to * update the duration of a key, only. It is not used to update key control * bits. * - * If the KeyRefreshObject’s key_control_iv is null, then the key_control is - * not encrypted. If the key_control_iv is specified, then key_control is - * encrypted with the first 128 bits of the corresponding content key. + * If the KeyRefreshObject's key_control_iv has zero length, then the + * key_control is not encrypted. If the key_control_iv is specified, then + * key_control is encrypted with the first 128 bits of the corresponding + * content key. * - * If the KeyRefreshObject’s key_id is null, then this refresh object should - * be used to update the duration of all keys for the current session. In - * this case, key_control_iv will also be null and the control block will not - * be encrypted. + * If the KeyRefreshObject's key_id has zero length, then this refresh object + * should be used to update the duration of all keys for the current session. + * In this case, key_control_iv will also have zero length and the control + * block will not be encrypted. * * If the session's license_type is OEMCrypto_ContentLicense, and the - * KeyRefreshObject's key_id is not null, then the entry in the - * keytable with the matching content_key_id is updated. + * KeyRefreshObject's key_id is not null, then the entry in the keytable with + * the matching content_key_id is updated. * * If the session's license_type is OEMCrypto_EntitlementLicense, and the * KeyRefreshObject's key_id is not null, then the entry in the keytable with * the matching entitlment_key_id is updated. * * If the key_id is not null, and no matching entry is found in the key - * table, then return OEMCrypto_KEY_NOT_LOADED. + * table, then return OEMCrypto_ERROR_NO_CONTENT_KEY. * * Aside from the key's duration, no other values in the key control block * should be updated by this function. @@ -1023,59 +1297,62 @@ OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( * Verification: * The following checks should be performed. If any check fails, an error is * returned, and none of the keys are loaded. - * - * 1. The signature of the message shall be computed, and the API 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). - * - * 2. The API shall verify that each pointer in each KeyObject points to a - * location in the message, or is null. I.e. (message <= p && p < - * message+message_length) for p in each of key_id,key_control_iv, - * key_control. If not, return OEMCrypto_ERROR_INVALID_CONTEXT. - * - * 3. Each key’s control block shall have a valid verification field. If not, - * return OEMCrypto_ERROR_INVALID_CONTEXT. - * - * 4. If the key control block has the Nonce_Enabled bit set, the Nonce field - * shall match one of the nonces in the cache. If not, return - * OEMCrypto_ERROR_INVALID_NONCE. If there is a match, remove that nonce from - * the cache. Note that all the key control blocks in a particular call shall - * have the same nonce value. + * 1. The signature of the message shall be computed using mac_key[server], + * and the API 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). + * 2. The API shall verify that each substring in each KeyObject has zero + * length or satisfies the range check described in the discussion of + * OEMCrypto_LoadKeys. If not, return OEMCrypto_ERROR_INVALID_CONTEXT. + * 3. Each key's control block shall have a valid verification field. If + * not, return OEMCrypto_ERROR_INVALID_CONTEXT. + * 4. If the key control block has the Nonce_Enabled bit set, the Nonce + * field shall match one of the nonces in the cache. If not, return + * OEMCrypto_ERROR_INVALID_NONCE. If there is a match, remove that nonce + * from the cache. Note that all the key control blocks in a + * particular call shall have the same nonce value. + * 5. If a key ID is specified, and that key has not been loaded into this + * session, return OEMCrypto_ERROR_NO_CONTENT_KEY. * * Parameters: - * session (in) - crypto session identifier. - * message (in) - pointer to memory containing message to be verified. - * message_length (in) - length of the message, in bytes. - * signature (in) - pointer to memory containing the signature. - * signature_length (in) - length of the signature, in bytes. - * num_keys (in) - number of keys present. - * key_array (in) - set of key updates. - * - * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. + * [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_INVALID_NONCE * OEMCrypto_ERROR_SIGNATURE_FAILURE + * OEMCrypto_ERROR_INVALID_NONCE * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES * OEMCrypto_ERROR_UNKNOWN_FAILURE * OEMCrypto_ERROR_BUFFER_TOO_LARGE - * OEMCrypto_KEY_NOT_LOADED + * OEMCrypto_ERROR_NO_CONTENT_KEY + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * - * Buffer Sizes - * OEMCrypto shall support message sizes of at least 8 KiB. + * Buffer Sizes: + * OEMCrypto shall support message sizes of at least 8 KiB. * 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 8. + * This method changed in API version 12. */ OEMCryptoResult OEMCrypto_RefreshKeys( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, @@ -1086,57 +1363,54 @@ OEMCryptoResult OEMCrypto_RefreshKeys( * 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. + * Returns the decrypted key control block for the given content_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 + * 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 + * 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. + * 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 - * content_key_id (in) - The unique id of the content key of interest. - * content_key_id_length (in) - The length of key_id, in bytes. From 1 to 16 - * inclusive. - * key_control_block(out) - A caller-owned buffer. - * key_control_block_length (in/out) - The length of key_control_block buffer. + * Parameters: + * [in] content_key_id: The unique id of the key of interest. + * [in] content_key_id_length: The length of key_id, in bytes. From 1 to 16, + * inclusive. + * [out] key_control_block: A caller-owned buffer. + * [in/out] key_control_block_length. The length of key_control_block buffer. * - * Returns + * Returns: * OEMCrypto_SUCCESS * OEMCrypto_ERROR_INVALID_CONTEXT - * OEMCrypto_ERROR_SHORT_BUFFER - * OEMCrypto_ERROR_NO_CONTENT_KEY + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES * OEMCrypto_ERROR_UNKNOWN_FAILURE - * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * - * Buffer Sizes - * OEMCrypto shall support message sizes of at least 8 KiB. - * 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. * - * 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. + * Version: + * This method is new in API version 10. */ OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session, const uint8_t* content_key_id, @@ -1150,84 +1424,81 @@ OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session, * Description: * 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 + * session. The specified key must have been previously "installed" via * OEMCrypto_LoadKeys() or OEMCrypto_RefreshKeys(). * - * 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 in - * "Key Control Block Definition". + * 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 + * in "Key Control Block Definition". * * Step 1: Lookup the content key data via the offered key_id. The key data * includes the key value, and the key control block. * - * Step 2: Latch the content key into the hardware key ladder. Set - * permission flags and timers based on the key's control block. + * Step 2: Latch the content key into the hardware key ladder. Set permission + * flags and timers based on the key's control block. * - * Step 3: use the latched content key to decrypt (AES-128-CTR) buffers - * passed in via OEMCrypto_DecryptCENC(). If the key is 256 bits it - * will be used for OEMCrypto_Generic_Sign or - * OEMCrypto_Generic_Verify as specified in the key control block. - * If the key will be used with OEMCrypto_Generic_Encrypt or - * OEMCrypto_Generic_Decrypt, the cipher mode will always be - * OEMCrypto_CipherMode_CBC. Continue to use this key until - * OEMCrypto_SelectKey() is called again, or until - * OEMCrypto_CloseSession() is called. + * Step 3: use the latched content key to decrypt (AES-128-CTR or + * AES-128-CBC) buffers passed in via OEMCrypto_DecryptCENC(). If the key is + * 256 bits it will be used for OEMCrypto_Generic_Sign or + * OEMCrypto_Generic_Verify as specified in the key control block. If the key + * will be used for OEMCrypto_Generic_Encrypt or OEMCrypto_Generic_Decrypt + * then the cipher mode will always be OEMCrypto_CipherMode_CBC. Continue to + * use this key for this session until OEMCrypto_SelectKey() is called again, + * or until OEMCrypto_CloseSession() is called. * * Verification: - * The following checks should be performed if is_encrypted is true. If any - * check fails, an error is returned, and no decryption is performed. - * - * 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_KEY_NOT_LOADED. - * - * 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 - * the device should disable analog video output. If the device has analog - * output that cannot be disabled, then the key is not selected, and - * OEMCrypto_ERROR_ANALOG_OUTPUT is returned. - * - * 4. 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. - * - * 5. 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. + * 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 + * 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. + * 4. 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. + * 5. 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. * * Parameters: - * session (in) - crypto session identifier - * content_key_id (in) - pointer to the Content Key ID - * content_key_id_length (in) - length of the Key ID in bytes. From 1 to 16 - * inclusive. - * cipher_mode (in) - whether the key should be prepared for CTR mode or CBC - * mode when used in later calls to DecryptCENC. This - * should be ignored when the key is used for Generic Crypto calls. - * - * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. + * [in] session: crypto session identifier. + * [in] content_key_id: pointer to the content Key ID. + * [in] content_key_id_length: length of the content Key ID, in bytes. From + * 1 to 16, inclusive. + * [in] cipher_mode: whether the key should be prepared for CTR mode or CBC + * mode when used in later calls to DecryptCENC. This should be ignored + * when the key is used for Generic Crypto calls. * * Returns: * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_KEY_EXPIRED - if the key'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 * OEMCrypto_ERROR_CONTROL_INVALID invalid or unsupported control input * OEMCrypto_ERROR_KEYBOX_INVALID cannot decrypt and read from Keybox - * OEMCrypto_ERROR_KEY_EXPIRED * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES * OEMCrypto_ERROR_UNKNOWN_FAILURE * OEMCrypto_ERROR_KEY_EXPIRED * OEMCrypto_ERROR_ANALOG_OUTPUT * OEMCrypto_ERROR_INSUFFICIENT_HDCP - * OEMCrypto_KEY_NOT_LOADED + * OEMCrypto_ERROR_NO_CONTENT_KEY + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * 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 14. @@ -1243,39 +1514,36 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, * Description: * Decrypts or copies the payload in the buffer referenced by the *data_addr * parameter into the buffer referenced by the out_buffer parameter, using - * the session context indicated by the session parameter. Decryption mode - * is AES-128-CTR or AES-128-CBC depending on the value of cipher_mode set in - * the OEMCrypto_KeyObject passed in to OEMCrypto_LoadKeys. If is_encrypted - * is true, the content key associated with the session is latched in the - * active hardware key ladder and is used for the decryption operation. If - * is_encrypted is false, the data is simply copied. + * the session context indicated by the session parameter. Decryption mode is + * AES-128-CTR or AES-128-CBC depending on the value of cipher_mode passed in + * to OEMCrypto_SelectKey. If is_encrypted is true, the content key + * associated with the session is latched in the active hardware key ladder + * and is used for the decryption operation. If is_encrypted is false, the + * data is simply copied. * * After decryption, the data_length bytes are copied to the location * described by out_buffer. This could be one of * - * 1. The structure out_buffer contains a pointer to a clear text buffer. The - * OEMCrypto library shall verify that key control allows data to be returned - * in clear text. If it is not authorized, this method should return an - * error. + * 1. The structure out_buffer contains a pointer to a clear text buffer. + * The OEMCrypto library shall verify that key control allows data to be + * returned in clear text. If it is not authorized, this method should + * return an error. + * 2. The structure out_buffer contains a handle to a secure buffer. + * 3. The structure out_buffer indicates that the data should be sent + * directly to the decoder and renderer. + * NOTES: * - * 2. The structure out_buffer contains a handle to a secure buffer. - * - * 3. The structure out_buffer indicates that the data should be sent - * directly to the decoder and rendered. - * - * NOTES: * For CTR mode, IV points to the counter value to be used for the initial - * encrypted block of the input buffer. The IV length is the AES block - * size. For subsequent encrypted AES blocks the IV is calculated by - * incrementing the lower 64 bits (byte 8-15) of the IV value used for the - * previous block. The counter rolls over to zero when it reaches its maximum - * value (0xFFFFFFFFFFFFFFFF). The upper 64 bits (byte 0-7) of the IV do not - * change. + * encrypted block of the input buffer. The IV length is the AES block size. + * For subsequent encrypted AES blocks the IV is calculated by incrementing + * the lower 64 bits (byte 8-15) of the IV value used for the previous block. + * The counter rolls over to zero when it reaches its maximum value + * (0xFFFFFFFFFFFFFFFF). The upper 64 bits (byte 0-7) of the IV do not change. * - * For CBC mode, IV points to the initialization vector for cipher block - * chaining. Within each subsample, OEMCrypto is responsible for updating - * the IV as prescribed by CBC mode. The calling layer above is responsible - * for updating the IV from one subsample to the next if needed. + * For CBC mode, IV points to the initial vector for cipher block chaining. + * Within each subsample, OEMCrypto is responsible for updating the IV as + * prescribed by CBC mode. The calling layer above is responsible for + * updating the IV from one subsample to the next if needed. * * This method may be called several times before the decrypted data is used. * For this reason, the parameter subsample_flags may be used to optimize @@ -1295,15 +1563,15 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, * change the status to "active" and set the time_of_first_decrypt. * * The decryption mode, either OEMCrypto_CipherMode_CTR or - * OEMCrypto_CipherMode_CBC, was specified in the call to OEMCrypto_SelectKey. - * The encryption pattern is specified by the fields in the parameter - * pattern. A description of partial encryption patterns can be found in the - * document Draft International Standard ISO/IEC DIS 23001-7. Search for the - * codes "cenc", "cbc1", "cens" or "cbcs". + * OEMCrypto_CipherMode_CBC, was specified in the call to + * OEMCrypto_SelectKey. The encryption pattern is specified by the fields in + * the parameter pattern. A description of partial encryption patterns can be + * found in the document Draft International Standard ISO/IEC DIS 23001-7. + * Search for the codes "cenc", "cbc1", "cens" or "cbcs". * * The most common mode is "cenc", which is OEMCrypto_CipherMode_CTR without - * a pattern. The entire subsample is either encrypted or clear, depending - * on the flag is_encrypted. In the structure pattern, both encrypt and skip + * a pattern. The entire subsample is either encrypted or clear, depending on + * the flag is_encrypted. In the structure pattern, both encrypt and skip * will be 0. This is the only mode that allows for a nonzero block_offset. * * A less common mode is "cens", which is OEMCrypto_CipherMode_CTR with an @@ -1317,82 +1585,75 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, * block will be in the clear. * * The mode "cbcs" is OEMCrypto_CipherMode_CBC with an encryption pattern. - * This mode allows devices to decrypt HLS content. If an encrypted - * subsample has a length that is not a multiple of 16, the final partial - * block will be in the clear. + * This mode allows devices to decrypt HLS content. If an encrypted subsample + * has a length that is not a multiple of 16, the final partial block will be + * in the clear. In practice, the most common pattern is (1, 9), or 1 + * encrypted block followed by 9 clear blocks. The ISO-CENC spec implicitly + * limits both the skip and encrypt values to be 4 bits, so a value of at + * most 15. * * A sample may be broken up into a mix of clear and encrypted subsamples. In * order to support the VP9 standard, the breakup of a subsample into clear * and encrypted subsamples is not always in pairs. * + * If OEMCrypto assembles all of the subsamples into a single buffer and then + * decrypts, it can assume that the block offset is 0. + * * Verification: * The following checks should be performed if is_encrypted is true. If any * check fails, an error is returned, and no decryption is performed. - * - * 1. 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. If not, return OEMCrypto_ERROR_KEY_EXPIRED. - * - * 2. If the current key’s control block has the Data_Path_Type bit set, then - * the API shall verify that the output buffer is secure or direct. If not, - * return OEMCrypto_ERROR_DECRYPT_FAILED. - * - * 3. If the current key control block has the bit Disable_Analog_Output set, - * then the device should disable analog video output. If the device has - * analog output that cannot be disabled, then the key is not selected, and - * OEMCrypto_ERROR_ANALOG_OUTPUT is returned. - * - * 4. If the current key’s control block has the HDCP bit set, then the API - * shall verify that the buffer will be output using HDCP only. If not, - * return OEMCrypto_ERROR_INSUFFICIENT_HDCP. - * - * 4. If the current key’s control block has a nonzero value for - * HDCP_Version, then the current version of HDCP for the device and the - * display combined will be compared against the version specified in the - * control block. If the current version is not at least as high as that in - * the control block, then return OEMCrypto_ERROR_INSUFFICIENT_HDCP. - * - * 5. If the current session has an entry in the Usage Table, and the status - * of that entry is either kInactiveUsed or kInactiveUnused, then return the - * error OEMCrypto_ERROR_LICENSE_INACTIVE. - * + * 1. 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. If not, return OEMCrypto_ERROR_KEY_EXPIRED. + * 2. If the current key's control block has the Data_Path_Type bit set, + * then the API shall verify that the output buffer is secure or direct. + * If not, return OEMCrypto_ERROR_DECRYPT_FAILED. + * 3. If the current 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 + * OEMCrypto_ERROR_ANALOG_OUTPUT is returned. + * 4. If the current key's control block has the HDCP bit set, then the API + * shall verify that the buffer will be displayed locally, or output + * externally using HDCP only. If not, return + * OEMCrypto_ERROR_INSUFFICIENT_HDCP. + * 5. If the current key's control block has a nonzero value for + * HDCP_Version, then the current version of HDCP for the device and the + * display combined will be compared against the version specified in + * the control block. If the current version is not at least as high as + * that in the control block, then return + * OEMCrypto_ERROR_INSUFFICIENT_HDCP. + * 6. If the current session has an entry in the Usage Table, and the + * status of that entry is either kInactiveUsed or kInactiveUnused, then + * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. * If the flag is_encrypted is false, then no verification is performed. This * call shall copy clear data even when there are no keys loaded, or there is * no selected key. * * Parameters: - * session (in) - crypto session identifier. - * data_addr (in) - An unaligned pointer to this segment of the stream. - * data_length (in) - The length of this segment of the stream, in bytes. - * is_encrypted (in) - True if the buffer described by data_addr, data_length - * is encrypted. If is_encrypted is false, only the - * data_addr and data_length parameters are used. The iv - * and offset arguments are ignored. - * iv (in) - The initial value block to be used for content decryption. - * block_offset (in) - If non-zero, the decryption block boundary is - * different from the start of the data. block_offset - * should be subtracted from data_addr to compute the - * starting address of the first decrypted block. The - * bytes between the decryption block start address and - * data_addr are discarded after decryption. It does not - * adjust the beginning of the source or destination - * data. This parameter satisfies 0 <= block_offset < - * 16. This paramater is only used for CTR mode. - * out_buffer (in) - A caller-owned descriptor that specifies the handling of - * the decrypted byte stream. See OEMCrypto_DestbufferDesc - * for details. - * pattern (in) - A caller-owned structure indicating the encrypt/skip - * pattern as specified in the CENC standard. - * 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. - * - * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. + * [in] session: crypto session identifier. + * [in] data_addr: An unaligned pointer to this segment of the stream. + * [in] data_length: The length of this segment of the stream, in bytes. + * [in] is_encrypted: True if the buffer described by data_addr, data_length + * is encrypted. If is_encrypted is false, only the data_addr and + * data_length parameters are used. The iv and offset arguments are + * ignored. + * [in] iv: The initial value block to be used for content decryption. + * This is discussed further below. + * [in] block_offset: If non-zero, the decryption block boundary is different + * from the start of the data. block_offset should be subtracted from + * data_addr to compute the starting address of the first decrypted + * block. The bytes between the decryption block start address and + * data_addr are discarded after decryption. It does not adjust the + * beginning of the source or destination data. This parameter + * satisfies 0 <= block_offset < 16. + * [in] out_buffer: A caller-owned descriptor that specifies the handling of + * the decrypted byte stream. See OEMCrypto_DestbufferDesc for details. + * [in] pattern: A caller-owned structure indicating the encrypt/skip pattern + * as specified in the CENC standard. + * [in] subsample_flags: bitwise flags indicating if this is the first, + * middle, or last subsample in a chunk of data. 1 = first subsample, 2 + * = last subsample, 3 = both first and last subsample, 0 = neither + * first nor last subsample. * * Returns: * OEMCrypto_SUCCESS @@ -1406,25 +1667,40 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES * OEMCrypto_ERROR_UNKNOWN_FAILURE * OEMCrypto_ERROR_BUFFER_TOO_LARGE - * OEMCrypto_ERROR_LICENSE_INACTIVE + * OEMCrypto_ERROR_OUTPUT_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * - * Buffer Sizes - * OEMCrypto shall support subsample sizes (i.e. data_length) of at least - * 100 KiB. - * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is - * larger than the supported size. If OEMCrypto returns - * OEMCrypto_ERROR_BUFFER_TOO_LARGE, the calling function must break the buffer - * into smaller chunks. For high performance devices, OEMCrypto should handle - * larger buffers. We encourage OEMCrypto implementers to not artificially - * restrict the maximum buffer size. + * Buffer Sizes: + * OEMCrypto shall support subsample sizes (i.e. data_length) of at least 100 + * KiB. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. If OEMCrypto returns + * OEMCrypto_ERROR_BUFFER_TOO_LARGE, the calling function must break the + * buffer into smaller chunks. For high performance devices, OEMCrypto should + * handle larger buffers. We encourage OEMCrypto implementers not to + * artificially restrict the maximum buffer size. + * If OEMCrypto detects that the output data is too large, and breaking the + * buffer into smaller subsamples will not work, then it returns + * OEMCrypto_ERROR_OUTPUT_TOO_LARGE. This error will bubble up to the + * application, which can decide to skip the current frame of video or to + * switch to a lower resolution. + * + * 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 13. - * This method changed its name in API version 11. + * This method changed in API version 15. This method changed its name in API + * version 11. */ OEMCryptoResult OEMCrypto_DecryptCENC( OEMCrypto_SESSION session, const uint8_t* data_addr, size_t data_length, - bool is_encrypted, const uint8_t* iv, size_t block_offset, + bool is_encrypted, const uint8_t* iv, + size_t block_offset, // used for CTR "cenc" mode only. OEMCrypto_DestBufferDesc* out_buffer, const OEMCrypto_CENCEncryptPatternDesc* pattern, uint8_t subsample_flags); @@ -1439,18 +1715,18 @@ OEMCryptoResult OEMCrypto_DecryptCENC( * * The main difference between this and DecryptCENC 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 + * other 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: + * 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 + * 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. @@ -1459,140 +1735,434 @@ OEMCryptoResult OEMCrypto_DecryptCENC( * CopyBuffer begins storing data out_buffer->secure.offset bytes after the * beginning of the secure buffer. * - * Verification + * Verification: * The following checks should be performed. - * 1. If either data_addr or out_buffer is null, return - * OEMCrypto_ERROR_INVALID_CONTEXT. + * 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. + * Parameters: + * [in] session: crypto session identifier. + * [in] data_addr: An unaligned pointer to the buffer to be copied. + * [in] data_length: The length of the buffer, in bytes. + * [in] out_buffer: A caller-owned descriptor that specifies the handling of + * the byte stream. See OEMCrypto_DestbufferDesc for details. + * [in] subsample_flags: bitwise flags indicating if this is the first, + * middle, or last subsample in a chunk of data. 1 = first subsample, 2 + * = last subsample, 3 = both first and last subsample, 0 = neither + * first nor last subsample. * - * Returns + * Returns: * OEMCrypto_SUCCESS * OEMCrypto_ERROR_INVALID_CONTEXT + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES * OEMCrypto_ERROR_UNKNOWN_FAILURE * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_OUTPUT_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * - * Buffer Sizes - * OEMCrypto shall support subsample sizes (i.e. data_length) of at least - * 100 KiB. - * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is - * larger than the supported size. If OEMCrypto returns - * OEMCrypto_ERROR_BUFFER_TOO_LARGE, the calling function must break the buffer - * into smaller chunks. For high performance devices, OEMCrypto should handle - * larger buffers. We encourage OEMCrypto implementers to not artificially - * restrict the maximum buffer size. + * Buffer Sizes: + * OEMCrypto shall support subsample sizes (i.e. data_length) up to 100 KiB. + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. If OEMCrypto returns + * OEMCrypto_ERROR_BUFFER_TOO_LARGE, the calling function must break the + * buffer into smaller chunks. For high performance devices, OEMCrypto should + * handle larger buffers. We encourage OEMCrypto implementers not to + * artificially restrict the maximum buffer size. + * If OEMCrypto detects that the output data is too large, and breaking the + * buffer into smaller subsamples will not work, then it returns + * OEMCrypto_ERROR_OUTPUT_TOO_LARGE. This error will bubble up to the + * application, which can decide to skip the current frame of video or to + * switch to a lower resolution. * - * Threading - * This function may be called simultaneously with any other functions. - * Version - * This method changed in API version 12. + * 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 changed in API version 15. */ -OEMCryptoResult OEMCrypto_CopyBuffer(const uint8_t* data_addr, +OEMCryptoResult OEMCrypto_CopyBuffer(OEMCrypto_SESSION session, + const uint8_t* data_addr, size_t data_length, OEMCrypto_DestBufferDesc* out_buffer, uint8_t subsample_flags); /* - * OEMCrypto_WrapKeyboxOrOEMCert + * OEMCrypto_Generic_Encrypt * * Description: + * This function encrypts a generic buffer of data using the current key. * - * A device should be provisioned at the factory with either an OEM - * Certificate or a keybox. We will call this data the root of trust. During - * manufacturing, the root of trust should be encrypted with the OEM root key - * and stored on the file system in a region that will not be erased during - * factory reset. This function may be used by legacy systems that use the - * two-step WrapKeyboxOrOEMCert/InstallKeyboxOrOEMCert approach. When - * the Widevine DRM plugin initializes, it will look for a wrapped root of - * trust in the file /factory/wv.keys and install it into the security - * processor by calling OEMCrypto_InstallKeyboxOrOEMCert(). + * If the session has an entry in the Usage Table, then OEMCrypto will update + * 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_WrapKeyboxOrOEMCert() is used to generate an OEM-encrypted - * root of trust that may be passed to OEMCrypto_InstallKeyboxOrOEMCert() - * for provisioning. The root of trust may be either passed in the clear or - * previously encrypted with a transport key. If a transport key is supplied, - * the keybox is first decrypted with the transport key before being wrapped - * with the OEM root key. This function is only needed if the root of trust - * provisioning method involves saving the keybox to the file system. + * OEMCrypto should be able to handle buffers at least 100 KiB long. + * + * Verification: + * The following checks should be performed. If any check fails, an error is + * returned, and the data is not encrypted. + * 1. The control bit for the current key shall have the Allow_Encrypt set. + * If not, return OEMCrypto_ERROR_UNKNOWN_FAILURE. + * 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. If not, return OEMCrypto_ERROR_KEY_EXPIRED. + * 3. If the current session has an entry in the Usage Table, and the + * status of that entry is either kInactiveUsed or kInactiveUnused, then + * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. * * Parameters: - * rot (in) - pointer to root of trust data to encrypt. May be NULL on the - * first call to test size of wrapped keybox. The keybox may either be - * clear or previously encrypted. - * rotLength (in) - length the rot data in bytes - * wrappedRot (out) – Pointer to wrapped rot - * wrappedRotLength (out) – Pointer to the length of the wrapped keybox in - * bytes - * transportKey (in) – Optional. AES transport key. If provided, the rot - * parameter was previously encrypted with this key. The rot 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: - * This function is not called simultaneously with any other functions + * [in] session: crypto session identifier. + * [in] in_buffer: pointer to memory containing data to be encrypted. + * [in] buffer_length: length of the buffer, in bytes. The algorithm may + * restrict buffer_length to be a multiple of block size. + * [in] iv: IV for encrypting data. Size is 128 bits. + * [in] algorithm: Specifies which encryption algorithm to use. Currently, + * only CBC 128 mode is allowed for encryption. + * [out] out_buffer: pointer to buffer in which encrypted data should be + * stored. * * Returns: * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_WRAP_KEYBOX failed to wrap Keybox - * OEMCrypto_ERROR_SHORT_BUFFER if keybox is provided as NULL, to determine - * the size of the wrapped keybox + * OEMCrypto_ERROR_KEY_EXPIRED + * OEMCrypto_ERROR_NO_DEVICE_KEY + * OEMCrypto_ERROR_INVALID_SESSION * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES - * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support buffers sizes of at least 100 KiB for generic + * crypto operations. + * 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 supported by all API versions. + * This method changed in API version 12. */ -OEMCryptoResult OEMCrypto_WrapKeyboxOrOEMCert(const uint8_t* rot, size_t rotLength, - uint8_t* wrappedRot, - size_t* wrappedRotLength, - const uint8_t* transportKey, - size_t transportKeyLength); +OEMCryptoResult OEMCrypto_Generic_Encrypt( + OEMCrypto_SESSION session, const uint8_t* in_buffer, size_t buffer_length, + const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer); + +/* + * OEMCrypto_Generic_Decrypt + * + * Description: + * This function decrypts a generic buffer of data using the current key. + * + * If the session has an entry in the Usage Table, then OEMCrypto will update + * 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. + * + * Verification: + * The following checks should be performed. If any check fails, an error is + * returned, and the data is not decrypted. + * 1. The control bit for the current key shall have the Allow_Decrypt set. + * If not, return OEMCrypto_ERROR_DECRYPT_FAILED. + * 2. If the current key's control block has the Data_Path_Type bit set, + * then return OEMCrypto_ERROR_DECRYPT_FAILED. + * 3. 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. If not, return OEMCrypto_ERROR_KEY_EXPIRED. + * 4. If the current session has an entry in the Usage Table, and the + * status of that entry is either kInactiveUsed or kInactiveUnused, then + * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. + * + * Parameters: + * [in] session: crypto session identifier. + * [in] in_buffer: pointer to memory containing data to be encrypted. + * [in] buffer_length: length of the buffer, in bytes. The algorithm may + * restrict buffer_length to be a multiple of block size. + * [in] iv: IV for encrypting data. Size is 128 bits. + * [in] algorithm: Specifies which encryption algorithm to use. Currently, + * only CBC 128 mode is allowed for decryption. + * [out] out_buffer: pointer to buffer in which decrypted data should be + * stored. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_KEY_EXPIRED + * OEMCrypto_ERROR_DECRYPT_FAILED + * OEMCrypto_ERROR_NO_DEVICE_KEY + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support buffers sizes of at least 100 KiB for generic + * crypto operations. + * 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 12. + */ +OEMCryptoResult OEMCrypto_Generic_Decrypt( + OEMCrypto_SESSION session, const uint8_t* in_buffer, size_t buffer_length, + const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer); + +/* + * OEMCrypto_Generic_Sign + * + * Description: + * This function signs a generic buffer of data using the current key. + * + * If the session has an entry in the Usage Table, then OEMCrypto will update + * 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. + * + * Verification: + * The following checks should be performed. If any check fails, an error is + * returned, and the data is not signed. + * 1. The control bit for the current key shall have the Allow_Sign set. + * 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. If not, return OEMCrypto_ERROR_KEY_EXPIRED. + * 3. If the current session has an entry in the Usage Table, and the + * status of that entry is either kInactiveUsed or kInactiveUnused, then + * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. + * + * Parameters: + * [in] session: crypto session identifier. + * [in] in_buffer: pointer to memory containing data to be encrypted. + * [in] buffer_length: length of the buffer, in bytes. + * [in] algorithm: Specifies which algorithm to use. + * [out] signature: pointer to buffer in which signature should be stored. + * May be null on the first call in order to find required buffer size. + * [in/out] signature_length: (in) length of the signature buffer, in bytes. + * (out) actual length of the signature + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_KEY_EXPIRED + * OEMCrypto_ERROR_SHORT_BUFFER if signature buffer is not large enough to + * hold the output signature. + * OEMCrypto_ERROR_NO_DEVICE_KEY + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support buffers sizes of at least 100 KiB for generic + * crypto operations. + * 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 14. + */ +OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, + const uint8_t* in_buffer, + size_t buffer_length, + OEMCrypto_Algorithm algorithm, + uint8_t* signature, + size_t* signature_length); + +/* + * OEMCrypto_Generic_Verify + * + * Description: + * This function verifies the signature of a generic buffer of data using the + * current key. + * + * If the session has an entry in the Usage Table, then OEMCrypto will update + * 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. + * + * Verification: + * The following checks should be performed. If any check fails, an error is + * returned. + * 1. The control bit for the current key shall have the Allow_Verify set. + * 2. The signature of the message shall be computed, and the API shall + * verify the computed signature matches the signature passed in. If + * not, return OEMCrypto_ERROR_SIGNATURE_FAILURE. + * 3. The signature verification shall use a constant-time algorithm (a + * signature mismatch will always take the same time as a successful + * comparison). + * 4. 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. If not, return OEMCrypto_ERROR_KEY_EXPIRED. + * 5. If the current session has an entry in the Usage Table, and the + * status of that entry is either kInactiveUsed or kInactiveUnused, then + * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. + * + * Parameters: + * [in] session: crypto session identifier. + * [in] in_buffer: pointer to memory containing data to be encrypted. + * [in] buffer_length: length of the buffer, in bytes. + * [in] algorithm: Specifies which algorithm to use. + * [in] signature: pointer to buffer in which signature resides. + * [in] signature_length: length of the signature buffer, in bytes. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_KEY_EXPIRED + * OEMCrypto_ERROR_SIGNATURE_FAILURE + * OEMCrypto_ERROR_NO_DEVICE_KEY + * OEMCrypto_ERROR_INVALID_SESSION + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Buffer Sizes: + * OEMCrypto shall support buffers sizes of at least 100 KiB for generic + * crypto operations. + * 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 14. + */ +OEMCryptoResult OEMCrypto_Generic_Verify(OEMCrypto_SESSION session, + const uint8_t* in_buffer, + size_t buffer_length, + OEMCrypto_Algorithm algorithm, + const uint8_t* signature, + size_t signature_length); + +/* + * OEMCrypto_WrapKeyboxOrOEMCert + * + * Description: + * A device should be provisioned at the factory with either an OEM + * Certificate or a keybox. We will call this data the root of trust. During + * manufacturing, the root of trust should be encrypted with the OEM root key + * and stored on the file system in a region that will not be erased during + * factory reset. This function may be used by legacy systems that use the + * two-step WrapKeyboxOrOEMCert/InstallKeyboxOrOEMCert approach. When the + * Widevine DRM plugin initializes, it will look for a wrapped root of trust + * in the file /factory/wv.keys and install it into the security processor by + * calling OEMCrypto_InstallKeyboxOrOEMCert(). + * + * Figure 10. OEMCrypto_WrapKeyboxOrOEMCert Operation + * + * OEMCrypto_WrapKeyboxOrOEMCert() is used to generate an OEM-encrypted root + * of trust that may be passed to OEMCrypto_InstallKeyboxOrOEMCert() for + * provisioning. The root of trust may be either passed in the clear or + * previously encrypted with a transport key. If a transport key is supplied, + * the keybox is first decrypted with the transport key before being wrapped + * with the OEM root key. This function is only needed if the root of trust + * provisioning method involves saving the keybox or OEM Certificate to the + * file system. + * + * Parameters: + * [in] rot - pointer to root of trust data to encrypt -- this is either a + * keybox or an OEM Certificate private key. May be NULL on the first + * call to test size of wrapped keybox. The keybox may either be clear + * or previously encrypted. + * [in] rotLength - length the keybox data in bytes + * [out] wrappedRot – Pointer to wrapped keybox + * [out] wrappedRotLength – Pointer to the length of the wrapped rot in bytes + * [in] transportKey – Optional. AES transport key. If provided, the rot + * parameter was previously encrypted with this key. The keybox will be + * decrypted with the transport key using AES-CBC and a null IV. + * [in] transportKeyLength – Optional. Number of bytes in the transportKey, + * if used. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_WRITE_KEYBOX failed to encrypt the keybox + * OEMCrypto_ERROR_SHORT_BUFFER if keybox is provided as NULL, to determine + * the size of the wrapped keybox + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is an "Initialization and Termination 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 supported in all API versions. + */ +OEMCryptoResult OEMCrypto_WrapKeyboxOrOEMCert(const uint8_t* rot, + size_t rotLength, + uint8_t* wrappedRot, + size_t* wrappedRotLength, + const uint8_t* transportKey, + size_t transportKeyLength); /* * OEMCrypto_InstallKeyboxOrOEMCert * * Description: - * - * Decrypts a wrapped root of trust and installs it in the security processor. - * The root of trust is unwrapped then encrypted with the OEM root key. This - * function is called from the Widevine DRM plugin at initialization time if - * there is no valid root of trust installed. It looks for wrapped data in - * the file /factory/wv.keys and if it is present, will read the file and call - * OEMCrypto_InstallKeyboxOrOEMCert() with the contents of the file. This - * function is only needed if the factory provisioning method involves saving - * the keybox to the file system. + * Decrypts a wrapped root of trust and installs it in the security + * processor. The root of trust is unwrapped then encrypted with the OEM root + * key. This function is called from the Widevine DRM plugin at + * initialization time if there is no valid root of trust installed. It looks + * for wrapped data in the file /factory/wv.keys and if it is present, will + * read the file and call OEMCrypto_InstallKeyboxOrOEMCert() with the + * contents of the file. This function is only needed if the factory + * provisioning method involves saving the keybox or OEM Certificate to the + * file system. * * Parameters: - * rot (in) - pointer to encrypted data as input - * rotLength (in) - length of the data in bytes - * - * Threading: - * This function is not called simultaneously with any other functions. + * [in] rot - pointer to encrypted data as input + * [in] rotLength - length of the data in bytes * * Returns: * OEMCrypto_SUCCESS success * OEMCrypto_ERROR_BAD_MAGIC * OEMCrypto_ERROR_BAD_CRC * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES - * OEMCrypto_ERROR_WRITE_KEYBOX failed to handle and store Keybox + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is an "Initialization and Termination 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 supported in all API versions. */ OEMCryptoResult OEMCrypto_InstallKeyboxOrOEMCert(const uint8_t* rot, - size_t rotLength); + size_t rotLength); /* * OEMCrypto_GetProvisioningMethod @@ -1605,49 +2175,205 @@ OEMCryptoResult OEMCrypto_InstallKeyboxOrOEMCert(const uint8_t* rot, * none * * Returns: - * OEMCrypto_DrmCertificate - means the device has a DRM certificate built - * into the system. This cannot be used by level 1 devices. - * OEMCrypto_Keybox - means the device has a unique keybox. For level 1 - * devices this keybox must be securely installed by the device manufacturer. - * OEMCrypto_OEMCertificate - means the device has a factory installed OEM - * certificate. This is also called Provisioning 3.0. + * - DrmCertificate means the device has a DRM certificate built into the + * system. This cannot be used by level 1 devices. This provisioning + * method is deprecated and should not be used on new devices. + * OEMCertificate provisioning should be used instead. + * - Keybox means the device has a unique keybox. For level 1 devices this + * keybox must be securely installed by the device manufacturer. + * - OEMCertificate means the device has a factory installed OEM + * certificate. This is also called Provisioning 3.0. + * - ProvisioningError indicates a serious problem with the OEMCrypto + * library. * * Threading: - * This function may be called simultaneously with any session functions. + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. * * Version: * This method is new API version 12. */ OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod(); +/* + * OEMCrypto_IsKeyboxOrOEMCertValid + * + * Description: + * If the device has a keybox, this validates the Widevine Keybox loaded into + * the security processor device. This method verifies two fields in the + * keybox: + * + * - Verify the MAGIC field contains a valid signature (such as, + * 'k''b''o''x'). + * - Compute the CRC using CRC-32-POSIX-1003.2 standard and compare the + * checksum to the CRC stored in the Keybox. + * The CRC is computed over the entire Keybox excluding the 4 bytes of the + * CRC (for example, Keybox[0..123]). For a description of the fields stored + * in the keybox, see Keybox Definition. + * + * If the device has an OEM Certificate, this validates the certificate + * private key. + * + * Parameters: + * none + * + * Returns: + * OEMCrypto_SUCCESS + * OEMCrypto_ERROR_BAD_MAGIC + * OEMCrypto_ERROR_BAD_CRC + * OEMCrypto_ERROR_KEYBOX_INVALID + * OEMCrypto_ERROR_INVALID_RSA_KEY + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method is supported in all API versions. + */ +OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void); + +/* + * OEMCrypto_GetDeviceID + * + * Description: + * Retrieve DeviceID from the Keybox. For devices that have an OEM + * Certificate instead of a keybox, this function may return + * OEMCrypto_ERROR_NOT_IMPLEMENTED. If the function is implemented on an OEM + * Certificate device, it should set the device ID to a device-unique string, + * such as the device serial number. The ID should be device-unique and it + * should be stable -- i.e. it should not change across a device reboot or a + * system upgrade. + * + * Parameters: + * [out] deviceId - pointer to the buffer that receives the Device ID + * [in/out] idLength – on input, size of the caller's device ID buffer. On + * output, the number of bytes written into the buffer. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_SHORT_BUFFER if the buffer is too small to return device ID + * OEMCrypto_ERROR_NO_DEVICEID failed to return Device Id + * OEMCrypto_ERROR_NOT_IMPLEMENTED - this function is required for + * Provisioning 2.0 only. + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method is supported in all API versions. + */ +OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, size_t* idLength); + +/* + * OEMCrypto_GetKeyData + * + * Description: + * Return the Key Data field from the Keybox. + * + * Parameters: + * [out] keyData - pointer to the buffer to hold the Key Data field from the + * Keybox + * [in/out] keyDataLength – on input, the allocated buffer size. On output, + * the number of bytes in Key Data + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_SHORT_BUFFER if the buffer is too small to return KeyData + * OEMCrypto_ERROR_NO_KEYDATA + * OEMCrypto_ERROR_NOT_IMPLEMENTED - this function is for Provisioning 2.0 + * only. + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method is supported in all API versions. + */ +OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, size_t* keyDataLength); + +/* + * OEMCrypto_LoadTestKeybox + * + * Description: + * Temporarily use the specified test keybox until the next call to + * OEMCrypto_Terminate. This allows a standard suite of unit tests to be run + * on a production device without permanently changing the keybox. Using the + * test keybox is not persistent. OEMCrypto cannot assume that this keybox is + * the same as previous keyboxes used for testing. + * + * Devices that use an OEM Certificate instead of a keybox (i.e. Provisioning + * 3.0) do not need to support this functionality, and may return + * OEMCrypto_ERROR_NOT_IMPLEMENTED. + * + * Parameters: + * [in] buffer: pointer to memory containing test keybox, in binary form. + * [in] length: length of the buffer, in bytes. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_NOT_IMPLEMENTED - this function is for Provisioning 2.0 + * only. + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. It is called after OEMCrypto_Initialize and + * after OEMCrypto_GetProvisioningMethod and only if the provisoining method + * is OEMCrypto_Keybox, + * + * Version: + * This method changed in API version 14. + */ +OEMCryptoResult OEMCrypto_LoadTestKeybox(const uint8_t* buffer, size_t length); + /* * OEMCrypto_GetOEMPublicCertificate * * Description: - * This function should place the OEM public certificate in the buffer - * public_cert. After a call to this function, all methods using an RSA key - * should use the OEM certificate’s private RSA key. See the discussion of - * Provisioning 3.0 in the document "WV Modular DRM Security Itegration Guide - * for Common Encryption (CENC)". + * This function should place the OEM public certificate in the buffer + * public_cert. After a call to this function, all methods using an RSA key + * should use the OEM certificate's private RSA key. See the section above + * discussing Provisioning 3.0. * - * If the buffer is not large enough, OEMCrypto should update - * public_cert_length and return OEMCrypto_ERROR_SHORT_BUFFER. + * If the buffer is not large enough, OEMCrypto should update + * public_cert_length and return OEMCrypto_ERROR_SHORT_BUFFER. * * Parameters: - * session (in) - this function affects the specified session only. - * public_cert (out) - the buffer where the public certificate is stored. - * public_cert_length (in/out) - on input, this is the available size of the - * buffer. On output, this is the number of bytes needed for the - * certificate. + * - [in] session: this function affects the specified session only. + * - [out] public_cert: the buffer where the public certificate is stored. + * - [in/out] public_cert_length: on input, this is the available size of + * the buffer. On output, this is the number of bytes needed for the + * certificate. * * Returns: - * OEMCrypto_SUCCESS - * OEMCrypto_ERROR_NOT_IMPLEMENTED - * OEMCrypto_ERROR_SHORT_BUFFER + * OEMCrypto_SUCCESS + * OEMCrypto_ERROR_NOT_IMPLEMENTED - this function is for Provisioning 3.0 + * only. + * OEMCrypto_ERROR_SHORT_BUFFER + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. + * 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 API version 12. @@ -1656,159 +2382,556 @@ OEMCryptoResult OEMCrypto_GetOEMPublicCertificate(OEMCrypto_SESSION session, uint8_t* public_cert, size_t* public_cert_length); -/* - * 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 - * buffer (in) - pointer to memory containing test keybox, in binary form. - * length (in) - length of the buffer, in bytes. - * - * 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(const uint8_t *buffer, size_t length); - -/* - * OEMCrypto_IsKeyboxOrOEMCertValid - * - * Description: - * - * If the device has a keybox, this validates the Widevine Keybox loaded into - * the security processor device. - * - * The API performs two verification steps on the Keybox. It first verifies - * the MAGIC field contains a valid signature (must be 'kbox'). The API then - * computes the CRC using CRC-32 (Posix 1003.2 standard) and compares the - * checksum to the CRC stored in the Keybox. The CRC is computed over the - * entire Keybox excluding the 4 CRC bytes (i.e. Keybox[0..123]). - * - * If the device has an OEM Certificate, this validates the certificate private - * key. - * - * Parameters: - * none - * - * Threading: - * This function may be called simultaneously with any session functions. - * - * Returns: - * OEMCrypto_SUCCESS - * OEMCrypto_ERROR_BAD_MAGIC - * OEMCrypto_ERROR_BAD_CRC - * OEMCrypto_ERROR_KEYBOX_INVALID - * OEMCrypto_ERROR_NOT_IMPLEMENTED - * - * Version: - * This method is supported by all API versions. - */ -OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void); - -/* - * OEMCrypto_GetDeviceID - * - * Description: - * Retrieve the device's unique identifier from the Keybox. - * - * Parameters: - * deviceId (out) - pointer to the buffer that receives the Device ID - * idLength (in/out) - on input, size of the caller's device ID buffer. - * On output, the number of bytes written into the buffer. - * - * Threading: - * This function may be called simultaneously with any session functions. - * - * Returns: - * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_SHORT_BUFFER buffer is too small to return the device ID - * OEMCrypto_ERROR_NO_DEVICEID failed to return Device Id - * - * Version: - * This method is supported by all API versions. - */ -OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, size_t* idLength); - -/* - * OEMCrypto_GetKeyData - * - * Description: - * Returns the Key Data field from the Keybox. The Key Data field does not - * need to be encrypted by an OEM root key, but may be if desired. - * - * If the Key Data field was encrypted with an OEM root key when the Keybox - * was stored on the device, then this function should decrypt it and return - * the clear Key Data. If the Key Data was not encrypted, then this function - * should just access and return the clear Key data. - * - * Parameters: - * keyData (out) - pointer to a caller-managed buffer to hold the Key Data - * field from the Keybox - * dataLength (in/out) - on input, the allocated buffer size. On output, - * the number of bytes in KeyData. - * - * Threading: - * This function may be called simultaneously with any session functions. - * - * Returns: - * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_SHORT_BUFFER the buffer is too small to return the KeyData - * OEMCrypto_ERROR_NO_KEYDATA failed to return KeyData - * OEMCrypto_ERROR_NOT_IMPLEMENTED - device does not use keybox - * - * Version: - * This method is supported by all API versions. - */ -OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, size_t* keyDataLength); - /* * OEMCrypto_GetRandom * * Description: - * Return a buffer filled with hardware-generated random bytes. If the - * hardware feature does not exist, return OEMCrypto_ERROR_RNG_NOT_SUPPORTED. + * Returns a buffer filled with hardware-generated random bytes, if supported + * by the hardware. If the hardware feature does not exist, return + * OEMCrypto_ERROR_RNG_NOT_SUPPORTED. * * Parameters: - * randomData (out) - Pointer to caller-manager buffer that will receive the - * random data. - * dataLength (in) - Length of the random data buffer in bytes. - * - * Threading: - * This function may be called simultaneously with any session functions. + * [out] randomData - pointer to the buffer that receives random data + * [in] dataLength - length of the random data buffer in bytes * * Returns: * OEMCrypto_SUCCESS success * OEMCrypto_ERROR_RNG_FAILED failed to generate random number * OEMCrypto_ERROR_RNG_NOT_SUPPORTED function not supported * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * - * Buffer Sizes - * OEMCrypto shall support dataLength of at least 32 bytes for random number - * generation. + * Buffer Sizes: + * OEMCrypto shall support dataLength sizes of at least 32 bytes for random + * number generation. * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is - * too large. + * larger than the supported size. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. * * Version: - * This method is supported by all API versions. + * This method is supported in all API versions. */ OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, size_t dataLength); +/* + * OEMCrypto_APIVersion + * + * Description: + * This function returns the current API version number. The version number + * allows the calling application to avoid version mis-match errors, because + * this API is part of a shared library. + * + * There is a possibility that some API methods will be backwards compatible, + * or backwards compatible at a reduced security level. + * + * There is no plan to introduce forward-compatibility. Applications will + * reject a library with a newer version of the API. + * + * The version specified in this document is 15. Any OEM that returns this + * version number guarantees it passes all unit tests associated with this + * version. + * + * Parameters: + * none + * + * Returns: + * The supported API, as specified in the header file OEMCryptoCENC.h. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method changed in each API version. + */ +uint32_t OEMCrypto_APIVersion(); + +/* + * OEMCrypto_BuildInformation + * + * Description: + * Report the build information of the OEMCrypto library as a short null + * terminated C string. The string should be at most 128 characters long. + * This string should be updated with each release or OEMCrypto build. + * + * Some SOC vendors deliver a binary OEMCrypto library to a device + * manufacturer. This means the OEMCrypto version may not be exactly in sync + * with the system's versions. This string can be used to help track which + * version is installed on a device. + * + * It may be used for logging or bug tracking and may be bubbled up to the + * app so that it may track metrics on errors. + * + * Since the OEMCrypto API also changes its minor version number when there + * are minor corrections, it would be useful to include the API version + * number in this string, e.g. "15.1" or "15.2" if those minor versions are + * released. + * + * Parameters: + * none + * + * Returns: + * A printable null terminated C string, suitable for a single line in a log. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method changed in each API version. + */ +const char* OEMCrypto_BuildInformation(); + +/* + * OEMCrypto_Security_Patch_Level + * + * Description: + * This function returns the current patch level of the software running in + * the trusted environment. The patch level is defined by the OEM, and is + * only incremented when a security update has been added. + * + * See the section Security Patch Level above for more details. + * + * Parameters: + * none + * + * Returns: + * The OEM defined version number. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method was introduced in API version 11. + */ +uint8_t OEMCrypto_Security_Patch_Level(); + +/* + * OEMCrypto_SecurityLevel + * + * Description: + * Returns a string specifying the security level of the library. + * + * Since this function is spoofable, it is not relied on for security + * purposes. It is for information only. + * + * Parameters: + * none + * + * Returns: + * A null terminated string. Useful value are "L1", "L2" and "L3". + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 6. + */ +const char* OEMCrypto_SecurityLevel(); + +/* + * OEMCrypto_GetHDCPCapability + * + * Description: + * 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: + * + * The value 0xFF means the device is using a local, secure, data path + * instead of HDMI output. Notice that HDCP must use flag Type 1: all + * downstream devices will also use the same version or higher. + * + * The current HDCP should be the minimum value of any display currently + * connected through any channel, either through HDMI or a supported wireless + * format. The current value can be used by the application or server to + * decide which license can currently be used. If the key control block + * requires the current HDCP level, we expect the key to be usable. + * + * The maximum HDCP level should be the maximum value that the device can + * enforce. For example, if the device has an HDCP 1.0 port and an HDCP 2.0 + * port, and the first port can be disabled, then the maximum is HDCP 2.0. If + * the first port cannot be disabled, then the maximum is HDCP 1.0. The + * maximum value can be used by the application or server to decide if a + * license may be used in the future. For example, a device may be connected + * to an external display while an offline license is downloaded, but the + * user intends to view the content on a local display. The user will want to + * download the higher quality content. + * + * When a license requires HDCP, a device may use a wireless protocol to + * connect to a display only if that protocol supports the version of HDCP as + * required by the license. Both WirelessHD (formerly WiFi Display) and + * Miracast support HDCP. + * + * Parameters: + * [out] current - this is the current HDCP version, based on the device + * itself, and the display to which it is connected. + * [out] maximum - this is the maximum supported HDCP version for the device, + * ignoring any attached device. + * + * Returns: + * OEMCrypto_SUCCESS + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 10. + */ +OEMCryptoResult OEMCrypto_GetHDCPCapability(OEMCrypto_HDCP_Capability* current, + OEMCrypto_HDCP_Capability* maximum); + +/* + * OEMCrypto_SupportsUsageTable + * + * Description: + * This is used to determine if the device can support a usage table. Since + * this function is spoofable, it is not relied on for security purposes. It + * is for information only. The usage table is described in the section above. + * + * Parameters: + * none + * + * Returns: + * Returns true if the device can maintain a usage table. Returns false + * otherwise. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 9. + */ +bool OEMCrypto_SupportsUsageTable(); + +/* + * OEMCrypto_IsAntiRollbackHwPresent + * + * Description: + * Indicate whether there is hardware protection to detect and/or prevent the + * rollback of the usage table. For example, if the usage table contents 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 + * + * Returns: + * Returns true if oemcrypto uses anti-rollback hardware. Returns false + * otherwise. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method is new in API version 10. + */ +bool OEMCrypto_IsAntiRollbackHwPresent(); + +/* + * OEMCrypto_GetNumberOfOpenSessions + * + * Description: + * Returns the current number of open sessions. The CDM and OEMCrypto + * consumers can query this value so they can use resources more effectively. + * + * Parameters: + * [out] count - this is the current number of opened sessions. + * + * Returns: + * OEMCrypto_SUCCESS + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method is new 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. + * + * OEMCrypto shall support a minimum of 10 sessions. Some applications use + * multiple sessions to pre-fetch licenses, so high end devices should + * support more sessions -- we recommend a minimum of 50 sessions. + * + * Parameters: + * [out] count - this is the current number of opened sessions. + * + * Returns: + * OEMCrypto_SUCCESS + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 12. + */ +OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(size_t* max); + +/* + * OEMCrypto_SupportedCertificates + * + * Description: + * Returns the type of certificates keys that this device supports. With very + * few exceptions, all devices should support at least 2048 bit RSA keys. + * High end devices should also support 3072 bit RSA keys. Devices that are + * cast receivers should also support RSA cast receiver certificates. + * + * Beginning with OEMCrypto v14, the provisioning server may deliver to the + * device an RSA key that uses the Carmichael totient. This does not change + * the RSA algorithm -- however the product of the private and public keys is + * not necessarily the Euler number \phi (n). OEMCrypto should not reject + * such keys. + * + * Parameters: + * none + * + * Returns: + * Returns the bitwise or of the following flags. It is likely that high end + * devices will support both 2048 and 3072 bit keys while the widevine + * servers transition to new key sizes. + * - 0x1 = OEMCrypto_Supports_RSA_2048bit - the device can load a DRM + * certificate with a 2048 bit RSA key. + * - 0x2 = OEMCrypto_Supports_RSA_3072bit - the device can load a DRM + * certificate with a 3072 bit RSA key. + * - 0x10 = OEMCrypto_Supports_RSA_CAST - the device can load a CAST + * certificate. These certificate are used with + * OEMCrypto_GenerateRSASignature with padding type set to 0x2, PKCS1 + * with block type 1 padding. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 13. + */ +uint32_t OEMCrypto_SupportedCertificates(); + +/* + * OEMCrypto_IsSRMUpdateSupported + * + * Description: + * Returns true if the device supports SRM files and the file can be updated + * via the function OEMCrypto_LoadSRM. This also returns false for devices + * that do not support an SRM file, devices that do not support HDCP, and + * devices that have no external display support. + * + * Parameters: + * none + * + * Returns: + * true - if LoadSRM is supported. + * false - otherwise. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 13. + */ +bool OEMCrypto_IsSRMUpdateSupported(); + +/* + * OEMCrypto_GetCurrentSRMVersion + * + * Description: + * Returns the version number of the current SRM file. If the device does not + * support SRM files, this will return OEMCrypto_ERROR_NOT_IMPLEMENTED. If + * the device only supports local displays, it would return + * OEMCrypto_LOCAL_DISPLAY_ONLY. If the device has an SRM, but cannot use + * OEMCrypto to update the SRM, then this function would set version to be + * the current version number, and return OEMCrypto_SUCCESS, but it would + * return false from OEMCrypto_IsSRMUpdateSupported. + * + * Parameters: + * [out] version: current SRM version number. + * + * Returns: + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_SUCCESS + * OEMCrypto_LOCAL_DISPLAY_ONLY - to indicate version was not set, and is not + * needed. + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method changed in API version 13. + */ +OEMCryptoResult OEMCrypto_GetCurrentSRMVersion(uint16_t* version); + +/* + * OEMCrypto_GetAnalogOutputFlags + * + * Description: + * Returns whether the device supports analog output or not. This information + * will be sent to the license server, and may be used to determine the type + * of license allowed. This function is for reporting only. It is paired with + * the key control block flags Disable_Analog_Output and CGMS. + * + * Parameters: + * none. + * + * Returns: + * Returns a bitwise OR of the following flags. + * - 0x0 = OEMCrypto_No_Analog_Output -- the device has no analog output. + * - 0x1 = OEMCrypto_Supports_Analog_Output - the device does have analog + * output. + * - 0x2 = OEMCrypto_Can_Disable_Analog_Ouptput - the device does have + * analog output, but it will disable analog output if required by the + * key control block. + * - 0x4 = OEMCrypto_Supports_CGMS_A - the device supports signaling 2-bit + * CGMS-A, if required by the key control block + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method is new in API version 14. + */ +uint32_t OEMCrypto_GetAnalogOutputFlags(); + +/* + * OEMCrypto_ResourceRatingTier + * + * Description: + * This function returns a positive number indicating which resource rating + * it supports. This value will bubble up to the application level as a + * property in much the same way security level does. This will allow + * applications to estimate what resolution and bandwidth the device expects + * to support. + * + * OEMCrypto unit tests and Android GTS tests will verify that devices do + * support the resource values specified in the table below at the tier + * claimed by the device. If a device claims to be a low end device, the + * OEMCrypto unit tests will only verify the low end performance values. + * + * OEMCrypto implementers should consider the numbers below to be minimum + * values. + * + * These performance parameters are for OEMCrypto only. In particular, + * bandwidth and codec resolution are determined by the platform. + * + * Some parameters need more explanation. The Sample size is typically the + * size of one encoded frame. Converting this to resolution depends on the + * Codec, which is not specified by OEMCrypto. Some content has the sample + * broken into several subsamples. The "number of subsamples" restriction + * requires that any content can be broken into at least that many + * subsamples. However, this number may be larger if DecryptCENC returns + * OEMCrypto_ERROR_BUFFER_TOO_LARGE. In that case, the layer above OEMCrypto + * will break the sample into subsamples of size "Decrypt Buffer Size" as + * specified in the table below. The "Decrypt Buffer Size" means the size of + * one subsample that may be passed into DecryptCENC or CopyBuffer without + * returning error OEMCrypto_ERROR_BUFFER_TOO_LARGE. + * + * The number of keys per session is an indication of how many different + * track types there can be for a piece of content. Typically, content will + * have several keys corresponding to audio and video at different + * resolutions. If the content uses key rotation, there could be three keys + * -- previous interval, current interval, and next interval -- for each + * resolution. + * + * Concurrent playback sessions versus concurrent sessions: some applications + * will preload multiple licenses before the user picks which content to + * play. Each of these licenses corresponds to an open session. Once playback + * starts, some platforms support picture-in-picture or multiple displays. + * Each of these pictures would correspond to a separate playback session + * with active decryption. + * + * Decrypted frames per second -- strictly speaking, OEMCrypto only controls + * the decryption part of playback and cannot control the decoding and + * display part. However, devices that support the higher resource tiers + * should also support a higher frame rate. Platforms may enforce these + * values. For example Android will enforce a frame rate via a GTS test. + * + * + * | Resource Rating Tier | 1 - Low | 2 - Medium | 3 - High | + * | Sample size | 1 MB | 2 MB | 4 MB | + * | Number of Subsamples| 8 | 16 | 32 | + * | Decrypt buffer size | 100 KB | 500 KB | 1 MB | + * | Generic crypto buffer size | 10 KB | 100 KB | 500 KB | + * | Number of concurrent sessions | 10 | 20 | 20 | + * | Number of keys per session | 4 | 20 | 20 | + * | Simultaneous secure playback | 1 | 2 | 2 | + * | Decrypted Frames per Second | 30 fps SD | 30 fps HD | 60 fps HD | + * + * + * Parameters: + * none. + * + * Returns: + * Returns an integer indicating which resource tier the device supports. + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method is new in API version 15. + */ +uint32_t OEMCrypto_ResourceRatingTier(); + /* * OEMCrypto_RewrapDeviceRSAKey30 * @@ -1823,91 +2946,88 @@ OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, size_t dataLength); * using an algorithm at least as strong as that in GenerateDerivedKeys. * * After decrypting enc_rsa_key, If the first four bytes of the buffer are - * the string “SIGN”, then the actual RSA key begins on the 9th byte of the + * the string "SIGN", then the actual RSA key begins on the 9th byte of the * buffer. The second four bytes of the buffer is the 32 bit field - * “allowed_schemes”, of type RSA_Padding_Scheme, which is used in - * OEMCrypto_GenerateRSASignature. The value of allowed_schemes must also - * be wrapped with RSA key. We recommend storing the magic string “SIGN” with + * "allowed_schemes", of type RSA_Padding_Scheme, which is used in + * OEMCrypto_GenerateRSASignature. The value of allowed_schemes must also be + * wrapped with RSA key. We recommend storing the magic string "SIGN" with * the key to distinguish keys that have a value for allowed_schemes from * those that should use the default allowed_schemes. Devices that do not * support the alternative signing algorithms may refuse to load these keys * and return an error of OEMCrypto_ERROR_NOT_IMPLEMENTED. The main use case * for these alternative signing algorithms is to support devices that use - * x509 certificates for authentication when acting as a ChromeCast receiver. + * X509 certificates for authentication when acting as a ChromeCast receiver. * This is not needed for devices that wish to send data to a ChromeCast. * * If the first four bytes of the buffer enc_rsa_key are not the string - * “SIGN”, then the default value of allowed_schemes = 1 (kSign_RSASSA_PSS) + * "SIGN", then the default value of allowed_schemes = 1 (kSign_RSASSA_PSS) * will be used. * * Verification and Algorithm: * The following checks should be performed. If any check fails, an error is * returned, and the key is not loaded. - * 1. Verify that in_wrapped_rsa_key_length is large enough to hold the - * rewrapped key, returning OEMCrypto_ERROR_SHORT_BUFFER otherwise. - * 2. 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. - * 3. Decrypt encrypted_message_key with the OEM certificate’s private RSA key - * using RSA-OAEP into the buffer message_key. This message key is a 128 bit - * AES key used only in step 4. This message_key should be kept in secure - * memory and protected from the user. - * 4. Decrypt enc_rsa_key into the buffer rsa_key using the message_key, which - * was found in step 3. Use enc_rsa_key_iv as the initial vector for - * AES_128-CBC mode, with PKCS#5 padding. The rsa_key should be kept in - * secure memory and protected from the user. - * 5. If the first four bytes of the buffer rsa_key are the string “SIGN”, - * then the actual RSA key begins on the 9th byte of the buffer. The second - * four bytes of the buffer is the 32 bit field “allowed_schemes”, of type - * RSA_Padding_Scheme, which is used in OEMCrypto_GenerateRSASignature. - * The value of allowed_schemes must also be wrapped with RSA key. We - * recommend storing the magic string “SIGN” with the key to distinguish keys - * that have a value for allowed_schemes from those that should use the - * default allowed_schemes. Devices that do not support the alternative - * signing algorithms may refuse to load these keys and return an error of - * OEMCrypto_ERROR_NOT_IMPLEMENTED. The main use case for these alternative - * signing algorithms is to support devices that use X.509 certificates for - * authentication when acting as a ChromeCast receiver. This is not needed - * for devices that wish to send data to a ChromeCast. - * 6. If the first four bytes of the buffer rsa_key are not the string “SIGN”, - * then the default value of allowed_schemes = 1 (kSign_RSASSA_PSS) will be - * used. - * 7. After possibly skipping past the first 8 bytes signifying the allowed - * signing algorithm, the rest of the buffer rsa_key contains an RSA device - * key in PKCS#8 binary DER encoded format. The OEMCrypto library shall - * verify that this RSA key is valid. - * 8. Re-encrypt the device RSA key with an internal key (such as the OEM key - * or Widevine Keybox key) and the generated IV using AES-128-CBC with PKCS#5 - * padding. - * 9. Copy the rewrapped key to the buffer specified by wrapped_rsa_key and - * the size of the wrapped key to wrapped_rsa_key_length. + * + * 1. Verify that in_wrapped_rsa_key_length is large enough to hold the + * rewrapped key, returning OEMCrypto_ERROR_SHORT_BUFFER otherwise. + * 2. 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. Notice that the nonce may not point + * to a word aligned memory location. + * 3. Decrypt encrypted_message_key with the OEM certificate's private RSA + * key using RSA-OAEP into the buffer message_key. This message key is + * a 128 bit AES key used only in step 4. This message_key should be + * kept in secure memory and protected from the user. + * 4. Decrypt enc_rsa_key into the buffer rsa_key using the message_key, + * which was found in step 3. Use enc_rsa_key_iv as the initial vector + * for AES_128-CBC mode, with PKCS#5 padding. The rsa_key should be kept + * in secure memory and protected from the user. + * 5. If the first four bytes of the buffer rsa_key are the string "SIGN", + * then the actual RSA key begins on the 9th byte of the buffer. The + * second four bytes of the buffer is the 32 bit field + * "allowed_schemes", of type RSA_Padding_Scheme, which is used in + * OEMCrypto_GenerateRSASignature. The value of allowed_schemes must + * also be wrapped with RSA key. We recommend storing the magic string + * "SIGN" with the key to distinguish keys that have a value for + * allowed_schemes from those that should use the default + * allowed_schemes. Devices that do not support the alternative signing + * algorithms may refuse to load these keys and return an error of + * OEMCrypto_ERROR_NOT_IMPLEMENTED. The main use case for these + * alternative signing algorithms is to support devices that use X.509 + * certificates for authentication when acting as a ChromeCast receiver. + * This is not needed for devices that wish to send data to a ChromeCast. + * 6. If the first four bytes of the buffer rsa_key are not the string + * "SIGN", then the default value of allowed_schemes = 1 + * (kSign_RSASSA_PSS) will be used. + * 7. After possibly skipping past the first 8 bytes signifying the allowed + * signing algorithm, the rest of the buffer rsa_key contains an RSA + * device key in PKCS#8 binary DER encoded format. The OEMCrypto library + * shall verify that this RSA key is valid. + * 8. Re-encrypt the device RSA key with an internal key (such as the OEM + * key or Widevine Keybox key) and the generated IV using AES-128-CBC + * with PKCS#5 padding. + * 9. Copy the rewrapped key to the buffer specified by wrapped_rsa_key and + * the size of the wrapped key to wrapped_rsa_key_length. * * Parameters: - * session (in) - crypto session identifier. - * unaligned_nonce (in) - The nonce provided in the provisioning - * - response. This points to an uint32_t that might - * - not be aligned to a word boundary. - * encrypted_message_key (in) - message_key encrypted by private key - * - from OEM cert. - * encrypted_message_key_length (in) - length of encrypted_message_key in - * - bytes. - * enc_rsa_key (in) - Encrypted device private RSA key received from - * - the provisioning server. Format is PKCS#8 - * - binary DER encoded, encrypted with message_key, - * - using AES-128-CBC with PKCS#5 - * - padding. Encrypted by message_key. - * enc_rsa_key_length (in) - length of the encrypted RSA key, in bytes. - * enc_rsa_key_iv (in) - IV for decrypting RSA key. Size is 128 bits. - * wrapped_rsa_key (out) - pointer to buffer in which encrypted RSA key - * - should be stored. May be null on the first call - * - in order to find required buffer size. - * wrapped_rsa_key_length (in/out) - length of the encrypted RSA key, in - * - bytes. - * - * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. + * [in] session: crypto session identifier. + * [in] nonce: A pointer to the nonce provided in the provisioning response. + * (unaligned uint32_t) + * [in] encrypted_message_key : message_key encrypted by private key from + * OEM cert. + * [in] encrypted_message_key_length : length of encrypted_message_key in + * bytes. + * [in] enc_rsa_key: Encrypted device private RSA key received from the + * provisioning server. Format is PKCS#8, binary DER encoded, and + * encrypted with message_key, using AES-128-CBC with PKCS#5 padding. + * [in] enc_rsa_key_length: length of the encrypted RSA key, in bytes. + * [in] enc_rsa_key_iv: IV for decrypting RSA key. Size is 128 bits. + * [out] wrapped_rsa_key: pointer to buffer in which encrypted RSA key should + * be stored. May be null on the first call in order to find required + * buffer size. + * [in/out] wrapped_rsa_key_length: (in) length of the encrypted RSA key, in + * bytes. + * (out) actual length of the encrypted RSA key * * Returns: * OEMCrypto_SUCCESS success @@ -1920,14 +3040,23 @@ OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, size_t dataLength); * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES * OEMCrypto_ERROR_UNKNOWN_FAILURE * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * - * Buffer Sizes - * OEMCrypto shall support message sizes of at least 8 KiB. - * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is - * larger than the supported size. + * Buffer Sizes: + * OEMCrypto shall support message sizes of at least 8 KiB. + * 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 12. + * This method changed in API version 12. */ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30( OEMCrypto_SESSION session, const uint32_t* unaligned_nonce, @@ -1945,100 +3074,95 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30( * RSA provisioning response is valid and corresponds to the previous * provisioning request by checking the nonce. The RSA private key is * decrypted and stored in secure memory. The RSA key is then re-encrypted - * and signed for storage on the filesystem. We recommend that the OEM use - * an encryption key and signing key generated using an algorithm at least as + * and signed for storage on the filesystem. We recommend that the OEM use an + * encryption key and signing key generated using an algorithm at least as * strong as that in GenerateDerivedKeys. * * After decrypting enc_rsa_key, If the first four bytes of the buffer are - * the string “SIGN”, then the actual RSA key begins on the 9th byte of the + * the string "SIGN", then the actual RSA key begins on the 9th byte of the * buffer. The second four bytes of the buffer is the 32 bit field - * “allowed_schemes”, of type RSA_Padding_Scheme, which is used in - * OEMCrypto_GenerateRSASignature. The value of allowed_schemes must also - * be wrapped with RSA key. We recommend storing the magic string “SIGN” with + * "allowed_schemes", of type RSA_Padding_Scheme, which is used in + * OEMCrypto_GenerateRSASignature. The value of allowed_schemes must also be + * wrapped with RSA key. We recommend storing the magic string "SIGN" with * the key to distinguish keys that have a value for allowed_schemes from * those that should use the default allowed_schemes. Devices that do not * support the alternative signing algorithms may refuse to load these keys * and return an error of OEMCrypto_ERROR_NOT_IMPLEMENTED. The main use case * for these alternative signing algorithms is to support devices that use - * x509 certificates for authentication when acting as a ChromeCast receiver. + * X509 certificates for authentication when acting as a ChromeCast receiver. * This is not needed for devices that wish to send data to a ChromeCast. * * If the first four bytes of the buffer enc_rsa_key are not the string - * “SIGN”, then the default value of allowed_schemes = 1 (kSign_RSASSA_PSS) + * "SIGN", then the default value of allowed_schemes = 1 (kSign_RSASSA_PSS) * will be used. * * Verification and Algorithm: * The following checks should be performed. If any check fails, an error is * returned, and the key is not loaded. - * 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_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. - * 4. Verify the message signature, using the derived signing key - * (mac_key[server]) from a previous call to OEMCrypto_GenerateDerivedKeys. - * 5. Decrypt enc_rsa_key in the buffer rsa_key using the derived encryption - * key (enc_key) from a previous call to OEMCrypto_GenerateDerivedKeys. Use - * enc_rsa_key_iv as the initial vector for AES_128-CBC mode, with PKCS#5 - * padding. The rsa_key should be kept in secure memory and protected from - * the user. - * 6. If the first four bytes of the buffer rsa_key are the string “SIGN”, then - * the actual RSA key begins on the 9th byte of the buffer. The second four - * bytes of the buffer is the 32 bit field “allowed_schemes”, of type - * RSA_Padding_Scheme, which is used in OEMCrypto_GenerateRSASignature. - * The value of allowed_schemes must also be wrapped with RSA key. We - * recommend storing the magic string “SIGN” with the key to distinguish keys - * that have a value for allowed_schemes from those that should use the - * default allowed_schemes. Devices that do not support the alternative - * signing algorithms may refuse to load these keys and return an error of - * OEMCrypto_ERROR_NOT_IMPLEMENTED. The main use case for these alternative - * signing algorithms is to support devices that use X.509 certificates for - * authentication when acting as a ChromeCast receiver. This is not needed - * for devices that wish to send data to a ChromeCast. - * 7. If the first four bytes of the buffer rsa_key are not the string “SIGN”, - * then the default value of allowed_schemes = 1 (kSign_RSASSA_PSS) will be - * used. - * 8. After possibly skipping past the first 8 bytes signifying the allowed - * signing algorithm, the rest of the buffer rsa_key contains an RSA device - * key in PKCS#8 binary DER encoded format. The OEMCrypto library shall - * verify that this RSA key is valid. - * 9. Re-encrypt the device RSA key with an internal key (such as the OEM key - * or Widevine Keybox key) and the generated IV using AES-128-CBC with PKCS#5 - * padding. - * 10. Copy the rewrapped key to the buffer specified by wrapped_rsa_key and - * the size of the wrapped key to wrapped_rsa_key_length. + * + * 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_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. + * 4. Verify the message signature, using the derived signing key + * (mac_key[server]) from a previous call to + * OEMCrypto_GenerateDerivedKeys. + * 5. Decrypt enc_rsa_key in the buffer rsa_key using the derived + * encryption key (enc_key) from a previous call to + * OEMCrypto_GenerateDerivedKeys. Use enc_rsa_key_iv as the initial + * vector for AES_128-CBC mode, with PKCS#5 padding. The rsa_key should + * be kept in secure memory and protected from the user. + * 6. If the first four bytes of the buffer rsa_key are the string "SIGN", + * then the actual RSA key begins on the 9th byte of the buffer. The + * second four bytes of the buffer is the 32 bit field + * "allowed_schemes", of type RSA_Padding_Scheme, which is used in + * OEMCrypto_GenerateRSASignature. The value of allowed_schemes must + * also be wrapped with RSA key. We recommend storing the magic string + * "SIGN" with the key to distinguish keys that have a value for + * allowed_schemes from those that should use the default + * allowed_schemes. Devices that do not support the alternative signing + * algorithms may refuse to load these keys and return an error of + * OEMCrypto_ERROR_NOT_IMPLEMENTED. The main use case for these + * alternative signing algorithms is to support devices that use X.509 + * certificates for authentication when acting as a ChromeCast receiver. + * This is not needed for devices that wish to send data to a ChromeCast. + * 7. If the first four bytes of the buffer rsa_key are not the string + * "SIGN", then the default value of allowed_schemes = 1 + * (kSign_RSASSA_PSS) will be used. + * 8. After possibly skipping past the first 8 bytes signifying the allowed + * signing algorithm, the rest of the buffer rsa_key contains an RSA + * device key in PKCS#8 binary DER encoded format. The OEMCrypto library + * shall verify that this RSA key is valid. + * 9. Re-encrypt the device RSA key with an internal key (such as the OEM + * key or Widevine Keybox key) and the generated IV using AES-128-CBC + * with PKCS#5 padding. + * 10. Copy the rewrapped key to the buffer specified by wrapped_rsa_key + * and the size of the wrapped key to wrapped_rsa_key_length. * * Parameters: - * session (in) - crypto session identifier. - * message (in) - pointer to memory containing message to be - * - verified. - * message_length (in) - length of the message, in bytes. - * signature (in) - pointer to memory containing the HMAC-SHA256 - * - signature for message, received from the - * - provisioning server. - * signature_length (in) - length of the signature, in bytes. - * unaligned_nonce (in) - The nonce provided in the provisioning - * - response. This points to an uint32_t that might - * - not be aligned to a word boundary. - * enc_rsa_key (in) - Encrypted device private RSA key received from - * - the provisioning server. Format is PKCS#8 - * - binary DER encoded, encrypted with the derived - * - encryption key, using AES-128-CBC with PKCS#5 - * - padding. - * enc_rsa_key_length (in) - length of the encrypted RSA key, in bytes. - * enc_rsa_key_iv (in) - IV for decrypting RSA key. Size is 128 bits. - * wrapped_rsa_key (out) - pointer to buffer in which encrypted RSA key - * - should be stored. May be null on the first call - * - in order to find required buffer size. - * wrapped_rsa_key_length (in/out) - length of the encrypted RSA key, in - * - bytes. - * - * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. + * [in] session: crypto session identifier. + * [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 HMAC-SHA256 signature for + * message, received from the provisioning server. + * [in] signature_length: length of the signature, in bytes. + * [in] nonce: A pointer to the nonce provided in the provisioning response. + * [in] enc_rsa_key: Encrypted device private RSA key received from the + * provisioning server. Format is PKCS#8, binary DER encoded, and + * encrypted with the derived encryption key, using AES-128-CBC with + * PKCS#5 padding. + * [in] enc_rsa_key_length: length of the encrypted RSA key, in bytes. + * [in] enc_rsa_key_iv: IV for decrypting RSA key. Size is 128 bits. + * [out] wrapped_rsa_key: pointer to buffer in which encrypted RSA key should + * be stored. May be null on the first call in order to find required + * buffer size. + * [in/out] wrapped_rsa_key_length: (in) length of the encrypted RSA key, in + * bytes. + * (out) actual length of the encrypted RSA key * * Returns: * OEMCrypto_SUCCESS success @@ -2051,16 +3175,24 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30( * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES * OEMCrypto_ERROR_UNKNOWN_FAILURE * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * - * Buffer Sizes - * OEMCrypto shall support message sizes of at least 8 KiB. - * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is - * larger than the supported size. + * Buffer Sizes: + * OEMCrypto shall support message sizes of at least 8 KiB. + * 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 9. + * This method changed in API version 12. */ - OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length, @@ -2085,25 +3217,19 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey( * Verification: * The following checks should be performed. If any check fails, an error is * returned, and the RSA key is not loaded. - * 1. The wrapped key has a valid signature, as described in - * RewrapDeviceRSAKey. - * 2. The decrypted key is a valid private RSA key. - * 3. If a value for allowed_schemes is included with the key, it is a valid - * value. + * 1. The wrapped key has a valid signature, as described in + * RewrapDeviceRSAKey. + * 2. The decrypted key is a valid private RSA key. + * 3. If a value for allowed_schemes is included with the key, it is a + * valid value. * * Parameters: - * session (in) - crypto session identifier. - * wrapped_rsa_key (in) - wrapped device RSA key stored on the device. - * - Format is PKCS#8, binary DER encoded, and - * - encrypted with a key internal to the - * - OEMCrypto instance, using AES-128-CBC with - * - PKCS#5 padding. This is the wrapped key - * - generated by OEMCrypto_RewrapDeviceRSAKey. - * wrapped_rsa_key_length (in) - length of the wrapped key buffer, in bytes. - * - * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. + * [in] session: crypto session identifier. + * [in] wrapped_rsa_key: wrapped device RSA key stored on the device. Format + * is PKCS#8, binary DER encoded, and encrypted with a key internal to + * the OEMCrypto instance, using AES-128-CBC with PKCS#5 padding. This + * is the wrapped key generated by OEMCrypto_RewrapDeviceRSAKey. + * [in] wrapped_rsa_key_length: length of the wrapped key buffer, in bytes. * * Returns: * OEMCrypto_SUCCESS success @@ -2112,6 +3238,15 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey( * OEMCrypto_ERROR_INVALID_RSA_KEY * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * 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 9. @@ -2124,29 +3259,37 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session, * OEMCrypto_LoadTestRSAKey * * Description: - - * Temporarily use the standard test RSA key. This function is only required - * for platforms that do not use a keybox, but have an RSA certificate baked - * in. This allows a standard suite of unit tests to be run on a production - * device without permanently changing the certificate. This RSA key will - * persist until the next call to OEMCrypto_Terminate or - * OEMCrypto_Initialize. + * Some platforms do not support keyboxes or OEM Certificates. On those + * platforms, there is a DRM certificate baked into the OEMCrypto library. + * This is unusual, and is only available for L3 devices. In order to debug + * and test those devices, they should be able to switch to the test DRM + * certificate. * - * The test RSA key can be found in the reference implementation. + * Temporarily use the standard test RSA key until the next call to + * OEMCrypto_Terminate. This allows a standard suite of unit tests to be run + * on a production device without permanently changing the key. Using the + * test key is not persistent. * - * Parameters + * The test key can be found in the unit test code, oemcrypto_test.cpp, in + * PKCS8 form as the constant kTestRSAPKCS8PrivateKeyInfo2_2048. + * + * Parameters: * none * - * Returns + * Returns: * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_NOT_IMPLEMENTED - devices that use a keybox should not + * implement this function + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * - * Threading - * This function is not called simultaneously with any other functions. - * It will be called just after OEMCrypto_OpenSession(). + * Threading: + * This is an "Initialization and Termination 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 added in API version 10. + * Version: + * This method is new in API version 10. */ OEMCryptoResult OEMCrypto_LoadTestRSAKey(); @@ -2156,24 +3299,27 @@ OEMCryptoResult OEMCrypto_LoadTestRSAKey(); * Description: * The OEMCrypto_GenerateRSASignature method is used to sign messages using * the device private RSA key, specifically, it is used to sign the initial - * license request. Refer to the License Request Signed by RSA Certificate - * section above for more details. + * license request. + * + * Refer to the Signing Messages Sent to a Server section above for more + * details. * * If this function is called after OEMCrypto_LoadDeviceRSAKey for the same * session, then this function should use the device RSA key that was loaded. * If this function is called after a call to * OEMCrypto_GetOEMPublicCertificate for the same session, then this function * should use the RSA private key associated with the OEM certificate. The - * only padding scheme that is valid for the OEM certificate is - * 0x1 - RSASSA-PSS with SHA1. Any other padding scheme must generate an - * error. + * only padding scheme that is valid for the OEM certificate is 0x1 - + * RSASSA-PSS with SHA1. Any other padding scheme must generate an error. * * For devices that wish to be CAST receivers, there is a new RSA padding - * scheme. The padding_scheme parameter indicates which hashing and padding + * scheme. The padding_scheme parameter indicates which hashing and padding * is to be applied to the message so as to generate the encoded message (the * modulus-sized block to which the integer conversion and RSA decryption is * applied). The following values are defined: + * * 0x1 - RSASSA-PSS with SHA1. + * * 0x2 - PKCS1 with block type 1 padding (only). * * In the first case, a hash algorithm (SHA1) is first applied to the @@ -2182,54 +3328,58 @@ OEMCryptoResult OEMCrypto_LoadTestRSAKey(); * message_length can be no longer than 83 bytes. If the message_length is * greater than 83 bytes OEMCrypto_ERROR_SIGNATURE_FAILURE shall be returned. * - * The second padding scheme is for devices that use x509 certificates for + * The second padding scheme is for devices that use X509 certificates for * authentication. The main example is devices that work as a Cast receiver, * like a ChromeCast, not for devices that wish to send to the Cast device, - * such as almost all Android devices. OEMs that do not support x509 + * such as almost all Android devices. OEMs that do not support X509 * certificate authentication need not implement the second scheme and can * return OEMCrypto_ERROR_NOT_IMPLEMENTED. * * Verification: - * The bitwise AND of the parameter padding_scheme and the RSA key’s + * The bitwise AND of the parameter padding_scheme and the RSA key's * allowed_schemes is computed. If this value is 0, then the signature is not * computed and the error OEMCrypto_ERROR_INVALID_RSA_KEY is returned. * * Parameters: - * session (in) - crypto session identifier. - * message (in) - pointer to memory containing message to be - * - signed. - * message_length (in) - length of the message, in bytes. - * signature (out) - buffer to hold the message signature. On - * - return, it will contain the message signature - * - generated with the device private RSA key using - * - RSASSA-PSS. - * signature_length (in/out) - (in) length of the signature buffer, in bytes. - * - (out) actual length of the signature - * padding_scheme (in) - specify which scheme to use for the signature. - * - * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. + * [in] session: crypto session identifier. + * [in] message: pointer to memory containing message to be signed. + * [in] message_length: length of the message, in bytes. + * [out] signature: buffer to hold the message signature. On return, it will + * contain the message signature generated with the device private RSA + * key using RSASSA-PSS. Will be null on the first call in order to + * find required buffer size. + * [in/out] signature_length: (in) length of the signature buffer, in bytes. + * (out) actual length of the signature + * [in] padding_scheme: specify which scheme to use for the signature. * * Returns: * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_SHORT_BUFFER if the signature buffer is too small. * OEMCrypto_ERROR_INVALID_SESSION * OEMCrypto_ERROR_INVALID_CONTEXT - * OEMCrypto_ERROR_SHORT_BUFFER if the signature buffer is too small. * OEMCrypto_ERROR_INVALID_RSA_KEY * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES * OEMCrypto_ERROR_UNKNOWN_FAILURE - * OEMCrypto_ERROR_NOT_IMPLEMENTED - if algorithm > 0, and the device does not - * support that algorithm. + * OEMCrypto_ERROR_NOT_IMPLEMENTED - if algorithm > 0, and the device does + * not support that algorithm. * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * - * Buffer Sizes - * OEMCrypto shall support message sizes of at least 8 KiB. - * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is - * larger than the supported size. + * Buffer Sizes: + * OEMCrypto shall support message sizes of at least 8 KiB. + * 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 9. + * This method changed in API version 12. */ OEMCryptoResult OEMCrypto_GenerateRSASignature( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, @@ -2237,558 +3387,243 @@ OEMCryptoResult OEMCrypto_GenerateRSASignature( RSA_Padding_Scheme padding_scheme); /* - * OEMCrypto_DeriveKeysFromSessionKey + * OEMCrypto_CreateUsageTableHeader * * Description: - * Generates three secondary keys -- mac_key_server, mac_key_client, and - * encrypt_key -- for handling signing and content key decryption under the - * license server protocol for AES CTR mode. + * This creates a new Usage Table Header with no entries. If there is already + * a generation number stored in secure storage, it will be incremented by 1 + * and used as the new Master Generation Number. This will only be called if + * the CDM layer finds no existing usage table on the file system. OEMCrypto + * will encrypt and sign the new, empty, header and return it in the provided + * buffer. * - * This function is similar to OEMCrypto_GenerateDerivedKeys, except that it - * uses a session key to generate the secondary keys instead of the Widevine - * Keybox device key. These two keys will be stored in secure memory until - * the next call to LoadKeys. The session key is passed in encrypted by the - * device RSA public key, and must be decrypted with the RSA private key - * before use. 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 using a Widevine keybox token. - * - * Verification: - * If the RSA key’s allowed_schemes is not kSign_RSASSA_PSS, then no keys are - * derived and the error OEMCrypto_ERROR_INVALID_RSA_KEY is returned. An RSA - * key cannot be used for both deriving session keys and also for PKCS1 - * signatures. + * Devices that do not implement a Session Usage Table may return + * OEMCrypto_ERROR_NOT_IMPLEMENTED. * * Parameters: - * session (in) - crypto session identifier. - * enc_session_key (in) - session key, encrypted with the device RSA - * - key (from the device certifcate) using - * - RSA-OAEP. - * enc_session_key_length (in) - length of session_key, in bytes. - * mac_key_context (in) - pointer to memory containing context data for - * - computing the HMAC generation key. - * mac_key_context_length (in) - length of the HMAC key context data, in - * - bytes. - * enc_key_context (in) - pointer to memory containing context data for - * - computing the encryption key. - * enc_key_context_length (in) - length of the encryption key context data, in - * - bytes. - * - * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. + * [out] header_buffer: pointer to memory where encrypted usage table header + * is written. + * [in/out] header_buffer_length: (in) length of the header_buffer, in bytes. + * (out) actual length of the header_buffer * * Returns: * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED - * OEMCrypto_ERROR_INVALID_SESSION - * OEMCrypto_ERROR_INVALID_CONTEXT - * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES - * OEMCrypto_ERROR_UNKNOWN_FAILURE - * OEMCrypto_ERROR_BUFFER_TOO_LARGE - * - * Buffer Sizes - * OEMCrypto shall support message sizes of at least 8 KiB. - * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is - * larger than the supported size. - * - * Version: - * This method changed in API version 9. - */ -OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( - OEMCrypto_SESSION session, const uint8_t* enc_session_key, - size_t enc_session_key_length, const uint8_t* mac_key_context, - size_t mac_key_context_length, const uint8_t* enc_key_context, - size_t enc_key_context_length); - -/* - * OEMCrypto_APIVersion() - * - * Description: - * This function returns the current API version number. Because this - * API is part of a shared library, the version number allows the calling - * application to avoid version mis-match errors. - * - * There is a possibility that some API methods will be backwards compatible, - * or backwards compatible at a reduced security level. - * - * There is no plan to introduce forward-compatibility. Applications will - * reject a library with a newer version of the API. - * - * Parameters: - * none - * - * Threading: - * This function may be called simultaneously with any other functions. - * - * Returns: - * The supported API, as specified in the header file OEMCryptoCENC.h. - * - * Version: - * This method should change in all API versions. - */ -uint32_t OEMCrypto_APIVersion(); - -/** - * OEMCrypto_Security_Patch_Level() - * - * Description: - * This function returns the current patch level of the software running in - * the trusted environment. The patch level is defined by the OEM, and is - * only incremented when a security update has been added. - * - * Parameters: - * none - * - * Returns: - * The OEM defined version number. - * - * Threading: - * This function may be called simultaneously with any other functions. - * - * Version: - * This method was introduced in API version 11. - */ -uint8_t OEMCrypto_Security_Patch_Level(); - -/* - * OEMCrypto_SecurityLevel() - * - * Description: - * This function returns the security level of the OEMCrypto library. - * - * Since this function is spoofable, it is not relied on for security - * purposes. It is for information only. - * - * Returns: - * A null terminated string. Useful values are "L1", "L2" or "L3". - * - * Threading: - * This function may be called simultaneously with any other functions. - * - * Version: - * This method changed in API version 6. - */ -const char* OEMCrypto_SecurityLevel(); - -/* - * OEMCrypto_GetHDCPCapability() - * - * Description: - * Returns the maximum HDCP version supported by the device, and the HDCP - * version supported by the device and any connected display. - * - * Parameters: - * current (out) - this is the current HDCP version, based on the device - * itself, and the display to which it is connected. - * maximum (out) - this is the maximum supported HDCP version for the device, - * ignoring any attached device. - * - * Threading: - * This function may be called simultaneously with any other functions. - * - * Returns: - * OEMCrypto_SUCCESS - * OEMCrypto_ERROR_UNKNOWN_FAILURE - * - * Version: - * This method changed in API version 10. - */ -OEMCryptoResult OEMCrypto_GetHDCPCapability(OEMCrypto_HDCP_Capability* current, - OEMCrypto_HDCP_Capability* maximum); - -/* - * OEMCrypto_SupportsUsageTable() - * - * Description: - * This is used to determine if the device can support a usage table. Since - * this function is spoofable, it is not relied on for security purposes. It - * is for information only. The usage table is described in the section - * above. - * - * Parameters: - * none - * - * Threading: - * This function may be called simultaneously with any other functions. - * - * Returns: - * Returns true if the device can maintain a usage table. Returns false - * otherwise. - * - * Version: - * This method changed in API version 9. - */ -bool OEMCrypto_SupportsUsageTable(); - -/* - * 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. - * - * OEMCrypto shall support a minimum of 10 sessions. Some applications use - * multiple sessions to pre-fetch licenses, so high end devices should - * support more sessions -- we recommend a minimum of 50 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_SupportedCertificates() - * - * Description: - * Returns the type of certificates keys that this device supports. With very - * few exceptions, all devices should support at least 2048 bit RSA keys. - * High end devices should also support 3072 bit RSA keys. Devices that are - * cast receivers should also support RSA cast receiver certificates. - * - * Beginning with OEMCrypto v14, the provisioning server may deliver to the - * device an RSA key that uses the Carmichael totient. This does not change - * the RSA algorithm -- however the product of the private and public keys is - * not necessarily the Euler number phi. OEMCrypto should not reject such - * keys. - * - * Parameters: none - * - * Threading: - * This function may be called simultaneously with any other functions. - * - * Returns: - * Returns the bitwise or of the following flags. It is likely that high - * end devices will support both 2048 and 3072 bit keys while the widevine - * servers transition to new key sizes. - * - * 0x1 = OEMCrypto_Supports_RSA_2048bit - the device can load a DRM - * certificate with a 2048 bit RSA key. - * - * 0x2 = OEMCrypto_Supports_RSA_3072bit - the device can load a DRM - * certificate with a 3072 bit RSA key. - * - * 0x10 = OEMCrypto_Supports_RSA_CAST - the device can load a CAST - * certificate. These certificate are used with - * OEMCrypto_GenerateRSASignature with padding type set to 0x2, PKCS1 with - * block type 1 padding. - * - * Version: - * This method is added in API version 13. - */ -uint32_t OEMCrypto_SupportedCertificates(); - -/* - * OEMCrypto_Generic_Encrypt - * - * Description: - * This function encrypts a generic buffer of data using the current key. - * - * If the session has an entry in the Usage Table, then OEMCrypto will update - * 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. - * - * Verification: - * The following checks should be performed. If any check fails, an error is - * returned, and the data is not encrypted. - * 1. The control bit for the current key shall have the Allow_Encrypt - * set. If not, return OEMCrypto_ERROR_UNKNOWN_FAILURE. - * 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. If not, return OEMCrypto_ERROR_KEY_EXPIRED. - * 3. If the current session has an entry in the Usage Table, and the status - * of that entry is "inactive", then return OEMCrypto_ERROR_INVALID_SESSION. - * - * Parameters: - * session (in) - crypto session identifier. - * in_buffer (in) - pointer to memory containing data to be encrypted. - * buffer_length (in) - length of the buffer, in bytes. - * iv (in) - IV for encrypting data. Size is specified by the algorithm. - * algorithm (in) - Specifies which encryption algorithm to use. See - * OEMCrypto_Algorithm for valid values. - * out_buffer (out) - pointer to buffer in which encrypted data should be - * stored. - * - * Returns: - * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_KEY_EXPIRED - * OEMCrypto_ERROR_NO_DEVICE_KEY - * OEMCrypto_ERROR_INVALID_SESSION - * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES - * OEMCrypto_ERROR_UNKNOWN_FAILURE - * OEMCrypto_ERROR_BUFFER_TOO_LARGE - * - * Buffer Sizes - * OEMCrypto shall support buffer sizes of at least 100 KiB for generic - * crypto operations. - * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is - * larger than the supported size. - * - * Threading: - * This function may be called simultaneously with functions on other sessions, - * but not with other functions on this session. - * - * Version: - * This method changed in API version 9. - */ -OEMCryptoResult OEMCrypto_Generic_Encrypt( - OEMCrypto_SESSION session, const uint8_t* in_buffer, size_t buffer_length, - const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer); - -/* - * OEMCrypto_Generic_Decrypt - * - * Description: - * This function decrypts a generic buffer of data using the current key. - * - * If the session has an entry in the Usage Table, then OEMCrypto will update - * 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. - * - * Verification: - * The following checks should be performed. If any check fails, an error is - * returned, and the data is not decrypted. - * 1. The control bit for the current key shall have the Allow_Decrypt set. If - * not, return OEMCrypto_ERROR_DECRYPT_FAILED. - * 2. If the current key’s control block has the Data_Path_Type bit set, then - * return OEMCrypto_ERROR_DECRYPT_FAILED. - * 3. 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. If not, return OEMCrypto_ERROR_KEY_EXPIRED. - * 4. If the current session has an entry in the Usage Table, and the status - * of that entry is "inactive", then return OEMCrypto_ERROR_INVALID_SESSION. - * - * Parameters: - * session (in) - crypto session identifier. - * in_buffer (in) - pointer to memory containing data to be encrypted. - * buffer_length (in) - length of the buffer, in bytes. The algorithm may - * restrict buffer_length to be a multiple of block size. - * iv (in) - IV for encrypting data. Size is 128 bits. - * algorithm (in) - Specifies which encryption algorithm to use. - * out_buffer (out) - pointer to buffer in which decrypted data should be - * stored. - * - * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. - * - * Returns: - * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_KEY_EXPIRED - * OEMCrypto_ERROR_DECRYPT_FAILED - * OEMCrypto_ERROR_NO_DEVICE_KEY - * OEMCrypto_ERROR_INVALID_SESSION - * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES - * OEMCrypto_ERROR_UNKNOWN_FAILURE - * OEMCrypto_ERROR_BUFFER_TOO_LARGE - * - * Buffer Sizes - * OEMCrypto shall support buffer sizes of at least 100 KiB for generic - * crypto operations. - * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is - * larger than the supported size. - * - * Version: - * This method changed in API version 9. - */ -OEMCryptoResult OEMCrypto_Generic_Decrypt( - OEMCrypto_SESSION session, const uint8_t* in_buffer, size_t buffer_length, - const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer); - -/* - * OEMCrypto_Generic_Sign - * - * Description: - * This function signs a generic buffer of data using the current key. - * - * If the session has an entry in the Usage Table, then OEMCrypto will update - * 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. - * - * Verification: - * The following checks should be performed. If any check fails, an error is - * returned, and the data is not signed. - * 1. The control bit for the current key shall have the Allow_Sign set. - * 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. If not, return OEMCrypto_ERROR_KEY_EXPIRED. - * 3. If the current session has an entry in the Usage Table, and the status of - * that entry is "inactive", then return OEMCrypto_ERROR_INVALID_SESSION. - * - * Parameters: - * session (in) - crypto session identifier. - * in_buffer (in) - pointer to memory containing data to be encrypted. - * buffer_length (in) - length of the buffer, in bytes. - * algorithm (in) - Specifies which algorithm to use. - * signature (out) - pointer to buffer in which signature should be - * stored. May be null on the first call in order to find required buffer - * size. - * signature_length (in/out) - (in) length of the signature buffer, in bytes. - * (out) actual length of the signature - * - * - * - * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. - * - * Returns: - * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_KEY_EXPIRED - * OEMCrypto_ERROR_SHORT_BUFFER if signature buffer is not large enough to - * hold the output signature. - * OEMCrypto_ERROR_NO_DEVICE_KEY - * OEMCrypto_ERROR_INVALID_SESSION - * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES - * OEMCrypto_ERROR_UNKNOWN_FAILURE - * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SHORT_BUFFER - if header_buffer_length is too small. * OEMCrypto_ERROR_NOT_IMPLEMENTED - * - * Buffer Sizes - * OEMCrypto shall support buffer sizes of at least 100 KiB for generic - * crypto operations. - * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is - * larger than the supported size. - * - * Version: - * This method changed in API version 9. - */ -OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, - const uint8_t* in_buffer, - size_t buffer_length, - OEMCrypto_Algorithm algorithm, - uint8_t* signature, - size_t* signature_length); - -/* - * OEMCrypto_Generic_Verify - * - * Description: - * This function verifies the signature of a generic buffer of data using the - * current key. - * - * If the session has an entry in the Usage Table, then OEMCrypto will update - * 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. - * - * Verification: - * The following checks should be performed. If any check fails, an error is - * returned. - * 1. The control bit for the current key shall have the Allow_Verify set. - * 2. The signature of the message shall be computed, and the API shall verify - * the computed signature matches the signature passed in. If not, return - * OEMCrypto_ERROR_SIGNATURE_FAILURE. - * 3. The signature verification shall use a constant-time algorithm (a - * signature mismatch will always take the same time as a successful - * comparison). - * 4. 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. If not, return OEMCrypto_ERROR_KEY_EXPIRED. - * 5. If the current session has an entry in the Usage Table, and the status - * of that entry is "inactive", then return OEMCrypto_ERROR_INVALID_SESSION. - * - * Parameters: - * session (in) - crypto session identifier. - * in_buffer (in) - pointer to memory containing data to be encrypted. - * buffer_length (in) - length of the buffer, in bytes. - * algorithm (in) - Specifies which algorithm to use. - * signature (in) - pointer to buffer in which signature resides. - * signature_length (in) - length of the signature buffer, in bytes. + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. + * 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 changed in API version 13. + */ +OEMCryptoResult OEMCrypto_CreateUsageTableHeader(uint8_t* header_buffer, + size_t* header_buffer_length); + +/* + * OEMCrypto_LoadUsageTableHeader + * + * Description: + * This loads the Usage Table Header. The buffer's signature is verified and + * the buffer is decrypted. OEMCrypto will verify the verification string. If + * the Master Generation Number is more than 1 off, the table is considered + * bad, the headers are NOT loaded, and the error + * OEMCrypto_ERROR_GENERATION_SKEW is returned. If the generation number is + * off by 1, the warning OEMCrypto_WARNING_GENERATION_SKEW is returned but + * the header is still loaded. This warning may be logged by the CDM layer. + * + * Parameters: + * [in] buffer: pointer to memory containing encrypted usage table header. + * [in] buffert_length: length of the buffer, in bytes. * * Returns: * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_KEY_EXPIRED - * OEMCrypto_ERROR_SIGNATURE_FAILURE - * OEMCrypto_ERROR_NO_DEVICE_KEY - * OEMCrypto_ERROR_INVALID_SESSION - * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * OEMCrypto_ERROR_SHORT_BUFFER + * OEMCrypto_ERROR_NOT_IMPLEMENTED - some devices do not implement usage + * tables. * OEMCrypto_ERROR_UNKNOWN_FAILURE - * OEMCrypto_ERROR_BUFFER_TOO_LARGE - * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_WARNING_GENERATION_SKEW - if the generation number is off by + * exactly 1. + * OEMCrypto_ERROR_GENERATION_SKEW - if the generation number is off by more + * than 1. + * OEMCrypto_ERROR_SIGNATURE_FAILURE - if the signature failed. + * OEMCrypto_ERROR_BAD_MAGIC - verification string does not match. + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * - * Buffer Sizes - * OEMCrypto shall support buffer sizes of at least 100 KiB for generic - * crypto operations. - * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is - * larger than the supported size. + * 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 changed in API version 9. + * This method changed in API version 13. */ -OEMCryptoResult OEMCrypto_Generic_Verify(OEMCrypto_SESSION session, - const uint8_t* in_buffer, - size_t buffer_length, - OEMCrypto_Algorithm algorithm, - const uint8_t* signature, - size_t signature_length); +OEMCryptoResult OEMCrypto_LoadUsageTableHeader(const uint8_t* buffer, + size_t buffer_length); + +/* + * OEMCrypto_CreateNewUsageEntry + * + * Description: + * This creates a new usage entry. The size of the header will be increased + * by 8 bytes, and secure volatile memory will be allocated for it. The new + * entry will be associated with the given session. The status of the new + * entry will be set to "unused". OEMCrypto will set *usage_entry_number to + * be the index of the new entry. The first entry created will have index 0. + * The new entry will be initialized with a generation number equal to the + * master generation number, which will also be stored in the header's new + * slot. Then the master generation number will be incremented. Since each + * entry's generation number is less than the master generation number, the + * new entry will have a generation number that is larger than all other + * entries and larger than all previously deleted entries. This helps prevent + * a rogue application from deleting an entry and then loading an old version + * of it. + * + * Parameters: + * [in] session: handle for the session to be used. + * [out] usage_entry_number: index of new usage entry. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_NOT_IMPLEMENTED - some devices do not implement usage + * tables. + * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES - if there is no room in memory to + * increase the size of the usage table header. The CDM layer can + * delete some entries and then try again, or it can pass the error up + * to the application. + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * 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 changed in API version 13. + */ +OEMCryptoResult OEMCrypto_CreateNewUsageEntry(OEMCrypto_SESSION session, + uint32_t* usage_entry_number); + +/* + * OEMCrypto_LoadUsageEntry + * + * Description: + * This loads a usage table saved previously by UpdateUsageEntry. The + * signature at the beginning of the buffer is verified and the buffer will + * be decrypted. Then the verification field in the entry will be verified. + * The index in the entry must match the index passed in. The generation + * number in the entry will be compared against that in the header. If it is + * off by 1, a warning is returned, but the entry is still loaded. This + * warning may be logged by the CDM layer. If the generation number is off by + * more than 1, an error is returned and the entry is not loaded. + * + * If the entry is already loaded into another open session, then this fails + * and returns OEMCrypto_ERROR_INVALID_SESSION. + * + * Parameters: + * [in] session: handle for the session to be used. + * [in] usage_entry_number: index of existing usage entry. + * [in] buffer: pointer to memory containing encrypted usage table entry. + * [in] buffer_length: length of the buffer, in bytes. + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_SHORT_BUFFER + * OEMCrypto_ERROR_NOT_IMPLEMENTED - some devices do not implement usage + * tables. + * OEMCrypto_ERROR_UNKNOWN_FAILURE - index beyond end of table. + * OEMCrypto_ERROR_INVALID_SESSION - entry associated with another session or + * the index is wrong. + * OEMCrypto_WARNING_GENERATION_SKEW - if the generation number is off by + * exactly 1. + * OEMCrypto_ERROR_GENERATION_SKEW - if the generation number is off by more + * than 1. + * OEMCrypto_ERROR_SIGNATURE_FAILURE - if the signature failed. + * OEMCrypto_ERROR_BAD_MAGIC - verification string does not match. + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * 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 changed in API version 13. + */ +OEMCryptoResult OEMCrypto_LoadUsageEntry(OEMCrypto_SESSION session, + uint32_t usage_entry_number, + const uint8_t* buffer, + size_t buffer_length); + +/* + * OEMCrypto_UpdateUsageEntry + * + * Description: + * Updates the session's usage entry and fills buffers with the encrypted and + * signed entry and usage table header. OEMCrypto will update all time and + * status values in the entry, and then increment the entry's generation + * number. The corresponding generation number in the usage table header is + * also incremented so that it matches the one in the entry. The master + * generation number in the usage table header is incremented and is copied + * to secure persistent storage. OEMCrypto will encrypt and sign the entry + * into the entry_buffer, and it will encrypt and sign the usage table header + * into the header_buffer. Some actions, such as the first decrypt and + * deactivating an entry, will also increment the entry's generation number + * as well as changing the entry's status and time fields. As in OEMCrypto + * v12, the first decryption will change the status from Inactive to Active, + * and it will set the time stamp "first decrypt". + * + * If the usage entry has the flag ForbidReport set, then the flag is + * cleared. It is the responsibility of the CDM layer to call this function + * and save the usage table before the next call to ReportUsage and before + * the CDM is terminated. Failure to do so will result in generation number + * skew, which will invalidate all of the usage table. + * + * If either buffer_length is not large enough, they are set to the needed + * size, and OEMCrypto_ERROR_SHORT_BUFFER. In this case, the entry is not + * updated, ForbidReport is not cleared, generation numbers are not + * incremented, and no other work is done. + * + * Parameters: + * [in] session: handle for the session to be used. + * [out] header_buffer: pointer to memory where encrypted usage table header + * is written. + * [in/out] header_buffer_length: (in) length of the header_buffer, in bytes. + * (out) actual length of the header_buffer + * [out] entry_buffer: pointer to memory where encrypted usage table entry is + * written. + * [in/out] buffer_length: (in) length of the entry_buffer, in bytes. + * (out) actual length of the entry_buffer + * + * Returns: + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_SHORT_BUFFER + * OEMCrypto_ERROR_NOT_IMPLEMENTED - some devices do not implement usage + * tables. + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * 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 changed in API version 13. + */ +OEMCryptoResult OEMCrypto_UpdateUsageEntry(OEMCrypto_SESSION session, + uint8_t* header_buffer, + size_t* header_buffer_length, + uint8_t* entry_buffer, + size_t* entry_buffer_length); /* * OEMCrypto_DeactivateUsageEntry @@ -2796,38 +3631,39 @@ OEMCryptoResult OEMCrypto_Generic_Verify(OEMCrypto_SESSION session, * Description: * This deactivates the usage entry associated with the current session. This * means that the state of the usage entry is changed to InactiveUsed if it - * was Active, or InactiveUnused if it was Unused. This also increments the - * entry's generation number, and the header's master generation number. The - * entry's flag ForbidReport will be set. This flag prevents an application + * was Active, or InactiveUnused if it was Unused. This also increments the + * entry's generation number, and the header's master generation number. The + * entry's flag ForbidReport will be set. This flag prevents an application * from generating a report of a deactivated license without first saving the * entry. * - * Devices that do not implement a Session Usage Table may return - * OEMCrypto_ERROR_NOT_IMPLEMENTED. - * * Parameters: - * session (in): handle for the session to be used. - * pst (in) - pointer to memory containing Provider Session Token. - * pst_length (in) - length of the pst, in bytes. - * - * Threading: - * This function will not be called simultaneously with any session functions. + * [in] session: handle for the session to be used. + * [in] pst: pointer to memory containing Provider Session Token. + * [in] pst_length: length of the pst, in bytes. * * Returns: * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_INVALID_CONTEXT - no entry has matching PST. + * OEMCrypto_ERROR_INVALID_CONTEXT - an entry was not created or loaded, or + * the pst does not match. * OEMCrypto_ERROR_NOT_IMPLEMENTED * OEMCrypto_ERROR_UNKNOWN_FAILURE * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * - * Buffer Sizes - * OEMCrypto shall support pst sizes of at least 255 bytes. + * Buffer Sizes: + * OEMCrypto shall support pst sizes of at least 255 bytes. * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is - * too large. + * larger than the supported size. + * + * 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 changed in API version 13. - * */ OEMCryptoResult OEMCrypto_DeactivateUsageEntry(OEMCrypto_SESSION session, const uint8_t* pst, @@ -2837,87 +3673,93 @@ OEMCryptoResult OEMCrypto_DeactivateUsageEntry(OEMCrypto_SESSION session, * OEMCrypto_ReportUsage * * Description: + * All fields of OEMCrypto_PST_Report are in network byte order. + * * If the buffer_length is not sufficient to hold a report structure, set * buffer_length and return OEMCrypto_ERROR_SHORT_BUFFER. * * If the an entry was not loaded or created with - * OEMCrypto_CreateNewUsageEntry or OEMCrypto_LoadUsageEntry, or if the pst + * OEMCrypto_CreateNewUsageEntry or OEMCRypto_LoadUsageEntry, or if the pst * does not match that in the entry, return the error * OEMCrypto_ERROR_INVALID_CONTEXT. * - * If the usage entry’s flag ForbidReport is set, indicating the entry has + * If the usage entry's flag ForbidReport is set, indicating the entry has * not been saved since the entry was deactivated, then the error * OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE is returned and a report is not - * generated. Similarly, if any key in the session has been used since the + * generated. Similarly, if any key in the session has been used since the * last call to OEMCrypto_UpdateUsageEntry, then the report is not generated, * and OEMCrypto returns the error OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE. * * The pst_report is filled out by subtracting the times in the Usage Entry - * from the current time on the secure clock. This is done in case the - * secure clock is not using UTC time, but is instead using something like - * seconds since clock installed. + * from the current time on the secure clock. This is done in case the secure + * clock is not using UTC time, but is instead using something like seconds + * since clock installed. * * Valid values for status are: - * 0 = kUnused -- the keys have not been used to decrypt. - * 1 = kActive -- the keys have been used, and have not been deactivated. - * 2 = kInactive -- deprecated. Use kInactiveUsed or kInactiveUnused. - * 3 = kInactiveUsed -- the keys have been marked inactive after a decrypt. - * 4 = kInactiveUnused -- the keys have been marked inactive, no decrypt. * + * - 0 = kUnused -- the keys have not been used to decrypt. + * - 1 = kActive -- the keys have been used, and have not been deactivated. + * - 2 = kInactive - deprecated. Use kInactiveUsed or kInactiveUnused. + * - 3 = kInactiveUsed -- the keys have been marked inactive after being + * active. + * - 4 = kInactiveUnused -- they keys have been marked inactive, but were + * never active. * The clock_security_level is reported as follows: - * 0 = Insecure Clock - clock just uses system time. - * 1 = Secure Timer - clock uses secure timer, which cannot be modified by - * user software, when OEMCrypto is active and the system time when - * OEMCrypto is inactive. - * 2 = Software Secure Clock - clock cannot be modified by user software - * when OEMCrypto is active or inactive. - * 3 = Hardware Secure Clock - clock cannot be modified by user software - * and there are security features that prevent the user from modifying the - * clock in hardware, such as a tamper proof battery. * + * - 0 = Insecure Clock - clock just uses system time. + * - 1 = Secure Timer - clock runs from a secure timer which is initialized + * from system time when OEMCrypto becomes active and cannot be modified + * by user software or the user while OEMCrypto is active. + * - 2 = Secure Clock - Real-time clock set from a secure source that + * cannot be modified by user software regardless of whether OEMCrypto + * is active or inactive. The clock time can only be modified by + * tampering with the security software or hardware. + * - 3 = Hardware Secure Clock - Real-time clock set from a secure source + * that cannot be modified by user software and there are security + * features that prevent the user from modifying the clock in hardware, + * such as a tamper proof battery. * After pst_report has been filled in, the HMAC SHA1 signature is computed * for the buffer from bytes 20 to the end of the pst field. The signature is - * computed using the client_mac_key which is stored in the usage table. The + * computed using the mac_key[client] which is stored in the usage table. The * HMAC SHA1 signature is used to prevent a rogue application from using * OMECrypto_GenerateSignature to forge a Usage Report. * - * This function also copies the client_mac_key and server_mac_key from the - * Usage Table entry to the session. They will be used to verify a signature - * in OEMCrypto_DeleteUsageEntry below. This session will be associated with - * the entry in the Usage Table. - * * Devices that do not implement a Session Usage Table may return * OEMCrypto_ERROR_NOT_IMPLEMENTED. * * Parameters: - * session (in) - handle for the session to be used. - * pst (in) - pointer to memory containing Provider Session Token. - * pst_length (in) - length of the pst, in bytes. - * buffer (out) - pointer to buffer in which usage report should be - * stored. May be null on the first call in order to find required buffer - * size. - * buffer_length (in/out) - (in) length of the report buffer, in bytes. - * (out) actual length of the report - * - * Threading: - * This function will not be called simultaneously with any session functions. + * [in] session: handle for the session to be used. + * [in] pst: pointer to memory containing Provider Session Token. + * [in] pst_length: length of the pst, in bytes. + * [out] buffer: pointer to buffer in which usage report should be stored. + * May be null on the first call in order to find required buffer size. + * [in/out] buffer_length: (in) length of the report buffer, in bytes. + * (out) actual length of the report * * Returns: * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_SHORT_BUFFER if report buffer is not large enough to hold - * the output report. - * OEMCrypto_ERROR_INVALID_SESSION no open session with that id. - * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_SHORT_BUFFER - if report buffer is not large enough to + * hold the output report. + * OEMCrypto_ERROR_INVALID_SESSION - no open session with that id. * OEMCrypto_ERROR_INVALID_CONTEXT - * OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE - if no call to UpdateUsageEntry since - * last call to Deactivate or since key use. + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_UNKNOWN_FAILURE * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE - if no call to UpdateUsageEntry since + * last call to Deactivate or since key use. * OEMCrypto_ERROR_WRONG_PST - report asked for wrong pst. + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * - * Buffer Sizes - * OEMCrypto shall support pst sizes of at least 255 bytes. + * Buffer Sizes: + * OEMCrypto shall support pst sizes of at least 255 bytes. * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is - * too large. + * larger than the supported size. + * + * 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 changed in API version 13. @@ -2928,418 +3770,65 @@ OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session, size_t* buffer_length); /* - * OEMCrypto_DeleteOldUsageTable + * OEMCrypto_MoveEntry * * Description: - * This function will delete the old usage table, if possible, freeing any - * nonvolatile secure memory. This may return - * OEMCrypto_ERROR_NOT_IMPLEMENTED if the device did not support pre-v13 - * usage tables. - * - * This is only needed for devices that are upgrading from a previous version - * of OEMCrypto to v13. Devices that have an existing usage table with - * customer’s offline licenses will use this method to move entries from the - * old table to the new one. - * - * Parameters: - * none - * - * Threading: - * This function will not be called simultaneously with any session functions. - * - * Returns: - * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_NOT_IMPLEMENTED - * OEMCrypto_ERROR_UNKNOWN_FAILURE - * - * Version: - * This method changed in API version 13. - */ -OEMCryptoResult OEMCrypto_DeleteOldUsageTable(); - -/* - * OEMCrypto_CreateOldUsageEntry - * - * Description: - * This forces the creation of an entry in the old usage table in order to - * test OEMCrypto_CopyOldUsageTable. OEMCrypto will create a new entry, set - * the status and compute the times at license receive, first decrypt and - * last decrypt. The mac keys will be copied to the entry. The mac keys are - * not encrypted, but will only correspond to a test license. - * - * Devices that have do not support usage tables, or devices that are will - * not be field upgraded to OEMCrypto v13 may return - * OEMCrypto_ERROR_NOT_IMPLEMENTED. - * - * Threading: - * This function will not be called simultaneously with any session functions. - * - * Returns: - * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_NOT_IMPLEMENTED - * OEMCrypto_ERROR_UNKNOWN_FAILURE - * - * Version: - * This method changed in API version 13. - */ -OEMCryptoResult OEMCrypto_CreateOldUsageEntry(uint64_t time_since_license_received, - uint64_t time_since_first_decrypt, - uint64_t time_since_last_decrypt, - OEMCrypto_Usage_Entry_Status status, - uint8_t *server_mac_key, - uint8_t *client_mac_key, - const uint8_t* pst, - size_t pst_length); - -/* - * OEMCrypto_IsSRMUpdateSupported - * - * Description: - * Returns true if the device supports SRM files and the file can be updated - * via the function OEMCrypto_LoadSRM. This also returns false for devices - * that do not support an SRM file, devices that do not support HDCP, and - * devices that have no external display support. - * - * Parameters: - * none - * - * Threading: - * This function will not be called simultaneously with any session functions. - * - * Returns: - * true - if LoadSRM is supported. - * false - otherwise. - * - * Version: - * This method is new in API version 13. - */ -bool OEMCrypto_IsSRMUpdateSupported(); - -/* - * OEMCrypto_GetCurrentSRMVersion - * - * Description: - * Returns the version number of the current SRM file. If the device does - * not support SRM files, this will return OEMCrypto_ERROR_NOT_IMPLEMENTED. - * If the device only supports local displays, it would return - * OEMCrypto_LOCAL_DISPLAY_ONLY. If the device has an SRM, but cannot use - * OEMCrypto to update the SRM, then this function would set version to be - * the current version number, and return OEMCrypto_SUCCESS, but it would - * return false from OEMCrypto_IsSRMUpdateSupported. - * - * Parameters: - * version (out): current SRM version number. - * - * Threading: - * This function will not be called simultaneously with any session functions. - * - * Returns: - * OEMCrypto_ERROR_NOT_IMPLEMENTED - * OEMCrypto_SUCCESS - * OEMCrypto_LOCAL_DISPLAY_ONLY - to indicate version was not set, and is not - * needed. - * - * Version: - * This method is new in API version 13. - */ -OEMCryptoResult OEMCrypto_GetCurrentSRMVersion(uint16_t* version); - - -/* - * OEMCrypto_LoadSRM - * - * Description: - * Verify and install a new SRM file. The device shall install the new file - * only if verification passes. If verification fails, the existing SRM will - * be left in place. Verification is defined by DCP, and includes - * verification of the SRM’s signature and verification that the SRM version - * number will not be decreased. See the section HDCP SRM Update above for - * more details about the SRM. This function is for devices that support HDCP - * v2.2 or higher and wish to receive 4k content. - * - * Parameters: - * bufer (in): buffer containing the SRM - * buffer_length (in): length of the SRM, in bytes. - * - * Threading: - * This function will not be called simultaneously with any session functions. - * - * Returns: - * OEMCrypto_SUCCESS - if the file was valid and was installed. - * OEMCrypto_ERROR_INVALID_CONTEXT - if the SRM version is too low, or the - * file is corrupted. - * OEMCrypto_ERROR_SIGNATURE_FAILURE - If the signature is invalid. - * OEMCrypto_ERROR_BUFFER_TOO_LARGE - if the buffer is too large for the device. - * OEMCrypto_ERROR_NOT_IMPLEMENTED - * - * Version: - * This method is new in API version 13. - */ -OEMCryptoResult OEMCrypto_LoadSRM(const uint8_t* buffer, - size_t buffer_length); - -/* - * OEMCrypto_RemoveSRM - * - * Description: - * Delete the current SRM. Any valid SRM, regardless of version number, will - * be installable after this via OEMCrypto_LoadSRM. - * - * This function should not be implemented on production devices, and will - * only be used to verify unit tests on a test device. - * - * Parameters: - * none - * - * Threading: - * This function will not be called simultaneously with any session functions. - * - * Returns: - * OEMCrypto_ERROR_NOT_IMPLEMENTED - * OEMCrypto_SUCCESS - * OEMCrypto_ERROR_UNKNOWN_FAILURE - * - * Version: - * This method is new in API version 13. - */ -OEMCryptoResult OEMCrypto_RemoveSRM(); - -/* - * OEMCrypto_CreateUsageTableHeader - * - * Description: - * This creates a new Usage Table Header with no entries. If there is - * already a generation number stored in secure storage, it will be - * incremented by 1 and used as the new Master Generation Number. This will - * only be called if the CDM layer finds no existing usage table on the file - * system. OEMCrypto will encrypt and sign the new, empty, header and return - * it in the provided buffer. + * 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 + * to defragment the usage table. This does not modify any data in the entry, + * except the index and the generation number. The index in the session's + * usage entry will be changed to new_index. The generation number in + * session's usage entry and in the header for new_index will be increased to + * the master generation number, and then the master generation number is + * incremented. If there was an existing entry at the new location, it will + * be overwritten. It is an error to call this when the entry that was at + * new_index is associated with a currently open session. In this case, the + * error code OEMCrypto_ERROR_ENTRY_IN_USE is returned. It is the CDM layer's + * responsibility to call UpdateUsageEntry after moving an entry. It is an + * error for new_index to be beyond the end of the existing usage table + * header. * * Devices that do not implement a Session Usage Table may return * OEMCrypto_ERROR_NOT_IMPLEMENTED. * * Parameters: - * [out] header_buffer: pointer to memory where encrypted usage table header - * is written. - * [in/out] header_buffer_length: (in) length of the header_buffer, in bytes. - * (out) actual length of the header_buffer - * - * Threading: - * This function will not be called simultaneously with any session functions. + * [in] session: handle for the session to be used. + * [in] new_index: new index to be used for the session's usage entry * * Returns: * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_SHORT_BUFFER - if header_buffer_length is too small. * OEMCrypto_ERROR_NOT_IMPLEMENTED * OEMCrypto_ERROR_UNKNOWN_FAILURE - * - * Version: - * This method is new in API version 13. - */ -OEMCryptoResult OEMCrypto_CreateUsageTableHeader(uint8_t* header_buffer, - size_t* header_buffer_length); - -/* - * OEMCrypto_LoadUsageTableHeader - * - * Description: - * This loads the Usage Table Header. The buffer’s signature is verified and - * the buffer is decrypted. OEMCrypto will verify the verification - * string. If the Master Generation Number is more than 1 off, the table is - * considered bad, the headers are NOT loaded, and the error - * OEMCrypto_ERROR_GENERATION_SKEW is returned. If the generation number is - * off by 1, the warning OEMCrypto_WARNING_GENERATION_SKEW is returned but - * the header is still loaded. This warning may be logged by the CDM layer. - * - * - * Parameters: - * [in] buffer: pointer to memory containing encrypted usage table header. - * [in] buffert_length: length of the buffer, in bytes. + * OEMCrypto_ERROR_BUFFER_TOO_LARGE + * OEMCrypto_ERROR_ENTRY_IN_USE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED * * Threading: - * This function will not be called simultaneously with any session functions. - * - * Returns: - * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_SHORT_BUFFER - * OEMCrypto_ERROR_NOT_IMPLEMENTED - some devices do not implement usage - * tables. - * OEMCrypto_ERROR_UNKNOWN_FAILURE - * OEMCrypto_WARNING_GENERATION_SKEW - if the generation number is off by - * exactly 1. - * OEMCrypto_ERROR_GENERATION_SKEW - if the generation number is off by more - * than 1. - * OEMCrypto_ERROR_SIGNATURE_FAILURE - if the signature failed. - * OEMCrypto_ERROR_BAD_MAGIC - verification string does not match. + * 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 13. */ -OEMCryptoResult OEMCrypto_LoadUsageTableHeader(const uint8_t* buffer, - size_t buffer_length); - -/* - * OEMCrypto_CreateNewUsageEntry - * - * Description: - * This creates a new usage entry. The size of the header will be increased - * by 8 bytes, and secure volatile memory will be allocated for it. The new - * entry will be associated with the given session. The status of the new - * entry will be set to “unused”. OEMCrypto will set *usage_entry_number to - * be the index of the new entry. The first entry created will have index 0. - * The new entry will be initialized with a generation number equal to the - * master generation number, which will also be stored in the header’s new - * slot. Then the master generation number will be incremented. Since each - * entry’s generation number is less than the master generation number, the - * new entry will have a generation number that is larger than all other - * entries and larger than all previously deleted entries. This helps - * prevent a rogue application from deleting an entry and then loading an old - * version of it. - * - * Parameters: - * [in] session: handle for the session to be used. - * [out] usage_entry_number: index of new usage entry. - * - * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. - * - * Returns: - * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_NOT_IMPLEMENTED - some devices do not implement usage tables. - * OEMCrypto_ERROR_INSUFFICIENT_RESOURCES - if there is no room in memory to - * increase the size of the usage table header. The CDM layer can delete some - * entries and then try again, or it can pass the error up to the - * application. - * OEMCrypto_ERROR_UNKNOWN_FAILURE - * - * Version: - * This method is new in API version 13. - */ -OEMCryptoResult OEMCrypto_CreateNewUsageEntry(OEMCrypto_SESSION session, - uint32_t* usage_entry_number); - -/* - * OEMCrypto_LoadUsageEntry - * - * Description: - * This loads a usage table saved previously by UpdateUsageEntry. The - * signature at the beginning of the buffer is verified and the buffer will - * be decrypted. Then the verification field in the entry will be verified. - * The index in the entry must match the index passed in. The generation - * number in the entry will be compared against that in the header. If it is - * off by 1, a warning is returned, but the entry is still loaded. This - * warning may be logged by the CDM layer. If the generation number is off - * by more than 1, an error is returned and the entry is not loaded. - * - * If the entry is already loaded into another session, then this fails and - * returns OEMCrypto_ERROR_INVALID_SESSION. - * - * Parameters: - * [in] session: handle for the session to be used. - * [in] usage_entry_number: index of existing usage entry. - * [in] buffer: pointer to memory containing encrypted usage table entry. - * [in] buffer_length: length of the buffer, in bytes. - * - * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. - * - * Returns: - * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_SHORT_BUFFER - * OEMCrypto_ERROR_NOT_IMPLEMENTED - some devices do not implement usage - * tables. - * OEMCrypto_ERROR_UNKNOWN_FAILURE - index beyond end of table. - * OEMCrypto_ERROR_INVALID_SESSION - entry associated with another session or - * the index is wrong. - * OEMCrypto_WARNING_GENERATION_SKEW - if the generation number is off by - * exactly 1. - * OEMCrypto_ERROR_GENERATION_SKEW - if the generation number is off by more - * than 1. - * OEMCrypto_ERROR_SIGNATURE_FAILURE - if the signature failed. - * OEMCrypto_ERROR_BAD_MAGIC - verification string does not match. - * - * Version: - * This method is new in API version 13. - */ -OEMCryptoResult OEMCrypto_LoadUsageEntry(OEMCrypto_SESSION session, - uint32_t index, - const uint8_t* buffer, - size_t buffer_size); - -/* - * OEMCrypto_UpdateUsageEntry - * - * Description: - * Updates the session’s usage entry and fills buffers with the encrypted and - * signed entry and usage table header. OEMCrypto will update all time and - * status values in the entry, and then increment the entry’s generation - * number. The corresponding generation number in the usage table header is - * also incremented so that it matches the one in the entry. The master - * generation number in the usage table header is incremented and is copied - * to secure persistent storage. OEMCrypto will encrypt and sign the entry - * into the entry_buffer, and it will encrypt and sign the usage table header - * into the header_buffer. Some actions, such as the first decrypt and - * deactivating an entry, will also increment the entry’s generation number - * as well as changing the entry’s status and time fields. As in OEMCrypto - * v12, the first decryption will change the status from Inactive to Active, - * and it will set the time stamp "first decrypt". - * - * If the usage entry has the flag ForbidReport set, then the flag is - * cleared. It is the responsibility of the CDM layer to call this function - * and save the usage table before the next call to ReportUsage and before - * the CDM is terminated. Failure to do so will result in generation number - * skew, which will invalidate all of the usage table. - * - * If either buffer_length is not large enough, they are set to the needed - * size, and OEMCrypto_ERROR_SHORT_BUFFER. In this case, the entry is not - * updated, ForbidReport is not cleared, generation numbers are not - * incremented, and no other work is done. - * - * Parameters: - * [in] session: handle for the session to be used. - * [out] header_buffer: pointer to memory where encrypted usage table header - * is written. - * [in/out] header_buffer_length: (in) length of the header_buffer, in bytes. - * (out) actual length of the header_buffer - * [out] entry_buffer: pointer to memory where encrypted usage table entry is - * written. - * [in/out] buffer_length: (in) length of the entry_buffer, in bytes. - * (out) actual length of the entry_buffer - * - * Threading: - * This function may be called simultaneously with functions on other - * sessions, but not with other functions on this session. - * - * Returns: - * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_SHORT_BUFFER - * OEMCrypto_ERROR_NOT_IMPLEMENTED - some devices do not implement usage tables. - * OEMCrypto_ERROR_UNKNOWN_FAILURE - * - * Version: - * This method is new in API version 13. - */ -OEMCryptoResult OEMCrypto_UpdateUsageEntry(OEMCrypto_SESSION session, - uint8_t* header_buffer, - size_t* header_buffer_length, - uint8_t* entry_buffer, - size_t* entry_buffer_length); +OEMCryptoResult OEMCrypto_MoveEntry(OEMCrypto_SESSION session, + uint32_t new_index); /* * OEMCrypto_ShrinkUsageTableHeader * * Description: - * This shrinks the usage table and the header. This function is used by the + * This shrinks the usage table and the header. This function is used by the * CDM layer after it has defragmented the usage table and can delete unused - * entries. It is an error if any open session is associated with an entry - * that will be erased. If new_table_size is larger than the current size, - * then the header is not changed and the error is returned. If the header - * has not been previously loaded, then an error is returned. OEMCrypto will + * entries. It is an error if any open session is associated with an entry + * that will be erased - the error OEMCrypto_ERROR_ENTRY_IN_USE shall be + * returned in this case. If new_table_size is larger than the current size, + * then the header is not changed and the error is returned. If the header + * has not been previously loaded, then an error is returned. OEMCrypto will * increment the master generation number in the header and store the new - * value in secure persistent storage. Then, OEMCrypto will encrypt and sign - * the header into the provided buffer. The generation numbers of all + * value in secure persistent storage. Then, OEMCrypto will encrypt and sign + * the header into the provided buffer. The generation numbers of all * remaining entries will remain unchanged. The next time * OEMCrypto_CreateNewUsageEntry is called, the new entry will have an index * of new_table_size. @@ -3352,20 +3841,24 @@ OEMCryptoResult OEMCrypto_UpdateUsageEntry(OEMCrypto_SESSION session, * OEMCrypto_ERROR_SHORT_BUFFER is returned. * * Parameters: - * [in] new_entry_count: number of entries in the to be in the header. - * [out] header_buffer: pointer to memory where encrypted usage table header - * is written. - * [in/out] header_buffer_length: (in) length of the header_buffer, in bytes. - * (out) actual length of the header_buffer - * - * Threading: - * This function will not be called simultaneously with any session functions. + * [in] new_entry_count: number of entries in the to be in the header. + * [out] header_buffer: pointer to memory where encrypted usage table header + * is written. + * [in/out] header_buffer_length: (in) length of the header_buffer, in bytes. + * (out) actual length of the header_buffer * * Returns: * OEMCrypto_SUCCESS success * OEMCrypto_ERROR_SHORT_BUFFER * OEMCrypto_ERROR_NOT_IMPLEMENTED * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_ENTRY_IN_USE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * 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 13. @@ -3374,111 +3867,309 @@ OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader(uint32_t new_entry_count, uint8_t* header_buffer, size_t* header_buffer_length); -/* - * OEMCrypto_MoveEntry - * - * Description: 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 to defragment the usage table. This does not modify any data - * in the entry, except the index and the generation number. The index in - * the session’s usage entry will be changed to new_index. The generation - * number in session’s usage entry and in the header for new_index will be - * increased to the master generation number, and then the master generation - * number is incremented. If there was an existing entry at the new location, - * it will be overwritten. It is an error to call this when the entry that - * was at new_index is associated with a currently open session. In this - * case, the error code OEMCrypto_ERROR_ENTRY_IN_USE is returned. It is the - * CDM layer’s responsibility to call UpdateUsageEntry after moving an entry. - * It is an error for new_index to be beyond the end of the existing usage - * table header. - * - * Devices that do not implement a Session Usage Table may return - * OEMCrypto_ERROR_NOT_IMPLEMENTED. - * - * Parameters: - * [in] session: handle for the session to be used. - * [in] new_index: new index to be used for the session’s usage entry - * - * Threading: - * This function will not be called simultaneously with any session functions. - * - * Returns: - * OEMCrypto_SUCCESS success - * OEMCrypto_ERROR_NOT_IMPLEMENTED - * OEMCrypto_ERROR_UNKNOWN_FAILURE - * OEMCrypto_ERROR_BUFFER_TOO_LARGE - * - * Version: - * This method is new in API version 13. - */ -OEMCryptoResult OEMCrypto_MoveEntry(OEMCrypto_SESSION session, - uint32_t new_index); - /* * OEMCrypto_CopyOldUsageEntry * * Description: - * This function copies an entry from the old v12 table to the new table. - * The new entry will already have been loaded by CreateNewUsageEntry. If - * the device did not support pre-v13 usage tables, this may return + * This function copies an entry from the old v12 table to the new table. The + * new entry will already have been loaded by CreateNewUsageEntry. If the + * device did not support pre-v13 usage tables, this may return * OEMCrypto_ERROR_NOT_IMPLEMENTED. * - * This is only needed for devices that are upgrading from a previous version - * of OEMCrypto to v13. Devices that have an existing usage table with - * customer’s offline licenses will use this method to move entries from the - * old table to the new one. + * This is only needed for devices that are upgrading from a version of + * OEMCrypto before v13 to a recent version. Devices that have an existing + * usage table with customer's offline licenses will use this method to move + * entries from the old table to the new one. * * Parameters: - * [in] session: handle for the session to be used. - * [in] pst: pointer to memory containing Provider Session Token. - * [in] pst_length: length of the pst, in bytes. - * - * Threading: - * This function will not be called simultaneously with any session functions. + * [in] session: handle for the session to be used. + * [in] pst: pointer to memory containing Provider Session Token. + * [in] pst_length: length of the pst, in bytes. * * Returns: * OEMCrypto_SUCCESS success * OEMCrypto_ERROR_NOT_IMPLEMENTED * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * 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 13. */ OEMCryptoResult OEMCrypto_CopyOldUsageEntry(OEMCrypto_SESSION session, - const uint8_t*pst, + const uint8_t* pst, size_t pst_length); /* - * OEMCrypto_GetAnalogOutputFlags + * OEMCrypto_DeleteOldUsageTable * * Description: - * Returns whether the device supports analog output or not. This - * information will be sent to the license server, and may be used to - * determine the type of license allowed. This function is for reporting - * only. It is paired with the key control block flags Disable_Analog_Output - * and CGMS. + * This function will delete the old usage table, if possible, freeing any + * nonvolatile secure memory. This may return OEMCrypto_ERROR_NOT_IMPLEMENTED + * if the device did not support pre-v13 usage tables. + * + * This is only needed for devices that are upgrading from a version of + * OEMCrypto before v13 to a recent version. Devices that have an existing + * usage table with customer's offline licenses will use this method to move + * entries from the old table to the new one. * * Parameters: - * none. - * - * Threading: - * This function will not be called simultaneously with any session functions. + * none * * Returns: - * Returns a bitwise OR of the following flags. - * 0x0 = OEMCrypto_No_Analog_Output -- the device has no analog output. - * 0x1 = OEMCrypto_Supports_Analog_Output - the device does have analog - * output. - * 0x2 = OEMCrypto_Can_Disable_Analog_Ouptput - the device does have analog - * output, but it will disable analog output if required by the key - * control block. - * 0x4 = OEMCrypto_Supports_CGMS_A - the device supports signaling 2-bit - * CGMS-A, if required by the key control block + * OEMCrypto_SUCCESS success + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_UNKNOWN_FAILURE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * Threading: + * This is an "Initialization and Termination 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 14. + * This method is new in API version 13. */ -uint32_t OEMCrypto_GetAnalogOutputFlags(); +OEMCryptoResult OEMCrypto_DeleteOldUsageTable(); + +/* + * OEMCrypto_RemoveSRM + * + * Description: + * Delete the current SRM. Any valid SRM, regardless of version number, will + * be installable after this via OEMCrypto_LoadSRM. + * + * This function should not be implemented on production devices, and will + * only be used to verify unit tests on a test device. + * + * Parameters: + * none + * + * Returns: + * OEMCrypto_SUCCESS - if the SRM file was deleted. + * OEMCrypto_ERROR_NOT_IMPLEMENTED - always on production devices. + * + * Threading: + * This is an "Initialization and Termination 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 13. + */ +OEMCryptoResult OEMCrypto_RemoveSRM(); + +/* + * OEMCrypto_CreateOldUsageEntry + * + * Description: + * This forces the creation of an entry in the old usage table in order to + * test OEMCrypto_CopyOldUsageTable. OEMCrypto will create a new entry, set + * the status and compute the times at license receive, first decrypt and + * last decrypt. The mac keys will be copied to the entry. The mac keys are + * not encrypted, but will only correspond to a test license. + * + * Devices that do not support usage tables, or devices that will not be + * field upgraded from a version of OEMCrypto before v13 to a recent version + * may return OEMCrypto_ERROR_NOT_IMPLEMENTED. + * + * Returns: + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_SUCCESS + * + * Threading: + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. It is only used when running unit tests. + * + * Version: + * This method is new in API version 13. + */ +OEMCryptoResult OEMCrypto_CreateOldUsageEntry(uint64_t time_since_license_received, + uint64_t time_since_first_decrypt, + uint64_t time_since_last_decrypt, + OEMCrypto_Usage_Entry_Status status, + uint8_t *server_mac_key, + uint8_t *client_mac_key, + const uint8_t* pst, + size_t pst_length); + +/* + * OEMCrypto_SupportsDecryptHash + * + * Description: + * Returns the type of hash function supported for Full Decrypt Path Testing. + * A hash type of 0 means this feature is not supported. OEMCrypto is not + * required by Google to support this feature, but support will greatly + * improve automated testing. A hash type of 1 means the device will be able + * to compute the CRC32 checksum of the decrypted content in the secure + * buffer after a call to OEMCrypto_DecryptCENC. Google intends to provide + * test applications on some platforms, such as Android, that will automate + * decryption testing using the CRC 32 checksum of all frames in some test + * content. + * + * If an SOC vendor cannot support CRC 32 checksums of decrypted output, but + * can support some other hash or checksum, then the function should return + * OEMCrypto_Partner_Defined_Hash and those partners should provide files + * containing hashes of test content. An application that computes the CRC 32 + * hashes of test content and builds a hash file in the correct format will + * be provided by Widevine. The source of this application will be provided + * so that partners may modify it to compute their own hash format and + * generate their own hash files. + * + * Returns: + * OEMCrypto_Hash_Not_Supported = 0; + * OEMCrypto_CRC_Clear_Buffer = 1; + * OEMCrypto_Partner_Defined_Hash = 2; + * + * Threading: + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * Version: + * This method is new in API version 15. + */ +uint32_t OEMCrypto_SupportsDecryptHash(); + +/* + * OEMCrypto_InitializeDecryptHash + * + * Description: + * This function is called before the first subsample is passed to + * OEMCrypto_DecryptCENC, when the subsample_flag has the bit + * OEMCrytpo_FirstSubsample set. OEMCrypto should expect to compute a hash + * over the whole sample. + * + * This function returns OEMCrypto_ERROR_UNKNOWN_FAILURE if the current key + * does not have the bit Allow_Hash_Verification set in its key control block. + * + * Parameters: + * [in] session: session id for current decrypt operation + * + * Returns: + * OEMCrypto_SUCCESS - if the hash was set + * OEMCrypto_ERROR_NOT_IMPLEMENTED - function not implemented + * OEMCrypto_ERROR_INVALID_SESSION - session not open + * OEMCrypto_ERROR_UNKNOWN_FAILURE - other error + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * 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 15. + */ +OEMCryptoResult OEMCrypto_InitializeDecryptHash(OEMCrypto_SESSION session); + +/* + * OEMCrypto_SetDecryptHash + * + * Description: + * Set the hash value for the frame that was just decrypted. The hash is over + * all of the frame: encrypted and clear subsamples concatenated together. 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 could return OEMCrypto_ERROR_UNKNOWN_FAILURE. + * The length of the hash will be at most 128 bytes. This function is called + * just after the last subsample in the frame, when the subsample_flag has + * the bit OEMCrypto_LastSubsample set. The hash only applies to the previous + * frame. + * + * This function returns OEMCrypto_ERROR_UNKNOWN_FAILURE if the current key + * does not have the bit Allow_Hash_Verification set in its key control block. + * + * OEMCrypto should compute the hash of the frame and then compare it with + * the correct value. If the values differ, then OEMCrypto should latch in an + * error and save the frame number of the bad hash. It is allowed for + * OEMCrypto to postpone computation of the hash until the frame is + * displayed. This might happen if the actual decryption operation is carried + * out by a later step in the video pipeline, or if you are using a partner + * specified hash of the decoded frame. For this reason, an error state must + * be saved until the call to OEMCrypto_GetHashErrorCode is made. + * + * Parameters: + * [in] session: session id for current decrypt operation + * [in] frame_number: frame number for the recent DecryptCENC sample. + * [in] hash: hash or CRC of previously decrypted frame. + * [in] hash_length: length of hash, in bytes. + * + * Returns: + * OEMCrypto_SUCCESS - if the hash was set + * OEMCrypto_ERROR_NOT_IMPLEMENTED - function not implemented + * OEMCrypto_ERROR_INVALID_SESSION - session not open + * OEMCrypto_ERROR_SHORT_BUFFER - hash_length too short for supported hash + * type + * OEMCrypto_ERROR_BUFFER_TOO_LARGE - hash_length too long for supported hash + * type + * OEMCrypto_ERROR_UNKNOWN_FAILURE - other error + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * 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 15. + */ +OEMCryptoResult OEMCrypto_SetDecryptHash(OEMCrypto_SESSION session, + uint32_t frame_number, + const uint8_t* hash, + size_t hash_length); + +/* + * OEMCrypto_GetHashErrorCode + * + * Description: + * If the hash set in OEMCrypto_SetDecryptHash did not match the computed + * hash, then an error code was saved internally. This function returns that + * error and the frame number of the bad hash. This will be called + * periodically, but not exactly in sync with the decrypt loop. OEMCrypto + * shall not reset the error state to "no error" once a frame has failed + * verification. It should be initialized to "no error" when the session is + * first opened. If there is more than one bad frame, it is the implementer's + * choice if it is more useful to return the number of the first bad frame, + * or the most recent bad frame. + * + * Parameters: + * [in] session: session id for operation. + * [out] failed_frame_number: frame number for sample with incorrect hash. + * + * Returns: + * OEMCrypto_SUCCESS - if all frames have had a correct hash + * OEMCrypto_ERROR_NOT_IMPLEMENTED + * OEMCrypto_ERROR_BAD_HASH - if any frame had an incorrect hash + * OEMCrypto_ERROR_UNKNOWN_FAILURE - if the hash could not be computed + * OEMCrypto_ERROR_SESSION_LOST_STATE + * OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * 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 15. + */ +OEMCryptoResult OEMCrypto_GetHashErrorCode(OEMCrypto_SESSION session, + uint32_t* failed_frame_number); #ifdef __cplusplus } diff --git a/oemcrypto/include/level3.h b/oemcrypto/include/level3.h index d2f2d1a..499d2ca 100644 --- a/oemcrypto/include/level3.h +++ b/oemcrypto/include/level3.h @@ -170,13 +170,10 @@ OEMCryptoResult Level3_GenerateSignature(OEMCrypto_SESSION session, size_t message_length, uint8_t* signature, size_t* signature_length); -OEMCryptoResult Level3_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 Level3_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_V14* key_array); OEMCryptoResult Level3_QueryKeyControl(OEMCrypto_SESSION session, const uint8_t* key_id, size_t key_id_length, @@ -347,27 +344,20 @@ OEMCryptoResult Level3_CreateOldUsageEntry(uint64_t time_since_license_received, const uint8_t* pst, size_t pst_length); uint32_t Level3_GetAnalogOutputFlags(); -OEMCryptoResult Level3_LoadTestKeybox(const uint8_t *buffer, size_t length); -OEMCryptoResult Level3_LoadEntitledContentKeys(OEMCrypto_SESSION session, - size_t num_keys, - const OEMCrypto_EntitledContentKeyObject* key_array); +OEMCryptoResult Level3_LoadTestKeybox(const uint8_t* buffer, size_t length); +OEMCryptoResult Level3_LoadEntitledContentKeys( + OEMCrypto_SESSION session, size_t num_keys, + const OEMCrypto_EntitledContentKeyObject_V14* key_array); OEMCryptoResult Level3_SelectKey(const OEMCrypto_SESSION session, - const uint8_t* key_id, - size_t key_id_length, + const uint8_t* key_id, size_t key_id_length, OEMCryptoCipherMode cipher_mode); -OEMCryptoResult Level3_LoadKeys(OEMCrypto_SESSION session, - const uint8_t* message, - size_t message_length, - const uint8_t* signature, - size_t signature_length, - const uint8_t* enc_mac_key_iv, - const uint8_t* enc_mac_key, - size_t num_keys, - const OEMCrypto_KeyObject* key_array, - const uint8_t* pst, - size_t pst_length, - const uint8_t* srm_requirement, - OEMCrypto_LicenseType license_type); +OEMCryptoResult Level3_LoadKeys( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const uint8_t* signature, size_t signature_length, + const uint8_t* enc_mac_key_iv, const uint8_t* enc_mac_key, size_t num_keys, + const OEMCrypto_KeyObject_V14* key_array, const uint8_t* pst, + size_t pst_length, const uint8_t* srm_requirement, + OEMCrypto_LicenseType license_type); /* * Level3_GetInitializationState * diff --git a/oemcrypto/include/oemcrypto_types.h b/oemcrypto/include/oemcrypto_types.h index ba00f7d..2bff9d7 100644 --- a/oemcrypto/include/oemcrypto_types.h +++ b/oemcrypto/include/oemcrypto_types.h @@ -28,6 +28,7 @@ const uint32_t kControlObserveDataPath = (1<<31); const uint32_t kControlObserveHDCP = (1<<30); const uint32_t kControlObserveCGMS = (1<<29); const uint32_t kControlRequireAntiRollbackHardware = (1<<28); +const uint32_t kControlAllowHashVerification = (1<<24); const uint32_t kSharedLicense = (1<<23); const uint32_t kControlSRMVersionRequired = (1<<22); const uint32_t kControlDisableAnalogOutput = (1<<21); diff --git a/oemcrypto/ref/src/oem_cert.cpp b/oemcrypto/ref/src/oem_cert.cpp index 7a0278c..0b7ab7f 100644 --- a/oemcrypto/ref/src/oem_cert.cpp +++ b/oemcrypto/ref/src/oem_cert.cpp @@ -4,378 +4,320 @@ namespace wvoec_ref { -extern const uint32_t kOEMSystemId_Prod = 7346; +const uint32_t kOEMSystemId_Prod = 7913; -extern const uint8_t kOEMPrivateKey_Prod[] = { - 0x30, 0x82, 0x06, 0xfe, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, - 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, - 0x06, 0xe8, 0x30, 0x82, 0x06, 0xe4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, - 0x81, 0x00, 0xf5, 0x09, 0x64, 0x4a, 0x26, 0xfe, 0xc0, 0x98, 0x55, 0x6a, - 0x1d, 0x5d, 0x1c, 0xc7, 0x38, 0xaf, 0xfd, 0x49, 0x9e, 0x85, 0x3f, 0xd6, - 0x45, 0x0e, 0x99, 0x09, 0x85, 0x69, 0x84, 0x3c, 0xfe, 0x72, 0xa5, 0x56, - 0xfa, 0x11, 0x4f, 0x6b, 0x7d, 0x32, 0x2b, 0x0c, 0xbf, 0x8f, 0xac, 0x47, - 0x96, 0x22, 0x82, 0x3d, 0xf5, 0x64, 0x74, 0x7e, 0x62, 0x68, 0x74, 0xcd, - 0x0a, 0xec, 0x84, 0xc5, 0x15, 0x06, 0x0e, 0x5a, 0x2f, 0x20, 0xe3, 0xc9, - 0x67, 0xcd, 0xdd, 0x01, 0xb8, 0xb3, 0x18, 0x87, 0x8c, 0xa9, 0x58, 0x86, - 0x0f, 0xb6, 0xc3, 0x42, 0x7e, 0x87, 0x48, 0x5e, 0x10, 0x49, 0xc7, 0xd7, - 0xb7, 0xb8, 0xa6, 0x34, 0x08, 0x0c, 0x94, 0xf4, 0xbb, 0x2a, 0x06, 0xa4, - 0x4f, 0xec, 0xbc, 0xc4, 0x37, 0xbe, 0x99, 0x10, 0x23, 0x37, 0x24, 0xb1, - 0xdf, 0xcb, 0xe6, 0x3f, 0xc1, 0xf0, 0x0f, 0x04, 0x03, 0xc8, 0xb0, 0x1e, - 0xd6, 0xb8, 0xae, 0x77, 0xe1, 0x4d, 0x6d, 0x97, 0x69, 0x6d, 0x8a, 0x73, - 0x66, 0x32, 0x57, 0x6f, 0xcf, 0xea, 0x1e, 0x7b, 0x87, 0x03, 0x75, 0xb1, - 0xef, 0x83, 0x64, 0x26, 0xf1, 0x3f, 0xbf, 0xe6, 0x28, 0x03, 0x72, 0x57, - 0xbf, 0x47, 0x29, 0x99, 0x8f, 0x74, 0x1d, 0x01, 0x16, 0xad, 0xb2, 0xdf, - 0x80, 0xa4, 0xd3, 0x8b, 0xeb, 0x61, 0xd1, 0x40, 0x68, 0xb9, 0xa2, 0xa5, - 0xef, 0x2b, 0xe5, 0x78, 0xe8, 0x28, 0x88, 0x87, 0xb7, 0x53, 0x49, 0xbb, - 0xe4, 0xea, 0x0d, 0x5e, 0x96, 0xa5, 0xdd, 0x1f, 0x0b, 0x25, 0x8b, 0xb5, - 0x95, 0x46, 0xe7, 0xba, 0xb8, 0xc4, 0x0a, 0x36, 0xb1, 0x89, 0xeb, 0x27, - 0x5d, 0xd9, 0x97, 0x24, 0x59, 0xa3, 0x9b, 0xb0, 0x23, 0x0b, 0xd2, 0xec, - 0x65, 0x91, 0xf9, 0xf0, 0xa0, 0x74, 0x5f, 0xb4, 0xce, 0x22, 0x27, 0x18, - 0x37, 0xe2, 0x4b, 0xfc, 0x91, 0xf9, 0x09, 0x15, 0xe6, 0xdb, 0x06, 0x9b, - 0x4d, 0x82, 0xdc, 0x36, 0x14, 0x48, 0xc6, 0xd5, 0x87, 0xca, 0xec, 0x5a, - 0xa2, 0x29, 0x33, 0xef, 0x22, 0x0c, 0x4b, 0xbf, 0xe7, 0x2f, 0x95, 0xe1, - 0xd3, 0xa5, 0xd8, 0xaa, 0x44, 0x77, 0x29, 0xa3, 0x20, 0x33, 0xd2, 0x51, - 0xa2, 0xf9, 0x4a, 0x6f, 0xf7, 0x3e, 0xf7, 0x0b, 0x8a, 0xec, 0xc1, 0x99, - 0x1d, 0x47, 0xf3, 0x74, 0x02, 0x04, 0xab, 0x8e, 0x62, 0x4c, 0x9e, 0x00, - 0xc2, 0x84, 0xd7, 0xd0, 0xf8, 0xe4, 0x1c, 0x9d, 0x98, 0x15, 0xa8, 0x8f, - 0x08, 0x98, 0x4e, 0x5a, 0xfa, 0xd6, 0x60, 0x87, 0x12, 0xdc, 0x8e, 0xfd, - 0xcb, 0xb3, 0x13, 0x97, 0x7a, 0xa8, 0x8c, 0x56, 0x2e, 0x49, 0x26, 0x60, - 0xe9, 0x4a, 0xdc, 0xec, 0x3f, 0xf0, 0x94, 0xcd, 0x90, 0x8e, 0x7c, 0x21, - 0x3f, 0x80, 0x14, 0x33, 0xdd, 0xb0, 0x00, 0xe2, 0x09, 0x37, 0x06, 0xdd, - 0x17, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x81, 0x00, - 0xa1, 0xc9, 0x44, 0xad, 0x6d, 0x17, 0xd1, 0x04, 0x03, 0x89, 0x5f, 0xbf, - 0xe5, 0xcb, 0x68, 0x13, 0x52, 0xf2, 0x33, 0xb7, 0x19, 0x12, 0x19, 0x60, - 0x6d, 0x0d, 0x0b, 0x48, 0x42, 0xe6, 0x9e, 0xbe, 0x05, 0x8a, 0xea, 0xeb, - 0x58, 0xfb, 0xc8, 0x9a, 0xc2, 0x2f, 0xd5, 0x9f, 0x40, 0x09, 0xb8, 0x08, - 0x2a, 0xe4, 0x4b, 0xcc, 0xba, 0xd9, 0xe3, 0x91, 0xc2, 0x64, 0xcb, 0x6c, - 0xa4, 0xb1, 0x17, 0x93, 0x7b, 0x10, 0x72, 0x83, 0x8d, 0xc2, 0xa2, 0x46, - 0x1b, 0x41, 0x12, 0xb9, 0x35, 0x5d, 0xf2, 0x32, 0xb1, 0xdf, 0x3a, 0x2a, - 0xda, 0xbb, 0x61, 0x9d, 0x62, 0xdb, 0xb0, 0x77, 0x76, 0x7a, 0x68, 0xb4, - 0x83, 0x10, 0x61, 0xac, 0x25, 0x01, 0x7d, 0x3e, 0x5f, 0x4a, 0x47, 0xf7, - 0x30, 0x1f, 0x82, 0x0a, 0xd7, 0x36, 0xff, 0x79, 0x5e, 0x42, 0x0f, 0x58, - 0xaa, 0x3a, 0xb8, 0x8b, 0x0e, 0xef, 0x00, 0xac, 0x96, 0x14, 0x96, 0x83, - 0x33, 0xb6, 0xb5, 0x4c, 0x91, 0x2a, 0x62, 0x92, 0xcf, 0xd2, 0x27, 0xcc, - 0xdf, 0x4c, 0x55, 0x03, 0xe8, 0x82, 0x78, 0xff, 0x80, 0xcb, 0x2e, 0x30, - 0x1b, 0x85, 0x56, 0xce, 0x57, 0x9e, 0xd8, 0x16, 0x86, 0x7d, 0x87, 0x2e, - 0xae, 0x39, 0xd4, 0xac, 0xbe, 0xa5, 0xc4, 0x5a, 0x85, 0x7a, 0xea, 0x8e, - 0x69, 0x9a, 0xbd, 0x9c, 0x45, 0x33, 0xf8, 0xb1, 0x70, 0xc1, 0x8c, 0xaa, - 0xad, 0x3d, 0x76, 0x08, 0x5b, 0x7d, 0x12, 0x93, 0x03, 0x70, 0xe6, 0x5f, - 0xb2, 0xac, 0x78, 0xae, 0xbe, 0xc5, 0x31, 0xc8, 0x6d, 0x2c, 0x1c, 0x2f, - 0x41, 0x37, 0xf6, 0x88, 0xd3, 0x80, 0x93, 0xed, 0x55, 0xb1, 0xaa, 0x49, - 0xe8, 0x42, 0xd0, 0x19, 0x20, 0x58, 0xe7, 0x2d, 0x10, 0xf2, 0x69, 0x49, - 0xe9, 0x47, 0x95, 0xbb, 0xce, 0xa7, 0xe9, 0x86, 0x46, 0x1c, 0xd1, 0x1f, - 0xd4, 0xa9, 0xeb, 0x28, 0x57, 0x78, 0x6c, 0xc6, 0x6f, 0x84, 0x3b, 0xb4, - 0x8c, 0xe5, 0xd3, 0x23, 0x8b, 0xbe, 0x83, 0x75, 0x5e, 0xea, 0xcd, 0x93, - 0xd2, 0x42, 0x86, 0xfd, 0x2b, 0x67, 0x72, 0xe0, 0x46, 0x9c, 0xf7, 0xc1, - 0xe9, 0x5d, 0xad, 0xac, 0xcb, 0x57, 0xb4, 0xe7, 0x87, 0x25, 0x7d, 0x5a, - 0x43, 0x90, 0xa3, 0x2e, 0xbf, 0x36, 0xbd, 0x4c, 0xba, 0xec, 0x0f, 0x21, - 0x51, 0xda, 0x66, 0xb8, 0x1e, 0xac, 0x33, 0xeb, 0xa1, 0x3e, 0x72, 0x15, - 0x10, 0x45, 0xc0, 0xe4, 0xdb, 0x04, 0x6d, 0xaf, 0x66, 0xc2, 0xfc, 0x35, - 0x04, 0x60, 0x7d, 0x2f, 0x5e, 0x9e, 0x83, 0xf6, 0x72, 0x92, 0x6a, 0x9f, - 0xba, 0x94, 0x97, 0x33, 0xe1, 0x1d, 0x42, 0xda, 0xad, 0xa5, 0x8b, 0xad, - 0x2f, 0x2f, 0x32, 0x16, 0x88, 0x54, 0x88, 0xb2, 0x85, 0xe2, 0x33, 0x08, - 0x43, 0xc8, 0x68, 0x69, 0xaa, 0xea, 0x9a, 0xbf, 0x41, 0x12, 0xe6, 0xf1, - 0x02, 0x81, 0xc1, 0x00, 0xfe, 0x96, 0xe7, 0xc8, 0x89, 0x61, 0x2b, 0x58, - 0xaa, 0xcd, 0x37, 0x46, 0x13, 0xa1, 0x2a, 0xc8, 0x1b, 0x76, 0xde, 0x4c, - 0xb3, 0x00, 0x4f, 0x6b, 0x02, 0xc0, 0x10, 0xef, 0x87, 0xe2, 0x6d, 0x7f, - 0x10, 0x57, 0xec, 0xde, 0x70, 0x60, 0xb5, 0x8f, 0x6d, 0x17, 0x35, 0xbd, - 0xfd, 0x6a, 0x2c, 0xbb, 0xf0, 0x48, 0x5b, 0x32, 0x41, 0xf6, 0xc0, 0x62, - 0x3a, 0x88, 0xc5, 0x41, 0x83, 0x85, 0x56, 0xa7, 0x11, 0xf4, 0xd2, 0xa9, - 0xb3, 0xa3, 0xcb, 0xae, 0xca, 0xee, 0x1c, 0x52, 0x7f, 0x04, 0x34, 0x61, - 0xb9, 0x8d, 0xa3, 0x26, 0x88, 0xce, 0x3d, 0xdb, 0x9c, 0xbf, 0xcc, 0xc4, - 0x38, 0x8b, 0xf2, 0xe4, 0x7e, 0xcc, 0x46, 0x86, 0x7a, 0x3c, 0xb7, 0x95, - 0x3f, 0xbd, 0x81, 0x45, 0xc3, 0x1d, 0xbb, 0xf8, 0x56, 0x6e, 0xa5, 0x88, - 0x2d, 0xff, 0x78, 0xc0, 0xc2, 0x4a, 0x4f, 0xea, 0xb8, 0x81, 0xf3, 0x96, - 0x5e, 0xd8, 0xcb, 0x96, 0x42, 0xa3, 0x21, 0x03, 0xc8, 0x00, 0xbf, 0x95, - 0xc7, 0x83, 0x80, 0xc6, 0xc2, 0x38, 0xe4, 0xaf, 0xb2, 0x0e, 0x80, 0x92, - 0x97, 0x21, 0x16, 0xce, 0x39, 0xd3, 0x95, 0xb7, 0xc3, 0x78, 0xe1, 0x1c, - 0xc0, 0x5a, 0xbc, 0x9b, 0x68, 0x3f, 0xd6, 0x42, 0xcd, 0xca, 0x0b, 0x6d, - 0x9f, 0xde, 0x6b, 0x98, 0x3b, 0x47, 0x57, 0xb9, 0x2d, 0x92, 0x52, 0x29, - 0xc5, 0xed, 0xb5, 0x0d, 0x02, 0x81, 0xc1, 0x00, 0xf6, 0x64, 0xef, 0xef, - 0x57, 0xdb, 0x06, 0xae, 0x36, 0x86, 0x11, 0xaf, 0x96, 0xb9, 0xb1, 0x29, - 0x53, 0xce, 0x24, 0x60, 0x96, 0x8f, 0xd0, 0xb7, 0x4b, 0x60, 0x1e, 0xb3, - 0x1f, 0xae, 0x15, 0x41, 0xf1, 0x56, 0xd6, 0xf3, 0x07, 0xf8, 0xd7, 0xdd, - 0x1c, 0x82, 0xe8, 0xe0, 0xff, 0xb3, 0x41, 0x0d, 0x41, 0x96, 0x0d, 0xf2, - 0x03, 0xb0, 0x68, 0xed, 0xda, 0x8b, 0x83, 0x18, 0x4d, 0xae, 0xaf, 0x72, - 0xa1, 0x82, 0xe5, 0x5a, 0xdc, 0x2a, 0x5f, 0x93, 0x29, 0xc7, 0x24, 0xa0, - 0x8e, 0x32, 0x4c, 0x0e, 0xca, 0x6d, 0x14, 0x69, 0x5b, 0x61, 0xc5, 0xdc, - 0x0e, 0x50, 0x0c, 0x14, 0x84, 0x8b, 0xee, 0x9e, 0x1e, 0x8c, 0x3d, 0xdb, - 0x24, 0xe7, 0x99, 0x6d, 0x3c, 0xaf, 0xe6, 0x3b, 0xaa, 0xb4, 0xe4, 0x42, - 0x13, 0x53, 0x3e, 0x02, 0x47, 0x0d, 0x3a, 0x2b, 0x97, 0x71, 0x9f, 0x1b, - 0x76, 0x2d, 0xe5, 0x9c, 0x5e, 0x46, 0x5f, 0x36, 0xbf, 0x18, 0xb1, 0x1d, - 0x9a, 0xeb, 0x4d, 0x5e, 0x83, 0xd5, 0x3e, 0x5f, 0xf2, 0x6a, 0x56, 0x79, - 0x0f, 0x54, 0xec, 0x41, 0xc0, 0xdc, 0x29, 0x42, 0x45, 0xae, 0x47, 0x1c, - 0x7a, 0xd5, 0xb7, 0x92, 0x1e, 0x66, 0xb8, 0x1a, 0x2f, 0x53, 0xd2, 0x6d, - 0x42, 0x3c, 0x6c, 0x02, 0x01, 0x03, 0x9e, 0x9a, 0x95, 0x35, 0x81, 0x21, - 0x53, 0x53, 0x16, 0xda, 0x8a, 0x80, 0x8c, 0xcd, 0x02, 0x81, 0xc1, 0x00, - 0xd5, 0xba, 0x05, 0xf7, 0x7a, 0x2d, 0x52, 0xe0, 0x6a, 0xf3, 0x40, 0xd5, - 0xd9, 0xa0, 0xd1, 0x73, 0x90, 0x6a, 0xe8, 0x10, 0x67, 0xad, 0x78, 0xfe, - 0x93, 0x1e, 0x7e, 0x99, 0x37, 0xf0, 0x44, 0x90, 0x09, 0x3e, 0x67, 0x22, - 0x0e, 0x21, 0x82, 0x0a, 0x58, 0x40, 0xc5, 0xe3, 0x2b, 0x9d, 0x38, 0xd4, - 0xc5, 0xd1, 0x58, 0x8e, 0x06, 0x86, 0x89, 0xd7, 0x6c, 0xe0, 0x69, 0x08, - 0xa8, 0xcb, 0x05, 0x85, 0xd8, 0x33, 0x39, 0xaf, 0x31, 0x99, 0xee, 0x62, - 0x5d, 0x06, 0x2c, 0x4c, 0xad, 0x48, 0xf0, 0x58, 0xa2, 0x17, 0x5f, 0xc1, - 0xf7, 0xd3, 0x7c, 0x66, 0xa3, 0x5e, 0xf9, 0x1e, 0x39, 0x82, 0x73, 0x74, - 0x93, 0x66, 0x16, 0x46, 0xca, 0xd3, 0xb2, 0x22, 0xdf, 0x91, 0xcd, 0xb6, - 0xad, 0x28, 0x87, 0x26, 0xe2, 0x18, 0x9d, 0x6a, 0x87, 0x83, 0x12, 0xf2, - 0x6f, 0xa9, 0x47, 0x11, 0xfb, 0xb7, 0x4c, 0xb1, 0x0e, 0x0a, 0xde, 0x4e, - 0xd4, 0xbe, 0x71, 0xf6, 0xe4, 0xae, 0x8c, 0x27, 0xc7, 0x88, 0x84, 0x51, - 0x57, 0xb7, 0xbf, 0x74, 0x27, 0xfc, 0xb8, 0xbf, 0x57, 0x94, 0x75, 0xba, - 0xc7, 0x1c, 0xf3, 0x71, 0x83, 0xee, 0x34, 0xbd, 0x98, 0x56, 0x14, 0x44, - 0x3a, 0xee, 0x6c, 0x87, 0x44, 0x8f, 0xbb, 0xac, 0x5a, 0x2b, 0xb5, 0x13, - 0xe5, 0x9f, 0xec, 0xeb, 0x0e, 0x70, 0xe9, 0xfd, 0x1b, 0xa6, 0x84, 0xf9, - 0x02, 0x81, 0xc0, 0x4e, 0x82, 0x26, 0xf9, 0x6a, 0x52, 0xfd, 0xb3, 0xf0, - 0xe7, 0x93, 0x27, 0x11, 0xad, 0xa5, 0x47, 0x77, 0xce, 0x8d, 0x44, 0xc1, - 0x74, 0x9d, 0x9a, 0x69, 0xc7, 0xfc, 0xc0, 0x32, 0x6d, 0xf3, 0x94, 0x09, - 0x64, 0x14, 0x25, 0x67, 0xfa, 0xe0, 0x3d, 0x31, 0xe2, 0x7c, 0x75, 0x84, - 0xc4, 0x07, 0x0c, 0x44, 0x43, 0x9d, 0xb9, 0xe9, 0x77, 0x02, 0x58, 0x17, - 0x74, 0xb0, 0x96, 0xc3, 0xd9, 0xcf, 0x49, 0x85, 0x31, 0x02, 0x07, 0x8b, - 0x73, 0x6c, 0xf4, 0xa5, 0x31, 0x30, 0xf8, 0x7f, 0x96, 0x83, 0x29, 0x8b, - 0x52, 0x6a, 0x58, 0x8f, 0xa7, 0x7d, 0xb5, 0xfa, 0x51, 0x83, 0x27, 0xde, - 0x7b, 0xff, 0xd2, 0x1e, 0x05, 0xad, 0x87, 0xf0, 0x20, 0x63, 0x80, 0xac, - 0xff, 0x97, 0x2a, 0x97, 0xdf, 0xff, 0x83, 0x16, 0x49, 0x45, 0xce, 0xcf, - 0xf8, 0xe4, 0xfa, 0x12, 0xcd, 0x3f, 0x57, 0x2e, 0xb6, 0xbd, 0x1c, 0xaf, - 0xe5, 0x58, 0x5d, 0x47, 0x52, 0x84, 0xcc, 0xdc, 0x19, 0xf1, 0x93, 0x16, - 0x0a, 0x92, 0x4f, 0x5c, 0x1c, 0x89, 0xe5, 0x14, 0xff, 0x88, 0x30, 0x03, - 0x55, 0xa3, 0x47, 0xdc, 0x90, 0x05, 0x54, 0x8b, 0xc7, 0x21, 0x30, 0xcb, - 0xc3, 0x0b, 0x12, 0x3c, 0xd6, 0x46, 0x8c, 0x4d, 0xb8, 0x96, 0xe9, 0xa4, - 0x8d, 0x14, 0xb2, 0x48, 0xac, 0xbd, 0xb2, 0x72, 0xac, 0x5c, 0xf1, 0xd1, - 0x83, 0xd8, 0x59, 0x02, 0x81, 0xc0, 0x2d, 0x65, 0xc1, 0xc7, 0x0f, 0xca, - 0xbc, 0x5d, 0xa1, 0x30, 0x28, 0x27, 0x51, 0xcc, 0xc9, 0x6c, 0x7b, 0x76, - 0x43, 0xa9, 0x77, 0xd8, 0x29, 0xa3, 0x80, 0x57, 0x3b, 0xe9, 0x72, 0x1c, - 0x51, 0x37, 0xc2, 0x0b, 0x74, 0xb7, 0xaa, 0x63, 0xd5, 0xe2, 0x9b, 0x3a, - 0x3c, 0x78, 0x50, 0xcb, 0x88, 0x1a, 0xd6, 0x59, 0xdc, 0xb3, 0x05, 0xbf, - 0xe5, 0xc5, 0xb5, 0xe3, 0x9b, 0xba, 0xe7, 0xbb, 0x4d, 0x45, 0xb3, 0x4c, - 0xf2, 0x48, 0x65, 0xe7, 0x6b, 0xee, 0x12, 0xc8, 0xd5, 0xea, 0xf0, 0x89, - 0xf9, 0x03, 0xa3, 0xd9, 0x5f, 0x62, 0x2d, 0x1a, 0x55, 0x51, 0x5d, 0xf6, - 0xca, 0x6e, 0x5f, 0xf0, 0x66, 0x02, 0xf4, 0x20, 0xe6, 0xe9, 0xc4, 0xd7, - 0x36, 0x8d, 0x00, 0xce, 0x23, 0xfd, 0x90, 0xd4, 0x19, 0x5c, 0xe9, 0xcb, - 0x23, 0xe2, 0x2c, 0xf5, 0xe1, 0x6f, 0x9d, 0xb5, 0xdf, 0xea, 0x51, 0xdd, - 0x02, 0xd8, 0x40, 0xd6, 0x7f, 0x4b, 0xdb, 0x0e, 0xe2, 0x27, 0x4d, 0x0d, - 0x9b, 0x2e, 0xf7, 0xc8, 0x22, 0xca, 0x63, 0x3c, 0x2c, 0xe5, 0xa8, 0x42, - 0x26, 0xd9, 0xfc, 0xdc, 0x42, 0xc8, 0x07, 0x64, 0xa2, 0x98, 0xae, 0xb4, - 0x57, 0x02, 0x02, 0xb2, 0x2d, 0xc8, 0x59, 0x73, 0x9b, 0xee, 0xc0, 0x9a, - 0x42, 0x9a, 0xef, 0xc2, 0x27, 0x24, 0x2b, 0x20, 0x92, 0xad, 0x50, 0xfe, - 0x2c, 0x2d, 0xb6, 0xb6, 0xb5, 0xba +// From file test_rsa_key_2_carmichael.pk8 in team shared drive. +// Size is 1216. +const uint8_t kOEMPrivateKey_Prod[] = { + 0x30, 0x82, 0x04, 0xbc, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x04, 0xa6, 0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, + 0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, + 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde, + 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, + 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4, + 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, + 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce, + 0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, + 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e, + 0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, + 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b, + 0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, + 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54, + 0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, + 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51, + 0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, + 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12, + 0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, + 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a, + 0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, + 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb, + 0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, + 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, + 0x82, 0x01, 0x00, 0x0a, 0xf9, 0x4a, 0x19, 0x72, 0x88, 0x1b, 0x4e, 0xd8, + 0x2f, 0xef, 0x99, 0x93, 0x32, 0xda, 0x51, 0x21, 0x2e, 0x14, 0x06, 0xf4, + 0xe9, 0x65, 0x1c, 0xf9, 0xd4, 0xcf, 0x1a, 0x51, 0x53, 0xcd, 0x48, 0x33, + 0x8c, 0x30, 0xed, 0xdd, 0x53, 0x6f, 0x29, 0x82, 0xf9, 0xe0, 0x74, 0xde, + 0xb1, 0x13, 0x01, 0x88, 0x8f, 0xce, 0x14, 0xc1, 0x3b, 0x90, 0xb7, 0xcc, + 0x6c, 0xdf, 0x35, 0xa1, 0xf2, 0x1a, 0x3d, 0xbe, 0x19, 0xd7, 0x0a, 0xe4, + 0x67, 0x75, 0xbb, 0xfa, 0x87, 0xf4, 0x03, 0xb5, 0x7f, 0x69, 0xe4, 0x0b, + 0x6a, 0xdc, 0x92, 0x82, 0x54, 0x64, 0x1a, 0x94, 0x2d, 0xe4, 0x63, 0x40, + 0xb2, 0xb4, 0x85, 0x6b, 0xc8, 0x34, 0xba, 0xa2, 0x14, 0x30, 0x47, 0x1a, + 0xeb, 0x90, 0x62, 0x30, 0x43, 0x44, 0x02, 0xc7, 0x0c, 0x30, 0xc0, 0x7f, + 0xa9, 0x47, 0xae, 0xde, 0x68, 0x27, 0x92, 0xaa, 0x11, 0x95, 0xf5, 0x6f, + 0xfc, 0x19, 0x8b, 0x49, 0xa0, 0x77, 0x9d, 0xc6, 0x13, 0x5d, 0x73, 0xff, + 0x45, 0xa2, 0x4c, 0x3b, 0xf3, 0xe1, 0x2d, 0xd7, 0xc4, 0x70, 0xe2, 0x6c, + 0x37, 0x99, 0x4c, 0x7a, 0xa9, 0x27, 0xf8, 0x3a, 0xd6, 0xfd, 0xc5, 0xd8, + 0xfa, 0x2d, 0x0e, 0x71, 0x4b, 0x85, 0x7e, 0xce, 0xcb, 0x1c, 0x79, 0x71, + 0xbd, 0xff, 0x63, 0x03, 0x6b, 0x58, 0x68, 0xe0, 0x14, 0xca, 0x5e, 0x85, + 0xfd, 0xd0, 0xb7, 0xe0, 0x68, 0x14, 0xff, 0x2c, 0x82, 0x22, 0x26, 0x8a, + 0x3f, 0xbf, 0xb0, 0x2a, 0x90, 0xff, 0xc7, 0x72, 0xfc, 0x66, 0x51, 0x3e, + 0x51, 0x9f, 0x82, 0x68, 0x0e, 0xf3, 0x65, 0x74, 0x88, 0xab, 0xb7, 0xe5, + 0x97, 0x5f, 0x0f, 0x3e, 0xe5, 0x3a, 0xbc, 0xa4, 0xa1, 0x50, 0xdd, 0x5c, + 0x94, 0x4b, 0x0c, 0x70, 0x71, 0x48, 0x4e, 0xd0, 0xec, 0x46, 0x8f, 0xdf, + 0xa2, 0x9a, 0xfe, 0xd8, 0x35, 0x1a, 0x2f, 0x02, 0x81, 0x81, 0x00, 0xcf, + 0x73, 0x8c, 0xbe, 0x6d, 0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75, + 0x78, 0xcc, 0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9, 0x64, 0x60, 0x8c, 0x43, + 0xeb, 0x85, 0xab, 0x04, 0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda, + 0x84, 0x68, 0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4, 0xde, 0x51, 0x4b, 0xb6, + 0x51, 0x86, 0x7b, 0xd0, 0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f, + 0x3a, 0x83, 0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13, 0x93, 0xd7, 0x9c, 0x27, + 0x80, 0xb7, 0x1e, 0x64, 0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8, + 0x18, 0x6c, 0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96, 0x90, 0x8f, 0xa2, 0x16, + 0x22, 0x6a, 0xcc, 0x48, 0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44, + 0x3c, 0x2d, 0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27, 0x33, 0x85, 0x26, 0x60, + 0x48, 0x16, 0xcb, 0xef, 0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce, + 0x15, 0x43, 0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87, 0xc3, 0x41, 0x45, 0x97, + 0xb1, 0x49, 0xc2, 0x19, 0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28, + 0xcb, 0x43, 0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb, 0xbb, 0xdb, 0xfd, 0x11, + 0x9d, 0x17, 0x68, 0x78, 0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3, + 0xa7, 0x5b, 0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54, 0x91, 0x99, 0xe5, 0x91, + 0x32, 0x2d, 0xeb, 0x3f, 0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41, + 0xc1, 0xee, 0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42, 0x58, 0xf4, 0xd0, 0xb2, + 0x74, 0x1d, 0x8e, 0x87, 0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd, + 0x0d, 0x6c, 0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53, 0xda, 0xfb, 0xed, 0x83, + 0x51, 0x67, 0xa9, 0x55, 0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17, + 0x53, 0xa8, 0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02, 0x81, 0x80, 0x67, 0x9c, + 0x32, 0x83, 0x39, 0x57, 0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0, + 0x0a, 0x2d, 0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97, 0xf3, 0x90, 0x9a, 0xab, + 0x9b, 0x0b, 0x1b, 0x43, 0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c, + 0xeb, 0xdb, 0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80, 0xb8, 0xe1, 0xb3, 0xa1, + 0x6c, 0x25, 0x92, 0xe4, 0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f, + 0x37, 0x43, 0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81, 0x20, 0x82, 0xa1, 0x48, + 0x2c, 0x2d, 0x45, 0xdc, 0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41, + 0xf9, 0xca, 0x58, 0xce, 0x4a, 0x66, 0x53, 0x54, 0xc8, 0x28, 0x10, 0x1e, + 0x08, 0x71, 0x16, 0xd8, 0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5, + 0xb1, 0x31, 0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf, 0x35, 0x95, 0x41, 0x29, + 0x40, 0x19, 0x83, 0x35, 0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b, + 0xcc, 0x3b, 0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae, 0x50, 0x76, 0x63, 0x94, + 0x49, 0x4c, 0xad, 0x10, 0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8, + 0x6a, 0xab, 0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b, 0x8a, 0xa2, 0xb9, 0x8f, + 0xce, 0xec, 0x5e, 0x61, 0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a, + 0x5f, 0xdf, 0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69, 0xe4, 0x8b, 0x01, 0x06, + 0x59, 0x22, 0xfa, 0x34, 0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a, + 0x77, 0xe6, 0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26, 0x6c, 0xfa, 0x2b, 0xd9, + 0x83, 0x5a, 0x2d, 0x0c, 0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a, + 0xd9, 0xbe, 0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3, 0x66, 0xff, 0x1c, 0x1b, + 0xc8, 0x96, 0x76, 0xe8, 0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8, + 0xac, 0x21, 0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80, 0x2c, 0x7c, 0xad, 0x1e, + 0x75, 0xf6, 0x69, 0x1d, 0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65, + 0x28, 0x66, 0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57, 0xae, 0xb7, 0x65, 0x2c, + 0x52, 0xf9, 0xe4, 0xc7, 0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33, + 0x70, 0xcf, 0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50, 0x75, 0x61, 0x96, 0x86, + 0x4b, 0xb6, 0x2b, 0xad, 0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35, + 0x50, 0xcb, 0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a, 0xd3, 0x29, 0x23, 0x02, + 0x60, 0xf7, 0xab, 0x30, 0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4, + 0xa2, 0x0d, 0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18, 0xf4, 0xd4, 0x52, 0x95, + 0x00, 0xae, 0x84, 0x6b, 0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde, + 0x72, 0x2c, 0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, 0x56, 0xfe, 0x39, 0x28, + 0x33, 0xe0, 0xdb, 0x03 }; -extern const size_t kOEMPrivateKeySize_Prod = 1794; -extern const uint8_t kOEMPublicCert_Prod[] = { - 0x30, 0x82, 0x09, 0xf7, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, - 0x01, 0x07, 0x02, 0xa0, 0x82, 0x09, 0xe8, 0x30, 0x82, 0x09, 0xe4, 0x02, - 0x01, 0x01, 0x31, 0x00, 0x30, 0x0f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x02, 0x04, 0x00, 0xa0, 0x82, 0x09, - 0xc8, 0x30, 0x82, 0x04, 0x1a, 0x30, 0x82, 0x03, 0x02, 0xa0, 0x03, 0x02, - 0x01, 0x02, 0x02, 0x11, 0x00, 0xf2, 0xa1, 0x08, 0xdf, 0x12, 0x84, 0xb9, - 0x73, 0x6c, 0x23, 0x73, 0xe1, 0x1f, 0xf3, 0xac, 0x7a, 0x30, 0x0d, 0x06, - 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, - 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, - 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, - 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, - 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, - 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, - 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, - 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x30, 0x30, 0x2e, - 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x27, 0x47, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x20, 0x4f, 0x45, 0x4d, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x44, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x3b, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, - 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x33, 0x34, 0x36, 0x30, 0x1e, - 0x17, 0x0d, 0x31, 0x37, 0x30, 0x33, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x32, 0x30, 0x38, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x6d, 0x31, 0x12, 0x30, 0x10, - 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x37, 0x33, 0x34, 0x36, 0x2d, - 0x6c, 0x65, 0x61, 0x66, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, - 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, - 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, - 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, - 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, - 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, - 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x30, 0x82, 0x01, - 0xa2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, - 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x8f, 0x00, 0x30, 0x82, 0x01, - 0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xf5, 0x09, 0x64, 0x4a, 0x26, 0xfe, - 0xc0, 0x98, 0x55, 0x6a, 0x1d, 0x5d, 0x1c, 0xc7, 0x38, 0xaf, 0xfd, 0x49, - 0x9e, 0x85, 0x3f, 0xd6, 0x45, 0x0e, 0x99, 0x09, 0x85, 0x69, 0x84, 0x3c, - 0xfe, 0x72, 0xa5, 0x56, 0xfa, 0x11, 0x4f, 0x6b, 0x7d, 0x32, 0x2b, 0x0c, - 0xbf, 0x8f, 0xac, 0x47, 0x96, 0x22, 0x82, 0x3d, 0xf5, 0x64, 0x74, 0x7e, - 0x62, 0x68, 0x74, 0xcd, 0x0a, 0xec, 0x84, 0xc5, 0x15, 0x06, 0x0e, 0x5a, - 0x2f, 0x20, 0xe3, 0xc9, 0x67, 0xcd, 0xdd, 0x01, 0xb8, 0xb3, 0x18, 0x87, - 0x8c, 0xa9, 0x58, 0x86, 0x0f, 0xb6, 0xc3, 0x42, 0x7e, 0x87, 0x48, 0x5e, - 0x10, 0x49, 0xc7, 0xd7, 0xb7, 0xb8, 0xa6, 0x34, 0x08, 0x0c, 0x94, 0xf4, - 0xbb, 0x2a, 0x06, 0xa4, 0x4f, 0xec, 0xbc, 0xc4, 0x37, 0xbe, 0x99, 0x10, - 0x23, 0x37, 0x24, 0xb1, 0xdf, 0xcb, 0xe6, 0x3f, 0xc1, 0xf0, 0x0f, 0x04, - 0x03, 0xc8, 0xb0, 0x1e, 0xd6, 0xb8, 0xae, 0x77, 0xe1, 0x4d, 0x6d, 0x97, - 0x69, 0x6d, 0x8a, 0x73, 0x66, 0x32, 0x57, 0x6f, 0xcf, 0xea, 0x1e, 0x7b, - 0x87, 0x03, 0x75, 0xb1, 0xef, 0x83, 0x64, 0x26, 0xf1, 0x3f, 0xbf, 0xe6, - 0x28, 0x03, 0x72, 0x57, 0xbf, 0x47, 0x29, 0x99, 0x8f, 0x74, 0x1d, 0x01, - 0x16, 0xad, 0xb2, 0xdf, 0x80, 0xa4, 0xd3, 0x8b, 0xeb, 0x61, 0xd1, 0x40, - 0x68, 0xb9, 0xa2, 0xa5, 0xef, 0x2b, 0xe5, 0x78, 0xe8, 0x28, 0x88, 0x87, - 0xb7, 0x53, 0x49, 0xbb, 0xe4, 0xea, 0x0d, 0x5e, 0x96, 0xa5, 0xdd, 0x1f, - 0x0b, 0x25, 0x8b, 0xb5, 0x95, 0x46, 0xe7, 0xba, 0xb8, 0xc4, 0x0a, 0x36, - 0xb1, 0x89, 0xeb, 0x27, 0x5d, 0xd9, 0x97, 0x24, 0x59, 0xa3, 0x9b, 0xb0, - 0x23, 0x0b, 0xd2, 0xec, 0x65, 0x91, 0xf9, 0xf0, 0xa0, 0x74, 0x5f, 0xb4, - 0xce, 0x22, 0x27, 0x18, 0x37, 0xe2, 0x4b, 0xfc, 0x91, 0xf9, 0x09, 0x15, - 0xe6, 0xdb, 0x06, 0x9b, 0x4d, 0x82, 0xdc, 0x36, 0x14, 0x48, 0xc6, 0xd5, - 0x87, 0xca, 0xec, 0x5a, 0xa2, 0x29, 0x33, 0xef, 0x22, 0x0c, 0x4b, 0xbf, - 0xe7, 0x2f, 0x95, 0xe1, 0xd3, 0xa5, 0xd8, 0xaa, 0x44, 0x77, 0x29, 0xa3, - 0x20, 0x33, 0xd2, 0x51, 0xa2, 0xf9, 0x4a, 0x6f, 0xf7, 0x3e, 0xf7, 0x0b, - 0x8a, 0xec, 0xc1, 0x99, 0x1d, 0x47, 0xf3, 0x74, 0x02, 0x04, 0xab, 0x8e, - 0x62, 0x4c, 0x9e, 0x00, 0xc2, 0x84, 0xd7, 0xd0, 0xf8, 0xe4, 0x1c, 0x9d, - 0x98, 0x15, 0xa8, 0x8f, 0x08, 0x98, 0x4e, 0x5a, 0xfa, 0xd6, 0x60, 0x87, - 0x12, 0xdc, 0x8e, 0xfd, 0xcb, 0xb3, 0x13, 0x97, 0x7a, 0xa8, 0x8c, 0x56, - 0x2e, 0x49, 0x26, 0x60, 0xe9, 0x4a, 0xdc, 0xec, 0x3f, 0xf0, 0x94, 0xcd, - 0x90, 0x8e, 0x7c, 0x21, 0x3f, 0x80, 0x14, 0x33, 0xdd, 0xb0, 0x00, 0xe2, - 0x09, 0x37, 0x06, 0xdd, 0x17, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, - 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, - 0xd6, 0x79, 0x04, 0x01, 0x01, 0x04, 0x04, 0x02, 0x02, 0x1c, 0xb2, 0x30, - 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, - 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x8e, 0x2d, 0x13, 0x1e, 0x60, - 0xaa, 0xda, 0x52, 0x53, 0x55, 0x64, 0x3a, 0xdc, 0xb6, 0x7a, 0xc0, 0xba, - 0xfa, 0xeb, 0x20, 0xab, 0xb6, 0x63, 0xcf, 0xcd, 0x9b, 0xdb, 0x71, 0xf3, - 0xa0, 0xd6, 0x91, 0xbf, 0x0c, 0xc1, 0xae, 0x8f, 0x02, 0x18, 0x00, 0x54, - 0xfb, 0x49, 0x03, 0x34, 0x8d, 0x92, 0x9d, 0x5d, 0x8d, 0xa8, 0x1c, 0x20, - 0x0f, 0x85, 0x60, 0xf9, 0xf6, 0x8b, 0xbb, 0x2b, 0x82, 0xce, 0xb3, 0xe2, - 0x91, 0xe7, 0xbd, 0x91, 0x61, 0x52, 0x36, 0x40, 0x9f, 0x2f, 0x5e, 0xa6, - 0x5d, 0x2f, 0xb3, 0x81, 0xe7, 0xf1, 0x87, 0xbe, 0xc5, 0x9d, 0x67, 0x5a, - 0xf7, 0x41, 0x1e, 0x73, 0xb0, 0x1e, 0xdc, 0x4f, 0x8d, 0x53, 0x21, 0x38, - 0x1b, 0xfd, 0x92, 0x43, 0x68, 0x83, 0x03, 0xd0, 0x9a, 0xca, 0x92, 0x14, - 0x73, 0x04, 0x94, 0x2a, 0x93, 0x22, 0x60, 0x5e, 0xee, 0xb6, 0xec, 0x0f, - 0xb0, 0xc8, 0x92, 0x97, 0xfb, 0x5d, 0xed, 0x1f, 0xa0, 0x5f, 0xe4, 0x98, - 0x2f, 0xf6, 0x13, 0x78, 0x99, 0xec, 0xb3, 0xf1, 0x0d, 0x27, 0xaa, 0x19, - 0x95, 0x39, 0xdb, 0xb0, 0x7b, 0x96, 0x74, 0x03, 0x5e, 0x51, 0xf5, 0x15, - 0x27, 0xce, 0xca, 0x0b, 0x2a, 0x0d, 0x43, 0xb3, 0x68, 0x17, 0x1e, 0x11, - 0x60, 0xd9, 0x84, 0x9b, 0xc3, 0x53, 0xce, 0xbd, 0xf4, 0x61, 0x51, 0x4b, - 0x41, 0x00, 0x7e, 0xe1, 0x5f, 0x69, 0xb3, 0x4a, 0x89, 0x7e, 0x47, 0x67, - 0xfd, 0x76, 0xf8, 0x94, 0x2f, 0x72, 0xb6, 0x14, 0x08, 0x2c, 0x16, 0x4e, - 0x9d, 0x37, 0x62, 0xbf, 0x11, 0x67, 0xc0, 0x70, 0x71, 0xec, 0x55, 0x51, - 0x4e, 0x46, 0x76, 0xb4, 0xc3, 0xeb, 0x52, 0x06, 0x17, 0x06, 0xce, 0x61, - 0x43, 0xce, 0x26, 0x80, 0x68, 0xb6, 0x2d, 0x57, 0xba, 0x8c, 0x7d, 0xb7, - 0xc5, 0x05, 0x2c, 0xf8, 0xa3, 0x69, 0xf8, 0x96, 0xad, 0xac, 0xd1, 0x30, - 0x82, 0x05, 0xa6, 0x30, 0x82, 0x03, 0x8e, 0xa0, 0x03, 0x02, 0x01, 0x02, - 0x02, 0x10, 0x73, 0xd1, 0xe1, 0x1d, 0xa9, 0x75, 0xfd, 0x0c, 0xda, 0x7f, - 0xfa, 0x43, 0x3c, 0x26, 0xbd, 0x3d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, - 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x7e, 0x31, - 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, - 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, - 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, - 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, - 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, - 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, - 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, - 0x76, 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, - 0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, - 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30, - 0x33, 0x31, 0x34, 0x30, 0x33, 0x30, 0x32, 0x34, 0x31, 0x5a, 0x17, 0x0d, - 0x32, 0x37, 0x30, 0x33, 0x31, 0x34, 0x30, 0x33, 0x30, 0x32, 0x34, 0x31, - 0x5a, 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, - 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, - 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, - 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, - 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, - 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, - 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x30, 0x30, - 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x27, 0x47, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x20, 0x4f, 0x45, 0x4d, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, - 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x3b, 0x20, 0x73, 0x79, 0x73, 0x74, - 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x33, 0x34, 0x36, 0x30, - 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, - 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa5, 0x45, 0x13, 0xf2, - 0xb2, 0xcb, 0x4b, 0x0f, 0xb4, 0x44, 0x25, 0x9c, 0x8a, 0x68, 0x54, 0xd5, - 0x45, 0x1e, 0x15, 0x89, 0x5b, 0xb8, 0xce, 0xda, 0x5a, 0x42, 0xe6, 0x9a, - 0x8c, 0xc1, 0xcb, 0xe8, 0xc5, 0xf5, 0x8f, 0x49, 0x0e, 0x02, 0xef, 0x5e, - 0x97, 0x1a, 0x91, 0xa4, 0x94, 0xc3, 0x50, 0x13, 0xe5, 0x13, 0xb7, 0x7f, - 0x26, 0x53, 0x19, 0xb0, 0x37, 0xa5, 0xef, 0xe6, 0x2a, 0x39, 0xdc, 0x93, - 0x37, 0xe2, 0x3d, 0x7f, 0xcb, 0x4b, 0x93, 0xa2, 0xc3, 0x69, 0x78, 0xc9, - 0x01, 0xfa, 0x68, 0x3b, 0xe0, 0xe2, 0x22, 0x6c, 0xeb, 0xe4, 0x8a, 0xa8, - 0x3e, 0xf5, 0x20, 0x82, 0xa8, 0x62, 0x68, 0x59, 0x78, 0x24, 0xde, 0xef, - 0x47, 0x43, 0xb1, 0x6c, 0x38, 0x29, 0xd3, 0x69, 0x3f, 0xae, 0x35, 0x57, - 0x75, 0x80, 0xc9, 0x21, 0xe7, 0x01, 0xb9, 0x54, 0x8b, 0x6e, 0x4e, 0x2e, - 0x5a, 0x5b, 0x77, 0xa4, 0x22, 0xc2, 0x7b, 0x95, 0xb9, 0x39, 0x2c, 0xbd, - 0xc2, 0x1e, 0x02, 0xa6, 0xb2, 0xbc, 0x0f, 0x7a, 0xcb, 0xdc, 0xbc, 0xbc, - 0x90, 0x66, 0xe3, 0xca, 0x46, 0x53, 0x3e, 0x98, 0xff, 0x2e, 0x78, 0x9f, - 0xd3, 0xa1, 0x12, 0x93, 0x66, 0x7d, 0xcc, 0x94, 0x6b, 0xec, 0x19, 0x0e, - 0x20, 0x45, 0x22, 0x57, 0x6d, 0x9e, 0xd0, 0x89, 0xf2, 0xa9, 0x34, 0xdc, - 0xab, 0xa5, 0x73, 0x47, 0x38, 0xe3, 0x7f, 0x98, 0x3a, 0x61, 0xae, 0x6c, - 0x4d, 0xf2, 0x31, 0x90, 0xcb, 0x83, 0xc1, 0xee, 0xb4, 0xf2, 0x9a, 0x28, - 0x5f, 0xbb, 0x7d, 0x89, 0xdf, 0xa2, 0x31, 0xb6, 0x1d, 0x39, 0x2b, 0x70, - 0xbf, 0x1e, 0xad, 0xe1, 0x74, 0x94, 0x1d, 0xf8, 0xc5, 0x1a, 0x8d, 0x13, - 0x45, 0xf0, 0x6a, 0x80, 0x0c, 0x5d, 0xbb, 0x46, 0x8a, 0x43, 0xd0, 0xff, - 0x21, 0x39, 0x57, 0x53, 0x5b, 0x51, 0xf8, 0xa2, 0x8f, 0x7f, 0x27, 0xc7, - 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x10, 0x30, 0x82, 0x01, - 0x0c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, - 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, - 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, - 0x04, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, - 0xe8, 0xe9, 0xac, 0x16, 0x5c, 0x5e, 0xb2, 0xe8, 0xeb, 0xff, 0x57, 0x27, - 0x20, 0x08, 0x72, 0x63, 0x9b, 0xe5, 0xb5, 0x16, 0x30, 0x81, 0xb2, 0x06, - 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xaa, 0x30, 0x81, 0xa7, 0x80, 0x14, - 0x04, 0x94, 0x66, 0xaa, 0xf9, 0x61, 0x89, 0xb6, 0xdb, 0xb5, 0xf7, 0x13, - 0x38, 0x3d, 0x62, 0x84, 0xb8, 0x18, 0x0a, 0x8f, 0xa1, 0x81, 0x83, 0xa4, - 0x81, 0x80, 0x30, 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, - 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, - 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, - 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, - 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, - 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, - 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, - 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, - 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, - 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x82, 0x09, - 0x00, 0xdf, 0x86, 0x05, 0x31, 0x01, 0xbe, 0x9a, 0x9a, 0x30, 0x12, 0x06, - 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x04, 0x01, 0x01, 0x04, - 0x04, 0x02, 0x02, 0x1c, 0xb2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, - 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, - 0x00, 0x25, 0xce, 0xd2, 0x02, 0x48, 0xbb, 0xbe, 0xfc, 0xb6, 0xa4, 0x87, - 0x87, 0xe0, 0x21, 0x7d, 0xfa, 0x23, 0xc3, 0x0d, 0x73, 0x8f, 0x46, 0xe7, - 0x09, 0x59, 0xda, 0x2e, 0x55, 0x59, 0xff, 0x3c, 0x1b, 0xf6, 0xf8, 0x9a, - 0xc4, 0x1c, 0xf7, 0xac, 0xca, 0xe7, 0x63, 0xf2, 0xc7, 0xd6, 0x0c, 0x2d, - 0xa6, 0xad, 0x55, 0xf4, 0x10, 0x0e, 0xa8, 0x82, 0x0f, 0x88, 0xb5, 0x44, - 0xe8, 0x8e, 0x84, 0x08, 0xf7, 0xdd, 0xe7, 0x10, 0xce, 0x71, 0x56, 0x57, - 0x3f, 0xed, 0x48, 0xee, 0xe2, 0x5d, 0x08, 0x0a, 0x58, 0xe4, 0xfe, 0xbc, - 0x8c, 0x27, 0x1a, 0x46, 0x3f, 0xd5, 0x2d, 0xdb, 0x0b, 0x71, 0x73, 0xd1, - 0x49, 0xf3, 0x5c, 0x86, 0x4d, 0x0a, 0xe1, 0xeb, 0x53, 0x21, 0x38, 0x4f, - 0xec, 0x1e, 0xc2, 0x68, 0x1f, 0x7d, 0xa6, 0x33, 0xe9, 0xa5, 0x37, 0x2a, - 0xef, 0xcd, 0x78, 0x56, 0xb3, 0x39, 0x60, 0xf4, 0xa5, 0xf9, 0x2b, 0x85, - 0xcf, 0xe6, 0x1c, 0x7c, 0x8a, 0x5d, 0xe8, 0x26, 0x02, 0xcf, 0x7a, 0x56, - 0x1f, 0xae, 0x0d, 0x71, 0x20, 0xee, 0xec, 0x3b, 0xae, 0x95, 0x25, 0x15, - 0xc8, 0xf6, 0x92, 0x5d, 0xb8, 0x9b, 0xc2, 0xb4, 0x95, 0x33, 0x13, 0x76, - 0x45, 0xbe, 0x21, 0xe2, 0x3a, 0x69, 0x66, 0xd7, 0xff, 0x22, 0x00, 0x89, - 0xc9, 0x44, 0xb6, 0x54, 0x38, 0x1f, 0x33, 0xe4, 0xda, 0x7b, 0x87, 0xf3, - 0x23, 0xed, 0xf5, 0x16, 0x08, 0xbe, 0x4b, 0xea, 0x91, 0x8f, 0x91, 0x8b, - 0x4e, 0xd1, 0x02, 0x06, 0xa2, 0x77, 0x15, 0x03, 0x46, 0x11, 0x7d, 0x5b, - 0xea, 0x7a, 0xf6, 0x86, 0x7d, 0x96, 0xb7, 0x73, 0x9b, 0x5b, 0x32, 0xc3, - 0xf8, 0x92, 0x36, 0xe3, 0xe3, 0x2f, 0xe8, 0xf1, 0x72, 0xec, 0x0d, 0x50, - 0xd4, 0x86, 0xc5, 0x62, 0x83, 0xf1, 0x2a, 0x4c, 0xd1, 0xbf, 0x76, 0x62, - 0xd4, 0x21, 0x11, 0x68, 0xb2, 0xd6, 0x8d, 0xc4, 0xf8, 0xe4, 0x70, 0x85, - 0x19, 0xa7, 0x82, 0x27, 0x2c, 0x24, 0x21, 0x7a, 0x3b, 0xad, 0x8a, 0xd3, - 0xae, 0xda, 0x78, 0x3c, 0x6c, 0xab, 0xa2, 0xaa, 0x36, 0xf0, 0x1c, 0x58, - 0xd4, 0x72, 0x5e, 0xe8, 0x8b, 0x41, 0x08, 0xf5, 0x85, 0xdd, 0xee, 0x99, - 0x12, 0xf4, 0xd6, 0x41, 0x83, 0x69, 0xe7, 0x79, 0x19, 0xa3, 0x74, 0xc4, - 0x34, 0x2a, 0x8a, 0x7e, 0x4d, 0xbb, 0x2c, 0x49, 0x19, 0xf7, 0x98, 0x98, - 0xfc, 0x81, 0xf7, 0x9b, 0x7f, 0xff, 0xd9, 0x66, 0xf4, 0x51, 0x14, 0x29, - 0x2a, 0x14, 0x1d, 0x4f, 0xbd, 0x91, 0xba, 0x6f, 0x32, 0x34, 0x3c, 0x40, - 0x28, 0x6c, 0x97, 0xf8, 0x6d, 0x38, 0xcd, 0xa3, 0x7b, 0x18, 0xc8, 0x77, - 0x58, 0x4d, 0x53, 0x30, 0x7f, 0x4d, 0x89, 0xca, 0x95, 0x6e, 0xb5, 0xb8, - 0x8e, 0xc8, 0x2d, 0x18, 0x2f, 0x52, 0x2a, 0xde, 0xac, 0x56, 0x8d, 0x8c, - 0x67, 0x14, 0xf6, 0xb9, 0xf1, 0x65, 0xd3, 0x22, 0x43, 0xa3, 0x98, 0x42, - 0x20, 0x43, 0x4c, 0xdf, 0xf2, 0xeb, 0x31, 0x8c, 0x0e, 0x53, 0x5b, 0x99, - 0x82, 0xc3, 0x48, 0x04, 0x53, 0xad, 0x96, 0xb6, 0x9f, 0x52, 0xcc, 0x01, - 0xc8, 0xb3, 0x87, 0x6b, 0x9e, 0xea, 0xa9, 0xeb, 0xda, 0xac, 0xf9, 0x6f, - 0xde, 0xa1, 0x44, 0x32, 0x52, 0x49, 0x47, 0xff, 0x65, 0x79, 0x1e, 0xc5, - 0x73, 0x17, 0xb3, 0x36, 0xfc, 0x45, 0xca, 0x90, 0x37, 0x59, 0x1e, 0x16, - 0xab, 0x09, 0x69, 0xcf, 0xda, 0x56, 0x51, 0xfd, 0xeb, 0xcf, 0xcb, 0x8f, - 0xb1, 0xc3, 0x45, 0x2b, 0x7c, 0x0a, 0xa5, 0x9c, 0x0d, 0x2c, 0xad, 0x1c, - 0xd3, 0x33, 0xdd, 0xfe, 0x93, 0x69, 0xa2, 0x4b, 0x4b, 0xcf, 0x1d, 0x20, - 0x98, 0x4a, 0x4f, 0x5b, 0xe9, 0x24, 0xca, 0xfa, 0x18, 0x11, 0x81, 0x8b, - 0x7a, 0xb4, 0x5a, 0xc8, 0xdf, 0x6f, 0x5f, 0x21, 0x07, 0x31, 0x00 +const size_t kOEMPrivateKeySize_Prod = sizeof(kOEMPrivateKey_Prod); + +// From the team shared drive file +// oem-7913-leaf-and-intermediate-certs-test-key-2-carmichael.p7b, size 2353. +const uint8_t kOEMPublicCert_Prod[] = { + 0x30, 0x82, 0x09, 0x2d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x07, 0x02, 0xa0, 0x82, 0x09, 0x1e, 0x30, 0x82, 0x09, 0x1a, 0x02, + 0x01, 0x01, 0x31, 0x00, 0x30, 0x0f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x02, 0x04, 0x00, 0xa0, 0x82, 0x08, + 0xfe, 0x30, 0x82, 0x03, 0x71, 0x30, 0x82, 0x02, 0x59, 0xa0, 0x03, 0x02, + 0x01, 0x02, 0x02, 0x11, 0x00, 0xc2, 0x8d, 0x20, 0x22, 0x82, 0x8b, 0x9e, + 0x63, 0x9d, 0x15, 0x89, 0x2c, 0xa9, 0x8f, 0xd9, 0x5d, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, + 0x30, 0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x02, 0x57, 0x41, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, + 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, + 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, + 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x73, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x39, 0x31, + 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x31, 0x31, 0x31, 0x31, + 0x33, 0x32, 0x36, 0x32, 0x32, 0x5a, 0x17, 0x0d, 0x33, 0x38, 0x30, 0x31, + 0x30, 0x36, 0x31, 0x33, 0x32, 0x36, 0x32, 0x32, 0x5a, 0x30, 0x65, 0x31, + 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x37, 0x39, + 0x31, 0x33, 0x2d, 0x6c, 0x65, 0x61, 0x66, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x57, 0x41, 0x31, 0x11, 0x30, + 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, + 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, + 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, + 0x76, 0x69, 0x6e, 0x65, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, + 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, 0x40, + 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde, 0xa7, + 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, 0x56, + 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4, 0x4e, + 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, 0x34, + 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce, 0x31, + 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, 0x3e, + 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e, 0x39, + 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, 0xf2, + 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b, 0x54, + 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, 0xb3, + 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54, 0x71, + 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, 0x96, + 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51, 0x5a, + 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, 0x4c, + 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12, 0x7f, + 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, 0xca, + 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a, 0x77, + 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, 0x27, + 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb, 0x9c, + 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, 0x2c, + 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x16, + 0x30, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, + 0x79, 0x04, 0x01, 0x01, 0x04, 0x04, 0x02, 0x02, 0x1e, 0xe9, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x88, 0x95, 0xec, 0xcd, 0x8b, 0xa7, + 0x51, 0xda, 0x74, 0x81, 0xa5, 0x39, 0x62, 0x1a, 0x0e, 0x2e, 0xde, 0x3c, + 0x37, 0xea, 0xad, 0x7c, 0xee, 0x9b, 0x26, 0x8e, 0xe2, 0xd6, 0x34, 0xcd, + 0xb7, 0x70, 0xba, 0xbf, 0xa0, 0xa3, 0xfe, 0xb3, 0x4b, 0xbc, 0xf4, 0x1c, + 0x72, 0x66, 0x81, 0xd5, 0x09, 0x33, 0x78, 0x0c, 0x61, 0x21, 0xa8, 0xf1, + 0xe2, 0xc9, 0xe2, 0x83, 0xc2, 0x19, 0x02, 0xf2, 0xe8, 0xab, 0x17, 0x36, + 0x3a, 0x0b, 0x20, 0xaf, 0x0f, 0xae, 0x2e, 0x73, 0x68, 0xac, 0x15, 0xee, + 0x9c, 0xc0, 0x92, 0x03, 0x7e, 0x95, 0x63, 0xaa, 0xad, 0x15, 0x96, 0x43, + 0x20, 0x3b, 0xe5, 0x9b, 0x1f, 0xca, 0x02, 0xba, 0xf0, 0x07, 0x76, 0x80, + 0xd7, 0xa3, 0x1a, 0xeb, 0xc8, 0xdb, 0x03, 0x7b, 0x43, 0x56, 0xe5, 0x96, + 0x6b, 0x86, 0xfe, 0x08, 0x58, 0x8a, 0x84, 0xbd, 0xe9, 0x47, 0x18, 0xee, + 0xb2, 0xa8, 0x05, 0x7b, 0xf0, 0xfd, 0xaa, 0xb9, 0x85, 0xcd, 0x7a, 0x0e, + 0x6b, 0x6c, 0x9f, 0xc6, 0x75, 0xd2, 0x2a, 0xfe, 0x5b, 0xf3, 0xb7, 0x31, + 0x6c, 0xac, 0xe3, 0x00, 0x9f, 0xe7, 0xdd, 0xe3, 0x81, 0xc1, 0x36, 0xc3, + 0x1c, 0x5f, 0xdf, 0xf2, 0xc3, 0x5e, 0xfa, 0x55, 0x32, 0xd8, 0x5c, 0xa8, + 0xe5, 0xcc, 0xb6, 0x4a, 0xe9, 0xe2, 0xcc, 0x38, 0x44, 0x07, 0x46, 0x59, + 0x34, 0x84, 0x79, 0xf9, 0xee, 0x3c, 0x4b, 0x48, 0x90, 0xab, 0x73, 0xb0, + 0xa1, 0x92, 0xc3, 0xd6, 0x83, 0x87, 0x81, 0xca, 0x12, 0x81, 0xd6, 0x5d, + 0xf7, 0x6f, 0x7a, 0x35, 0x5e, 0x4f, 0x02, 0x66, 0x8a, 0x47, 0x88, 0x82, + 0xab, 0xf0, 0x12, 0x1d, 0xb9, 0x75, 0x3b, 0x7b, 0xa8, 0x36, 0x15, 0xef, + 0xa8, 0x12, 0x0e, 0x53, 0xb4, 0x83, 0x78, 0x53, 0xc0, 0x52, 0xae, 0xa6, + 0x0a, 0xa0, 0x53, 0xdc, 0x1c, 0x15, 0x22, 0xdd, 0x17, 0x98, 0x30, 0x82, + 0x05, 0x85, 0x30, 0x82, 0x03, 0x6d, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, + 0x10, 0x03, 0xb1, 0xf7, 0x58, 0xdf, 0x1d, 0xe3, 0x25, 0x00, 0x0b, 0x10, + 0x3d, 0xd5, 0xe6, 0xe4, 0x64, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x7e, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, + 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, + 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, + 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d, + 0x70, 0x72, 0x6f, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x31, 0x31, + 0x31, 0x38, 0x30, 0x31, 0x31, 0x33, 0x33, 0x35, 0x5a, 0x17, 0x0d, 0x32, + 0x37, 0x31, 0x31, 0x31, 0x38, 0x30, 0x31, 0x31, 0x33, 0x31, 0x33, 0x5a, + 0x30, 0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x02, 0x57, 0x41, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, + 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, + 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, + 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x73, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x39, 0x31, + 0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, + 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xae, 0xc8, + 0x71, 0xae, 0x08, 0x0c, 0x06, 0x06, 0x2d, 0x81, 0x7c, 0xa9, 0x8b, 0xb3, + 0xd6, 0x66, 0xe4, 0xf6, 0x08, 0x5e, 0x5a, 0x75, 0xe8, 0x74, 0x61, 0x7a, + 0x88, 0xca, 0x85, 0x14, 0x0d, 0x58, 0xa4, 0x09, 0x19, 0x6c, 0x60, 0xc9, + 0xad, 0x91, 0x1c, 0xbf, 0x04, 0xb3, 0x47, 0x10, 0x63, 0x7f, 0x02, 0x58, + 0xc2, 0x1e, 0xbd, 0xcc, 0x07, 0x77, 0xaa, 0x7e, 0x14, 0xa8, 0xc2, 0x01, + 0xcd, 0xe8, 0x46, 0x60, 0x53, 0x6f, 0x2f, 0xda, 0x17, 0x2d, 0x4d, 0x9d, + 0x0e, 0x5d, 0xb5, 0x50, 0x95, 0xae, 0xab, 0x6e, 0x43, 0xe3, 0xb0, 0x00, + 0x12, 0xb4, 0x05, 0x82, 0x4a, 0x2b, 0x14, 0x63, 0x0d, 0x1f, 0x06, 0x12, + 0xaa, 0xe1, 0x9d, 0xe7, 0xba, 0xda, 0xe3, 0xfc, 0x7c, 0x6c, 0x73, 0xae, + 0x56, 0xf8, 0xab, 0xf7, 0x51, 0x93, 0x31, 0xef, 0x8f, 0xe4, 0xb6, 0x01, + 0x2c, 0xeb, 0x7b, 0xe4, 0xd8, 0xb3, 0xea, 0x70, 0x37, 0x89, 0x05, 0xa9, + 0x51, 0x57, 0x72, 0x98, 0x9e, 0xa8, 0x46, 0xdb, 0xeb, 0x7a, 0x38, 0x2b, + 0x2f, 0xc0, 0x27, 0xb7, 0xc2, 0xe1, 0x9a, 0x17, 0xdf, 0xf5, 0xd6, 0x9c, + 0xd5, 0x8c, 0xb8, 0x66, 0x42, 0xd5, 0x04, 0x1e, 0x7c, 0x36, 0x4c, 0x1e, + 0x3e, 0x45, 0x51, 0x4d, 0x41, 0x72, 0x22, 0x53, 0x3d, 0xf4, 0x57, 0x7c, + 0x6c, 0x33, 0x34, 0x24, 0x45, 0xdf, 0x84, 0x87, 0x4a, 0xa6, 0xcb, 0x7c, + 0x03, 0xa3, 0xaa, 0x8e, 0x2d, 0x82, 0x01, 0x27, 0x87, 0x74, 0x82, 0x1a, + 0xbc, 0x0f, 0x76, 0x69, 0xab, 0xe0, 0x4e, 0x70, 0xbe, 0x37, 0xfc, 0xc8, + 0x2c, 0x91, 0x17, 0x4f, 0xd5, 0x26, 0x3b, 0x7b, 0x90, 0xb5, 0x2d, 0x64, + 0xba, 0xf7, 0xd2, 0x8a, 0xb4, 0x8f, 0x38, 0x9d, 0x8e, 0xba, 0xe7, 0x5c, + 0x52, 0xf1, 0x0a, 0xb8, 0xc0, 0x1b, 0xb6, 0xb1, 0x70, 0x7e, 0x47, 0x59, + 0x94, 0x59, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x10, 0x30, + 0x82, 0x01, 0x0c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, + 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, + 0x02, 0x02, 0x04, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, + 0x04, 0x14, 0x4b, 0xcb, 0xdf, 0xaa, 0x02, 0xde, 0x8d, 0xc3, 0xe7, 0xe5, + 0x85, 0xdb, 0x2e, 0x8a, 0xbe, 0x75, 0x6b, 0x8a, 0x67, 0x58, 0x30, 0x81, + 0xb2, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xaa, 0x30, 0x81, 0xa7, + 0x80, 0x14, 0x04, 0x94, 0x66, 0xaa, 0xf9, 0x61, 0x89, 0xb6, 0xdb, 0xb5, + 0xf7, 0x13, 0x38, 0x3d, 0x62, 0x84, 0xb8, 0x18, 0x0a, 0x8f, 0xa1, 0x81, + 0x83, 0xa4, 0x81, 0x80, 0x30, 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, + 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, + 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, + 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, + 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, + 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69, + 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, + 0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64, + 0x82, 0x09, 0x00, 0xdf, 0x86, 0x05, 0x31, 0x01, 0xbe, 0x9a, 0x9a, 0x30, + 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x04, 0x01, + 0x01, 0x04, 0x04, 0x02, 0x02, 0x1e, 0xe9, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, + 0x02, 0x01, 0x00, 0x61, 0x3f, 0x2f, 0x43, 0xe4, 0xbe, 0x66, 0x34, 0xef, + 0x92, 0x06, 0xe9, 0x88, 0xba, 0x6a, 0x1d, 0x4f, 0x54, 0x5a, 0x97, 0xb1, + 0x75, 0xd7, 0x93, 0xf8, 0x45, 0xc6, 0x83, 0x92, 0x36, 0xfd, 0x55, 0xa9, + 0x21, 0x0b, 0xdc, 0xf6, 0xae, 0x11, 0xdc, 0x62, 0x21, 0x44, 0xbd, 0x04, + 0x1d, 0x58, 0x2c, 0x03, 0xf8, 0xe4, 0xe2, 0x1e, 0xba, 0xe6, 0xdd, 0x19, + 0xdd, 0x56, 0xfd, 0xce, 0x06, 0x73, 0x5f, 0x94, 0x1e, 0xb6, 0x03, 0xdb, + 0x3d, 0x7b, 0xab, 0xab, 0x72, 0x64, 0x7b, 0xde, 0x7d, 0x4d, 0xcf, 0x7e, + 0xf0, 0x91, 0x29, 0xc1, 0x77, 0x13, 0xc2, 0x6f, 0x80, 0xab, 0x7a, 0xa8, + 0xce, 0xb0, 0x1c, 0x2a, 0xc5, 0x9c, 0xfb, 0x0b, 0xe5, 0x9f, 0x9c, 0x1b, + 0xc9, 0x4b, 0x58, 0xdf, 0x96, 0x18, 0xf7, 0x67, 0x67, 0x89, 0xa4, 0xe9, + 0x14, 0x48, 0xac, 0xfa, 0x9d, 0x86, 0x2a, 0xeb, 0x75, 0x2c, 0x2b, 0xbf, + 0x63, 0x7d, 0xc7, 0x4e, 0x7e, 0xad, 0x39, 0x2d, 0xb4, 0x7c, 0x07, 0xa5, + 0x5a, 0xe8, 0x3a, 0xd4, 0xf5, 0x0c, 0x4f, 0xf3, 0xa2, 0x9c, 0x3c, 0x32, + 0xed, 0x9d, 0x4b, 0x49, 0x05, 0xbc, 0x1f, 0xa0, 0x13, 0xe6, 0xdd, 0x82, + 0x79, 0x06, 0x31, 0x3b, 0xc6, 0x97, 0xec, 0x8d, 0xaa, 0x4f, 0xef, 0x14, + 0x3c, 0x21, 0xf6, 0x72, 0xb2, 0x09, 0x42, 0xc7, 0x74, 0xfe, 0xef, 0x70, + 0xbd, 0xe9, 0x85, 0x41, 0x30, 0x0b, 0xb3, 0x6b, 0x59, 0x0c, 0x0f, 0x11, + 0x75, 0xd4, 0xbb, 0xb1, 0xdf, 0xb1, 0xdf, 0xb3, 0xfa, 0xb3, 0x3a, 0x43, + 0x17, 0x7d, 0x8a, 0x82, 0xae, 0xa2, 0x07, 0xf8, 0x83, 0x51, 0xfb, 0x16, + 0xfb, 0x64, 0xb6, 0x46, 0xda, 0xbe, 0x32, 0x2b, 0xc0, 0xee, 0x78, 0x2a, + 0x84, 0xa9, 0x54, 0x0a, 0xf9, 0x2d, 0x61, 0x65, 0xde, 0xa5, 0x97, 0x66, + 0x79, 0x02, 0xf8, 0x97, 0x17, 0xe2, 0xd4, 0x9f, 0x9e, 0xac, 0xcc, 0xae, + 0x99, 0x9a, 0x03, 0x04, 0xbb, 0x45, 0xfe, 0xb2, 0xf5, 0x80, 0xba, 0xbf, + 0xdd, 0x24, 0xe5, 0xe6, 0x1e, 0x5d, 0x36, 0xa5, 0x87, 0x0c, 0xdf, 0x60, + 0x81, 0x6f, 0xb7, 0x5f, 0xb9, 0x1f, 0xca, 0x75, 0x3c, 0x1a, 0x63, 0xb0, + 0xeb, 0xe6, 0x95, 0x86, 0x0d, 0xae, 0xa6, 0xc9, 0x2a, 0x94, 0xf1, 0xd0, + 0xbe, 0x75, 0xc8, 0xf8, 0x07, 0xd7, 0x88, 0xff, 0xec, 0xf9, 0xcd, 0x49, + 0xc6, 0xfe, 0x4d, 0x7f, 0x44, 0x1e, 0xd8, 0xaf, 0xa9, 0x72, 0x27, 0x98, + 0xe2, 0x5a, 0x08, 0xea, 0x55, 0xd3, 0xb3, 0xea, 0xdc, 0x76, 0x69, 0x51, + 0x10, 0x01, 0x46, 0x7d, 0x33, 0x94, 0x9c, 0x94, 0xef, 0xfe, 0x76, 0x1c, + 0xc6, 0xd7, 0x15, 0x53, 0x3e, 0x8d, 0x3d, 0x29, 0x9a, 0x58, 0x6a, 0xf1, + 0x75, 0x9e, 0xea, 0x1b, 0x4c, 0xf0, 0x47, 0x76, 0xac, 0xc6, 0xa2, 0x32, + 0x44, 0x40, 0xdf, 0xfe, 0xff, 0x9d, 0xf4, 0xe2, 0xc2, 0xfa, 0xa1, 0x5f, + 0x2e, 0x66, 0xe9, 0x97, 0xcb, 0x27, 0x26, 0x6e, 0x53, 0xe4, 0xe8, 0x86, + 0x2c, 0xea, 0xd3, 0x69, 0x6c, 0x61, 0x4f, 0xfe, 0xc1, 0xc9, 0x8b, 0x05, + 0x92, 0x6f, 0x47, 0x96, 0xce, 0xf0, 0x33, 0xfa, 0x7c, 0x78, 0x24, 0x9b, + 0xd7, 0x8d, 0x36, 0x56, 0x37, 0x86, 0xbc, 0x72, 0x5a, 0xf9, 0xb9, 0xb0, + 0x93, 0xf0, 0x81, 0x78, 0x10, 0xf2, 0xb0, 0xc2, 0x79, 0x91, 0x5e, 0xcf, + 0xbc, 0x8c, 0xf2, 0x32, 0x0f, 0xf7, 0x2d, 0x30, 0xd8, 0x13, 0x77, 0x4f, + 0x78, 0x9e, 0x40, 0x8d, 0xe6, 0x3a, 0x98, 0xb2, 0xaa, 0x13, 0x4d, 0x25, + 0x49, 0x34, 0x6c, 0x80, 0x9e, 0x19, 0x03, 0xdb, 0xcd, 0xf5, 0xb1, 0x54, + 0x74, 0x1b, 0x67, 0x3c, 0x46, 0xac, 0x3e, 0x5d, 0xa2, 0xd9, 0x13, 0x83, + 0x30, 0xeb, 0x82, 0x3b, 0x06, 0xab, 0x3c, 0x39, 0x7d, 0xd0, 0x68, 0x31, + 0x00 }; -extern const size_t kOEMPublicCertSize_Prod = 2555; + +const size_t kOEMPublicCertSize_Prod = sizeof(kOEMPublicCert_Prod); // Refer to the following in main modules. // This level of indirection is present so new OEM Certificates can be diff --git a/oemcrypto/ref/src/oemcrypto_engine_ref.cpp b/oemcrypto/ref/src/oemcrypto_engine_ref.cpp index 4f225db..66319ff 100644 --- a/oemcrypto/ref/src/oemcrypto_engine_ref.cpp +++ b/oemcrypto/ref/src/oemcrypto_engine_ref.cpp @@ -13,12 +13,14 @@ #include #include +#include #include #include "keys.h" #include "log.h" #include "oemcrypto_key_ref.h" #include "oemcrypto_rsa_key_shared.h" +#include "string_conversions.h" namespace wvoec_ref { @@ -84,6 +86,105 @@ SessionContext* CryptoEngine::FindSession(SessionId sid) { return NULL; } +time_t CryptoEngine::OnlineTime() { + // Use the monotonic clock for times that don't have to be stable across + // device boots. + timespec current_time; + int gettime_result = clock_gettime(CLOCK_MONOTONIC, ¤t_time); + if (gettime_result == 0) { + return current_time.tv_sec; + } else { + // Can't use monotonic clock, use roll back time. + return RollbackCorrectedOfflineTime(); + } +} + +time_t CryptoEngine::RollbackCorrectedOfflineTime() { + struct TimeInfo { + // The max time recorded through this function call. + time_t previous_time; + // If the wall time is rollbacked to before the previous_time, this member + // is updated to reflect the offset. + time_t rollback_offset; + // Pad the struct so that TimeInfo is a multiple of 16. + uint8_t padding[16 - (2 * sizeof(time_t)) % 16]; + }; + + std::vector encrypted_buffer(sizeof(TimeInfo)); + std::vector clear_buffer(sizeof(TimeInfo)); + TimeInfo time_info; + memset(&time_info, 0, sizeof(time_info)); + // Use the device key for encrypt/decrypt. + const std::vector& key = DeviceRootKey(); + + wvcdm::File* file; + std::string path; + // Note: this path is OK for a real implementation, but using security level 1 + // would be better. + // TODO(fredgc, jfore): Address how this property is presented to the ref. + // For now, the path is empty. + /*if (!wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3, + &path)) { + LOGE("RollbackCorrectedOfflineTime: Unable to get base path"); + }*/ + std::string filename = path + "StoredUsageTime.dat"; + + wvcdm::FileSystem* file_system = file_system_.get(); + if (file_system->Exists(filename)) { + // Load time info from previous call to this function. + file = file_system->Open(filename, wvcdm::FileSystem::kReadOnly); + if (!file) { + LOGE("RollbackCorrectedOfflineTime: File open failed: %s", + filename.c_str()); + return time(NULL); + } + file->Read(reinterpret_cast(&encrypted_buffer[0]), sizeof(TimeInfo)); + file->Close(); + // Decrypt the encrypted TimeInfo buffer. + AES_KEY aes_key; + AES_set_decrypt_key(&key[0], 128, &aes_key); + std::vector iv(wvoec::KEY_IV_SIZE, 0); + AES_cbc_encrypt(&encrypted_buffer[0], &clear_buffer[0], sizeof(TimeInfo), + &aes_key, iv.data(), AES_DECRYPT); + memcpy(&time_info, &clear_buffer[0], sizeof(TimeInfo)); + } + + time_t current_time; + // Add any time offsets in the past to the current time. + current_time = time(NULL) + time_info.rollback_offset; + if (time_info.previous_time > current_time) { + // Time has been rolled back. + // Update the rollback offset. + time_info.rollback_offset += time_info.previous_time - current_time; + // Keep current time at previous recorded time. + current_time = time_info.previous_time; + } + // The new previous_time will either stay the same or move forward. + time_info.previous_time = current_time; + + // Copy updated data and encrypt the buffer. + memcpy(&clear_buffer[0], &time_info, sizeof(TimeInfo)); + AES_KEY aes_key; + AES_set_encrypt_key(&key[0], 128, &aes_key); + std::vector iv(wvoec::KEY_IV_SIZE, 0); + AES_cbc_encrypt(&clear_buffer[0], &encrypted_buffer[0], sizeof(TimeInfo), + &aes_key, iv.data(), AES_ENCRYPT); + + // Write the encrypted buffer to disk. + file = file_system->Open( + filename, wvcdm::FileSystem::kCreate | wvcdm::FileSystem::kTruncate); + if (!file) { + LOGE("RollbackCorrectedOfflineTime: File open failed: %s", + filename.c_str()); + return time(NULL); + } + file->Write(reinterpret_cast(&encrypted_buffer[0]), sizeof(TimeInfo)); + file->Close(); + + // Return time with offset. + return current_time; +} + OEMCrypto_HDCP_Capability CryptoEngine::config_current_hdcp_capability() { return config_local_display_only() ? HDCP_NO_DIGITAL_OUTPUT : HDCP_V1; } diff --git a/oemcrypto/ref/src/oemcrypto_engine_ref.h b/oemcrypto/ref/src/oemcrypto_engine_ref.h index 60c9d09..c965edf 100644 --- a/oemcrypto/ref/src/oemcrypto_engine_ref.h +++ b/oemcrypto/ref/src/oemcrypto_engine_ref.h @@ -88,6 +88,10 @@ class CryptoEngine { return kMaxSupportedOEMCryptoSessions; } + time_t OnlineTime(); + + time_t RollbackCorrectedOfflineTime(); + // Returns the HDCP version currently in use. virtual OEMCrypto_HDCP_Capability config_current_hdcp_capability(); @@ -144,6 +148,7 @@ class CryptoEngine { virtual uint8_t config_security_patch_level() { return 0; } // If 0 no restriction, otherwise it's the max buffer for DecryptCENC. + // This is the same as the max subsample size, not the sample or frame size. virtual size_t max_buffer_size() { return 1024 * 100; } // 100 KiB. virtual bool srm_update_supported() { return false; } @@ -170,6 +175,8 @@ class CryptoEngine { // size is unlimited -- or limited only by memory size. virtual size_t max_usage_table_size() { return 0; } + virtual uint32_t resource_rating() { return 1; } + // Set destination pointer based on the output destination description. OEMCryptoResult SetDestination(OEMCrypto_DestBufferDesc* out_description, size_t data_length, uint8_t subsample_flags); diff --git a/oemcrypto/ref/src/oemcrypto_key_ref.cpp b/oemcrypto/ref/src/oemcrypto_key_ref.cpp index 557cb6f..cc08c27 100644 --- a/oemcrypto/ref/src/oemcrypto_key_ref.cpp +++ b/oemcrypto/ref/src/oemcrypto_key_ref.cpp @@ -21,7 +21,8 @@ bool KeyControlBlock::Validate() { memcmp(verification_, "kc11", 4) && // add in version 11 api memcmp(verification_, "kc12", 4) && // add in version 12 api memcmp(verification_, "kc13", 4) && // add in version 13 api - memcmp(verification_, "kc14", 4)) { // add in version 14 api + memcmp(verification_, "kc14", 4) && // add in version 14 api + memcmp(verification_, "kc15", 4)) { // add in version 15 api LOGE("KCB: BAD verification string: %4.4s", verification_); valid_ = false; } else { diff --git a/oemcrypto/ref/src/oemcrypto_old_usage_table_ref.cpp b/oemcrypto/ref/src/oemcrypto_old_usage_table_ref.cpp index 46eb8f2..93438eb 100644 --- a/oemcrypto/ref/src/oemcrypto_old_usage_table_ref.cpp +++ b/oemcrypto/ref/src/oemcrypto_old_usage_table_ref.cpp @@ -31,16 +31,21 @@ namespace wvoec_ref { -OldUsageTableEntry::OldUsageTableEntry(const std::vector &pst_hash) +OldUsageTableEntry::OldUsageTableEntry(OldUsageTable *old_usage_table, + const std::vector &pst_hash) : pst_hash_(pst_hash), - time_of_license_received_(time(NULL)), + old_usage_table_(old_usage_table), + time_of_license_received_( + old_usage_table_->ce_->RollbackCorrectedOfflineTime()), time_of_first_decrypt_(0), time_of_last_decrypt_(0), status_(kUnused) {} OldUsageTableEntry::~OldUsageTableEntry() {} -OldUsageTableEntry::OldUsageTableEntry(const OldStoredUsageEntry *buffer) { +OldUsageTableEntry::OldUsageTableEntry(OldUsageTable *old_usage_table, + const OldStoredUsageEntry *buffer) + : old_usage_table_(old_usage_table) { pst_hash_.assign(buffer->pst_hash, buffer->pst_hash + SHA256_DIGEST_LENGTH); time_of_license_received_ = buffer->time_of_license_received; time_of_first_decrypt_ = buffer->time_of_first_decrypt; @@ -95,6 +100,11 @@ OldUsageTable::OldUsageTable(CryptoEngine *ce) { // This should be encrypted and signed with a device specific key. // For the reference implementation, I'm just going to use the keybox key. const std::vector &key = ce_->DeviceRootKey(); + if (key.empty()) { + LOGE("OldUsageTable: DeviceRootKey is unexpectedly empty."); + table_.clear(); + return; + } uint8_t computed_signature[SHA256_DIGEST_LENGTH]; unsigned int sig_length = sizeof(computed_signature); @@ -152,7 +162,7 @@ OldUsageTable::OldUsageTable(CryptoEngine *ce) { // entries. for (uint64_t i = 0; i < stored_table->count; i++) { OldUsageTableEntry *entry = - new OldUsageTableEntry(&stored_table->entries[i].entry); + new OldUsageTableEntry(this, &stored_table->entries[i].entry); table_[entry->pst_hash()] = entry; } } @@ -183,7 +193,7 @@ OldUsageTableEntry *OldUsageTable::CreateEntry( LOGE("OldUsageTable: Could not compute hash of pst."); return NULL; } - OldUsageTableEntry *entry = new OldUsageTableEntry(pst_hash); + OldUsageTableEntry *entry = new OldUsageTableEntry(this, pst_hash); wvcdm::AutoLock lock(lock_); table_[pst_hash] = entry; return entry; diff --git a/oemcrypto/ref/src/oemcrypto_old_usage_table_ref.h b/oemcrypto/ref/src/oemcrypto_old_usage_table_ref.h index 5d1b7a8..1072d9e 100644 --- a/oemcrypto/ref/src/oemcrypto_old_usage_table_ref.h +++ b/oemcrypto/ref/src/oemcrypto_old_usage_table_ref.h @@ -23,6 +23,7 @@ namespace wvoec_ref { class CryptoEngine; +class OldUsageTable; class UsagetTableEntry; struct OldStoredUsageEntry { @@ -51,13 +52,16 @@ struct OldStoredUsageTable { class OldUsageTableEntry { public: - OldUsageTableEntry(const std::vector &pst_hash); - OldUsageTableEntry(const OldStoredUsageEntry *buffer); + OldUsageTableEntry(OldUsageTable *old_usage_table, + const std::vector &pst_hash); + OldUsageTableEntry(OldUsageTable *old_usage_table, + const OldStoredUsageEntry *buffer); ~OldUsageTableEntry(); const std::vector &pst_hash() const { return pst_hash_; } private: std::vector pst_hash_; + const OldUsageTable *old_usage_table_; int64_t time_of_license_received_; int64_t time_of_first_decrypt_; int64_t time_of_last_decrypt_; @@ -88,6 +92,8 @@ class OldUsageTable { wvcdm::Lock lock_; int64_t generation_; CryptoEngine *ce_; + + friend class OldUsageTableEntry; }; } // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_ref.cpp b/oemcrypto/ref/src/oemcrypto_ref.cpp index a394138..7675308 100644 --- a/oemcrypto/ref/src/oemcrypto_ref.cpp +++ b/oemcrypto/ref/src/oemcrypto_ref.cpp @@ -74,6 +74,11 @@ extern "C" OEMCryptoResult OEMCrypto_Initialize(void) { return OEMCrypto_SUCCESS; } +extern "C" OEMCryptoResult OEMCrypto_SetSandbox(const uint8_t* /*sandbox_id*/, + size_t /*sandbox_id_length*/) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + extern "C" OEMCryptoResult OEMCrypto_Terminate(void) { if (!crypto_engine) { LOGE("[OEMCrypto_Terminate(): not initialized]"); @@ -238,12 +243,21 @@ bool RangeCheck(const uint8_t* message, uint32_t message_length, return true; } +bool RangeCheck(uint32_t message_length, const OEMCrypto_Substring& substring, + bool allow_null) { + if (!substring.length) return allow_null; + if (substring.offset > message_length) return false; + if (substring.offset + substring.length > message_length) return false; + return true; +} + extern "C" OEMCryptoResult OEMCrypto_LoadKeys( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length, - const uint8_t* enc_mac_key_iv, const uint8_t* enc_mac_keys, size_t num_keys, - const OEMCrypto_KeyObject* key_array, const uint8_t* pst, size_t pst_length, - const uint8_t* srm_requirement, OEMCrypto_LicenseType license_type) { + OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys, + size_t num_keys, const OEMCrypto_KeyObject* key_array, + OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data, + OEMCrypto_LicenseType license_type) { if (!crypto_engine) { LOGE("OEMCrypto_LoadKeys: OEMCrypto Not Initialized."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -262,20 +276,12 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys( LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT]"); return OEMCrypto_ERROR_INVALID_CONTEXT; } - // Later on, we use pst_length to verify the the pst is valid. This makes - // sure that we aren't given a null string but told it has postiive length. - if (pst == NULL && pst_length > 0) { - LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_ONCTEXT - null pst.]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } // Range check - if (!RangeCheck(message, message_length, enc_mac_keys, 2 * wvoec::MAC_KEY_SIZE, - true) || - !RangeCheck(message, message_length, enc_mac_key_iv, wvoec::KEY_IV_SIZE, true) || - !RangeCheck(message, message_length, pst, pst_length, true) || - !RangeCheck(message, message_length, srm_requirement, - wvoec::SRM_REQUIREMENT_SIZE, true)) { + if (!RangeCheck(message_length, enc_mac_keys_iv, true) || + !RangeCheck(message_length, enc_mac_keys, true) || + !RangeCheck(message_length, pst, true) || + !RangeCheck(message_length, srm_restriction_data, true)) { LOGE( "[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - range " "check.]"); @@ -283,16 +289,11 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys( } for (unsigned int i = 0; i < num_keys; i++) { - if (!RangeCheck(message, message_length, key_array[i].key_id, - key_array[i].key_id_length, false) || - !RangeCheck(message, message_length, key_array[i].key_data, - key_array[i].key_data_length, false) || - !RangeCheck(message, message_length, key_array[i].key_data_iv, - wvoec::KEY_IV_SIZE, false) || - !RangeCheck(message, message_length, key_array[i].key_control, - wvoec::KEY_CONTROL_SIZE, false) || - !RangeCheck(message, message_length, key_array[i].key_control_iv, - wvoec::KEY_IV_SIZE, false)) { + if (!RangeCheck(message_length, key_array[i].key_id, false) || + !RangeCheck(message_length, key_array[i].key_data, false) || + !RangeCheck(message_length, key_array[i].key_data_iv, false) || + !RangeCheck(message_length, key_array[i].key_control, false) || + !RangeCheck(message_length, key_array[i].key_control_iv, false)) { LOGE( "[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT -range " "check %d]", @@ -301,14 +302,14 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys( } } return session_ctx->LoadKeys(message, message_length, signature, - signature_length, enc_mac_key_iv, enc_mac_keys, - num_keys, key_array, pst, pst_length, - srm_requirement, license_type); + signature_length, enc_mac_keys_iv, enc_mac_keys, + num_keys, key_array, pst, srm_restriction_data, + license_type); } extern "C" OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( - OEMCrypto_SESSION session, size_t num_keys, - const OEMCrypto_EntitledContentKeyObject* key_array) { + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + size_t num_keys, const OEMCrypto_EntitledContentKeyObject* key_array) { if (num_keys == 0) { LOGE("[OEMCrypto_LoadEntitledContentKeys(): key_array is empty."); return OEMCrypto_SUCCESS; @@ -326,8 +327,22 @@ extern "C" OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( LOGE("[OEMCrypto_LoadEntitledContentKeys(): ERROR_INVALID_SESSION]"); return OEMCrypto_ERROR_INVALID_SESSION; } + for (unsigned int i = 0; i < num_keys; i++) { + if (!RangeCheck(message_length, key_array[i].entitlement_key_id, false) || + !RangeCheck(message_length, key_array[i].content_key_id, false) || + !RangeCheck(message_length, key_array[i].content_key_data_iv, false) || + !RangeCheck(message_length, key_array[i].content_key_data, false)) { + LOGE( + "[OEMCrypto_LoadEntitledContentKeys(): " + "OEMCrypto_ERROR_INVALID_CONTEXT -range " + "check %d]", + i); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + } - return session_ctx->LoadEntitledContentKeys(num_keys, key_array); + return session_ctx->LoadEntitledContentKeys(message, message_length, num_keys, + key_array); } extern "C" OEMCryptoResult OEMCrypto_RefreshKeys( @@ -358,12 +373,9 @@ extern "C" OEMCryptoResult OEMCrypto_RefreshKeys( // Range check for (unsigned int i = 0; i < num_keys; i++) { - if (!RangeCheck(message, message_length, key_array[i].key_id, - key_array[i].key_id_length, true) || - !RangeCheck(message, message_length, key_array[i].key_control, - wvoec::KEY_CONTROL_SIZE, false) || - !RangeCheck(message, message_length, key_array[i].key_control_iv, - wvoec::KEY_IV_SIZE, true)) { + 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); return OEMCrypto_ERROR_INVALID_CONTEXT; } @@ -382,24 +394,28 @@ extern "C" OEMCryptoResult OEMCrypto_RefreshKeys( std::vector key_control; std::vector key_control_iv; for (unsigned int i = 0; i < num_keys; i++) { - if (key_array[i].key_id != NULL) { - key_id.assign(key_array[i].key_id, - key_array[i].key_id + key_array[i].key_id_length); - key_control.assign(key_array[i].key_control, - key_array[i].key_control + wvoec::KEY_CONTROL_SIZE); - if (key_array[i].key_control_iv == NULL) { + if (key_array[i].key_id.length != 0) { + key_id.assign( + message + key_array[i].key_id.offset, + message + key_array[i].key_id.offset + key_array[i].key_id.length); + key_control.assign( + message + key_array[i].key_control.offset, + message + key_array[i].key_control.offset + wvoec::KEY_CONTROL_SIZE); + if (key_array[i].key_control_iv.length == 0) { key_control_iv.clear(); } else { - key_control_iv.assign(key_array[i].key_control_iv, - key_array[i].key_control_iv + wvoec::KEY_IV_SIZE); + key_control_iv.assign( + message + key_array[i].key_control_iv.offset, + message + key_array[i].key_control_iv.offset + wvoec::KEY_IV_SIZE); } } else { // key_id could be null if special control key type // key_control is not encrypted in this case key_id.clear(); key_control_iv.clear(); - key_control.assign(key_array[i].key_control, - key_array[i].key_control + wvoec::KEY_CONTROL_SIZE); + key_control.assign( + message + key_array[i].key_control.offset, + message + key_array[i].key_control.offset + wvoec::KEY_CONTROL_SIZE); } status = session_ctx->RefreshKey(key_id, key_control, key_control_iv); @@ -522,7 +538,7 @@ extern "C" OEMCryptoResult OEMCrypto_DecryptCENC( } extern "C" OEMCryptoResult OEMCrypto_CopyBuffer( - const uint8_t* data_addr, size_t data_length, + OEMCrypto_SESSION session, const uint8_t* data_addr, size_t data_length, OEMCrypto_DestBufferDesc* out_buffer, uint8_t subsample_flags) { if (!crypto_engine) { LOGE("OEMCrypto_CopyBuffer: OEMCrypto Not Initialized."); @@ -714,6 +730,10 @@ extern "C" OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, extern "C" OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, size_t dataLength) { + if (!crypto_engine) { + LOGE("OEMCrypto_GetRandom: OEMCrypto Not Initialized."); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } if (!randomData) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -1114,7 +1134,7 @@ extern "C" OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( return OEMCrypto_SUCCESS; } -extern "C" uint32_t OEMCrypto_APIVersion() { return 14; } +extern "C" uint32_t OEMCrypto_APIVersion() { return 15; } extern "C" uint8_t OEMCrypto_Security_Patch_Level() { uint8_t security_patch_level = crypto_engine->config_security_patch_level(); @@ -1147,6 +1167,18 @@ extern "C" uint32_t OEMCrypto_GetAnalogOutputFlags() { return crypto_engine->analog_output_flags(); } +extern "C" const char* OEMCrypto_BuildInformation() { + return "OEMCrypto Ref Code " __DATE__ " " __TIME__; +} + +extern "C" uint32_t OEMCrypto_ResourceRatingTier(){ + if (!crypto_engine) { + LOGE("OEMCrypto_ResourceRatingTier: OEMCrypto Not Initialized."); + return 0; + } + return crypto_engine->resource_rating(); +} + extern "C" bool OEMCrypto_SupportsUsageTable() { if (!crypto_engine) { LOGE("OEMCrypto_SupportsUsageTable: OEMCrypto Not Initialized."); @@ -1584,4 +1616,52 @@ extern "C" OEMCryptoResult OEMCrypto_CreateOldUsageEntry( pst_length); } +extern "C" uint32_t OEMCrypto_SupportsDecryptHash() { + return OEMCrypto_CRC_Clear_Buffer; +} + +extern "C" OEMCryptoResult OEMCrypto_InitializeDecryptHash( + OEMCrypto_SESSION session) { + if (!crypto_engine) { + LOGE("OEMCrypto_InitializeDecryptHash: OEMCrypto Not Initialized."); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + SessionContext* session_ctx = crypto_engine->FindSession(session); + if (!session_ctx || !session_ctx->isValid()) { + LOGE("[OEMCrypto_InitializeDecryptHash(): ERROR_INVALID_SESSION]"); + return OEMCrypto_ERROR_INVALID_SESSION; + } + return session_ctx->InitializeDecryptHash(); +} + +extern "C" OEMCryptoResult OEMCrypto_SetDecryptHash(OEMCrypto_SESSION session, + uint32_t frame_number, + const uint8_t* hash, + size_t hash_length) { + if (!crypto_engine) { + LOGE("OEMCrypto_SetDecryptHash: OEMCrypto Not Initialized."); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + SessionContext* session_ctx = crypto_engine->FindSession(session); + if (!session_ctx || !session_ctx->isValid()) { + LOGE("[OEMCrypto_SetDecryptHash(): ERROR_INVALID_SESSION]"); + return OEMCrypto_ERROR_INVALID_SESSION; + } + return session_ctx->SetDecryptHash(frame_number, hash, hash_length); +} + +extern "C" OEMCryptoResult OEMCrypto_GetHashErrorCode( + OEMCrypto_SESSION session, uint32_t* failed_frame_number) { + if (!crypto_engine) { + LOGE("OEMCrypto_GetHashErrorCode: OEMCrypto Not Initialized."); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + SessionContext* session_ctx = crypto_engine->FindSession(session); + if (!session_ctx || !session_ctx->isValid()) { + LOGE("[OEMCrypto_GetHashErrorCode(): ERROR_INVALID_SESSION]"); + return OEMCrypto_ERROR_INVALID_SESSION; + } + return session_ctx->GetHashErrorCode(failed_frame_number); +} + } // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_session.cpp b/oemcrypto/ref/src/oemcrypto_session.cpp index b6a4350..7b1fb66 100644 --- a/oemcrypto/ref/src/oemcrypto_session.cpp +++ b/oemcrypto/ref/src/oemcrypto_session.cpp @@ -32,6 +32,7 @@ #include "oemcrypto_types.h" #include "disallow_copy_and_assign.h" #include "string_conversions.h" +#include "wvcrc32.h" static const int kPssSaltLength = 20; @@ -483,19 +484,20 @@ OEMCryptoResult SessionContext::CheckNonceOrEntry( return OEMCrypto_SUCCESS; } -void SessionContext::StartTimer() { timer_start_ = time(NULL); } +void SessionContext::StartTimer() { timer_start_ = ce_->OnlineTime(); } uint32_t SessionContext::CurrentTimer() { - time_t now = time(NULL); + time_t now = ce_->OnlineTime(); return now - timer_start_; } OEMCryptoResult SessionContext::LoadKeys( const uint8_t* message, size_t message_length, const uint8_t* signature, - size_t signature_length, const uint8_t* enc_mac_key_iv, - const uint8_t* enc_mac_keys, size_t num_keys, - const OEMCrypto_KeyObject* key_array, const uint8_t* pst, size_t pst_length, - const uint8_t* srm_requirement, OEMCrypto_LicenseType license_type) { + size_t signature_length, OEMCrypto_Substring enc_mac_keys_iv, + OEMCrypto_Substring enc_mac_keys, size_t num_keys, + const OEMCrypto_KeyObject* key_array, OEMCrypto_Substring pst, + OEMCrypto_Substring srm_restriction_data, + OEMCrypto_LicenseType license_type) { // Validate message signature if (!ValidateMessage(message, message_length, signature, signature_length)) { return OEMCrypto_ERROR_SIGNATURE_FAILURE; @@ -522,16 +524,16 @@ OEMCryptoResult SessionContext::LoadKeys( StartTimer(); - if (srm_requirement) { + if (srm_restriction_data.length != 0) { const std::string kSRMVerificationString = "HDCPDATA"; - if (memcmp(srm_requirement, kSRMVerificationString.c_str(), - kSRMVerificationString.size())) { + if (memcmp(message + srm_restriction_data.offset, + kSRMVerificationString.c_str(), kSRMVerificationString.size())) { LOGE("SRM Requirement Data has bad verification string: %8s", - srm_requirement); + message + srm_restriction_data.offset); return OEMCrypto_ERROR_INVALID_CONTEXT; } - uint32_t minimum_version = - htonl(*reinterpret_cast(srm_requirement + 8)); + uint32_t minimum_version = htonl(*reinterpret_cast( + message + srm_restriction_data.offset + 8)); uint16_t current_version = 0; if (OEMCrypto_SUCCESS != ce_->current_srm_version(¤t_version)) { LOGW("[LoadKeys: SRM Version not available."); @@ -563,20 +565,25 @@ OEMCryptoResult SessionContext::LoadKeys( std::vector key_control; std::vector key_control_iv; for (unsigned int i = 0; i < num_keys; i++) { - key_id.assign(key_array[i].key_id, - key_array[i].key_id + key_array[i].key_id_length); - enc_key_data.assign(key_array[i].key_data, - key_array[i].key_data + key_array[i].key_data_length); - key_data_iv.assign(key_array[i].key_data_iv, - key_array[i].key_data_iv + wvoec::KEY_IV_SIZE); - if (key_array[i].key_control == NULL) { + key_id.assign( + message + key_array[i].key_id.offset, + message + key_array[i].key_id.offset + key_array[i].key_id.length); + enc_key_data.assign( + message + key_array[i].key_data.offset, + message + key_array[i].key_data.offset + key_array[i].key_data.length); + key_data_iv.assign( + message + key_array[i].key_data_iv.offset, + message + key_array[i].key_data_iv.offset + wvoec::KEY_IV_SIZE); + if (key_array[i].key_control.length == 0) { status = OEMCrypto_ERROR_UNKNOWN_FAILURE; break; } - key_control.assign(key_array[i].key_control, - key_array[i].key_control + wvoec::KEY_CONTROL_SIZE); - key_control_iv.assign(key_array[i].key_control_iv, - key_array[i].key_control_iv + wvoec::KEY_IV_SIZE); + key_control.assign( + message + key_array[i].key_control.offset, + message + key_array[i].key_control.offset + wvoec::KEY_CONTROL_SIZE); + key_control_iv.assign( + message + key_array[i].key_control_iv.offset, + message + key_array[i].key_control_iv.offset + wvoec::KEY_IV_SIZE); OEMCryptoResult result = InstallKey(key_id, enc_key_data, key_data_iv, key_control, @@ -590,12 +597,14 @@ OEMCryptoResult SessionContext::LoadKeys( if (status != OEMCrypto_SUCCESS) return status; // enc_mac_key can be NULL if license renewal is not supported - if (enc_mac_keys != NULL) { + if (enc_mac_keys.length != 0) { // V2.1 license protocol: update mac keys after processing license response const std::vector enc_mac_keys_str = std::vector( - enc_mac_keys, enc_mac_keys + 2 * wvoec::MAC_KEY_SIZE); + message + enc_mac_keys.offset, + message + enc_mac_keys.offset + 2 * wvoec::MAC_KEY_SIZE); const std::vector enc_mac_key_iv_str = std::vector( - enc_mac_key_iv, enc_mac_key_iv + wvoec::KEY_IV_SIZE); + message + enc_mac_keys_iv.offset, + message + enc_mac_keys_iv.offset + wvoec::KEY_IV_SIZE); if (!UpdateMacKeys(enc_mac_keys_str, enc_mac_key_iv_str)) { LOGE("Failed to update mac keys.\n"); @@ -606,13 +615,13 @@ OEMCryptoResult SessionContext::LoadKeys( OEMCryptoResult result = OEMCrypto_SUCCESS; switch (usage_entry_status_) { case kNoUsageEntry: - if (pst_length > 0) { + if (pst.length > 0) { LOGE("LoadKeys: PST specified but no usage entry loaded."); return OEMCrypto_ERROR_INVALID_CONTEXT; } break; // no extra check. case kUsageEntryNew: - result = usage_entry_->SetPST(pst, pst_length); + result = usage_entry_->SetPST(message + pst.offset, pst.length); if (result != OEMCrypto_SUCCESS) { return result; } @@ -622,7 +631,7 @@ OEMCryptoResult SessionContext::LoadKeys( } break; case kUsageEntryLoaded: - if (!usage_entry_->VerifyPST(pst, pst_length)) { + if (!usage_entry_->VerifyPST(message + pst.offset, pst.length)) { return OEMCrypto_ERROR_WRONG_PST; } if (!usage_entry_->VerifyMacKeys(mac_key_server_, mac_key_client_)) { @@ -637,7 +646,8 @@ OEMCryptoResult SessionContext::LoadKeys( } OEMCryptoResult SessionContext::LoadEntitledContentKeys( - size_t num_keys, const OEMCrypto_EntitledContentKeyObject* key_array) { + const uint8_t* message, size_t message_length, size_t num_keys, + const OEMCrypto_EntitledContentKeyObject* key_array) { if (!key_array) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -647,9 +657,9 @@ OEMCryptoResult SessionContext::LoadEntitledContentKeys( for (size_t i = 0; i < num_keys; ++i) { const OEMCrypto_EntitledContentKeyObject* key_data = &key_array[i]; std::vector entitlement_key_id; - entitlement_key_id.assign( - key_data->entitlement_key_id, - key_data->entitlement_key_id + key_data->entitlement_key_id_length); + entitlement_key_id.assign(message + key_data->entitlement_key_id.offset, + message + key_data->entitlement_key_id.offset + + key_data->entitlement_key_id.length); const std::vector* entitlement_key = NULL; if (!session_keys_->GetEntitlementKey(entitlement_key_id, @@ -661,14 +671,14 @@ OEMCryptoResult SessionContext::LoadEntitledContentKeys( std::vector encrypted_content_key; std::vector content_key_id; - iv.assign(key_data->content_key_data_iv, - key_data->content_key_data_iv + 16); - encrypted_content_key.assign( - key_data->content_key_data, - key_data->content_key_data + key_data->content_key_data_length); - content_key_id.assign( - key_data->content_key_id, - key_data->content_key_id + key_data->content_key_id_length); + iv.assign(message + key_data->content_key_data_iv.offset, + message + key_data->content_key_data_iv.offset + 16); + encrypted_content_key.assign(message + key_data->content_key_data.offset, + message + key_data->content_key_data.offset + + key_data->content_key_data.length); + content_key_id.assign(message + key_data->content_key_id.offset, + message + key_data->content_key_id.offset + + key_data->content_key_id.length); if (!DecryptMessage(*entitlement_key, iv, encrypted_content_key, &content_key, 256 /* key size */)) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -809,7 +819,7 @@ OEMCryptoResult SessionContext::RefreshKey( if (NULL == content_key) { LOGE("Key ID not found."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; + return OEMCrypto_ERROR_NO_CONTENT_KEY; } if (key_control.empty()) { @@ -1156,8 +1166,9 @@ OEMCryptoResult SessionContext::SelectContentKey( Key* content_key = session_keys_->Find(key_id); if (NULL == content_key) { LOGE("No key matches key id"); - return OEMCrypto_KEY_NOT_LOADED; + return OEMCrypto_ERROR_NO_CONTENT_KEY; } + compute_hash_ = false; content_key->set_ctr_mode(cipher_mode == OEMCrypto_CipherMode_CTR); current_content_key_ = content_key; const KeyControlBlock& control = current_content_key()->control(); @@ -1275,6 +1286,29 @@ OEMCryptoResult SessionContext::DecryptCENC( const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data, size_t cipher_data_length, bool is_encrypted, uint8_t* clear_data, OEMCryptoBufferType buffer_type) { + OEMCryptoResult result = + ChooseDecrypt(iv, block_offset, pattern, cipher_data, cipher_data_length, + is_encrypted, clear_data, buffer_type); + if (compute_hash_) { + if (current_content_key() == NULL || + (current_content_key()->control().control_bits() & + wvoec::kControlAllowHashVerification) == 0) { + // This should not happen: this check should already have occured in + // InitializeDecryptHash or the hash should have been discarded in + // SelectContentKey. But it doesn't hurt to double check. + LOGE("[DecryptCENC(): OEMCrypto_ERROR_UNKNOWN_FAILURE]"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + current_hash_ = wvcrc32Cont(clear_data, cipher_data_length, current_hash_); + } + return result; +} + +OEMCryptoResult SessionContext::ChooseDecrypt( + const uint8_t* iv, size_t block_offset, + const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data, + size_t cipher_data_length, bool is_encrypted, uint8_t* clear_data, + OEMCryptoBufferType buffer_type) { // If the data is clear, we do not need a current key selected. if (!is_encrypted) { if (buffer_type != OEMCrypto_BufferType_Direct) { @@ -1492,4 +1526,62 @@ OEMCryptoResult SessionContext::DecryptCTR(const uint8_t* key_u8, return OEMCrypto_SUCCESS; } +OEMCryptoResult SessionContext::InitializeDecryptHash() { + // Check there is a content key, and it is allowed. + if (current_content_key() == NULL || + (current_content_key()->control().control_bits() & + wvoec::kControlAllowHashVerification) == 0) { + LOGE("[InitializeDecryptHash(): OEMCrypto_ERROR_UNKNOWN_FAILURE]"); + compute_hash_ = false; + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + compute_hash_ = true; + current_hash_ = wvcrc32Init(); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult SessionContext::SetDecryptHash(uint32_t frame_number, + const uint8_t* hash, + size_t hash_length) { + // Check there is a content key, and it is allowed. + if (current_content_key() == NULL || + (current_content_key()->control().control_bits() & + wvoec::kControlAllowHashVerification) == 0) { + LOGE("[SetDecryptHash(): OEMCrypto_ERROR_UNKNOWN_FAILURE]"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!compute_hash_) { + // This would happen if somebody computes the hash, and then changes keys. + LOGE("[SetDecryptHash(): OEMCrypto_ERROR_UNKNOWN_FAILURE]"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + compute_hash_ = false; + if (hash_length < sizeof(uint32_t)) { + LOGE("[SetDecryptHash(): short buffer]"); + return OEMCrypto_ERROR_SHORT_BUFFER; + } + if (hash_length > sizeof(uint32_t)) { + LOGE("[SetDecryptHash(): long buffer]"); + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } + uint32_t given_hash = *reinterpret_cast(hash); + if (current_hash_ != given_hash) { + LOGE("CRC for frame %d is %08x, should be %08x\n", frame_number, + current_hash_, given_hash); + // Update bad_frame_number_ only if this is the first bad frame. + if (hash_error_ == OEMCrypto_SUCCESS) bad_frame_number_ = frame_number; + hash_error_ = OEMCrypto_ERROR_BAD_HASH; + } + // Return success if the hash was compared, even if there was an error. + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult SessionContext::GetHashErrorCode( + uint32_t* failed_frame_number) { + if (failed_frame_number == NULL) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (hash_error_ != OEMCrypto_SUCCESS) + *failed_frame_number = bad_frame_number_; + return hash_error_; +} + } // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_session.h b/oemcrypto/ref/src/oemcrypto_session.h index 0ddf74e..9d65c4f 100644 --- a/oemcrypto/ref/src/oemcrypto_session.h +++ b/oemcrypto/ref/src/oemcrypto_session.h @@ -73,7 +73,11 @@ class SessionContext { allowed_schemes_(kSign_RSASSA_PSS), usage_entry_(NULL), srm_requirements_status_(NoSRMVersion), - usage_entry_status_(kNoUsageEntry) {} + usage_entry_status_(kNoUsageEntry), + compute_hash_(false), + current_hash_(0), + bad_frame_number_(0), + hash_error_(OEMCrypto_SUCCESS) {} virtual ~SessionContext(); bool isValid() { return valid_; } @@ -119,13 +123,14 @@ class SessionContext { uint32_t CurrentTimer(); // (seconds). virtual OEMCryptoResult LoadKeys( const uint8_t* message, size_t message_length, const uint8_t* signature, - size_t signature_length, const uint8_t* enc_mac_key_iv, - const uint8_t* enc_mac_keys, size_t num_keys, - const OEMCrypto_KeyObject* key_array, const uint8_t* pst, - size_t pst_length, const uint8_t* srm_requirement, + size_t signature_length, OEMCrypto_Substring enc_mac_keys_iv, + OEMCrypto_Substring enc_mac_keys, size_t num_keys, + const OEMCrypto_KeyObject* key_array, OEMCrypto_Substring pst, + OEMCrypto_Substring srm_restriction_data, OEMCrypto_LicenseType license_type); OEMCryptoResult LoadEntitledContentKeys( - size_t num_keys, const OEMCrypto_EntitledContentKeyObject* key_array); + const uint8_t* message, size_t message_length, size_t num_keys, + const OEMCrypto_EntitledContentKeyObject* key_array); virtual OEMCryptoResult InstallKey(const KeyId& key_id, const std::vector& key_data, const std::vector& key_data_iv, @@ -147,6 +152,11 @@ class SessionContext { virtual bool QueryKeyControlBlock(const KeyId& key_id, uint32_t* data); virtual OEMCryptoResult SelectContentKey(const KeyId& key_id, OEMCryptoCipherMode cipher_mode); + virtual OEMCryptoResult InitializeDecryptHash(); + virtual OEMCryptoResult SetDecryptHash(uint32_t frame_number, + const uint8_t* hash, + size_t hash_length); + virtual OEMCryptoResult GetHashErrorCode(uint32_t* failed_frame_number); const Key* current_content_key(void) { return current_content_key_; } void set_mac_key_server(const std::vector& mac_key_server) { mac_key_server_ = mac_key_server; @@ -199,6 +209,12 @@ class SessionContext { OEMCryptoResult CheckStatusOnline(uint32_t nonce, uint32_t control); // Check that the usage entry status is valid for offline use. OEMCryptoResult CheckStatusOffline(uint32_t nonce, uint32_t control); + OEMCryptoResult ChooseDecrypt(const uint8_t* iv, size_t block_offset, + const OEMCrypto_CENCEncryptPatternDesc* pattern, + const uint8_t* cipher_data, + size_t cipher_data_length, bool is_encrypted, + uint8_t* clear_data, + OEMCryptoBufferType buffer_type); OEMCryptoResult DecryptCBC(const uint8_t* key, const uint8_t* iv, const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data, @@ -238,6 +254,13 @@ class SessionContext { kUsageEntryLoaded, // After loading entry or loading keys. }; UsageEntryStatus usage_entry_status_; + + // These are used when doing full decrypt path testing. + bool compute_hash_; // True if the current frame needs a hash. + uint32_t current_hash_; // Running CRC hash of frame. + uint32_t bad_frame_number_; // Frame number with bad hash. + OEMCryptoResult hash_error_; // Error code for first bad frame. + CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext); }; diff --git a/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp b/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp index b91ed78..21eb7e0 100644 --- a/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp +++ b/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp @@ -69,16 +69,17 @@ UsageTableEntry::~UsageTableEntry() { usage_table_->ReleaseEntry(data_.index); } OEMCryptoResult UsageTableEntry::SetPST(const uint8_t* pst, size_t pst_length) { if (pst_length > kMaxPSTLength) return OEMCrypto_ERROR_BUFFER_TOO_LARGE; data_.pst_length = pst_length; - if (!pst) return OEMCrypto_ERROR_INVALID_CONTEXT; + if (!pst || !pst_length) return OEMCrypto_ERROR_INVALID_CONTEXT; memcpy(data_.pst, pst, pst_length); - data_.time_of_license_received = time(NULL); + data_.time_of_license_received = + usage_table_->ce_->RollbackCorrectedOfflineTime(); return OEMCrypto_SUCCESS; } bool UsageTableEntry::VerifyPST(const uint8_t* pst, size_t pst_length) { if (pst_length > kMaxPSTLength) return false; if (data_.pst_length != pst_length) return false; - if (!pst) return false; + if (!pst || !pst_length) return false; return 0 == memcmp(pst, data_.pst, pst_length); } @@ -105,7 +106,8 @@ bool UsageTableEntry::CheckForUse() { recent_decrypt_ = true; if (data_.status == kUnused) { data_.status = kActive; - data_.time_of_first_decrypt = time(NULL); + data_.time_of_first_decrypt = + usage_table_->ce_->RollbackCorrectedOfflineTime(); data_.generation_number++; usage_table_->IncrementGeneration(); } @@ -149,7 +151,7 @@ OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector& pst, return OEMCrypto_ERROR_INVALID_CONTEXT; } wvcdm::Unpacked_PST_Report pst_report(buffer); - int64_t now = time(NULL); + int64_t now = usage_table_->ce_->RollbackCorrectedOfflineTime(); 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); @@ -170,7 +172,8 @@ OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector& pst, void UsageTableEntry::UpdateAndIncrement() { if (recent_decrypt_) { - data_.time_of_last_decrypt = time(NULL); + data_.time_of_last_decrypt = + usage_table_->ce_->RollbackCorrectedOfflineTime(); recent_decrypt_ = false; } data_.generation_number++; @@ -197,6 +200,10 @@ OEMCryptoResult UsageTableEntry::SaveData(CryptoEngine* ce, // This should be encrypted and signed with a device specific key. // For the reference implementation, I'm just going to use the keybox key. const std::vector& key = ce->DeviceRootKey(); + if (key.empty()) { + LOGE("SaveUsageEntry: DeviceRootKey is unexpectedly empty."); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } // Encrypt the entry. RAND_bytes(encrypted->iv, wvoec::KEY_IV_SIZE); @@ -235,6 +242,10 @@ OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index, // This should be encrypted and signed with a device specific key. // For the reference implementation, I'm just going to use the keybox key. const std::vector& key = ce->DeviceRootKey(); + if (key.empty()) { + LOGE("LoadUsageEntry: DeviceRootKey is unexpectedly empty."); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } // Verify the signature of the usage entry. Sign encrypted into clear buffer. unsigned int sig_length = SHA256_DIGEST_LENGTH; @@ -494,6 +505,10 @@ OEMCryptoResult UsageTable::SaveUsageTableHeader(uint8_t* signed_buffer, // This should be encrypted and signed with a device specific key. // For the reference implementation, I'm just going to use the keybox key. const std::vector& key = ce_->DeviceRootKey(); + if (key.empty()) { + LOGE("SaveUsageTableHeader: DeviceRootKey is unexpectedly empty."); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } // Encrypt the entry. RAND_bytes(encrypted->iv, wvoec::KEY_IV_SIZE); @@ -537,6 +552,10 @@ OEMCryptoResult UsageTable::LoadUsageTableHeader( // This should be encrypted and signed with a device specific key. // For the reference implementation, I'm just going to use the keybox key. const std::vector& key = ce_->DeviceRootKey(); + if (key.empty()) { + LOGE("LoadUsageTableHeader: DeviceRootKey is unexpectedly empty."); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } // Verify the signature of the usage entry. Sign encrypted into clear buffer. unsigned int sig_length = SHA256_DIGEST_LENGTH; @@ -741,7 +760,7 @@ OEMCryptoResult UsageTable::CreateOldUsageEntry( std::vector pstv(pst, pst + pst_length); OldUsageTableEntry* old_entry = old_table_->CreateEntry(pstv); - int64_t now = time(NULL); + int64_t now = ce_->RollbackCorrectedOfflineTime(); old_entry->time_of_license_received_ = now - time_since_license_received; old_entry->time_of_first_decrypt_ = now - time_since_first_decrypt; old_entry->time_of_last_decrypt_ = now - time_since_last_decrypt; diff --git a/oemcrypto/ref/src/oemcrypto_usage_table_ref.h b/oemcrypto/ref/src/oemcrypto_usage_table_ref.h index 1e0d9a9..3278852 100644 --- a/oemcrypto/ref/src/oemcrypto_usage_table_ref.h +++ b/oemcrypto/ref/src/oemcrypto_usage_table_ref.h @@ -129,6 +129,8 @@ class UsageTable { std::vector generation_numbers_; std::vector sessions_; OldUsageTable* old_table_; + + friend class UsageTableEntry; }; } // namespace wvoec_ref diff --git a/oemcrypto/ref/src/wvcrc.cpp b/oemcrypto/ref/src/wvcrc.cpp index 3683bc1..1e88ea6 100644 --- a/oemcrypto/ref/src/wvcrc.cpp +++ b/oemcrypto/ref/src/wvcrc.cpp @@ -91,6 +91,14 @@ uint32_t wvcrc32(const uint8_t* p_begin, int i_count) { return(wvrunningcrc32(p_begin, i_count, INIT_CRC32)); } +uint32_t wvcrc32Init() { + return INIT_CRC32; +} + +uint32_t wvcrc32Cont(const uint8_t* p_begin, int i_count, uint32_t prev_crc) { + return(wvrunningcrc32(p_begin, i_count, prev_crc)); +} + uint32_t wvcrc32n(const uint8_t* p_begin, int i_count) { return htonl(wvrunningcrc32(p_begin, i_count, INIT_CRC32)); } diff --git a/oemcrypto/ref/src/wvcrc32.h b/oemcrypto/ref/src/wvcrc32.h index b81a7db..b1fde53 100644 --- a/oemcrypto/ref/src/wvcrc32.h +++ b/oemcrypto/ref/src/wvcrc32.h @@ -10,6 +10,8 @@ #include uint32_t wvcrc32(const uint8_t* p_begin, int i_count); +uint32_t wvcrc32Init(); +uint32_t wvcrc32Cont(const uint8_t* p_begin, int i_count, uint32_t prev_crc); // Convert to network byte order uint32_t wvcrc32n(const uint8_t* p_begin, int i_count); diff --git a/oemcrypto/test/oec_device_features.cpp b/oemcrypto/test/oec_device_features.cpp index 802a106..35c27e0 100644 --- a/oemcrypto/test/oec_device_features.cpp +++ b/oemcrypto/test/oec_device_features.cpp @@ -29,6 +29,7 @@ void DeviceFeatures::Initialize(bool is_cast_receiver, supports_rsa_3072 = false; api_version = 0; derive_key_method = NO_METHOD; + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); if (OEMCrypto_SUCCESS != OEMCrypto_Initialize()) { printf("OEMCrypto_Initialize failed. All tests will fail.\n"); return; @@ -94,6 +95,19 @@ void DeviceFeatures::Initialize(bool is_cast_receiver, } } printf("cast_receiver = %s.\n", cast_receiver ? "true" : "false"); + resource_rating = OEMCrypto_ResourceRatingTier(); + printf("resource_rating = %d, security leve %s.\n", resource_rating, + OEMCrypto_SecurityLevel()); + uint32_t decrypt_hash_type = OEMCrypto_SupportsDecryptHash(); + supports_crc = (decrypt_hash_type == OEMCrypto_CRC_Clear_Buffer); + if (supports_crc) { + printf("Decrypt hashes will be tested.\n"); + } else { + printf("Decrypt hashes will not be tested -- %s.\n", + decrypt_hash_type == OEMCrypto_Hash_Not_Supported + ? "not supported" + : "partner defined hash"); + } switch (derive_key_method) { case NO_METHOD: printf("NO_METHOD: Cannot derive known session keys.\n"); @@ -110,9 +124,6 @@ void DeviceFeatures::Initialize(bool is_cast_receiver, case LOAD_TEST_RSA_KEY: printf("LOAD_TEST_RSA_KEY: Call LoadTestRSAKey before deriving keys.\n"); break; - case EXISTING_TEST_KEYBOX: - printf("EXISTING_TEST_KEYBOX: Keybox is already the test keybox.\n"); - break; case FORCE_TEST_KEYBOX: printf("FORCE_TEST_KEYBOX: User requested calling InstallKeybox.\n"); break; @@ -120,6 +131,11 @@ void DeviceFeatures::Initialize(bool is_cast_receiver, printf("TEST_PROVISION_30: Device provisioed with OEM Cert.\n"); break; } + std::string security_level = OEMCrypto_SecurityLevel(); + supports_level_1 = (security_level == "L1"); + printf("SecurityLevel is %s (%s)", + supports_level_1 ? "Level 1" : "Not Level 1", + security_level.c_str()); OEMCrypto_Terminate(); } @@ -183,32 +199,12 @@ void DeviceFeatures::PickDerivedKey() { // If device uses a keybox, try to load the test keybox. if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestKeybox(NULL, 0)) { derive_key_method = LOAD_TEST_KEYBOX; - } else if (IsTestKeyboxInstalled()) { - derive_key_method = EXISTING_TEST_KEYBOX; } } else if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) { derive_key_method = LOAD_TEST_RSA_KEY; } } -bool DeviceFeatures::IsTestKeyboxInstalled() { - uint8_t key_data[256]; - size_t key_data_len = sizeof(key_data); - if (OEMCrypto_GetKeyData(key_data, &key_data_len) != OEMCrypto_SUCCESS) - return false; - if (key_data_len != sizeof(kValidKeybox01.data_)) return false; - if (memcmp(key_data, kValidKeybox01.data_, key_data_len)) return false; - uint8_t dev_id[128] = {0}; - size_t dev_id_len = 128; - if (OEMCrypto_GetDeviceID(dev_id, &dev_id_len) != OEMCrypto_SUCCESS) - return false; - // We use strncmp instead of memcmp because we don't really care about the - // multiple '\0' characters at the end of the device id. - return 0 == strncmp(reinterpret_cast(dev_id), - reinterpret_cast(kValidKeybox01.device_id_), - sizeof(kValidKeybox01.device_id_)); -} - void DeviceFeatures::FilterOut(std::string* current_filter, const std::string& new_filter) { if (current_filter->find('-') == std::string::npos) { diff --git a/oemcrypto/test/oec_device_features.h b/oemcrypto/test/oec_device_features.h index f8929d7..8c8f79f 100644 --- a/oemcrypto/test/oec_device_features.h +++ b/oemcrypto/test/oec_device_features.h @@ -14,7 +14,6 @@ class DeviceFeatures { NO_METHOD, // Cannot derive known session keys. LOAD_TEST_KEYBOX, // Call LoadTestKeybox before deriving keys. LOAD_TEST_RSA_KEY, // Call LoadTestRSAKey before deriving keys. - EXISTING_TEST_KEYBOX, // Keybox is already the test keybox. FORCE_TEST_KEYBOX, // User requested calling InstallKeybox. TEST_PROVISION_30, // Device has OEM Certificate installed. }; @@ -27,6 +26,9 @@ class DeviceFeatures { bool cast_receiver; // Device supports alternate rsa signature padding. bool usage_table; // Device saves usage information. bool supports_rsa_3072; // Device supports 3072 bit RSA keys. + bool supports_level_1; // Device supports Level 1 security. + uint32_t resource_rating; // Device's resource rating tier. + bool supports_crc; // Supported decrypt hash type CRC. uint32_t api_version; OEMCrypto_ProvisioningMethod provisioning_method; diff --git a/oemcrypto/test/oec_session_util.cpp b/oemcrypto/test/oec_session_util.cpp index 64907fb..0cc739d 100644 --- a/oemcrypto/test/oec_session_util.cpp +++ b/oemcrypto/test/oec_session_util.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "OEMCryptoCENC.h" @@ -96,6 +97,26 @@ class boringssl_ptr { CORE_DISALLOW_COPY_AND_ASSIGN(boringssl_ptr); }; +OEMCrypto_Substring GetSubstring(const std::string& message, + const std::string& field, bool set_zero) { + OEMCrypto_Substring substring; + if (set_zero || field.empty() || message.empty()) { + substring.offset = 0; + substring.length = 0; + } else { + size_t pos = message.find(field); + if (pos == std::string::npos) { + LOGW("GetSubstring : Cannot find offset for %s", field.c_str()); + substring.offset = 0; + substring.length = 0; + } else { + substring.offset = pos; + substring.length = field.length(); + } + } + return substring; +} + Session::Session() : open_(false), forced_session_id_(false), @@ -253,129 +274,149 @@ void Session::GenerateDerivedKeysFromSessionKey() { DeriveKeys(&session_key[0], mac_context, enc_context); } -void Session::LoadTestKeys(const std::string& pst, bool new_mac_keys) { - uint8_t* pst_ptr = NULL; - if (pst.length() > 0) { - pst_ptr = encrypted_license().pst; - } +void Session::LoadTestKeys(const std::string& provider_session_token, + bool new_mac_keys) { + std::string message = + wvcdm::BytesToString(message_ptr(), sizeof(MessageData)); + OEMCrypto_Substring pst = GetSubstring(message, provider_session_token); + OEMCrypto_Substring enc_mac_keys_iv = GetSubstring( + message, wvcdm::BytesToString(encrypted_license().mac_key_iv, + sizeof(encrypted_license().mac_key_iv))); + OEMCrypto_Substring enc_mac_keys = GetSubstring( + message, wvcdm::BytesToString(encrypted_license().mac_keys, + sizeof(encrypted_license().mac_keys))); if (new_mac_keys) { ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_, - &signature_[0], signature_.size(), - encrypted_license().mac_key_iv, - encrypted_license().mac_keys, num_keys_, - key_array_, pst_ptr, pst.length(), NULL, - OEMCrypto_ContentLicense)); + OEMCrypto_LoadKeys( + session_id(), message_ptr(), message_size_, &signature_[0], + signature_.size(), enc_mac_keys_iv, enc_mac_keys, num_keys_, + key_array_, pst, GetSubstring(), OEMCrypto_ContentLicense)); // Update new generated keys. memcpy(&mac_key_server_[0], license_.mac_keys, MAC_KEY_SIZE); - memcpy(&mac_key_client_[0], license_.mac_keys + MAC_KEY_SIZE, - MAC_KEY_SIZE); + memcpy(&mac_key_client_[0], license_.mac_keys + MAC_KEY_SIZE, MAC_KEY_SIZE); } else { - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_, - &signature_[0], signature_.size(), NULL, NULL, - num_keys_, key_array_, pst_ptr, pst.length(), NULL, - OEMCrypto_ContentLicense)); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_LoadKeys( + session_id(), message_ptr(), message_size_, &signature_[0], + signature_.size(), GetSubstring(), GetSubstring(), num_keys_, + key_array_, pst, GetSubstring(), OEMCrypto_ContentLicense)); } VerifyTestKeys(); } -void Session::LoadEnitlementTestKeys(const std::string& pst, - bool new_mac_keys, - OEMCryptoResult expected_sts) { - uint8_t* pst_ptr = NULL; - if (pst.length() > 0) { - pst_ptr = encrypted_license().pst; - } +void Session::LoadEntitlementTestKeys(const std::string& provider_session_token, + bool new_mac_keys, + OEMCryptoResult expected_sts) { + std::string message = + wvcdm::BytesToString(message_ptr(), sizeof(MessageData)); + OEMCrypto_Substring pst = GetSubstring(message, provider_session_token); + OEMCrypto_Substring enc_mac_keys_iv = GetSubstring( + message, wvcdm::BytesToString(encrypted_license().mac_key_iv, + sizeof(encrypted_license().mac_key_iv))); + OEMCrypto_Substring enc_mac_keys = GetSubstring( + message, wvcdm::BytesToString(encrypted_license().mac_keys, + sizeof(encrypted_license().mac_keys))); if (new_mac_keys) { - ASSERT_EQ(expected_sts, - OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_, - &signature_[0], signature_.size(), - encrypted_license().mac_key_iv, - encrypted_license().mac_keys, num_keys_, - key_array_, pst_ptr, pst.length(), NULL, - OEMCrypto_EntitlementLicense)); + ASSERT_EQ( + expected_sts, + OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_, + &signature_[0], signature_.size(), enc_mac_keys_iv, + enc_mac_keys, num_keys_, key_array_, pst, + GetSubstring(), OEMCrypto_EntitlementLicense)); // Update new generated keys. memcpy(&mac_key_server_[0], license_.mac_keys, MAC_KEY_SIZE); - memcpy(&mac_key_client_[0], license_.mac_keys + MAC_KEY_SIZE, - MAC_KEY_SIZE); + memcpy(&mac_key_client_[0], license_.mac_keys + MAC_KEY_SIZE, MAC_KEY_SIZE); } else { ASSERT_EQ( expected_sts, OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_, - &signature_[0], signature_.size(), NULL, NULL, - num_keys_, key_array_, pst_ptr, pst.length(), NULL, - OEMCrypto_EntitlementLicense)); + &signature_[0], signature_.size(), GetSubstring(), + GetSubstring(), num_keys_, key_array_, pst, + GetSubstring(), OEMCrypto_EntitlementLicense)); } } void Session::FillEntitledKeyArray() { + int offset = 0; + entitled_message_.clear(); for (size_t i = 0; i < num_keys_; ++i) { EntitledContentKeyData* key_data = &entitled_key_data_[i]; - entitled_key_array_[i].entitlement_key_id = key_array_[i].key_id; - entitled_key_array_[i].entitlement_key_id_length = - key_array_[i].key_id_length; + entitled_key_array_[i].entitlement_key_id.offset = offset; + entitled_key_array_[i].entitlement_key_id.length = + key_array_[i].key_id.length; + offset += key_array_[i].key_id.length; + entitled_message_ += + wvcdm::BytesToString(message_ptr() + key_array_[i].key_id.offset, + key_array_[i].key_id.length); - EXPECT_EQ( - 1, GetRandBytes(key_data->content_key_id, - sizeof(key_data->content_key_id))); - entitled_key_array_[i].content_key_id = key_data->content_key_id; - entitled_key_array_[i].content_key_id_length = + EXPECT_EQ(1, GetRandBytes(key_data->content_key_id, + sizeof(key_data->content_key_id))); + entitled_key_array_[i].content_key_id.offset = offset; + entitled_key_array_[i].content_key_id.length = sizeof(key_data->content_key_id); + offset += sizeof(key_data->content_key_id); + entitled_message_ += wvcdm::BytesToString(key_data->content_key_id, + sizeof(key_data->content_key_id)); - EXPECT_EQ( - 1, GetRandBytes(key_data->content_key_data, - sizeof(key_data->content_key_data))); - entitled_key_array_[i].content_key_data = key_data->content_key_data; - entitled_key_array_[i].content_key_data_length = + EXPECT_EQ(1, GetRandBytes(key_data->content_key_data, + sizeof(key_data->content_key_data))); + entitled_key_array_[i].content_key_data.offset = offset; + entitled_key_array_[i].content_key_data.length = sizeof(key_data->content_key_data); + offset += sizeof(key_data->content_key_data); + entitled_message_ += wvcdm::BytesToString( + key_data->content_key_data, sizeof(key_data->content_key_data)); - EXPECT_EQ( - 1, GetRandBytes(entitled_key_data_[i].content_key_data_iv, - sizeof(entitled_key_data_[i].content_key_data_iv))); - entitled_key_array_[i].content_key_data_iv = key_data->content_key_data_iv; + EXPECT_EQ(1, GetRandBytes(key_data[i].content_key_data_iv, + sizeof(key_data[i].content_key_data_iv))); + entitled_key_array_[i].content_key_data_iv.offset = offset; + entitled_key_array_[i].content_key_data_iv.length = + sizeof(key_data->content_key_data_iv); + offset += sizeof(key_data->content_key_data_iv); + entitled_message_ += wvcdm::BytesToString( + key_data->content_key_data_iv, sizeof(key_data->content_key_data_iv)); } } void Session::LoadEntitledContentKeys(OEMCryptoResult expected_sts) { - // Create a copy of the stored |entitled_key_array_|. + encrypted_entitled_message_ = entitled_message_; std::vector encrypted_entitled_key_array; encrypted_entitled_key_array.resize(num_keys_); memcpy(&encrypted_entitled_key_array[0], &entitled_key_array_[0], sizeof(OEMCrypto_EntitledContentKeyObject) * num_keys_); - // Create a encrypted version of all of the content keys stored in - // |entitled_key_array_|. - std::vector > encrypted_content_keys; - encrypted_content_keys.resize(num_keys_); - for (size_t i = 0; i < num_keys_; ++i) { // Load the entitlement key from |key_array_|. AES_KEY aes_key; - AES_set_encrypt_key(&key_array_[i].key_data[0], 256, &aes_key); - encrypted_content_keys[i].resize( - encrypted_entitled_key_array[i].content_key_data_length); + AES_set_encrypt_key(message_ptr() + key_array_[i].key_data.offset, 256, + &aes_key); // Encrypt the content key with the entitlement key. uint8_t iv[16]; - memcpy(&iv[0], &encrypted_entitled_key_array[i].content_key_data[0], 16); - AES_cbc_encrypt( - &entitled_key_array_[i].content_key_data[0], - const_cast( - &encrypted_entitled_key_array[i].content_key_data[0]), - encrypted_entitled_key_array[i].content_key_data_length, - &aes_key, iv, AES_ENCRYPT); - - // Set the |encrypted_entitled_key_array| to point to the encrypted copy - // of the content key. - encrypted_entitled_key_array[i].content_key_data = - encrypted_content_keys[i].data(); + const uint8_t* content_key_data = reinterpret_cast( + entitled_message_.data() + + entitled_key_array_[i].content_key_data.offset); + const uint8_t* encrypted_content_key_data = + reinterpret_cast( + encrypted_entitled_message_.data() + + encrypted_entitled_key_array[i].content_key_data.offset); + memcpy(&iv[0], + message_ptr() + + encrypted_entitled_key_array[i].content_key_data_iv.offset, + 16); + AES_cbc_encrypt(content_key_data, + const_cast(encrypted_content_key_data), + encrypted_entitled_key_array[i].content_key_data.length, + &aes_key, iv, AES_ENCRYPT); } - ASSERT_EQ(expected_sts, - OEMCrypto_LoadEntitledContentKeys( - session_id(), num_keys_, &encrypted_entitled_key_array[0])); + ASSERT_EQ( + expected_sts, + OEMCrypto_LoadEntitledContentKeys( + session_id(), + reinterpret_cast(encrypted_entitled_message_.data()), + encrypted_entitled_message_.size(), num_keys_, + &encrypted_entitled_key_array[0])); if (expected_sts != OEMCrypto_SUCCESS) { return; } @@ -408,9 +449,12 @@ void Session::VerifyEntitlementTestKeys() { for (unsigned int i = 0; i < num_keys_; i++) { KeyControlBlock block; size_t size = sizeof(block); + const uint8_t* content_key_id = + reinterpret_cast(entitled_message_.data()); OEMCryptoResult sts = OEMCrypto_QueryKeyControl( - session_id(), entitled_key_array_[i].content_key_id, - entitled_key_array_[i].content_key_id_length, + session_id(), + content_key_id + entitled_key_array_[i].content_key_id.offset, + entitled_key_array_[i].content_key_id.length, reinterpret_cast(&block), &size); if (sts != OEMCrypto_ERROR_NOT_IMPLEMENTED) { ASSERT_EQ(OEMCrypto_SUCCESS, sts); @@ -482,15 +526,12 @@ void Session::FillSimpleMessage(uint32_t duration, uint32_t control, sizeof(license_.keys[i].key_iv))); EXPECT_EQ(1, GetRandBytes(license_.keys[i].control_iv, sizeof(license_.keys[i].control_iv))); - if (global_features.api_version == 14) { - // For version 14, we require OEMCrypto to handle kc14 for all licenses. - memcpy(license_.keys[i].control.verification, "kc14", 4); - } else if (global_features.api_version == 13) { - // For version 13, we require OEMCrypto to handle kc13 for all licenses. - memcpy(license_.keys[i].control.verification, "kc13", 4); - } else if (global_features.api_version == 12) { - // For version 12, we require OEMCrypto to handle kc12 for all licenses. - memcpy(license_.keys[i].control.verification, "kc12", 4); + if (global_features.api_version >= 12) { + // For version 12 and above, we require OEMCrypto to handle kcNN for all + // licenses. + std::stringstream stream; + stream << "kc" << global_features.api_version; + memcpy(license_.keys[i].control.verification, stream.str().c_str(), 4); } else if (control & wvoec::kControlSecurityPatchLevelMask) { // For versions before 12, we require the special key control block only // when there are newer features present. @@ -529,15 +570,12 @@ void Session::FillSimpleEntitlementMessage( sizeof(license_.keys[i].key_iv))); EXPECT_EQ(1, GetRandBytes(license_.keys[i].control_iv, sizeof(license_.keys[i].control_iv))); - if (global_features.api_version == 14) { - // For version 13, we require OEMCrypto to handle kc14 for all licenses. - memcpy(license_.keys[i].control.verification, "kc14", 4); - } else if (global_features.api_version == 13) { - // For version 13, we require OEMCrypto to handle kc13 for all licenses. - memcpy(license_.keys[i].control.verification, "kc13", 4); - } else if (global_features.api_version == 12) { - // For version 12, we require OEMCrypto to handle kc12 for all licenses. - memcpy(license_.keys[i].control.verification, "kc12", 4); + if (global_features.api_version >= 12) { + // For version 12 and above, we require OEMCrypto to handle kcNN for all + // licenses. + std::stringstream stream; + stream << "kc" << global_features.api_version; + memcpy(license_.keys[i].control.verification, stream.str().c_str(), 4); } else if (control & wvoec::kControlSecurityPatchLevelMask) { // For versions before 12, we require the special key control block only // when there are newer features present. @@ -565,15 +603,13 @@ void Session::FillRefreshMessage(size_t key_count, uint32_t control_bits, encrypted_license().keys[i].key_id_length = license_.keys[i].key_id_length; memcpy(encrypted_license().keys[i].key_id, license_.keys[i].key_id, encrypted_license().keys[i].key_id_length); - if (global_features.api_version == 14) { - // For version 14, we require OEMCrypto to handle kc14 for all licenses. - memcpy(encrypted_license().keys[i].control.verification, "kc14", 4); - } else if (global_features.api_version == 13) { - // For version 13, we require OEMCrypto to handle kc13 for all licenses. - memcpy(encrypted_license().keys[i].control.verification, "kc13", 4); - } else if (global_features.api_version == 12) { - // For version 12, we require OEMCrypto to handle kc12 for all licenses. - memcpy(encrypted_license().keys[i].control.verification, "kc12", 4); + if (global_features.api_version >= 12) { + // For version 12 and above, we require OEMCrypto to handle kcNN for all + // licenses. + std::stringstream stream; + stream << "kc" << global_features.api_version; + memcpy(encrypted_license().keys[i].control.verification, + stream.str().c_str(), 4); } else { // For versions before 12, we require the special key control block only // when there are newer features present. @@ -585,6 +621,27 @@ void Session::FillRefreshMessage(size_t key_count, uint32_t control_bits, } } +void Session::SetLoadKeysSubstringParams() { + load_keys_params_.resize(4); + std::string message = + wvcdm::BytesToString(message_ptr(), sizeof(MessageData)); + OEMCrypto_Substring* enc_mac_keys_iv = &load_keys_params_[0]; + *enc_mac_keys_iv = GetSubstring( + message, wvcdm::BytesToString(encrypted_license().mac_key_iv, + sizeof(encrypted_license().mac_key_iv))); + OEMCrypto_Substring* enc_mac_keys = &load_keys_params_[1]; + *enc_mac_keys = GetSubstring( + message, wvcdm::BytesToString(encrypted_license().mac_keys, + sizeof(encrypted_license().mac_keys))); + OEMCrypto_Substring* pst = &load_keys_params_[2]; + size_t pst_length = + strlen(reinterpret_cast(encrypted_license().pst)); + *pst = GetSubstring( + message, wvcdm::BytesToString(encrypted_license().pst, pst_length)); + OEMCrypto_Substring* srm_req = &load_keys_params_[3]; + *srm_req = GetSubstring(); +} + void Session::EncryptAndSign() { encrypted_license() = license_; @@ -613,6 +670,7 @@ void Session::EncryptAndSign() { ServerSignBuffer(reinterpret_cast(&padded_message_), message_size_, &signature_); FillKeyArray(encrypted_license(), key_array_); + SetLoadKeysSubstringParams(); } void Session::EncryptProvisioningMessage( @@ -671,31 +729,45 @@ void Session::VerifyClientSignature(size_t data_length) { void Session::FillKeyArray(const MessageData& data, OEMCrypto_KeyObject* key_array) { + const uint8_t* data_ptr = reinterpret_cast(&data); + std::string message = wvcdm::BytesToString(data_ptr, sizeof(MessageData)); for (unsigned int i = 0; i < num_keys_; i++) { - key_array[i].key_id = data.keys[i].key_id; - key_array[i].key_id_length = data.keys[i].key_id_length; - key_array[i].key_data_iv = data.keys[i].key_iv; - key_array[i].key_data = data.keys[i].key_data; - key_array[i].key_data_length = data.keys[i].key_data_length; - key_array[i].key_control_iv = data.keys[i].control_iv; - key_array[i].key_control = + key_array[i].key_id = GetSubstring( + message, + wvcdm::BytesToString(data.keys[i].key_id, data.keys[i].key_id_length)); + key_array[i].key_data_iv = GetSubstring( + message, + wvcdm::BytesToString(data.keys[i].key_iv, sizeof(data.keys[i].key_iv))); + key_array[i].key_data = GetSubstring( + message, wvcdm::BytesToString(data.keys[i].key_data, + data.keys[i].key_data_length)); + key_array[i].key_control_iv = GetSubstring( + message, wvcdm::BytesToString(data.keys[i].control_iv, + sizeof(data.keys[i].control_iv))); + const uint8_t* key_control_ptr = reinterpret_cast(&data.keys[i].control); + key_array[i].key_control = GetSubstring( + message, + wvcdm::BytesToString(key_control_ptr, sizeof(data.keys[i].control))); } } void Session::FillRefreshArray(OEMCrypto_KeyRefreshObject* key_array, size_t key_count) { + std::string message = + wvcdm::BytesToString(message_ptr(), sizeof(MessageData)); for (size_t i = 0; i < key_count; i++) { - if (key_count > 1) { - key_array[i].key_id = encrypted_license().keys[i].key_id; - key_array[i].key_id_length = encrypted_license().keys[i].key_id_length; - } else { - key_array[i].key_id = NULL; - key_array[i].key_id_length = 0; - } - key_array[i].key_control_iv = NULL; - key_array[i].key_control = - reinterpret_cast(&encrypted_license().keys[i].control); + key_array[i].key_id = GetSubstring( + message, + wvcdm::BytesToString(encrypted_license().keys[i].key_id, + sizeof(encrypted_license().keys[i].key_id)), + key_count <= 1); + key_array[i].key_control_iv = GetSubstring(); + key_array[i].key_control = GetSubstring( + message, + wvcdm::BytesToString(reinterpret_cast( + &encrypted_license().keys[i].control), + sizeof(encrypted_license().keys[i].control))); } } @@ -1297,4 +1369,8 @@ void Session::set_message_size(size_t size) { ASSERT_LE(message_size_, kMaxMessageSize); } +const uint8_t* Session::encrypted_entitled_message_ptr() { + return reinterpret_cast(encrypted_entitled_message_.data()); +} + } // namespace wvoec diff --git a/oemcrypto/test/oec_session_util.h b/oemcrypto/test/oec_session_util.h index 05645cd..885ce2a 100644 --- a/oemcrypto/test/oec_session_util.h +++ b/oemcrypto/test/oec_session_util.h @@ -27,6 +27,7 @@ void PrintTo(const vector& value, ostream* os); namespace wvoec { +// Make sure this is larger than kMaxKeysPerSession, in oemcrypto_test.cpp const size_t kMaxNumKeys = 20; namespace { @@ -61,7 +62,6 @@ const int kDefaultKeyIdLength = 16; const size_t kMaxTestRSAKeyLength = 2000; // Rough estimate. const size_t kMaxPSTLength = 255; // In specification. const size_t kMaxMessageSize = 8 * 1024; // In specification. -const size_t kMaxDecryptSize = 100 * 1024; // In specification. typedef struct { uint8_t key_id[kTestKeyIdMaxLength]; @@ -125,6 +125,13 @@ uint32_t htonl_fnc(uint32_t x); // Prints error string from BoringSSL void dump_boringssl_error(); +// Given a message and field, returns an OEMCrypto_Substring with the field's +// offset into the message and its length. If |set_zero| is true, both the +// offset and length will be zero. +OEMCrypto_Substring GetSubstring(const std::string& message = "", + const std::string& field = "", + bool set_zero = false); + class Session { public: Session(); @@ -165,12 +172,12 @@ class Session { // using OEMCrypto_LoadKeys. This message should have already been created // by FillSimpleEntitlementMessage, modified if needed, and then encrypted // and signed by the server's mac key in EncryptAndSign. - void LoadEnitlementTestKeys(const std::string& pst = "", + void LoadEntitlementTestKeys(const std::string& pst = "", bool new_mac_keys = true, OEMCryptoResult expected_sts = OEMCrypto_SUCCESS); // Fills an OEMCrypto_EntitledContentKeyObject using the information from // the license_ and randomly generated content keys. This method should be - // called after LoadEnitlementTestKeys. + // called after LoadEntitlementTestKeys. void FillEntitledKeyArray(); // Encrypts and loads the entitled content keys via // OEMCrypto_LoadEntitledContentKeys. @@ -196,7 +203,7 @@ class Session { const std::string& pst = ""); // This fills the data structure license_ with entitlement key information. // This data can be modified, and then should be encrypted and signed in - // EncryptAndSign before being loaded in LoadEnitlementTestKeys. + // EncryptAndSign before being loaded in LoadEntitlementTestKeys. void FillSimpleEntitlementMessage( uint32_t duration, uint32_t control, uint32_t nonce, const std::string& pst = ""); @@ -205,6 +212,11 @@ class Session { // is just signed. The signature is computed in RefreshTestKeys, above. void FillRefreshMessage(size_t key_count, uint32_t control_bits, uint32_t nonce); + // Sets the OEMCrypto_Substring parameters of the LoadKeys method. + // Specifically, it sets the |enc_mac_keys_iv|, |enc_mac_keys|, |pst|, and + // |srm_restriction_data| in that order. For testing purposes, + // |srm_restriction_data| will always be NULL. + void SetLoadKeysSubstringParams(); // This copies data from license_ to encrypted_license_, and then encrypts // each field in the key array appropriately. It then signes the buffer with // the server mac keys. It then fills out the key_array_ so that pointers in @@ -364,6 +376,12 @@ class Session { // An array of key objects for use in LoadKeys. OEMCrypto_KeyObject* key_array() { return key_array_; } + + // An array of key objects for LoadEntitledContentKeys. + OEMCrypto_EntitledContentKeyObject* entitled_key_array() { + return entitled_key_array_; + } + // The last signature generated with the server's mac key. std::vector& signature() { return signature_; } @@ -380,6 +398,19 @@ class Session { // The size of the encrypted message. size_t message_size() { return message_size_; } + // The OEMCrypto_Substrings associated with the encrypted license that are + // passed to LoadKeys. + vector load_keys_params() { return load_keys_params_; } + OEMCrypto_Substring enc_mac_keys_iv_substr() { return load_keys_params_[0]; } + OEMCrypto_Substring enc_mac_keys_substr() { return load_keys_params_[1]; } + OEMCrypto_Substring pst_substr() { return load_keys_params_[2]; } + OEMCrypto_Substring srm_restriction_data_substr() { + return load_keys_params_[3]; + } + + // Pointer to buffer holding |encrypted_entitled_message_| + const uint8_t* encrypted_entitled_message_ptr(); + private: // Generate mac and enc keys give the master key. void DeriveKeys(const uint8_t* master_key, @@ -404,6 +435,7 @@ class Session { } padded_message_; size_t message_size_; // How much of the padded message to use. OEMCrypto_KeyObject key_array_[kMaxNumKeys]; + vector load_keys_params_; std::vector signature_; unsigned int num_keys_; vector encrypted_usage_entry_; @@ -413,8 +445,11 @@ class Session { // Clear Entitlement key data. This is the backing data for // |entitled_key_array_|. EntitledContentKeyData entitled_key_data_[kMaxNumKeys]; + // Message containing data from |key_array| and |entitled_key_data_|. + std::string entitled_message_; // Entitled key object. Pointers are backed by |entitled_key_data_|. OEMCrypto_EntitledContentKeyObject entitled_key_array_[kMaxNumKeys]; + std::string encrypted_entitled_message_; }; } // namespace wvoec diff --git a/oemcrypto/test/oec_test_data.h b/oemcrypto/test/oec_test_data.h index b6e7c34..390e81a 100644 --- a/oemcrypto/test/oec_test_data.h +++ b/oemcrypto/test/oec_test_data.h @@ -15,48 +15,10 @@ namespace wvoec { -// These are test keyboxes. They will not be accepted by production systems. -// By using known keyboxes for these tests, the results for a given set of -// inputs to a test are predictable and can be compared to the actual results. -// The first keybox, kTestKeybox, with deviceID "TestKey01" is used for most of -// the tests. It should be loaded by OEMCrypto when OEMCrypto_LoadTestKeybox -// is called. -static const wvoec::WidevineKeybox kTestKeybox = { - // Sample keybox used for test vectors - { - // deviceID = WidevineTestOnlyKeybox000 - 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, - 0x54, 0x65, 0x73, 0x74, 0x4f, 0x6e, 0x6c, 0x79, - 0x4b, 0x65, 0x79, 0x62, 0x6f, 0x78, 0x30, 0x30, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, { - // key - 0xe4, 0xff, 0x57, 0x4c, 0x32, 0x2e, 0xf5, 0x34, - 0x26, 0x21, 0x2c, 0xb3, 0xed, 0x37, 0xf3, 0x5e, - }, { - // data (system ID 7912). - 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x1e, 0xe8, - 0xca, 0x1e, 0x71, 0x7c, 0xfb, 0xe8, 0xa3, 0x94, - 0x52, 0x0a, 0x6b, 0x71, 0x37, 0xd2, 0x69, 0xfa, - 0x5a, 0xc6, 0xb5, 0x4c, 0x6b, 0x46, 0x63, 0x9b, - 0xbe, 0x80, 0x3d, 0xbb, 0x4f, 0xf7, 0x4c, 0x5f, - 0x6f, 0x55, 0x0e, 0x3d, 0x3d, 0x9a, 0xcf, 0x81, - 0x12, 0x5d, 0x52, 0xe0, 0x47, 0x8c, 0xda, 0x0b, - 0xf4, 0x31, 0x41, 0x13, 0xd0, 0xd5, 0x2d, 0xa0, - 0x5b, 0x20, 0x9a, 0xed, 0x51, 0x5d, 0x13, 0xd6, - }, { - // magic - 0x6b, 0x62, 0x6f, 0x78, - }, { - // Crc - 0x39, 0xf2, 0x94, 0xa7, - } -}; - -// These are old test keyboxes. The first keybox can be used to update an -// older OEMCrypto because it is the same keybox that was previously used in -// unit tests. -static const wvoec::WidevineKeybox kValidKeybox01 = { +// TODO(fredgc, b/119316243): REMOVE THIS KEYBOX! +// This test keybox is used for testing with OEMCrypto v13. +// It should be removed before release! +static const WidevineKeybox kTestKeyboxForV13 = { // Sample keybox used for test vectors { // deviceID @@ -88,67 +50,38 @@ static const wvoec::WidevineKeybox kValidKeybox01 = { } }; -static const wvoec::WidevineKeybox kValidKeybox02 = { +// This is a test keybox. They will not be accepted by production systems. +// By using known keyboxes for these tests, the results for a given set of +// inputs to a test are predictable and can be compared to the actual results. +static const WidevineKeybox kTestKeybox = { // Sample keybox used for test vectors { - // deviceID - 0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x30, // TestKey02 - 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ + // deviceID = WidevineTestOnlyKeybox000 + 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, + 0x54, 0x65, 0x73, 0x74, 0x4f, 0x6e, 0x6c, 0x79, + 0x4b, 0x65, 0x79, 0x62, 0x6f, 0x78, 0x30, 0x30, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, { // key - 0x76, 0x5d, 0xce, 0x01, 0x04, 0x89, 0xb3, 0xd0, - 0xdf, 0xce, 0x54, 0x8a, 0x49, 0xda, 0xdc, 0xb6, + 0xe4, 0xff, 0x57, 0x4c, 0x32, 0x2e, 0xf5, 0x34, + 0x26, 0x21, 0x2c, 0xb3, 0xed, 0x37, 0xf3, 0x5e, }, { - // data - 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x19, - 0x92, 0x27, 0x0b, 0x1f, 0x1a, 0xd5, 0xc6, 0x93, - 0x19, 0x3f, 0xaa, 0x74, 0x1f, 0xdd, 0x5f, 0xb4, - 0xe9, 0x40, 0x2f, 0x34, 0xa4, 0x92, 0xf4, 0xae, - 0x9a, 0x52, 0x39, 0xbc, 0xb7, 0x24, 0x38, 0x13, - 0xab, 0xf4, 0x92, 0x96, 0xc4, 0x81, 0x60, 0x33, - 0xd8, 0xb8, 0x09, 0xc7, 0x55, 0x0e, 0x12, 0xfa, - 0xa8, 0x98, 0x62, 0x8a, 0xec, 0xea, 0x74, 0x8a, - 0x4b, 0xfa, 0x5a, 0x9e, 0xb6, 0x49, 0x0d, 0x80, + // data (system ID 7912 = 1EE8). + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x1e, 0xe8, + 0xca, 0x1e, 0x71, 0x7c, 0xfb, 0xe8, 0xa3, 0x94, + 0x52, 0x0a, 0x6b, 0x71, 0x37, 0xd2, 0x69, 0xfa, + 0x5a, 0xc6, 0xb5, 0x4c, 0x6b, 0x46, 0x63, 0x9b, + 0xbe, 0x80, 0x3d, 0xbb, 0x4f, 0xf7, 0x4c, 0x5f, + 0x6f, 0x55, 0x0e, 0x3d, 0x3d, 0x9a, 0xcf, 0x81, + 0x12, 0x5d, 0x52, 0xe0, 0x47, 0x8c, 0xda, 0x0b, + 0xf4, 0x31, 0x41, 0x13, 0xd0, 0xd5, 0x2d, 0xa0, + 0x5b, 0x20, 0x9a, 0xed, 0x51, 0x5d, 0x13, 0xd6, }, { // magic 0x6b, 0x62, 0x6f, 0x78, }, { // Crc - 0x2a, 0x3b, 0x3e, 0xe4, - } -}; - -static const wvoec::WidevineKeybox kValidKeybox03 = { - // Sample keybox used for test vectors - { - // deviceID - 0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x30, // TestKey03 - 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ - }, { - // key - 0x25, 0xe5, 0x2a, 0x02, 0x29, 0x68, 0x04, 0xa2, - 0x92, 0xfd, 0x7c, 0x67, 0x0b, 0x67, 0x1f, 0x31, - }, { - // data - 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x19, - 0xf4, 0x0a, 0x0e, 0xa2, 0x0a, 0x71, 0xd5, 0x92, - 0xfa, 0xa3, 0x25, 0xc6, 0x4b, 0x76, 0xf1, 0x64, - 0xf4, 0x60, 0xa0, 0x30, 0x72, 0x23, 0xbe, 0x03, - 0xcd, 0xde, 0x7a, 0x06, 0xd4, 0x01, 0xeb, 0xdc, - 0xe0, 0x50, 0xc0, 0x53, 0x0a, 0x50, 0xb0, 0x37, - 0xe5, 0x05, 0x25, 0x0e, 0xa4, 0xc8, 0x5a, 0xff, - 0x46, 0x6e, 0xa5, 0x31, 0xf3, 0xdd, 0x94, 0xb7, - 0xe0, 0xd3, 0xf9, 0x04, 0xb2, 0x54, 0xb1, 0x64, - }, { - // magic - 0x6b, 0x62, 0x6f, 0x78, - }, { - // Crc - 0xa1, 0x99, 0x5f, 0x46, + 0x39, 0xf2, 0x94, 0xa7, } }; @@ -783,6 +716,8 @@ static const uint8_t kTestKeyRSAEuler_2048[] = { 0x33, 0xe0, 0xdb, 0x03, }; +static const uint8_t kTestSandbox[] = { 0x01, 0x02, 0x03 }; + } // namespace wvoec #endif // CDM_OEC_TEST_DATA_H_ diff --git a/oemcrypto/test/oemcrypto_session_tests_helper.cpp b/oemcrypto/test/oemcrypto_session_tests_helper.cpp index d016362..ffc67fb 100644 --- a/oemcrypto/test/oemcrypto_session_tests_helper.cpp +++ b/oemcrypto/test/oemcrypto_session_tests_helper.cpp @@ -103,11 +103,8 @@ void SessionUtil::EnsureTestKeys() { switch (global_features.derive_key_method) { case DeviceFeatures::LOAD_TEST_KEYBOX: keybox_ = kTestKeybox; - /* Note: If you are upgrading from an older version, it may be easier to - * force the following condition. This uses the same test keybox as we - * used in older versions of this test. - */ - if (global_features.api_version < 14) keybox_ = kValidKeybox01; + // TODO(fredgc, b/119316243): REMOVE FOLLOWING LINE: + if (global_features.api_version < 14) keybox_ = kTestKeyboxForV13; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestKeybox( reinterpret_cast(&keybox_), @@ -116,10 +113,6 @@ void SessionUtil::EnsureTestKeys() { case DeviceFeatures::LOAD_TEST_RSA_KEY: ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestRSAKey()); break; - case DeviceFeatures::EXISTING_TEST_KEYBOX: - // already has old test keybox. - keybox_ = kValidKeybox01; - break; case DeviceFeatures::FORCE_TEST_KEYBOX: keybox_ = kTestKeybox; InstallKeybox(keybox_, true); diff --git a/oemcrypto/test/oemcrypto_test.cpp b/oemcrypto/test/oemcrypto_test.cpp index 6d20450..e3fdb12 100644 --- a/oemcrypto/test/oemcrypto_test.cpp +++ b/oemcrypto/test/oemcrypto_test.cpp @@ -36,6 +36,7 @@ #include "oemcrypto_session_tests_helper.h" #include "oemcrypto_types.h" #include "string_conversions.h" +#include "wvcrc32.h" using ::testing::Bool; using ::testing::Combine; @@ -58,15 +59,33 @@ void PrintTo(const tuple +T GetResourceValue(T (&resource_values)[N]) { + if (global_features.resource_rating < 1) return resource_values[0]; + if (global_features.resource_rating > N) return resource_values[N-1]; + return resource_values[global_features.resource_rating-1]; +} +const size_t kMaxSampleSize[] = { 1000*KiB, 2*MiB, 4*MiB}; +const size_t kMaxNumberSubsamples[] = { 10, 16, 32}; +const size_t kMaxSubsampleSize[] = { 100*KiB, 500*KiB, 1*MiB}; +const size_t kMaxGenericBuffer[] = { 10*KiB, 100*KiB, 500*KiB}; +const size_t kMaxConcurrentSession[] = { 10, 20, 20}; +const size_t kMaxKeysPerSession [] = { 4, 20, 20}; +// Note: Frame rate and simultaneous playback are specified by resource rating, +// but are tested at the system level, so there are no unit tests for frame +// rate. + int GetRandBytes(unsigned char* buf, int num) { // returns 1 on success, -1 if not supported, or 0 if other failure. return RAND_bytes(buf, num); } } // namespace -namespace wvoec { - class OEMCryptoClientTest : public ::testing::Test, public SessionUtil { protected: OEMCryptoClientTest() {} @@ -77,6 +96,7 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name()); + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); } @@ -112,8 +132,20 @@ TEST_F(OEMCryptoClientTest, VersionNumber) { } else { cout << " OEMCrypto does not support usage tables." << endl; } + if (version >= 15) { + const char* build_info = OEMCrypto_BuildInformation(); + ASSERT_TRUE(build_info != NULL); + ASSERT_TRUE(strnlen(build_info, 256) <= 256) + << "BuildInformation should be a short printable string."; + cout << " BuildInformation: " << build_info << endl; + } ASSERT_GE(version, 8u); - ASSERT_LE(version, 14u); + ASSERT_LE(version, 15u); +} + +TEST_F(OEMCryptoClientTest, ResourceRatingAPI15) { + ASSERT_GE(OEMCrypto_ResourceRatingTier(), 1u); + ASSERT_LE(OEMCrypto_ResourceRatingTier(), 3u); } TEST_F(OEMCryptoClientTest, ProvisioningDeclaredAPI12) { @@ -136,6 +168,8 @@ const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value) { return "HDCP version 2.1"; case HDCP_V2_2: return "HDCP version 2.2"; + case HDCP_V2_3: + return "HDCP version 2.3"; case HDCP_NO_DIGITAL_OUTPUT: return "No HDCP device attached/using local display with secure path"; default: @@ -183,6 +217,8 @@ TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) { OEMCryptoResult sts = OEMCrypto_GetMaxNumberOfSessions(&maximum); ASSERT_EQ(OEMCrypto_SUCCESS, sts); printf(" Max Number of Sessions: %zu.\n", maximum); + size_t required_max = GetResourceValue(kMaxConcurrentSession); + ASSERT_GE(maximum, required_max); } // @@ -191,6 +227,7 @@ TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) { TEST_F(OEMCryptoClientTest, NormalInitTermination) { // Should be able to terminate OEMCrypto, and then restart it. ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Terminate()); + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); } @@ -231,13 +268,13 @@ TEST_F(OEMCryptoClientTest, MaxSessionsOpenCloseAPI10) { ASSERT_EQ(0u, sessions_count); size_t max_sessions; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GetMaxNumberOfSessions(&max_sessions)); - // We expect OEMCrypto implementations support at least 10 sessions. - const size_t kMinimumSupportedMaxNumberOfSessions = 10u; - ASSERT_GE(max_sessions, kMinimumSupportedMaxNumberOfSessions); + // We expect OEMCrypto implementations support at least this many sessions. + size_t required_number = GetResourceValue(kMaxConcurrentSession); + ASSERT_GE(max_sessions, required_number); // We allow GetMaxNumberOfSessions to return an estimate. This tests with a // pad of 5%. Even if it's just an estimate, we still require 8 sessions. size_t max_sessions_with_pad = - max(max_sessions * 19 / 20, kMinimumSupportedMaxNumberOfSessions); + max(max_sessions * 19 / 20, required_number); vector sessions; // Limit the number of sessions for testing. const size_t kMaxNumberOfSessionsForTesting = 0x100u; @@ -391,6 +428,8 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood3API09) { } TEST_F(OEMCryptoClientTest, ClearCopyTestAPI10) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); const int kDataSize = 256; vector input_buffer(kDataSize); GetRandBytes(&input_buffer[0], input_buffer.size()); @@ -401,41 +440,48 @@ TEST_F(OEMCryptoClientTest, ClearCopyTestAPI10) { dest_buffer.buffer.clear.max_length = output_buffer.size(); ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_CopyBuffer(&input_buffer[0], input_buffer.size(), &dest_buffer, + OEMCrypto_CopyBuffer(s.session_id(), &input_buffer[0], + input_buffer.size(), &dest_buffer, OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); ASSERT_EQ(input_buffer, output_buffer); - ASSERT_EQ( - OEMCrypto_ERROR_INVALID_CONTEXT, - OEMCrypto_CopyBuffer(NULL, input_buffer.size(), &dest_buffer, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); - ASSERT_EQ( - OEMCrypto_ERROR_INVALID_CONTEXT, - OEMCrypto_CopyBuffer(&input_buffer[0], input_buffer.size(), NULL, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + OEMCrypto_CopyBuffer( + s.session_id(), NULL, input_buffer.size(), &dest_buffer, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + OEMCrypto_CopyBuffer( + s.session_id(), &input_buffer[0], input_buffer.size(), NULL, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); dest_buffer.buffer.clear.address = NULL; ASSERT_EQ( OEMCrypto_ERROR_INVALID_CONTEXT, - OEMCrypto_CopyBuffer(&input_buffer[0], input_buffer.size(), &dest_buffer, + OEMCrypto_CopyBuffer(s.session_id(), &input_buffer[0], + input_buffer.size(), &dest_buffer, OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); dest_buffer.buffer.clear.address = &output_buffer[0]; dest_buffer.buffer.clear.max_length = output_buffer.size() - 1; ASSERT_EQ( OEMCrypto_ERROR_SHORT_BUFFER, - OEMCrypto_CopyBuffer(&input_buffer[0], input_buffer.size(), &dest_buffer, + OEMCrypto_CopyBuffer(s.session_id(), &input_buffer[0], + input_buffer.size(), &dest_buffer, OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); } -TEST_F(OEMCryptoClientTest, ClearCopyTestLargeBufferAPI10) { - vector input_buffer(kMaxDecryptSize); +TEST_F(OEMCryptoClientTest, ClearCopyTestLargeSubsample) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + size_t max_size = GetResourceValue(kMaxSubsampleSize); + vector input_buffer(max_size); GetRandBytes(&input_buffer[0], input_buffer.size()); - vector output_buffer(kMaxDecryptSize); + vector output_buffer(max_size); OEMCrypto_DestBufferDesc dest_buffer; dest_buffer.type = OEMCrypto_BufferType_Clear; dest_buffer.buffer.clear.address = &output_buffer[0]; dest_buffer.buffer.clear.max_length = output_buffer.size(); ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_CopyBuffer(&input_buffer[0], input_buffer.size(), &dest_buffer, + OEMCrypto_CopyBuffer(s.session_id(), &input_buffer[0], + input_buffer.size(), &dest_buffer, OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); ASSERT_EQ(input_buffer, output_buffer); } @@ -693,23 +739,18 @@ TEST_F(OEMCryptoSessionTestKeyboxTest, GoodForceKeybox) { ASSERT_EQ(DeviceFeatures::FORCE_TEST_KEYBOX, global_features.derive_key_method) << "ForceKeybox tests will modify the installed keybox."; - wvoec::WidevineKeybox keybox = kValidKeybox02; + wvoec::WidevineKeybox keybox = kTestKeybox; OEMCryptoResult sts; InstallKeybox(keybox, true); sts = OEMCrypto_IsKeyboxValid(); ASSERT_EQ(OEMCrypto_SUCCESS, sts); - - keybox = kValidKeybox03; - InstallKeybox(keybox, true); - sts = OEMCrypto_IsKeyboxValid(); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); } TEST_F(OEMCryptoSessionTestKeyboxTest, BadCRCForceKeybox) { ASSERT_EQ(DeviceFeatures::FORCE_TEST_KEYBOX, global_features.derive_key_method) << "ForceKeybox tests will modify the installed keybox."; - wvoec::WidevineKeybox keybox = kValidKeybox02; + wvoec::WidevineKeybox keybox = kTestKeybox; keybox.crc_[1] ^= 42; OEMCryptoResult sts; InstallKeybox(keybox, false); @@ -721,7 +762,7 @@ TEST_F(OEMCryptoSessionTestKeyboxTest, BadMagicForceKeybox) { ASSERT_EQ(DeviceFeatures::FORCE_TEST_KEYBOX, global_features.derive_key_method) << "ForceKeybox tests will modify the installed keybox."; - wvoec::WidevineKeybox keybox = kValidKeybox02; + wvoec::WidevineKeybox keybox = kTestKeybox; keybox.magic_[1] ^= 42; OEMCryptoResult sts; InstallKeybox(keybox, false); @@ -733,7 +774,7 @@ TEST_F(OEMCryptoSessionTestKeyboxTest, BadDataForceKeybox) { ASSERT_EQ(DeviceFeatures::FORCE_TEST_KEYBOX, global_features.derive_key_method) << "ForceKeybox tests will modify the installed keybox."; - wvoec::WidevineKeybox keybox = kValidKeybox02; + wvoec::WidevineKeybox keybox = kTestKeybox; keybox.data_[1] ^= 42; OEMCryptoResult sts; InstallKeybox(keybox, false); @@ -848,7 +889,7 @@ TEST_F(OEMCryptoSessionTests, LoadEntitlementKeysAPI14) { ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleEntitlementMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); - ASSERT_NO_FATAL_FAILURE(s.LoadEnitlementTestKeys()); + ASSERT_NO_FATAL_FAILURE(s.LoadEntitlementTestKeys()); s.FillEntitledKeyArray(); ASSERT_NO_FATAL_FAILURE(s.LoadEntitledContentKeys()); s.FillEntitledKeyArray(); @@ -861,10 +902,27 @@ TEST_F(OEMCryptoSessionTests, LoadEntitlementKeysNoEntitlementKeysAPI14) { ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleEntitlementMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); + // We do NOT call LoadEntitlementTestKeys. s.FillEntitledKeyArray(); s.LoadEntitledContentKeys(OEMCrypto_ERROR_INVALID_CONTEXT); } +TEST_F(OEMCryptoSessionTests, LoadEntitlementKeysWrongEntitlementKeysAPI14) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); + ASSERT_NO_FATAL_FAILURE(s.FillSimpleEntitlementMessage(0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); + ASSERT_NO_FATAL_FAILURE(s.LoadEntitlementTestKeys()); + s.FillEntitledKeyArray(); + const std::string key_id = "no_key"; + memcpy(const_cast(s.encrypted_entitled_message_ptr()) + + s.entitled_key_array()[0].entitlement_key_id.offset, + reinterpret_cast(key_id.c_str()), key_id.length()); + s.entitled_key_array()[0].entitlement_key_id.length = key_id.length(); + s.LoadEntitledContentKeys(OEMCrypto_KEY_NOT_ENTITLED); +} + // This tests GenerateSignature with an 8k licnese request. TEST_F(OEMCryptoSessionTests, ClientSignatureLargeBuffer) { Session s; @@ -907,6 +965,15 @@ TEST_F(OEMCryptoSessionTests, LoadKeyLargeBuffer) { ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); } +// Returns a string containing two times the original message in continuous +// memory. Used as part of the BadRange tests. +std::string DuplicateMessage(MessageData& message) { + std::string single_message = wvcdm::BytesToString( + reinterpret_cast(&message), sizeof(message)); + std::string double_message = single_message + single_message; + return double_message; +} + /* The Bad Range tests verify that OEMCrypto_LoadKeys checks the range of all the pointers. It should reject a message if the pointer does not point into the message buffer */ @@ -916,15 +983,17 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange1) { ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); - vector mac_keys( - s.encrypted_license().mac_keys, - s.encrypted_license().mac_keys + sizeof(s.encrypted_license().mac_keys)); + std::string double_message = DuplicateMessage(s.encrypted_license()); + OEMCrypto_Substring wrong_mac_keys = s.enc_mac_keys_substr(); + wrong_mac_keys.offset += s.message_size(); OEMCryptoResult sts = OEMCrypto_LoadKeys( - s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - &mac_keys[0], // Not pointing into buffer. - s.num_keys(), s.key_array(), NULL, 0, NULL, OEMCrypto_ContentLicense); + s.session_id(), reinterpret_cast(double_message.data()), + s.message_size(), &s.signature()[0], s.signature().size(), + s.enc_mac_keys_iv_substr(), + wrong_mac_keys, // Not within range of one message. + s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(), + OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -934,17 +1003,16 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange2) { ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); - vector mac_key_iv(s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_key_iv + - sizeof(s.encrypted_license().mac_key_iv)); + std::string double_message = DuplicateMessage(s.encrypted_license()); + OEMCrypto_Substring wrong_mac_keys_iv = s.enc_mac_keys_iv_substr(); + wrong_mac_keys_iv.offset += s.message_size(); - OEMCryptoResult sts = - OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(), - &s.signature()[0], s.signature().size(), - &mac_key_iv[0], // bad. - s.encrypted_license().mac_keys, s.num_keys(), - s.key_array(), NULL, 0, NULL, - OEMCrypto_ContentLicense); + OEMCryptoResult sts = OEMCrypto_LoadKeys( + s.session_id(), reinterpret_cast(double_message.data()), + s.message_size(), &s.signature()[0], s.signature().size(), + wrong_mac_keys_iv, // bad. + s.enc_mac_keys_substr(), s.num_keys(), s.key_array(), GetSubstring(), + GetSubstring(), OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -954,16 +1022,14 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange3) { ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); - vector bad_buffer(s.encrypted_license().keys[0].key_id, - s.encrypted_license().keys[0].key_id + - s.encrypted_license().keys[0].key_id_length); - s.key_array()[0].key_id = &bad_buffer[0]; + std::string double_message = DuplicateMessage(s.encrypted_license()); + s.key_array()[0].key_id.offset += s.message_size(); OEMCryptoResult sts = OEMCrypto_LoadKeys( - s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL, OEMCrypto_ContentLicense); + s.session_id(), reinterpret_cast(double_message.data()), + s.message_size(), &s.signature()[0], s.signature().size(), + s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), s.num_keys(), + s.key_array(), GetSubstring(), GetSubstring(), OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -974,16 +1040,14 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange4) { ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); - vector bad_buffer( - s.encrypted_license().keys[1].key_data, - s.encrypted_license().keys[1].key_data + wvoec::KEY_SIZE); - s.key_array()[1].key_data = &bad_buffer[0]; + std::string double_message = DuplicateMessage(s.encrypted_license()); + s.key_array()[1].key_data.offset += s.message_size(); OEMCryptoResult sts = OEMCrypto_LoadKeys( - s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL, OEMCrypto_ContentLicense); + s.session_id(), reinterpret_cast(double_message.data()), + s.message_size(), &s.signature()[0], s.signature().size(), + s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), s.num_keys(), + s.key_array(), GetSubstring(), GetSubstring(), OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -993,15 +1057,13 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange5) { ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); - vector bad_buffer(s.encrypted_license().keys[1].key_iv, - s.encrypted_license().keys[1].key_iv + - sizeof(s.encrypted_license().keys[1].key_iv)); - s.key_array()[1].key_data_iv = &bad_buffer[0]; + std::string double_message = DuplicateMessage(s.encrypted_license()); + s.key_array()[1].key_data_iv.offset += s.message_size(); OEMCryptoResult sts = OEMCrypto_LoadKeys( - s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL, OEMCrypto_ContentLicense); + s.session_id(), reinterpret_cast(double_message.data()), + s.message_size(), &s.signature()[0], s.signature().size(), + s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), s.num_keys(), + s.key_array(), GetSubstring(), GetSubstring(), OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -1012,16 +1074,14 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange6) { ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); - vector bad_buffer(s.key_array()[2].key_control, - s.key_array()[2].key_control + - sizeof(s.encrypted_license().keys[1].control)); - s.key_array()[2].key_control = &bad_buffer[0]; + std::string double_message = DuplicateMessage(s.encrypted_license()); + s.key_array()[2].key_control.offset += s.message_size(); OEMCryptoResult sts = OEMCrypto_LoadKeys( - s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL, OEMCrypto_ContentLicense); + s.session_id(), reinterpret_cast(double_message.data()), + s.message_size(), &s.signature()[0], s.signature().size(), + s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), s.num_keys(), + s.key_array(), GetSubstring(), GetSubstring(), OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -1031,17 +1091,48 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange7) { ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); - vector bad_buffer( - s.key_array()[2].key_control_iv, - s.key_array()[2].key_control_iv + - sizeof(s.encrypted_license().keys[1].control_iv)); - s.key_array()[2].key_control_iv = &bad_buffer[0]; + std::string double_message = DuplicateMessage(s.encrypted_license()); + s.key_array()[2].key_control_iv.offset += s.message_size(); + + OEMCryptoResult sts = OEMCrypto_LoadKeys( + s.session_id(), reinterpret_cast(double_message.data()), + s.message_size(), &s.signature()[0], s.signature().size(), + s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), s.num_keys(), + s.key_array(), GetSubstring(), GetSubstring(), OEMCrypto_ContentLicense); + ASSERT_NE(OEMCrypto_SUCCESS, sts); +} + +TEST_F(OEMCryptoSessionTests, LoadKeyWithNullKeyControl) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); + ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); + s.key_array()[2].key_control.offset = 0; + s.key_array()[2].key_control.length = 0; OEMCryptoResult sts = OEMCrypto_LoadKeys( s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL, OEMCrypto_ContentLicense); + s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(), + OEMCrypto_ContentLicense); + ASSERT_NE(OEMCrypto_SUCCESS, sts); +} + +TEST_F(OEMCryptoSessionTests, LoadKeyWithNullKeyControlIv) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); + ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); + s.key_array()[2].key_control_iv.offset = 0; + s.key_array()[2].key_control_iv.length = 0; + + OEMCryptoResult sts = OEMCrypto_LoadKeys( + s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], + s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(), + OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -1049,15 +1140,14 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadNonce) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); - ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, - wvoec::kControlNonceEnabled, + ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, wvoec::kControlNonceEnabled, 42)); // bad nonce. ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); OEMCryptoResult sts = OEMCrypto_LoadKeys( s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL, OEMCrypto_ContentLicense); + s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(), + OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -1075,15 +1165,14 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithRepeatNonce) { ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); - ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, - wvoec::kControlNonceEnabled, + ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, wvoec::kControlNonceEnabled, nonce)); // same old nonce. ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); OEMCryptoResult sts = OEMCrypto_LoadKeys( s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL, OEMCrypto_ContentLicense); + s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(), + OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -1107,9 +1196,9 @@ TEST_F(OEMCryptoSessionTests, LoadKeyNonceReopenSession) { ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); OEMCryptoResult sts = OEMCrypto_LoadKeys( s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL, OEMCrypto_ContentLicense); + s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(), + OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -1132,9 +1221,9 @@ TEST_F(OEMCryptoSessionTests, LoadKeyNonceWrongSession) { ASSERT_NO_FATAL_FAILURE(s2.EncryptAndSign()); OEMCryptoResult sts = OEMCrypto_LoadKeys( s2.session_id(), s2.message_ptr(), s2.message_size(), &s2.signature()[0], - s2.signature().size(), s2.encrypted_license().mac_key_iv, - s2.encrypted_license().mac_keys, s2.num_keys(), s2.key_array(), NULL, 0, - NULL, OEMCrypto_ContentLicense); + s2.signature().size(), s2.enc_mac_keys_iv_substr(), + s2.enc_mac_keys_substr(), s2.num_keys(), s2.key_array(), GetSubstring(), + GetSubstring(), OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -1148,9 +1237,9 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadVerification) { ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); OEMCryptoResult sts = OEMCrypto_LoadKeys( s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL, OEMCrypto_ContentLicense); + s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(), + OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -1184,9 +1273,9 @@ TEST_P(SessionTestAlternateVerification, LoadKeys) { ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); OEMCryptoResult sts = OEMCrypto_LoadKeys( s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL, OEMCrypto_ContentLicense); + s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(), + OEMCrypto_ContentLicense); // If this is a future API, then LoadKeys should fail. if (global_features.api_version < target_api_) { ASSERT_NE(OEMCrypto_SUCCESS, sts); @@ -1201,7 +1290,7 @@ TEST_P(SessionTestAlternateVerification, LoadKeys) { // the current API + 2. We use +2 because we want to test at least 1 // future API, and the ::testing::Range is not inclusive. INSTANTIATE_TEST_CASE_P(TestAll, SessionTestAlternateVerification, - Range(8, 14 + 2)); + Range(8, 15 + 2)); TEST_F(OEMCryptoSessionTests, LoadKeysBadSignature) { Session s; @@ -1212,9 +1301,9 @@ TEST_F(OEMCryptoSessionTests, LoadKeysBadSignature) { s.signature()[0] ^= 42; // Bad signature. OEMCryptoResult sts = OEMCrypto_LoadKeys( s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL, OEMCrypto_ContentLicense); + s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(), + OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -1226,9 +1315,9 @@ TEST_F(OEMCryptoSessionTests, LoadKeysWithNoDerivedKeys) { ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); OEMCryptoResult sts = OEMCrypto_LoadKeys( s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL, OEMCrypto_ContentLicense); + s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(), + OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -1241,12 +1330,12 @@ TEST_F(OEMCryptoSessionTests, LoadKeyNoKeys) { ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(kDuration, 0, 42)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); int kNoKeys = 0; - ASSERT_NE( - OEMCrypto_SUCCESS, - OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(), - &s.signature()[0], s.signature().size(), NULL, NULL, - kNoKeys, s.key_array(), NULL, 0, NULL, - OEMCrypto_ContentLicense)); + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_LoadKeys( + s.session_id(), s.message_ptr(), s.message_size(), + &s.signature()[0], s.signature().size(), GetSubstring(), + GetSubstring(), kNoKeys, s.key_array(), GetSubstring(), + GetSubstring(), OEMCrypto_ContentLicense)); } TEST_F(OEMCryptoSessionTests, LoadKeyNoKeyWithNonce) { @@ -1257,12 +1346,27 @@ TEST_F(OEMCryptoSessionTests, LoadKeyNoKeyWithNonce) { s.FillSimpleMessage(0, wvoec::kControlNonceEnabled, s.get_nonce())); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); int kNoKeys = 0; - ASSERT_NE( - OEMCrypto_SUCCESS, - OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(), - &s.signature()[0], s.signature().size(), NULL, NULL, - kNoKeys, s.key_array(), NULL, 0, NULL, - OEMCrypto_ContentLicense)); + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_LoadKeys( + s.session_id(), s.message_ptr(), s.message_size(), + &s.signature()[0], s.signature().size(), GetSubstring(), + GetSubstring(), kNoKeys, s.key_array(), GetSubstring(), + GetSubstring(), OEMCrypto_ContentLicense)); +} + +TEST_F(OEMCryptoSessionTests, SelectKeyNotThereAPI15) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); + ASSERT_NO_FATAL_FAILURE( + s.FillSimpleMessage(0, wvoec::kControlNonceEnabled, s.get_nonce())); + ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); + ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); + const char* key_id = "no_key"; + ASSERT_EQ(OEMCrypto_ERROR_NO_CONTENT_KEY, + OEMCrypto_SelectKey( + s.session_id(), reinterpret_cast(key_id), + strlen(key_id), OEMCrypto_CipherMode_CTR)); } TEST_F(OEMCryptoSessionTests, QueryKeyControl) { @@ -1286,7 +1390,7 @@ TEST_F(OEMCryptoSessionTests, QueryKeyControl) { ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); const char* key_id = "no_key"; size = sizeof(block); - ASSERT_NE(OEMCrypto_SUCCESS, + ASSERT_EQ(OEMCrypto_ERROR_NO_CONTENT_KEY, OEMCrypto_QueryKeyControl( s.session_id(), reinterpret_cast(key_id), strlen(key_id), reinterpret_cast(&block), &size)); @@ -1301,9 +1405,9 @@ TEST_F(OEMCryptoSessionTests, AntiRollbackHardwareRequired) { ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); OEMCryptoResult sts = OEMCrypto_LoadKeys( s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL, OEMCrypto_ContentLicense); + s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(), + OEMCrypto_ContentLicense); if (OEMCrypto_IsAntiRollbackHwPresent()) { ASSERT_EQ(OEMCrypto_SUCCESS, sts); } else { @@ -1325,56 +1429,53 @@ TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) { OEMCrypto_SUCCESS, OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), - s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), - s.key_array(), NULL, 0, NULL, - OEMCrypto_ContentLicense)); + s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), GetSubstring(), + GetSubstring(), OEMCrypto_ContentLicense)); } if (patch_level < 0x3F) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( - 0, (patch_level + 1) << wvoec::kControlSecurityPatchLevelShift, - 0)); + 0, (patch_level + 1) << wvoec::kControlSecurityPatchLevelShift, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_EQ( OEMCrypto_ERROR_UNKNOWN_FAILURE, OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), - s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), - s.key_array(), NULL, 0, NULL, - OEMCrypto_ContentLicense)); + s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), GetSubstring(), + GetSubstring(), OEMCrypto_ContentLicense)); } if (patch_level > 0) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( - 0, (patch_level - 1) << wvoec::kControlSecurityPatchLevelShift, - 0)); + 0, (patch_level - 1) << wvoec::kControlSecurityPatchLevelShift, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_EQ( OEMCrypto_SUCCESS, OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), - s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), - s.key_array(), NULL, 0, NULL, - OEMCrypto_ContentLicense)); + s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), GetSubstring(), + GetSubstring(), OEMCrypto_ContentLicense)); } } -TEST_F(OEMCryptoSessionTests, Minimum20KeysAPI12) { +TEST_F(OEMCryptoSessionTests, MinimumKeysAPI12) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); - s.set_num_keys(kMaxNumKeys); + size_t num_keys = GetResourceValue(kMaxKeysPerSession); + ASSERT_LE(num_keys, kMaxNumKeys) << "Test constants need updating."; + s.set_num_keys(num_keys); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); - for (size_t key_index = 0; key_index < kMaxNumKeys; key_index++) { + for (size_t key_index = 0; key_index < num_keys; key_index++) { bool kSelectKeyFirst = true; ASSERT_NO_FATAL_FAILURE( s.TestDecryptCTR(kSelectKeyFirst, OEMCrypto_SUCCESS, key_index)); @@ -1413,7 +1514,7 @@ TEST_P(SessionTestDecryptWithHDCP, DecryptAPI09) { // Test parameterized by HDCP version. DecryptWithHDCP(static_cast(GetParam())); } -INSTANTIATE_TEST_CASE_P(TestHDCP, SessionTestDecryptWithHDCP, Range(1, 5)); +INSTANTIATE_TEST_CASE_P(TestHDCP, SessionTestDecryptWithHDCP, Range(1, 6)); // // Load, Refresh Keys Test @@ -1558,7 +1659,7 @@ TEST_P(SessionTestRefreshKeyTest, RefreshWithNoSelectKey) { ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR(false)); } -// Of only one key control block in the refesh, we update all the keys. +// If only one key control block in the refesh, we update all the keys. INSTANTIATE_TEST_CASE_P(TestRefreshAllKeys, SessionTestRefreshKeyTest, Values(std::make_pair(true, 1), std::make_pair(false, 1))); @@ -1568,6 +1669,25 @@ INSTANTIATE_TEST_CASE_P(TestRefreshEachKeys, SessionTestRefreshKeyTest, Values(std::make_pair(true, 4), std::make_pair(false, 4))); +// If the license does not allow a hash, then we should not compute one. +TEST_F(OEMCryptoSessionTests, HashForbiddenAPI15) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); + ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(kDuration, 0, 0)); + ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); + ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); + // Either failure, or not supported is allowed. + ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_InitializeDecryptHash(s.session_id())); + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(s.session_id(), s.license().keys[0].key_id, + s.license().keys[0].key_id_length, + OEMCrypto_CipherMode_CTR)); + // Still not allowed. + ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_InitializeDecryptHash(s.session_id())); +} + // // Decrypt Tests // @@ -1768,7 +1888,8 @@ class OEMCryptoSessionTestsDecryptTests Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); - ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(kDuration, 0, 0)); + ASSERT_NO_FATAL_FAILURE( + s.FillSimpleMessage(kDuration, kControlAllowHashVerification, 0)); memcpy(s.license().keys[0].key_data, &key[0], key.size()); s.license().keys[0].cipher_mode = cipher_mode_; ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); @@ -1777,7 +1898,10 @@ class OEMCryptoSessionTestsDecryptTests s.license().keys[0].key_id_length, cipher_mode_); ASSERT_EQ(OEMCrypto_SUCCESS, sts); - + if (global_features.supports_crc) { + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_InitializeDecryptHash(s.session_id())); + } // We decrypt each subsample. vector output_buffer(total_size_ + 16, 0xaa); const uint8_t *input_buffer = NULL; @@ -1846,6 +1970,18 @@ class OEMCryptoSessionTestsDecryptTests EXPECT_EQ(0xaa, output_buffer[total_size_]) << "Buffer overrun."; output_buffer.resize(total_size_); EXPECT_EQ(unencryptedData, output_buffer); + if (global_features.supports_crc) { + uint32_t hash = + wvcrc32(&unencryptedData[0], unencryptedData.size()); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_SetDecryptHash( + s.session_id(), 1, reinterpret_cast(&hash), + sizeof(hash))); + uint32_t frame; + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_GetHashErrorCode(s.session_id(), &frame)); + + } } OEMCrypto_CENCEncryptPatternDesc pattern_; @@ -2022,15 +2158,35 @@ TEST_P(OEMCryptoSessionTestsPartialBlockTests, PartialBlock) { TestDecryptCENC(key, encryptionIv, encryptedData, unencryptedData); } -TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptLargeBuffer) { - subsample_size_.push_back(SampleSize(kMaxDecryptSize, 0)); - subsample_size_.push_back(SampleSize(kMaxDecryptSize, 0)); - subsample_size_.push_back(SampleSize(0, kMaxDecryptSize)); - subsample_size_.push_back(SampleSize(0, kMaxDecryptSize)); - subsample_size_.push_back(SampleSize(kMaxDecryptSize, 0)); - subsample_size_.push_back(SampleSize(kMaxDecryptSize, 0)); - subsample_size_.push_back(SampleSize(0, kMaxDecryptSize)); - subsample_size_.push_back(SampleSize(0, kMaxDecryptSize)); +// Based on the resource rating, oemcrypto should handle at least +// kMaxNumberSubsamples na kMaxSampleSize +TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptMaxSample) { + size_t max_size = GetResourceValue(kMaxSampleSize); + size_t max_subsample_size = GetResourceValue(kMaxSubsampleSize); + size_t num_subsamples = GetResourceValue(kMaxNumberSubsamples); + if (num_subsamples * max_subsample_size > max_size) { + max_subsample_size = max_size / num_subsamples; + } + for(size_t i = 0; i < num_subsamples/2; i += 2) { + subsample_size_.push_back(SampleSize(max_subsample_size, 0)); + subsample_size_.push_back(SampleSize(0, max_subsample_size)); + } + FindTotalSize(); + vector unencryptedData(total_size_); + vector encryptedData(total_size_); + vector encryptionIv(AES_BLOCK_SIZE); + vector key(AES_BLOCK_SIZE); + EXPECT_EQ(1, GetRandBytes(&encryptionIv[0], AES_BLOCK_SIZE)); + EXPECT_EQ(1, GetRandBytes(&key[0], AES_BLOCK_SIZE)); + for (size_t i = 0; i < total_size_; i++) unencryptedData[i] = i % 256; + EncryptData(key, encryptionIv, unencryptedData, &encryptedData); + TestDecryptCENC(key, encryptionIv, encryptedData, unencryptedData); +} + +TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptMaxSubsample) { + size_t max_subsample_size = GetResourceValue(kMaxSubsampleSize); + subsample_size_.push_back(SampleSize(max_subsample_size, 0)); + subsample_size_.push_back(SampleSize(0, max_subsample_size)); FindTotalSize(); vector unencryptedData(total_size_); vector encryptedData(total_size_); @@ -4200,7 +4356,7 @@ TEST_F(GenericCryptoTest, GenericKeyBadVerify) { } TEST_F(GenericCryptoTest, GenericKeyEncryptLargeBuffer) { - buffer_size_ = kMaxDecryptSize; + buffer_size_ = GetResourceValue(kMaxGenericBuffer); EncryptAndLoadKeys(); unsigned int key_index = 0; vector expected_encrypted; @@ -4221,7 +4377,7 @@ TEST_F(GenericCryptoTest, GenericKeyEncryptLargeBuffer) { TEST_F(GenericCryptoTest, GenericKeyDecryptLargeBuffer) { // Some applications are known to pass in a block that is almost 400k. - buffer_size_ = kMaxDecryptSize; + buffer_size_ = GetResourceValue(kMaxGenericBuffer); EncryptAndLoadKeys(); unsigned int key_index = 1; vector encrypted; @@ -4241,7 +4397,7 @@ TEST_F(GenericCryptoTest, GenericKeyDecryptLargeBuffer) { } TEST_F(GenericCryptoTest, GenericKeySignLargeBuffer) { - buffer_size_ = kMaxDecryptSize; + buffer_size_ = GetResourceValue(kMaxGenericBuffer); EncryptAndLoadKeys(); unsigned int key_index = 2; vector expected_signature; @@ -4268,7 +4424,7 @@ TEST_F(GenericCryptoTest, GenericKeySignLargeBuffer) { } TEST_F(GenericCryptoTest, GenericKeyVerifyLargeBuffer) { - buffer_size_ = kMaxDecryptSize; + buffer_size_ = GetResourceValue(kMaxGenericBuffer); EncryptAndLoadKeys(); unsigned int key_index = 3; vector signature; @@ -4511,6 +4667,7 @@ class UsageTableTest : public GenericCryptoTest { } virtual void Restart() { + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); EnsureTestKeys(); ASSERT_NO_FATAL_FAILURE(session_.open()); @@ -4690,7 +4847,6 @@ TEST_F(UsageTableTest, RepeatOnlineLicense) { Session s2; ASSERT_NO_FATAL_FAILURE(s2.open()); ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2)); - uint8_t* pst_ptr = s.encrypted_license().pst; s2.LoadUsageEntry(s); // Use the same entry. // Trying to reuse a PST is bad. We use session ID for s2, everything else // reused from s. @@ -4698,10 +4854,9 @@ TEST_F(UsageTableTest, RepeatOnlineLicense) { OEMCrypto_SUCCESS, OEMCrypto_LoadKeys(s2.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), - s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), - s.key_array(), pst_ptr, pst.length(), NULL, - OEMCrypto_ContentLicense)); + s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), s.pst_substr(), + GetSubstring(), OEMCrypto_ContentLicense)); ASSERT_NO_FATAL_FAILURE(s2.close()); } @@ -4717,9 +4872,9 @@ TEST_F(UsageTableTest, OnlineEmptyPST) { ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry()); OEMCryptoResult sts = OEMCrypto_LoadKeys( s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL, OEMCrypto_ContentLicense); + s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(), + OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); ASSERT_NO_FATAL_FAILURE(s.close()); } @@ -4737,9 +4892,9 @@ TEST_F(UsageTableTest, OnlineMissingEntry) { // ENTRY NOT CREATED: ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry()); OEMCryptoResult sts = OEMCrypto_LoadKeys( s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), - s.encrypted_license().pst, pst.length(), NULL, OEMCrypto_ContentLicense); + s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), s.pst_substr(), GetSubstring(), + OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); ASSERT_NO_FATAL_FAILURE(s.close()); } @@ -4747,9 +4902,8 @@ TEST_F(UsageTableTest, OnlineMissingEntry) { TEST_P(UsageTableTestWithMAC, GenericCryptoEncrypt) { std::string pst = "A PST"; uint32_t nonce = session_.get_nonce(); - MakeFourKeys( - 0, wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired, - nonce, pst); + MakeFourKeys(0, wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired, + nonce, pst); ASSERT_NO_FATAL_FAILURE(session_.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(session_.CreateNewUsageEntry()); ASSERT_NO_FATAL_FAILURE(session_.LoadTestKeys(pst, new_mac_keys_)); @@ -5025,15 +5179,13 @@ TEST_P(UsageTableTestWithMAC, BadReloadOfflineLicense) { 0, wvoec::kControlNonceOrEntry, s2.get_nonce(), pst)); ASSERT_NO_FATAL_FAILURE(s2.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s2.LoadUsageEntry(s)); - uint8_t* pst_ptr = s2.encrypted_license().pst; ASSERT_NE( OEMCrypto_SUCCESS, OEMCrypto_LoadKeys(s2.session_id(), s2.message_ptr(), s2.message_size(), &s2.signature()[0], s2.signature().size(), - s2.encrypted_license().mac_key_iv, - s2.encrypted_license().mac_keys, s.num_keys(), - s2.key_array(), pst_ptr, pst.length(), NULL, - OEMCrypto_ContentLicense)); + s2.enc_mac_keys_iv_substr(), s2.enc_mac_keys_substr(), + s.num_keys(), s2.key_array(), s2.pst_substr(), + GetSubstring(), OEMCrypto_ContentLicense)); ASSERT_NO_FATAL_FAILURE(s2.close()); // Offline license with same mac keys should still be OK. @@ -5042,10 +5194,10 @@ TEST_P(UsageTableTestWithMAC, BadReloadOfflineLicense) { ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, new_mac_keys_)); ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE( - s.GenerateVerifyReport(pst, kUnused, - loaded, // license loaded. - 0, 0)); // first and last decrypt + ASSERT_NO_FATAL_FAILURE(s.GenerateVerifyReport(pst, kUnused, + loaded, // license loaded. + 0, + 0)); // first and last decrypt } // An offline license should not load on the first call if the nonce is bad. @@ -5058,12 +5210,11 @@ TEST_P(UsageTableTestWithMAC, OfflineBadNonce) { ASSERT_NO_FATAL_FAILURE( s.FillSimpleMessage(0, wvoec::kControlNonceOrEntry, 42, pst)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); - uint8_t* pst_ptr = s.encrypted_license().pst; OEMCryptoResult sts = OEMCrypto_LoadKeys( s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), pst_ptr, - pst.length(), NULL, OEMCrypto_ContentLicense); + s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), s.pst_substr(), GetSubstring(), + OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); ASSERT_NO_FATAL_FAILURE(s.close()); } @@ -5079,9 +5230,9 @@ TEST_P(UsageTableTestWithMAC, OfflineEmptyPST) { ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); OEMCryptoResult sts = OEMCrypto_LoadKeys( s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], - s.signature().size(), s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL, OEMCrypto_ContentLicense); + s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(), + OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); ASSERT_NO_FATAL_FAILURE(s.close()); } @@ -5097,14 +5248,12 @@ TEST_P(UsageTableTestWithMAC, ReloadOfflineWrongPST) { ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry()); memcpy(s.license().pst, bad_pst.c_str(), bad_pst.length()); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); - uint8_t* pst_ptr = s.encrypted_license().pst; - ASSERT_NE( - OEMCrypto_SUCCESS, - OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(), - &s.signature()[0], s.signature().size(), NULL, NULL, - s.num_keys(), s.key_array(), - pst_ptr, bad_pst.length(), NULL, - OEMCrypto_ContentLicense)); + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_LoadKeys( + s.session_id(), s.message_ptr(), s.message_size(), + &s.signature()[0], s.signature().size(), GetSubstring(), + GetSubstring(), s.num_keys(), s.key_array(), s.pst_substr(), + GetSubstring(), OEMCrypto_ContentLicense)); } TEST_P(UsageTableTestWithMAC, DeactivateOfflineLicense) { @@ -5131,15 +5280,13 @@ TEST_P(UsageTableTestWithMAC, DeactivateOfflineLicense) { ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2)); ASSERT_NO_FATAL_FAILURE(s2.LoadUsageEntry(s)); // Offile license can not be reused if it has been deactivated. - uint8_t* pst_ptr = s.encrypted_license().pst; EXPECT_NE( OEMCrypto_SUCCESS, OEMCrypto_LoadKeys(s2.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), - s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), - s.key_array(), pst_ptr, pst.length(), NULL, - OEMCrypto_ContentLicense)); + s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), s.pst_substr(), + GetSubstring(), OEMCrypto_ContentLicense)); s2.close(); // But we can still generate a report. Session s3; @@ -5174,15 +5321,13 @@ TEST_P(UsageTableTestWithMAC, DeactivateOfflineLicenseUnused) { ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2)); ASSERT_NO_FATAL_FAILURE(s2.LoadUsageEntry(s1)); // Offline license can not be reused if it has been deactivated. - uint8_t* pst_ptr = s1.encrypted_license().pst; EXPECT_NE( OEMCrypto_SUCCESS, OEMCrypto_LoadKeys(s2.session_id(), s1.message_ptr(), s1.message_size(), &s1.signature()[0], s1.signature().size(), - s1.encrypted_license().mac_key_iv, - s1.encrypted_license().mac_keys, s1.num_keys(), - s1.key_array(), pst_ptr, pst.length(), NULL, - OEMCrypto_ContentLicense)); + s1.enc_mac_keys_iv_substr(), s1.enc_mac_keys_substr(), + s1.num_keys(), s1.key_array(), s1.pst_substr(), + GetSubstring(), OEMCrypto_ContentLicense)); s2.close(); // But we can still generate a report. Session s3; @@ -5202,15 +5347,17 @@ TEST_P(UsageTableTestWithMAC, BadRange) { ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, wvoec::kControlNonceOrEntry, s.get_nonce(), pst)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); - uint8_t* pst_ptr = s.license().pst; // Bad: not in encrypted_license. + std::string double_message = DuplicateMessage(s.encrypted_license()); + OEMCrypto_Substring wrong_pst = s.pst_substr(); + wrong_pst.offset += s.message_size(); ASSERT_NE( OEMCrypto_SUCCESS, - OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(), - &s.signature()[0], s.signature().size(), - s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), - s.key_array(), pst_ptr, pst.length(), NULL, - OEMCrypto_ContentLicense)); + OEMCrypto_LoadKeys( + s.session_id(), + reinterpret_cast(double_message.data()), + s.message_size(), &s.signature()[0], s.signature().size(), + s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), s.num_keys(), + s.key_array(), wrong_pst, GetSubstring(), OEMCrypto_ContentLicense)); } TEST_F(UsageTableTest, UpdateFailsWithNullPtr) { @@ -5280,15 +5427,13 @@ class UsageTableDefragTest : public UsageTableTest { &s->encrypted_usage_entry()[0], s->encrypted_usage_entry().size())); - uint8_t* pst_ptr = s->encrypted_license().pst; - ASSERT_NE( - OEMCrypto_SUCCESS, - OEMCrypto_LoadKeys(s->session_id(), s->message_ptr(), s->message_size(), - &s->signature()[0], s->signature().size(), - s->encrypted_license().mac_key_iv, - s->encrypted_license().mac_keys, s->num_keys(), - s->key_array(), pst_ptr, s->pst().length(), NULL, - OEMCrypto_ContentLicense)); + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_LoadKeys( + s->session_id(), s->message_ptr(), s->message_size(), + &s->signature()[0], s->signature().size(), + s->enc_mac_keys_iv_substr(), s->enc_mac_keys_substr(), + s->num_keys(), s->key_array(), s->pst_substr(), + GetSubstring(), OEMCrypto_ContentLicense)); ASSERT_NO_FATAL_FAILURE(s->close()); } @@ -5965,15 +6110,13 @@ TEST_F(UsageTableTest, LoadSharedLicenseWithNoMaster) { htonl(wvoec::kSharedLicense); } ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); - uint8_t* pst_ptr = s.encrypted_license().pst; - ASSERT_EQ(OEMCrypto_ERROR_MISSING_MASTER, - OEMCrypto_LoadKeys( - s.session_id(), s.message_ptr(), s.message_size(), - &s.signature()[0], s.signature().size(), - s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, - s.num_keys(), s.key_array(), pst_ptr, pst.length(), NULL, - OEMCrypto_ContentLicense)); + ASSERT_EQ( + OEMCrypto_ERROR_MISSING_MASTER, + OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(), + &s.signature()[0], s.signature().size(), + s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), s.pst_substr(), + GetSubstring(), OEMCrypto_ContentLicense)); ASSERT_NO_FATAL_FAILURE(s.close()); } @@ -6000,16 +6143,14 @@ TEST_F(UsageTableTest, PSTLargeBuffer) { ASSERT_NO_FATAL_FAILURE(s2.open()); ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2)); // Offile license can not be reused if it has been deactivated. - uint8_t* pst_ptr = s.encrypted_license().pst; ASSERT_NO_FATAL_FAILURE(s2.LoadUsageEntry(s)); EXPECT_NE( OEMCrypto_SUCCESS, OEMCrypto_LoadKeys(s2.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), - s.encrypted_license().mac_key_iv, - s.encrypted_license().mac_keys, s.num_keys(), - s.key_array(), pst_ptr, pst.length(), NULL, - OEMCrypto_ContentLicense)); + s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), s.pst_substr(), + GetSubstring(), OEMCrypto_ContentLicense)); s2.close(); // But we can still generate a report. Session s3; diff --git a/oemcrypto/test/oemcrypto_test_android.cpp b/oemcrypto/test/oemcrypto_test_android.cpp index 9b06368..77a12ff 100644 --- a/oemcrypto/test/oemcrypto_test_android.cpp +++ b/oemcrypto/test/oemcrypto_test_android.cpp @@ -23,7 +23,10 @@ namespace wvoec { // These tests are required for LollyPop Android devices. class OEMCryptoAndroidLMPTest : public ::testing::Test { protected: - virtual void SetUp() { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); } + virtual void SetUp() { + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + } virtual void TearDown() { OEMCrypto_Terminate(); } }; @@ -153,7 +156,7 @@ class OEMCryptoAndroidQTest : public OEMCryptoAndroidOCTest {}; TEST_F(OEMCryptoAndroidQTest, MinVersionNumber14) { uint32_t version = OEMCrypto_APIVersion(); - ASSERT_GE(version, 14u); + ASSERT_GE(version, 15u); } } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_unittests.gyp b/oemcrypto/test/oemcrypto_unittests.gyp index 44f6a99..67257c3 100644 --- a/oemcrypto/test/oemcrypto_unittests.gyp +++ b/oemcrypto/test/oemcrypto_unittests.gyp @@ -5,7 +5,7 @@ # Override the variables below for the location of various gyp files. # Alternatively, set the environment variable CDM_DIR to point to a recent # version of the source CDM. - 'boringssl_dependency%': '(bytes); + return std::string(char_bytes, char_bytes + size); +} + } // namespace wvcdm