OEMCrypto v14 Docs
This has the released version of the OEMCrypto API v14 documentation. This patch also includes sample code and unit tests.
This commit is contained in:
BIN
docs/WidevineModularDRMSecurityIntegrationGuideforCENC_v13.pdf
Normal file
BIN
docs/WidevineModularDRMSecurityIntegrationGuideforCENC_v13.pdf
Normal file
Binary file not shown.
BIN
docs/WidevineModularDRMSecurityIntegrationGuideforCENC_v14.pdf
Normal file
BIN
docs/WidevineModularDRMSecurityIntegrationGuideforCENC_v14.pdf
Normal file
Binary file not shown.
Binary file not shown.
BIN
docs/Widevine_Level1_Provisioning_Models.pdf
Normal file
BIN
docs/Widevine_Level1_Provisioning_Models.pdf
Normal file
Binary file not shown.
BIN
docs/Widevine_Modular_DRM_Version_10_Delta.pdf
Normal file
BIN
docs/Widevine_Modular_DRM_Version_10_Delta.pdf
Normal file
Binary file not shown.
BIN
docs/Widevine_Modular_DRM_Version_11_Delta.pdf
Normal file
BIN
docs/Widevine_Modular_DRM_Version_11_Delta.pdf
Normal file
Binary file not shown.
BIN
docs/Widevine_Modular_DRM_Version_12_Delta.pdf
Normal file
BIN
docs/Widevine_Modular_DRM_Version_12_Delta.pdf
Normal file
Binary file not shown.
BIN
docs/Widevine_Modular_DRM_Version_13_Delta.pdf
Normal file
BIN
docs/Widevine_Modular_DRM_Version_13_Delta.pdf
Normal file
Binary file not shown.
Binary file not shown.
3462
include/OEMCryptoCENC.h
Normal file
3462
include/OEMCryptoCENC.h
Normal file
File diff suppressed because it is too large
Load Diff
402
include/level3.h
Normal file
402
include/level3.h
Normal file
@@ -0,0 +1,402 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
/*********************************************************************
|
||||
* level3.h
|
||||
*
|
||||
* Reference APIs needed to support Widevine's crypto algorithms.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef LEVEL3_OEMCRYPTO_H_
|
||||
#define LEVEL3_OEMCRYPTO_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "level3_file_system.h"
|
||||
#include "OEMCryptoCENC.h"
|
||||
|
||||
namespace wvoec3 {
|
||||
|
||||
#ifdef DYNAMIC_ADAPTER
|
||||
#define Level3_IsInApp _lcc00
|
||||
#define Level3_Initialize _lcc01
|
||||
#define Level3_Terminate _lcc02
|
||||
#define Level3_InstallKeybox _lcc03
|
||||
#define Level3_GetKeyData _lcc04
|
||||
#define Level3_IsKeyboxValid _lcc05
|
||||
#define Level3_GetRandom _lcc06
|
||||
#define Level3_GetDeviceID _lcc07
|
||||
#define Level3_WrapKeybox _lcc08
|
||||
#define Level3_OpenSession _lcc09
|
||||
#define Level3_CloseSession _lcc10
|
||||
#define Level3_DecryptCENC _lcc11
|
||||
#define Level3_GenerateDerivedKeys _lcc12
|
||||
#define Level3_GenerateSignature _lcc13
|
||||
#define Level3_GenerateNonce _lcc14
|
||||
#define Level3_RefreshKeys _lcc16
|
||||
#define Level3_SelectKey _lcc17
|
||||
#define Level3_RewrapDeviceRSAKey _lcc18
|
||||
#define Level3_LoadDeviceRSAKey _lcc19
|
||||
#define Level3_GenerateRSASignature _lcc20
|
||||
#define Level3_DeriveKeysFromSessionKey _lcc21
|
||||
#define Level3_APIVersion _lcc22
|
||||
#define Level3_SecurityLevel _lcc23
|
||||
#define Level3_Generic_Encrypt _lcc24
|
||||
#define Level3_Generic_Decrypt _lcc25
|
||||
#define Level3_Generic_Sign _lcc26
|
||||
#define Level3_Generic_Verify _lcc27
|
||||
#define Level3_GetHDCPCapability _lcc28
|
||||
#define Level3_SupportsUsageTable _lcc29
|
||||
#define Level3_UpdateUsageTable _lcc30
|
||||
#define Level3_DeactivateUsageEntry _lcc31
|
||||
#define Level3_ReportUsage _lcc32
|
||||
#define Level3_DeleteUsageEntry _lcc33
|
||||
#define Level3_DeleteOldUsageTable _lcc34
|
||||
#define Level3_GetMaxNumberOfSessions _lcc37
|
||||
#define Level3_GetNumberOfOpenSessions _lcc38
|
||||
#define Level3_IsAntiRollbackHwPresent _lcc39
|
||||
#define Level3_CopyBuffer _lcc40
|
||||
#define Level3_QueryKeyControl _lcc41
|
||||
#define Level3_LoadTestKeybox _lcc42
|
||||
#define Level3_ForceDeleteUsageEntry _lcc43
|
||||
#define Level3_LoadTestRSAKey _lcc45
|
||||
#define Level3_SecurityPatchLevel _lcc46
|
||||
#define Level3_GetProvisioningMethod _lcc49
|
||||
#define Level3_GetOEMPublicCertificate _lcc50
|
||||
#define Level3_RewrapDeviceRSAKey30 _lcc51
|
||||
#define Level3_SupportedCertificates _lcc52
|
||||
#define Level3_IsSRMUpdateSupported _lcc53
|
||||
#define Level3_GetCurrentSRMVersion _lcc54
|
||||
#define Level3_LoadSRM _lcc55
|
||||
#define Level3_LoadKeys _lcc56
|
||||
#define Level3_RemoveSRM _lcc57
|
||||
#define Level3_CreateUsageTableHeader _lcc61
|
||||
#define Level3_LoadUsageTableHeader _lcc62
|
||||
#define Level3_CreateNewUsageEntry _lcc63
|
||||
#define Level3_LoadUsageEntry _lcc64
|
||||
#define Level3_UpdateUsageEntry _lcc65
|
||||
#define Level3_ShrinkUsageTableHeader _lcc67
|
||||
#define Level3_MoveEntry _lcc68
|
||||
#define Level3_CopyOldUsageEntry _lcc69
|
||||
#define Level3_CreateOldUsageEntry _lcc70
|
||||
#else
|
||||
#define Level3_Initialize _oecc01
|
||||
#define Level3_Terminate _oecc02
|
||||
#define Level3_InstallKeybox _oecc03
|
||||
#define Level3_GetKeyData _oecc04
|
||||
#define Level3_IsKeyboxValid _oecc05
|
||||
#define Level3_GetRandom _oecc06
|
||||
#define Level3_GetDeviceID _oecc07
|
||||
#define Level3_WrapKeybox _oecc08
|
||||
#define Level3_OpenSession _oecc09
|
||||
#define Level3_CloseSession _oecc10
|
||||
#define Level3_GenerateDerivedKeys _oecc12
|
||||
#define Level3_GenerateSignature _oecc13
|
||||
#define Level3_GenerateNonce _oecc14
|
||||
#define Level3_RefreshKeys _oecc16
|
||||
#define Level3_SelectKey _oecc17
|
||||
#define Level3_RewrapDeviceRSAKey _oecc18
|
||||
#define Level3_LoadDeviceRSAKey _oecc19
|
||||
#define Level3_DeriveKeysFromSessionKey _oecc21
|
||||
#define Level3_APIVersion _oecc22
|
||||
#define Level3_SecurityLevel _oecc23
|
||||
#define Level3_Generic_Encrypt _oecc24
|
||||
#define Level3_Generic_Decrypt _oecc25
|
||||
#define Level3_Generic_Sign _oecc26
|
||||
#define Level3_Generic_Verify _oecc27
|
||||
#define Level3_SupportsUsageTable _oecc29
|
||||
#define Level3_UpdateUsageTable _oecc30
|
||||
#define Level3_ReportUsage _oecc32
|
||||
#define Level3_DeleteUsageEntry _oecc33
|
||||
#define Level3_DeleteOldUsageTable _oecc34
|
||||
#define Level3_GenerateRSASignature _oecc36
|
||||
#define Level3_GetMaxNumberOfSessions _oecc37
|
||||
#define Level3_GetNumberOfOpenSessions _oecc38
|
||||
#define Level3_IsAntiRollbackHwPresent _oecc39
|
||||
#define Level3_CopyBuffer _oecc40
|
||||
#define Level3_QueryKeyControl _oecc41
|
||||
#define Level3_LoadTestKeybox _oecc42
|
||||
#define Level3_ForceDeleteUsageEntry _oecc43
|
||||
#define Level3_GetHDCPCapability _oecc44
|
||||
#define Level3_LoadTestRSAKey _oecc45
|
||||
#define Level3_SecurityPatchLevel _oecc46
|
||||
#define Level3_DecryptCENC _oecc48
|
||||
#define Level3_GetProvisioningMethod _oecc49
|
||||
#define Level3_GetOEMPublicCertificate _oecc50
|
||||
#define Level3_RewrapDeviceRSAKey30 _oecc51
|
||||
#define Level3_SupportedCertificates _oecc52
|
||||
#define Level3_IsSRMUpdateSupported _oecc53
|
||||
#define Level3_GetCurrentSRMVersion _oecc54
|
||||
#define Level3_LoadSRM _oecc55
|
||||
#define Level3_LoadKeys _oecc56
|
||||
#define Level3_RemoveSRM _oecc57
|
||||
#define Level3_CreateUsageTableHeader _oecc61
|
||||
#define Level3_LoadUsageTableHeader _oecc62
|
||||
#define Level3_CreateNewUsageEntry _oecc63
|
||||
#define Level3_LoadUsageEntry _oecc64
|
||||
#define Level3_UpdateUsageEntry _oecc65
|
||||
#define Level3_DeactivateUsageEntry _oecc66
|
||||
#define Level3_ShrinkUsageTableHeader _oecc67
|
||||
#define Level3_MoveEntry _oecc68
|
||||
#define Level3_CopyOldUsageEntry _oecc69
|
||||
#define Level3_CreateOldUsageEntry _oecc70
|
||||
#endif
|
||||
|
||||
#define Level3_GetInitializationState _oecl3o01
|
||||
|
||||
extern "C" {
|
||||
|
||||
bool Level3_IsInApp();
|
||||
OEMCryptoResult Level3_Initialize(void);
|
||||
OEMCryptoResult Level3_Terminate(void);
|
||||
OEMCryptoResult Level3_OpenSession(OEMCrypto_SESSION *session);
|
||||
OEMCryptoResult Level3_CloseSession(OEMCrypto_SESSION session);
|
||||
OEMCryptoResult Level3_GenerateDerivedKeys(OEMCrypto_SESSION session,
|
||||
const uint8_t *mac_key_context,
|
||||
uint32_t mac_key_context_length,
|
||||
const uint8_t *enc_key_context,
|
||||
uint32_t enc_key_context_length);
|
||||
OEMCryptoResult Level3_GenerateNonce(OEMCrypto_SESSION session,
|
||||
uint32_t* nonce);
|
||||
OEMCryptoResult Level3_GenerateSignature(OEMCrypto_SESSION session,
|
||||
const uint8_t* message,
|
||||
size_t message_length,
|
||||
uint8_t* signature,
|
||||
size_t* signature_length);
|
||||
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_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);
|
||||
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_QueryKeyControl(OEMCrypto_SESSION session,
|
||||
const uint8_t* key_id,
|
||||
size_t key_id_length,
|
||||
uint8_t* key_control_block,
|
||||
size_t* key_control_block_length);
|
||||
OEMCryptoResult Level3_SelectKey(const OEMCrypto_SESSION session,
|
||||
const uint8_t* key_id,
|
||||
size_t key_id_length);
|
||||
OEMCryptoResult Level3_DecryptCENC(OEMCrypto_SESSION session,
|
||||
const uint8_t *data_addr,
|
||||
size_t data_length,
|
||||
bool is_encrypted,
|
||||
const uint8_t *iv,
|
||||
size_t block_offset,
|
||||
OEMCrypto_DestBufferDesc* out_buffer,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
||||
uint8_t subsample_flags);
|
||||
OEMCryptoResult Level3_CopyBuffer(const uint8_t *data_addr,
|
||||
size_t data_length,
|
||||
OEMCrypto_DestBufferDesc* out_buffer,
|
||||
uint8_t subsample_flags);
|
||||
OEMCryptoResult Level3_WrapKeybox(const uint8_t *keybox,
|
||||
size_t keyBoxLength,
|
||||
uint8_t *wrappedKeybox,
|
||||
size_t *wrappedKeyBoxLength,
|
||||
const uint8_t *transportKey,
|
||||
size_t transportKeyLength);
|
||||
OEMCryptoResult Level3_InstallKeybox(const uint8_t *keybox,
|
||||
size_t keyBoxLength);
|
||||
OEMCrypto_ProvisioningMethod Level3_GetProvisioningMethod();
|
||||
OEMCryptoResult Level3_GetOEMPublicCertificate(OEMCrypto_SESSION session,
|
||||
uint8_t *public_cert,
|
||||
size_t *public_cert_length);
|
||||
OEMCryptoResult Level3_LoadTestKeybox();
|
||||
OEMCryptoResult Level3_IsKeyboxValid(void);
|
||||
OEMCryptoResult Level3_GetDeviceID(uint8_t* deviceID,
|
||||
size_t *idLength);
|
||||
OEMCryptoResult Level3_GetKeyData(uint8_t* keyData,
|
||||
size_t *keyDataLength);
|
||||
OEMCryptoResult Level3_GetRandom(uint8_t* randomData,
|
||||
size_t dataLength);
|
||||
OEMCryptoResult Level3_RewrapDeviceRSAKey30(OEMCrypto_SESSION session,
|
||||
const uint32_t *nonce,
|
||||
const uint8_t* encrypted_message_key,
|
||||
size_t encrypted_message_key_length,
|
||||
const uint8_t* enc_rsa_key,
|
||||
size_t enc_rsa_key_length,
|
||||
const uint8_t* enc_rsa_key_iv,
|
||||
uint8_t* wrapped_rsa_key,
|
||||
size_t* wrapped_rsa_key_length);
|
||||
OEMCryptoResult Level3_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
const uint8_t* message,
|
||||
size_t message_length,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length,
|
||||
const uint32_t *nonce,
|
||||
const uint8_t* enc_rsa_key,
|
||||
size_t enc_rsa_key_length,
|
||||
const uint8_t* enc_rsa_key_iv,
|
||||
uint8_t* wrapped_rsa_key,
|
||||
size_t *wrapped_rsa_key_length);
|
||||
OEMCryptoResult Level3_LoadDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
const uint8_t* wrapped_rsa_key,
|
||||
size_t wrapped_rsa_key_length);
|
||||
OEMCryptoResult Level3_LoadTestRSAKey();
|
||||
OEMCryptoResult Level3_GenerateRSASignature(OEMCrypto_SESSION session,
|
||||
const uint8_t* message,
|
||||
size_t message_length,
|
||||
uint8_t* signature,
|
||||
size_t *signature_length,
|
||||
RSA_Padding_Scheme padding_scheme);
|
||||
OEMCryptoResult Level3_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);
|
||||
uint32_t Level3_APIVersion();
|
||||
uint8_t Level3_SecurityPatchLevel();
|
||||
const char* Level3_SecurityLevel();
|
||||
OEMCryptoResult Level3_GetHDCPCapability(OEMCrypto_HDCP_Capability* current,
|
||||
OEMCrypto_HDCP_Capability* maximum);
|
||||
bool Level3_SupportsUsageTable();
|
||||
bool Level3_IsAntiRollbackHwPresent();
|
||||
OEMCryptoResult Level3_GetNumberOfOpenSessions(size_t* count);
|
||||
OEMCryptoResult Level3_GetMaxNumberOfSessions(size_t* maximum);
|
||||
uint32_t Level3_SupportedCertificates();
|
||||
OEMCryptoResult Level3_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);
|
||||
OEMCryptoResult Level3_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);
|
||||
OEMCryptoResult Level3_Generic_Sign(OEMCrypto_SESSION session,
|
||||
const uint8_t* in_buffer,
|
||||
size_t buffer_length,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
uint8_t* signature,
|
||||
size_t* signature_length);
|
||||
OEMCryptoResult Level3_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 Level3_UpdateUsageTable();
|
||||
OEMCryptoResult Level3_DeactivateUsageEntry(OEMCrypto_SESSION session,
|
||||
const uint8_t *pst,
|
||||
size_t pst_length);
|
||||
OEMCryptoResult Level3_ReportUsage(OEMCrypto_SESSION session,
|
||||
const uint8_t *pst,
|
||||
size_t pst_length,
|
||||
uint8_t *buffer,
|
||||
size_t *buffer_length);
|
||||
OEMCryptoResult Level3_DeleteUsageEntry(OEMCrypto_SESSION session,
|
||||
const uint8_t* pst,
|
||||
size_t pst_length,
|
||||
const uint8_t *message,
|
||||
size_t message_length,
|
||||
const uint8_t *signature,
|
||||
size_t signature_length);
|
||||
OEMCryptoResult Level3_ForceDeleteUsageEntry(const uint8_t* pst,
|
||||
size_t pst_length);
|
||||
OEMCryptoResult Level3_DeleteOldUsageTable();
|
||||
bool Level3_IsSRMUpdateSupported();
|
||||
OEMCryptoResult Level3_GetCurrentSRMVersion(uint16_t* version);
|
||||
OEMCryptoResult Level3_LoadSRM(const uint8_t* buffer,
|
||||
size_t buffer_length);
|
||||
OEMCryptoResult Level3_RemoveSRM();
|
||||
uint32_t Level3_SupportsDecryptHash();
|
||||
OEMCryptoResult Level3_SetDecryptHash(OEMCrypto_SESSION session,
|
||||
const uint8_t* hash,
|
||||
size_t hash_length);
|
||||
OEMCryptoResult Level3_VerifyDecryptHash(OEMCrypto_SESSION session,
|
||||
uint64_t* failure_data);
|
||||
OEMCryptoResult Level3_CreateUsageTableHeader(uint8_t* header_buffer,
|
||||
size_t* header_buffer_length);
|
||||
OEMCryptoResult Level3_LoadUsageTableHeader(const uint8_t* buffer,
|
||||
size_t buffer_length);
|
||||
OEMCryptoResult Level3_CreateNewUsageEntry(OEMCrypto_SESSION session,
|
||||
uint32_t *usage_entry_number);
|
||||
OEMCryptoResult Level3_LoadUsageEntry(OEMCrypto_SESSION session,
|
||||
uint32_t index,
|
||||
const uint8_t *buffer,
|
||||
size_t buffer_size);
|
||||
OEMCryptoResult Level3_UpdateUsageEntry(OEMCrypto_SESSION session,
|
||||
uint8_t* header_buffer,
|
||||
size_t* header_buffer_length,
|
||||
uint8_t* entry_buffer,
|
||||
size_t* entry_buffer_length);
|
||||
OEMCryptoResult Level3_ShrinkUsageTableHeader(uint32_t new_table_size,
|
||||
uint8_t* header_buffer,
|
||||
size_t* header_buffer_length);
|
||||
OEMCryptoResult Level3_MoveEntry(OEMCrypto_SESSION session,
|
||||
uint32_t new_index);
|
||||
OEMCryptoResult Level3_CopyOldUsageEntry(OEMCrypto_SESSION session,
|
||||
const uint8_t*pst,
|
||||
size_t pst_length);
|
||||
OEMCryptoResult Level3_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);
|
||||
|
||||
/*
|
||||
* Level3_GetInitializationState
|
||||
*
|
||||
* Description:
|
||||
* Return any warning or error condition which occurred during
|
||||
* initialization. On some platforms, this value will be logged and metrics
|
||||
* will be gathered on production devices. This is an optional feature, and
|
||||
* OEMCrypto may always return 0, even if Level3_Initialize failed. This
|
||||
* function may be called whether Level3_Initialize succeeded or not.
|
||||
*
|
||||
* Parameters:
|
||||
* N/A
|
||||
*
|
||||
* Threading:
|
||||
* No other function calls will be made while this function is running.
|
||||
*
|
||||
* Returns:
|
||||
* 0 - no warnings or errors during initialization
|
||||
*
|
||||
* Version:
|
||||
* This method is new in API version 14.
|
||||
*/
|
||||
OEMCryptoResult Level3_GetInitializationState(void);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
// The following are interfaces needed for Level3 OEMCrypto specifically, which
|
||||
// partners are expected to implement.
|
||||
|
||||
// Returns a stable, unique identifier for the device. This could be a
|
||||
// serial number or any other character sequence representing that device.
|
||||
// The parameter |len| needs to be changed to reflect the length of the
|
||||
// unique identifier.
|
||||
const char *getUniqueID(size_t *len);
|
||||
|
||||
// Returns a 64-bit unsigned integer to be used as a random seed for RNG.
|
||||
// If the operation is unsuccessful, this function returns 0.
|
||||
// We provide a sample implementation under the name generate_entropy_linux.cpp
|
||||
// which partners should use if they can.
|
||||
uint64_t generate_entropy();
|
||||
|
||||
// Creates and returns an OEMCrypto_Level3FileSystem implementation.
|
||||
OEMCrypto_Level3FileSystem* createLevel3FileSystem();
|
||||
|
||||
// Deletes the pointer retrieved by the function above.
|
||||
void deleteLevel3FileSystem(OEMCrypto_Level3FileSystem* file_system);
|
||||
|
||||
} // namespace wvoec3
|
||||
|
||||
#endif // LEVEL3_OEMCRYPTO_H_
|
||||
29
include/level3_file_system.h
Normal file
29
include/level3_file_system.h
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved
|
||||
|
||||
/*********************************************************************
|
||||
* level3_file_system.h
|
||||
*
|
||||
* File system for OEMCrypto Level3 file operations.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef LEVEL3_FILE_SYSTEM_H_
|
||||
#define LEVEL3_FILE_SYSTEM_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace wvoec3 {
|
||||
|
||||
class OEMCrypto_Level3FileSystem {
|
||||
public:
|
||||
virtual ~OEMCrypto_Level3FileSystem() {}
|
||||
virtual ssize_t Read(const char *filename, void *buffer, size_t size) = 0;
|
||||
virtual ssize_t Write(const char *filename, const void *buffer,
|
||||
size_t size) = 0;
|
||||
virtual bool Exists(const char *filename) = 0;
|
||||
virtual ssize_t FileSize(const char *filename) = 0;
|
||||
virtual bool Remove(const char *filename) = 0;
|
||||
};
|
||||
|
||||
} // namespace wvoec3
|
||||
|
||||
#endif
|
||||
65
include/oemcrypto_logging.h
Normal file
65
include/oemcrypto_logging.h
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef WVOEC_OEMCRYPTO_LOGGING_H_
|
||||
#define WVOEC_OEMCRYPTO_LOGGING_H_
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
// The constants below represent integers with a single "on" bit that
|
||||
// represents categories of logging This allows users to specify with
|
||||
// more precision what they want to log. LogCategoryEnabled(category)
|
||||
// is used to see if the category passed in the parameters is to
|
||||
// be logged based on the current settings. Categories can be combines
|
||||
// using the | (or) bitwise operator. For example
|
||||
// LogCategoryEnabled(category1 | category2) will return true if
|
||||
// category1 and/or category2 are set to logging.
|
||||
|
||||
const int kLoggingTraceOEMCryptoCalls = 0x01; // All except decrypt calls.
|
||||
const int kLoggingDumpContentKeys = 0x02;
|
||||
const int kLoggingDumpKeyControlBlocks = 0x04;
|
||||
const int kLoggingDumpDerivedKeys = 0x08;
|
||||
const int kLoggingTraceNonce = 0x10;
|
||||
const int kLoggingTraceDecryption = 0x20;
|
||||
const int kLoggingTraceUsageTable = 0x40;
|
||||
const int kLoggingTraceDecryptCalls = 0x80;
|
||||
const int kLoggingDumpTraceAll = 0xFF;
|
||||
|
||||
void SetLoggingSettings(int level, int categories);
|
||||
|
||||
// set level of logging
|
||||
void SetLoggingLevel(int level);
|
||||
|
||||
void TurnOffLoggingForAllCategories();
|
||||
|
||||
// Returns true if the category passed is set to logging.
|
||||
// Returns false otherwise. The category constant declared
|
||||
// above are passed.
|
||||
bool LogCategoryEnabled(int category);
|
||||
|
||||
// Turn on logging for the categories passed.
|
||||
void AddLoggingForCategories(int categories);
|
||||
|
||||
// Turn off logging for the categories passed.
|
||||
void RemoveLoggingForCategories(int categories);
|
||||
|
||||
void dump_hex_helper(std::string& buffer, std::string name,
|
||||
const uint8_t* vector, size_t length);
|
||||
|
||||
void dump_hex(std::string name, const uint8_t* vector, size_t length);
|
||||
|
||||
void dump_array_part_helper(std::string& buffer, std::string array,
|
||||
size_t index, std::string name,
|
||||
const uint8_t* vector, size_t length);
|
||||
|
||||
void dump_array_part(std::string array, size_t index, std::string name,
|
||||
const uint8_t* vector, size_t length);
|
||||
|
||||
} // namespace wvoec_mock
|
||||
|
||||
#endif
|
||||
146
include/pst_report.h
Normal file
146
include/pst_report.h
Normal file
@@ -0,0 +1,146 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
/*********************************************************************
|
||||
* pst_report.h
|
||||
*
|
||||
* Reference APIs needed to support Widevine's crypto algorithms.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef PST_REPORT_H_
|
||||
#define PST_REPORT_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "string_conversions.h" // needed for htonll64.
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
class Unpacked_PST_Report {
|
||||
public:
|
||||
// This object does not own the buffer, and does not check that buffer
|
||||
// is not null.
|
||||
Unpacked_PST_Report(uint8_t *buffer) : buffer_(buffer) {}
|
||||
|
||||
// Copy and move semantics of this class is like that of a pointer.
|
||||
Unpacked_PST_Report(const Unpacked_PST_Report& other) :
|
||||
buffer_(other.buffer_) {}
|
||||
|
||||
Unpacked_PST_Report& operator=(const Unpacked_PST_Report& other) {
|
||||
buffer_ = other.buffer_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t report_size() const {
|
||||
return pst_length() + kraw_pst_report_size;
|
||||
}
|
||||
|
||||
static size_t report_size(size_t pst_length) {
|
||||
return pst_length + kraw_pst_report_size;
|
||||
}
|
||||
|
||||
uint8_t status() const {
|
||||
return static_cast<uint8_t>(* (buffer_ + kstatus_offset));
|
||||
}
|
||||
|
||||
void set_status(uint8_t value) {
|
||||
buffer_[kstatus_offset] = value;
|
||||
}
|
||||
|
||||
uint8_t* signature() {
|
||||
return buffer_ + ksignature_offset;
|
||||
}
|
||||
|
||||
uint8_t clock_security_level() const {
|
||||
return static_cast<uint8_t>(* (buffer_ + kclock_security_level_offset));
|
||||
}
|
||||
|
||||
void set_clock_security_level(uint8_t value) {
|
||||
buffer_[kclock_security_level_offset] = value;
|
||||
}
|
||||
|
||||
uint8_t pst_length() const {
|
||||
return static_cast<uint8_t>(* (buffer_ + kpst_length_offset));
|
||||
}
|
||||
|
||||
void set_pst_length(uint8_t value) {
|
||||
buffer_[kpst_length_offset] = value;
|
||||
}
|
||||
|
||||
uint8_t padding() const {
|
||||
return static_cast<uint8_t>(* (buffer_ + kpadding_offset));
|
||||
}
|
||||
|
||||
void set_padding(uint8_t value) {
|
||||
buffer_[kpadding_offset] = value;
|
||||
}
|
||||
|
||||
// In host byte order.
|
||||
int64_t seconds_since_license_received() const {
|
||||
int64_t time;
|
||||
memcpy(&time, buffer_ + kseconds_since_license_received_offset,
|
||||
sizeof(int64_t));
|
||||
return wvcdm::ntohll64(time);
|
||||
}
|
||||
|
||||
// Parameter time is in host byte order.
|
||||
void set_seconds_since_license_received(int64_t time) const {
|
||||
time = wvcdm::ntohll64(time);
|
||||
memcpy(buffer_ + kseconds_since_license_received_offset, &time,
|
||||
sizeof(int64_t));
|
||||
}
|
||||
|
||||
// In host byte order.
|
||||
int64_t seconds_since_first_decrypt() const {
|
||||
int64_t time;
|
||||
memcpy(&time, buffer_ + kseconds_since_first_decrypt_offset,
|
||||
sizeof(int64_t));
|
||||
return wvcdm::ntohll64(time);
|
||||
}
|
||||
|
||||
// Parameter time is in host byte order.
|
||||
void set_seconds_since_first_decrypt(int64_t time) const {
|
||||
time = wvcdm::ntohll64(time);
|
||||
memcpy(buffer_ + kseconds_since_first_decrypt_offset, &time,
|
||||
sizeof(int64_t));
|
||||
}
|
||||
|
||||
// In host byte order.
|
||||
int64_t seconds_since_last_decrypt() const {
|
||||
int64_t time;
|
||||
memcpy(&time, buffer_ + kseconds_since_last_decrypt_offset,
|
||||
sizeof(int64_t));
|
||||
return wvcdm::ntohll64(time);
|
||||
}
|
||||
|
||||
// Parameter time is in host byte order.
|
||||
void set_seconds_since_last_decrypt(int64_t time) const {
|
||||
time = wvcdm::ntohll64(time);
|
||||
memcpy(buffer_ + kseconds_since_last_decrypt_offset, &time,
|
||||
sizeof(int64_t));
|
||||
}
|
||||
|
||||
uint8_t* pst() {
|
||||
return (buffer_ + kpst_offset);
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t *buffer_;
|
||||
|
||||
// Size of the PST_Report without the pst string.
|
||||
static const size_t kraw_pst_report_size = 48;
|
||||
static const size_t ksignature_offset = 0;
|
||||
static const size_t kstatus_offset = 20;
|
||||
static const size_t kclock_security_level_offset = 21;
|
||||
static const size_t kpst_length_offset = 22;
|
||||
static const size_t kpadding_offset = 23;
|
||||
static const size_t kseconds_since_license_received_offset = 24;
|
||||
static const size_t kseconds_since_first_decrypt_offset = 32;
|
||||
static const size_t kseconds_since_last_decrypt_offset = 40;
|
||||
static const size_t kpst_offset = 48;
|
||||
};
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // PST_REPORT_H_
|
||||
41
mock/oec_mock.gyp
Normal file
41
mock/oec_mock.gyp
Normal file
@@ -0,0 +1,41 @@
|
||||
# Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
{
|
||||
'target_defaults': {
|
||||
# It seems that if one target uses -fPIC, then all targets will need that
|
||||
# flag or else there will be linking errors. For generating a shared
|
||||
# library, we need position independent code.
|
||||
'cflags': [
|
||||
'-g',
|
||||
'-fPIC',
|
||||
'-std=gnu++98',
|
||||
],
|
||||
'ldflags': [
|
||||
'-fPIC',
|
||||
],
|
||||
},
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'oec_mock',
|
||||
'type': 'static_library',
|
||||
'sources': [
|
||||
'src/oemcrypto_keybox_testkey.cpp',
|
||||
'src/oemcrypto_engine_device_properties.cpp',
|
||||
],
|
||||
'variables': {
|
||||
'oec_mock_dir': '.',
|
||||
},
|
||||
'includes': [
|
||||
'oec_mock_kernel.gypi',
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'oec_mock_shared',
|
||||
'type': 'shared_library',
|
||||
'dependencies': [
|
||||
'oec_mock'
|
||||
# TODO(joeyparrish or fredgc): circular dependencies. 'wvcdm_sysdep'
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
37
mock/oec_mock_kernel.gypi
Normal file
37
mock/oec_mock_kernel.gypi
Normal file
@@ -0,0 +1,37 @@
|
||||
# Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
# Define oec_mock_dir and include into your oec target.
|
||||
|
||||
{
|
||||
'include_dirs': [
|
||||
'<(oec_mock_dir)/../../core/include', # for lock.h and wvcdm_types.h
|
||||
'<(oec_mock_dir)/../include',
|
||||
'<(oec_mock_dir)/src',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'<(oec_mock_dir)/../../core/include',
|
||||
'<(oec_mock_dir)/../include',
|
||||
'<(oec_mock_dir)/src',
|
||||
],
|
||||
},
|
||||
'sources': [
|
||||
'<(oec_mock_dir)/src/keys.cpp',
|
||||
'<(oec_mock_dir)/src/oemcrypto_auth_mock.cpp',
|
||||
'<(oec_mock_dir)/src/oemcrypto_engine_mock.cpp',
|
||||
'<(oec_mock_dir)/src/oemcrypto_key_mock.cpp',
|
||||
'<(oec_mock_dir)/src/oemcrypto_keybox_mock.cpp',
|
||||
'<(oec_mock_dir)/src/oemcrypto_mock.cpp',
|
||||
'<(oec_mock_dir)/src/oemcrypto_nonce_table.cpp',
|
||||
'<(oec_mock_dir)/src/oemcrypto_old_usage_table_mock.cpp',
|
||||
'<(oec_mock_dir)/src/oemcrypto_rsa_key_shared.cpp',
|
||||
'<(oec_mock_dir)/src/oemcrypto_session.cpp',
|
||||
'<(oec_mock_dir)/src/oemcrypto_session_key_table.cpp',
|
||||
'<(oec_mock_dir)/src/oemcrypto_usage_table_mock.cpp',
|
||||
'<(oec_mock_dir)/src/wvcrc.cpp',
|
||||
'<(oec_mock_dir)/src/oemcrypto_logging.cpp',
|
||||
],
|
||||
'dependencies': [
|
||||
'<(oec_mock_dir)/../../third_party/boringssl/boringssl.gyp:crypto',
|
||||
],
|
||||
}
|
||||
10
mock/src/keys.cpp
Normal file
10
mock/src/keys.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
// If you are using a baked-in certificate instead of supporting keyboxes,
|
||||
// you should have received a keys.cpp from Widevine that replaces this file.
|
||||
//
|
||||
// If you are not using a baked-in certificate, then you may ignore this file,
|
||||
// as it intentionally defines an empty key.
|
||||
|
||||
#include "keys.h"
|
||||
|
||||
const uint8_t kPrivateKey[] = { 0, };
|
||||
const size_t kPrivateKeySize = 0;
|
||||
11
mock/src/keys.h
Normal file
11
mock/src/keys.h
Normal file
@@ -0,0 +1,11 @@
|
||||
// This header is used to access the baked-in certificate if one is in use.
|
||||
#ifndef KEYS_H_
|
||||
#define KEYS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern const uint8_t kPrivateKey[];
|
||||
extern const size_t kPrivateKeySize;
|
||||
|
||||
#endif // KEYS_H_
|
||||
392
mock/src/oem_cert.cpp
Normal file
392
mock/src/oem_cert.cpp
Normal file
@@ -0,0 +1,392 @@
|
||||
// This file contains the test OEM cert.
|
||||
|
||||
#include "oem_cert.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
extern const uint32_t kOEMSystemId_Prod = 7346;
|
||||
|
||||
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
|
||||
};
|
||||
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
|
||||
};
|
||||
extern const size_t kOEMPublicCertSize_Prod = 2555;
|
||||
|
||||
// Refer to the following in main modules.
|
||||
// This level of indirection is present so new OEM Certificates can be
|
||||
// added and then selected for use at compile time or run time.
|
||||
|
||||
const uint32_t kOEMSystemId = kOEMSystemId_Prod;
|
||||
|
||||
const uint8_t* kOEMPrivateKey = kOEMPrivateKey_Prod;
|
||||
const uint8_t* kOEMPublicCert = kOEMPublicCert_Prod;
|
||||
|
||||
const size_t kOEMPrivateKeySize = kOEMPrivateKeySize_Prod;
|
||||
const size_t kOEMPublicCertSize = kOEMPublicCertSize_Prod;
|
||||
|
||||
} // namespace wvoec_mock
|
||||
21
mock/src/oem_cert.h
Normal file
21
mock/src/oem_cert.h
Normal file
@@ -0,0 +1,21 @@
|
||||
// This header is used to access the OEM certificate if one is in use.
|
||||
#ifndef OEM_CERT_H_
|
||||
#define OEM_CERT_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
// Refer to the following in main modules
|
||||
extern const uint32_t kOEMSystemId;
|
||||
|
||||
extern const uint8_t* kOEMPrivateKey;
|
||||
extern const uint8_t* kOEMPublicCert;
|
||||
|
||||
extern const size_t kOEMPrivateKeySize;
|
||||
extern const size_t kOEMPublicCertSize;
|
||||
|
||||
} // namespace wvoec_mock
|
||||
|
||||
#endif // OEM_CERT_H_
|
||||
203
mock/src/oemcrypto_auth_mock.cpp
Normal file
203
mock/src/oemcrypto_auth_mock.cpp
Normal file
@@ -0,0 +1,203 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
#include "oemcrypto_auth_mock.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "keys.h"
|
||||
#include "log.h"
|
||||
#include "oemcrypto_key_mock.h"
|
||||
#include "oemcrypto_logging.h"
|
||||
#include "oemcrypto_rsa_key_shared.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// A 2048 bit RSA key in PKCS#8 PrivateKeyInfo format
|
||||
// This is the RSA Test Key.
|
||||
static const uint8_t kTestRSAPKCS8PrivateKeyInfo2_2048[] = {
|
||||
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, 0x5e,
|
||||
0x79, 0x65, 0x49, 0xa5, 0x76, 0x79, 0xf9, 0x05,
|
||||
0x45, 0x0f, 0xf4, 0x03, 0xbd, 0xa4, 0x7d, 0x29,
|
||||
0xd5, 0xde, 0x33, 0x63, 0xd8, 0xb8, 0xac, 0x97,
|
||||
0xeb, 0x3f, 0x5e, 0x55, 0xe8, 0x7d, 0xf3, 0xe7,
|
||||
0x3b, 0x5c, 0x2d, 0x54, 0x67, 0x36, 0xd6, 0x1d,
|
||||
0x46, 0xf5, 0xca, 0x2d, 0x8b, 0x3a, 0x7e, 0xdc,
|
||||
0x45, 0x38, 0x79, 0x7e, 0x65, 0x71, 0x5f, 0x1c,
|
||||
0x5e, 0x79, 0xb1, 0x40, 0xcd, 0xfe, 0xc5, 0xe1,
|
||||
0xc1, 0x6b, 0x78, 0x04, 0x4e, 0x8e, 0x79, 0xf9,
|
||||
0x0a, 0xfc, 0x79, 0xb1, 0x5e, 0xb3, 0x60, 0xe3,
|
||||
0x68, 0x7b, 0xc6, 0xef, 0xcb, 0x71, 0x4c, 0xba,
|
||||
0xa7, 0x79, 0x5c, 0x7a, 0x81, 0xd1, 0x71, 0xe7,
|
||||
0x00, 0x21, 0x13, 0xe2, 0x55, 0x69, 0x0e, 0x75,
|
||||
0xbe, 0x09, 0xc3, 0x4f, 0xa9, 0xc9, 0x68, 0x22,
|
||||
0x0e, 0x97, 0x8d, 0x89, 0x6e, 0xf1, 0xe8, 0x88,
|
||||
0x7a, 0xd1, 0xd9, 0x09, 0x5d, 0xd3, 0x28, 0x78,
|
||||
0x25, 0x0b, 0x1c, 0x47, 0x73, 0x25, 0xcc, 0x21,
|
||||
0xb6, 0xda, 0xc6, 0x24, 0x5a, 0xd0, 0x37, 0x14,
|
||||
0x46, 0xc7, 0x94, 0x69, 0xe4, 0x43, 0x6f, 0x47,
|
||||
0xde, 0x00, 0x33, 0x4d, 0x8f, 0x95, 0x72, 0xfa,
|
||||
0x68, 0x71, 0x17, 0x66, 0x12, 0x1a, 0x87, 0x27,
|
||||
0xf7, 0xef, 0x7e, 0xe0, 0x35, 0x58, 0xf2, 0x4d,
|
||||
0x6f, 0x35, 0x01, 0xaa, 0x96, 0xe2, 0x3d, 0x51,
|
||||
0x13, 0x86, 0x9c, 0x79, 0xd0, 0xb7, 0xb6, 0x64,
|
||||
0xe8, 0x86, 0x65, 0x50, 0xbf, 0xcc, 0x27, 0x53,
|
||||
0x1f, 0x51, 0xd4, 0xca, 0xbe, 0xf5, 0xdd, 0x77,
|
||||
0x70, 0x98, 0x0f, 0xee, 0xa8, 0x96, 0x07, 0x5f,
|
||||
0x45, 0x6a, 0x7a, 0x0d, 0x03, 0x9c, 0x4f, 0x29,
|
||||
0xf6, 0x06, 0xf3, 0x5d, 0x58, 0x6c, 0x47, 0xd0,
|
||||
0x96, 0xa9, 0x03, 0x17, 0xbb, 0x4e, 0xc9, 0x21,
|
||||
0xe0, 0xac, 0xcd, 0x78, 0x78, 0xb2, 0xfe, 0x81,
|
||||
0xb2, 0x51, 0x53, 0xa6, 0x1f, 0x98, 0x45, 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
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
AuthenticationRoot::AuthenticationRoot(OEMCrypto_ProvisioningMethod method) :
|
||||
provisioning_method_(method),
|
||||
use_test_keybox_(false) {
|
||||
if ((provisioning_method_ == OEMCrypto_DrmCertificate) &&
|
||||
!rsa_key_.LoadPkcs8RsaKey(kPrivateKey, kPrivateKeySize)) {
|
||||
// This error message is OK in unit tests which use test certificate.
|
||||
LOGE("FATAL ERROR: Platform uses a baked-in certificate instead of a "
|
||||
"keybox, but the certificate could not be loaded.");
|
||||
}
|
||||
}
|
||||
|
||||
KeyboxError AuthenticationRoot::ValidateKeybox() {
|
||||
return keybox().Validate();
|
||||
}
|
||||
|
||||
bool AuthenticationRoot::LoadTestRsaKey() {
|
||||
return rsa_key_.LoadPkcs8RsaKey(kTestRSAPKCS8PrivateKeyInfo2_2048,
|
||||
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048));
|
||||
}
|
||||
|
||||
bool AuthenticationRoot::Validate() {
|
||||
return NO_ERROR == ValidateKeybox();
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
76
mock/src/oemcrypto_auth_mock.h
Normal file
76
mock/src/oemcrypto_auth_mock.h
Normal file
@@ -0,0 +1,76 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
#ifndef OEMCRYPTO_AUTH_MOCK_H_
|
||||
#define OEMCRYPTO_AUTH_MOCK_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include "OEMCryptoCENC.h" // Needed for enums only.
|
||||
#include "oemcrypto_key_mock.h"
|
||||
#include "oemcrypto_keybox_mock.h"
|
||||
#include "oemcrypto_rsa_key_shared.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
class AuthenticationRoot {
|
||||
public:
|
||||
explicit AuthenticationRoot(OEMCrypto_ProvisioningMethod method);
|
||||
~AuthenticationRoot() {}
|
||||
|
||||
bool Validate();
|
||||
|
||||
KeyboxError ValidateKeybox();
|
||||
|
||||
bool InstallKeybox(const uint8_t* keybox_data, size_t keybox_length) {
|
||||
return keybox().InstallKeybox(keybox_data, keybox_length);
|
||||
}
|
||||
|
||||
const std::vector<uint8_t>& DeviceKey(bool use_real_keybox = false) {
|
||||
return use_real_keybox ? real_keybox().device_key() :
|
||||
keybox().device_key();
|
||||
}
|
||||
|
||||
const std::vector<uint8_t>& DeviceId() {
|
||||
return keybox().device_id();
|
||||
}
|
||||
|
||||
size_t DeviceTokenLength() {
|
||||
return keybox().key_data_length();
|
||||
}
|
||||
|
||||
const uint8_t* DeviceToken() {
|
||||
return keybox().key_data();
|
||||
}
|
||||
|
||||
WvKeybox& keybox() { return use_test_keybox_ ? test_keybox_ : keybox_; }
|
||||
bool UseTestKeybox(const uint8_t* keybox_data, size_t keybox_length) {
|
||||
use_test_keybox_ = true;
|
||||
return test_keybox_.InstallKeybox(keybox_data, keybox_length);
|
||||
}
|
||||
|
||||
RSA_shared_ptr& SharedRsaKey() { return rsa_key_; }
|
||||
RSA* rsa_key() { return rsa_key_.get(); }
|
||||
bool LoadTestRsaKey();
|
||||
|
||||
private:
|
||||
OEMCrypto_ProvisioningMethod provisioning_method_;
|
||||
WvKeybox& real_keybox() { return keybox_; }
|
||||
|
||||
WvKeybox keybox_;
|
||||
WvTestKeybox test_keybox_;
|
||||
bool use_test_keybox_;
|
||||
|
||||
RSA_shared_ptr rsa_key_; // If no keybox, this is baked in certificate.
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(AuthenticationRoot);
|
||||
};
|
||||
|
||||
} // namespace wvoec_mock
|
||||
|
||||
#endif // OEMCRYPTO_AUTH_MOCK_H_
|
||||
15
mock/src/oemcrypto_engine_device_properties.cpp
Normal file
15
mock/src/oemcrypto_engine_device_properties.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
|
||||
#include "oemcrypto_engine_mock.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
CryptoEngine* CryptoEngine::MakeCryptoEngine(
|
||||
std::auto_ptr<wvcdm::FileSystem> file_system) {
|
||||
return new CryptoEngine(file_system);
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
36
mock/src/oemcrypto_engine_device_properties_L1.cpp
Normal file
36
mock/src/oemcrypto_engine_device_properties_L1.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
// This file contains oemcrypto engine properties that would be for a
|
||||
// level 1 device.
|
||||
#include "oemcrypto_engine_mock.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
class L1CryptoEngine : public CryptoEngine {
|
||||
public:
|
||||
explicit L1CryptoEngine(std::auto_ptr<wvcdm::FileSystem> file_system)
|
||||
: CryptoEngine(file_system) {}
|
||||
|
||||
bool config_local_display_only() { return true; }
|
||||
|
||||
OEMCrypto_HDCP_Capability config_maximum_hdcp_capability() {
|
||||
return HDCP_V2;
|
||||
}
|
||||
|
||||
bool config_is_anti_rollback_hw_present() { return true; }
|
||||
|
||||
const char* config_security_level() { return "L1"; }
|
||||
|
||||
// This should start at 0, and be incremented only when a security patch has
|
||||
// been applied to the device that fixes a security bug.
|
||||
uint8_t config_security_patch_level() { return 3; }
|
||||
};
|
||||
|
||||
CryptoEngine* CryptoEngine::MakeCryptoEngine(
|
||||
std::auto_ptr<wvcdm::FileSystem> file_system) {
|
||||
return new L1CryptoEngine(file_system);
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
35
mock/src/oemcrypto_engine_device_properties_cert.cpp
Normal file
35
mock/src/oemcrypto_engine_device_properties_cert.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright 2015 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
// This file contains oemcrypto engine properties that would be for a device
|
||||
// that does not have persistant storage or a keybox.
|
||||
//
|
||||
// Note: We also define it to be L2 for illustration only. Production devices
|
||||
// are rarely level 2.
|
||||
#include "oemcrypto_engine_mock.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
class CertOnlyCryptoEngine : public CryptoEngine {
|
||||
public:
|
||||
explicit CertOnlyCryptoEngine(std::auto_ptr<wvcdm::FileSystem> file_system)
|
||||
: CryptoEngine(file_system) {}
|
||||
|
||||
bool config_local_display_only() { return true; }
|
||||
|
||||
bool config_supports_usage_table() { return false; }
|
||||
|
||||
OEMCrypto_ProvisioningMethod config_provisioning_method() {
|
||||
return OEMCrypto_DrmCertificate;
|
||||
}
|
||||
|
||||
const char* config_security_level() { return "L2"; }
|
||||
};
|
||||
|
||||
CryptoEngine* CryptoEngine::MakeCryptoEngine(
|
||||
std::auto_ptr<wvcdm::FileSystem> file_system) {
|
||||
return new CertOnlyCryptoEngine(file_system);
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
595
mock/src/oemcrypto_engine_device_properties_mod.cpp
Normal file
595
mock/src/oemcrypto_engine_device_properties_mod.cpp
Normal file
@@ -0,0 +1,595 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
// This file contains oemcrypto engine properties that reads data from a file
|
||||
// to decide what it's current status is. It is used for testing cdm code.
|
||||
// The following properties are read from the file:
|
||||
// log_level: logging level to use.
|
||||
// 0 = LOG_ERROR,
|
||||
// 1 = LOG_WARN,
|
||||
// 2 = LOG_INFO,
|
||||
// 3 = LOG_DEBUG,
|
||||
// 4 = LOG_VERBOSE
|
||||
// kLogging*: All logging flags found in oemcrypto/include/oemcrypto_logging.h
|
||||
// can be turned on (1) or off (0).
|
||||
// security_level: returned by OEMCrypto_SecurityLevel.
|
||||
// secure_lib: If set, then this will be used as a path to
|
||||
// the L1 liboemcrypto.so that we can use secure buffers.
|
||||
// current_hdcp: returned by OEMCrypto_GetHDCPCapability and
|
||||
// used to verify the key control block in methods like DecryptCENC.
|
||||
// HDCP_NONE = 0, // No HDCP supported, no secure data path.
|
||||
// HDCP_V1 = 1, // HDCP version 1.0
|
||||
// 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_NO_DIGITAL_OUTPUT = 0xff // No digital output.
|
||||
// max_hdcp: returned by OEMCrypto_GetHDCPCapability. Same values as above.
|
||||
// srm_update_supported: If "1", then srm update is supported.
|
||||
// srm_initial_version: Initial value for srm version.
|
||||
// This will be ignored after a reset. If this is not set, CurrentSRM will
|
||||
// return NOT_IMPLEMENTED.
|
||||
// srm_load_fail: If set to a nonzero number, then load_srm will
|
||||
// fail and the version will not be updated. The number is converted to
|
||||
// an OEMCryptoResult and returned.
|
||||
// srm_load_version: If this is set, then it will be used as the
|
||||
// new srm version after loading an SRM -- ignoring the contents of the SRM.
|
||||
// If srm_load_version is -1, then the buffer passed into LoadSRM will be
|
||||
// parsed.
|
||||
// srm_blacklisted_device_attached: If set to "1", then a
|
||||
// oemcrypto will act as if a blacklisted device is attached -- i.e.
|
||||
// playback will be restricted to the local display only.
|
||||
// srm_attached_device_id: If nonzero, the id of a blacklisted device.
|
||||
// If this id is in the revocation list of an SRM file when it is loaded,
|
||||
// playback will be restricted to the local display only.
|
||||
// security_patch_level: This is the value returned by
|
||||
// OEMCrypto_Security_Patch_Level. If the key control block requires a
|
||||
// higher level, then OEMCrypto_LoadKeys will fail.
|
||||
// max_buffer_size: maximum size of a buffer accepted by DecryptCENC and
|
||||
// friends. If this is 0, there is no restriction. If it is 1, the
|
||||
// minimum allowed value is used.
|
||||
// use_keybox: If this is 1, then the test keybox is used. If this is zero,
|
||||
// then the test OEM certificate is used.
|
||||
// use_fallback: If this is nonzero, then the installed Level 1 library will
|
||||
// be used to play content to a secure buffer. Decryption and key
|
||||
// verification are done by the mock, but then the data is copied to the
|
||||
// secure buffer using OEMCrypto_CopyBuffer. The filename of the fallback
|
||||
// library is hardcoded to "level1_backup_liboemcrypto.so". It is
|
||||
// recommended you use the install script to ensure you have the right
|
||||
// filename.
|
||||
//
|
||||
#include <arpa/inet.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "log.h"
|
||||
#include "oem_cert.h"
|
||||
#include "oemcrypto_engine_mock.h"
|
||||
#include "oemcrypto_logging.h"
|
||||
#include "properties.h"
|
||||
#include "string_conversions.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
namespace {
|
||||
typedef OEMCryptoResult (*L1_Initialize_t)(void);
|
||||
typedef OEMCryptoResult (*L1_Terminate_t)(void);
|
||||
typedef OEMCryptoResult (*L1_CopyBuffer_t)(const uint8_t* data_addr,
|
||||
size_t data_length,
|
||||
OEMCrypto_DestBufferDesc* out_buffer,
|
||||
uint8_t subsample_flags);
|
||||
const std::string kDefaultOptionsFile = "/data/mediadrm/oemcrypto/options.txt";
|
||||
} // namespace
|
||||
|
||||
class AndroidModifiableCryptoEngine : public CryptoEngine {
|
||||
public:
|
||||
AndroidModifiableCryptoEngine(std::auto_ptr<wvcdm::FileSystem> file_system)
|
||||
: CryptoEngine(file_system),
|
||||
options_file_(kDefaultOptionsFile),
|
||||
srm_loaded_(false),
|
||||
srm_version_(0),
|
||||
level1_valid_(false),
|
||||
level1_library_(NULL) {
|
||||
std::string path;
|
||||
if (wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3,
|
||||
&path)) {
|
||||
options_file_ = path + "options.txt";
|
||||
}
|
||||
}
|
||||
|
||||
void MaybeReadOptionsFile() {
|
||||
static time_t last_check = 0;
|
||||
static time_t last_changed = 0;
|
||||
time_t now = time(NULL);
|
||||
if (now > last_check + 5) { // Check every five seconds.
|
||||
last_check = now;
|
||||
struct stat file_stat;
|
||||
if (stat(options_file_.c_str(), &file_stat)) {
|
||||
LOGE("Could not stat %s: %s", options_file_.c_str(), strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (file_stat.st_mtime > last_changed) {
|
||||
last_changed = file_stat.st_mtime;
|
||||
ReadOptionsFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReadOptionsFile() {
|
||||
FILE *file = fopen(options_file_.c_str(), "r");
|
||||
if (!file) {
|
||||
LOGE("Could not read %s %s", options_file_.c_str(), strerror(errno));
|
||||
return;
|
||||
}
|
||||
while (!feof(file)) {
|
||||
char name[80 + 1];
|
||||
int64_t value;
|
||||
if (fscanf(file, "%80s %lld", name, &value)) {
|
||||
LOGD("Option %s = %lld", name, value);
|
||||
options_[std::string(name)] = value;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
InitializeLogging();
|
||||
}
|
||||
|
||||
int64_t GetOption(const std::string &key, int64_t default_value) {
|
||||
MaybeReadOptionsFile();
|
||||
if (options_.find(key) == options_.end() ) {
|
||||
LOGW("Option %s not set. Using default %lld", key.c_str(), default_value);
|
||||
return default_value;
|
||||
}
|
||||
return options_[key];
|
||||
}
|
||||
|
||||
void InitializeLogging() {
|
||||
int log_level = GetOption("log_level", wvcdm::LOG_DEBUG);
|
||||
int categories = 0;
|
||||
if (GetOption("kLoggingTraceOEMCryptoCalls", 0) > 0)
|
||||
categories |= kLoggingTraceOEMCryptoCalls;
|
||||
if (GetOption("kLoggingDumpContentKeys", 0) > 0)
|
||||
categories |= kLoggingDumpContentKeys;
|
||||
if (GetOption("kLoggingDumpKeyControlBlocks", 0) > 0)
|
||||
categories |= kLoggingDumpKeyControlBlocks;
|
||||
if (GetOption("kLoggingDumpDerivedKeys", 0) > 0)
|
||||
categories |= kLoggingDumpDerivedKeys;
|
||||
if (GetOption("kLoggingTraceNonce", 0) > 0)
|
||||
categories |= kLoggingTraceNonce;
|
||||
if (GetOption("kLoggingTraceDecryption", 0) > 0)
|
||||
categories |= kLoggingTraceDecryption;
|
||||
if (GetOption("kLoggingTraceUsageTable", 0) > 0)
|
||||
categories |= kLoggingTraceUsageTable;
|
||||
if (GetOption("kLoggingTraceDecryptCalls", 0) > 0)
|
||||
categories |= kLoggingTraceDecryptCalls;
|
||||
if (GetOption("kLoggingDumpTraceAll", 0) > 0)
|
||||
categories |= kLoggingDumpTraceAll;
|
||||
SetLoggingSettings(log_level, categories);
|
||||
}
|
||||
|
||||
#define QUOTE_DEFINE(A) #A
|
||||
#define QUOTE(A) QUOTE_DEFINE(A)
|
||||
#define LOOKUP(Name, Function) \
|
||||
Name = (L1_##Name##t)dlsym(level1_library_, QUOTE(Function)); \
|
||||
if (!Name) { \
|
||||
LOGW("Could not load L1 %s.", \
|
||||
QUOTE(Function)); \
|
||||
Terminate(); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
virtual bool Initialize() {
|
||||
LOGD("OEMCrypto Mock With Options " " " __DATE__ " " __TIME__);
|
||||
MaybeReadOptionsFile();
|
||||
if (!GetOption("use_fallback", 1)) {
|
||||
LOGD("Level 1 fallback ignored.");
|
||||
return true;
|
||||
}
|
||||
level1_library_ = dlopen("level1_backup_liboemcrypto.so", RTLD_NOW);
|
||||
if (level1_library_ == NULL) {
|
||||
LOGE("Could not load backup: %s", dlerror());
|
||||
return false;
|
||||
}
|
||||
LOOKUP(Initialize_, OEMCrypto_Initialize);
|
||||
LOOKUP(Terminate_, OEMCrypto_Terminate);
|
||||
LOOKUP(CopyBuffer_, OEMCrypto_CopyBuffer);
|
||||
level1_valid_ = true;
|
||||
OEMCryptoResult sts = Initialize_();
|
||||
LOGD("L1 fall back initialized. status = %d.", sts);
|
||||
if (sts != OEMCrypto_SUCCESS) {
|
||||
LOGW("Terminating L1 because init failed.");
|
||||
Terminate();
|
||||
LOGW("Continuing Mock without L1 fallback.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void Terminate() {
|
||||
if (level1_valid_) Terminate_();
|
||||
if (level1_library_ != NULL) {
|
||||
LOGD("Closing L1 fall back.\n");
|
||||
dlclose(level1_library_);
|
||||
level1_valid_ = false;
|
||||
level1_library_ = NULL;
|
||||
CopyBuffer_ = NULL;
|
||||
Initialize_ = NULL;
|
||||
Terminate_ = NULL;
|
||||
} else {
|
||||
LOGD("Terminate mock.\n");
|
||||
}
|
||||
}
|
||||
|
||||
const char *HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value) {
|
||||
switch (value) {
|
||||
case HDCP_NONE:
|
||||
return "No HDCP supported, no secure data path";
|
||||
case HDCP_V1:
|
||||
return "HDCP version 1.0";
|
||||
case HDCP_V2:
|
||||
return "HDCP version 2.0";
|
||||
case HDCP_V2_1:
|
||||
return "HDCP version 2.1";
|
||||
case HDCP_V2_2:
|
||||
return "HDCP version 2.2";
|
||||
case HDCP_NO_DIGITAL_OUTPUT:
|
||||
return "No HDCP device attached/using local display with secure path";
|
||||
default:
|
||||
return "<INVALID VALUE>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OEMCrypto_ProvisioningMethod config_provisioning_method() {
|
||||
if (GetOption("use_keybox", 1)) {
|
||||
return OEMCrypto_Keybox;
|
||||
} else {
|
||||
return OEMCrypto_OEMCertificate;
|
||||
}
|
||||
}
|
||||
|
||||
OEMCryptoResult get_oem_certificate(SessionContext* session,
|
||||
uint8_t* public_cert,
|
||||
size_t* public_cert_length) {
|
||||
if (GetOption("use_keybox", 1)) {
|
||||
LOGD("OEM Cert asked for when use_keybox = 1.");
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
if (kOEMPublicCertSize == 0) {
|
||||
LOGD("OEM Cert Size is 0.");
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
if (public_cert_length == NULL) {
|
||||
LOGD("OEM Cert length is 0.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (*public_cert_length < kOEMPublicCertSize) {
|
||||
*public_cert_length = kOEMPublicCertSize;
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
*public_cert_length = kOEMPublicCertSize;
|
||||
if (public_cert == NULL) {
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
memcpy(public_cert, kOEMPublicCert, kOEMPublicCertSize);
|
||||
if (!session->LoadRSAKey(kOEMPrivateKey, kOEMPrivateKeySize)) {
|
||||
LOGE("Private RSA Key did not load correctly.");
|
||||
return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
// Returns "L3" for a software only library. L1 is for hardware protected
|
||||
// data paths.
|
||||
const char *config_security_level() {
|
||||
switch (GetOption("security_level", 0)) {
|
||||
default:
|
||||
LOGW("Option security_level not set. Default is L3.");
|
||||
case 3:
|
||||
return "L3";
|
||||
case 2:
|
||||
return "L2";
|
||||
case 1:
|
||||
return "L1";
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the HDCP version currently in use.
|
||||
OEMCrypto_HDCP_Capability config_current_hdcp_capability() {
|
||||
static OEMCrypto_HDCP_Capability current_hdcp = HDCP_NONE;
|
||||
OEMCrypto_HDCP_Capability new_current_hdcp =
|
||||
static_cast<OEMCrypto_HDCP_Capability>(GetOption("current_hdcp", 0));
|
||||
if (current_hdcp != new_current_hdcp) {
|
||||
LOGI("OEMCrypto current HDCP changed from %d (%s) to %d (%s)", current_hdcp,
|
||||
HDCPCapabilityAsString(current_hdcp), new_current_hdcp,
|
||||
HDCPCapabilityAsString(new_current_hdcp));
|
||||
current_hdcp = new_current_hdcp;
|
||||
}
|
||||
return current_hdcp;
|
||||
}
|
||||
|
||||
// Returns the max HDCP version supported.
|
||||
OEMCrypto_HDCP_Capability config_maximum_hdcp_capability() {
|
||||
static OEMCrypto_HDCP_Capability max_hdcp = HDCP_NONE;
|
||||
MaybeReadOptionsFile();
|
||||
OEMCrypto_HDCP_Capability new_max_hdcp =
|
||||
static_cast<OEMCrypto_HDCP_Capability>(GetOption("max_hdcp", 0));
|
||||
if (max_hdcp != new_max_hdcp) {
|
||||
LOGI("OEMCrypto max HDCP changed from %d (%s) to %d (%s)", max_hdcp,
|
||||
HDCPCapabilityAsString(max_hdcp), new_max_hdcp,
|
||||
HDCPCapabilityAsString(new_max_hdcp));
|
||||
max_hdcp = new_max_hdcp;
|
||||
}
|
||||
return max_hdcp;
|
||||
}
|
||||
|
||||
// This should start at 0, and be incremented only when a security patch has
|
||||
// been applied to the device that fixes a security bug.
|
||||
uint8_t config_security_patch_level() {
|
||||
return GetOption("security_patch_level", 0);
|
||||
}
|
||||
|
||||
size_t max_buffer_size() {
|
||||
int max = GetOption("max_buffer_size", 0);
|
||||
// If max is 1, just use default max buffer.
|
||||
if (max == 1) return CryptoEngine::max_buffer_size();
|
||||
return max; // If 0, no restriction. If something else, use that restriction.
|
||||
}
|
||||
|
||||
bool srm_update_supported() {
|
||||
int supported = GetOption("srm_update_supported", 0);
|
||||
LOGI("OEMCrypto mock %s supporting SRM update.",
|
||||
supported ? "is" : "is not");
|
||||
return supported != 0;
|
||||
}
|
||||
|
||||
OEMCryptoResult current_srm_version(uint16_t *version) {
|
||||
if (srm_loaded_) {
|
||||
LOGV("SRM loaded. version used is %d.", srm_version_);
|
||||
*version = srm_version_;
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
int value = GetOption("srm_initial_version", -1);
|
||||
if (value > 0) {
|
||||
LOGV("SRM version from get option: %d.", value);
|
||||
srm_version_ = value;
|
||||
*version = value;
|
||||
return OEMCrypto_SUCCESS;
|
||||
} else {
|
||||
LOGI("SRM initial version is %d -- reporting not implemented.", value);
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert uint24 or uint40 into a uint64.
|
||||
int64_t unpack_odd_bytes(const uint8_t *buffer, size_t length) {
|
||||
uint8_t small_buffer[8];
|
||||
memset(small_buffer, 0, 8);
|
||||
if (length > 8) {
|
||||
LOGE("OEMCrypto Mock: programmer error. unpack %d bytes.", length);
|
||||
length = 8;
|
||||
}
|
||||
size_t offset = 8 - length;
|
||||
memcpy(small_buffer + offset, buffer, length);
|
||||
return wvcdm::htonll64(*reinterpret_cast<const int64_t*>(small_buffer));
|
||||
}
|
||||
|
||||
OEMCryptoResult load_srm(const uint8_t *buffer, size_t buffer_length) {
|
||||
if (!srm_update_supported()) {
|
||||
LOGE("OEMCrypto mock update not supported, but load_srm called.");
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
int result = GetOption("srm_load_fail", 0);
|
||||
if (result > 0) {
|
||||
LOGE("OEMCrypto mock load_srm returning error %d.", result);
|
||||
return static_cast<OEMCryptoResult>(result);
|
||||
}
|
||||
int new_version = GetOption("srm_load_version", -1);
|
||||
if (new_version >= 0) {
|
||||
if (new_version < srm_version_) {
|
||||
LOGE("New SRM version is lower than existing SRM version: %d < %d",
|
||||
new_version, srm_version_);
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
srm_version_ = new_version;
|
||||
LOGI("OEMCrypto mock told to change SRM version to %d.", srm_version_);
|
||||
srm_loaded_ = true;
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
if (buffer_length < 395) {
|
||||
LOGE("OEMCrypto mock bad buffer size: %ld < 395.", buffer_length);
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
uint8_t srm_id = buffer[0] >> 4;
|
||||
uint8_t hdcp2_indicator = buffer[0] & 0x0F;
|
||||
uint8_t reserved = buffer[1];
|
||||
uint16_t version = htons(*reinterpret_cast<const uint16_t *>(&buffer[2]));
|
||||
if (reserved) {
|
||||
LOGE("OEMCrypto mock. SRM's second byte nonzero: %02X.", reserved);
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
uint8_t generation = buffer[4];
|
||||
if (generation > 1) {
|
||||
LOGW("OEMCrypto mock. SRM Generation number is %d, but only first gen is parsed.",
|
||||
generation);
|
||||
LOGW("If the revoked device is in a a later generation, it will not be recognized.");
|
||||
}
|
||||
int64_t length = unpack_odd_bytes(buffer + 5, 3); // 24 bits.
|
||||
if (length + 5 != buffer_length) {
|
||||
LOGW("OEMCrypto mock. SRM length is %lld = 0x%llx, but I expected %zd = 0x%zx.",
|
||||
length, length, buffer_length - 5, buffer_length - 5);
|
||||
}
|
||||
int64_t count = 0;
|
||||
const uint8_t *ids;
|
||||
if (srm_id == 8 && hdcp2_indicator == 0) {
|
||||
// https://www.digital-cp.com/sites/default/files/specifications/HDCP%20Specification%20Rev1_4_Secure.pdf
|
||||
count = buffer[8];
|
||||
LOGI("OEMCrypto mock loading HDCP1 SRM. version = %d. count=%lld.",
|
||||
version, count);
|
||||
ids = buffer + 9;
|
||||
if (buffer_length < 9 + count*5) {
|
||||
LOGE("OEMCrypto mock bad buffer size for count = %lld: %d < %lld.",
|
||||
count, buffer_length, 12 + count*5);
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
} else if (srm_id == 9 && hdcp2_indicator == 1) {
|
||||
// https://www.digital-cp.com/sites/default/files/specifications/HDCP%20on%20HDMI%20Specification%20Rev2_2_Final1.pdf
|
||||
count = unpack_odd_bytes(buffer + 8, 2) >> 6; // 10 bits = 2 bytes - 6.
|
||||
LOGI("OEMCrypto mock loading HDCP2 SRM. version = %d. count=%lld.",
|
||||
version, count);
|
||||
ids = buffer + 12;
|
||||
if (buffer_length < 12 + count*5) {
|
||||
LOGE("OEMCrypto mock bad buffer size for count: %d < %ld.",
|
||||
buffer_length, 12 + count*5);
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
} else {
|
||||
LOGE("OEMCrypto mock bad buffer start: %02X%02X%02X%02X...", buffer[0],
|
||||
buffer[1], buffer[2], buffer[3]);
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
for(size_t i = 0; i < count; i++) {
|
||||
int64_t id = unpack_odd_bytes(ids + 5*i, 5);
|
||||
srm_revocation_list_.push_back(id);
|
||||
LOGI("OEMCrypto mock SRM revokes device %lld = 0x%llx", id, id);
|
||||
}
|
||||
srm_loaded_ = true;
|
||||
srm_version_ = version;
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
OEMCryptoResult remove_srm() {
|
||||
if (!srm_update_supported()) {
|
||||
LOGE("OEMCrypto mock update not supported, bug load_srm called.");
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
srm_version_ = 0;
|
||||
srm_loaded_ = false;
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
bool srm_blacklisted_device_attached() {
|
||||
if (GetOption("srm_load_version", -1) < 0) {
|
||||
return scan_revoked_list();
|
||||
}
|
||||
static int blacklisted = 0;
|
||||
int new_value = GetOption("srm_blacklisted_device_attached", 0);
|
||||
if (new_value != blacklisted) {
|
||||
LOGI("SRM blacklisted device changed from %d to %d", blacklisted,
|
||||
new_value);
|
||||
blacklisted = new_value;
|
||||
}
|
||||
return blacklisted > 0;
|
||||
}
|
||||
|
||||
bool scan_revoked_list() {
|
||||
static int64_t old_attached_id = 0;
|
||||
int64_t attached_id = GetOption("srm_attached_device_id", 0);
|
||||
bool print_all_ids = false;
|
||||
if (attached_id != old_attached_id) {
|
||||
LOGD("OEMCrypto mock -- ID of attached device is %lld = 0x%lld",
|
||||
attached_id, attached_id);
|
||||
old_attached_id = attached_id;
|
||||
print_all_ids = true;
|
||||
}
|
||||
for (size_t i = 0; i < srm_revocation_list_.size(); i++) {
|
||||
if (print_all_ids) {
|
||||
LOGD("OEMCrypto mock: %d) revoked id %lld = 0x%lld.", i,
|
||||
srm_revocation_list_[i], srm_revocation_list_[i]);
|
||||
}
|
||||
if (srm_revocation_list_[i] == attached_id) {
|
||||
LOGD("OEMCrypto mock: attached device %lld = 0x%lld is revoked.",
|
||||
attached_id, attached_id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
LOGD("OEMCrypto mock: attached device %lld is not revoked.", attached_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void adjust_destination(OEMCrypto_DestBufferDesc *out_description,
|
||||
size_t data_length, uint8_t subsample_flags) {
|
||||
if (out_description->type != OEMCrypto_BufferType_Secure) return;
|
||||
if (!level1_valid_) {
|
||||
static bool warned_once = false;
|
||||
if (!warned_once) {
|
||||
warned_once = true;
|
||||
LOGW("OEMCrypto Mock: given secure buffer with no level1 fallback.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (subsample_flags & OEMCrypto_FirstSubsample) {
|
||||
final_destination_.type = OEMCrypto_BufferType_Secure;
|
||||
final_destination_.buffer.secure.handle =
|
||||
out_description->buffer.secure.handle;
|
||||
final_destination_.buffer.secure.max_length =
|
||||
out_description->buffer.secure.max_length;
|
||||
final_destination_.buffer.secure.offset =
|
||||
out_description->buffer.secure.offset;
|
||||
temp_buffer_.resize(final_destination_.buffer.secure.max_length);
|
||||
temp_buffer_length_ = 0;
|
||||
}
|
||||
if (temp_buffer_length_ != out_description->buffer.secure.offset) {
|
||||
LOGW("OEMCrypto: offset into secure buffer is not correct %zd != %zd.",
|
||||
temp_buffer_length_, out_description->buffer.secure.offset);
|
||||
}
|
||||
size_t new_length = temp_buffer_length_ + data_length;
|
||||
if (new_length > temp_buffer_.size()) {
|
||||
LOGW("Temp buffer was not big enough. %zd > %zd.", new_length,
|
||||
temp_buffer_.size());
|
||||
temp_buffer_.resize(new_length);
|
||||
}
|
||||
destination_ = &temp_buffer_[temp_buffer_length_];
|
||||
temp_buffer_length_ = new_length;
|
||||
}
|
||||
|
||||
// Push destination buffer to L1 output.
|
||||
virtual OEMCryptoResult PushDestination(
|
||||
OEMCrypto_DestBufferDesc *out_description, uint8_t subsample_flags) {
|
||||
if (level1_valid_ &&
|
||||
(out_description->type == OEMCrypto_BufferType_Secure)) {
|
||||
if (subsample_flags & OEMCrypto_LastSubsample) {
|
||||
return CopyBuffer_(&temp_buffer_[0], temp_buffer_length_,
|
||||
&final_destination_,
|
||||
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample);
|
||||
}
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
private:
|
||||
// If the SRM version has been loaded or not. If not, we use the system
|
||||
// property to find the current SRM version.
|
||||
bool srm_loaded_;
|
||||
// Current srm version. Before an SRM has been loaded, this will be set from
|
||||
// the system property.
|
||||
int srm_version_;
|
||||
// List of forbidden/revoked devices.
|
||||
std::vector<int64_t> srm_revocation_list_;
|
||||
|
||||
std::map<std::string, int64_t> options_;
|
||||
|
||||
std::string options_file_;
|
||||
bool level1_valid_;
|
||||
void* level1_library_;
|
||||
L1_CopyBuffer_t CopyBuffer_;
|
||||
L1_Initialize_t Initialize_;
|
||||
L1_Terminate_t Terminate_;
|
||||
OEMCrypto_DestBufferDesc final_destination_;
|
||||
std::vector<uint8_t> temp_buffer_;
|
||||
size_t temp_buffer_length_; // Length of temp buffer currently in use.
|
||||
};
|
||||
|
||||
CryptoEngine* CryptoEngine::MakeCryptoEngine(
|
||||
std::auto_ptr<wvcdm::FileSystem> file_system) {
|
||||
return new AndroidModifiableCryptoEngine(file_system);
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
82
mock/src/oemcrypto_engine_device_properties_prov30.cpp
Normal file
82
mock/src/oemcrypto_engine_device_properties_prov30.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
// This file contains oemcrypto engine properties that would be for a
|
||||
// level 2 device that does not have persistant storage or a keybox.
|
||||
// Note: this is for illustration only. Production devices are rarely level 2.
|
||||
|
||||
#include "oemcrypto_engine_mock.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "oem_cert.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
class Prov30CryptoEngine : public CryptoEngine {
|
||||
public:
|
||||
explicit Prov30CryptoEngine(std::auto_ptr<wvcdm::FileSystem> file_system)
|
||||
: CryptoEngine(file_system) {}
|
||||
|
||||
bool config_local_display_only() { return true; }
|
||||
|
||||
// Returns the max HDCP version supported.
|
||||
OEMCrypto_HDCP_Capability config_maximum_hdcp_capability() {
|
||||
return HDCP_NO_DIGITAL_OUTPUT;
|
||||
}
|
||||
|
||||
// Returns true if the client supports persistent storage of
|
||||
// offline usage table information.
|
||||
bool config_supports_usage_table() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns true if the client uses a keybox as the root of trust.
|
||||
bool config_supports_keybox() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This version uses an OEM Certificate.
|
||||
OEMCrypto_ProvisioningMethod config_provisioning_method() {
|
||||
return OEMCrypto_OEMCertificate;
|
||||
}
|
||||
|
||||
OEMCryptoResult get_oem_certificate(SessionContext* session,
|
||||
uint8_t* public_cert,
|
||||
size_t* public_cert_length) {
|
||||
if (kOEMPublicCertSize == 0) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
if (public_cert_length == NULL) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (*public_cert_length < kOEMPublicCertSize) {
|
||||
*public_cert_length = kOEMPublicCertSize;
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
*public_cert_length = kOEMPublicCertSize;
|
||||
if (public_cert == NULL) {
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
memcpy(public_cert, kOEMPublicCert, kOEMPublicCertSize);
|
||||
if (!session->LoadRSAKey(kOEMPrivateKey, kOEMPrivateKeySize)) {
|
||||
LOGE("Private RSA Key did not load correctly.");
|
||||
return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
// Returns "L3" for a software only library. L1 is for hardware protected
|
||||
// keys and data paths. L2 is for hardware protected keys but no data path
|
||||
// protection.
|
||||
const char* config_security_level() { return "L2"; }
|
||||
};
|
||||
|
||||
CryptoEngine* CryptoEngine::MakeCryptoEngine(
|
||||
std::auto_ptr<wvcdm::FileSystem> file_system) {
|
||||
return new Prov30CryptoEngine(file_system);
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
124
mock/src/oemcrypto_engine_mock.cpp
Normal file
124
mock/src/oemcrypto_engine_mock.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
#include "oemcrypto_engine_mock.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "keys.h"
|
||||
#include "log.h"
|
||||
#include "oemcrypto_key_mock.h"
|
||||
#include "oemcrypto_rsa_key_shared.h"
|
||||
#include "string_conversions.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
// Note: The class CryptoEngine is configured at compile time by compiling in
|
||||
// different device property files. The methods in this file are generic to
|
||||
// all configurations. See the files oemcrypto_engine_device_properties*.cpp
|
||||
// for methods that are configured for specific configurations.
|
||||
|
||||
CryptoEngine::CryptoEngine(std::auto_ptr<wvcdm::FileSystem> file_system)
|
||||
: root_of_trust_(config_provisioning_method()),
|
||||
file_system_(file_system),
|
||||
usage_table_(this) {
|
||||
ERR_load_crypto_strings();
|
||||
}
|
||||
|
||||
CryptoEngine::~CryptoEngine() {
|
||||
wvcdm::AutoLock lock(session_table_lock_);
|
||||
ActiveSessions::iterator it;
|
||||
for (it = sessions_.begin(); it != sessions_.end(); ++it) {
|
||||
delete it->second;
|
||||
}
|
||||
sessions_.clear();
|
||||
ERR_free_strings();
|
||||
}
|
||||
|
||||
SessionId CryptoEngine::CreateSession() {
|
||||
wvcdm::AutoLock lock(session_table_lock_);
|
||||
static int unique_id = 1;
|
||||
SessionId sid = (SessionId)++unique_id;
|
||||
SessionContext* sctx =
|
||||
new SessionContext(this, sid, root_of_trust_.SharedRsaKey());
|
||||
sessions_[sid] = sctx;
|
||||
return sid;
|
||||
}
|
||||
|
||||
bool CryptoEngine::DestroySession(SessionId sid) {
|
||||
SessionContext* sctx = FindSession(sid);
|
||||
wvcdm::AutoLock lock(session_table_lock_);
|
||||
if (sctx) {
|
||||
sessions_.erase(sid);
|
||||
delete sctx;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SessionContext* CryptoEngine::FindSession(SessionId sid) {
|
||||
wvcdm::AutoLock lock(session_table_lock_);
|
||||
ActiveSessions::iterator it = sessions_.find(sid);
|
||||
if (it != sessions_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OEMCrypto_HDCP_Capability CryptoEngine::config_current_hdcp_capability() {
|
||||
return config_local_display_only() ? HDCP_NO_DIGITAL_OUTPUT : HDCP_V1;
|
||||
}
|
||||
|
||||
OEMCrypto_HDCP_Capability CryptoEngine::config_maximum_hdcp_capability() {
|
||||
return HDCP_NO_DIGITAL_OUTPUT;
|
||||
}
|
||||
|
||||
OEMCryptoResult CryptoEngine::SetDestination(
|
||||
OEMCrypto_DestBufferDesc* out_description, size_t data_length,
|
||||
uint8_t subsample_flags) {
|
||||
size_t max_length = 0;
|
||||
switch (out_description->type) {
|
||||
case OEMCrypto_BufferType_Clear:
|
||||
destination_ = out_description->buffer.clear.address;
|
||||
max_length = out_description->buffer.clear.max_length;
|
||||
break;
|
||||
case OEMCrypto_BufferType_Secure:
|
||||
destination_ =
|
||||
reinterpret_cast<uint8_t*>(out_description->buffer.secure.handle) +
|
||||
out_description->buffer.secure.offset;
|
||||
max_length = out_description->buffer.secure.max_length -
|
||||
out_description->buffer.secure.offset;
|
||||
break;
|
||||
case OEMCrypto_BufferType_Direct:
|
||||
// Direct buffer type is only used on some specialized devices where
|
||||
// oemcrypto has a direct connection to the screen buffer. It is not,
|
||||
// for example, supported on Android.
|
||||
destination_ = NULL;
|
||||
break;
|
||||
default:
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if (out_description->type != OEMCrypto_BufferType_Direct &&
|
||||
max_length < data_length) {
|
||||
LOGE("[SetDestination(): OEMCrypto_ERROR_SHORT_BUFFER]");
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
adjust_destination(out_description, data_length, subsample_flags);
|
||||
if ((out_description->type != OEMCrypto_BufferType_Direct) &&
|
||||
(destination_ == NULL)) {
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
183
mock/src/oemcrypto_engine_mock.h
Normal file
183
mock/src/oemcrypto_engine_mock.h
Normal file
@@ -0,0 +1,183 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
#ifndef MOCK_OEMCRYPTO_ENGINE_MOCK_H_
|
||||
#define MOCK_OEMCRYPTO_ENGINE_MOCK_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include "OEMCryptoCENC.h" // Needed for enums only.
|
||||
#include "file_store.h"
|
||||
#include "lock.h"
|
||||
#include "oemcrypto_auth_mock.h"
|
||||
#include "oemcrypto_key_mock.h"
|
||||
#include "oemcrypto_rsa_key_shared.h"
|
||||
#include "oemcrypto_session.h"
|
||||
#include "oemcrypto_usage_table_mock.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
typedef std::map<SessionId, SessionContext*> ActiveSessions;
|
||||
|
||||
class CryptoEngine {
|
||||
public:
|
||||
// This is like a factory method, except we choose which version to use at
|
||||
// compile time. It is defined in several source files. The build system
|
||||
// should choose which one to use by only linking in the correct one.
|
||||
// NOTE: The caller must instantiate a FileSystem object - ownership
|
||||
// will be transferred to the new CryptoEngine object.
|
||||
static CryptoEngine* MakeCryptoEngine(
|
||||
std::auto_ptr<wvcdm::FileSystem> file_system);
|
||||
|
||||
virtual ~CryptoEngine();
|
||||
|
||||
virtual bool Initialize() { return true; }
|
||||
|
||||
bool ValidRootOfTrust() { return root_of_trust_.Validate(); }
|
||||
|
||||
bool InstallKeybox(const uint8_t* keybox, size_t keybox_length) {
|
||||
return root_of_trust_.InstallKeybox(keybox, keybox_length);
|
||||
}
|
||||
|
||||
bool UseTestKeybox(const uint8_t* keybox_data, size_t keybox_length) {
|
||||
return root_of_trust_.UseTestKeybox(keybox_data, keybox_length);
|
||||
}
|
||||
|
||||
bool LoadTestRsaKey() { return root_of_trust_.LoadTestRsaKey(); }
|
||||
|
||||
KeyboxError ValidateKeybox() { return root_of_trust_.ValidateKeybox(); }
|
||||
|
||||
const std::vector<uint8_t>& DeviceRootKey(bool override_to_real = false) {
|
||||
return root_of_trust_.DeviceKey(override_to_real);
|
||||
}
|
||||
|
||||
const std::vector<uint8_t>& DeviceRootId() {
|
||||
return root_of_trust_.DeviceId();
|
||||
}
|
||||
|
||||
size_t DeviceRootTokenLength() { return root_of_trust_.DeviceTokenLength(); }
|
||||
|
||||
const uint8_t* DeviceRootToken() {
|
||||
return root_of_trust_.DeviceToken();
|
||||
}
|
||||
|
||||
virtual void Terminate() {}
|
||||
|
||||
SessionId CreateSession();
|
||||
|
||||
bool DestroySession(SessionId sid);
|
||||
|
||||
SessionContext* FindSession(SessionId sid);
|
||||
|
||||
size_t GetNumberOfOpenSessions() { return sessions_.size(); }
|
||||
|
||||
size_t GetMaxNumberOfSessions() {
|
||||
// An arbitrary limit for mock implementation.
|
||||
static const size_t kMaxSupportedOEMCryptoSessions = 64;
|
||||
return kMaxSupportedOEMCryptoSessions;
|
||||
}
|
||||
|
||||
// Returns the HDCP version currently in use.
|
||||
virtual OEMCrypto_HDCP_Capability config_current_hdcp_capability();
|
||||
|
||||
// Returns the max HDCP version supported.
|
||||
virtual OEMCrypto_HDCP_Capability config_maximum_hdcp_capability();
|
||||
|
||||
UsageTable& usage_table() { return usage_table_; }
|
||||
wvcdm::FileSystem* file_system() { return file_system_.get(); }
|
||||
|
||||
// If config_local_display_only() returns true, we pretend we are using a
|
||||
// built-in display, instead of HDMI or WiFi output.
|
||||
virtual bool config_local_display_only() { return false; }
|
||||
|
||||
// A closed platform is permitted to use clear buffers.
|
||||
virtual bool config_closed_platform() { return false; }
|
||||
|
||||
// Returns true if the client supports persistent storage of
|
||||
// offline usage table information.
|
||||
virtual bool config_supports_usage_table() { return true; }
|
||||
|
||||
virtual OEMCrypto_ProvisioningMethod config_provisioning_method() {
|
||||
return OEMCrypto_Keybox;
|
||||
}
|
||||
|
||||
virtual OEMCryptoResult get_oem_certificate(SessionContext* session,
|
||||
uint8_t* public_cert,
|
||||
size_t* public_cert_length) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// Used for OEMCrypto_IsAntiRollbackHwPresent.
|
||||
virtual bool config_is_anti_rollback_hw_present() { return false; }
|
||||
|
||||
// Returns "L3" for a software only library. L1 is for hardware protected
|
||||
// data paths.
|
||||
virtual const char* config_security_level() { return "L3"; }
|
||||
|
||||
// This should start at 0, and be incremented only when a security patch has
|
||||
// been applied to the device that fixes a security bug.
|
||||
virtual uint8_t config_security_patch_level() { return 0; }
|
||||
|
||||
// If 0 no restriction, otherwise it's the max buffer for DecryptCENC.
|
||||
virtual size_t max_buffer_size() { return 1024 * 100; } // 100 KiB.
|
||||
|
||||
virtual bool srm_update_supported() { return false; }
|
||||
|
||||
virtual OEMCryptoResult current_srm_version(uint16_t* version) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
virtual OEMCryptoResult load_srm(const uint8_t* buffer,
|
||||
size_t buffer_length) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
virtual OEMCryptoResult remove_srm() {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
virtual bool srm_blacklisted_device_attached() { return false; }
|
||||
|
||||
// Set destination pointer based on the output destination description.
|
||||
OEMCryptoResult SetDestination(OEMCrypto_DestBufferDesc* out_description,
|
||||
size_t data_length, uint8_t subsample_flags);
|
||||
|
||||
// The current destination.
|
||||
uint8_t* destination() { return destination_; }
|
||||
|
||||
// Subclasses can adjust the destination -- for use in testing.
|
||||
virtual void adjust_destination(OEMCrypto_DestBufferDesc* out_description,
|
||||
size_t data_length, uint8_t subsample_flags) {
|
||||
}
|
||||
|
||||
// Push destination buffer to output -- used by subclasses for testing.
|
||||
virtual OEMCryptoResult PushDestination(
|
||||
OEMCrypto_DestBufferDesc* out_description, uint8_t subsample_flags) {
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit CryptoEngine(std::auto_ptr<wvcdm::FileSystem> file_system);
|
||||
uint8_t* destination_;
|
||||
|
||||
private:
|
||||
ActiveSessions sessions_;
|
||||
AuthenticationRoot root_of_trust_;
|
||||
wvcdm::Lock session_table_lock_;
|
||||
std::auto_ptr<wvcdm::FileSystem> file_system_;
|
||||
UsageTable usage_table_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(CryptoEngine);
|
||||
};
|
||||
|
||||
} // namespace wvoec_mock
|
||||
|
||||
#endif // MOCK_OEMCRYPTO_ENGINE_MOCK_H_
|
||||
122
mock/src/oemcrypto_key_mock.cpp
Normal file
122
mock/src/oemcrypto_key_mock.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
#include "oemcrypto_key_mock.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
#include "log.h"
|
||||
#include "oemcrypto_logging.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
bool KeyControlBlock::Validate() {
|
||||
if (memcmp(verification_, "kctl", 4) && // original verification
|
||||
memcmp(verification_, "kc09", 4) && // add in version 9 api
|
||||
memcmp(verification_, "kc10", 4) && // add in version 10 api
|
||||
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
|
||||
LOGE("KCB: BAD verification string: %4.4s", verification_);
|
||||
valid_ = false;
|
||||
} else {
|
||||
valid_ = true;
|
||||
}
|
||||
return valid_;
|
||||
}
|
||||
|
||||
// This extracts 4 bytes in network byte order to a 32 bit integer in
|
||||
// host byte order.
|
||||
uint32_t KeyControlBlock::ExtractField(const std::vector<uint8_t>& str,
|
||||
int idx) {
|
||||
int bidx = idx * 4;
|
||||
uint32_t t = static_cast<unsigned char>(str[bidx]) << 24;
|
||||
t |= static_cast<unsigned char>(str[bidx + 1]) << 16;
|
||||
t |= static_cast<unsigned char>(str[bidx + 2]) << 8;
|
||||
t |= static_cast<unsigned char>(str[bidx + 3]);
|
||||
return t;
|
||||
}
|
||||
|
||||
KeyControlBlock::KeyControlBlock(
|
||||
const std::vector<uint8_t>& key_control_string) {
|
||||
if (key_control_string.size() < wvcdm::KEY_CONTROL_SIZE) {
|
||||
LOGE("KCB: BAD Size: %d (not %d)", key_control_string.size(),
|
||||
wvcdm::KEY_CONTROL_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(verification_, &key_control_string[0], 4);
|
||||
duration_ = ExtractField(key_control_string, 1);
|
||||
nonce_ = ExtractField(key_control_string, 2);
|
||||
control_bits_ = ExtractField(key_control_string, 3);
|
||||
if (LogCategoryEnabled(kLoggingDumpKeyControlBlocks)) {
|
||||
LOGD("KCB:");
|
||||
LOGD(" valid: %d", valid());
|
||||
LOGD(" duration: %d", duration());
|
||||
LOGD(" nonce: %08X", nonce());
|
||||
LOGD(" magic: %08X", verification());
|
||||
LOGD(" bits: %08X", control_bits());
|
||||
LOGD(" bit kSharedLicense %s.",
|
||||
(control_bits() & kSharedLicense) ? "set" : "unset");
|
||||
LOGD(" bit kControlSRMVersionRequired %s.",
|
||||
(control_bits() & kControlSRMVersionRequired) ? "set" : "unset");
|
||||
LOGD(" bit kControlDisableAnalogOutput %s.",
|
||||
(control_bits() & kControlDisableAnalogOutput) ? "set" : "unset");
|
||||
LOGD(" bits kControlSecurityPatchLevel 0x%02x.",
|
||||
(control_bits() & kControlSecurityPatchLevelMask)
|
||||
>> kControlSecurityPatchLevelShift);
|
||||
switch (control_bits() & kControlReplayMask) {
|
||||
case kControlNonceRequired:
|
||||
LOGD(" bits kControlReplay kControlNonceRequired.");
|
||||
break;
|
||||
case kControlNonceOrEntry:
|
||||
LOGD(" bits kControlReplay kControlNonceOrEntry.");
|
||||
break;
|
||||
default:
|
||||
LOGD(" bits kControlReplay unset.");
|
||||
break;
|
||||
}
|
||||
LOGD(" bits kControlHDCPVersion 0x%02x.",
|
||||
(control_bits() & kControlHDCPVersionMask)
|
||||
>> kControlHDCPVersionShift);
|
||||
LOGD(" bit kControlAllowEncrypt %s.",
|
||||
(control_bits() & kControlAllowEncrypt) ? "set" : "unset");
|
||||
LOGD(" bit kControlAllowDecrypt %s.",
|
||||
(control_bits() & kControlAllowDecrypt) ? "set" : "unset");
|
||||
LOGD(" bit kControlAllowSign %s.",
|
||||
(control_bits() & kControlAllowSign) ? "set" : "unset");
|
||||
LOGD(" bit kControlAllowVerify %s.",
|
||||
(control_bits() & kControlAllowVerify) ? "set" : "unset");
|
||||
LOGD(" bit kControlObserveDataPath %s.",
|
||||
(control_bits() & kControlObserveDataPath) ? "set" : "unset");
|
||||
LOGD(" bit kControlObserveHDCP %s.",
|
||||
(control_bits() & kControlObserveHDCP) ? "set" : "unset");
|
||||
LOGD(" bit kControlObserveCGMS %s.",
|
||||
(control_bits() & kControlObserveCGMS) ? "set" : "unset");
|
||||
LOGD(" bit kControlDataPathSecure %s.",
|
||||
(control_bits() & kControlDataPathSecure) ? "set" : "unset");
|
||||
LOGD(" bit kControlNonceEnabled %s.",
|
||||
(control_bits() & kControlNonceEnabled) ? "set" : "unset");
|
||||
LOGD(" bit kControlHDCPRequired %s.",
|
||||
(control_bits() & kControlHDCPRequired) ? "set" : "unset");
|
||||
uint32_t cgms_bits = control_bits() & 0x3;
|
||||
const char* cgms_values[4] = {"free", "BAD", "once", "never"};
|
||||
LOGD(" CGMS = %s", cgms_values[cgms_bits]);
|
||||
}
|
||||
Validate();
|
||||
}
|
||||
|
||||
void Key::UpdateDuration(const KeyControlBlock& control) {
|
||||
control_.set_duration(control.duration());
|
||||
}
|
||||
|
||||
void KeyControlBlock::RequireLocalDisplay() {
|
||||
// Set all bits to require HDCP Local Display Only.
|
||||
control_bits_ |= kControlHDCPVersionMask;
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
112
mock/src/oemcrypto_key_mock.h
Normal file
112
mock/src/oemcrypto_key_mock.h
Normal file
@@ -0,0 +1,112 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
#ifndef OEMCRYPTO_KEY_MOCK_H_
|
||||
#define OEMCRYPTO_KEY_MOCK_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
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 kSharedLicense = (1<<23);
|
||||
const uint32_t kControlSRMVersionRequired = (1<<22);
|
||||
const uint32_t kControlDisableAnalogOutput = (1<<21);
|
||||
const uint32_t kControlSecurityPatchLevelShift = 15;
|
||||
const uint32_t kControlSecurityPatchLevelMask =
|
||||
(0x3F<<kControlSecurityPatchLevelShift);
|
||||
const uint32_t kControlReplayMask = (0x03<<13);
|
||||
const uint32_t kControlNonceRequired = (0x01<<13);
|
||||
const uint32_t kControlNonceOrEntry = (0x02<<13);
|
||||
const uint32_t kControlHDCPVersionShift = 9;
|
||||
const uint32_t kControlHDCPVersionMask = (0x0F<<kControlHDCPVersionShift);
|
||||
const uint32_t kControlAllowEncrypt = (1<<8);
|
||||
const uint32_t kControlAllowDecrypt = (1<<7);
|
||||
const uint32_t kControlAllowSign = (1<<6);
|
||||
const uint32_t kControlAllowVerify = (1<<5);
|
||||
const uint32_t kControlDataPathSecure = (1<<4);
|
||||
const uint32_t kControlNonceEnabled = (1<<3);
|
||||
const uint32_t kControlHDCPRequired = (1<<2);
|
||||
const uint32_t kControlCGMSMask = (0x03);
|
||||
const uint32_t kControlCGMSCopyFreely = (0x00);
|
||||
const uint32_t kControlCGMSCopyOnce = (0x02);
|
||||
const uint32_t kControlCGMSCopyNever = (0x03);
|
||||
|
||||
class KeyControlBlock {
|
||||
public:
|
||||
KeyControlBlock(const std::vector<uint8_t>& key_control_string);
|
||||
~KeyControlBlock() {}
|
||||
|
||||
bool Validate();
|
||||
void Invalidate() { valid_ = false; }
|
||||
|
||||
bool valid() const { return valid_; }
|
||||
uint32_t duration() const { return duration_; }
|
||||
void set_duration(uint32_t duration) { duration_ = duration; }
|
||||
uint32_t nonce() const { return nonce_; }
|
||||
const char* verification() const { return verification_; }
|
||||
uint32_t control_bits() const { return control_bits_; }
|
||||
void RequireLocalDisplay();
|
||||
|
||||
private:
|
||||
uint32_t ExtractField(const std::vector<uint8_t>& str, int idx);
|
||||
|
||||
bool valid_;
|
||||
char verification_[4];
|
||||
uint32_t duration_;
|
||||
uint32_t nonce_;
|
||||
uint32_t control_bits_;
|
||||
};
|
||||
|
||||
// AES-128 crypto key, or HMAC signing key.
|
||||
class Key {
|
||||
public:
|
||||
Key(const Key& key)
|
||||
: value_(key.value_), control_(key.control_), ctr_mode_(key.ctr_mode_) {}
|
||||
Key(const std::vector<uint8_t>& key_string, const KeyControlBlock& control)
|
||||
: value_(key_string), control_(control), ctr_mode_(true){};
|
||||
|
||||
virtual ~Key(){};
|
||||
void UpdateDuration(const KeyControlBlock& control);
|
||||
virtual const std::vector<uint8_t>& value() const { return value_; }
|
||||
const KeyControlBlock& control() const { return control_; }
|
||||
bool ctr_mode() const { return ctr_mode_; }
|
||||
void set_ctr_mode(bool ctr_mode) { ctr_mode_ = ctr_mode; }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> value_;
|
||||
KeyControlBlock control_;
|
||||
bool ctr_mode_;
|
||||
};
|
||||
|
||||
// AES-256 entitlement key. |Key| holds the entitlement key. |EntitlementKey|
|
||||
// holds the content key.
|
||||
class EntitlementKey : public Key {
|
||||
public:
|
||||
EntitlementKey(const Key& key) : Key(key) {}
|
||||
virtual ~EntitlementKey() {}
|
||||
virtual const std::vector<uint8_t>& value() const { return content_key_; }
|
||||
const std::vector<uint8_t>& content_key() { return content_key_; }
|
||||
const std::vector<uint8_t>& content_key_id() { return content_key_id_; }
|
||||
const std::vector<uint8_t>& entitlement_key() { return Key::value(); }
|
||||
bool SetContentKey(const std::vector<uint8_t>& content_key,
|
||||
const std::vector<uint8_t>& content_key_id) {
|
||||
content_key_.assign(content_key.begin(), content_key.end());
|
||||
content_key_id_.assign(content_key_id.begin(), content_key_id.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> content_key_;
|
||||
std::vector<uint8_t> content_key_id_;
|
||||
};
|
||||
|
||||
} // namespace wvoec_mock
|
||||
|
||||
#endif // OEMCRYPTO_KEY_MOCK_H_
|
||||
112
mock/src/oemcrypto_keybox_mock.cpp
Normal file
112
mock/src/oemcrypto_keybox_mock.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
#include "oemcrypto_keybox_mock.h"
|
||||
|
||||
#include <arpa/inet.h> // needed for ntoh()
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <string>
|
||||
#include "log.h"
|
||||
#include "wv_keybox.h"
|
||||
#include "wvcrc32.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
namespace {
|
||||
|
||||
const WidevineKeybox kTestKeybox = {
|
||||
// Sample keybox used for test vectors
|
||||
{
|
||||
// deviceID
|
||||
0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x30, // TestKey01
|
||||
0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
|
||||
}, {
|
||||
// key
|
||||
0xfb, 0xda, 0x04, 0x89, 0xa1, 0x58, 0x16, 0x0e,
|
||||
0xa4, 0x02, 0xe9, 0x29, 0xe3, 0xb6, 0x8f, 0x04,
|
||||
}, {
|
||||
// data
|
||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x19,
|
||||
0x07, 0xd9, 0xff, 0xde, 0x13, 0xaa, 0x95, 0xc1,
|
||||
0x22, 0x67, 0x80, 0x53, 0x36, 0x21, 0x36, 0xbd,
|
||||
0xf8, 0x40, 0x8f, 0x82, 0x76, 0xe4, 0xc2, 0xd8,
|
||||
0x7e, 0xc5, 0x2b, 0x61, 0xaa, 0x1b, 0x9f, 0x64,
|
||||
0x6e, 0x58, 0x73, 0x49, 0x30, 0xac, 0xeb, 0xe8,
|
||||
0x99, 0xb3, 0xe4, 0x64, 0x18, 0x9a, 0x14, 0xa8,
|
||||
0x72, 0x02, 0xfb, 0x02, 0x57, 0x4e, 0x70, 0x64,
|
||||
0x0b, 0xd2, 0x2e, 0xf4, 0x4b, 0x2d, 0x7e, 0x39,
|
||||
}, {
|
||||
// magic
|
||||
0x6b, 0x62, 0x6f, 0x78,
|
||||
}, {
|
||||
// Crc
|
||||
0x0a, 0x7a, 0x2c, 0x35,
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
WvKeybox::WvKeybox() {
|
||||
valid_ = Prepare();
|
||||
}
|
||||
|
||||
KeyboxError WvKeybox::Validate() {
|
||||
if (!valid_) {
|
||||
LOGE("[KEYBOX NOT LOADED]");
|
||||
return OTHER_ERROR;
|
||||
}
|
||||
if (strncmp(reinterpret_cast<char*>(magic_), "kbox", 4) != 0) {
|
||||
LOGE("[KEYBOX HAS BAD MAGIC]");
|
||||
return BAD_MAGIC;
|
||||
}
|
||||
uint32_t crc_computed;
|
||||
uint32_t crc_stored;
|
||||
uint8_t* crc_stored_bytes = (uint8_t*) &crc_stored;
|
||||
memcpy(crc_stored_bytes, crc_, sizeof(crc_));
|
||||
WidevineKeybox keybox;
|
||||
memset(&keybox, 0, sizeof(keybox));
|
||||
memcpy(keybox.device_id_, &device_id_[0], device_id_.size());
|
||||
memcpy(keybox.device_key_, &device_key_[0], sizeof(keybox.device_key_));
|
||||
memcpy(keybox.data_, key_data_, sizeof(keybox.data_));
|
||||
memcpy(keybox.magic_, magic_, sizeof(keybox.magic_));
|
||||
|
||||
crc_computed = ntohl(wvcrc32(reinterpret_cast<uint8_t*>(&keybox),
|
||||
sizeof(keybox) - 4)); // Drop last 4 bytes.
|
||||
if (crc_computed != crc_stored) {
|
||||
LOGE("[KEYBOX CRC problem: computed = %08x, stored = %08x]\n",
|
||||
crc_computed, crc_stored);
|
||||
return BAD_CRC;
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
bool WvKeybox::InstallKeybox(const uint8_t* buffer, size_t keyBoxLength) {
|
||||
if (keyBoxLength != 128) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const WidevineKeybox* keybox
|
||||
= reinterpret_cast<const WidevineKeybox*>(buffer);
|
||||
size_t device_id_length
|
||||
= strnlen(reinterpret_cast<const char*>(keybox->device_id_), 32);
|
||||
device_id_.assign(keybox->device_id_,
|
||||
keybox->device_id_ + device_id_length);
|
||||
device_key_.assign(keybox->device_key_,
|
||||
keybox->device_key_ + sizeof(keybox->device_key_));
|
||||
memcpy(key_data_, keybox->data_, sizeof(keybox->data_));
|
||||
memcpy(magic_, keybox->magic_, sizeof(keybox->magic_));
|
||||
memcpy(crc_, keybox->crc_, sizeof(keybox->crc_));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
WvTestKeybox::WvTestKeybox() {
|
||||
InstallKeybox(reinterpret_cast<const uint8_t*>(&kTestKeybox),
|
||||
sizeof(kTestKeybox));
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
51
mock/src/oemcrypto_keybox_mock.h
Normal file
51
mock/src/oemcrypto_keybox_mock.h
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
#ifndef OEMCRYPTO_KEYBOX_MOCK_H_
|
||||
#define OEMCRYPTO_KEYBOX_MOCK_H_
|
||||
|
||||
#include "oemcrypto_key_mock.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
const int DEVICE_KEY_LENGTH = 16;
|
||||
typedef uint8_t WvKeyboxKey[DEVICE_KEY_LENGTH];
|
||||
|
||||
const int KEY_DATA_LENGTH = 72;
|
||||
typedef uint8_t WvKeyboxKeyData[KEY_DATA_LENGTH];
|
||||
|
||||
enum KeyboxError { NO_ERROR, BAD_CRC, BAD_MAGIC, OTHER_ERROR };
|
||||
|
||||
// Widevine keybox
|
||||
class WvKeybox {
|
||||
public:
|
||||
WvKeybox();
|
||||
~WvKeybox() {}
|
||||
|
||||
KeyboxError Validate();
|
||||
const std::vector<uint8_t>& device_id() { return device_id_; }
|
||||
std::vector<uint8_t>& device_key() { return device_key_; }
|
||||
const WvKeyboxKeyData& key_data() { return key_data_; }
|
||||
size_t key_data_length() { return KEY_DATA_LENGTH; }
|
||||
bool InstallKeybox(const uint8_t* keybox, size_t keyBoxLength);
|
||||
|
||||
private:
|
||||
bool Prepare();
|
||||
|
||||
bool valid_;
|
||||
std::vector<uint8_t> device_id_;
|
||||
std::vector<uint8_t> device_key_;
|
||||
WvKeyboxKeyData key_data_;
|
||||
uint8_t magic_[4];
|
||||
uint8_t crc_[4];
|
||||
};
|
||||
|
||||
class WvTestKeybox : public WvKeybox {
|
||||
public:
|
||||
WvTestKeybox();
|
||||
};
|
||||
|
||||
} // namespace wvoec_mock
|
||||
|
||||
#endif // OEMCRYPTO_KEYBOX_MOCK_H_
|
||||
54
mock/src/oemcrypto_keybox_testkey.cpp
Normal file
54
mock/src/oemcrypto_keybox_testkey.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Test keybox.
|
||||
|
||||
#include "oemcrypto_keybox_mock.h"
|
||||
#include "wv_keybox.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
namespace {
|
||||
|
||||
// Note: this is a valid keybox, but it is not accepted by production servers.
|
||||
// However, it is different from the one used for most of the unit tests.
|
||||
const WidevineKeybox kKeybox = {
|
||||
// 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, // ........
|
||||
}, {
|
||||
// key
|
||||
0x76, 0x5d, 0xce, 0x01, 0x04, 0x89, 0xb3, 0xd0,
|
||||
0xdf, 0xce, 0x54, 0x8a, 0x49, 0xda, 0xdc, 0xb6,
|
||||
}, {
|
||||
// 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,
|
||||
}, {
|
||||
// magic
|
||||
0x6b, 0x62, 0x6f, 0x78,
|
||||
}, {
|
||||
// Crc
|
||||
0x2a, 0x3b, 0x3e, 0xe4,
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
bool WvKeybox::Prepare() {
|
||||
InstallKeybox(reinterpret_cast<const uint8_t*>(&kKeybox),
|
||||
sizeof(kKeybox));
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
104
mock/src/oemcrypto_logging.cpp
Normal file
104
mock/src/oemcrypto_logging.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
|
||||
#include "oemcrypto_logging.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
int logging_category_setting = 0x00;
|
||||
|
||||
void SetLoggingSettings(int level, int categories) {
|
||||
SetLoggingLevel(level);
|
||||
TurnOffLoggingForAllCategories();
|
||||
AddLoggingForCategories(categories);
|
||||
}
|
||||
|
||||
void TurnOffLoggingForAllCategories() { logging_category_setting = 0; }
|
||||
|
||||
void SetLoggingLevel(int level) {
|
||||
wvcdm::g_cutoff = static_cast<wvcdm::LogPriority>(level);
|
||||
}
|
||||
|
||||
void SetLoggingLevel(wvcdm::LogPriority level) { wvcdm::g_cutoff = level; }
|
||||
|
||||
void AddLoggingForCategories(int categories) {
|
||||
logging_category_setting |= categories;
|
||||
}
|
||||
|
||||
void RemoveLoggingForCategories(int categories) {
|
||||
logging_category_setting &= ~categories;
|
||||
}
|
||||
|
||||
bool LogCategoryEnabled(int categories) {
|
||||
return ((logging_category_setting & categories) != 0);
|
||||
}
|
||||
|
||||
void dump_hex_helper(std::string& buffer, std::string name,
|
||||
const uint8_t* vector, size_t length) {
|
||||
buffer += name + " = ";
|
||||
if (vector == NULL) {
|
||||
buffer += "NULL;\n";
|
||||
LOGE(buffer.c_str());
|
||||
return;
|
||||
}
|
||||
int a, b;
|
||||
char int_to_hexcar[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
if (i == 0) {
|
||||
buffer += "\n wvcdm::a2b_hex(\"";
|
||||
} else if (i % 32 == 0) {
|
||||
buffer += "\"\n \"";
|
||||
}
|
||||
a = vector[i] % 16;
|
||||
b = (vector[i] - a) / 16;
|
||||
buffer += int_to_hexcar[b];
|
||||
buffer += int_to_hexcar[a];
|
||||
}
|
||||
buffer += "\");\n";
|
||||
}
|
||||
|
||||
void dump_hex(std::string name, const uint8_t* vector, size_t length) {
|
||||
std::string buffer = "";
|
||||
dump_hex_helper(buffer, name, vector, length);
|
||||
LOGV(buffer.c_str());
|
||||
}
|
||||
|
||||
void dump_array_part_helper(std::string& buffer, std::string array,
|
||||
size_t index, std::string name,
|
||||
const uint8_t* vector, size_t length) {
|
||||
char index_str[256];
|
||||
|
||||
snprintf(index_str, sizeof index_str, "%zu", index);
|
||||
|
||||
if (vector == NULL) {
|
||||
buffer += array.c_str();
|
||||
buffer += "[";
|
||||
buffer += index_str;
|
||||
buffer += "].";
|
||||
buffer += name.c_str();
|
||||
buffer += " = NULL;\n";
|
||||
LOGW(buffer.c_str());
|
||||
return;
|
||||
}
|
||||
buffer += "std::string s";
|
||||
buffer += index_str;
|
||||
buffer += "_";
|
||||
dump_hex_helper(buffer, name, vector, length);
|
||||
buffer += array.c_str();
|
||||
buffer += "[";
|
||||
buffer += index_str;
|
||||
buffer += "]." + name + " = message_ptr + message.find(s";
|
||||
buffer += index_str;
|
||||
buffer += "_" + name + ".data());\n";
|
||||
}
|
||||
|
||||
void dump_array_part(std::string array, size_t index, std::string name,
|
||||
const uint8_t* vector, size_t length) {
|
||||
std::string buffer = "";
|
||||
dump_array_part_helper(buffer, array, index, name, vector, length);
|
||||
LOGV(buffer.c_str());
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
1958
mock/src/oemcrypto_mock.cpp
Normal file
1958
mock/src/oemcrypto_mock.cpp
Normal file
File diff suppressed because it is too large
Load Diff
67
mock/src/oemcrypto_nonce_table.cpp
Normal file
67
mock/src/oemcrypto_nonce_table.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
#include "oemcrypto_nonce_table.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
void NonceTable::AddNonce(uint32_t nonce) {
|
||||
int new_slot = -1;
|
||||
int oldest_slot = -1;
|
||||
|
||||
// Flush any nonces that have been checked but not flushed.
|
||||
// After flush, nonces will be either valid or invalid.
|
||||
Flush();
|
||||
|
||||
for (int i = 0; i < kTableSize; ++i) {
|
||||
// Increase age of all valid nonces.
|
||||
if (kNTStateValid == state_[i]) {
|
||||
++age_[i];
|
||||
if (-1 == oldest_slot) {
|
||||
oldest_slot = i;
|
||||
} else {
|
||||
if (age_[i] > age_[oldest_slot]) {
|
||||
oldest_slot = i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (-1 == new_slot) {
|
||||
age_[i] = 0;
|
||||
nonces_[i] = nonce;
|
||||
state_[i] = kNTStateValid;
|
||||
new_slot = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (-1 == new_slot) {
|
||||
// reuse oldest
|
||||
// assert (oldest_slot != -1)
|
||||
int i = oldest_slot;
|
||||
age_[i] = 0;
|
||||
nonces_[i] = nonce;
|
||||
state_[i] = kNTStateValid;
|
||||
}
|
||||
}
|
||||
|
||||
bool NonceTable::CheckNonce(uint32_t nonce) {
|
||||
for (int i = 0; i < kTableSize; ++i) {
|
||||
if (kNTStateInvalid != state_[i]) {
|
||||
if (nonce == nonces_[i]) {
|
||||
state_[i] = kNTStateFlushPending;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void NonceTable::Flush() {
|
||||
for (int i = 0; i < kTableSize; ++i) {
|
||||
if (kNTStateFlushPending == state_[i]) {
|
||||
state_[i] = kNTStateInvalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
38
mock/src/oemcrypto_nonce_table.h
Normal file
38
mock/src/oemcrypto_nonce_table.h
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
#ifndef MOCK_OEMCRYPTO_NONCE_TABLE_H_
|
||||
#define MOCK_OEMCRYPTO_NONCE_TABLE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
class NonceTable {
|
||||
public:
|
||||
static const int kTableSize = 16;
|
||||
NonceTable() {
|
||||
for (int i = 0; i < kTableSize; ++i) {
|
||||
state_[i] = kNTStateInvalid;
|
||||
}
|
||||
}
|
||||
~NonceTable() {}
|
||||
void AddNonce(uint32_t nonce);
|
||||
bool CheckNonce(uint32_t nonce);
|
||||
void Flush();
|
||||
|
||||
private:
|
||||
enum NonceTableState {
|
||||
kNTStateInvalid,
|
||||
kNTStateValid,
|
||||
kNTStateFlushPending
|
||||
};
|
||||
NonceTableState state_[kTableSize];
|
||||
uint32_t age_[kTableSize];
|
||||
uint32_t nonces_[kTableSize];
|
||||
};
|
||||
|
||||
} // namespace wvoec_mock
|
||||
|
||||
#endif // MOCK_OEMCRYPTO_NONCE_TABLE_H_
|
||||
240
mock/src/oemcrypto_old_usage_table_mock.cpp
Normal file
240
mock/src/oemcrypto_old_usage_table_mock.cpp
Normal file
@@ -0,0 +1,240 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
// This is from the v12 version of oemcrypto usage tables. It is used for
|
||||
// devices that upgrade from v12 to v13 in the field, and need to convert from
|
||||
// the old type of usage table to the new.
|
||||
#include "oemcrypto_old_usage_table_mock.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "file_store.h"
|
||||
#include "log.h"
|
||||
#include "oemcrypto_engine_mock.h"
|
||||
#include "oemcrypto_logging.h"
|
||||
#include "properties.h"
|
||||
#include "pst_report.h"
|
||||
#include "string_conversions.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
OldUsageTableEntry::OldUsageTableEntry(const std::vector<uint8_t> &pst_hash)
|
||||
: pst_hash_(pst_hash),
|
||||
time_of_license_received_(time(NULL)),
|
||||
time_of_first_decrypt_(0),
|
||||
time_of_last_decrypt_(0),
|
||||
status_(kUnused) {}
|
||||
|
||||
OldUsageTableEntry::~OldUsageTableEntry() {}
|
||||
|
||||
OldUsageTableEntry::OldUsageTableEntry(const OldStoredUsageEntry *buffer) {
|
||||
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;
|
||||
time_of_last_decrypt_ = buffer->time_of_last_decrypt;
|
||||
status_ = buffer->status;
|
||||
mac_key_server_.assign(buffer->mac_key_server,
|
||||
buffer->mac_key_server + wvcdm::MAC_KEY_SIZE);
|
||||
mac_key_client_.assign(buffer->mac_key_client,
|
||||
buffer->mac_key_client + wvcdm::MAC_KEY_SIZE);
|
||||
}
|
||||
|
||||
OldUsageTable::OldUsageTable(CryptoEngine *ce) {
|
||||
ce_ = ce;
|
||||
generation_ = 0;
|
||||
table_.clear();
|
||||
|
||||
// Load saved table.
|
||||
wvcdm::FileSystem* file_system = ce->file_system();
|
||||
wvcdm::File *file;
|
||||
std::string path;
|
||||
// Note: this path is OK for a real implementation, but using security level 1
|
||||
// would be better.
|
||||
if (!wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3,
|
||||
&path)) {
|
||||
LOGE("OldUsageTable: Unable to get base path");
|
||||
return;
|
||||
}
|
||||
std::string filename = path + "UsageTable.dat";
|
||||
if (!file_system->Exists(filename)) {
|
||||
if (LogCategoryEnabled(kLoggingTraceUsageTable)) {
|
||||
LOGI("OldUsageTable: No saved usage table. Creating new table.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
size_t file_size = file_system->FileSize(filename);
|
||||
std::vector<uint8_t> encrypted_buffer(file_size);
|
||||
std::vector<uint8_t> buffer(file_size);
|
||||
OldStoredUsageTable *stored_table =
|
||||
reinterpret_cast<OldStoredUsageTable *>(&buffer[0]);
|
||||
OldStoredUsageTable *encrypted_table =
|
||||
reinterpret_cast<OldStoredUsageTable *>(&encrypted_buffer[0]);
|
||||
|
||||
file = file_system->Open(filename, wvcdm::FileSystem::kReadOnly);
|
||||
if (!file) {
|
||||
LOGE("OldUsageTable: File open failed: %s", path.c_str());
|
||||
return;
|
||||
}
|
||||
file->Read(reinterpret_cast<char *>(&encrypted_buffer[0]), file_size);
|
||||
file->Close();
|
||||
|
||||
// Verify the signature of the usage table file.
|
||||
|
||||
// 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 bool override_to_real = true;
|
||||
const std::vector<uint8_t> &key = ce_->DeviceRootKey(override_to_real);
|
||||
|
||||
uint8_t computed_signature[SHA256_DIGEST_LENGTH];
|
||||
unsigned int sig_length = sizeof(computed_signature);
|
||||
if (!HMAC(EVP_sha256(), &key[0], key.size(),
|
||||
&encrypted_buffer[SHA256_DIGEST_LENGTH],
|
||||
file_size - SHA256_DIGEST_LENGTH, computed_signature,
|
||||
&sig_length)) {
|
||||
LOGE("OldUsageTable: Could not recreate signature.");
|
||||
table_.clear();
|
||||
return;
|
||||
}
|
||||
if (memcmp(encrypted_table->signature, computed_signature, sig_length)) {
|
||||
LOGE("OldUsageTable: Invalid signature given: %s",
|
||||
wvcdm::HexEncode(&encrypted_buffer[0], sig_length).c_str());
|
||||
LOGE("OldUsageTable: Invalid signature computed: %s",
|
||||
wvcdm::HexEncode(computed_signature, sig_length).c_str());
|
||||
table_.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Next, decrypt the table.
|
||||
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
|
||||
memcpy(iv_buffer, encrypted_table->iv, wvcdm::KEY_IV_SIZE);
|
||||
AES_KEY aes_key;
|
||||
AES_set_decrypt_key(&key[0], 128, &aes_key);
|
||||
AES_cbc_encrypt(&encrypted_buffer[SHA256_DIGEST_LENGTH + wvcdm::KEY_IV_SIZE],
|
||||
&buffer[SHA256_DIGEST_LENGTH + wvcdm::KEY_IV_SIZE],
|
||||
file_size - SHA256_DIGEST_LENGTH - wvcdm::KEY_IV_SIZE,
|
||||
&aes_key, iv_buffer, AES_DECRYPT);
|
||||
|
||||
// Next, read the generation number from a different location.
|
||||
// On a real implementation, you should NOT put the generation number in
|
||||
// a file in user space. It should be stored in secure memory. For the
|
||||
// reference implementation, we'll just pretend this is secure.
|
||||
std::string filename2 = path + "GenerationNumber.dat";
|
||||
file = file_system->Open(filename2, wvcdm::FileSystem::kReadOnly);
|
||||
if (!file) {
|
||||
LOGE("OldUsageTable: File open failed: %s (clearing table)", path.c_str());
|
||||
generation_ = 0;
|
||||
table_.clear();
|
||||
return;
|
||||
}
|
||||
file->Read(reinterpret_cast<char *>(&generation_), sizeof(int64_t));
|
||||
file->Close();
|
||||
if (stored_table->generation == generation_ + 1) {
|
||||
if (LogCategoryEnabled(kLoggingTraceUsageTable)) {
|
||||
LOGW("OldUsageTable: File is one generation old. Acceptable rollback.");
|
||||
}
|
||||
} else if (stored_table->generation == generation_ - 1) {
|
||||
if (LogCategoryEnabled(kLoggingTraceUsageTable)) {
|
||||
LOGW("OldUsageTable: File is one generation new. Acceptable rollback.");
|
||||
}
|
||||
// This might happen if the generation number was rolled back?
|
||||
} else if (stored_table->generation != generation_) {
|
||||
LOGE("OldUsageTable: Rollback detected. Clearing Usage Table. %lx -> %lx",
|
||||
generation_, stored_table->generation);
|
||||
table_.clear();
|
||||
generation_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point, the stored table looks valid. We can load in all the
|
||||
// entries.
|
||||
for (uint64_t i = 0; i < stored_table->count; i++) {
|
||||
OldUsageTableEntry *entry =
|
||||
new OldUsageTableEntry(&stored_table->entries[i].entry);
|
||||
table_[entry->pst_hash()] = entry;
|
||||
}
|
||||
if (LogCategoryEnabled(kLoggingTraceUsageTable)) {
|
||||
LOGI("OldUsageTable: loaded %d entries.", stored_table->count);
|
||||
}
|
||||
}
|
||||
|
||||
OldUsageTableEntry *OldUsageTable::FindEntry(const std::vector<uint8_t> &pst) {
|
||||
wvcdm::AutoLock lock(lock_);
|
||||
return FindEntryLocked(pst);
|
||||
}
|
||||
|
||||
OldUsageTableEntry *OldUsageTable::FindEntryLocked(const std::vector<uint8_t> &pst) {
|
||||
std::vector<uint8_t> pst_hash;
|
||||
if (!ComputeHash(pst, pst_hash)) {
|
||||
LOGE("OldUsageTable: Could not compute hash of pst.");
|
||||
return NULL;
|
||||
}
|
||||
EntryMap::iterator it = table_.find(pst_hash);
|
||||
if (it == table_.end()) {
|
||||
return NULL;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
OldUsageTableEntry *OldUsageTable::CreateEntry(const std::vector<uint8_t> &pst) {
|
||||
std::vector<uint8_t> pst_hash;
|
||||
if (!ComputeHash(pst, pst_hash)) {
|
||||
LOGE("OldUsageTable: Could not compute hash of pst.");
|
||||
return NULL;
|
||||
}
|
||||
OldUsageTableEntry *entry = new OldUsageTableEntry(pst_hash);
|
||||
wvcdm::AutoLock lock(lock_);
|
||||
table_[pst_hash] = entry;
|
||||
return entry;
|
||||
}
|
||||
|
||||
void OldUsageTable::Clear() {
|
||||
wvcdm::AutoLock lock(lock_);
|
||||
for (EntryMap::iterator i = table_.begin(); i != table_.end(); ++i) {
|
||||
if (i->second) delete i->second;
|
||||
}
|
||||
table_.clear();
|
||||
}
|
||||
|
||||
void OldUsageTable::DeleteFile(CryptoEngine *ce) {
|
||||
wvcdm::FileSystem* file_system = ce->file_system();
|
||||
std::string path;
|
||||
// Note: this path is OK for a real implementation, but using security level 1
|
||||
// would be better.
|
||||
if (!wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3,
|
||||
&path)) {
|
||||
LOGE("OldUsageTable: Unable to get base path");
|
||||
return;
|
||||
}
|
||||
std::string filename = path + "UsageTable.dat";
|
||||
if (file_system->Exists(filename)) {
|
||||
if (!file_system->Remove(filename)) {
|
||||
LOGE("DeleteOldUsageTable: error removing file.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool OldUsageTable::ComputeHash(const std::vector<uint8_t> &pst,
|
||||
std::vector<uint8_t> &pst_hash) {
|
||||
// The PST is not fixed size, and we have no promises that it is reasonbly
|
||||
// sized, so we compute a hash of it, and store that instead.
|
||||
pst_hash.resize(SHA256_DIGEST_LENGTH);
|
||||
SHA256_CTX context;
|
||||
if (!SHA256_Init(&context)) return false;
|
||||
if (!SHA256_Update(&context, &pst[0], pst.size())) return false;
|
||||
if (!SHA256_Final(&pst_hash[0], &context)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
93
mock/src/oemcrypto_old_usage_table_mock.h
Normal file
93
mock/src/oemcrypto_old_usage_table_mock.h
Normal file
@@ -0,0 +1,93 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
// This is from the v12 version of oemcrypto usage tables. It is used for
|
||||
// devices that upgrade from v12 to v13 in the field, and need to convert from
|
||||
// the old type of usage table to the new.
|
||||
#ifndef OEMCRYPTO_OLD_USAGE_TABLE_MOCK_H_
|
||||
#define OEMCRYPTO_OLD_USAGE_TABLE_MOCK_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "lock.h"
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "openssl/sha.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
class CryptoEngine;
|
||||
class UsagetTableEntry;
|
||||
|
||||
struct OldStoredUsageEntry {
|
||||
// To save disk space, we only store a hash of the pst.
|
||||
uint8_t pst_hash[SHA256_DIGEST_LENGTH];
|
||||
int64_t time_of_license_received;
|
||||
int64_t time_of_first_decrypt;
|
||||
int64_t time_of_last_decrypt;
|
||||
enum OEMCrypto_Usage_Entry_Status status;
|
||||
uint8_t mac_key_server[wvcdm::MAC_KEY_SIZE];
|
||||
uint8_t mac_key_client[wvcdm::MAC_KEY_SIZE];
|
||||
};
|
||||
|
||||
typedef union {
|
||||
struct OldStoredUsageEntry entry;
|
||||
uint8_t padding[128]; // multiple of block size and bigger than entry size.
|
||||
} AlignedOldStoredUsageEntry;
|
||||
|
||||
struct OldStoredUsageTable {
|
||||
uint8_t signature[SHA256_DIGEST_LENGTH];
|
||||
uint8_t iv[wvcdm::KEY_IV_SIZE];
|
||||
int64_t generation;
|
||||
uint64_t count;
|
||||
AlignedOldStoredUsageEntry entries[];
|
||||
};
|
||||
|
||||
class OldUsageTableEntry {
|
||||
public:
|
||||
OldUsageTableEntry(const std::vector<uint8_t> &pst_hash);
|
||||
OldUsageTableEntry(const OldStoredUsageEntry *buffer);
|
||||
~OldUsageTableEntry();
|
||||
const std::vector<uint8_t> &pst_hash() const { return pst_hash_; }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> pst_hash_;
|
||||
int64_t time_of_license_received_;
|
||||
int64_t time_of_first_decrypt_;
|
||||
int64_t time_of_last_decrypt_;
|
||||
enum OEMCrypto_Usage_Entry_Status status_;
|
||||
std::vector<uint8_t> mac_key_server_;
|
||||
std::vector<uint8_t> mac_key_client_;
|
||||
|
||||
friend class UsageTableEntry;
|
||||
friend class UsageTable;
|
||||
};
|
||||
|
||||
class OldUsageTable {
|
||||
public:
|
||||
OldUsageTable(CryptoEngine *ce);
|
||||
~OldUsageTable() { Clear(); }
|
||||
OldUsageTableEntry *FindEntry(const std::vector<uint8_t> &pst);
|
||||
OldUsageTableEntry *CreateEntry(const std::vector<uint8_t> &pst);
|
||||
void Clear();
|
||||
static void DeleteFile(CryptoEngine *ce);
|
||||
|
||||
private:
|
||||
OldUsageTableEntry *FindEntryLocked(const std::vector<uint8_t> &pst);
|
||||
bool ComputeHash(const std::vector<uint8_t> &pst,
|
||||
std::vector<uint8_t> &pst_hash);
|
||||
|
||||
typedef std::map<std::vector<uint8_t>, OldUsageTableEntry *> EntryMap;
|
||||
EntryMap table_;
|
||||
wvcdm::Lock lock_;
|
||||
int64_t generation_;
|
||||
CryptoEngine *ce_;
|
||||
};
|
||||
|
||||
} // namespace wvoec_mock
|
||||
|
||||
#endif // OEMCRYPTO_OLD_USAGE_TABLE_MOCK_H_
|
||||
98
mock/src/oemcrypto_rsa_key_shared.cpp
Normal file
98
mock/src/oemcrypto_rsa_key_shared.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
#include "oemcrypto_rsa_key_shared.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include "oemcrypto_logging.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void dump_openssl_error() {
|
||||
while (unsigned long err = ERR_get_error()) {
|
||||
char buffer[120];
|
||||
LOGE("openssl error -- %lu -- %s",
|
||||
err, ERR_error_string(err, buffer));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
void RSA_shared_ptr::reset() {
|
||||
if (rsa_key_ && key_owned_) {
|
||||
RSA_free(rsa_key_);
|
||||
}
|
||||
key_owned_ = false;
|
||||
rsa_key_ = NULL;
|
||||
}
|
||||
|
||||
bool RSA_shared_ptr::LoadPkcs8RsaKey(const uint8_t* buffer, size_t length) {
|
||||
assert(buffer != NULL);
|
||||
reset();
|
||||
uint8_t* pkcs8_rsa_key = const_cast<uint8_t*>(buffer);
|
||||
BIO* bio = BIO_new_mem_buf(pkcs8_rsa_key, length);
|
||||
if (bio == NULL) {
|
||||
LOGE("[LoadPkcs8RsaKey(): Could not allocate bio buffer]");
|
||||
return false;
|
||||
}
|
||||
bool success = true;
|
||||
PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL);
|
||||
if (pkcs8_pki == NULL) {
|
||||
BIO_reset(bio);
|
||||
pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL);
|
||||
if (pkcs8_pki == NULL) {
|
||||
LOGE("[LoadPkcs8RsaKey(): d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL]");
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
EVP_PKEY* evp = NULL;
|
||||
if (success) {
|
||||
evp = EVP_PKCS82PKEY(pkcs8_pki);
|
||||
if (evp == NULL) {
|
||||
LOGE("[LoadPkcs8RsaKey(): EVP_PKCS82PKEY returned NULL]");
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
rsa_key_ = EVP_PKEY_get1_RSA(evp);
|
||||
if (rsa_key_ == NULL) {
|
||||
LOGE("[LoadPkcs8RsaKey(): PrivateKeyInfo did not contain an RSA key]");
|
||||
success = false;
|
||||
}
|
||||
key_owned_ = true;
|
||||
}
|
||||
if (evp != NULL) {
|
||||
EVP_PKEY_free(evp);
|
||||
}
|
||||
if (pkcs8_pki != NULL) {
|
||||
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
|
||||
}
|
||||
BIO_free(bio);
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
switch (RSA_check_key(rsa_key_)) {
|
||||
case 1: // valid.
|
||||
return true;
|
||||
case 0: // not valid.
|
||||
LOGE("[LoadPkcs8RsaKey(): rsa key not valid]");
|
||||
dump_openssl_error();
|
||||
return false;
|
||||
default: // -1 == check failed.
|
||||
LOGE("[LoadPkcs8RsaKey(): error checking rsa key]");
|
||||
dump_openssl_error();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
37
mock/src/oemcrypto_rsa_key_shared.h
Normal file
37
mock/src/oemcrypto_rsa_key_shared.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
#ifndef OEMCRYPTO_RSA_KEY_SHARED_H_
|
||||
#define OEMCRYPTO_RSA_KEY_SHARED_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
// Shared pointer with specialized destructor. This pointer is only shared
|
||||
// from a CryptoEngine to a Session -- so we don't have to use full reference
|
||||
// counting.
|
||||
class RSA_shared_ptr {
|
||||
public:
|
||||
RSA_shared_ptr() : rsa_key_(NULL), key_owned_(false) {}
|
||||
~RSA_shared_ptr() { reset(); };
|
||||
// Explicitly allow copy as share.
|
||||
explicit RSA_shared_ptr(const RSA_shared_ptr& other) :
|
||||
rsa_key_(other.rsa_key_), key_owned_(false) {}
|
||||
RSA* get() { return rsa_key_; }
|
||||
void reset();
|
||||
bool LoadPkcs8RsaKey(const uint8_t* buffer, size_t length);
|
||||
|
||||
private:
|
||||
void operator=(const RSA_shared_ptr); // disallow assign.
|
||||
|
||||
RSA* rsa_key_;
|
||||
bool key_owned_;
|
||||
};
|
||||
|
||||
} // namespace wvoec_mock
|
||||
|
||||
#endif // OEMCRYPTO_RSA_KEY_SHARED_H_
|
||||
1611
mock/src/oemcrypto_session.cpp
Normal file
1611
mock/src/oemcrypto_session.cpp
Normal file
File diff suppressed because it is too large
Load Diff
251
mock/src/oemcrypto_session.h
Normal file
251
mock/src/oemcrypto_session.h
Normal file
@@ -0,0 +1,251 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
#ifndef MOCK_OEMCRYPTO_SESSION_H_
|
||||
#define MOCK_OEMCRYPTO_SESSION_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include "OEMCryptoCENC.h" // Needed for enums only.
|
||||
#include "file_store.h"
|
||||
#include "lock.h"
|
||||
#include "oemcrypto_auth_mock.h"
|
||||
#include "oemcrypto_key_mock.h"
|
||||
#include "oemcrypto_nonce_table.h"
|
||||
#include "oemcrypto_rsa_key_shared.h"
|
||||
#include "oemcrypto_session_key_table.h"
|
||||
#include "oemcrypto_usage_table_mock.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
class CryptoEngine;
|
||||
typedef uint32_t SessionId;
|
||||
|
||||
enum SRMVersionStatus { NoSRMVersion, ValidSRMVersion, InvalidSRMVersion };
|
||||
|
||||
// TODO(jfore): Is there a better name?
|
||||
class SessionContextKeys {
|
||||
public:
|
||||
virtual OEMCrypto_LicenseType type() = 0;
|
||||
virtual size_t size() = 0;
|
||||
virtual bool Insert(const KeyId& key_id, const Key& key_data) = 0;
|
||||
virtual Key* Find(const KeyId& key_id) = 0;
|
||||
virtual void Remove(const KeyId& key_id) = 0;
|
||||
virtual void UpdateDuration(const KeyControlBlock& control) = 0;
|
||||
|
||||
// Methods supported exclusively for entitlement keys. Returns false if
|
||||
// entitlement keys are not found or not supported by the current key table.
|
||||
// It is the caller's responsibility to check the context.
|
||||
virtual bool SetContentKey(const KeyId& entitlement_id,
|
||||
const KeyId& content_key_id,
|
||||
const std::vector<uint8_t>& content_key) = 0;
|
||||
virtual bool GetEntitlementKey(const KeyId& entitlement_id,
|
||||
const std::vector<uint8_t>** key) = 0;
|
||||
|
||||
virtual ~SessionContextKeys() {}
|
||||
|
||||
protected:
|
||||
SessionContextKeys() {}
|
||||
|
||||
private:
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContextKeys);
|
||||
};
|
||||
|
||||
class SessionContext {
|
||||
private:
|
||||
SessionContext() {}
|
||||
|
||||
public:
|
||||
SessionContext(CryptoEngine* ce, SessionId sid, const RSA_shared_ptr& rsa_key)
|
||||
: valid_(true),
|
||||
ce_(ce),
|
||||
id_(sid),
|
||||
current_content_key_(NULL),
|
||||
session_keys_(NULL),
|
||||
rsa_key_(rsa_key),
|
||||
allowed_schemes_(kSign_RSASSA_PSS),
|
||||
usage_entry_(NULL),
|
||||
srm_requirements_status_(NoSRMVersion),
|
||||
usage_entry_status_(kNoUsageEntry) {}
|
||||
~SessionContext();
|
||||
|
||||
bool isValid() { return valid_; }
|
||||
|
||||
bool DeriveKeys(const std::vector<uint8_t>& master_key,
|
||||
const std::vector<uint8_t>& mac_context,
|
||||
const std::vector<uint8_t>& enc_context);
|
||||
bool RSADeriveKeys(const std::vector<uint8_t>& enc_session_key,
|
||||
const std::vector<uint8_t>& mac_context,
|
||||
const std::vector<uint8_t>& enc_context);
|
||||
bool GenerateSignature(const uint8_t* message, size_t message_length,
|
||||
uint8_t* signature, size_t* signature_length);
|
||||
size_t RSASignatureSize();
|
||||
OEMCryptoResult GenerateRSASignature(const uint8_t* message,
|
||||
size_t message_length,
|
||||
uint8_t* signature,
|
||||
size_t* signature_length,
|
||||
RSA_Padding_Scheme padding_scheme);
|
||||
bool ValidateMessage(const uint8_t* message, size_t message_length,
|
||||
const uint8_t* signature, size_t signature_length);
|
||||
OEMCryptoResult DecryptCENC(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 Generic_Encrypt(const uint8_t* in_buffer,
|
||||
size_t buffer_length, const uint8_t* iv,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
uint8_t* out_buffer);
|
||||
OEMCryptoResult Generic_Decrypt(const uint8_t* in_buffer,
|
||||
size_t buffer_length, const uint8_t* iv,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
uint8_t* out_buffer);
|
||||
OEMCryptoResult Generic_Sign(const uint8_t* in_buffer, size_t buffer_length,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
uint8_t* signature, size_t* signature_length);
|
||||
OEMCryptoResult Generic_Verify(const uint8_t* in_buffer, size_t buffer_length,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length);
|
||||
void StartTimer();
|
||||
uint32_t CurrentTimer(); // (seconds).
|
||||
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,
|
||||
OEMCrypto_LicenseType license_type);
|
||||
OEMCryptoResult LoadEntitledContentKeys(
|
||||
size_t num_keys,
|
||||
const OEMCrypto_EntitledContentKeyObject* key_array);
|
||||
OEMCryptoResult InstallKey(const KeyId& key_id,
|
||||
const std::vector<uint8_t>& key_data,
|
||||
const std::vector<uint8_t>& key_data_iv,
|
||||
const std::vector<uint8_t>& key_control,
|
||||
const std::vector<uint8_t>& key_control_iv,
|
||||
bool second_license);
|
||||
bool InstallRSAEncryptedKey(const uint8_t* encrypted_message_key,
|
||||
size_t encrypted_message_key_length);
|
||||
bool DecryptRSAKey(const uint8_t* enc_rsa_key, size_t enc_rsa_key_length,
|
||||
const uint8_t* wrapped_rsa_key_iv, uint8_t* pkcs8_rsa_key);
|
||||
bool EncryptRSAKey(const uint8_t* pkcs8_rsa_key, size_t enc_rsa_key_length,
|
||||
const uint8_t* enc_rsa_key_iv, uint8_t* enc_rsa_key);
|
||||
bool LoadRSAKey(const uint8_t* pkcs8_rsa_key, size_t rsa_key_length);
|
||||
OEMCryptoResult RefreshKey(const KeyId& key_id,
|
||||
const std::vector<uint8_t>& key_control,
|
||||
const std::vector<uint8_t>& key_control_iv);
|
||||
bool UpdateMacKeys(const std::vector<uint8_t>& mac_keys,
|
||||
const std::vector<uint8_t>& iv);
|
||||
bool QueryKeyControlBlock(const KeyId& key_id, uint32_t* data);
|
||||
OEMCryptoResult SelectContentKey(const KeyId& key_id,
|
||||
OEMCryptoCipherMode cipher_mode);
|
||||
const Key* current_content_key(void) { return current_content_key_; }
|
||||
void set_mac_key_server(const std::vector<uint8_t>& mac_key_server) {
|
||||
mac_key_server_ = mac_key_server;
|
||||
}
|
||||
const std::vector<uint8_t>& mac_key_server() { return mac_key_server_; }
|
||||
void set_mac_key_client(const std::vector<uint8_t>& mac_key_client) {
|
||||
mac_key_client_ = mac_key_client;
|
||||
}
|
||||
const std::vector<uint8_t>& mac_key_client() { return mac_key_client_; }
|
||||
|
||||
void set_encryption_key(const std::vector<uint8_t>& enc_key) {
|
||||
encryption_key_ = enc_key;
|
||||
}
|
||||
const std::vector<uint8_t>& encryption_key() { return encryption_key_; }
|
||||
uint32_t allowed_schemes() const { return allowed_schemes_; }
|
||||
|
||||
void AddNonce(uint32_t nonce);
|
||||
bool CheckNonce(uint32_t nonce);
|
||||
void FlushNonces();
|
||||
|
||||
OEMCryptoResult CreateNewUsageEntry(uint32_t* usage_entry_number);
|
||||
OEMCryptoResult LoadUsageEntry(uint32_t index,
|
||||
const std::vector<uint8_t>& buffer);
|
||||
OEMCryptoResult UpdateUsageEntry(uint8_t* header_buffer,
|
||||
size_t* header_buffer_length,
|
||||
uint8_t* entry_buffer,
|
||||
size_t* entry_buffer_length);
|
||||
OEMCryptoResult DeactivateUsageEntry(const std::vector<uint8_t>& pst);
|
||||
OEMCryptoResult ReportUsage(const std::vector<uint8_t>& pst, uint8_t* buffer,
|
||||
size_t* buffer_length);
|
||||
OEMCryptoResult MoveEntry(uint32_t new_index);
|
||||
OEMCryptoResult CopyOldUsageEntry(const std::vector<uint8_t>& pst);
|
||||
|
||||
private:
|
||||
bool DeriveKey(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& context, int counter,
|
||||
std::vector<uint8_t>* out);
|
||||
bool DecryptMessage(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv,
|
||||
const std::vector<uint8_t>& message,
|
||||
std::vector<uint8_t>* decrypted);
|
||||
bool DecryptEntitlement(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv,
|
||||
const std::vector<uint8_t>& message,
|
||||
std::vector<uint8_t>* decrypted);
|
||||
// Either verify the nonce or usage entry, as required by the key control
|
||||
// block.
|
||||
OEMCryptoResult CheckNonceOrEntry(const KeyControlBlock& key_control_block);
|
||||
// If there is a usage entry, check that it is not inactive.
|
||||
// It also updates the status of the entry if needed.
|
||||
bool CheckUsageEntry();
|
||||
// Check that the usage entry status is valid for online use.
|
||||
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 DecryptCBC(const uint8_t* key, const uint8_t* iv,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
||||
const uint8_t* cipher_data,
|
||||
size_t cipher_data_length, uint8_t* clear_data);
|
||||
OEMCryptoResult PatternDecryptCTR(
|
||||
const uint8_t* key, const uint8_t* iv, size_t block_offset,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
||||
const uint8_t* cipher_data, size_t cipher_data_length,
|
||||
uint8_t* clear_data);
|
||||
OEMCryptoResult DecryptCTR(const uint8_t* key_u8, const uint8_t* iv,
|
||||
size_t block_offset, const uint8_t* cipher_data,
|
||||
size_t cipher_data_length, uint8_t* clear_data);
|
||||
// Checks if the key is allowed for the specified type. If there is a usage
|
||||
// entry, it also checks the usage entry.
|
||||
OEMCryptoResult CheckKeyUse(const std::string& log_string, uint32_t use_type,
|
||||
OEMCryptoBufferType buffer_type);
|
||||
RSA* rsa_key() { return rsa_key_.get(); }
|
||||
|
||||
bool valid_;
|
||||
CryptoEngine* ce_;
|
||||
SessionId id_;
|
||||
std::vector<uint8_t> mac_key_server_;
|
||||
std::vector<uint8_t> mac_key_client_;
|
||||
std::vector<uint8_t> encryption_key_;
|
||||
std::vector<uint8_t> session_key_;
|
||||
const Key* current_content_key_;
|
||||
SessionContextKeys* session_keys_;
|
||||
NonceTable nonce_table_;
|
||||
RSA_shared_ptr rsa_key_;
|
||||
uint32_t allowed_schemes_; // for RSA signatures.
|
||||
time_t timer_start_;
|
||||
UsageTableEntry* usage_entry_;
|
||||
SRMVersionStatus srm_requirements_status_;
|
||||
enum UsageEntryStatus {
|
||||
kNoUsageEntry, // No entry loaded for this session.
|
||||
kUsageEntryNew, // After entry was created.
|
||||
kUsageEntryLoaded, // After loading entry or loading keys.
|
||||
};
|
||||
UsageEntryStatus usage_entry_status_;
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext);
|
||||
};
|
||||
|
||||
} // namespace wvoec_mock
|
||||
|
||||
#endif // MOCK_OEMCRYPTO_SESSION_H_
|
||||
117
mock/src/oemcrypto_session_key_table.cpp
Normal file
117
mock/src/oemcrypto_session_key_table.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
#include "oemcrypto_session_key_table.h"
|
||||
|
||||
#include "keys.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
SessionKeyTable::~SessionKeyTable() {
|
||||
for (KeyMap::iterator i = keys_.begin(); i != keys_.end(); ++i) {
|
||||
if (NULL != i->second) {
|
||||
delete i->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SessionKeyTable::Insert(const KeyId key_id, const Key& key_data) {
|
||||
if (keys_.find(key_id) != keys_.end()) return false;
|
||||
keys_[key_id] = new Key(key_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
Key* SessionKeyTable::Find(const KeyId key_id) {
|
||||
if (keys_.find(key_id) == keys_.end()) {
|
||||
return NULL;
|
||||
}
|
||||
return keys_[key_id];
|
||||
}
|
||||
|
||||
void SessionKeyTable::Remove(const KeyId key_id) {
|
||||
if (keys_.find(key_id) != keys_.end()) {
|
||||
delete keys_[key_id];
|
||||
keys_.erase(key_id);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionKeyTable::UpdateDuration(const KeyControlBlock& control) {
|
||||
for (KeyMap::iterator it = keys_.begin(); it != keys_.end(); ++it) {
|
||||
it->second->UpdateDuration(control);
|
||||
}
|
||||
}
|
||||
|
||||
bool EntitlementKeyTable::Insert(const KeyId key_id, const Key& key_data) {
|
||||
// |key_id| and |key_data| are for an entitlement key. Insert a new
|
||||
// entitlement key entry.
|
||||
if (keys_.find(key_id) != keys_.end()) return false;
|
||||
keys_[key_id] = new EntitlementKey(key_data);
|
||||
// If this is a new insertion, we don't have a content key assigned yet.
|
||||
return true;
|
||||
}
|
||||
|
||||
Key* EntitlementKeyTable::Find(const KeyId key_id) {
|
||||
// |key_id| refers to a content key.
|
||||
ContentIdToEntitlementIdMap::iterator it =
|
||||
contentid_to_entitlementid_.find(key_id);
|
||||
if (it == contentid_to_entitlementid_.end()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (keys_.find(it->second) == keys_.end()) {
|
||||
return NULL;
|
||||
}
|
||||
return keys_[it->second];
|
||||
}
|
||||
|
||||
void EntitlementKeyTable::Remove(const KeyId key_id) {
|
||||
// |key_id| refers to a content key. No one currently calls Remove so this
|
||||
// method is free to change if needed.
|
||||
ContentIdToEntitlementIdMap::iterator it =
|
||||
contentid_to_entitlementid_.find(key_id);
|
||||
if (it == contentid_to_entitlementid_.end()) {
|
||||
return;
|
||||
}
|
||||
keys_.erase(it->second);
|
||||
contentid_to_entitlementid_.erase(key_id);
|
||||
}
|
||||
|
||||
void EntitlementKeyTable::UpdateDuration(const KeyControlBlock& control) {
|
||||
for (EntitlementKeyMap::iterator it = keys_.begin(); it != keys_.end();
|
||||
++it) {
|
||||
it->second->UpdateDuration(control);
|
||||
}
|
||||
}
|
||||
|
||||
bool EntitlementKeyTable::SetContentKey(
|
||||
const KeyId& entitlement_id, const KeyId& content_key_id,
|
||||
const std::vector<uint8_t> content_key) {
|
||||
EntitlementKeyMap::iterator it = keys_.find(entitlement_id);
|
||||
if (it == keys_.end()) {
|
||||
return false;
|
||||
}
|
||||
contentid_to_entitlementid_.erase(it->second->content_key_id());
|
||||
if (!it->second->SetContentKey(content_key_id, content_key)) {
|
||||
return false;
|
||||
}
|
||||
contentid_to_entitlementid_[content_key_id] = entitlement_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EntitlementKeyTable::GetEntitlementKey(
|
||||
const KeyId& entitlement_id,
|
||||
const std::vector<uint8_t>** entitlement_key) {
|
||||
if (!entitlement_key) {
|
||||
return false;
|
||||
}
|
||||
EntitlementKeyMap::iterator it = keys_.find(entitlement_id);
|
||||
if (it == keys_.end()) {
|
||||
return false;
|
||||
}
|
||||
*entitlement_key = &it->second->entitlement_key();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
68
mock/src/oemcrypto_session_key_table.h
Normal file
68
mock/src/oemcrypto_session_key_table.h
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
#ifndef MOCK_OEMCRYPTO_SESSION_KEY_TABLE_H_
|
||||
#define MOCK_OEMCRYPTO_SESSION_KEY_TABLE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "oemcrypto_key_mock.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
class SessionContext;
|
||||
class CryptoEngine;
|
||||
class UsageTable;
|
||||
class UsageTableEntry;
|
||||
|
||||
typedef std::vector<uint8_t> KeyId;
|
||||
typedef std::map<KeyId, Key*> KeyMap;
|
||||
typedef std::map<KeyId, EntitlementKey*> EntitlementKeyMap;
|
||||
|
||||
// SessionKeyTable holds the keys for the current session
|
||||
class SessionKeyTable {
|
||||
public:
|
||||
SessionKeyTable() {}
|
||||
~SessionKeyTable();
|
||||
|
||||
bool Insert(const KeyId key_id, const Key& key_data);
|
||||
Key* Find(const KeyId key_id);
|
||||
void Remove(const KeyId key_id);
|
||||
void UpdateDuration(const KeyControlBlock& control);
|
||||
size_t size() const { return keys_.size(); }
|
||||
|
||||
private:
|
||||
KeyMap keys_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(SessionKeyTable);
|
||||
};
|
||||
|
||||
class EntitlementKeyTable {
|
||||
typedef std::map<KeyId, KeyId> ContentIdToEntitlementIdMap;
|
||||
|
||||
public:
|
||||
EntitlementKeyTable() {}
|
||||
~EntitlementKeyTable() {}
|
||||
bool Insert(const KeyId key_id, const Key& key_data);
|
||||
Key* Find(const KeyId key_id);
|
||||
void Remove(const KeyId key_id);
|
||||
void UpdateDuration(const KeyControlBlock& control);
|
||||
size_t size() const { return contentid_to_entitlementid_.size(); }
|
||||
bool SetContentKey(const KeyId& entitlement_id, const KeyId& content_key_id,
|
||||
const std::vector<uint8_t> content_key);
|
||||
bool GetEntitlementKey(const KeyId& entitlement_id,
|
||||
const std::vector<uint8_t>** entitlement_key);
|
||||
|
||||
private:
|
||||
EntitlementKeyMap keys_;
|
||||
ContentIdToEntitlementIdMap contentid_to_entitlementid_;
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(EntitlementKeyTable);
|
||||
};
|
||||
|
||||
} // namespace wvoec_mock
|
||||
|
||||
#endif // MOCK_OEMCRYPTO_SESSION_KEY_TABLE_H_
|
||||
752
mock/src/oemcrypto_usage_table_mock.cpp
Normal file
752
mock/src/oemcrypto_usage_table_mock.cpp
Normal file
@@ -0,0 +1,752 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
#include "oemcrypto_usage_table_mock.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "file_store.h"
|
||||
#include "log.h"
|
||||
#include "oemcrypto_engine_mock.h"
|
||||
#include "oemcrypto_logging.h"
|
||||
#include "oemcrypto_old_usage_table_mock.h"
|
||||
#include "properties.h"
|
||||
#include "pst_report.h"
|
||||
#include "string_conversions.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
namespace {
|
||||
const size_t kMagicLength = 8;
|
||||
const char* kEntryVerification = "USEENTRY";
|
||||
const char* kHeaderVerification = "USEHEADR";
|
||||
// Offset into a signed block where we start encrypting. We need to
|
||||
// skip the signature and the iv.
|
||||
const size_t kEncryptionOffset = SHA256_DIGEST_LENGTH + SHA256_DIGEST_LENGTH;
|
||||
|
||||
// A structure that holds an usage entry and its signature.
|
||||
struct SignedEntryBlock {
|
||||
uint8_t signature[SHA256_DIGEST_LENGTH];
|
||||
uint8_t iv[SHA256_DIGEST_LENGTH];
|
||||
uint8_t verification[kMagicLength];
|
||||
StoredUsageEntry data;
|
||||
};
|
||||
|
||||
// This has the data in the header of constant size. There is also an array
|
||||
// of generation numbers.
|
||||
struct SignedHeaderBlock {
|
||||
uint8_t signature[SHA256_DIGEST_LENGTH];
|
||||
uint8_t iv[SHA256_DIGEST_LENGTH];
|
||||
uint8_t verification[kMagicLength];
|
||||
int64_t master_generation;
|
||||
uint64_t count;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
UsageTableEntry::UsageTableEntry(UsageTable* table, uint32_t index,
|
||||
int64_t generation)
|
||||
: usage_table_(table), recent_decrypt_(false), forbid_report_(true) {
|
||||
memset(&data_, 0, sizeof(data_));
|
||||
data_.generation_number = generation;
|
||||
data_.index = index;
|
||||
}
|
||||
|
||||
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;
|
||||
memcpy(data_.pst, pst, pst_length);
|
||||
data_.time_of_license_received = time(NULL);
|
||||
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;
|
||||
return 0 == memcmp(pst, data_.pst, pst_length);
|
||||
}
|
||||
|
||||
bool UsageTableEntry::VerifyMacKeys(const std::vector<uint8_t>& server,
|
||||
const std::vector<uint8_t>& client) {
|
||||
return (server.size() == wvcdm::MAC_KEY_SIZE) &&
|
||||
(client.size() == wvcdm::MAC_KEY_SIZE) &&
|
||||
(0 == memcmp(&server[0], data_.mac_key_server, wvcdm::MAC_KEY_SIZE)) &&
|
||||
(0 == memcmp(&client[0], data_.mac_key_client, wvcdm::MAC_KEY_SIZE));
|
||||
}
|
||||
|
||||
bool UsageTableEntry::SetMacKeys(const std::vector<uint8_t>& server,
|
||||
const std::vector<uint8_t>& client) {
|
||||
if ((server.size() != wvcdm::MAC_KEY_SIZE) ||
|
||||
(client.size() != wvcdm::MAC_KEY_SIZE))
|
||||
return false;
|
||||
memcpy(data_.mac_key_server, &server[0], wvcdm::MAC_KEY_SIZE);
|
||||
memcpy(data_.mac_key_client, &client[0], wvcdm::MAC_KEY_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UsageTableEntry::CheckForUse() {
|
||||
if (Inactive()) return false;
|
||||
recent_decrypt_ = true;
|
||||
if (data_.status == kUnused) {
|
||||
data_.status = kActive;
|
||||
data_.time_of_first_decrypt = time(NULL);
|
||||
data_.generation_number++;
|
||||
usage_table_->IncrementGeneration();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void UsageTableEntry::Deactivate(const std::vector<uint8_t>& pst) {
|
||||
if (data_.status == kUnused) {
|
||||
data_.status = kInactiveUnused;
|
||||
} else if (data_.status == kActive) {
|
||||
data_.status = kInactiveUsed;
|
||||
}
|
||||
forbid_report_ = true;
|
||||
data_.generation_number++;
|
||||
usage_table_->IncrementGeneration();
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector<uint8_t>& pst,
|
||||
uint8_t* buffer,
|
||||
size_t* buffer_length) {
|
||||
if (forbid_report_) return OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE;
|
||||
if (recent_decrypt_) return OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE;
|
||||
if (pst.size() == 0 || pst.size() > kMaxPSTLength ||
|
||||
pst.size() != data_.pst_length) {
|
||||
LOGE("ReportUsage: bad pst length = %d, should be %d.",
|
||||
pst.size(), data_.pst_length);
|
||||
return OEMCrypto_ERROR_WRONG_PST;
|
||||
}
|
||||
if (memcmp(&pst[0], data_.pst, data_.pst_length)) {
|
||||
LOGE("ReportUsage: wrong pst %s, should be %s.",
|
||||
wvcdm::b2a_hex(pst).c_str(),
|
||||
wvcdm::HexEncode(data_.pst, data_.pst_length).c_str());
|
||||
return OEMCrypto_ERROR_WRONG_PST;
|
||||
}
|
||||
size_t length_needed = wvcdm::Unpacked_PST_Report::report_size(pst.size());
|
||||
if (*buffer_length < length_needed) {
|
||||
*buffer_length = length_needed;
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
if (!buffer) {
|
||||
LOGE("ReportUsage: buffer was null pointer.");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
wvcdm::Unpacked_PST_Report pst_report(buffer);
|
||||
int64_t now = time(NULL);
|
||||
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);
|
||||
pst_report.set_seconds_since_last_decrypt(now - data_.time_of_last_decrypt);
|
||||
pst_report.set_status(data_.status);
|
||||
pst_report.set_clock_security_level(kSecureTimer);
|
||||
pst_report.set_pst_length(data_.pst_length);
|
||||
memcpy(pst_report.pst(), data_.pst, data_.pst_length);
|
||||
unsigned int md_len = SHA_DIGEST_LENGTH;
|
||||
if (LogCategoryEnabled(kLoggingDumpDerivedKeys)) {
|
||||
std::vector<uint8_t> mac_key_client(
|
||||
data_.mac_key_client,
|
||||
data_.mac_key_client + wvcdm::MAC_KEY_SIZE * sizeof(uint8_t));
|
||||
LOGI(("message signed with HMAC and data_.mac_key_client, "
|
||||
"mac_key_client = " +
|
||||
wvcdm::b2a_hex(mac_key_client)).c_str());
|
||||
}
|
||||
if (!HMAC(EVP_sha1(), data_.mac_key_client, wvcdm::MAC_KEY_SIZE,
|
||||
buffer + SHA_DIGEST_LENGTH, length_needed - SHA_DIGEST_LENGTH,
|
||||
pst_report.signature(), &md_len)) {
|
||||
LOGE("ReportUsage: could not compute signature.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
void UsageTableEntry::UpdateAndIncrement() {
|
||||
if (recent_decrypt_) {
|
||||
data_.time_of_last_decrypt = time(NULL);
|
||||
recent_decrypt_ = false;
|
||||
}
|
||||
data_.generation_number++;
|
||||
usage_table_->IncrementGeneration();
|
||||
forbid_report_ = false;
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTableEntry::SaveData(CryptoEngine* ce,
|
||||
SessionContext* session,
|
||||
uint8_t* signed_buffer,
|
||||
size_t buffer_size) {
|
||||
// buffer_size was determined by calling function.
|
||||
if (buffer_size != SignedEntrySize()) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
std::vector<uint8_t> clear_buffer(buffer_size);
|
||||
memset(&clear_buffer[0], 0, buffer_size);
|
||||
memset(signed_buffer, 0, buffer_size);
|
||||
SignedEntryBlock* clear =
|
||||
reinterpret_cast<SignedEntryBlock*>(&clear_buffer[0]);
|
||||
SignedEntryBlock* encrypted =
|
||||
reinterpret_cast<SignedEntryBlock*>(signed_buffer);
|
||||
clear->data = this->data_; // Copy the current data.
|
||||
memcpy(clear->verification, kEntryVerification, kMagicLength);
|
||||
|
||||
// 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 bool override_to_real = true;
|
||||
const std::vector<uint8_t>& key = ce->DeviceRootKey(override_to_real);
|
||||
|
||||
// Encrypt the entry.
|
||||
RAND_bytes(encrypted->iv, wvcdm::KEY_IV_SIZE);
|
||||
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE]; // working iv buffer.
|
||||
memcpy(iv_buffer, encrypted->iv, wvcdm::KEY_IV_SIZE);
|
||||
AES_KEY aes_key;
|
||||
AES_set_encrypt_key(&key[0], 128, &aes_key);
|
||||
AES_cbc_encrypt(
|
||||
&clear_buffer[kEncryptionOffset], &signed_buffer[kEncryptionOffset],
|
||||
buffer_size - kEncryptionOffset, &aes_key, iv_buffer, AES_ENCRYPT);
|
||||
|
||||
// Sign the entry.
|
||||
unsigned int sig_length = SHA256_DIGEST_LENGTH;
|
||||
if (!HMAC(EVP_sha256(), &key[0], key.size(),
|
||||
&signed_buffer[SHA256_DIGEST_LENGTH],
|
||||
buffer_size - SHA256_DIGEST_LENGTH, encrypted->signature,
|
||||
&sig_length)) {
|
||||
LOGE("SaveUsageEntry: Could not sign entry.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index,
|
||||
const std::vector<uint8_t>& buffer) {
|
||||
if (buffer.size() < SignedEntrySize()) return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
if (buffer.size() > SignedEntrySize())
|
||||
LOGW("LoadUsageTableEntry: buffer is large. %d > %d", buffer.size(),
|
||||
SignedEntrySize());
|
||||
std::vector<uint8_t> clear_buffer(buffer.size());
|
||||
SignedEntryBlock* clear =
|
||||
reinterpret_cast<SignedEntryBlock*>(&clear_buffer[0]);
|
||||
const SignedEntryBlock* encrypted =
|
||||
reinterpret_cast<const SignedEntryBlock*>(&buffer[0]);
|
||||
|
||||
// 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 bool override_to_real = true;
|
||||
const std::vector<uint8_t>& key = ce->DeviceRootKey(override_to_real);
|
||||
|
||||
// Verify the signature of the usage entry. Sign encrypted into clear buffer.
|
||||
unsigned int sig_length = SHA256_DIGEST_LENGTH;
|
||||
if (!HMAC(EVP_sha256(), &key[0], key.size(), &buffer[SHA256_DIGEST_LENGTH],
|
||||
buffer.size() - SHA256_DIGEST_LENGTH, clear->signature,
|
||||
&sig_length)) {
|
||||
LOGE("LoadUsageEntry: Could not sign entry.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (memcmp(clear->signature, encrypted->signature, SHA256_DIGEST_LENGTH)) {
|
||||
LOGE("LoadUsageEntry: Signature did not match.");
|
||||
LOGE("LoadUsageEntry: Invalid signature given: %s",
|
||||
wvcdm::HexEncode(encrypted->signature, sig_length).c_str());
|
||||
LOGE("LoadUsageEntry: Invalid signature computed: %s",
|
||||
wvcdm::HexEncode(clear->signature, sig_length).c_str());
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
|
||||
// Next, decrypt the entry.
|
||||
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
|
||||
memcpy(iv_buffer, encrypted->iv, wvcdm::KEY_IV_SIZE);
|
||||
AES_KEY aes_key;
|
||||
AES_set_decrypt_key(&key[0], 128, &aes_key);
|
||||
AES_cbc_encrypt(&buffer[kEncryptionOffset], &clear_buffer[kEncryptionOffset],
|
||||
buffer.size() - kEncryptionOffset, &aes_key, iv_buffer,
|
||||
AES_DECRYPT);
|
||||
|
||||
// Check the verification string is correct.
|
||||
if (memcmp(kEntryVerification, clear->verification, kMagicLength)) {
|
||||
LOGE("LoadUsageEntry: Invalid magic: %s=%8.8s expected: %s=%8.8s",
|
||||
wvcdm::HexEncode(clear->verification, kMagicLength).c_str(),
|
||||
clear->verification,
|
||||
wvcdm::HexEncode(reinterpret_cast<const uint8_t*>(kEntryVerification),
|
||||
kMagicLength).c_str(),
|
||||
reinterpret_cast<const uint8_t*>(kEntryVerification));
|
||||
return OEMCrypto_ERROR_BAD_MAGIC;
|
||||
}
|
||||
|
||||
// Check that the index is correct.
|
||||
if (index != clear->data.index) {
|
||||
LOGE("LoadUsageEntry: entry says index is %d, not %d", clear->data.index,
|
||||
index);
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
if (clear->data.status > kInactiveUnused) {
|
||||
LOGE("LoadUsageEntry: entry has bad status %d", clear->data.status);
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
this->data_ = clear->data;
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTableEntry::CopyOldUsageEntry(
|
||||
const std::vector<uint8_t>& pst) {
|
||||
OldUsageTableEntry* old_entry = usage_table_->FindOldUsageEntry(pst);
|
||||
if (!old_entry) return OEMCrypto_ERROR_WRONG_PST;
|
||||
data_.time_of_license_received = old_entry->time_of_license_received_;
|
||||
data_.time_of_first_decrypt = old_entry->time_of_first_decrypt_;
|
||||
data_.time_of_last_decrypt = old_entry->time_of_last_decrypt_;
|
||||
data_.status = old_entry->status_;
|
||||
if (old_entry->mac_key_server_.size() != wvcdm::MAC_KEY_SIZE) {
|
||||
LOGE("CopyOldEntry: Old entry has bad server mac key.");
|
||||
} else {
|
||||
memcpy(data_.mac_key_server, &(old_entry->mac_key_server_[0]),
|
||||
wvcdm::MAC_KEY_SIZE);
|
||||
}
|
||||
if (old_entry->mac_key_client_.size() != wvcdm::MAC_KEY_SIZE) {
|
||||
LOGE("CopyOldEntry: Old entry has bad client mac key.");
|
||||
} else {
|
||||
memcpy(data_.mac_key_client, &(old_entry->mac_key_client_[0]),
|
||||
wvcdm::MAC_KEY_SIZE);
|
||||
if (LogCategoryEnabled(kLoggingDumpDerivedKeys)) {
|
||||
std::vector<uint8_t> mac_key_client(
|
||||
data_.mac_key_client,
|
||||
data_.mac_key_client + wvcdm::MAC_KEY_SIZE * sizeof(uint8_t));
|
||||
LOGI(("data_.mac_key_client has changed to = " +
|
||||
wvcdm::b2a_hex(mac_key_client)).c_str());
|
||||
}
|
||||
}
|
||||
if (pst.size() > kMaxPSTLength) {
|
||||
LOGE("CopyOldEntry: PST Length was too large. Truncating.");
|
||||
data_.pst_length = kMaxPSTLength;
|
||||
} else {
|
||||
data_.pst_length = pst.size();
|
||||
}
|
||||
memcpy(data_.pst, &pst[0], data_.pst_length);
|
||||
data_.pst[data_.pst_length] = '\0';
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
size_t UsageTableEntry::SignedEntrySize() {
|
||||
size_t base = sizeof(SignedEntryBlock);
|
||||
// round up to make even number of blocks:
|
||||
size_t blocks = (base - 1) / wvcdm::KEY_IV_SIZE + 1;
|
||||
return blocks * wvcdm::KEY_IV_SIZE;
|
||||
}
|
||||
|
||||
UsageTable::~UsageTable() {
|
||||
if (old_table_) {
|
||||
delete old_table_;
|
||||
old_table_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
size_t UsageTable::SignedHeaderSize(size_t count) {
|
||||
size_t base = sizeof(SignedHeaderBlock) + count * sizeof(int64_t);
|
||||
// round up to make even number of blocks:
|
||||
size_t blocks = (base - 1) / wvcdm::KEY_IV_SIZE + 1;
|
||||
return blocks * wvcdm::KEY_IV_SIZE;
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTable::UpdateUsageEntry(SessionContext* session,
|
||||
UsageTableEntry* entry,
|
||||
uint8_t* header_buffer,
|
||||
size_t* header_buffer_length,
|
||||
uint8_t* entry_buffer,
|
||||
size_t* entry_buffer_length) {
|
||||
size_t signed_header_size = SignedHeaderSize(generation_numbers_.size());
|
||||
if (*entry_buffer_length < UsageTableEntry::SignedEntrySize() ||
|
||||
*header_buffer_length < signed_header_size) {
|
||||
*entry_buffer_length = UsageTableEntry::SignedEntrySize();
|
||||
*header_buffer_length = signed_header_size;
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
*entry_buffer_length = UsageTableEntry::SignedEntrySize();
|
||||
*header_buffer_length = signed_header_size;
|
||||
if ((!header_buffer) || (!entry_buffer))
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
entry->UpdateAndIncrement();
|
||||
generation_numbers_[entry->index()] = entry->generation_number();
|
||||
OEMCryptoResult result =
|
||||
entry->SaveData(ce_, session, entry_buffer, *entry_buffer_length);
|
||||
if (result != OEMCrypto_SUCCESS) return result;
|
||||
result = SaveUsageTableHeader(header_buffer, *header_buffer_length);
|
||||
return result;
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTable::CreateNewUsageEntry(SessionContext* session,
|
||||
UsageTableEntry** entry,
|
||||
uint32_t* usage_entry_number) {
|
||||
if (!header_loaded_) {
|
||||
LOGE("CreateNewUsageEntry: Header not loaded.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (!entry) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if (!usage_entry_number) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
uint32_t index = generation_numbers_.size();
|
||||
UsageTableEntry* new_entry =
|
||||
new UsageTableEntry(this, index, master_generation_number_);
|
||||
generation_numbers_.push_back(master_generation_number_);
|
||||
sessions_.push_back(session);
|
||||
master_generation_number_++;
|
||||
*entry = new_entry;
|
||||
*usage_entry_number = index;
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTable::LoadUsageEntry(SessionContext* session,
|
||||
UsageTableEntry** entry,
|
||||
uint32_t index,
|
||||
const std::vector<uint8_t>& buffer) {
|
||||
if (!header_loaded_) {
|
||||
LOGE("CreateNewUsageEntry: Header not loaded.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (!entry) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if (index >= generation_numbers_.size())
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if (sessions_[index]) {
|
||||
LOGE("LoadUsageEntry: index %d used by other session.", index);
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
UsageTableEntry* new_entry =
|
||||
new UsageTableEntry(this, index, master_generation_number_);
|
||||
|
||||
OEMCryptoResult status = new_entry->LoadData(ce_, index, buffer);
|
||||
if (status != OEMCrypto_SUCCESS) {
|
||||
delete new_entry;
|
||||
return status;
|
||||
}
|
||||
if (new_entry->generation_number() != generation_numbers_[index]) {
|
||||
LOGE("Generation SKEW: %ld -> %ld", new_entry->generation_number(),
|
||||
generation_numbers_[index]);
|
||||
if ((new_entry->generation_number() + 1 < generation_numbers_[index]) ||
|
||||
(new_entry->generation_number() - 1 > generation_numbers_[index])) {
|
||||
delete new_entry;
|
||||
return OEMCrypto_ERROR_GENERATION_SKEW;
|
||||
}
|
||||
status = OEMCrypto_WARNING_GENERATION_SKEW;
|
||||
}
|
||||
sessions_[index] = session;
|
||||
*entry = new_entry;
|
||||
return status;
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTable::ShrinkUsageTableHeader(
|
||||
uint32_t new_table_size, uint8_t* header_buffer,
|
||||
size_t* header_buffer_length) {
|
||||
if (new_table_size > generation_numbers_.size()) {
|
||||
LOGE("OEMCrypto_ShrinkUsageTableHeader: %d > %zd.", new_table_size,
|
||||
generation_numbers_.size());
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
size_t signed_header_size = SignedHeaderSize(new_table_size);
|
||||
if (*header_buffer_length < signed_header_size) {
|
||||
*header_buffer_length = signed_header_size;
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
*header_buffer_length = signed_header_size;
|
||||
if (!header_buffer) {
|
||||
LOGE("OEMCrypto_ShrinkUsageTableHeader: buffer null.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
for (size_t i = new_table_size; i < sessions_.size(); ++i) {
|
||||
if (sessions_[i]) {
|
||||
LOGE("ShrinkUsageTableHeader: session open for %d", i);
|
||||
return OEMCrypto_ERROR_ENTRY_IN_USE;
|
||||
}
|
||||
}
|
||||
generation_numbers_.resize(new_table_size);
|
||||
sessions_.resize(new_table_size);
|
||||
master_generation_number_++;
|
||||
return SaveUsageTableHeader(header_buffer, *header_buffer_length);
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTable::SaveUsageTableHeader(uint8_t* signed_buffer,
|
||||
size_t buffer_size) {
|
||||
if (!SaveGenerationNumber()) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
size_t count = generation_numbers_.size();
|
||||
// buffer_size was determined by calling function.
|
||||
if (buffer_size != SignedHeaderSize(count))
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
std::vector<uint8_t> clear_buffer(buffer_size);
|
||||
memset(&clear_buffer[0], 0, buffer_size);
|
||||
memset(signed_buffer, 0, buffer_size);
|
||||
SignedHeaderBlock* clear =
|
||||
reinterpret_cast<SignedHeaderBlock*>(&clear_buffer[0]);
|
||||
SignedHeaderBlock* encrypted =
|
||||
reinterpret_cast<SignedHeaderBlock*>(signed_buffer);
|
||||
|
||||
// Pack the clear data into the clear buffer.
|
||||
memcpy(clear->verification, kHeaderVerification, kMagicLength);
|
||||
clear->master_generation = master_generation_number_;
|
||||
clear->count = count;
|
||||
// This points to the variable size part of the buffer.
|
||||
int64_t* stored_generations =
|
||||
reinterpret_cast<int64_t*>(&clear_buffer[sizeof(SignedHeaderBlock)]);
|
||||
std::copy(generation_numbers_.begin(), generation_numbers_.begin() + count,
|
||||
stored_generations);
|
||||
|
||||
// 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 bool override_to_real = true;
|
||||
const std::vector<uint8_t>& key = ce_->DeviceRootKey(override_to_real);
|
||||
|
||||
// Encrypt the entry.
|
||||
RAND_bytes(encrypted->iv, wvcdm::KEY_IV_SIZE);
|
||||
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE]; // working iv buffer.
|
||||
memcpy(iv_buffer, encrypted->iv, wvcdm::KEY_IV_SIZE);
|
||||
AES_KEY aes_key;
|
||||
AES_set_encrypt_key(&key[0], 128, &aes_key);
|
||||
AES_cbc_encrypt(
|
||||
&clear_buffer[kEncryptionOffset], &signed_buffer[kEncryptionOffset],
|
||||
buffer_size - kEncryptionOffset, &aes_key, iv_buffer, AES_ENCRYPT);
|
||||
|
||||
// Sign the entry.
|
||||
unsigned int sig_length = SHA256_DIGEST_LENGTH;
|
||||
if (!HMAC(EVP_sha256(), &key[0], key.size(),
|
||||
&signed_buffer[SHA256_DIGEST_LENGTH],
|
||||
buffer_size - SHA256_DIGEST_LENGTH, encrypted->signature,
|
||||
&sig_length)) {
|
||||
LOGE("SaveUsageHeader: Could not sign entry.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTable::LoadUsageTableHeader(
|
||||
const std::vector<uint8_t>& buffer) {
|
||||
if (!LoadGenerationNumber(false)) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
|
||||
if (buffer.size() < SignedHeaderSize(0)) return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
std::vector<uint8_t> clear_buffer(buffer.size());
|
||||
SignedHeaderBlock* clear =
|
||||
reinterpret_cast<SignedHeaderBlock*>(&clear_buffer[0]);
|
||||
const SignedHeaderBlock* encrypted =
|
||||
reinterpret_cast<const SignedHeaderBlock*>(&buffer[0]);
|
||||
|
||||
// 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 bool override_to_real = true;
|
||||
const std::vector<uint8_t>& key = ce_->DeviceRootKey(override_to_real);
|
||||
|
||||
// Verify the signature of the usage entry. Sign encrypted into clear buffer.
|
||||
unsigned int sig_length = SHA256_DIGEST_LENGTH;
|
||||
if (!HMAC(EVP_sha256(), &key[0], key.size(), &buffer[SHA256_DIGEST_LENGTH],
|
||||
buffer.size() - SHA256_DIGEST_LENGTH, clear->signature,
|
||||
&sig_length)) {
|
||||
LOGE("LoadUsageTableHeader: Could not sign entry.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (memcmp(clear->signature, encrypted->signature, SHA256_DIGEST_LENGTH)) {
|
||||
LOGE("LoadUsageTableHeader: Signature did not match.");
|
||||
LOGE("LoadUsageTableHeader: Invalid signature given: %s",
|
||||
wvcdm::HexEncode(encrypted->signature, sig_length).c_str());
|
||||
LOGE("LoadUsageTableHeader: Invalid signature computed: %s",
|
||||
wvcdm::HexEncode(clear->signature, sig_length).c_str());
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
|
||||
// Next, decrypt the entry.
|
||||
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
|
||||
memcpy(iv_buffer, encrypted->iv, wvcdm::KEY_IV_SIZE);
|
||||
AES_KEY aes_key;
|
||||
AES_set_decrypt_key(&key[0], 128, &aes_key);
|
||||
AES_cbc_encrypt(&buffer[kEncryptionOffset], &clear_buffer[kEncryptionOffset],
|
||||
buffer.size() - kEncryptionOffset, &aes_key, iv_buffer,
|
||||
AES_DECRYPT);
|
||||
|
||||
// Check the verification string is correct.
|
||||
if (memcmp(kHeaderVerification, clear->verification, kMagicLength)) {
|
||||
LOGE("LoadUsageTableHeader: Invalid magic: %s=%8.8s expected: %s=%8.8s",
|
||||
wvcdm::HexEncode(clear->verification, kMagicLength).c_str(),
|
||||
clear->verification,
|
||||
wvcdm::HexEncode(reinterpret_cast<const uint8_t*>(kHeaderVerification),
|
||||
kMagicLength).c_str(),
|
||||
reinterpret_cast<const uint8_t*>(kHeaderVerification));
|
||||
return OEMCrypto_ERROR_BAD_MAGIC;
|
||||
}
|
||||
|
||||
// Check that size is correct, now that we know what it should be.
|
||||
if (buffer.size() < SignedHeaderSize(clear->count)) {
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
if (buffer.size() > SignedHeaderSize(clear->count)) {
|
||||
LOGW("LoadUsageTableHeader: buffer is large. %d > %d", buffer.size(),
|
||||
SignedHeaderSize(clear->count));
|
||||
}
|
||||
|
||||
OEMCryptoResult status = OEMCrypto_SUCCESS;
|
||||
if (clear->master_generation != master_generation_number_) {
|
||||
LOGE("Generation SKEW: %ld -> %ld", clear->master_generation,
|
||||
master_generation_number_);
|
||||
if ((clear->master_generation + 1 < master_generation_number_) ||
|
||||
(clear->master_generation - 1 > master_generation_number_)) {
|
||||
return OEMCrypto_ERROR_GENERATION_SKEW;
|
||||
}
|
||||
status = OEMCrypto_WARNING_GENERATION_SKEW;
|
||||
}
|
||||
int64_t* stored_generations =
|
||||
reinterpret_cast<int64_t*>(&clear_buffer[0] + sizeof(SignedHeaderBlock));
|
||||
generation_numbers_.assign(stored_generations,
|
||||
stored_generations + clear->count);
|
||||
sessions_.clear();
|
||||
sessions_.resize(clear->count);
|
||||
header_loaded_ = true;
|
||||
return status;
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTable::MoveEntry(UsageTableEntry* entry,
|
||||
uint32_t new_index) {
|
||||
if (new_index >= generation_numbers_.size()) {
|
||||
LOGE("MoveEntry: index beyond end of usage table %d >= %d", new_index,
|
||||
generation_numbers_.size());
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if (sessions_[new_index]) {
|
||||
LOGE("MoveEntry: session open for %d", new_index);
|
||||
return OEMCrypto_ERROR_ENTRY_IN_USE;
|
||||
}
|
||||
if (!entry) {
|
||||
LOGE("MoveEntry: null entry");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
sessions_[new_index] = sessions_[entry->index()];
|
||||
sessions_[entry->index()] = 0;
|
||||
|
||||
entry->set_index(new_index);
|
||||
generation_numbers_[new_index] = master_generation_number_;
|
||||
entry->set_generation_number(master_generation_number_);
|
||||
master_generation_number_++;
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
void UsageTable::IncrementGeneration() {
|
||||
master_generation_number_++;
|
||||
SaveGenerationNumber();
|
||||
}
|
||||
|
||||
bool UsageTable::SaveGenerationNumber() {
|
||||
wvcdm::FileSystem* file_system = ce_->file_system();
|
||||
std::string path;
|
||||
// Note: this path is OK for a real implementation, but using security level 1
|
||||
// would be better.
|
||||
if (!wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3,
|
||||
&path)) {
|
||||
LOGE("UsageTable: Unable to get base path");
|
||||
return false;
|
||||
}
|
||||
// On a real implementation, you should NOT put the generation number in
|
||||
// a file in user space. It should be stored in secure memory.
|
||||
std::string filename = path + "GenerationNumber.dat";
|
||||
wvcdm::File* file = file_system->Open(
|
||||
filename, wvcdm::FileSystem::kCreate | wvcdm::FileSystem::kTruncate);
|
||||
if (!file) {
|
||||
LOGE("UsageTable: File open failed: %s", path.c_str());
|
||||
return false;
|
||||
}
|
||||
file->Write(reinterpret_cast<char*>(&master_generation_number_),
|
||||
sizeof(int64_t));
|
||||
file->Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UsageTable::LoadGenerationNumber(bool or_make_new_one) {
|
||||
wvcdm::FileSystem* file_system = ce_->file_system();
|
||||
std::string path;
|
||||
// Note: this path is OK for a real implementation, but using security level 1
|
||||
// would be better.
|
||||
if (!wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3,
|
||||
&path)) {
|
||||
LOGE("UsageTable: Unable to get base path");
|
||||
return false;
|
||||
}
|
||||
// On a real implementation, you should NOT put the generation number in
|
||||
// a file in user space. It should be stored in secure memory.
|
||||
std::string filename = path + "GenerationNumber.dat";
|
||||
wvcdm::File* file = file_system->Open(filename,
|
||||
wvcdm::FileSystem::kReadOnly);
|
||||
if (!file) {
|
||||
if (or_make_new_one) {
|
||||
RAND_bytes(reinterpret_cast<uint8_t*>(&master_generation_number_),
|
||||
sizeof(int64_t));
|
||||
return true;
|
||||
}
|
||||
LOGE("UsageTable: File open failed: %s (clearing table)", path.c_str());
|
||||
master_generation_number_ = 0;
|
||||
return false;
|
||||
}
|
||||
file->Read(reinterpret_cast<char*>(&master_generation_number_),
|
||||
sizeof(int64_t));
|
||||
file->Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTable::CreateUsageTableHeader(
|
||||
uint8_t* header_buffer, size_t* header_buffer_length) {
|
||||
size_t signed_header_size = SignedHeaderSize(0);
|
||||
if (*header_buffer_length < signed_header_size) {
|
||||
*header_buffer_length = signed_header_size;
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
*header_buffer_length = signed_header_size;
|
||||
if (!LoadGenerationNumber(true)) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
// Make sure there are no entries that are currently tied to an open session.
|
||||
for (size_t i=0; i < sessions_.size(); ++i) {
|
||||
if (sessions_[i] != NULL) {
|
||||
LOGE("CreateUsageTableHeader: index %d used by session.", i);
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
}
|
||||
sessions_.clear();
|
||||
generation_numbers_.clear();
|
||||
header_loaded_ = true;
|
||||
return SaveUsageTableHeader(header_buffer, *header_buffer_length);
|
||||
}
|
||||
|
||||
OldUsageTableEntry* UsageTable::FindOldUsageEntry(
|
||||
const std::vector<uint8_t>& pst) {
|
||||
if (!old_table_) old_table_ = new OldUsageTable(ce_);
|
||||
return old_table_->FindEntry(pst);
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTable::DeleteOldUsageTable() {
|
||||
if (old_table_) {
|
||||
old_table_->Clear();
|
||||
delete old_table_;
|
||||
old_table_ = NULL;
|
||||
}
|
||||
OldUsageTable::DeleteFile(ce_);
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTable::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) {
|
||||
if (!old_table_) old_table_ = new OldUsageTable(ce_);
|
||||
std::vector<uint8_t> pstv(pst, pst+pst_length);
|
||||
OldUsageTableEntry *old_entry = old_table_->CreateEntry(pstv);
|
||||
|
||||
int64_t now = time(NULL);
|
||||
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;
|
||||
old_entry->status_ = status;
|
||||
old_entry->mac_key_server_.assign(server_mac_key,
|
||||
server_mac_key + wvcdm::MAC_KEY_SIZE);
|
||||
old_entry->mac_key_client_.assign(client_mac_key,
|
||||
client_mac_key + wvcdm::MAC_KEY_SIZE);
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
137
mock/src/oemcrypto_usage_table_mock.h
Normal file
137
mock/src/oemcrypto_usage_table_mock.h
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Mock implementation of OEMCrypto APIs
|
||||
//
|
||||
#ifndef OEMCRYPTO_USAGE_TABLE_MOCK_H_
|
||||
#define OEMCRYPTO_USAGE_TABLE_MOCK_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "file_store.h"
|
||||
#include "lock.h"
|
||||
#include "openssl/sha.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
class SessionContext;
|
||||
class CryptoEngine;
|
||||
class UsageTable;
|
||||
class OldUsageTable;
|
||||
class OldUsageTableEntry;
|
||||
|
||||
const size_t kMaxPSTLength = 255;
|
||||
// This is the data we store offline.
|
||||
struct StoredUsageEntry {
|
||||
int64_t generation_number;
|
||||
int64_t time_of_license_received;
|
||||
int64_t time_of_first_decrypt;
|
||||
int64_t time_of_last_decrypt;
|
||||
enum OEMCrypto_Usage_Entry_Status status;
|
||||
uint8_t mac_key_server[wvcdm::MAC_KEY_SIZE];
|
||||
uint8_t mac_key_client[wvcdm::MAC_KEY_SIZE];
|
||||
uint32_t index;
|
||||
uint8_t pst[kMaxPSTLength+1]; // add 1 for padding.
|
||||
uint8_t pst_length;
|
||||
};
|
||||
|
||||
class UsageTableEntry {
|
||||
public:
|
||||
UsageTableEntry(UsageTable* table, uint32_t index, int64_t generation);
|
||||
// owner_(owner), session_(session), loaded_(false) {}
|
||||
~UsageTableEntry(); // Free memory, remove reference in header.
|
||||
bool Inactive() { return data_.status >= kInactive; }
|
||||
OEMCryptoResult SetPST(const uint8_t* pst, size_t pst_length);
|
||||
bool VerifyPST(const uint8_t* pst, size_t pst_length);
|
||||
bool VerifyMacKeys(const std::vector<uint8_t>& server,
|
||||
const std::vector<uint8_t>& client);
|
||||
bool SetMacKeys(const std::vector<uint8_t>& server,
|
||||
const std::vector<uint8_t>& client);
|
||||
// Returns false if the entry is inactive. Otherwise, returns true.
|
||||
// If the status was unused, it is updated, and decrypt times are flaged
|
||||
// for update.
|
||||
bool CheckForUse();
|
||||
void Deactivate(const std::vector<uint8_t>& pst);
|
||||
OEMCryptoResult ReportUsage(const std::vector<uint8_t>& pst, uint8_t* buffer,
|
||||
size_t* buffer_length);
|
||||
void UpdateAndIncrement();
|
||||
OEMCryptoResult SaveData(CryptoEngine* ce, SessionContext* session,
|
||||
uint8_t* signed_buffer, size_t buffer_size);
|
||||
OEMCryptoResult LoadData(CryptoEngine* ce, uint32_t index,
|
||||
const std::vector<uint8_t>& buffer);
|
||||
OEMCryptoResult CopyOldUsageEntry(const std::vector<uint8_t>& pst);
|
||||
int64_t generation_number() { return data_.generation_number; }
|
||||
void set_generation_number(int64_t value) { data_.generation_number = value; }
|
||||
void set_index(int32_t index) { data_.index = index; }
|
||||
uint32_t index() { return data_.index; }
|
||||
static size_t SignedEntrySize();
|
||||
const uint8_t* mac_key_server() { return data_.mac_key_server; }
|
||||
const uint8_t* mac_key_client() { return data_.mac_key_client; }
|
||||
|
||||
private:
|
||||
UsageTable* usage_table_; // Owner of this object.
|
||||
bool recent_decrypt_;
|
||||
bool forbid_report_;
|
||||
StoredUsageEntry data_;
|
||||
};
|
||||
|
||||
class UsageTable {
|
||||
public:
|
||||
explicit UsageTable(CryptoEngine* ce)
|
||||
: ce_(ce), header_loaded_(false), old_table_(NULL){};
|
||||
~UsageTable();
|
||||
|
||||
OEMCryptoResult CreateNewUsageEntry(SessionContext* session,
|
||||
UsageTableEntry** entry,
|
||||
uint32_t* usage_entry_number);
|
||||
OEMCryptoResult LoadUsageEntry(SessionContext* session,
|
||||
UsageTableEntry** entry, uint32_t index,
|
||||
const std::vector<uint8_t>& buffer);
|
||||
OEMCryptoResult UpdateUsageEntry(SessionContext* session,
|
||||
UsageTableEntry* entry,
|
||||
uint8_t* header_buffer,
|
||||
size_t* header_buffer_length,
|
||||
uint8_t* entry_buffer,
|
||||
size_t* entry_buffer_length);
|
||||
OEMCryptoResult MoveEntry(UsageTableEntry* entry, uint32_t new_index);
|
||||
OEMCryptoResult CreateUsageTableHeader(uint8_t* header_buffer,
|
||||
size_t* header_buffer_length);
|
||||
OEMCryptoResult LoadUsageTableHeader(const std::vector<uint8_t>& buffer);
|
||||
OEMCryptoResult ShrinkUsageTableHeader(uint32_t new_table_size,
|
||||
uint8_t* header_buffer,
|
||||
size_t* header_buffer_length);
|
||||
void ReleaseEntry(uint32_t index) { sessions_[index] = 0; }
|
||||
void IncrementGeneration();
|
||||
static size_t SignedHeaderSize(size_t count);
|
||||
OldUsageTableEntry* FindOldUsageEntry(const std::vector<uint8_t>& pst);
|
||||
OEMCryptoResult DeleteOldUsageTable();
|
||||
OEMCryptoResult 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);
|
||||
|
||||
private:
|
||||
OEMCryptoResult SaveUsageTableHeader(uint8_t* signed_buffer,
|
||||
size_t buffer_size);
|
||||
bool SaveGenerationNumber();
|
||||
bool LoadGenerationNumber(bool or_make_new_one);
|
||||
|
||||
CryptoEngine* ce_;
|
||||
bool header_loaded_;
|
||||
int64_t master_generation_number_;
|
||||
std::vector<int64_t> generation_numbers_;
|
||||
std::vector<SessionContext*> sessions_;
|
||||
OldUsageTable *old_table_;
|
||||
};
|
||||
|
||||
} // namespace wvoec_mock
|
||||
|
||||
#endif // OEMCRYPTO_USAGE_TABLE_MOCK_H_
|
||||
26
mock/src/wv_keybox.h
Normal file
26
mock/src/wv_keybox.h
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef WV_KEYBOX_H_
|
||||
#define WV_KEYBOX_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
// This is the format of a Widevine keybox.
|
||||
typedef struct { // 128 bytes total.
|
||||
// C character string identifying the device. Null terminated.
|
||||
uint8_t device_id_[32];
|
||||
// 128 bit AES key assigned to device. Generated by Widevine.
|
||||
uint8_t device_key_[16];
|
||||
// Key Data. Encrypted data.
|
||||
uint8_t data_[72];
|
||||
// Constant code used to recognize a valid keybox "kbox" = 0x6b626f78.
|
||||
uint8_t magic_[4];
|
||||
// The CRC checksum of the first 124 bytes of the keybox.
|
||||
uint8_t crc_[4];
|
||||
} WidevineKeybox;
|
||||
|
||||
} // namespace wvoec_mock
|
||||
|
||||
#endif // WV_KEYBOX_H_
|
||||
94
mock/src/wvcrc.cpp
Normal file
94
mock/src/wvcrc.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Compute CRC32 Checksum. Needed for verification of WV Keybox.
|
||||
//
|
||||
#include <arpa/inet.h>
|
||||
#include "wvcrc32.h"
|
||||
|
||||
#define INIT_CRC32 0xffffffff
|
||||
|
||||
uint32_t wvrunningcrc32(const uint8_t* p_begin, int i_count, uint32_t i_crc) {
|
||||
static uint32_t CRC32[256] = {
|
||||
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
|
||||
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
|
||||
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
|
||||
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
|
||||
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
|
||||
0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
|
||||
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
|
||||
0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
|
||||
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
|
||||
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
|
||||
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
|
||||
0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
|
||||
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
|
||||
0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
|
||||
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
|
||||
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
|
||||
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
|
||||
0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
|
||||
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
|
||||
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
|
||||
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
|
||||
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
|
||||
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
|
||||
0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
|
||||
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
|
||||
0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
|
||||
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
|
||||
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
|
||||
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
|
||||
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
|
||||
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
|
||||
0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
|
||||
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
|
||||
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
|
||||
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
|
||||
0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
|
||||
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
|
||||
0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
|
||||
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
|
||||
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
|
||||
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
|
||||
0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
|
||||
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
|
||||
0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
|
||||
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
|
||||
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
|
||||
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
|
||||
0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
|
||||
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
|
||||
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
|
||||
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
|
||||
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
|
||||
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
|
||||
0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
|
||||
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
|
||||
0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
|
||||
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
|
||||
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
|
||||
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
|
||||
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
|
||||
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
|
||||
0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
|
||||
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
|
||||
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
|
||||
};
|
||||
|
||||
/* Calculate the CRC */
|
||||
while (i_count > 0) {
|
||||
i_crc = (i_crc << 8) ^ CRC32[(i_crc >> 24) ^ ((uint32_t) * p_begin)];
|
||||
p_begin++;
|
||||
i_count--;
|
||||
}
|
||||
|
||||
return(i_crc);
|
||||
}
|
||||
|
||||
uint32_t wvcrc32(const uint8_t* p_begin, int i_count) {
|
||||
return(wvrunningcrc32(p_begin, i_count, INIT_CRC32));
|
||||
}
|
||||
|
||||
uint32_t wvcrc32n(const uint8_t* p_begin, int i_count) {
|
||||
return htonl(wvrunningcrc32(p_begin, i_count, INIT_CRC32));
|
||||
}
|
||||
15
mock/src/wvcrc32.h
Normal file
15
mock/src/wvcrc32.h
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Compute CRC32 Checksum. Needed for verification of WV Keybox.
|
||||
//
|
||||
#ifndef WVCRC32_H_
|
||||
#define WVCRC32_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint32_t wvcrc32(const uint8_t* p_begin, int i_count);
|
||||
|
||||
// Convert to network byte order
|
||||
uint32_t wvcrc32n(const uint8_t* p_begin, int i_count);
|
||||
|
||||
#endif // WVCRC32_H_
|
||||
119
mock/test/oemcrypto_logging_test.cpp
Normal file
119
mock/test/oemcrypto_logging_test.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
|
||||
#include <string>
|
||||
#include <gtest/gtest.h>
|
||||
#include "log.h"
|
||||
#include "oemcrypto_logging.h"
|
||||
#include "oemcrypto_mock.cpp"
|
||||
|
||||
class OEMCryptoLoggingTest : public ::testing::Test {
|
||||
protected:
|
||||
OEMCryptoLoggingTest() {}
|
||||
|
||||
void SetUp() {
|
||||
::testing::Test::SetUp();
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize());
|
||||
}
|
||||
|
||||
void TearDown() {
|
||||
OEMCrypto_Terminate();
|
||||
::testing::Test::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(OEMCryptoLoggingTest, TestDumpHexFunctions) {
|
||||
uint8_t vector[] = {0xFA, 0x11, 0x28, 0x33};
|
||||
std::string buffer;
|
||||
wvoec_mock::dump_hex_helper(buffer, "name", vector, 4u);
|
||||
ASSERT_EQ("name = \n wvcdm::a2b_hex(\"FA112833\");\n", buffer);
|
||||
|
||||
uint8_t vector2[] = {
|
||||
0xFA, 0x11, 0x28, 0x33, 0xFA, 0x11, 0x28, 0x33, 0xFA, 0x11,
|
||||
0x28, 0x33, 0xFA, 0x11, 0x28, 0x33, 0xFA, 0x11, 0x28, 0x33,
|
||||
0xFA, 0x11, 0x28, 0x33, 0x01, 0x14, 0x28, 0xAB, 0xFA, 0xCD,
|
||||
0xEF, 0x67, 0x01, 0x14, 0x28, 0xAB, 0xFA, 0xCD, 0xEF, 0x67,
|
||||
};
|
||||
|
||||
buffer.clear(); // dump_hex_helper appends to buffer
|
||||
wvoec_mock::dump_hex_helper(buffer, "name", vector2, 40u);
|
||||
ASSERT_EQ(
|
||||
"name = \n "
|
||||
"wvcdm::a2b_hex("
|
||||
"\"FA112833FA112833FA112833FA112833FA112833FA112833011428ABFACDEF67\"\n "
|
||||
" \"011428ABFACDEF67\");\n",
|
||||
buffer);
|
||||
|
||||
buffer.clear(); // dump_hex_helper appends to buffer
|
||||
wvoec_mock::dump_array_part_helper(buffer, "array", 5u, "name", vector2, 40u);
|
||||
ASSERT_EQ(
|
||||
"std::string s5_name = \n "
|
||||
"wvcdm::a2b_hex("
|
||||
"\"FA112833FA112833FA112833FA112833FA112833FA112833011428ABFACDEF67\"\n "
|
||||
" \"011428ABFACDEF67\");\narray[5].name = message_ptr + "
|
||||
"message.find(s5_name.data());\n",
|
||||
buffer);
|
||||
|
||||
buffer.clear(); // dump_hex_helper appends to buffer
|
||||
wvoec_mock::dump_array_part_helper(buffer, "array", 5u, "name", NULL, 40u);
|
||||
ASSERT_EQ("array[5].name = NULL;\n", buffer);
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoLoggingTest, TestChangeLoggingLevel) {
|
||||
wvoec_mock::SetLoggingLevel(wvcdm::LOG_WARN);
|
||||
ASSERT_EQ(wvcdm::LOG_WARN, wvcdm::g_cutoff);
|
||||
|
||||
wvoec_mock::SetLoggingLevel(wvcdm::LOG_INFO);
|
||||
ASSERT_EQ(wvcdm::LOG_INFO, wvcdm::g_cutoff);
|
||||
|
||||
wvoec_mock::SetLoggingSettings(wvcdm::LOG_WARN,
|
||||
wvoec_mock::kLoggingDumpTraceAll);
|
||||
ASSERT_EQ(wvcdm::LOG_WARN, wvcdm::g_cutoff);
|
||||
ASSERT_TRUE(wvoec_mock::LogCategoryEnabled(wvoec_mock::kLoggingDumpTraceAll));
|
||||
wvoec_mock::TurnOffLoggingForAllCategories();
|
||||
|
||||
wvoec_mock::SetLoggingLevel(wvcdm::LOG_VERBOSE);
|
||||
ASSERT_EQ(wvcdm::LOG_VERBOSE, wvcdm::g_cutoff);
|
||||
|
||||
wvoec_mock::SetLoggingLevel(wvcdm::LOG_WARN);
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoLoggingTest, TestChangeLoggingCategories) {
|
||||
using namespace wvoec_mock;
|
||||
TurnOffLoggingForAllCategories();
|
||||
ASSERT_FALSE(LogCategoryEnabled(kLoggingTraceDecryption |
|
||||
kLoggingTraceOEMCryptoCalls));
|
||||
|
||||
AddLoggingForCategories(kLoggingDumpKeyControlBlocks |
|
||||
kLoggingDumpDerivedKeys);
|
||||
ASSERT_TRUE(LogCategoryEnabled(kLoggingDumpKeyControlBlocks));
|
||||
ASSERT_FALSE(LogCategoryEnabled(kLoggingTraceUsageTable));
|
||||
ASSERT_TRUE(LogCategoryEnabled(kLoggingDumpTraceAll));
|
||||
|
||||
RemoveLoggingForCategories(kLoggingDumpKeyControlBlocks |
|
||||
kLoggingTraceUsageTable);
|
||||
ASSERT_FALSE(LogCategoryEnabled(kLoggingDumpKeyControlBlocks));
|
||||
|
||||
ASSERT_TRUE(LogCategoryEnabled(kLoggingDumpDerivedKeys));
|
||||
ASSERT_FALSE(LogCategoryEnabled(kLoggingTraceUsageTable));
|
||||
|
||||
TurnOffLoggingForAllCategories();
|
||||
ASSERT_FALSE(LogCategoryEnabled(kLoggingTraceUsageTable));
|
||||
|
||||
AddLoggingForCategories(kLoggingDumpTraceAll);
|
||||
ASSERT_TRUE(LogCategoryEnabled(kLoggingDumpKeyControlBlocks));
|
||||
|
||||
ASSERT_TRUE(LogCategoryEnabled(kLoggingTraceOEMCryptoCalls));
|
||||
ASSERT_TRUE(LogCategoryEnabled(kLoggingDumpContentKeys));
|
||||
ASSERT_TRUE(LogCategoryEnabled(kLoggingDumpKeyControlBlocks));
|
||||
ASSERT_TRUE(LogCategoryEnabled(kLoggingDumpDerivedKeys));
|
||||
ASSERT_TRUE(LogCategoryEnabled(kLoggingTraceNonce));
|
||||
ASSERT_TRUE(LogCategoryEnabled(kLoggingTraceDecryption));
|
||||
ASSERT_TRUE(LogCategoryEnabled(kLoggingTraceUsageTable));
|
||||
ASSERT_TRUE(LogCategoryEnabled(kLoggingTraceDecryptCalls));
|
||||
ASSERT_TRUE(LogCategoryEnabled(kLoggingDumpTraceAll));
|
||||
|
||||
RemoveLoggingForCategories(kLoggingDumpKeyControlBlocks);
|
||||
ASSERT_FALSE(LogCategoryEnabled(kLoggingDumpKeyControlBlocks));
|
||||
}
|
||||
227
test/oec_device_features.cpp
Normal file
227
test/oec_device_features.cpp
Normal file
@@ -0,0 +1,227 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// OEMCrypto device features for unit tests
|
||||
//
|
||||
#include "oec_device_features.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "oec_test_data.h"
|
||||
|
||||
namespace wvoec {
|
||||
|
||||
DeviceFeatures global_features;
|
||||
|
||||
void DeviceFeatures::Initialize(bool is_cast_receiver,
|
||||
bool force_load_test_keybox) {
|
||||
cast_receiver = is_cast_receiver;
|
||||
uses_keybox = false;
|
||||
uses_certificate = false;
|
||||
loads_certificate = false;
|
||||
generic_crypto = false;
|
||||
usage_table = false;
|
||||
supports_rsa_3072 = false;
|
||||
api_version = 0;
|
||||
derive_key_method = NO_METHOD;
|
||||
if (OEMCrypto_SUCCESS != OEMCrypto_Initialize()) {
|
||||
printf("OEMCrypto_Initialize failed. All tests will fail.\n");
|
||||
return;
|
||||
}
|
||||
uint32_t nonce = 0;
|
||||
uint8_t buffer[1];
|
||||
size_t size = 0;
|
||||
provisioning_method = OEMCrypto_GetProvisioningMethod();
|
||||
printf("provisioning_method = %s\n",
|
||||
ProvisioningMethodName(provisioning_method));
|
||||
uses_keybox =
|
||||
(OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_GetKeyData(buffer, &size));
|
||||
printf("uses_keybox = %s.\n", uses_keybox ? "true" : "false");
|
||||
OEMCrypto_SESSION session;
|
||||
OEMCryptoResult result = OEMCrypto_OpenSession(&session);
|
||||
if (result != OEMCrypto_SUCCESS) {
|
||||
printf("--- ERROR: Could not open session: %d ----\n", result);
|
||||
}
|
||||
// If the device uses a keybox, check to see if loading a certificate is
|
||||
// installed.
|
||||
if (provisioning_method == OEMCrypto_Keybox) {
|
||||
loads_certificate =
|
||||
(OEMCrypto_ERROR_NOT_IMPLEMENTED !=
|
||||
OEMCrypto_RewrapDeviceRSAKey(session, buffer, 0, buffer, 0, &nonce,
|
||||
buffer, 0, buffer, buffer, &size));
|
||||
} else if (provisioning_method == OEMCrypto_OEMCertificate) {
|
||||
// If the device says it uses Provisioning 3.0, then it should be able to
|
||||
// load a DRM certificate. These devices must support RewrapDeviceRSAKey30.
|
||||
loads_certificate = true;
|
||||
} else {
|
||||
// Other devices are either broken, or they have a baked in certificate.
|
||||
loads_certificate = false;
|
||||
}
|
||||
printf("loads_certificate = %s.\n", loads_certificate ? "true" : "false");
|
||||
uses_certificate = (OEMCrypto_ERROR_NOT_IMPLEMENTED !=
|
||||
OEMCrypto_GenerateRSASignature(session, buffer, 0, buffer,
|
||||
&size, kSign_RSASSA_PSS));
|
||||
printf("uses_certificate = %s.\n", uses_certificate ? "true" : "false");
|
||||
generic_crypto =
|
||||
(OEMCrypto_ERROR_NOT_IMPLEMENTED !=
|
||||
OEMCrypto_Generic_Encrypt(session, buffer, 0, buffer,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, buffer));
|
||||
printf("generic_crypto = %s.\n", generic_crypto ? "true" : "false");
|
||||
OEMCrypto_CloseSession(session);
|
||||
api_version = OEMCrypto_APIVersion();
|
||||
printf("api_version = %d.\n", api_version);
|
||||
// These unit tests only work with new usage tables. We do not test v12
|
||||
// usage tables.
|
||||
if (api_version > 12) usage_table = OEMCrypto_SupportsUsageTable();
|
||||
printf("usage_table = %s.\n", usage_table ? "true" : "false");
|
||||
if (force_load_test_keybox) {
|
||||
derive_key_method = FORCE_TEST_KEYBOX;
|
||||
} else {
|
||||
PickDerivedKey();
|
||||
}
|
||||
if (api_version >= 13) {
|
||||
uint32_t supported_cert = OEMCrypto_SupportedCertificates();
|
||||
if (supported_cert & OEMCrypto_Supports_RSA_CAST) {
|
||||
cast_receiver = true;
|
||||
}
|
||||
if (supported_cert & OEMCrypto_Supports_RSA_3072bit) {
|
||||
supports_rsa_3072 = true;
|
||||
}
|
||||
}
|
||||
printf("cast_receiver = %s.\n", cast_receiver ? "true" : "false");
|
||||
switch (derive_key_method) {
|
||||
case NO_METHOD:
|
||||
printf("NO_METHOD: Cannot derive known session keys.\n");
|
||||
// Note: cast_receiver left unchanged because set by user on command line.
|
||||
uses_keybox = false;
|
||||
uses_certificate = false;
|
||||
loads_certificate = false;
|
||||
generic_crypto = false;
|
||||
usage_table = false;
|
||||
break;
|
||||
case LOAD_TEST_KEYBOX:
|
||||
printf("LOAD_TEST_KEYBOX: Call LoadTestKeybox before deriving keys.\n");
|
||||
break;
|
||||
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;
|
||||
case TEST_PROVISION_30:
|
||||
printf("TEST_PROVISION_30: Device provisioed with OEM Cert.\n");
|
||||
break;
|
||||
}
|
||||
OEMCrypto_Terminate();
|
||||
}
|
||||
|
||||
std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) {
|
||||
std::string filter = initial_filter;
|
||||
if (!uses_keybox) FilterOut(&filter, "*KeyboxTest*");
|
||||
if (derive_key_method
|
||||
!= FORCE_TEST_KEYBOX) FilterOut(&filter, "*ForceKeybox*");
|
||||
if (!uses_certificate) FilterOut(&filter, "OEMCrypto*Cert*");
|
||||
if (!loads_certificate) FilterOut(&filter, "OEMCryptoLoadsCert*");
|
||||
if (!generic_crypto) FilterOut(&filter, "*GenericCrypto*");
|
||||
if (!cast_receiver) FilterOut(&filter, "*CastReceiver*");
|
||||
if (!usage_table) FilterOut(&filter, "*UsageTable*");
|
||||
if (derive_key_method == NO_METHOD) FilterOut(&filter, "*SessionTest*");
|
||||
if (provisioning_method
|
||||
!= OEMCrypto_OEMCertificate) FilterOut(&filter, "*Prov30*");
|
||||
if (!supports_rsa_3072) FilterOut(&filter, "*RSAKey3072*");
|
||||
if (api_version < 9) FilterOut(&filter, "*API09*");
|
||||
if (api_version < 10) FilterOut(&filter, "*API10*");
|
||||
if (api_version < 11) FilterOut(&filter, "*API11*");
|
||||
if (api_version < 12) FilterOut(&filter, "*API12*");
|
||||
if (api_version < 13) FilterOut(&filter, "*API13*");
|
||||
if (api_version < 14) FilterOut(&filter, "*API14*");
|
||||
// Performance tests take a long time. Filter them out if they are not
|
||||
// specifically requested.
|
||||
if (filter.find("Performance") == std::string::npos) {
|
||||
FilterOut(&filter, "*Performance*");
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
|
||||
void DeviceFeatures::PickDerivedKey() {
|
||||
if (api_version >= 12) {
|
||||
switch (provisioning_method) {
|
||||
case OEMCrypto_OEMCertificate:
|
||||
derive_key_method = TEST_PROVISION_30;
|
||||
return;
|
||||
case OEMCrypto_DrmCertificate:
|
||||
if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) {
|
||||
derive_key_method = LOAD_TEST_RSA_KEY;
|
||||
}
|
||||
return;
|
||||
case OEMCrypto_Keybox:
|
||||
// Fall through to api_version < 12 case.
|
||||
break;
|
||||
case OEMCrypto_ProvisioningError:
|
||||
printf(
|
||||
"ERROR: OEMCrypto_GetProvisioningMethod() returns "
|
||||
"OEMCrypto_ProvisioningError\n");
|
||||
// Then fall through to api_version < 12 case.
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (uses_keybox) {
|
||||
// If device uses a keybox, try to load the test keybox.
|
||||
// TODO(jfore): Update to pass in parameters.
|
||||
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(kTestKeybox.data_)) return false;
|
||||
if (memcmp(key_data, kTestKeybox.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<const char*>(dev_id),
|
||||
reinterpret_cast<const char*>(kTestKeybox.device_id_),
|
||||
sizeof(kTestKeybox.device_id_));
|
||||
}
|
||||
|
||||
void DeviceFeatures::FilterOut(std::string* current_filter,
|
||||
const std::string& new_filter) {
|
||||
if (current_filter->find('-') == std::string::npos) {
|
||||
*current_filter += "-" + new_filter;
|
||||
} else {
|
||||
*current_filter += ":" + new_filter;
|
||||
}
|
||||
}
|
||||
|
||||
const char* ProvisioningMethodName(OEMCrypto_ProvisioningMethod method) {
|
||||
switch (method) {
|
||||
case OEMCrypto_ProvisioningError:
|
||||
return "OEMCrypto_ProvisioningError";
|
||||
case OEMCrypto_DrmCertificate:
|
||||
return "OEMCrypto_DrmCertificate";
|
||||
case OEMCrypto_Keybox:
|
||||
return "OEMCrypto_Keybox";
|
||||
case OEMCrypto_OEMCertificate:
|
||||
return "OEMCrypto_OEMCertificate";
|
||||
}
|
||||
// Not reachable
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace wvoec
|
||||
47
test/oec_device_features.h
Normal file
47
test/oec_device_features.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef CDM_OEC_DEVICE_FEATURES_H_
|
||||
#define CDM_OEC_DEVICE_FEATURES_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "wv_keybox.h"
|
||||
|
||||
namespace wvoec {
|
||||
|
||||
class DeviceFeatures {
|
||||
public:
|
||||
enum DeriveMethod { // Method to use derive session keys.
|
||||
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.
|
||||
};
|
||||
|
||||
enum DeriveMethod derive_key_method;
|
||||
bool uses_keybox; // Device uses a keybox to derive session keys.
|
||||
bool uses_certificate; // Device uses a certificate to derive session keys.
|
||||
bool loads_certificate; // Device can load a certificate from the server.
|
||||
bool generic_crypto; // Device supports generic crypto.
|
||||
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.
|
||||
uint32_t api_version;
|
||||
OEMCrypto_ProvisioningMethod provisioning_method;
|
||||
|
||||
void Initialize(bool is_cast_receiver, bool force_load_test_keybox);
|
||||
std::string RestrictFilter(const std::string& initial_filter);
|
||||
|
||||
private:
|
||||
void PickDerivedKey();
|
||||
bool IsTestKeyboxInstalled();
|
||||
void FilterOut(std::string* current_filter, const std::string& new_filter);
|
||||
};
|
||||
|
||||
extern DeviceFeatures global_features;
|
||||
const char* ProvisioningMethodName(OEMCrypto_ProvisioningMethod method);
|
||||
|
||||
} // namespace wvoec
|
||||
|
||||
#endif // CDM_OEC_DEVICE_FEATURES_H_
|
||||
1284
test/oec_session_util.cpp
Normal file
1284
test/oec_session_util.cpp
Normal file
File diff suppressed because it is too large
Load Diff
412
test/oec_session_util.h
Normal file
412
test/oec_session_util.h
Normal file
@@ -0,0 +1,412 @@
|
||||
#ifndef CDM_OEC_SESSION_UTIL_H_
|
||||
#define CDM_OEC_SESSION_UTIL_H_
|
||||
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// OEMCrypto unit tests
|
||||
//
|
||||
#include <openssl/rsa.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "oec_device_features.h"
|
||||
#include "pst_report.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// GTest requires PrintTo to be in the same namespace as the thing it prints,
|
||||
// which is std::vector in this case.
|
||||
namespace std {
|
||||
|
||||
void PrintTo(const vector<uint8_t>& value, ostream* os);
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace wvoec {
|
||||
|
||||
const size_t kMaxNumKeys = 20;
|
||||
|
||||
namespace {
|
||||
#if defined(TEST_SPEED_MULTIPLIER) // Can slow test time limits when
|
||||
// debugging is slowing everything.
|
||||
const int kSpeedMultiplier = TEST_SPEED_MULTIPLIER;
|
||||
#else
|
||||
const int kSpeedMultiplier = 1;
|
||||
#endif
|
||||
const int kShortSleep = 1 * kSpeedMultiplier;
|
||||
const int kLongSleep = 2 * kSpeedMultiplier;
|
||||
const uint32_t kDuration = 2 * kSpeedMultiplier;
|
||||
const uint32_t kLongDuration = 5 * kSpeedMultiplier;
|
||||
const int32_t kTimeTolerance = 3 * kSpeedMultiplier;
|
||||
const time_t kUsageTableTimeTolerance = 10 * kSpeedMultiplier;
|
||||
} // namespace
|
||||
|
||||
typedef struct {
|
||||
uint8_t verification[4];
|
||||
uint32_t duration;
|
||||
uint32_t nonce;
|
||||
uint32_t control_bits;
|
||||
} KeyControlBlock;
|
||||
|
||||
// Note: The API does not specify a maximum key id length. We specify a
|
||||
// maximum just for these tests, so that we have a fixed message size.
|
||||
const size_t kTestKeyIdMaxLength = 16;
|
||||
|
||||
// Most content will use a key id that is 16 bytes long.
|
||||
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];
|
||||
size_t key_id_length;
|
||||
uint8_t key_data[wvcdm::MAC_KEY_SIZE];
|
||||
size_t key_data_length;
|
||||
uint8_t key_iv[wvcdm::KEY_IV_SIZE];
|
||||
uint8_t control_iv[wvcdm::KEY_IV_SIZE];
|
||||
KeyControlBlock control;
|
||||
// Note: cipher_mode may not be part of a real signed message. For these
|
||||
// tests, it is convenient to keep it in this structure anyway.
|
||||
OEMCryptoCipherMode cipher_mode;
|
||||
} MessageKeyData;
|
||||
|
||||
// This structure will be signed to simulate a message from the server.
|
||||
struct MessageData {
|
||||
MessageKeyData keys[kMaxNumKeys];
|
||||
uint8_t mac_key_iv[wvcdm::KEY_IV_SIZE];
|
||||
uint8_t mac_keys[2 * wvcdm::MAC_KEY_SIZE];
|
||||
uint8_t pst[kMaxPSTLength];
|
||||
};
|
||||
|
||||
// This structure will be signed to simulate a provisioning response from the
|
||||
// server.
|
||||
struct RSAPrivateKeyMessage {
|
||||
uint8_t rsa_key[kMaxTestRSAKeyLength];
|
||||
uint8_t rsa_key_iv[wvcdm::KEY_IV_SIZE];
|
||||
size_t rsa_key_length;
|
||||
uint32_t nonce;
|
||||
};
|
||||
|
||||
struct Test_PST_Report {
|
||||
Test_PST_Report(const std::string& pst_in,
|
||||
OEMCrypto_Usage_Entry_Status status_in)
|
||||
: status(status_in), pst(pst_in) {}
|
||||
|
||||
OEMCrypto_Usage_Entry_Status status;
|
||||
int64_t seconds_since_license_received;
|
||||
int64_t seconds_since_first_decrypt;
|
||||
int64_t seconds_since_last_decrypt;
|
||||
std::string pst;
|
||||
};
|
||||
|
||||
struct EntitledContentKeyData {
|
||||
uint8_t entitlement_key_id[wvcdm::KEY_SIZE];
|
||||
uint8_t content_key_id[wvcdm::KEY_SIZE];
|
||||
uint8_t content_key_data_iv[wvcdm::KEY_SIZE];
|
||||
uint8_t content_key_data[wvcdm::KEY_SIZE];
|
||||
};
|
||||
|
||||
// Increment counter for AES-CTR. The CENC spec specifies we increment only
|
||||
// the low 64 bits of the IV counter, and leave the high 64 bits alone. This
|
||||
// is different from the OpenSSL implementation, so we implement the CTR loop
|
||||
// ourselves.
|
||||
void ctr128_inc64(int64_t increaseBy, uint8_t* iv);
|
||||
|
||||
// Some compilers don't like the macro htonl within an ASSERT_EQ.
|
||||
uint32_t htonl_fnc(uint32_t x);
|
||||
|
||||
// Prints error string from BoringSSL
|
||||
void dump_boringssl_error();
|
||||
|
||||
class Session {
|
||||
public:
|
||||
Session();
|
||||
~Session();
|
||||
|
||||
// Returns the most recently generated nonce.
|
||||
// Valid after call to GenerateNonce.
|
||||
uint32_t get_nonce() { return nonce_; }
|
||||
// Valid after call to open().
|
||||
uint32_t session_id() { return (uint32_t)session_id_; }
|
||||
// Call OEMCrypto_OpenSession, with GTest ASSERTs.
|
||||
void open();
|
||||
// Call OEMCrypto_CloseSession, with GTest ASSERTs.
|
||||
void close();
|
||||
// Artifically set session id without calling OEMCrypto_OpenSession. This is
|
||||
// used in core/test/generic_crypto_unittest.cpp.
|
||||
void SetSessionId(uint32_t session_id);
|
||||
uint32_t GetOecSessionId() { return session_id_; }
|
||||
// Generates one nonce. If error_counter is null, this will sleep 1 second
|
||||
// and try again if a nonce flood has been detected. If error_counter is
|
||||
// not null, it will be incremented when a nonce flood is detected.
|
||||
void GenerateNonce(int* error_counter = NULL);
|
||||
// Fill the vectors with test context which generate known mac and enc keys.
|
||||
void FillDefaultContext(vector<uint8_t>* mac_context,
|
||||
vector<uint8_t>* enc_context);
|
||||
// Generate known mac and enc keys using OEMCrypto_GenerateDerivedKeys and
|
||||
// also fill out enc_key_, mac_key_server_, and mac_key_client_.
|
||||
void GenerateDerivedKeysFromKeybox(const wvoec_mock::WidevineKeybox& keybox);
|
||||
// Generate known mac and enc keys using OEMCrypto_DeriveKeysFromSessionKey
|
||||
// and also fill out enc_key_, mac_key_server_, and mac_key_client_.
|
||||
void GenerateDerivedKeysFromSessionKey();
|
||||
// Loads and verifies the keys in the message pointed to by message_ptr()
|
||||
// using OEMCrypto_LoadKeys. This message should have already been created
|
||||
// by FillSimpleMessage, modified if needed, and then encrypted and signed by
|
||||
// the server's mac key in EncryptAndSign.
|
||||
void LoadTestKeys(const std::string& pst = "", bool new_mac_keys = true);
|
||||
// Loads the entitlement keys in the message pointed to by message_ptr()
|
||||
// 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 = "",
|
||||
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.
|
||||
void FillEntitledKeyArray();
|
||||
// Encrypts and loads the entitled content keys via
|
||||
// OEMCrypto_LoadEntitledContentKeys.
|
||||
void LoadEntitledContentKeys(
|
||||
OEMCryptoResult expected_sts = OEMCrypto_SUCCESS);
|
||||
// This uses OEMCrypto_QueryKeyControl to check that the keys in OEMCrypto
|
||||
// have the correct key control data.
|
||||
void VerifyTestKeys();
|
||||
// This uses OEMCrypto_QueryKeyControl to check that the keys in OEMCrypto
|
||||
// have the correct key control data.
|
||||
void VerifyEntitlementTestKeys();
|
||||
// This creates a refresh key or license renewal message, signs it with the
|
||||
// server's mac key, and calls OEMCrypto_RefreshKeys.
|
||||
void RefreshTestKeys(const size_t key_count, uint32_t control_bits,
|
||||
uint32_t nonce, OEMCryptoResult expected_result);
|
||||
// This sets the key id in the current message data to the specified string.
|
||||
// This is used to test with different key id lengths.
|
||||
void SetKeyId(int index, const string& key_id);
|
||||
// This fills the data structure license_ with key information. This data
|
||||
// can be modified, and then should be encrypted and signed in EncryptAndSign
|
||||
// before being loaded in LoadTestKeys.
|
||||
void FillSimpleMessage(uint32_t duration, uint32_t control, uint32_t nonce,
|
||||
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.
|
||||
void FillSimpleEntitlementMessage(
|
||||
uint32_t duration, uint32_t control,
|
||||
uint32_t nonce, const std::string& pst = "");
|
||||
// Like FillSimpleMessage, this fills encrypted_license_ with data. The name
|
||||
// is a little misleading: the license renewal message is not encrypted, it
|
||||
// is just signed. The signature is computed in RefreshTestKeys, above.
|
||||
void FillRefreshMessage(size_t key_count, uint32_t control_bits,
|
||||
uint32_t nonce);
|
||||
// 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
|
||||
// that array point to the locations in the encrypted message.
|
||||
void EncryptAndSign();
|
||||
// This encrypts an RSAPrivateKeyMessage with encryption_key so that it may be
|
||||
// loaded with OEMCrypto_RewrapDeviceRSAKey.
|
||||
void EncryptProvisioningMessage(RSAPrivateKeyMessage* data,
|
||||
RSAPrivateKeyMessage* encrypted,
|
||||
const vector<uint8_t>& encryption_key);
|
||||
// Sign the buffer with server's mac key.
|
||||
void ServerSignBuffer(const uint8_t* data, size_t data_length,
|
||||
std::vector<uint8_t>* signature);
|
||||
// Sign the buffer with client's known mac key. Known test keys must be
|
||||
// installed first.
|
||||
void ClientSignMessage(const vector<uint8_t>& data,
|
||||
std::vector<uint8_t>* signature);
|
||||
// This checks the signature generated by OEMCrypto_GenerateSignature against
|
||||
// that generaged by ClientSignMessage.
|
||||
void VerifyClientSignature(size_t data_length = 400);
|
||||
// Set the pointers in key_array[*] to point values inside data. This is
|
||||
// needed to satisfy range checks in OEMCrypto_LoadKeys.
|
||||
void FillKeyArray(const MessageData& data, OEMCrypto_KeyObject* key_array);
|
||||
// As in FillKeyArray but for the license renewal message passed to
|
||||
// OEMCrypto_RefreshKeys.
|
||||
void FillRefreshArray(OEMCrypto_KeyRefreshObject* key_array,
|
||||
size_t key_count);
|
||||
// Encrypt a block of data using CTR mode.
|
||||
void EncryptCTR(const vector<uint8_t>& in_buffer, const uint8_t* key,
|
||||
const uint8_t* starting_iv, vector<uint8_t>* out_buffer);
|
||||
// Encrypt some data and pass to OEMCrypto_DecryptCENC to verify decryption.
|
||||
void TestDecryptCTR(bool select_key_first = true,
|
||||
OEMCryptoResult expected_result = OEMCrypto_SUCCESS,
|
||||
int key_index = 0);
|
||||
// This compares the actual result with the expected result. If OEMCrypto is
|
||||
// an older version, we allow it to report an equivalent error code.
|
||||
void TestDecryptResult(OEMCryptoResult expected_result,
|
||||
OEMCryptoResult actual_result);
|
||||
// Verify that an attempt to select an expired key either succeeds, or gives
|
||||
// an actionable error code.
|
||||
void TestSelectExpired(unsigned int key_index);
|
||||
// Calls OEMCrypto_GetOEMPublicCertificate and loads the OEM cert's public
|
||||
// rsa key into public_rsa_.
|
||||
void LoadOEMCert(bool verify_cert = false);
|
||||
// Creates RSAPrivateKeyMessage for the specified rsa_key, encrypts it with
|
||||
// the specified encryption key, and then signs it with the server's mac key.
|
||||
// If encryption_key is null, use the session's enc_key_.
|
||||
void MakeRSACertificate(struct RSAPrivateKeyMessage* encrypted,
|
||||
size_t message_size, std::vector<uint8_t>* signature,
|
||||
uint32_t allowed_schemes,
|
||||
const vector<uint8_t>& rsa_key,
|
||||
const vector<uint8_t>* encryption_key = NULL);
|
||||
// Calls OEMCrypto_RewrapDeviceRSAKey with the given provisioning response
|
||||
// message. If force is true, we assert that the key loads successfully.
|
||||
void RewrapRSAKey(const struct RSAPrivateKeyMessage& encrypted,
|
||||
size_t message_size, const std::vector<uint8_t>& signature,
|
||||
vector<uint8_t>* wrapped_key, bool force);
|
||||
// Loads the specified RSA public key into public_rsa_. If rsa_key is null,
|
||||
// the default test key is loaded.
|
||||
void PreparePublicKey(const uint8_t* rsa_key = NULL,
|
||||
size_t rsa_key_length = 0);
|
||||
// Verifies the given signature is from the given message and RSA key, pkey.
|
||||
static bool VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message,
|
||||
size_t message_length,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length);
|
||||
// Verify that the message was signed by the private key associated with
|
||||
// |public_rsa_| using the specified padding scheme.
|
||||
void VerifyRSASignature(const vector<uint8_t>& message,
|
||||
const uint8_t* signature, size_t signature_length,
|
||||
RSA_Padding_Scheme padding_scheme);
|
||||
// Encrypts a known session key with public_rsa_ for use in future calls to
|
||||
// OEMCrypto_DeriveKeysFromSessionKey or OEMCrypto_RewrapDeviceRSAKey30.
|
||||
// The unencrypted session key is stored in session_key.
|
||||
bool GenerateRSASessionKey(vector<uint8_t>* session_key,
|
||||
vector<uint8_t>* enc_session_key);
|
||||
// Calls OEMCrypto_RewrapDeviceRSAKey30 with the given provisioning response
|
||||
// message. If force is true, we assert that the key loads successfully.
|
||||
void RewrapRSAKey30(const struct RSAPrivateKeyMessage& encrypted,
|
||||
const std::vector<uint8_t>& encrypted_message_key,
|
||||
vector<uint8_t>* wrapped_key, bool force);
|
||||
// Loads the specified wrapped_rsa_key into OEMCrypto, and then runs
|
||||
// GenerateDerivedKeysFromSessionKey to install known encryption and mac keys.
|
||||
void InstallRSASessionTestKey(const vector<uint8_t>& wrapped_rsa_key);
|
||||
// Creates a new usage entry, and keeps track of the index.
|
||||
void CreateNewUsageEntry();
|
||||
// Copy encrypted usage entry from other session, and then load it.
|
||||
// This session must already be open.
|
||||
void LoadUsageEntry(uint32_t index, const vector<uint8_t>& buffer);
|
||||
// Copy encrypted usage entry from other session.
|
||||
// This session must already be open.
|
||||
void LoadUsageEntry(const Session& other) {
|
||||
LoadUsageEntry(other.usage_entry_number(), other.encrypted_usage_entry());
|
||||
}
|
||||
// Reload previously used usage entry.
|
||||
void ReloadUsageEntry() { LoadUsageEntry(*this); }
|
||||
// Update the usage entry and save the header to the specified buffer.
|
||||
void UpdateUsageEntry(std::vector<uint8_t>* header_buffer);
|
||||
// Deactivate this session's usage entry.
|
||||
void DeactivateUsageEntry(const std::string& pst);
|
||||
// The usage entry number for this session's usage entry.
|
||||
uint32_t usage_entry_number() const { return usage_entry_number_; }
|
||||
void set_usage_entry_number(uint32_t v) { usage_entry_number_ = v; }
|
||||
// The encrypted buffer holding the recently updated and saved usage entry.
|
||||
const vector<uint8_t>& encrypted_usage_entry() const {
|
||||
return encrypted_usage_entry_;
|
||||
}
|
||||
// Generates a usage report for the specified pst. If there is success,
|
||||
// the report's signature is verified, and several fields are given sanity
|
||||
// checks. If other is not null, then the mac keys are copied from other in
|
||||
// order to verify signatures.
|
||||
void GenerateReport(const std::string& pst,
|
||||
OEMCryptoResult expected_result = OEMCrypto_SUCCESS,
|
||||
Session* other = 0);
|
||||
// Move this usage entry to a new index.
|
||||
void MoveUsageEntry(uint32_t new_index, std::vector<uint8_t>* header_buffer,
|
||||
OEMCryptoResult expect_result = OEMCrypto_SUCCESS);
|
||||
// PST used in FillSimpleMesage.
|
||||
string pst() const { return pst_; }
|
||||
// Returns a pointer-like thing to the usage report generated by the previous
|
||||
// call to GenerateReport.
|
||||
wvcdm::Unpacked_PST_Report pst_report() {
|
||||
return wvcdm::Unpacked_PST_Report(&pst_report_buffer_[0]);
|
||||
}
|
||||
// Verify the values in the PST report. The signature should have been
|
||||
// verified in GenerateReport, above.
|
||||
void VerifyPST(const Test_PST_Report& report);
|
||||
// Generate and Verify the Usage Report. If any time is greater than 10
|
||||
// minutes, it is assumed to be an absolute time, and time_since will be
|
||||
// computed relative to now.
|
||||
void GenerateVerifyReport(const std::string& pst,
|
||||
OEMCrypto_Usage_Entry_Status status,
|
||||
int64_t time_license_received = 0,
|
||||
int64_t time_first_decrypt = 0,
|
||||
int64_t time_last_decrypt = 0);
|
||||
// Create an entry in the old usage table based on the given report.
|
||||
void CreateOldEntry(const Test_PST_Report &report);
|
||||
// Create a new entry and copy the old entry into it. Then very the report
|
||||
// is right.
|
||||
void CopyAndVerifyOldEntry(const Test_PST_Report &report,
|
||||
std::vector<uint8_t>* header_buffer);
|
||||
|
||||
// The unencrypted license response or license renewal response.
|
||||
MessageData& license() { return license_; }
|
||||
// The encrypted license response or license renewal response.
|
||||
MessageData& encrypted_license() { return padded_message_; }
|
||||
|
||||
// A pointer to the buffer holding encrypted_license.
|
||||
const uint8_t* message_ptr();
|
||||
|
||||
// An array of key objects for use in LoadKeys.
|
||||
OEMCrypto_KeyObject* key_array() { return key_array_; }
|
||||
// The last signature generated with the server's mac key.
|
||||
std::vector<uint8_t>& signature() { return signature_; }
|
||||
|
||||
// Set the number of keys to use in the license(), encrypted_license()
|
||||
// and key_array().
|
||||
void set_num_keys(int num_keys) { num_keys_ = num_keys; }
|
||||
// The current number of keys to use in the license(), encrypted_license()
|
||||
// and key_array().
|
||||
unsigned int num_keys() const { return num_keys_; }
|
||||
|
||||
// Set the size of the buffer used the encrypted license.
|
||||
// Must be between sizeof(MessageData) and kMaxMessageSize.
|
||||
void set_message_size(size_t size);
|
||||
// The size of the encrypted message.
|
||||
size_t message_size() { return message_size_; }
|
||||
|
||||
private:
|
||||
// Generate mac and enc keys give the master key.
|
||||
void DeriveKeys(const uint8_t* master_key,
|
||||
const vector<uint8_t>& mac_key_context,
|
||||
const vector<uint8_t>& enc_key_context);
|
||||
// Internal utility function to derive key using CMAC-128
|
||||
void DeriveKey(const uint8_t* key, const vector<uint8_t>& context,
|
||||
int counter, vector<uint8_t>* out);
|
||||
|
||||
bool open_;
|
||||
bool forced_session_id_;
|
||||
OEMCrypto_SESSION session_id_;
|
||||
vector<uint8_t> mac_key_server_;
|
||||
vector<uint8_t> mac_key_client_;
|
||||
vector<uint8_t> enc_key_;
|
||||
uint32_t nonce_;
|
||||
RSA* public_rsa_;
|
||||
vector<uint8_t> pst_report_buffer_;
|
||||
MessageData license_;
|
||||
struct PaddedMessageData : public MessageData {
|
||||
uint8_t padding[kMaxMessageSize - sizeof(MessageData)];
|
||||
} padded_message_;
|
||||
size_t message_size_; // How much of the padded message to use.
|
||||
OEMCrypto_KeyObject key_array_[kMaxNumKeys];
|
||||
std::vector<uint8_t> signature_;
|
||||
unsigned int num_keys_;
|
||||
vector<uint8_t> encrypted_usage_entry_;
|
||||
uint32_t usage_entry_number_;
|
||||
string pst_;
|
||||
|
||||
// Clear Entitlement key data. This is the backing data for
|
||||
// |entitled_key_array_|.
|
||||
EntitledContentKeyData entitled_key_data_[kMaxNumKeys];
|
||||
// Entitled key object. Pointers are backed by |entitled_key_data_|.
|
||||
OEMCrypto_EntitledContentKeyObject entitled_key_array_[kMaxNumKeys];
|
||||
};
|
||||
|
||||
} // namespace wvoec
|
||||
|
||||
#endif // CDM_OEC_SESSION_UTIL_H_
|
||||
465
test/oec_test_data.h
Normal file
465
test/oec_test_data.h
Normal file
@@ -0,0 +1,465 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Test data for OEMCrypto unit tests.
|
||||
//
|
||||
#ifndef CDM_OEC_TEST_DATA_H_
|
||||
#define CDM_OEC_TEST_DATA_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "wv_keybox.h"
|
||||
|
||||
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_mock::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_mock::WidevineKeybox kValidKeybox01 = {
|
||||
// Sample keybox used for test vectors
|
||||
{
|
||||
// deviceID
|
||||
0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x30, // TestKey01
|
||||
0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
|
||||
}, {
|
||||
// key
|
||||
0xfb, 0xda, 0x04, 0x89, 0xa1, 0x58, 0x16, 0x0e,
|
||||
0xa4, 0x02, 0xe9, 0x29, 0xe3, 0xb6, 0x8f, 0x04,
|
||||
}, {
|
||||
// data
|
||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x19,
|
||||
0x07, 0xd9, 0xff, 0xde, 0x13, 0xaa, 0x95, 0xc1,
|
||||
0x22, 0x67, 0x80, 0x53, 0x36, 0x21, 0x36, 0xbd,
|
||||
0xf8, 0x40, 0x8f, 0x82, 0x76, 0xe4, 0xc2, 0xd8,
|
||||
0x7e, 0xc5, 0x2b, 0x61, 0xaa, 0x1b, 0x9f, 0x64,
|
||||
0x6e, 0x58, 0x73, 0x49, 0x30, 0xac, 0xeb, 0xe8,
|
||||
0x99, 0xb3, 0xe4, 0x64, 0x18, 0x9a, 0x14, 0xa8,
|
||||
0x72, 0x02, 0xfb, 0x02, 0x57, 0x4e, 0x70, 0x64,
|
||||
0x0b, 0xd2, 0x2e, 0xf4, 0x4b, 0x2d, 0x7e, 0x39,
|
||||
}, {
|
||||
// magic
|
||||
0x6b, 0x62, 0x6f, 0x78,
|
||||
}, {
|
||||
// Crc
|
||||
0x0a, 0x7a, 0x2c, 0x35,
|
||||
}
|
||||
};
|
||||
|
||||
static const wvoec_mock::WidevineKeybox kValidKeybox02 = {
|
||||
// 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, // ........
|
||||
}, {
|
||||
// key
|
||||
0x76, 0x5d, 0xce, 0x01, 0x04, 0x89, 0xb3, 0xd0,
|
||||
0xdf, 0xce, 0x54, 0x8a, 0x49, 0xda, 0xdc, 0xb6,
|
||||
}, {
|
||||
// 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,
|
||||
}, {
|
||||
// magic
|
||||
0x6b, 0x62, 0x6f, 0x78,
|
||||
}, {
|
||||
// Crc
|
||||
0x2a, 0x3b, 0x3e, 0xe4,
|
||||
}
|
||||
};
|
||||
|
||||
static const wvoec_mock::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,
|
||||
}
|
||||
};
|
||||
|
||||
// A 2048 bit RSA key in PKCS#8 PrivateKeyInfo format
|
||||
// Used to verify the functions that manipulate RSA keys.
|
||||
static const uint8_t kTestRSAPKCS8PrivateKeyInfo2_2048[] = {
|
||||
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, 0x5e,
|
||||
0x79, 0x65, 0x49, 0xa5, 0x76, 0x79, 0xf9, 0x05,
|
||||
0x45, 0x0f, 0xf4, 0x03, 0xbd, 0xa4, 0x7d, 0x29,
|
||||
0xd5, 0xde, 0x33, 0x63, 0xd8, 0xb8, 0xac, 0x97,
|
||||
0xeb, 0x3f, 0x5e, 0x55, 0xe8, 0x7d, 0xf3, 0xe7,
|
||||
0x3b, 0x5c, 0x2d, 0x54, 0x67, 0x36, 0xd6, 0x1d,
|
||||
0x46, 0xf5, 0xca, 0x2d, 0x8b, 0x3a, 0x7e, 0xdc,
|
||||
0x45, 0x38, 0x79, 0x7e, 0x65, 0x71, 0x5f, 0x1c,
|
||||
0x5e, 0x79, 0xb1, 0x40, 0xcd, 0xfe, 0xc5, 0xe1,
|
||||
0xc1, 0x6b, 0x78, 0x04, 0x4e, 0x8e, 0x79, 0xf9,
|
||||
0x0a, 0xfc, 0x79, 0xb1, 0x5e, 0xb3, 0x60, 0xe3,
|
||||
0x68, 0x7b, 0xc6, 0xef, 0xcb, 0x71, 0x4c, 0xba,
|
||||
0xa7, 0x79, 0x5c, 0x7a, 0x81, 0xd1, 0x71, 0xe7,
|
||||
0x00, 0x21, 0x13, 0xe2, 0x55, 0x69, 0x0e, 0x75,
|
||||
0xbe, 0x09, 0xc3, 0x4f, 0xa9, 0xc9, 0x68, 0x22,
|
||||
0x0e, 0x97, 0x8d, 0x89, 0x6e, 0xf1, 0xe8, 0x88,
|
||||
0x7a, 0xd1, 0xd9, 0x09, 0x5d, 0xd3, 0x28, 0x78,
|
||||
0x25, 0x0b, 0x1c, 0x47, 0x73, 0x25, 0xcc, 0x21,
|
||||
0xb6, 0xda, 0xc6, 0x24, 0x5a, 0xd0, 0x37, 0x14,
|
||||
0x46, 0xc7, 0x94, 0x69, 0xe4, 0x43, 0x6f, 0x47,
|
||||
0xde, 0x00, 0x33, 0x4d, 0x8f, 0x95, 0x72, 0xfa,
|
||||
0x68, 0x71, 0x17, 0x66, 0x12, 0x1a, 0x87, 0x27,
|
||||
0xf7, 0xef, 0x7e, 0xe0, 0x35, 0x58, 0xf2, 0x4d,
|
||||
0x6f, 0x35, 0x01, 0xaa, 0x96, 0xe2, 0x3d, 0x51,
|
||||
0x13, 0x86, 0x9c, 0x79, 0xd0, 0xb7, 0xb6, 0x64,
|
||||
0xe8, 0x86, 0x65, 0x50, 0xbf, 0xcc, 0x27, 0x53,
|
||||
0x1f, 0x51, 0xd4, 0xca, 0xbe, 0xf5, 0xdd, 0x77,
|
||||
0x70, 0x98, 0x0f, 0xee, 0xa8, 0x96, 0x07, 0x5f,
|
||||
0x45, 0x6a, 0x7a, 0x0d, 0x03, 0x9c, 0x4f, 0x29,
|
||||
0xf6, 0x06, 0xf3, 0x5d, 0x58, 0x6c, 0x47, 0xd0,
|
||||
0x96, 0xa9, 0x03, 0x17, 0xbb, 0x4e, 0xc9, 0x21,
|
||||
0xe0, 0xac, 0xcd, 0x78, 0x78, 0xb2, 0xfe, 0x81,
|
||||
0xb2, 0x51, 0x53, 0xa6, 0x1f, 0x98, 0x45, 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 };
|
||||
|
||||
// A 3072 bit RSA key in PKCS#8 PrivateKeyInfo format
|
||||
// Used to verify the functions that manipulate RSA keys.
|
||||
static const uint8_t kTestRSAPKCS8PrivateKeyInfo3_3072[] = {
|
||||
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, 0xe3, 0x32, 0x2f, 0x0a, 0x94, 0x06, 0x46, 0x99, 0x0a, 0x58,
|
||||
0xda, 0xd0, 0x9b, 0x2b, 0xe4, 0x2a, 0x35, 0xdf, 0xb7, 0x9b, 0x5e, 0xbf,
|
||||
0xfb, 0xe5, 0x24, 0x47, 0x5a, 0x94, 0x06, 0x04, 0xe5, 0x43, 0xed, 0x37,
|
||||
0x33, 0x94, 0x09, 0xd0, 0xae, 0xad, 0x86, 0xb4, 0xc7, 0xc3, 0x56, 0x6f,
|
||||
0x88, 0x74, 0xfb, 0xab, 0xf7, 0xcf, 0xcb, 0xa6, 0x89, 0x48, 0x4a, 0x02,
|
||||
0x89, 0xcd, 0xfd, 0x83, 0x3d, 0x2a, 0x27, 0xc1, 0xa2, 0x99, 0x8e, 0xef,
|
||||
0xcf, 0x91, 0xd3, 0xb2, 0x96, 0xe7, 0x5f, 0x0c, 0xb3, 0x44, 0x6a, 0xcf,
|
||||
0xc1, 0x22, 0xb9, 0xe4, 0xd4, 0xc0, 0xf2, 0xc3, 0x8d, 0xe1, 0x43, 0x38,
|
||||
0x31, 0x9c, 0x56, 0x04, 0xd4, 0x9d, 0x41, 0x02, 0x31, 0xce, 0x7e, 0xc0,
|
||||
0x11, 0x24, 0x54, 0xb1, 0xa2, 0x99, 0x0e, 0xe2, 0x0c, 0x5b, 0x24, 0x94,
|
||||
0x85, 0xe8, 0x8c, 0x30, 0xbb, 0x12, 0x94, 0x74, 0x0f, 0x67, 0xe5, 0x69,
|
||||
0xa4, 0xc4, 0x59, 0xd6, 0x77, 0x96, 0xae, 0xc6, 0x00, 0xbe, 0xf5, 0xe6,
|
||||
0x1f, 0x71, 0x90, 0x6d, 0xdd, 0xfb, 0x7b, 0x42, 0xd0, 0xdf, 0x4b, 0x58,
|
||||
0xaf, 0x9c, 0xba, 0xcb, 0x35, 0x4b, 0xf3, 0x06, 0x3a, 0x20, 0x42, 0x97,
|
||||
0x96, 0x95, 0x47, 0xbe, 0x2d, 0xeb, 0x9a, 0xb6, 0xea, 0xe0, 0xc1, 0x1d,
|
||||
0x80, 0x61, 0x3e, 0x8e, 0x18, 0x66, 0xf4, 0x26, 0x77, 0xcf, 0x56, 0x27,
|
||||
0x8b, 0xde, 0x93, 0x94, 0x3e, 0x1d, 0xe4, 0x5f, 0x6d, 0xf2, 0x39, 0x03,
|
||||
0x15, 0x4f, 0x2e, 0x58, 0x59, 0x75, 0x19, 0xb9, 0x24, 0x87, 0xd4, 0xff,
|
||||
0x64, 0x82, 0x11, 0x10, 0x34, 0x30, 0x09, 0x39, 0x43, 0x9c, 0xd2, 0x3b,
|
||||
0x45, 0xdc, 0x85, 0x4f, 0x6d, 0xb7, 0xbb, 0x49, 0xda, 0x3b, 0x07, 0xa2,
|
||||
0x76, 0x56, 0xa0, 0xee, 0xa9, 0xa9, 0x52, 0xb7, 0xf1, 0xfd, 0xde, 0xa1,
|
||||
0x6f, 0x0e, 0x7f, 0x82, 0x3f, 0x9e, 0x3d, 0x46, 0xcd, 0x48, 0x55, 0xe8,
|
||||
0x59, 0x65, 0xd8, 0xc7, 0xe4, 0x6b, 0xe6, 0xc0, 0xdd, 0x6e, 0x5c, 0xb7,
|
||||
0x0c, 0xdb, 0x29, 0xad, 0x8e, 0xa4, 0x86, 0xe9, 0x4d, 0xad, 0x54, 0xf9,
|
||||
0x56, 0x06, 0x0e, 0xc4, 0x2b, 0x01, 0xd9, 0x86, 0x1f, 0x65, 0xbe, 0x0d,
|
||||
0x77, 0x8d, 0x9d, 0xff, 0x37, 0x97, 0x57, 0xc3, 0x06, 0x8a, 0x05, 0x80,
|
||||
0x78, 0xd3, 0xbd, 0x91, 0xa5, 0xc1, 0x11, 0x4d, 0x99, 0x1a, 0x83, 0xd7,
|
||||
0x30, 0x1c, 0x24, 0xac, 0xdf, 0x6c, 0xc1, 0x23, 0x60, 0x76, 0x54, 0xbf,
|
||||
0x2b, 0xac, 0x34, 0xf0, 0x35, 0x92, 0x0d, 0x36, 0x29, 0x09, 0x24, 0xd5,
|
||||
0x54, 0xe9, 0x68, 0x9c, 0x90, 0x07, 0x16, 0x86, 0xb1, 0xd0, 0x9b, 0xa5,
|
||||
0x86, 0x4e, 0xce, 0xbf, 0x30, 0x9d, 0x91, 0xd7, 0xd2, 0xa6, 0x4f, 0xbb,
|
||||
0xbb, 0x9d, 0x7c, 0x0f, 0x58, 0xaa, 0xf1, 0xd0, 0x90, 0x66, 0x20, 0x48,
|
||||
0x8f, 0x29, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x81, 0x00,
|
||||
0x88, 0x41, 0x28, 0x85, 0x27, 0x91, 0x3b, 0xf5, 0xbc, 0x86, 0xdd, 0x74,
|
||||
0x0e, 0x1b, 0x9c, 0x92, 0xd4, 0x0c, 0x7f, 0x88, 0xe6, 0xa2, 0x2c, 0xe7,
|
||||
0x97, 0x82, 0x53, 0x88, 0x42, 0xb3, 0xdc, 0xeb, 0x87, 0xf0, 0x7b, 0x36,
|
||||
0x65, 0x4c, 0x89, 0xf5, 0xf7, 0xbb, 0xa3, 0xb2, 0x3a, 0xbc, 0x59, 0x12,
|
||||
0x0f, 0x7d, 0x6a, 0xf9, 0x6c, 0x21, 0x4c, 0x63, 0xd6, 0x3e, 0xff, 0x76,
|
||||
0x52, 0x7b, 0xca, 0xca, 0xe5, 0x5c, 0xf3, 0xaf, 0x34, 0x52, 0x0e, 0x22,
|
||||
0x5e, 0xdb, 0xd4, 0x34, 0x9e, 0x84, 0x77, 0x5e, 0xa8, 0xd0, 0x3f, 0xfc,
|
||||
0x1b, 0x90, 0x69, 0x27, 0xee, 0x6f, 0xe9, 0x3f, 0x17, 0x99, 0x33, 0xe7,
|
||||
0x96, 0x8e, 0xff, 0x13, 0xf0, 0x50, 0xe8, 0x9d, 0xf6, 0xd6, 0x29, 0x71,
|
||||
0xa8, 0x79, 0x80, 0x12, 0x5b, 0x22, 0xa6, 0x56, 0x62, 0xf1, 0xcf, 0xfd,
|
||||
0x4f, 0x56, 0x4a, 0x5b, 0x32, 0x3d, 0x08, 0xa0, 0x3e, 0xad, 0xc4, 0xeb,
|
||||
0x1d, 0x15, 0xca, 0x52, 0xcc, 0x2e, 0x63, 0x74, 0x22, 0xf5, 0x08, 0x16,
|
||||
0x8b, 0x8f, 0xd8, 0x79, 0x61, 0xcb, 0x08, 0x89, 0x62, 0x1e, 0xa5, 0xf3,
|
||||
0x50, 0xf3, 0x5d, 0xdb, 0x56, 0xbc, 0x7d, 0x4f, 0xab, 0xa0, 0x4d, 0xe6,
|
||||
0xe9, 0x47, 0xdd, 0x32, 0x57, 0x6f, 0x2c, 0x1d, 0xee, 0xb3, 0x4a, 0xb3,
|
||||
0x07, 0x59, 0x20, 0xb9, 0x5d, 0xe3, 0x54, 0x27, 0x3c, 0x7c, 0x2b, 0x1d,
|
||||
0x07, 0xff, 0x49, 0x93, 0xe2, 0xe3, 0xb2, 0x65, 0xf3, 0x69, 0xc1, 0x1c,
|
||||
0x2a, 0x75, 0x80, 0x16, 0x37, 0xe6, 0x00, 0x5b, 0xd3, 0x1b, 0xac, 0xca,
|
||||
0x8b, 0x8b, 0x98, 0x77, 0x81, 0x67, 0xe3, 0xdc, 0xbb, 0xc4, 0x3a, 0x45,
|
||||
0x15, 0xec, 0xd9, 0xad, 0xdb, 0x60, 0xcf, 0xe5, 0xd8, 0xd9, 0xfc, 0xcf,
|
||||
0xbe, 0x76, 0x2f, 0x5b, 0x60, 0xdb, 0x06, 0x62, 0x5b, 0x80, 0x7e, 0x53,
|
||||
0xde, 0x74, 0xb1, 0xa3, 0xb6, 0x9b, 0x14, 0xd7, 0x09, 0x65, 0x21, 0x1d,
|
||||
0xd5, 0xd3, 0x34, 0xca, 0x89, 0xe7, 0xbc, 0xf4, 0x48, 0x81, 0x6a, 0xcf,
|
||||
0x28, 0xbe, 0x74, 0x8b, 0x40, 0xad, 0x86, 0xcd, 0xa5, 0xd6, 0xfa, 0x64,
|
||||
0x9b, 0xd2, 0xd4, 0x17, 0x20, 0xd6, 0x0d, 0xbe, 0x95, 0xd4, 0xaf, 0xa5,
|
||||
0xde, 0x31, 0x0d, 0x6a, 0x90, 0xc6, 0xd0, 0x59, 0xd4, 0x8c, 0x81, 0x2d,
|
||||
0x9d, 0x09, 0xf1, 0x22, 0xf5, 0x30, 0x2d, 0xdf, 0x85, 0x54, 0x34, 0x8a,
|
||||
0xde, 0x3c, 0xce, 0xdb, 0x36, 0x9f, 0xcf, 0x12, 0x61, 0x0e, 0x99, 0x87,
|
||||
0x70, 0x51, 0x04, 0x91, 0x74, 0xc6, 0x88, 0x22, 0x75, 0x02, 0x8f, 0x7e,
|
||||
0xb5, 0x79, 0x48, 0x2f, 0xf3, 0x3b, 0xb8, 0x82, 0x3e, 0x7e, 0x45, 0xe5,
|
||||
0xb2, 0xc8, 0x4c, 0x12, 0x73, 0xb8, 0x92, 0x04, 0xd1, 0x9a, 0xae, 0xaa,
|
||||
0x08, 0xd9, 0x23, 0x54, 0x19, 0x46, 0xc8, 0x56, 0x5f, 0x5e, 0x10, 0xa1,
|
||||
0x02, 0x81, 0xc1, 0x00, 0xf6, 0x38, 0x88, 0x31, 0x06, 0x85, 0xd9, 0x00,
|
||||
0xf0, 0x6b, 0xd8, 0x7d, 0x76, 0x08, 0xc0, 0x69, 0x6a, 0xfb, 0xa4, 0xc8,
|
||||
0xdc, 0x6b, 0x00, 0xaf, 0xae, 0x52, 0x82, 0xe6, 0xba, 0xc9, 0x5e, 0xc9,
|
||||
0xb7, 0x7f, 0xa1, 0xc4, 0xcb, 0xa0, 0xbc, 0x66, 0x3c, 0x55, 0x6a, 0xea,
|
||||
0x6e, 0x42, 0xf1, 0x6b, 0xbd, 0xc4, 0xf2, 0x6b, 0x91, 0x11, 0x82, 0x20,
|
||||
0xc2, 0xe6, 0x9e, 0x96, 0x5c, 0x9a, 0x7e, 0xb3, 0x57, 0x45, 0x9c, 0x42,
|
||||
0x60, 0x4c, 0x04, 0x4f, 0x47, 0xfb, 0xa7, 0x68, 0x4e, 0x15, 0x43, 0x5a,
|
||||
0x97, 0xb3, 0xfc, 0xd2, 0x91, 0x3c, 0x11, 0x5e, 0xaf, 0x57, 0x2a, 0xa1,
|
||||
0x45, 0xa5, 0x60, 0xf0, 0xbe, 0x31, 0xe8, 0xc4, 0x0b, 0x35, 0xe3, 0x42,
|
||||
0x9b, 0x22, 0x6b, 0xa3, 0x6c, 0x49, 0x71, 0x20, 0x34, 0x3f, 0x46, 0x0b,
|
||||
0x79, 0xc9, 0xb8, 0xb4, 0xbd, 0x9c, 0xad, 0xd3, 0xd8, 0x7e, 0x95, 0x9f,
|
||||
0x9a, 0xd4, 0x03, 0xe9, 0x5a, 0x54, 0x46, 0x94, 0x39, 0x55, 0xf1, 0x28,
|
||||
0x0d, 0xd1, 0xaa, 0xc9, 0xf8, 0x28, 0x58, 0xef, 0xb0, 0x62, 0xb6, 0x2d,
|
||||
0xc7, 0xd2, 0x09, 0x3a, 0x21, 0x0f, 0x7d, 0xa1, 0xb9, 0x59, 0xd5, 0xa7,
|
||||
0x43, 0xa9, 0x51, 0xb7, 0xbf, 0x9d, 0xf3, 0x85, 0xec, 0xb3, 0xfb, 0x51,
|
||||
0x61, 0xca, 0x81, 0x4d, 0xfa, 0xf1, 0xc3, 0x94, 0x37, 0x45, 0x91, 0xf0,
|
||||
0x4b, 0xfc, 0x8e, 0xff, 0x02, 0x81, 0xc1, 0x00, 0xec, 0x38, 0x37, 0x3b,
|
||||
0xba, 0x1b, 0x83, 0xaf, 0x3a, 0x00, 0xb9, 0x5e, 0x1f, 0xc8, 0xad, 0x57,
|
||||
0xcf, 0x7c, 0xe2, 0x94, 0x95, 0xf1, 0xec, 0x0a, 0x4b, 0x40, 0xc4, 0x48,
|
||||
0xfb, 0x47, 0x5f, 0x66, 0xc6, 0xf0, 0x70, 0x14, 0xe9, 0x08, 0xe4, 0x50,
|
||||
0x29, 0x0a, 0x24, 0x57, 0x93, 0x97, 0x21, 0xd9, 0xfb, 0xc5, 0x52, 0x0a,
|
||||
0x38, 0xb9, 0x68, 0xa3, 0x4f, 0x4b, 0xf8, 0xb8, 0x24, 0xef, 0x0c, 0x42,
|
||||
0xda, 0x57, 0x32, 0x77, 0xed, 0x9c, 0x78, 0xeb, 0x10, 0x3e, 0x70, 0x67,
|
||||
0xe9, 0x01, 0x03, 0x19, 0x19, 0xdb, 0x48, 0x9e, 0x1e, 0x52, 0x23, 0x88,
|
||||
0xb6, 0x87, 0xb8, 0x0d, 0x2d, 0x0c, 0xfc, 0x90, 0x31, 0x9f, 0xa6, 0x96,
|
||||
0x0a, 0xe1, 0x34, 0x72, 0x86, 0x0e, 0x49, 0x7c, 0xfe, 0x21, 0xaa, 0x25,
|
||||
0xdd, 0x36, 0xbb, 0x1f, 0x85, 0xfe, 0x34, 0x18, 0xc2, 0x36, 0xa2, 0x7d,
|
||||
0xee, 0xd9, 0x4f, 0x8e, 0xcb, 0x49, 0x8e, 0x7a, 0x43, 0x3c, 0x52, 0x73,
|
||||
0x18, 0x60, 0xf6, 0xb7, 0x7a, 0xc4, 0x7a, 0x8a, 0x1c, 0xf0, 0xc9, 0x2e,
|
||||
0xad, 0x54, 0xb1, 0x7b, 0x8e, 0xcb, 0x4d, 0xc2, 0xbc, 0x2a, 0x72, 0xfe,
|
||||
0x61, 0x01, 0xd8, 0xff, 0x0a, 0x22, 0x6c, 0x51, 0x7e, 0x06, 0x9e, 0x9e,
|
||||
0x3c, 0xe8, 0x31, 0x98, 0xf5, 0x08, 0x34, 0x7e, 0xfa, 0x08, 0xd1, 0x14,
|
||||
0xdf, 0xfd, 0x26, 0x2f, 0x1f, 0x5a, 0x89, 0xd7, 0x02, 0x81, 0xc0, 0x76,
|
||||
0xdd, 0xed, 0xe9, 0xf5, 0x23, 0x33, 0x13, 0x3f, 0xfe, 0x60, 0xa2, 0x99,
|
||||
0x14, 0x3a, 0x87, 0xea, 0x0d, 0x18, 0x8d, 0x9b, 0xd3, 0xd0, 0x9d, 0xff,
|
||||
0xc3, 0x77, 0xcc, 0x9a, 0x0a, 0x53, 0x47, 0x80, 0xde, 0x0e, 0x23, 0xea,
|
||||
0xc6, 0x6b, 0x8d, 0xd3, 0xbc, 0xcd, 0x03, 0xe6, 0x3d, 0x4d, 0x3d, 0xdd,
|
||||
0x7c, 0xb2, 0x27, 0xf9, 0xfe, 0x00, 0xdb, 0x7e, 0x1c, 0x46, 0x1d, 0x83,
|
||||
0x11, 0x56, 0xef, 0x8f, 0xc7, 0x5c, 0x5b, 0xb3, 0x0f, 0x9f, 0xd9, 0x02,
|
||||
0x80, 0x5c, 0x5e, 0x7f, 0xab, 0xc6, 0x3b, 0x7b, 0x17, 0x7a, 0x8b, 0xd1,
|
||||
0x6f, 0xb5, 0x57, 0x07, 0xc1, 0x46, 0x24, 0x5b, 0x72, 0x2e, 0xad, 0xaa,
|
||||
0xb4, 0x7f, 0x91, 0xfd, 0x73, 0x83, 0x86, 0x89, 0x4c, 0x81, 0xb8, 0x80,
|
||||
0xb3, 0xa7, 0xf8, 0x8b, 0x20, 0xac, 0xd9, 0x27, 0x6f, 0x9a, 0x4b, 0x2f,
|
||||
0x6a, 0xef, 0x84, 0x61, 0x75, 0x23, 0x18, 0xcd, 0x6f, 0x63, 0x80, 0x09,
|
||||
0x8a, 0xbc, 0x14, 0x1c, 0xe5, 0xff, 0xa9, 0x7d, 0x9a, 0x66, 0x20, 0x61,
|
||||
0x3c, 0x61, 0x4b, 0x3d, 0xd5, 0x39, 0xec, 0x3a, 0x16, 0x8d, 0x3b, 0xd1,
|
||||
0xf0, 0x1f, 0x8f, 0xae, 0xe2, 0xce, 0xc1, 0x94, 0x69, 0xae, 0xb8, 0xcd,
|
||||
0xba, 0x1c, 0x71, 0xe0, 0x47, 0x37, 0xa2, 0x1f, 0x5a, 0xdb, 0x37, 0xe1,
|
||||
0x59, 0x4c, 0x39, 0x46, 0xc1, 0xc0, 0x65, 0xc8, 0xd9, 0x61, 0xd3, 0x02,
|
||||
0x81, 0xc0, 0x2f, 0x63, 0xe7, 0xd0, 0xd7, 0xb9, 0x85, 0x65, 0xb6, 0x21,
|
||||
0x47, 0x0f, 0x17, 0x19, 0x4f, 0x8d, 0x7a, 0x56, 0xf7, 0xae, 0x0f, 0x97,
|
||||
0x05, 0x5f, 0xdb, 0x51, 0x17, 0x0f, 0xfd, 0x39, 0x88, 0x6e, 0x3a, 0x23,
|
||||
0x2a, 0x99, 0x47, 0x57, 0x3d, 0x56, 0xc7, 0xa4, 0xfd, 0x3d, 0x84, 0xa2,
|
||||
0xa1, 0x6b, 0xf6, 0x12, 0xd4, 0x2e, 0xb0, 0xca, 0xa1, 0xaf, 0x81, 0xcd,
|
||||
0x20, 0x0c, 0xf1, 0x7b, 0xf3, 0xdd, 0xc5, 0xa8, 0x10, 0xbb, 0xf6, 0xb3,
|
||||
0x99, 0x9e, 0xaf, 0x17, 0x97, 0xbd, 0x81, 0x05, 0x6e, 0xf5, 0xae, 0x36,
|
||||
0x4c, 0x0f, 0x4c, 0xcd, 0xf5, 0xcb, 0x0b, 0xb3, 0x96, 0xbd, 0x2d, 0xf8,
|
||||
0x99, 0x02, 0xe4, 0xb1, 0xbe, 0xde, 0x03, 0x38, 0xc3, 0x28, 0xe6, 0xb4,
|
||||
0x1f, 0x12, 0x30, 0x79, 0xd8, 0x84, 0xd8, 0x28, 0x8e, 0xc9, 0xf8, 0x3b,
|
||||
0xd3, 0x7f, 0xd4, 0x16, 0xd9, 0xea, 0xa1, 0xec, 0x7f, 0x05, 0x8a, 0xcb,
|
||||
0x2b, 0x06, 0x64, 0x4e, 0xc9, 0xcb, 0xc5, 0x6c, 0x4e, 0x92, 0xe8, 0xd2,
|
||||
0x5a, 0x33, 0x33, 0x33, 0x2b, 0x69, 0x6d, 0xe4, 0xbb, 0xe6, 0xa9, 0xf3,
|
||||
0x27, 0x9a, 0x95, 0xdd, 0x7e, 0x4c, 0x82, 0x71, 0xb8, 0x73, 0x12, 0x39,
|
||||
0x6d, 0xb9, 0xbb, 0xaa, 0xe0, 0x4f, 0xa6, 0xb0, 0x7e, 0xa2, 0xcd, 0x25,
|
||||
0xe4, 0x42, 0x45, 0x2f, 0x57, 0xa2, 0xf4, 0x7c, 0xf9, 0x18, 0x23, 0x16,
|
||||
0x2a, 0xe9, 0x02, 0x81, 0xc1, 0x00, 0xab, 0x35, 0x0d, 0x35, 0x94, 0x9d,
|
||||
0x96, 0xb2, 0xb7, 0x45, 0x16, 0xef, 0xb7, 0xea, 0xba, 0xa4, 0x32, 0xec,
|
||||
0x43, 0x05, 0xb0, 0x14, 0xbd, 0x9e, 0xd2, 0xbe, 0x0a, 0x0c, 0x4f, 0xca,
|
||||
0x4f, 0xf3, 0x11, 0xb3, 0x1f, 0xdc, 0x04, 0x18, 0x38, 0x9d, 0xb0, 0x09,
|
||||
0xb8, 0xf1, 0xcf, 0x7a, 0x89, 0x03, 0xd8, 0xed, 0x28, 0x30, 0xe8, 0xe6,
|
||||
0xbc, 0x7c, 0x1c, 0x59, 0x12, 0xf8, 0x95, 0x9b, 0x36, 0xad, 0xf2, 0xea,
|
||||
0x4a, 0x34, 0x00, 0xcf, 0x94, 0x3e, 0xeb, 0xff, 0xe2, 0x5b, 0x6c, 0x72,
|
||||
0xe3, 0x04, 0xd1, 0x10, 0x2e, 0xdd, 0x18, 0x8d, 0x9a, 0x84, 0x93, 0x55,
|
||||
0x4a, 0x80, 0x6c, 0xb5, 0x82, 0xc4, 0x16, 0x19, 0xc4, 0xba, 0xad, 0x2e,
|
||||
0x40, 0x76, 0xb3, 0xc9, 0xd4, 0x26, 0x5d, 0xc9, 0xb1, 0x05, 0x0f, 0x1f,
|
||||
0x7d, 0x59, 0x8c, 0x7b, 0xbe, 0x34, 0x09, 0x3e, 0x71, 0x0b, 0xc8, 0xf9,
|
||||
0xb3, 0x77, 0x4e, 0x4b, 0xfb, 0xbf, 0x81, 0x55, 0xa4, 0x5e, 0xc6, 0xe9,
|
||||
0xa1, 0xc3, 0x16, 0xff, 0xc8, 0x37, 0x88, 0xd5, 0x2d, 0xfb, 0x06, 0x98,
|
||||
0xe9, 0x82, 0x1b, 0x5e, 0x1e, 0xdd, 0x48, 0x5d, 0x6c, 0x59, 0xee, 0x7a,
|
||||
0xa6, 0xa4, 0x29, 0x41, 0x20, 0xb4, 0xcd, 0xf4, 0x58, 0x95, 0xfd, 0x7d,
|
||||
0xbf, 0xfc, 0x83, 0xf5, 0xe1, 0x5a, 0x5d, 0xa8, 0x08, 0x66, 0xd8, 0xa0,
|
||||
0x7f, 0xad, 0x7d, 0xcd, 0x22, 0x06
|
||||
};
|
||||
|
||||
} // namespace wvoec
|
||||
|
||||
#endif // CDM_OEC_TEST_DATA_H_
|
||||
159
test/oemcrypto_session_tests_helper.cpp
Normal file
159
test/oemcrypto_session_tests_helper.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
#include "oemcrypto_session_tests_helper.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "oec_test_data.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace wvoec;
|
||||
|
||||
namespace wvoec {
|
||||
|
||||
// Make this function available when in Fuzz mode because we are not inheriting
|
||||
// from OEMCryptoClientTest.
|
||||
const uint8_t* find(const vector<uint8_t>& message,
|
||||
const vector<uint8_t>& substring) {
|
||||
vector<uint8_t>::const_iterator pos = search(
|
||||
message.begin(), message.end(), substring.begin(), substring.end());
|
||||
if (pos == message.end()) {
|
||||
return NULL;
|
||||
}
|
||||
return &(*pos);
|
||||
}
|
||||
|
||||
// If force is true, we assert that the key loads successfully.
|
||||
void SessionUtil::CreateWrappedRSAKeyFromKeybox(uint32_t allowed_schemes,
|
||||
bool force) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox(keybox_));
|
||||
// Provisioning request would be signed by the client and verified by the
|
||||
// server.
|
||||
ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature());
|
||||
struct RSAPrivateKeyMessage encrypted;
|
||||
std::vector<uint8_t> signature;
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s.MakeRSACertificate(&encrypted, sizeof(encrypted),
|
||||
&signature, allowed_schemes,
|
||||
encoded_rsa_key_));
|
||||
ASSERT_NO_FATAL_FAILURE(s.RewrapRSAKey(
|
||||
encrypted, sizeof(encrypted), signature, &wrapped_rsa_key_, force));
|
||||
// Verify that the clear key is not contained in the wrapped key.
|
||||
// It should be encrypted.
|
||||
ASSERT_EQ(NULL, find(wrapped_rsa_key_, encoded_rsa_key_));
|
||||
}
|
||||
|
||||
// If force is true, we assert that the key loads successfully.
|
||||
void SessionUtil::CreateWrappedRSAKeyFromOEMCert(
|
||||
uint32_t allowed_schemes, bool force) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(s.LoadOEMCert());
|
||||
s.GenerateNonce();
|
||||
struct RSAPrivateKeyMessage encrypted;
|
||||
std::vector<uint8_t> signature;
|
||||
std::vector<uint8_t> message_key;
|
||||
std::vector<uint8_t> encrypted_message_key;
|
||||
s.GenerateRSASessionKey(&message_key, &encrypted_message_key);
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s.MakeRSACertificate(&encrypted, sizeof(encrypted), &signature,
|
||||
allowed_schemes, encoded_rsa_key_, &message_key));
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s.RewrapRSAKey30(encrypted, encrypted_message_key,
|
||||
&wrapped_rsa_key_, force));
|
||||
// Verify that the clear key is not contained in the wrapped key.
|
||||
// It should be encrypted.
|
||||
ASSERT_EQ(NULL, find(wrapped_rsa_key_, encoded_rsa_key_));
|
||||
}
|
||||
|
||||
// If force is true, we assert that the key loads successfully.
|
||||
void SessionUtil::CreateWrappedRSAKey(uint32_t allowed_schemes,
|
||||
bool force) {
|
||||
switch (global_features.provisioning_method) {
|
||||
case OEMCrypto_OEMCertificate:
|
||||
CreateWrappedRSAKeyFromOEMCert(allowed_schemes, force);
|
||||
break;
|
||||
case OEMCrypto_Keybox:
|
||||
CreateWrappedRSAKeyFromKeybox(allowed_schemes, force);
|
||||
break;
|
||||
default:
|
||||
FAIL() << "Cannot generate wrapped RSA key if provision method = "
|
||||
<< wvoec::ProvisioningMethodName(
|
||||
global_features.provisioning_method);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionUtil::InstallKeybox(const wvoec_mock::WidevineKeybox& keybox,
|
||||
bool good) {
|
||||
uint8_t wrapped[sizeof(wvoec_mock::WidevineKeybox)];
|
||||
size_t length = sizeof(wvoec_mock::WidevineKeybox);
|
||||
keybox_ = keybox;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
OEMCrypto_WrapKeybox(reinterpret_cast<const uint8_t*>(&keybox),
|
||||
sizeof(keybox), wrapped, &length, NULL, 0));
|
||||
OEMCryptoResult sts = OEMCrypto_InstallKeybox(wrapped, sizeof(keybox));
|
||||
if (good) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
} else {
|
||||
// Can return error now, or return error on IsKeyboxValid.
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
* uncomment the following line. This uses the same test keybox as we
|
||||
* used in older versions of this test.
|
||||
*/
|
||||
// keybox_ = kValidKeybox01;
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_LoadTestKeybox(
|
||||
reinterpret_cast<const uint8_t*>(&keybox_),
|
||||
sizeof(keybox_)));
|
||||
break;
|
||||
case DeviceFeatures::LOAD_TEST_RSA_KEY:
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestRSAKey());
|
||||
break;
|
||||
case DeviceFeatures::EXISTING_TEST_KEYBOX:
|
||||
// already has test keybox.
|
||||
keybox_ = kTestKeybox;
|
||||
break;
|
||||
case DeviceFeatures::FORCE_TEST_KEYBOX:
|
||||
keybox_ = kTestKeybox;
|
||||
InstallKeybox(keybox_, true);
|
||||
break;
|
||||
case DeviceFeatures::TEST_PROVISION_30:
|
||||
// Can use oem certificate to install test rsa key.
|
||||
break;
|
||||
default:
|
||||
FAIL() << "Cannot run test without test keybox or RSA key installed.";
|
||||
}
|
||||
}
|
||||
|
||||
// This makes sure that the derived keys (encryption key and two mac keys)
|
||||
// are installed in OEMCrypto and in the test session.
|
||||
void SessionUtil::InstallTestSessionKeys(Session* s) {
|
||||
if (global_features.uses_certificate) {
|
||||
if (global_features.loads_certificate) {
|
||||
if (wrapped_rsa_key_.size() == 0) {
|
||||
// If we don't have a wrapped key yet, create one.
|
||||
// This wrapped key will be shared by all sessions in the test.
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
CreateWrappedRSAKey(kSign_RSASSA_PSS, true));
|
||||
}
|
||||
// Load the wrapped rsa test key.
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s->InstallRSASessionTestKey(wrapped_rsa_key_));
|
||||
}
|
||||
// Test RSA key should be loaded.
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s->GenerateDerivedKeysFromSessionKey());
|
||||
} else { // Just uses keybox. Test keybox should already be installed.
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s->GenerateDerivedKeysFromKeybox(keybox_));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
40
test/oemcrypto_session_tests_helper.h
Normal file
40
test/oemcrypto_session_tests_helper.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "oec_session_util.h"
|
||||
#include "oec_test_data.h"
|
||||
#include "OEMCryptoCENC.h"
|
||||
|
||||
namespace wvoec {
|
||||
|
||||
class SessionUtil {
|
||||
public:
|
||||
SessionUtil()
|
||||
: encoded_rsa_key_(kTestRSAPKCS8PrivateKeyInfo2_2048,
|
||||
kTestRSAPKCS8PrivateKeyInfo2_2048 +
|
||||
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048)) {}
|
||||
|
||||
// If force is true, we assert that the key loads successfully.
|
||||
void CreateWrappedRSAKeyFromKeybox(uint32_t allowed_schemes, bool force);
|
||||
|
||||
// If force is true, we assert that the key loads successfully.
|
||||
void CreateWrappedRSAKeyFromOEMCert(uint32_t allowed_schemes, bool force);
|
||||
|
||||
// If force is true, we assert that the key loads successfully.
|
||||
void CreateWrappedRSAKey(uint32_t allowed_schemes, bool force);
|
||||
|
||||
void InstallKeybox(const wvoec_mock::WidevineKeybox& keybox, bool good);
|
||||
|
||||
void EnsureTestKeys();
|
||||
|
||||
void InstallTestSessionKeys(Session* s);
|
||||
|
||||
std::vector<uint8_t> encoded_rsa_key_;
|
||||
std::vector<uint8_t> wrapped_rsa_key_;
|
||||
wvoec_mock::WidevineKeybox keybox_;
|
||||
};
|
||||
|
||||
} // namespace wvoec
|
||||
5714
test/oemcrypto_test.cpp
Normal file
5714
test/oemcrypto_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
151
test/oemcrypto_test_android.cpp
Normal file
151
test/oemcrypto_test_android.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// OEMCrypto unit tests - extra tests required for Android platform.
|
||||
//
|
||||
// The Widevine CDM system can be built on many platforms, with different
|
||||
// capabilities. For example, some platforms do not require usage tables,
|
||||
// and some can have a pre-installed certificate and do not need a keybox.
|
||||
// On Android, these features are not optional. This set of unit tests
|
||||
// verify that these features are implemented.
|
||||
//
|
||||
// In the file oemcrypto_test.cpp, the unit tests only verify correct
|
||||
// functionality for functions that are implemented. Android devices must pass
|
||||
// unit tests in both files.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "oec_test_data.h"
|
||||
#include "OEMCryptoCENC.h"
|
||||
|
||||
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 TearDown() { OEMCrypto_Terminate(); }
|
||||
};
|
||||
|
||||
// Android devices must have a keybox, or use provisioning 3.0.
|
||||
TEST_F(OEMCryptoAndroidLMPTest, GetKeyDataImplemented) {
|
||||
uint8_t key_data[256];
|
||||
size_t key_data_len = sizeof(key_data);
|
||||
if (OEMCrypto_Keybox == OEMCrypto_GetProvisioningMethod()) {
|
||||
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED,
|
||||
OEMCrypto_GetKeyData(key_data, &key_data_len));
|
||||
} else {
|
||||
ASSERT_EQ(OEMCrypto_OEMCertificate, OEMCrypto_GetProvisioningMethod());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoAndroidLMPTest, MinVersionNumber9) {
|
||||
uint32_t version = OEMCrypto_APIVersion();
|
||||
ASSERT_LE(9u, version);
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoAndroidLMPTest, ValidKeyboxTest) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid());
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoAndroidLMPTest, RewrapDeviceRSAKeyImplemented) {
|
||||
if (OEMCrypto_Keybox == OEMCrypto_GetProvisioningMethod()) {
|
||||
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED,
|
||||
OEMCrypto_RewrapDeviceRSAKey(0, NULL, 0, NULL, 0, NULL, NULL, 0,
|
||||
NULL, NULL, NULL));
|
||||
} else {
|
||||
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED,
|
||||
OEMCrypto_RewrapDeviceRSAKey30(0, NULL, NULL, 0, NULL, 0, NULL,
|
||||
NULL, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoAndroidLMPTest, RSASignatureImplemented) {
|
||||
ASSERT_NE(
|
||||
OEMCrypto_ERROR_NOT_IMPLEMENTED,
|
||||
OEMCrypto_GenerateRSASignature(0, NULL, 0, NULL, NULL, kSign_RSASSA_PSS));
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoAndroidLMPTest, GenericCryptoImplemented) {
|
||||
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED,
|
||||
OEMCrypto_Generic_Encrypt(0, NULL, 0, NULL,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, NULL));
|
||||
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED,
|
||||
OEMCrypto_Generic_Decrypt(0, NULL, 0, NULL,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, NULL));
|
||||
ASSERT_NE(
|
||||
OEMCrypto_ERROR_NOT_IMPLEMENTED,
|
||||
OEMCrypto_Generic_Sign(0, NULL, 0, OEMCrypto_HMAC_SHA256, NULL, NULL));
|
||||
ASSERT_NE(
|
||||
OEMCrypto_ERROR_NOT_IMPLEMENTED,
|
||||
OEMCrypto_Generic_Verify(0, NULL, 0, OEMCrypto_HMAC_SHA256, NULL, 0));
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoAndroidLMPTest, SupportsUsageTable) {
|
||||
ASSERT_TRUE(OEMCrypto_SupportsUsageTable());
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoAndroidLMPTest, Level1Required) {
|
||||
const char* char_level = OEMCrypto_SecurityLevel();
|
||||
std::string security_level(char_level ? char_level : "");
|
||||
EXPECT_EQ("L1", security_level)
|
||||
<< "The security level is " << security_level << ". but we expect L1.\n"
|
||||
<< "If you are testing a device that should be L3 or L2, please\n"
|
||||
<< "repeat the tests with the flag --gtest_filter=\"*-*Level1Required\"";
|
||||
}
|
||||
|
||||
// These tests are required for M Android devices.
|
||||
class OEMCryptoAndroidMNCTest : public OEMCryptoAndroidLMPTest {};
|
||||
|
||||
TEST_F(OEMCryptoAndroidMNCTest, MinVersionNumber10) {
|
||||
uint32_t version = OEMCrypto_APIVersion();
|
||||
ASSERT_GE(version, 10u);
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoAndroidMNCTest, LoadsTestKeyboxImplemented) {
|
||||
if (OEMCrypto_Keybox == OEMCrypto_GetProvisioningMethod()) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestKeybox(
|
||||
reinterpret_cast<const uint8_t*>(&kTestKeybox),
|
||||
sizeof(kTestKeybox)));
|
||||
} else {
|
||||
// Android should use keybox or provisioning 3.0.
|
||||
ASSERT_EQ(OEMCrypto_OEMCertificate, OEMCrypto_GetProvisioningMethod());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoAndroidMNCTest, NumberOfSessionsImplemented) {
|
||||
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED,
|
||||
OEMCrypto_GetNumberOfOpenSessions(NULL));
|
||||
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED,
|
||||
OEMCrypto_GetMaxNumberOfSessions(NULL));
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoAndroidMNCTest, QueryKeyControlImplemented) {
|
||||
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED,
|
||||
OEMCrypto_QueryKeyControl(0, NULL, 0, NULL, NULL));
|
||||
}
|
||||
|
||||
// These tests are required for N Android devices.
|
||||
class OEMCryptoAndroidNYCTest : public OEMCryptoAndroidMNCTest {};
|
||||
|
||||
TEST_F(OEMCryptoAndroidNYCTest, MinVersionNumber11) {
|
||||
uint32_t version = OEMCrypto_APIVersion();
|
||||
ASSERT_GE(version, 11u);
|
||||
}
|
||||
|
||||
// These tests are required for O MR1 Android devices.
|
||||
class OEMCryptoAndroidOCTest : public OEMCryptoAndroidNYCTest {};
|
||||
|
||||
TEST_F(OEMCryptoAndroidOCTest, MinVersionNumber13) {
|
||||
uint32_t version = OEMCrypto_APIVersion();
|
||||
ASSERT_GE(version, 13u);
|
||||
}
|
||||
|
||||
// These tests are required for Pi Android devices.
|
||||
class OEMCryptoAndroidPiTest : public OEMCryptoAndroidOCTest {};
|
||||
|
||||
TEST_F(OEMCryptoAndroidPiTest, MinVersionNumber14) {
|
||||
uint32_t version = OEMCrypto_APIVersion();
|
||||
ASSERT_GE(version, 14u);
|
||||
}
|
||||
|
||||
} // namespace wvoec
|
||||
43
test/oemcrypto_test_main.cpp
Normal file
43
test/oemcrypto_test_main.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "log.h"
|
||||
#include "oec_device_features.h"
|
||||
#include "properties.h"
|
||||
|
||||
static void acknowledge_cast() {
|
||||
std::cout
|
||||
<< "==================================================================\n"
|
||||
<< "= This device is expected to load x509 certs as a cast receiver. =\n"
|
||||
<< "==================================================================\n";
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
wvcdm::Properties::Init();
|
||||
wvcdm::g_cutoff = wvcdm::LOG_INFO;
|
||||
bool is_cast_receiver = false;
|
||||
bool force_load_test_keybox = false;
|
||||
bool filter_tests = true;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "--cast")) {
|
||||
acknowledge_cast();
|
||||
is_cast_receiver = true;
|
||||
}
|
||||
if (!strcmp(argv[i], "--force_load_test_keybox")) {
|
||||
force_load_test_keybox = true;
|
||||
}
|
||||
if (!strcmp(argv[i], "--no_filter")) {
|
||||
filter_tests = false;
|
||||
}
|
||||
}
|
||||
wvoec::global_features.Initialize(is_cast_receiver, force_load_test_keybox);
|
||||
// If the user requests --no_filter, we don't change the filter, otherwise, we
|
||||
// filter out features that are not supported.
|
||||
if (filter_tests) {
|
||||
::testing::GTEST_FLAG(filter) =
|
||||
wvoec::global_features.RestrictFilter(::testing::GTEST_FLAG(filter));
|
||||
}
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
Reference in New Issue
Block a user