Unit tests and reference code for v15

This CL updates the unit tests and reference code to support OEMCrypto
API v15.
This commit is contained in:
Fred Gylys-Colwell
2018-11-14 17:19:35 -08:00
parent 70e67379ec
commit 4b95763c6a
28 changed files with 4325 additions and 3160 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -170,13 +170,10 @@ OEMCryptoResult Level3_GenerateSignature(OEMCrypto_SESSION session,
size_t message_length, size_t message_length,
uint8_t* signature, uint8_t* signature,
size_t* signature_length); size_t* signature_length);
OEMCryptoResult Level3_RefreshKeys(OEMCrypto_SESSION session, OEMCryptoResult Level3_RefreshKeys(
const uint8_t* message, OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
size_t message_length, const uint8_t* signature, size_t signature_length, size_t num_keys,
const uint8_t* signature, const OEMCrypto_KeyRefreshObject_V14* key_array);
size_t signature_length,
size_t num_keys,
const OEMCrypto_KeyRefreshObject* key_array);
OEMCryptoResult Level3_QueryKeyControl(OEMCrypto_SESSION session, OEMCryptoResult Level3_QueryKeyControl(OEMCrypto_SESSION session,
const uint8_t* key_id, const uint8_t* key_id,
size_t key_id_length, size_t key_id_length,
@@ -347,27 +344,20 @@ OEMCryptoResult Level3_CreateOldUsageEntry(uint64_t time_since_license_received,
const uint8_t* pst, const uint8_t* pst,
size_t pst_length); size_t pst_length);
uint32_t Level3_GetAnalogOutputFlags(); uint32_t Level3_GetAnalogOutputFlags();
OEMCryptoResult Level3_LoadTestKeybox(const uint8_t *buffer, size_t length); OEMCryptoResult Level3_LoadTestKeybox(const uint8_t* buffer, size_t length);
OEMCryptoResult Level3_LoadEntitledContentKeys(OEMCrypto_SESSION session, OEMCryptoResult Level3_LoadEntitledContentKeys(
size_t num_keys, OEMCrypto_SESSION session, size_t num_keys,
const OEMCrypto_EntitledContentKeyObject* key_array); const OEMCrypto_EntitledContentKeyObject_V14* key_array);
OEMCryptoResult Level3_SelectKey(const OEMCrypto_SESSION session, OEMCryptoResult Level3_SelectKey(const OEMCrypto_SESSION session,
const uint8_t* key_id, const uint8_t* key_id, size_t key_id_length,
size_t key_id_length,
OEMCryptoCipherMode cipher_mode); OEMCryptoCipherMode cipher_mode);
OEMCryptoResult Level3_LoadKeys(OEMCrypto_SESSION session, OEMCryptoResult Level3_LoadKeys(
const uint8_t* message, OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
size_t message_length, const uint8_t* signature, size_t signature_length,
const uint8_t* signature, const uint8_t* enc_mac_key_iv, const uint8_t* enc_mac_key, size_t num_keys,
size_t signature_length, const OEMCrypto_KeyObject_V14* key_array, const uint8_t* pst,
const uint8_t* enc_mac_key_iv, size_t pst_length, const uint8_t* srm_requirement,
const uint8_t* enc_mac_key, OEMCrypto_LicenseType license_type);
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);
/* /*
* Level3_GetInitializationState * Level3_GetInitializationState
* *

View File

@@ -28,6 +28,7 @@ const uint32_t kControlObserveDataPath = (1<<31);
const uint32_t kControlObserveHDCP = (1<<30); const uint32_t kControlObserveHDCP = (1<<30);
const uint32_t kControlObserveCGMS = (1<<29); const uint32_t kControlObserveCGMS = (1<<29);
const uint32_t kControlRequireAntiRollbackHardware = (1<<28); const uint32_t kControlRequireAntiRollbackHardware = (1<<28);
const uint32_t kControlAllowHashVerification = (1<<24);
const uint32_t kSharedLicense = (1<<23); const uint32_t kSharedLicense = (1<<23);
const uint32_t kControlSRMVersionRequired = (1<<22); const uint32_t kControlSRMVersionRequired = (1<<22);
const uint32_t kControlDisableAnalogOutput = (1<<21); const uint32_t kControlDisableAnalogOutput = (1<<21);

View File

@@ -4,378 +4,320 @@
namespace wvoec_ref { namespace wvoec_ref {
extern const uint32_t kOEMSystemId_Prod = 7346; const uint32_t kOEMSystemId_Prod = 7913;
extern const uint8_t kOEMPrivateKey_Prod[] = { // From file test_rsa_key_2_carmichael.pk8 in team shared drive.
0x30, 0x82, 0x06, 0xfe, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, // Size is 1216.
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, const uint8_t kOEMPrivateKey_Prod[] = {
0x06, 0xe8, 0x30, 0x82, 0x06, 0xe4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x30, 0x82, 0x04, 0xbc, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x81, 0x00, 0xf5, 0x09, 0x64, 0x4a, 0x26, 0xfe, 0xc0, 0x98, 0x55, 0x6a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
0x1d, 0x5d, 0x1c, 0xc7, 0x38, 0xaf, 0xfd, 0x49, 0x9e, 0x85, 0x3f, 0xd6, 0x04, 0xa6, 0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01,
0x45, 0x0e, 0x99, 0x09, 0x85, 0x69, 0x84, 0x3c, 0xfe, 0x72, 0xa5, 0x56, 0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a,
0xfa, 0x11, 0x4f, 0x6b, 0x7d, 0x32, 0x2b, 0x0c, 0xbf, 0x8f, 0xac, 0x47, 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde,
0x96, 0x22, 0x82, 0x3d, 0xf5, 0x64, 0x74, 0x7e, 0x62, 0x68, 0x74, 0xcd, 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e,
0x0a, 0xec, 0x84, 0xc5, 0x15, 0x06, 0x0e, 0x5a, 0x2f, 0x20, 0xe3, 0xc9, 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4,
0x67, 0xcd, 0xdd, 0x01, 0xb8, 0xb3, 0x18, 0x87, 0x8c, 0xa9, 0x58, 0x86, 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3,
0x0f, 0xb6, 0xc3, 0x42, 0x7e, 0x87, 0x48, 0x5e, 0x10, 0x49, 0xc7, 0xd7, 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce,
0xb7, 0xb8, 0xa6, 0x34, 0x08, 0x0c, 0x94, 0xf4, 0xbb, 0x2a, 0x06, 0xa4, 0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb,
0x4f, 0xec, 0xbc, 0xc4, 0x37, 0xbe, 0x99, 0x10, 0x23, 0x37, 0x24, 0xb1, 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e,
0xdf, 0xcb, 0xe6, 0x3f, 0xc1, 0xf0, 0x0f, 0x04, 0x03, 0xc8, 0xb0, 0x1e, 0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4,
0xd6, 0xb8, 0xae, 0x77, 0xe1, 0x4d, 0x6d, 0x97, 0x69, 0x6d, 0x8a, 0x73, 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b,
0x66, 0x32, 0x57, 0x6f, 0xcf, 0xea, 0x1e, 0x7b, 0x87, 0x03, 0x75, 0xb1, 0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda,
0xef, 0x83, 0x64, 0x26, 0xf1, 0x3f, 0xbf, 0xe6, 0x28, 0x03, 0x72, 0x57, 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54,
0xbf, 0x47, 0x29, 0x99, 0x8f, 0x74, 0x1d, 0x01, 0x16, 0xad, 0xb2, 0xdf, 0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03,
0x80, 0xa4, 0xd3, 0x8b, 0xeb, 0x61, 0xd1, 0x40, 0x68, 0xb9, 0xa2, 0xa5, 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51,
0xef, 0x2b, 0xe5, 0x78, 0xe8, 0x28, 0x88, 0x87, 0xb7, 0x53, 0x49, 0xbb, 0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b,
0xe4, 0xea, 0x0d, 0x5e, 0x96, 0xa5, 0xdd, 0x1f, 0x0b, 0x25, 0x8b, 0xb5, 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12,
0x95, 0x46, 0xe7, 0xba, 0xb8, 0xc4, 0x0a, 0x36, 0xb1, 0x89, 0xeb, 0x27, 0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01,
0x5d, 0xd9, 0x97, 0x24, 0x59, 0xa3, 0x9b, 0xb0, 0x23, 0x0b, 0xd2, 0xec, 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a,
0x65, 0x91, 0xf9, 0xf0, 0xa0, 0x74, 0x5f, 0xb4, 0xce, 0x22, 0x27, 0x18, 0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed,
0x37, 0xe2, 0x4b, 0xfc, 0x91, 0xf9, 0x09, 0x15, 0xe6, 0xdb, 0x06, 0x9b, 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb,
0x4d, 0x82, 0xdc, 0x36, 0x14, 0x48, 0xc6, 0xd5, 0x87, 0xca, 0xec, 0x5a, 0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb,
0xa2, 0x29, 0x33, 0xef, 0x22, 0x0c, 0x4b, 0xbf, 0xe7, 0x2f, 0x95, 0xe1, 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
0xd3, 0xa5, 0xd8, 0xaa, 0x44, 0x77, 0x29, 0xa3, 0x20, 0x33, 0xd2, 0x51, 0x82, 0x01, 0x00, 0x0a, 0xf9, 0x4a, 0x19, 0x72, 0x88, 0x1b, 0x4e, 0xd8,
0xa2, 0xf9, 0x4a, 0x6f, 0xf7, 0x3e, 0xf7, 0x0b, 0x8a, 0xec, 0xc1, 0x99, 0x2f, 0xef, 0x99, 0x93, 0x32, 0xda, 0x51, 0x21, 0x2e, 0x14, 0x06, 0xf4,
0x1d, 0x47, 0xf3, 0x74, 0x02, 0x04, 0xab, 0x8e, 0x62, 0x4c, 0x9e, 0x00, 0xe9, 0x65, 0x1c, 0xf9, 0xd4, 0xcf, 0x1a, 0x51, 0x53, 0xcd, 0x48, 0x33,
0xc2, 0x84, 0xd7, 0xd0, 0xf8, 0xe4, 0x1c, 0x9d, 0x98, 0x15, 0xa8, 0x8f, 0x8c, 0x30, 0xed, 0xdd, 0x53, 0x6f, 0x29, 0x82, 0xf9, 0xe0, 0x74, 0xde,
0x08, 0x98, 0x4e, 0x5a, 0xfa, 0xd6, 0x60, 0x87, 0x12, 0xdc, 0x8e, 0xfd, 0xb1, 0x13, 0x01, 0x88, 0x8f, 0xce, 0x14, 0xc1, 0x3b, 0x90, 0xb7, 0xcc,
0xcb, 0xb3, 0x13, 0x97, 0x7a, 0xa8, 0x8c, 0x56, 0x2e, 0x49, 0x26, 0x60, 0x6c, 0xdf, 0x35, 0xa1, 0xf2, 0x1a, 0x3d, 0xbe, 0x19, 0xd7, 0x0a, 0xe4,
0xe9, 0x4a, 0xdc, 0xec, 0x3f, 0xf0, 0x94, 0xcd, 0x90, 0x8e, 0x7c, 0x21, 0x67, 0x75, 0xbb, 0xfa, 0x87, 0xf4, 0x03, 0xb5, 0x7f, 0x69, 0xe4, 0x0b,
0x3f, 0x80, 0x14, 0x33, 0xdd, 0xb0, 0x00, 0xe2, 0x09, 0x37, 0x06, 0xdd, 0x6a, 0xdc, 0x92, 0x82, 0x54, 0x64, 0x1a, 0x94, 0x2d, 0xe4, 0x63, 0x40,
0x17, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x81, 0x00, 0xb2, 0xb4, 0x85, 0x6b, 0xc8, 0x34, 0xba, 0xa2, 0x14, 0x30, 0x47, 0x1a,
0xa1, 0xc9, 0x44, 0xad, 0x6d, 0x17, 0xd1, 0x04, 0x03, 0x89, 0x5f, 0xbf, 0xeb, 0x90, 0x62, 0x30, 0x43, 0x44, 0x02, 0xc7, 0x0c, 0x30, 0xc0, 0x7f,
0xe5, 0xcb, 0x68, 0x13, 0x52, 0xf2, 0x33, 0xb7, 0x19, 0x12, 0x19, 0x60, 0xa9, 0x47, 0xae, 0xde, 0x68, 0x27, 0x92, 0xaa, 0x11, 0x95, 0xf5, 0x6f,
0x6d, 0x0d, 0x0b, 0x48, 0x42, 0xe6, 0x9e, 0xbe, 0x05, 0x8a, 0xea, 0xeb, 0xfc, 0x19, 0x8b, 0x49, 0xa0, 0x77, 0x9d, 0xc6, 0x13, 0x5d, 0x73, 0xff,
0x58, 0xfb, 0xc8, 0x9a, 0xc2, 0x2f, 0xd5, 0x9f, 0x40, 0x09, 0xb8, 0x08, 0x45, 0xa2, 0x4c, 0x3b, 0xf3, 0xe1, 0x2d, 0xd7, 0xc4, 0x70, 0xe2, 0x6c,
0x2a, 0xe4, 0x4b, 0xcc, 0xba, 0xd9, 0xe3, 0x91, 0xc2, 0x64, 0xcb, 0x6c, 0x37, 0x99, 0x4c, 0x7a, 0xa9, 0x27, 0xf8, 0x3a, 0xd6, 0xfd, 0xc5, 0xd8,
0xa4, 0xb1, 0x17, 0x93, 0x7b, 0x10, 0x72, 0x83, 0x8d, 0xc2, 0xa2, 0x46, 0xfa, 0x2d, 0x0e, 0x71, 0x4b, 0x85, 0x7e, 0xce, 0xcb, 0x1c, 0x79, 0x71,
0x1b, 0x41, 0x12, 0xb9, 0x35, 0x5d, 0xf2, 0x32, 0xb1, 0xdf, 0x3a, 0x2a, 0xbd, 0xff, 0x63, 0x03, 0x6b, 0x58, 0x68, 0xe0, 0x14, 0xca, 0x5e, 0x85,
0xda, 0xbb, 0x61, 0x9d, 0x62, 0xdb, 0xb0, 0x77, 0x76, 0x7a, 0x68, 0xb4, 0xfd, 0xd0, 0xb7, 0xe0, 0x68, 0x14, 0xff, 0x2c, 0x82, 0x22, 0x26, 0x8a,
0x83, 0x10, 0x61, 0xac, 0x25, 0x01, 0x7d, 0x3e, 0x5f, 0x4a, 0x47, 0xf7, 0x3f, 0xbf, 0xb0, 0x2a, 0x90, 0xff, 0xc7, 0x72, 0xfc, 0x66, 0x51, 0x3e,
0x30, 0x1f, 0x82, 0x0a, 0xd7, 0x36, 0xff, 0x79, 0x5e, 0x42, 0x0f, 0x58, 0x51, 0x9f, 0x82, 0x68, 0x0e, 0xf3, 0x65, 0x74, 0x88, 0xab, 0xb7, 0xe5,
0xaa, 0x3a, 0xb8, 0x8b, 0x0e, 0xef, 0x00, 0xac, 0x96, 0x14, 0x96, 0x83, 0x97, 0x5f, 0x0f, 0x3e, 0xe5, 0x3a, 0xbc, 0xa4, 0xa1, 0x50, 0xdd, 0x5c,
0x33, 0xb6, 0xb5, 0x4c, 0x91, 0x2a, 0x62, 0x92, 0xcf, 0xd2, 0x27, 0xcc, 0x94, 0x4b, 0x0c, 0x70, 0x71, 0x48, 0x4e, 0xd0, 0xec, 0x46, 0x8f, 0xdf,
0xdf, 0x4c, 0x55, 0x03, 0xe8, 0x82, 0x78, 0xff, 0x80, 0xcb, 0x2e, 0x30, 0xa2, 0x9a, 0xfe, 0xd8, 0x35, 0x1a, 0x2f, 0x02, 0x81, 0x81, 0x00, 0xcf,
0x1b, 0x85, 0x56, 0xce, 0x57, 0x9e, 0xd8, 0x16, 0x86, 0x7d, 0x87, 0x2e, 0x73, 0x8c, 0xbe, 0x6d, 0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75,
0xae, 0x39, 0xd4, 0xac, 0xbe, 0xa5, 0xc4, 0x5a, 0x85, 0x7a, 0xea, 0x8e, 0x78, 0xcc, 0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9, 0x64, 0x60, 0x8c, 0x43,
0x69, 0x9a, 0xbd, 0x9c, 0x45, 0x33, 0xf8, 0xb1, 0x70, 0xc1, 0x8c, 0xaa, 0xeb, 0x85, 0xab, 0x04, 0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda,
0xad, 0x3d, 0x76, 0x08, 0x5b, 0x7d, 0x12, 0x93, 0x03, 0x70, 0xe6, 0x5f, 0x84, 0x68, 0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4, 0xde, 0x51, 0x4b, 0xb6,
0xb2, 0xac, 0x78, 0xae, 0xbe, 0xc5, 0x31, 0xc8, 0x6d, 0x2c, 0x1c, 0x2f, 0x51, 0x86, 0x7b, 0xd0, 0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f,
0x41, 0x37, 0xf6, 0x88, 0xd3, 0x80, 0x93, 0xed, 0x55, 0xb1, 0xaa, 0x49, 0x3a, 0x83, 0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13, 0x93, 0xd7, 0x9c, 0x27,
0xe8, 0x42, 0xd0, 0x19, 0x20, 0x58, 0xe7, 0x2d, 0x10, 0xf2, 0x69, 0x49, 0x80, 0xb7, 0x1e, 0x64, 0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8,
0xe9, 0x47, 0x95, 0xbb, 0xce, 0xa7, 0xe9, 0x86, 0x46, 0x1c, 0xd1, 0x1f, 0x18, 0x6c, 0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96, 0x90, 0x8f, 0xa2, 0x16,
0xd4, 0xa9, 0xeb, 0x28, 0x57, 0x78, 0x6c, 0xc6, 0x6f, 0x84, 0x3b, 0xb4, 0x22, 0x6a, 0xcc, 0x48, 0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44,
0x8c, 0xe5, 0xd3, 0x23, 0x8b, 0xbe, 0x83, 0x75, 0x5e, 0xea, 0xcd, 0x93, 0x3c, 0x2d, 0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27, 0x33, 0x85, 0x26, 0x60,
0xd2, 0x42, 0x86, 0xfd, 0x2b, 0x67, 0x72, 0xe0, 0x46, 0x9c, 0xf7, 0xc1, 0x48, 0x16, 0xcb, 0xef, 0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce,
0xe9, 0x5d, 0xad, 0xac, 0xcb, 0x57, 0xb4, 0xe7, 0x87, 0x25, 0x7d, 0x5a, 0x15, 0x43, 0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87, 0xc3, 0x41, 0x45, 0x97,
0x43, 0x90, 0xa3, 0x2e, 0xbf, 0x36, 0xbd, 0x4c, 0xba, 0xec, 0x0f, 0x21, 0xb1, 0x49, 0xc2, 0x19, 0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28,
0x51, 0xda, 0x66, 0xb8, 0x1e, 0xac, 0x33, 0xeb, 0xa1, 0x3e, 0x72, 0x15, 0xcb, 0x43, 0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb, 0xbb, 0xdb, 0xfd, 0x11,
0x10, 0x45, 0xc0, 0xe4, 0xdb, 0x04, 0x6d, 0xaf, 0x66, 0xc2, 0xfc, 0x35, 0x9d, 0x17, 0x68, 0x78, 0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3,
0x04, 0x60, 0x7d, 0x2f, 0x5e, 0x9e, 0x83, 0xf6, 0x72, 0x92, 0x6a, 0x9f, 0xa7, 0x5b, 0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54, 0x91, 0x99, 0xe5, 0x91,
0xba, 0x94, 0x97, 0x33, 0xe1, 0x1d, 0x42, 0xda, 0xad, 0xa5, 0x8b, 0xad, 0x32, 0x2d, 0xeb, 0x3f, 0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41,
0x2f, 0x2f, 0x32, 0x16, 0x88, 0x54, 0x88, 0xb2, 0x85, 0xe2, 0x33, 0x08, 0xc1, 0xee, 0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42, 0x58, 0xf4, 0xd0, 0xb2,
0x43, 0xc8, 0x68, 0x69, 0xaa, 0xea, 0x9a, 0xbf, 0x41, 0x12, 0xe6, 0xf1, 0x74, 0x1d, 0x8e, 0x87, 0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd,
0x02, 0x81, 0xc1, 0x00, 0xfe, 0x96, 0xe7, 0xc8, 0x89, 0x61, 0x2b, 0x58, 0x0d, 0x6c, 0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53, 0xda, 0xfb, 0xed, 0x83,
0xaa, 0xcd, 0x37, 0x46, 0x13, 0xa1, 0x2a, 0xc8, 0x1b, 0x76, 0xde, 0x4c, 0x51, 0x67, 0xa9, 0x55, 0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17,
0xb3, 0x00, 0x4f, 0x6b, 0x02, 0xc0, 0x10, 0xef, 0x87, 0xe2, 0x6d, 0x7f, 0x53, 0xa8, 0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02, 0x81, 0x80, 0x67, 0x9c,
0x10, 0x57, 0xec, 0xde, 0x70, 0x60, 0xb5, 0x8f, 0x6d, 0x17, 0x35, 0xbd, 0x32, 0x83, 0x39, 0x57, 0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0,
0xfd, 0x6a, 0x2c, 0xbb, 0xf0, 0x48, 0x5b, 0x32, 0x41, 0xf6, 0xc0, 0x62, 0x0a, 0x2d, 0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97, 0xf3, 0x90, 0x9a, 0xab,
0x3a, 0x88, 0xc5, 0x41, 0x83, 0x85, 0x56, 0xa7, 0x11, 0xf4, 0xd2, 0xa9, 0x9b, 0x0b, 0x1b, 0x43, 0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c,
0xb3, 0xa3, 0xcb, 0xae, 0xca, 0xee, 0x1c, 0x52, 0x7f, 0x04, 0x34, 0x61, 0xeb, 0xdb, 0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80, 0xb8, 0xe1, 0xb3, 0xa1,
0xb9, 0x8d, 0xa3, 0x26, 0x88, 0xce, 0x3d, 0xdb, 0x9c, 0xbf, 0xcc, 0xc4, 0x6c, 0x25, 0x92, 0xe4, 0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f,
0x38, 0x8b, 0xf2, 0xe4, 0x7e, 0xcc, 0x46, 0x86, 0x7a, 0x3c, 0xb7, 0x95, 0x37, 0x43, 0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81, 0x20, 0x82, 0xa1, 0x48,
0x3f, 0xbd, 0x81, 0x45, 0xc3, 0x1d, 0xbb, 0xf8, 0x56, 0x6e, 0xa5, 0x88, 0x2c, 0x2d, 0x45, 0xdc, 0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41,
0x2d, 0xff, 0x78, 0xc0, 0xc2, 0x4a, 0x4f, 0xea, 0xb8, 0x81, 0xf3, 0x96, 0xf9, 0xca, 0x58, 0xce, 0x4a, 0x66, 0x53, 0x54, 0xc8, 0x28, 0x10, 0x1e,
0x5e, 0xd8, 0xcb, 0x96, 0x42, 0xa3, 0x21, 0x03, 0xc8, 0x00, 0xbf, 0x95, 0x08, 0x71, 0x16, 0xd8, 0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5,
0xc7, 0x83, 0x80, 0xc6, 0xc2, 0x38, 0xe4, 0xaf, 0xb2, 0x0e, 0x80, 0x92, 0xb1, 0x31, 0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf, 0x35, 0x95, 0x41, 0x29,
0x97, 0x21, 0x16, 0xce, 0x39, 0xd3, 0x95, 0xb7, 0xc3, 0x78, 0xe1, 0x1c, 0x40, 0x19, 0x83, 0x35, 0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b,
0xc0, 0x5a, 0xbc, 0x9b, 0x68, 0x3f, 0xd6, 0x42, 0xcd, 0xca, 0x0b, 0x6d, 0xcc, 0x3b, 0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae, 0x50, 0x76, 0x63, 0x94,
0x9f, 0xde, 0x6b, 0x98, 0x3b, 0x47, 0x57, 0xb9, 0x2d, 0x92, 0x52, 0x29, 0x49, 0x4c, 0xad, 0x10, 0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8,
0xc5, 0xed, 0xb5, 0x0d, 0x02, 0x81, 0xc1, 0x00, 0xf6, 0x64, 0xef, 0xef, 0x6a, 0xab, 0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b, 0x8a, 0xa2, 0xb9, 0x8f,
0x57, 0xdb, 0x06, 0xae, 0x36, 0x86, 0x11, 0xaf, 0x96, 0xb9, 0xb1, 0x29, 0xce, 0xec, 0x5e, 0x61, 0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a,
0x53, 0xce, 0x24, 0x60, 0x96, 0x8f, 0xd0, 0xb7, 0x4b, 0x60, 0x1e, 0xb3, 0x5f, 0xdf, 0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69, 0xe4, 0x8b, 0x01, 0x06,
0x1f, 0xae, 0x15, 0x41, 0xf1, 0x56, 0xd6, 0xf3, 0x07, 0xf8, 0xd7, 0xdd, 0x59, 0x22, 0xfa, 0x34, 0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a,
0x1c, 0x82, 0xe8, 0xe0, 0xff, 0xb3, 0x41, 0x0d, 0x41, 0x96, 0x0d, 0xf2, 0x77, 0xe6, 0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26, 0x6c, 0xfa, 0x2b, 0xd9,
0x03, 0xb0, 0x68, 0xed, 0xda, 0x8b, 0x83, 0x18, 0x4d, 0xae, 0xaf, 0x72, 0x83, 0x5a, 0x2d, 0x0c, 0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a,
0xa1, 0x82, 0xe5, 0x5a, 0xdc, 0x2a, 0x5f, 0x93, 0x29, 0xc7, 0x24, 0xa0, 0xd9, 0xbe, 0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3, 0x66, 0xff, 0x1c, 0x1b,
0x8e, 0x32, 0x4c, 0x0e, 0xca, 0x6d, 0x14, 0x69, 0x5b, 0x61, 0xc5, 0xdc, 0xc8, 0x96, 0x76, 0xe8, 0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8,
0x0e, 0x50, 0x0c, 0x14, 0x84, 0x8b, 0xee, 0x9e, 0x1e, 0x8c, 0x3d, 0xdb, 0xac, 0x21, 0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80, 0x2c, 0x7c, 0xad, 0x1e,
0x24, 0xe7, 0x99, 0x6d, 0x3c, 0xaf, 0xe6, 0x3b, 0xaa, 0xb4, 0xe4, 0x42, 0x75, 0xf6, 0x69, 0x1d, 0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65,
0x13, 0x53, 0x3e, 0x02, 0x47, 0x0d, 0x3a, 0x2b, 0x97, 0x71, 0x9f, 0x1b, 0x28, 0x66, 0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57, 0xae, 0xb7, 0x65, 0x2c,
0x76, 0x2d, 0xe5, 0x9c, 0x5e, 0x46, 0x5f, 0x36, 0xbf, 0x18, 0xb1, 0x1d, 0x52, 0xf9, 0xe4, 0xc7, 0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33,
0x9a, 0xeb, 0x4d, 0x5e, 0x83, 0xd5, 0x3e, 0x5f, 0xf2, 0x6a, 0x56, 0x79, 0x70, 0xcf, 0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50, 0x75, 0x61, 0x96, 0x86,
0x0f, 0x54, 0xec, 0x41, 0xc0, 0xdc, 0x29, 0x42, 0x45, 0xae, 0x47, 0x1c, 0x4b, 0xb6, 0x2b, 0xad, 0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35,
0x7a, 0xd5, 0xb7, 0x92, 0x1e, 0x66, 0xb8, 0x1a, 0x2f, 0x53, 0xd2, 0x6d, 0x50, 0xcb, 0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a, 0xd3, 0x29, 0x23, 0x02,
0x42, 0x3c, 0x6c, 0x02, 0x01, 0x03, 0x9e, 0x9a, 0x95, 0x35, 0x81, 0x21, 0x60, 0xf7, 0xab, 0x30, 0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4,
0x53, 0x53, 0x16, 0xda, 0x8a, 0x80, 0x8c, 0xcd, 0x02, 0x81, 0xc1, 0x00, 0xa2, 0x0d, 0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18, 0xf4, 0xd4, 0x52, 0x95,
0xd5, 0xba, 0x05, 0xf7, 0x7a, 0x2d, 0x52, 0xe0, 0x6a, 0xf3, 0x40, 0xd5, 0x00, 0xae, 0x84, 0x6b, 0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde,
0xd9, 0xa0, 0xd1, 0x73, 0x90, 0x6a, 0xe8, 0x10, 0x67, 0xad, 0x78, 0xfe, 0x72, 0x2c, 0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, 0x56, 0xfe, 0x39, 0x28,
0x93, 0x1e, 0x7e, 0x99, 0x37, 0xf0, 0x44, 0x90, 0x09, 0x3e, 0x67, 0x22, 0x33, 0xe0, 0xdb, 0x03
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[] = { const size_t kOEMPrivateKeySize_Prod = sizeof(kOEMPrivateKey_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, // From the team shared drive file
0x01, 0x01, 0x31, 0x00, 0x30, 0x0f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, // oem-7913-leaf-and-intermediate-certs-test-key-2-carmichael.p7b, size 2353.
0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x02, 0x04, 0x00, 0xa0, 0x82, 0x09, const uint8_t kOEMPublicCert_Prod[] = {
0xc8, 0x30, 0x82, 0x04, 0x1a, 0x30, 0x82, 0x03, 0x02, 0xa0, 0x03, 0x02, 0x30, 0x82, 0x09, 0x2d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x02, 0x02, 0x11, 0x00, 0xf2, 0xa1, 0x08, 0xdf, 0x12, 0x84, 0xb9, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x09, 0x1e, 0x30, 0x82, 0x09, 0x1a, 0x02,
0x73, 0x6c, 0x23, 0x73, 0xe1, 0x1f, 0xf3, 0xac, 0x7a, 0x30, 0x0d, 0x06, 0x01, 0x01, 0x31, 0x00, 0x30, 0x0f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x02, 0x04, 0x00, 0xa0, 0x82, 0x08,
0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0xfe, 0x30, 0x82, 0x03, 0x71, 0x30, 0x82, 0x02, 0x59, 0xa0, 0x03, 0x02,
0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x01, 0x02, 0x02, 0x11, 0x00, 0xc2, 0x8d, 0x20, 0x22, 0x82, 0x8b, 0x9e,
0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x63, 0x9d, 0x15, 0x89, 0x2c, 0xa9, 0x8f, 0xd9, 0x5d, 0x30, 0x0d, 0x06,
0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x30, 0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08,
0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x0c, 0x02, 0x57, 0x41, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x30, 0x30, 0x2e, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31,
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x27, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f,
0x65, 0x20, 0x4f, 0x45, 0x4d, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x44, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
0x65, 0x76, 0x69, 0x63, 0x65, 0x3b, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31,
0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x33, 0x34, 0x36, 0x30, 0x1e, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x73, 0x79,
0x17, 0x0d, 0x31, 0x37, 0x30, 0x33, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x39, 0x31,
0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x32, 0x30, 0x38, 0x30, 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x31, 0x31, 0x31, 0x31,
0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x6d, 0x31, 0x12, 0x30, 0x10, 0x33, 0x32, 0x36, 0x32, 0x32, 0x5a, 0x17, 0x0d, 0x33, 0x38, 0x30, 0x31,
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x37, 0x33, 0x34, 0x36, 0x2d, 0x30, 0x36, 0x31, 0x33, 0x32, 0x36, 0x32, 0x32, 0x5a, 0x30, 0x65, 0x31,
0x6c, 0x65, 0x61, 0x66, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x37, 0x39,
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x31, 0x33, 0x2d, 0x6c, 0x65, 0x61, 0x66, 0x31, 0x0b, 0x30, 0x09, 0x06,
0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09,
0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x57, 0x41, 0x31, 0x11, 0x30,
0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b,
0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04,
0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30,
0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x30, 0x82, 0x01, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65,
0xa2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x76, 0x69, 0x6e, 0x65, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x8f, 0x00, 0x30, 0x82, 0x01, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xf5, 0x09, 0x64, 0x4a, 0x26, 0xfe, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
0xc0, 0x98, 0x55, 0x6a, 0x1d, 0x5d, 0x1c, 0xc7, 0x38, 0xaf, 0xfd, 0x49, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, 0x40,
0x9e, 0x85, 0x3f, 0xd6, 0x45, 0x0e, 0x99, 0x09, 0x85, 0x69, 0x84, 0x3c, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde, 0xa7,
0xfe, 0x72, 0xa5, 0x56, 0xfa, 0x11, 0x4f, 0x6b, 0x7d, 0x32, 0x2b, 0x0c, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, 0x56,
0xbf, 0x8f, 0xac, 0x47, 0x96, 0x22, 0x82, 0x3d, 0xf5, 0x64, 0x74, 0x7e, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4, 0x4e,
0x62, 0x68, 0x74, 0xcd, 0x0a, 0xec, 0x84, 0xc5, 0x15, 0x06, 0x0e, 0x5a, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, 0x34,
0x2f, 0x20, 0xe3, 0xc9, 0x67, 0xcd, 0xdd, 0x01, 0xb8, 0xb3, 0x18, 0x87, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce, 0x31,
0x8c, 0xa9, 0x58, 0x86, 0x0f, 0xb6, 0xc3, 0x42, 0x7e, 0x87, 0x48, 0x5e, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, 0x3e,
0x10, 0x49, 0xc7, 0xd7, 0xb7, 0xb8, 0xa6, 0x34, 0x08, 0x0c, 0x94, 0xf4, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e, 0x39,
0xbb, 0x2a, 0x06, 0xa4, 0x4f, 0xec, 0xbc, 0xc4, 0x37, 0xbe, 0x99, 0x10, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, 0xf2,
0x23, 0x37, 0x24, 0xb1, 0xdf, 0xcb, 0xe6, 0x3f, 0xc1, 0xf0, 0x0f, 0x04, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b, 0x54,
0x03, 0xc8, 0xb0, 0x1e, 0xd6, 0xb8, 0xae, 0x77, 0xe1, 0x4d, 0x6d, 0x97, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, 0xb3,
0x69, 0x6d, 0x8a, 0x73, 0x66, 0x32, 0x57, 0x6f, 0xcf, 0xea, 0x1e, 0x7b, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54, 0x71,
0x87, 0x03, 0x75, 0xb1, 0xef, 0x83, 0x64, 0x26, 0xf1, 0x3f, 0xbf, 0xe6, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, 0x96,
0x28, 0x03, 0x72, 0x57, 0xbf, 0x47, 0x29, 0x99, 0x8f, 0x74, 0x1d, 0x01, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51, 0x5a,
0x16, 0xad, 0xb2, 0xdf, 0x80, 0xa4, 0xd3, 0x8b, 0xeb, 0x61, 0xd1, 0x40, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, 0x4c,
0x68, 0xb9, 0xa2, 0xa5, 0xef, 0x2b, 0xe5, 0x78, 0xe8, 0x28, 0x88, 0x87, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12, 0x7f,
0xb7, 0x53, 0x49, 0xbb, 0xe4, 0xea, 0x0d, 0x5e, 0x96, 0xa5, 0xdd, 0x1f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, 0xca,
0x0b, 0x25, 0x8b, 0xb5, 0x95, 0x46, 0xe7, 0xba, 0xb8, 0xc4, 0x0a, 0x36, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a, 0x77,
0xb1, 0x89, 0xeb, 0x27, 0x5d, 0xd9, 0x97, 0x24, 0x59, 0xa3, 0x9b, 0xb0, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, 0x27,
0x23, 0x0b, 0xd2, 0xec, 0x65, 0x91, 0xf9, 0xf0, 0xa0, 0x74, 0x5f, 0xb4, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb, 0x9c,
0xce, 0x22, 0x27, 0x18, 0x37, 0xe2, 0x4b, 0xfc, 0x91, 0xf9, 0x09, 0x15, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, 0x2c,
0xe6, 0xdb, 0x06, 0x9b, 0x4d, 0x82, 0xdc, 0x36, 0x14, 0x48, 0xc6, 0xd5, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x16,
0x87, 0xca, 0xec, 0x5a, 0xa2, 0x29, 0x33, 0xef, 0x22, 0x0c, 0x4b, 0xbf, 0x30, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6,
0xe7, 0x2f, 0x95, 0xe1, 0xd3, 0xa5, 0xd8, 0xaa, 0x44, 0x77, 0x29, 0xa3, 0x79, 0x04, 0x01, 0x01, 0x04, 0x04, 0x02, 0x02, 0x1e, 0xe9, 0x30, 0x0d,
0x20, 0x33, 0xd2, 0x51, 0xa2, 0xf9, 0x4a, 0x6f, 0xf7, 0x3e, 0xf7, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
0x8a, 0xec, 0xc1, 0x99, 0x1d, 0x47, 0xf3, 0x74, 0x02, 0x04, 0xab, 0x8e, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x88, 0x95, 0xec, 0xcd, 0x8b, 0xa7,
0x62, 0x4c, 0x9e, 0x00, 0xc2, 0x84, 0xd7, 0xd0, 0xf8, 0xe4, 0x1c, 0x9d, 0x51, 0xda, 0x74, 0x81, 0xa5, 0x39, 0x62, 0x1a, 0x0e, 0x2e, 0xde, 0x3c,
0x98, 0x15, 0xa8, 0x8f, 0x08, 0x98, 0x4e, 0x5a, 0xfa, 0xd6, 0x60, 0x87, 0x37, 0xea, 0xad, 0x7c, 0xee, 0x9b, 0x26, 0x8e, 0xe2, 0xd6, 0x34, 0xcd,
0x12, 0xdc, 0x8e, 0xfd, 0xcb, 0xb3, 0x13, 0x97, 0x7a, 0xa8, 0x8c, 0x56, 0xb7, 0x70, 0xba, 0xbf, 0xa0, 0xa3, 0xfe, 0xb3, 0x4b, 0xbc, 0xf4, 0x1c,
0x2e, 0x49, 0x26, 0x60, 0xe9, 0x4a, 0xdc, 0xec, 0x3f, 0xf0, 0x94, 0xcd, 0x72, 0x66, 0x81, 0xd5, 0x09, 0x33, 0x78, 0x0c, 0x61, 0x21, 0xa8, 0xf1,
0x90, 0x8e, 0x7c, 0x21, 0x3f, 0x80, 0x14, 0x33, 0xdd, 0xb0, 0x00, 0xe2, 0xe2, 0xc9, 0xe2, 0x83, 0xc2, 0x19, 0x02, 0xf2, 0xe8, 0xab, 0x17, 0x36,
0x09, 0x37, 0x06, 0xdd, 0x17, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x3a, 0x0b, 0x20, 0xaf, 0x0f, 0xae, 0x2e, 0x73, 0x68, 0xac, 0x15, 0xee,
0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x9c, 0xc0, 0x92, 0x03, 0x7e, 0x95, 0x63, 0xaa, 0xad, 0x15, 0x96, 0x43,
0xd6, 0x79, 0x04, 0x01, 0x01, 0x04, 0x04, 0x02, 0x02, 0x1c, 0xb2, 0x30, 0x20, 0x3b, 0xe5, 0x9b, 0x1f, 0xca, 0x02, 0xba, 0xf0, 0x07, 0x76, 0x80,
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0xd7, 0xa3, 0x1a, 0xeb, 0xc8, 0xdb, 0x03, 0x7b, 0x43, 0x56, 0xe5, 0x96,
0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x8e, 0x2d, 0x13, 0x1e, 0x60, 0x6b, 0x86, 0xfe, 0x08, 0x58, 0x8a, 0x84, 0xbd, 0xe9, 0x47, 0x18, 0xee,
0xaa, 0xda, 0x52, 0x53, 0x55, 0x64, 0x3a, 0xdc, 0xb6, 0x7a, 0xc0, 0xba, 0xb2, 0xa8, 0x05, 0x7b, 0xf0, 0xfd, 0xaa, 0xb9, 0x85, 0xcd, 0x7a, 0x0e,
0xfa, 0xeb, 0x20, 0xab, 0xb6, 0x63, 0xcf, 0xcd, 0x9b, 0xdb, 0x71, 0xf3, 0x6b, 0x6c, 0x9f, 0xc6, 0x75, 0xd2, 0x2a, 0xfe, 0x5b, 0xf3, 0xb7, 0x31,
0xa0, 0xd6, 0x91, 0xbf, 0x0c, 0xc1, 0xae, 0x8f, 0x02, 0x18, 0x00, 0x54, 0x6c, 0xac, 0xe3, 0x00, 0x9f, 0xe7, 0xdd, 0xe3, 0x81, 0xc1, 0x36, 0xc3,
0xfb, 0x49, 0x03, 0x34, 0x8d, 0x92, 0x9d, 0x5d, 0x8d, 0xa8, 0x1c, 0x20, 0x1c, 0x5f, 0xdf, 0xf2, 0xc3, 0x5e, 0xfa, 0x55, 0x32, 0xd8, 0x5c, 0xa8,
0x0f, 0x85, 0x60, 0xf9, 0xf6, 0x8b, 0xbb, 0x2b, 0x82, 0xce, 0xb3, 0xe2, 0xe5, 0xcc, 0xb6, 0x4a, 0xe9, 0xe2, 0xcc, 0x38, 0x44, 0x07, 0x46, 0x59,
0x91, 0xe7, 0xbd, 0x91, 0x61, 0x52, 0x36, 0x40, 0x9f, 0x2f, 0x5e, 0xa6, 0x34, 0x84, 0x79, 0xf9, 0xee, 0x3c, 0x4b, 0x48, 0x90, 0xab, 0x73, 0xb0,
0x5d, 0x2f, 0xb3, 0x81, 0xe7, 0xf1, 0x87, 0xbe, 0xc5, 0x9d, 0x67, 0x5a, 0xa1, 0x92, 0xc3, 0xd6, 0x83, 0x87, 0x81, 0xca, 0x12, 0x81, 0xd6, 0x5d,
0xf7, 0x41, 0x1e, 0x73, 0xb0, 0x1e, 0xdc, 0x4f, 0x8d, 0x53, 0x21, 0x38, 0xf7, 0x6f, 0x7a, 0x35, 0x5e, 0x4f, 0x02, 0x66, 0x8a, 0x47, 0x88, 0x82,
0x1b, 0xfd, 0x92, 0x43, 0x68, 0x83, 0x03, 0xd0, 0x9a, 0xca, 0x92, 0x14, 0xab, 0xf0, 0x12, 0x1d, 0xb9, 0x75, 0x3b, 0x7b, 0xa8, 0x36, 0x15, 0xef,
0x73, 0x04, 0x94, 0x2a, 0x93, 0x22, 0x60, 0x5e, 0xee, 0xb6, 0xec, 0x0f, 0xa8, 0x12, 0x0e, 0x53, 0xb4, 0x83, 0x78, 0x53, 0xc0, 0x52, 0xae, 0xa6,
0xb0, 0xc8, 0x92, 0x97, 0xfb, 0x5d, 0xed, 0x1f, 0xa0, 0x5f, 0xe4, 0x98, 0x0a, 0xa0, 0x53, 0xdc, 0x1c, 0x15, 0x22, 0xdd, 0x17, 0x98, 0x30, 0x82,
0x2f, 0xf6, 0x13, 0x78, 0x99, 0xec, 0xb3, 0xf1, 0x0d, 0x27, 0xaa, 0x19, 0x05, 0x85, 0x30, 0x82, 0x03, 0x6d, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
0x95, 0x39, 0xdb, 0xb0, 0x7b, 0x96, 0x74, 0x03, 0x5e, 0x51, 0xf5, 0x15, 0x10, 0x03, 0xb1, 0xf7, 0x58, 0xdf, 0x1d, 0xe3, 0x25, 0x00, 0x0b, 0x10,
0x27, 0xce, 0xca, 0x0b, 0x2a, 0x0d, 0x43, 0xb3, 0x68, 0x17, 0x1e, 0x11, 0x3d, 0xd5, 0xe6, 0xe4, 0x64, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
0x60, 0xd9, 0x84, 0x9b, 0xc3, 0x53, 0xce, 0xbd, 0xf4, 0x61, 0x51, 0x4b, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x7e, 0x31, 0x0b,
0x41, 0x00, 0x7e, 0xe1, 0x5f, 0x69, 0xb3, 0x4a, 0x89, 0x7e, 0x47, 0x67, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
0xfd, 0x76, 0xf8, 0x94, 0x2f, 0x72, 0xb6, 0x14, 0x08, 0x2c, 0x16, 0x4e, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61,
0x9d, 0x37, 0x62, 0xbf, 0x11, 0x67, 0xc0, 0x70, 0x71, 0xec, 0x55, 0x51, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f,
0x4e, 0x46, 0x76, 0xb4, 0xc3, 0xeb, 0x52, 0x06, 0x17, 0x06, 0xce, 0x61, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c,
0x43, 0xce, 0x26, 0x80, 0x68, 0xb6, 0x2d, 0x57, 0xba, 0x8c, 0x7d, 0xb7, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a,
0xc5, 0x05, 0x2c, 0xf8, 0xa3, 0x69, 0xf8, 0x96, 0xad, 0xac, 0xd1, 0x30, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f,
0x82, 0x05, 0xa6, 0x30, 0x82, 0x03, 0x8e, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76,
0x02, 0x10, 0x73, 0xd1, 0xe1, 0x1d, 0xa9, 0x75, 0xfd, 0x0c, 0xda, 0x7f, 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03,
0xfa, 0x43, 0x3c, 0x26, 0xbd, 0x3d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63,
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x7e, 0x31, 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d,
0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x70, 0x72, 0x6f, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x31, 0x31,
0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x31, 0x38, 0x30, 0x31, 0x31, 0x33, 0x33, 0x35, 0x5a, 0x17, 0x0d, 0x32,
0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x37, 0x31, 0x31, 0x31, 0x38, 0x30, 0x31, 0x31, 0x33, 0x31, 0x33, 0x5a,
0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x30, 0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08,
0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0c, 0x02, 0x57, 0x41, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31,
0x76, 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f,
0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31,
0x2d, 0x70, 0x72, 0x6f, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x73, 0x79,
0x33, 0x31, 0x34, 0x30, 0x33, 0x30, 0x32, 0x34, 0x31, 0x5a, 0x17, 0x0d, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x39, 0x31,
0x32, 0x37, 0x30, 0x33, 0x31, 0x34, 0x30, 0x33, 0x30, 0x32, 0x34, 0x31, 0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
0x5a, 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f,
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xae, 0xc8,
0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x71, 0xae, 0x08, 0x0c, 0x06, 0x06, 0x2d, 0x81, 0x7c, 0xa9, 0x8b, 0xb3,
0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0xd6, 0x66, 0xe4, 0xf6, 0x08, 0x5e, 0x5a, 0x75, 0xe8, 0x74, 0x61, 0x7a,
0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x88, 0xca, 0x85, 0x14, 0x0d, 0x58, 0xa4, 0x09, 0x19, 0x6c, 0x60, 0xc9,
0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0xad, 0x91, 0x1c, 0xbf, 0x04, 0xb3, 0x47, 0x10, 0x63, 0x7f, 0x02, 0x58,
0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0xc2, 0x1e, 0xbd, 0xcc, 0x07, 0x77, 0xaa, 0x7e, 0x14, 0xa8, 0xc2, 0x01,
0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x30, 0x30, 0xcd, 0xe8, 0x46, 0x60, 0x53, 0x6f, 0x2f, 0xda, 0x17, 0x2d, 0x4d, 0x9d,
0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x27, 0x47, 0x6f, 0x6f, 0x67, 0x0e, 0x5d, 0xb5, 0x50, 0x95, 0xae, 0xab, 0x6e, 0x43, 0xe3, 0xb0, 0x00,
0x6c, 0x65, 0x20, 0x4f, 0x45, 0x4d, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x12, 0xb4, 0x05, 0x82, 0x4a, 0x2b, 0x14, 0x63, 0x0d, 0x1f, 0x06, 0x12,
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x3b, 0x20, 0x73, 0x79, 0x73, 0x74, 0xaa, 0xe1, 0x9d, 0xe7, 0xba, 0xda, 0xe3, 0xfc, 0x7c, 0x6c, 0x73, 0xae,
0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x33, 0x34, 0x36, 0x30, 0x56, 0xf8, 0xab, 0xf7, 0x51, 0x93, 0x31, 0xef, 0x8f, 0xe4, 0xb6, 0x01,
0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x2c, 0xeb, 0x7b, 0xe4, 0xd8, 0xb3, 0xea, 0x70, 0x37, 0x89, 0x05, 0xa9,
0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x51, 0x57, 0x72, 0x98, 0x9e, 0xa8, 0x46, 0xdb, 0xeb, 0x7a, 0x38, 0x2b,
0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa5, 0x45, 0x13, 0xf2, 0x2f, 0xc0, 0x27, 0xb7, 0xc2, 0xe1, 0x9a, 0x17, 0xdf, 0xf5, 0xd6, 0x9c,
0xb2, 0xcb, 0x4b, 0x0f, 0xb4, 0x44, 0x25, 0x9c, 0x8a, 0x68, 0x54, 0xd5, 0xd5, 0x8c, 0xb8, 0x66, 0x42, 0xd5, 0x04, 0x1e, 0x7c, 0x36, 0x4c, 0x1e,
0x45, 0x1e, 0x15, 0x89, 0x5b, 0xb8, 0xce, 0xda, 0x5a, 0x42, 0xe6, 0x9a, 0x3e, 0x45, 0x51, 0x4d, 0x41, 0x72, 0x22, 0x53, 0x3d, 0xf4, 0x57, 0x7c,
0x8c, 0xc1, 0xcb, 0xe8, 0xc5, 0xf5, 0x8f, 0x49, 0x0e, 0x02, 0xef, 0x5e, 0x6c, 0x33, 0x34, 0x24, 0x45, 0xdf, 0x84, 0x87, 0x4a, 0xa6, 0xcb, 0x7c,
0x97, 0x1a, 0x91, 0xa4, 0x94, 0xc3, 0x50, 0x13, 0xe5, 0x13, 0xb7, 0x7f, 0x03, 0xa3, 0xaa, 0x8e, 0x2d, 0x82, 0x01, 0x27, 0x87, 0x74, 0x82, 0x1a,
0x26, 0x53, 0x19, 0xb0, 0x37, 0xa5, 0xef, 0xe6, 0x2a, 0x39, 0xdc, 0x93, 0xbc, 0x0f, 0x76, 0x69, 0xab, 0xe0, 0x4e, 0x70, 0xbe, 0x37, 0xfc, 0xc8,
0x37, 0xe2, 0x3d, 0x7f, 0xcb, 0x4b, 0x93, 0xa2, 0xc3, 0x69, 0x78, 0xc9, 0x2c, 0x91, 0x17, 0x4f, 0xd5, 0x26, 0x3b, 0x7b, 0x90, 0xb5, 0x2d, 0x64,
0x01, 0xfa, 0x68, 0x3b, 0xe0, 0xe2, 0x22, 0x6c, 0xeb, 0xe4, 0x8a, 0xa8, 0xba, 0xf7, 0xd2, 0x8a, 0xb4, 0x8f, 0x38, 0x9d, 0x8e, 0xba, 0xe7, 0x5c,
0x3e, 0xf5, 0x20, 0x82, 0xa8, 0x62, 0x68, 0x59, 0x78, 0x24, 0xde, 0xef, 0x52, 0xf1, 0x0a, 0xb8, 0xc0, 0x1b, 0xb6, 0xb1, 0x70, 0x7e, 0x47, 0x59,
0x47, 0x43, 0xb1, 0x6c, 0x38, 0x29, 0xd3, 0x69, 0x3f, 0xae, 0x35, 0x57, 0x94, 0x59, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x10, 0x30,
0x75, 0x80, 0xc9, 0x21, 0xe7, 0x01, 0xb9, 0x54, 0x8b, 0x6e, 0x4e, 0x2e, 0x82, 0x01, 0x0c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
0x5a, 0x5b, 0x77, 0xa4, 0x22, 0xc2, 0x7b, 0x95, 0xb9, 0x39, 0x2c, 0xbd, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30,
0xc2, 0x1e, 0x02, 0xa6, 0xb2, 0xbc, 0x0f, 0x7a, 0xcb, 0xdc, 0xbc, 0xbc, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
0x90, 0x66, 0xe3, 0xca, 0x46, 0x53, 0x3e, 0x98, 0xff, 0x2e, 0x78, 0x9f, 0x02, 0x02, 0x04, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
0xd3, 0xa1, 0x12, 0x93, 0x66, 0x7d, 0xcc, 0x94, 0x6b, 0xec, 0x19, 0x0e, 0x04, 0x14, 0x4b, 0xcb, 0xdf, 0xaa, 0x02, 0xde, 0x8d, 0xc3, 0xe7, 0xe5,
0x20, 0x45, 0x22, 0x57, 0x6d, 0x9e, 0xd0, 0x89, 0xf2, 0xa9, 0x34, 0xdc, 0x85, 0xdb, 0x2e, 0x8a, 0xbe, 0x75, 0x6b, 0x8a, 0x67, 0x58, 0x30, 0x81,
0xab, 0xa5, 0x73, 0x47, 0x38, 0xe3, 0x7f, 0x98, 0x3a, 0x61, 0xae, 0x6c, 0xb2, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xaa, 0x30, 0x81, 0xa7,
0x4d, 0xf2, 0x31, 0x90, 0xcb, 0x83, 0xc1, 0xee, 0xb4, 0xf2, 0x9a, 0x28, 0x80, 0x14, 0x04, 0x94, 0x66, 0xaa, 0xf9, 0x61, 0x89, 0xb6, 0xdb, 0xb5,
0x5f, 0xbb, 0x7d, 0x89, 0xdf, 0xa2, 0x31, 0xb6, 0x1d, 0x39, 0x2b, 0x70, 0xf7, 0x13, 0x38, 0x3d, 0x62, 0x84, 0xb8, 0x18, 0x0a, 0x8f, 0xa1, 0x81,
0xbf, 0x1e, 0xad, 0xe1, 0x74, 0x94, 0x1d, 0xf8, 0xc5, 0x1a, 0x8d, 0x13, 0x83, 0xa4, 0x81, 0x80, 0x30, 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
0x45, 0xf0, 0x6a, 0x80, 0x0c, 0x5d, 0xbb, 0x46, 0x8a, 0x43, 0xd0, 0xff, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06,
0x21, 0x39, 0x57, 0x53, 0x5b, 0x51, 0xf8, 0xa2, 0x8f, 0x7f, 0x27, 0xc7, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e,
0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x10, 0x30, 0x82, 0x01, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
0x0c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31,
0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f,
0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
0x04, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31,
0xe8, 0xe9, 0xac, 0x16, 0x5c, 0x5e, 0xb2, 0xe8, 0xeb, 0xff, 0x57, 0x27, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69,
0x20, 0x08, 0x72, 0x63, 0x9b, 0xe5, 0xb5, 0x16, 0x30, 0x81, 0xb2, 0x06, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f,
0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xaa, 0x30, 0x81, 0xa7, 0x80, 0x14, 0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64,
0x04, 0x94, 0x66, 0xaa, 0xf9, 0x61, 0x89, 0xb6, 0xdb, 0xb5, 0xf7, 0x13, 0x82, 0x09, 0x00, 0xdf, 0x86, 0x05, 0x31, 0x01, 0xbe, 0x9a, 0x9a, 0x30,
0x38, 0x3d, 0x62, 0x84, 0xb8, 0x18, 0x0a, 0x8f, 0xa1, 0x81, 0x83, 0xa4, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x04, 0x01,
0x81, 0x80, 0x30, 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x01, 0x04, 0x04, 0x02, 0x02, 0x1e, 0xe9, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82,
0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x02, 0x01, 0x00, 0x61, 0x3f, 0x2f, 0x43, 0xe4, 0xbe, 0x66, 0x34, 0xef,
0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x92, 0x06, 0xe9, 0x88, 0xba, 0x6a, 0x1d, 0x4f, 0x54, 0x5a, 0x97, 0xb1,
0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x75, 0xd7, 0x93, 0xf8, 0x45, 0xc6, 0x83, 0x92, 0x36, 0xfd, 0x55, 0xa9,
0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x21, 0x0b, 0xdc, 0xf6, 0xae, 0x11, 0xdc, 0x62, 0x21, 0x44, 0xbd, 0x04,
0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1d, 0x58, 0x2c, 0x03, 0xf8, 0xe4, 0xe2, 0x1e, 0xba, 0xe6, 0xdd, 0x19,
0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, 0xdd, 0x56, 0xfd, 0xce, 0x06, 0x73, 0x5f, 0x94, 0x1e, 0xb6, 0x03, 0xdb,
0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, 0x3d, 0x7b, 0xab, 0xab, 0x72, 0x64, 0x7b, 0xde, 0x7d, 0x4d, 0xcf, 0x7e,
0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0xf0, 0x91, 0x29, 0xc1, 0x77, 0x13, 0xc2, 0x6f, 0x80, 0xab, 0x7a, 0xa8,
0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x82, 0x09, 0xce, 0xb0, 0x1c, 0x2a, 0xc5, 0x9c, 0xfb, 0x0b, 0xe5, 0x9f, 0x9c, 0x1b,
0x00, 0xdf, 0x86, 0x05, 0x31, 0x01, 0xbe, 0x9a, 0x9a, 0x30, 0x12, 0x06, 0xc9, 0x4b, 0x58, 0xdf, 0x96, 0x18, 0xf7, 0x67, 0x67, 0x89, 0xa4, 0xe9,
0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x04, 0x01, 0x01, 0x04, 0x14, 0x48, 0xac, 0xfa, 0x9d, 0x86, 0x2a, 0xeb, 0x75, 0x2c, 0x2b, 0xbf,
0x04, 0x02, 0x02, 0x1c, 0xb2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x63, 0x7d, 0xc7, 0x4e, 0x7e, 0xad, 0x39, 0x2d, 0xb4, 0x7c, 0x07, 0xa5,
0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x5a, 0xe8, 0x3a, 0xd4, 0xf5, 0x0c, 0x4f, 0xf3, 0xa2, 0x9c, 0x3c, 0x32,
0x00, 0x25, 0xce, 0xd2, 0x02, 0x48, 0xbb, 0xbe, 0xfc, 0xb6, 0xa4, 0x87, 0xed, 0x9d, 0x4b, 0x49, 0x05, 0xbc, 0x1f, 0xa0, 0x13, 0xe6, 0xdd, 0x82,
0x87, 0xe0, 0x21, 0x7d, 0xfa, 0x23, 0xc3, 0x0d, 0x73, 0x8f, 0x46, 0xe7, 0x79, 0x06, 0x31, 0x3b, 0xc6, 0x97, 0xec, 0x8d, 0xaa, 0x4f, 0xef, 0x14,
0x09, 0x59, 0xda, 0x2e, 0x55, 0x59, 0xff, 0x3c, 0x1b, 0xf6, 0xf8, 0x9a, 0x3c, 0x21, 0xf6, 0x72, 0xb2, 0x09, 0x42, 0xc7, 0x74, 0xfe, 0xef, 0x70,
0xc4, 0x1c, 0xf7, 0xac, 0xca, 0xe7, 0x63, 0xf2, 0xc7, 0xd6, 0x0c, 0x2d, 0xbd, 0xe9, 0x85, 0x41, 0x30, 0x0b, 0xb3, 0x6b, 0x59, 0x0c, 0x0f, 0x11,
0xa6, 0xad, 0x55, 0xf4, 0x10, 0x0e, 0xa8, 0x82, 0x0f, 0x88, 0xb5, 0x44, 0x75, 0xd4, 0xbb, 0xb1, 0xdf, 0xb1, 0xdf, 0xb3, 0xfa, 0xb3, 0x3a, 0x43,
0xe8, 0x8e, 0x84, 0x08, 0xf7, 0xdd, 0xe7, 0x10, 0xce, 0x71, 0x56, 0x57, 0x17, 0x7d, 0x8a, 0x82, 0xae, 0xa2, 0x07, 0xf8, 0x83, 0x51, 0xfb, 0x16,
0x3f, 0xed, 0x48, 0xee, 0xe2, 0x5d, 0x08, 0x0a, 0x58, 0xe4, 0xfe, 0xbc, 0xfb, 0x64, 0xb6, 0x46, 0xda, 0xbe, 0x32, 0x2b, 0xc0, 0xee, 0x78, 0x2a,
0x8c, 0x27, 0x1a, 0x46, 0x3f, 0xd5, 0x2d, 0xdb, 0x0b, 0x71, 0x73, 0xd1, 0x84, 0xa9, 0x54, 0x0a, 0xf9, 0x2d, 0x61, 0x65, 0xde, 0xa5, 0x97, 0x66,
0x49, 0xf3, 0x5c, 0x86, 0x4d, 0x0a, 0xe1, 0xeb, 0x53, 0x21, 0x38, 0x4f, 0x79, 0x02, 0xf8, 0x97, 0x17, 0xe2, 0xd4, 0x9f, 0x9e, 0xac, 0xcc, 0xae,
0xec, 0x1e, 0xc2, 0x68, 0x1f, 0x7d, 0xa6, 0x33, 0xe9, 0xa5, 0x37, 0x2a, 0x99, 0x9a, 0x03, 0x04, 0xbb, 0x45, 0xfe, 0xb2, 0xf5, 0x80, 0xba, 0xbf,
0xef, 0xcd, 0x78, 0x56, 0xb3, 0x39, 0x60, 0xf4, 0xa5, 0xf9, 0x2b, 0x85, 0xdd, 0x24, 0xe5, 0xe6, 0x1e, 0x5d, 0x36, 0xa5, 0x87, 0x0c, 0xdf, 0x60,
0xcf, 0xe6, 0x1c, 0x7c, 0x8a, 0x5d, 0xe8, 0x26, 0x02, 0xcf, 0x7a, 0x56, 0x81, 0x6f, 0xb7, 0x5f, 0xb9, 0x1f, 0xca, 0x75, 0x3c, 0x1a, 0x63, 0xb0,
0x1f, 0xae, 0x0d, 0x71, 0x20, 0xee, 0xec, 0x3b, 0xae, 0x95, 0x25, 0x15, 0xeb, 0xe6, 0x95, 0x86, 0x0d, 0xae, 0xa6, 0xc9, 0x2a, 0x94, 0xf1, 0xd0,
0xc8, 0xf6, 0x92, 0x5d, 0xb8, 0x9b, 0xc2, 0xb4, 0x95, 0x33, 0x13, 0x76, 0xbe, 0x75, 0xc8, 0xf8, 0x07, 0xd7, 0x88, 0xff, 0xec, 0xf9, 0xcd, 0x49,
0x45, 0xbe, 0x21, 0xe2, 0x3a, 0x69, 0x66, 0xd7, 0xff, 0x22, 0x00, 0x89, 0xc6, 0xfe, 0x4d, 0x7f, 0x44, 0x1e, 0xd8, 0xaf, 0xa9, 0x72, 0x27, 0x98,
0xc9, 0x44, 0xb6, 0x54, 0x38, 0x1f, 0x33, 0xe4, 0xda, 0x7b, 0x87, 0xf3, 0xe2, 0x5a, 0x08, 0xea, 0x55, 0xd3, 0xb3, 0xea, 0xdc, 0x76, 0x69, 0x51,
0x23, 0xed, 0xf5, 0x16, 0x08, 0xbe, 0x4b, 0xea, 0x91, 0x8f, 0x91, 0x8b, 0x10, 0x01, 0x46, 0x7d, 0x33, 0x94, 0x9c, 0x94, 0xef, 0xfe, 0x76, 0x1c,
0x4e, 0xd1, 0x02, 0x06, 0xa2, 0x77, 0x15, 0x03, 0x46, 0x11, 0x7d, 0x5b, 0xc6, 0xd7, 0x15, 0x53, 0x3e, 0x8d, 0x3d, 0x29, 0x9a, 0x58, 0x6a, 0xf1,
0xea, 0x7a, 0xf6, 0x86, 0x7d, 0x96, 0xb7, 0x73, 0x9b, 0x5b, 0x32, 0xc3, 0x75, 0x9e, 0xea, 0x1b, 0x4c, 0xf0, 0x47, 0x76, 0xac, 0xc6, 0xa2, 0x32,
0xf8, 0x92, 0x36, 0xe3, 0xe3, 0x2f, 0xe8, 0xf1, 0x72, 0xec, 0x0d, 0x50, 0x44, 0x40, 0xdf, 0xfe, 0xff, 0x9d, 0xf4, 0xe2, 0xc2, 0xfa, 0xa1, 0x5f,
0xd4, 0x86, 0xc5, 0x62, 0x83, 0xf1, 0x2a, 0x4c, 0xd1, 0xbf, 0x76, 0x62, 0x2e, 0x66, 0xe9, 0x97, 0xcb, 0x27, 0x26, 0x6e, 0x53, 0xe4, 0xe8, 0x86,
0xd4, 0x21, 0x11, 0x68, 0xb2, 0xd6, 0x8d, 0xc4, 0xf8, 0xe4, 0x70, 0x85, 0x2c, 0xea, 0xd3, 0x69, 0x6c, 0x61, 0x4f, 0xfe, 0xc1, 0xc9, 0x8b, 0x05,
0x19, 0xa7, 0x82, 0x27, 0x2c, 0x24, 0x21, 0x7a, 0x3b, 0xad, 0x8a, 0xd3, 0x92, 0x6f, 0x47, 0x96, 0xce, 0xf0, 0x33, 0xfa, 0x7c, 0x78, 0x24, 0x9b,
0xae, 0xda, 0x78, 0x3c, 0x6c, 0xab, 0xa2, 0xaa, 0x36, 0xf0, 0x1c, 0x58, 0xd7, 0x8d, 0x36, 0x56, 0x37, 0x86, 0xbc, 0x72, 0x5a, 0xf9, 0xb9, 0xb0,
0xd4, 0x72, 0x5e, 0xe8, 0x8b, 0x41, 0x08, 0xf5, 0x85, 0xdd, 0xee, 0x99, 0x93, 0xf0, 0x81, 0x78, 0x10, 0xf2, 0xb0, 0xc2, 0x79, 0x91, 0x5e, 0xcf,
0x12, 0xf4, 0xd6, 0x41, 0x83, 0x69, 0xe7, 0x79, 0x19, 0xa3, 0x74, 0xc4, 0xbc, 0x8c, 0xf2, 0x32, 0x0f, 0xf7, 0x2d, 0x30, 0xd8, 0x13, 0x77, 0x4f,
0x34, 0x2a, 0x8a, 0x7e, 0x4d, 0xbb, 0x2c, 0x49, 0x19, 0xf7, 0x98, 0x98, 0x78, 0x9e, 0x40, 0x8d, 0xe6, 0x3a, 0x98, 0xb2, 0xaa, 0x13, 0x4d, 0x25,
0xfc, 0x81, 0xf7, 0x9b, 0x7f, 0xff, 0xd9, 0x66, 0xf4, 0x51, 0x14, 0x29, 0x49, 0x34, 0x6c, 0x80, 0x9e, 0x19, 0x03, 0xdb, 0xcd, 0xf5, 0xb1, 0x54,
0x2a, 0x14, 0x1d, 0x4f, 0xbd, 0x91, 0xba, 0x6f, 0x32, 0x34, 0x3c, 0x40, 0x74, 0x1b, 0x67, 0x3c, 0x46, 0xac, 0x3e, 0x5d, 0xa2, 0xd9, 0x13, 0x83,
0x28, 0x6c, 0x97, 0xf8, 0x6d, 0x38, 0xcd, 0xa3, 0x7b, 0x18, 0xc8, 0x77, 0x30, 0xeb, 0x82, 0x3b, 0x06, 0xab, 0x3c, 0x39, 0x7d, 0xd0, 0x68, 0x31,
0x58, 0x4d, 0x53, 0x30, 0x7f, 0x4d, 0x89, 0xca, 0x95, 0x6e, 0xb5, 0xb8, 0x00
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;
const size_t kOEMPublicCertSize_Prod = sizeof(kOEMPublicCert_Prod);
// Refer to the following in main modules. // Refer to the following in main modules.
// This level of indirection is present so new OEM Certificates can be // This level of indirection is present so new OEM Certificates can be

View File

@@ -13,12 +13,14 @@
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <openssl/aes.h>
#include <openssl/err.h> #include <openssl/err.h>
#include "keys.h" #include "keys.h"
#include "log.h" #include "log.h"
#include "oemcrypto_key_ref.h" #include "oemcrypto_key_ref.h"
#include "oemcrypto_rsa_key_shared.h" #include "oemcrypto_rsa_key_shared.h"
#include "string_conversions.h"
namespace wvoec_ref { namespace wvoec_ref {
@@ -84,6 +86,105 @@ SessionContext* CryptoEngine::FindSession(SessionId sid) {
return NULL; return NULL;
} }
time_t CryptoEngine::OnlineTime() {
// Use the monotonic clock for times that don't have to be stable across
// device boots.
timespec current_time;
int gettime_result = clock_gettime(CLOCK_MONOTONIC, &current_time);
if (gettime_result == 0) {
return current_time.tv_sec;
} else {
// Can't use monotonic clock, use roll back time.
return RollbackCorrectedOfflineTime();
}
}
time_t CryptoEngine::RollbackCorrectedOfflineTime() {
struct TimeInfo {
// The max time recorded through this function call.
time_t previous_time;
// If the wall time is rollbacked to before the previous_time, this member
// is updated to reflect the offset.
time_t rollback_offset;
// Pad the struct so that TimeInfo is a multiple of 16.
uint8_t padding[16 - (2 * sizeof(time_t)) % 16];
};
std::vector<uint8_t> encrypted_buffer(sizeof(TimeInfo));
std::vector<uint8_t> clear_buffer(sizeof(TimeInfo));
TimeInfo time_info;
memset(&time_info, 0, sizeof(time_info));
// Use the device key for encrypt/decrypt.
const std::vector<uint8_t>& key = DeviceRootKey();
wvcdm::File* file;
std::string path;
// Note: this path is OK for a real implementation, but using security level 1
// would be better.
// TODO(fredgc, jfore): Address how this property is presented to the ref.
// For now, the path is empty.
/*if (!wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3,
&path)) {
LOGE("RollbackCorrectedOfflineTime: Unable to get base path");
}*/
std::string filename = path + "StoredUsageTime.dat";
wvcdm::FileSystem* file_system = file_system_.get();
if (file_system->Exists(filename)) {
// Load time info from previous call to this function.
file = file_system->Open(filename, wvcdm::FileSystem::kReadOnly);
if (!file) {
LOGE("RollbackCorrectedOfflineTime: File open failed: %s",
filename.c_str());
return time(NULL);
}
file->Read(reinterpret_cast<char*>(&encrypted_buffer[0]), sizeof(TimeInfo));
file->Close();
// Decrypt the encrypted TimeInfo buffer.
AES_KEY aes_key;
AES_set_decrypt_key(&key[0], 128, &aes_key);
std::vector<uint8_t> iv(wvoec::KEY_IV_SIZE, 0);
AES_cbc_encrypt(&encrypted_buffer[0], &clear_buffer[0], sizeof(TimeInfo),
&aes_key, iv.data(), AES_DECRYPT);
memcpy(&time_info, &clear_buffer[0], sizeof(TimeInfo));
}
time_t current_time;
// Add any time offsets in the past to the current time.
current_time = time(NULL) + time_info.rollback_offset;
if (time_info.previous_time > current_time) {
// Time has been rolled back.
// Update the rollback offset.
time_info.rollback_offset += time_info.previous_time - current_time;
// Keep current time at previous recorded time.
current_time = time_info.previous_time;
}
// The new previous_time will either stay the same or move forward.
time_info.previous_time = current_time;
// Copy updated data and encrypt the buffer.
memcpy(&clear_buffer[0], &time_info, sizeof(TimeInfo));
AES_KEY aes_key;
AES_set_encrypt_key(&key[0], 128, &aes_key);
std::vector<uint8_t> iv(wvoec::KEY_IV_SIZE, 0);
AES_cbc_encrypt(&clear_buffer[0], &encrypted_buffer[0], sizeof(TimeInfo),
&aes_key, iv.data(), AES_ENCRYPT);
// Write the encrypted buffer to disk.
file = file_system->Open(
filename, wvcdm::FileSystem::kCreate | wvcdm::FileSystem::kTruncate);
if (!file) {
LOGE("RollbackCorrectedOfflineTime: File open failed: %s",
filename.c_str());
return time(NULL);
}
file->Write(reinterpret_cast<char*>(&encrypted_buffer[0]), sizeof(TimeInfo));
file->Close();
// Return time with offset.
return current_time;
}
OEMCrypto_HDCP_Capability CryptoEngine::config_current_hdcp_capability() { OEMCrypto_HDCP_Capability CryptoEngine::config_current_hdcp_capability() {
return config_local_display_only() ? HDCP_NO_DIGITAL_OUTPUT : HDCP_V1; return config_local_display_only() ? HDCP_NO_DIGITAL_OUTPUT : HDCP_V1;
} }

View File

@@ -88,6 +88,10 @@ class CryptoEngine {
return kMaxSupportedOEMCryptoSessions; return kMaxSupportedOEMCryptoSessions;
} }
time_t OnlineTime();
time_t RollbackCorrectedOfflineTime();
// Returns the HDCP version currently in use. // Returns the HDCP version currently in use.
virtual OEMCrypto_HDCP_Capability config_current_hdcp_capability(); virtual OEMCrypto_HDCP_Capability config_current_hdcp_capability();
@@ -144,6 +148,7 @@ class CryptoEngine {
virtual uint8_t config_security_patch_level() { return 0; } virtual uint8_t config_security_patch_level() { return 0; }
// If 0 no restriction, otherwise it's the max buffer for DecryptCENC. // If 0 no restriction, otherwise it's the max buffer for DecryptCENC.
// This is the same as the max subsample size, not the sample or frame size.
virtual size_t max_buffer_size() { return 1024 * 100; } // 100 KiB. virtual size_t max_buffer_size() { return 1024 * 100; } // 100 KiB.
virtual bool srm_update_supported() { return false; } virtual bool srm_update_supported() { return false; }
@@ -170,6 +175,8 @@ class CryptoEngine {
// size is unlimited -- or limited only by memory size. // size is unlimited -- or limited only by memory size.
virtual size_t max_usage_table_size() { return 0; } virtual size_t max_usage_table_size() { return 0; }
virtual uint32_t resource_rating() { return 1; }
// Set destination pointer based on the output destination description. // Set destination pointer based on the output destination description.
OEMCryptoResult SetDestination(OEMCrypto_DestBufferDesc* out_description, OEMCryptoResult SetDestination(OEMCrypto_DestBufferDesc* out_description,
size_t data_length, uint8_t subsample_flags); size_t data_length, uint8_t subsample_flags);

View File

@@ -21,7 +21,8 @@ bool KeyControlBlock::Validate() {
memcmp(verification_, "kc11", 4) && // add in version 11 api memcmp(verification_, "kc11", 4) && // add in version 11 api
memcmp(verification_, "kc12", 4) && // add in version 12 api memcmp(verification_, "kc12", 4) && // add in version 12 api
memcmp(verification_, "kc13", 4) && // add in version 13 api memcmp(verification_, "kc13", 4) && // add in version 13 api
memcmp(verification_, "kc14", 4)) { // add in version 14 api memcmp(verification_, "kc14", 4) && // add in version 14 api
memcmp(verification_, "kc15", 4)) { // add in version 15 api
LOGE("KCB: BAD verification string: %4.4s", verification_); LOGE("KCB: BAD verification string: %4.4s", verification_);
valid_ = false; valid_ = false;
} else { } else {

View File

@@ -31,16 +31,21 @@
namespace wvoec_ref { namespace wvoec_ref {
OldUsageTableEntry::OldUsageTableEntry(const std::vector<uint8_t> &pst_hash) OldUsageTableEntry::OldUsageTableEntry(OldUsageTable *old_usage_table,
const std::vector<uint8_t> &pst_hash)
: pst_hash_(pst_hash), : pst_hash_(pst_hash),
time_of_license_received_(time(NULL)), old_usage_table_(old_usage_table),
time_of_license_received_(
old_usage_table_->ce_->RollbackCorrectedOfflineTime()),
time_of_first_decrypt_(0), time_of_first_decrypt_(0),
time_of_last_decrypt_(0), time_of_last_decrypt_(0),
status_(kUnused) {} status_(kUnused) {}
OldUsageTableEntry::~OldUsageTableEntry() {} OldUsageTableEntry::~OldUsageTableEntry() {}
OldUsageTableEntry::OldUsageTableEntry(const OldStoredUsageEntry *buffer) { OldUsageTableEntry::OldUsageTableEntry(OldUsageTable *old_usage_table,
const OldStoredUsageEntry *buffer)
: old_usage_table_(old_usage_table) {
pst_hash_.assign(buffer->pst_hash, buffer->pst_hash + SHA256_DIGEST_LENGTH); pst_hash_.assign(buffer->pst_hash, buffer->pst_hash + SHA256_DIGEST_LENGTH);
time_of_license_received_ = buffer->time_of_license_received; time_of_license_received_ = buffer->time_of_license_received;
time_of_first_decrypt_ = buffer->time_of_first_decrypt; time_of_first_decrypt_ = buffer->time_of_first_decrypt;
@@ -95,6 +100,11 @@ OldUsageTable::OldUsageTable(CryptoEngine *ce) {
// This should be encrypted and signed with a device specific key. // This should be encrypted and signed with a device specific key.
// For the reference implementation, I'm just going to use the keybox key. // For the reference implementation, I'm just going to use the keybox key.
const std::vector<uint8_t> &key = ce_->DeviceRootKey(); const std::vector<uint8_t> &key = ce_->DeviceRootKey();
if (key.empty()) {
LOGE("OldUsageTable: DeviceRootKey is unexpectedly empty.");
table_.clear();
return;
}
uint8_t computed_signature[SHA256_DIGEST_LENGTH]; uint8_t computed_signature[SHA256_DIGEST_LENGTH];
unsigned int sig_length = sizeof(computed_signature); unsigned int sig_length = sizeof(computed_signature);
@@ -152,7 +162,7 @@ OldUsageTable::OldUsageTable(CryptoEngine *ce) {
// entries. // entries.
for (uint64_t i = 0; i < stored_table->count; i++) { for (uint64_t i = 0; i < stored_table->count; i++) {
OldUsageTableEntry *entry = OldUsageTableEntry *entry =
new OldUsageTableEntry(&stored_table->entries[i].entry); new OldUsageTableEntry(this, &stored_table->entries[i].entry);
table_[entry->pst_hash()] = entry; table_[entry->pst_hash()] = entry;
} }
} }
@@ -183,7 +193,7 @@ OldUsageTableEntry *OldUsageTable::CreateEntry(
LOGE("OldUsageTable: Could not compute hash of pst."); LOGE("OldUsageTable: Could not compute hash of pst.");
return NULL; return NULL;
} }
OldUsageTableEntry *entry = new OldUsageTableEntry(pst_hash); OldUsageTableEntry *entry = new OldUsageTableEntry(this, pst_hash);
wvcdm::AutoLock lock(lock_); wvcdm::AutoLock lock(lock_);
table_[pst_hash] = entry; table_[pst_hash] = entry;
return entry; return entry;

View File

@@ -23,6 +23,7 @@
namespace wvoec_ref { namespace wvoec_ref {
class CryptoEngine; class CryptoEngine;
class OldUsageTable;
class UsagetTableEntry; class UsagetTableEntry;
struct OldStoredUsageEntry { struct OldStoredUsageEntry {
@@ -51,13 +52,16 @@ struct OldStoredUsageTable {
class OldUsageTableEntry { class OldUsageTableEntry {
public: public:
OldUsageTableEntry(const std::vector<uint8_t> &pst_hash); OldUsageTableEntry(OldUsageTable *old_usage_table,
OldUsageTableEntry(const OldStoredUsageEntry *buffer); const std::vector<uint8_t> &pst_hash);
OldUsageTableEntry(OldUsageTable *old_usage_table,
const OldStoredUsageEntry *buffer);
~OldUsageTableEntry(); ~OldUsageTableEntry();
const std::vector<uint8_t> &pst_hash() const { return pst_hash_; } const std::vector<uint8_t> &pst_hash() const { return pst_hash_; }
private: private:
std::vector<uint8_t> pst_hash_; std::vector<uint8_t> pst_hash_;
const OldUsageTable *old_usage_table_;
int64_t time_of_license_received_; int64_t time_of_license_received_;
int64_t time_of_first_decrypt_; int64_t time_of_first_decrypt_;
int64_t time_of_last_decrypt_; int64_t time_of_last_decrypt_;
@@ -88,6 +92,8 @@ class OldUsageTable {
wvcdm::Lock lock_; wvcdm::Lock lock_;
int64_t generation_; int64_t generation_;
CryptoEngine *ce_; CryptoEngine *ce_;
friend class OldUsageTableEntry;
}; };
} // namespace wvoec_ref } // namespace wvoec_ref

View File

@@ -74,6 +74,11 @@ extern "C" OEMCryptoResult OEMCrypto_Initialize(void) {
return OEMCrypto_SUCCESS; return OEMCrypto_SUCCESS;
} }
extern "C" OEMCryptoResult OEMCrypto_SetSandbox(const uint8_t* /*sandbox_id*/,
size_t /*sandbox_id_length*/) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
extern "C" OEMCryptoResult OEMCrypto_Terminate(void) { extern "C" OEMCryptoResult OEMCrypto_Terminate(void) {
if (!crypto_engine) { if (!crypto_engine) {
LOGE("[OEMCrypto_Terminate(): not initialized]"); LOGE("[OEMCrypto_Terminate(): not initialized]");
@@ -238,12 +243,21 @@ bool RangeCheck(const uint8_t* message, uint32_t message_length,
return true; return true;
} }
bool RangeCheck(uint32_t message_length, const OEMCrypto_Substring& substring,
bool allow_null) {
if (!substring.length) return allow_null;
if (substring.offset > message_length) return false;
if (substring.offset + substring.length > message_length) return false;
return true;
}
extern "C" OEMCryptoResult OEMCrypto_LoadKeys( extern "C" OEMCryptoResult OEMCrypto_LoadKeys(
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
const uint8_t* signature, size_t signature_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, OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys,
const OEMCrypto_KeyObject* key_array, const uint8_t* pst, size_t pst_length, size_t num_keys, const OEMCrypto_KeyObject* key_array,
const uint8_t* srm_requirement, OEMCrypto_LicenseType license_type) { OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data,
OEMCrypto_LicenseType license_type) {
if (!crypto_engine) { if (!crypto_engine) {
LOGE("OEMCrypto_LoadKeys: OEMCrypto Not Initialized."); LOGE("OEMCrypto_LoadKeys: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE; return OEMCrypto_ERROR_UNKNOWN_FAILURE;
@@ -262,20 +276,12 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys(
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT]"); LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT; return OEMCrypto_ERROR_INVALID_CONTEXT;
} }
// Later on, we use pst_length to verify the the pst is valid. This makes
// sure that we aren't given a null string but told it has postiive length.
if (pst == NULL && pst_length > 0) {
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_ONCTEXT - null pst.]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Range check // Range check
if (!RangeCheck(message, message_length, enc_mac_keys, 2 * wvoec::MAC_KEY_SIZE, if (!RangeCheck(message_length, enc_mac_keys_iv, true) ||
true) || !RangeCheck(message_length, enc_mac_keys, true) ||
!RangeCheck(message, message_length, enc_mac_key_iv, wvoec::KEY_IV_SIZE, true) || !RangeCheck(message_length, pst, true) ||
!RangeCheck(message, message_length, pst, pst_length, true) || !RangeCheck(message_length, srm_restriction_data, true)) {
!RangeCheck(message, message_length, srm_requirement,
wvoec::SRM_REQUIREMENT_SIZE, true)) {
LOGE( LOGE(
"[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - range " "[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - range "
"check.]"); "check.]");
@@ -283,16 +289,11 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys(
} }
for (unsigned int i = 0; i < num_keys; i++) { for (unsigned int i = 0; i < num_keys; i++) {
if (!RangeCheck(message, message_length, key_array[i].key_id, if (!RangeCheck(message_length, key_array[i].key_id, false) ||
key_array[i].key_id_length, false) || !RangeCheck(message_length, key_array[i].key_data, false) ||
!RangeCheck(message, message_length, key_array[i].key_data, !RangeCheck(message_length, key_array[i].key_data_iv, false) ||
key_array[i].key_data_length, false) || !RangeCheck(message_length, key_array[i].key_control, false) ||
!RangeCheck(message, message_length, key_array[i].key_data_iv, !RangeCheck(message_length, key_array[i].key_control_iv, false)) {
wvoec::KEY_IV_SIZE, false) ||
!RangeCheck(message, message_length, key_array[i].key_control,
wvoec::KEY_CONTROL_SIZE, false) ||
!RangeCheck(message, message_length, key_array[i].key_control_iv,
wvoec::KEY_IV_SIZE, false)) {
LOGE( LOGE(
"[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT -range " "[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT -range "
"check %d]", "check %d]",
@@ -301,14 +302,14 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys(
} }
} }
return session_ctx->LoadKeys(message, message_length, signature, return session_ctx->LoadKeys(message, message_length, signature,
signature_length, enc_mac_key_iv, enc_mac_keys, signature_length, enc_mac_keys_iv, enc_mac_keys,
num_keys, key_array, pst, pst_length, num_keys, key_array, pst, srm_restriction_data,
srm_requirement, license_type); license_type);
} }
extern "C" OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( extern "C" OEMCryptoResult OEMCrypto_LoadEntitledContentKeys(
OEMCrypto_SESSION session, size_t num_keys, OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
const OEMCrypto_EntitledContentKeyObject* key_array) { size_t num_keys, const OEMCrypto_EntitledContentKeyObject* key_array) {
if (num_keys == 0) { if (num_keys == 0) {
LOGE("[OEMCrypto_LoadEntitledContentKeys(): key_array is empty."); LOGE("[OEMCrypto_LoadEntitledContentKeys(): key_array is empty.");
return OEMCrypto_SUCCESS; return OEMCrypto_SUCCESS;
@@ -326,8 +327,22 @@ extern "C" OEMCryptoResult OEMCrypto_LoadEntitledContentKeys(
LOGE("[OEMCrypto_LoadEntitledContentKeys(): ERROR_INVALID_SESSION]"); LOGE("[OEMCrypto_LoadEntitledContentKeys(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION; return OEMCrypto_ERROR_INVALID_SESSION;
} }
for (unsigned int i = 0; i < num_keys; i++) {
if (!RangeCheck(message_length, key_array[i].entitlement_key_id, false) ||
!RangeCheck(message_length, key_array[i].content_key_id, false) ||
!RangeCheck(message_length, key_array[i].content_key_data_iv, false) ||
!RangeCheck(message_length, key_array[i].content_key_data, false)) {
LOGE(
"[OEMCrypto_LoadEntitledContentKeys(): "
"OEMCrypto_ERROR_INVALID_CONTEXT -range "
"check %d]",
i);
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
}
return session_ctx->LoadEntitledContentKeys(num_keys, key_array); return session_ctx->LoadEntitledContentKeys(message, message_length, num_keys,
key_array);
} }
extern "C" OEMCryptoResult OEMCrypto_RefreshKeys( extern "C" OEMCryptoResult OEMCrypto_RefreshKeys(
@@ -358,12 +373,9 @@ extern "C" OEMCryptoResult OEMCrypto_RefreshKeys(
// Range check // Range check
for (unsigned int i = 0; i < num_keys; i++) { for (unsigned int i = 0; i < num_keys; i++) {
if (!RangeCheck(message, message_length, key_array[i].key_id, if (!RangeCheck(message_length, key_array[i].key_id, true) ||
key_array[i].key_id_length, true) || !RangeCheck(message_length, key_array[i].key_control, false) ||
!RangeCheck(message, message_length, key_array[i].key_control, !RangeCheck(message_length, key_array[i].key_control_iv, true)) {
wvoec::KEY_CONTROL_SIZE, false) ||
!RangeCheck(message, message_length, key_array[i].key_control_iv,
wvoec::KEY_IV_SIZE, true)) {
LOGE("[OEMCrypto_RefreshKeys(): Range Check %d]", i); LOGE("[OEMCrypto_RefreshKeys(): Range Check %d]", i);
return OEMCrypto_ERROR_INVALID_CONTEXT; return OEMCrypto_ERROR_INVALID_CONTEXT;
} }
@@ -382,24 +394,28 @@ extern "C" OEMCryptoResult OEMCrypto_RefreshKeys(
std::vector<uint8_t> key_control; std::vector<uint8_t> key_control;
std::vector<uint8_t> key_control_iv; std::vector<uint8_t> key_control_iv;
for (unsigned int i = 0; i < num_keys; i++) { for (unsigned int i = 0; i < num_keys; i++) {
if (key_array[i].key_id != NULL) { if (key_array[i].key_id.length != 0) {
key_id.assign(key_array[i].key_id, key_id.assign(
key_array[i].key_id + key_array[i].key_id_length); message + key_array[i].key_id.offset,
key_control.assign(key_array[i].key_control, message + key_array[i].key_id.offset + key_array[i].key_id.length);
key_array[i].key_control + wvoec::KEY_CONTROL_SIZE); key_control.assign(
if (key_array[i].key_control_iv == NULL) { message + key_array[i].key_control.offset,
message + key_array[i].key_control.offset + wvoec::KEY_CONTROL_SIZE);
if (key_array[i].key_control_iv.length == 0) {
key_control_iv.clear(); key_control_iv.clear();
} else { } else {
key_control_iv.assign(key_array[i].key_control_iv, key_control_iv.assign(
key_array[i].key_control_iv + wvoec::KEY_IV_SIZE); message + key_array[i].key_control_iv.offset,
message + key_array[i].key_control_iv.offset + wvoec::KEY_IV_SIZE);
} }
} else { } else {
// key_id could be null if special control key type // key_id could be null if special control key type
// key_control is not encrypted in this case // key_control is not encrypted in this case
key_id.clear(); key_id.clear();
key_control_iv.clear(); key_control_iv.clear();
key_control.assign(key_array[i].key_control, key_control.assign(
key_array[i].key_control + wvoec::KEY_CONTROL_SIZE); message + key_array[i].key_control.offset,
message + key_array[i].key_control.offset + wvoec::KEY_CONTROL_SIZE);
} }
status = session_ctx->RefreshKey(key_id, key_control, key_control_iv); status = session_ctx->RefreshKey(key_id, key_control, key_control_iv);
@@ -522,7 +538,7 @@ extern "C" OEMCryptoResult OEMCrypto_DecryptCENC(
} }
extern "C" OEMCryptoResult OEMCrypto_CopyBuffer( extern "C" OEMCryptoResult OEMCrypto_CopyBuffer(
const uint8_t* data_addr, size_t data_length, OEMCrypto_SESSION session, const uint8_t* data_addr, size_t data_length,
OEMCrypto_DestBufferDesc* out_buffer, uint8_t subsample_flags) { OEMCrypto_DestBufferDesc* out_buffer, uint8_t subsample_flags) {
if (!crypto_engine) { if (!crypto_engine) {
LOGE("OEMCrypto_CopyBuffer: OEMCrypto Not Initialized."); LOGE("OEMCrypto_CopyBuffer: OEMCrypto Not Initialized.");
@@ -714,6 +730,10 @@ extern "C" OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData,
extern "C" OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, extern "C" OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData,
size_t dataLength) { size_t dataLength) {
if (!crypto_engine) {
LOGE("OEMCrypto_GetRandom: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!randomData) { if (!randomData) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE; return OEMCrypto_ERROR_UNKNOWN_FAILURE;
} }
@@ -1114,7 +1134,7 @@ extern "C" OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(
return OEMCrypto_SUCCESS; return OEMCrypto_SUCCESS;
} }
extern "C" uint32_t OEMCrypto_APIVersion() { return 14; } extern "C" uint32_t OEMCrypto_APIVersion() { return 15; }
extern "C" uint8_t OEMCrypto_Security_Patch_Level() { extern "C" uint8_t OEMCrypto_Security_Patch_Level() {
uint8_t security_patch_level = crypto_engine->config_security_patch_level(); uint8_t security_patch_level = crypto_engine->config_security_patch_level();
@@ -1147,6 +1167,18 @@ extern "C" uint32_t OEMCrypto_GetAnalogOutputFlags() {
return crypto_engine->analog_output_flags(); return crypto_engine->analog_output_flags();
} }
extern "C" const char* OEMCrypto_BuildInformation() {
return "OEMCrypto Ref Code " __DATE__ " " __TIME__;
}
extern "C" uint32_t OEMCrypto_ResourceRatingTier(){
if (!crypto_engine) {
LOGE("OEMCrypto_ResourceRatingTier: OEMCrypto Not Initialized.");
return 0;
}
return crypto_engine->resource_rating();
}
extern "C" bool OEMCrypto_SupportsUsageTable() { extern "C" bool OEMCrypto_SupportsUsageTable() {
if (!crypto_engine) { if (!crypto_engine) {
LOGE("OEMCrypto_SupportsUsageTable: OEMCrypto Not Initialized."); LOGE("OEMCrypto_SupportsUsageTable: OEMCrypto Not Initialized.");
@@ -1584,4 +1616,52 @@ extern "C" OEMCryptoResult OEMCrypto_CreateOldUsageEntry(
pst_length); pst_length);
} }
extern "C" uint32_t OEMCrypto_SupportsDecryptHash() {
return OEMCrypto_CRC_Clear_Buffer;
}
extern "C" OEMCryptoResult OEMCrypto_InitializeDecryptHash(
OEMCrypto_SESSION session) {
if (!crypto_engine) {
LOGE("OEMCrypto_InitializeDecryptHash: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (!session_ctx || !session_ctx->isValid()) {
LOGE("[OEMCrypto_InitializeDecryptHash(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
return session_ctx->InitializeDecryptHash();
}
extern "C" OEMCryptoResult OEMCrypto_SetDecryptHash(OEMCrypto_SESSION session,
uint32_t frame_number,
const uint8_t* hash,
size_t hash_length) {
if (!crypto_engine) {
LOGE("OEMCrypto_SetDecryptHash: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (!session_ctx || !session_ctx->isValid()) {
LOGE("[OEMCrypto_SetDecryptHash(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
return session_ctx->SetDecryptHash(frame_number, hash, hash_length);
}
extern "C" OEMCryptoResult OEMCrypto_GetHashErrorCode(
OEMCrypto_SESSION session, uint32_t* failed_frame_number) {
if (!crypto_engine) {
LOGE("OEMCrypto_GetHashErrorCode: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (!session_ctx || !session_ctx->isValid()) {
LOGE("[OEMCrypto_GetHashErrorCode(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
return session_ctx->GetHashErrorCode(failed_frame_number);
}
} // namespace wvoec_ref } // namespace wvoec_ref

View File

@@ -32,6 +32,7 @@
#include "oemcrypto_types.h" #include "oemcrypto_types.h"
#include "disallow_copy_and_assign.h" #include "disallow_copy_and_assign.h"
#include "string_conversions.h" #include "string_conversions.h"
#include "wvcrc32.h"
static const int kPssSaltLength = 20; static const int kPssSaltLength = 20;
@@ -483,19 +484,20 @@ OEMCryptoResult SessionContext::CheckNonceOrEntry(
return OEMCrypto_SUCCESS; return OEMCrypto_SUCCESS;
} }
void SessionContext::StartTimer() { timer_start_ = time(NULL); } void SessionContext::StartTimer() { timer_start_ = ce_->OnlineTime(); }
uint32_t SessionContext::CurrentTimer() { uint32_t SessionContext::CurrentTimer() {
time_t now = time(NULL); time_t now = ce_->OnlineTime();
return now - timer_start_; return now - timer_start_;
} }
OEMCryptoResult SessionContext::LoadKeys( OEMCryptoResult SessionContext::LoadKeys(
const uint8_t* message, size_t message_length, const uint8_t* signature, const uint8_t* message, size_t message_length, const uint8_t* signature,
size_t signature_length, const uint8_t* enc_mac_key_iv, size_t signature_length, OEMCrypto_Substring enc_mac_keys_iv,
const uint8_t* enc_mac_keys, size_t num_keys, OEMCrypto_Substring enc_mac_keys, size_t num_keys,
const OEMCrypto_KeyObject* key_array, const uint8_t* pst, size_t pst_length, const OEMCrypto_KeyObject* key_array, OEMCrypto_Substring pst,
const uint8_t* srm_requirement, OEMCrypto_LicenseType license_type) { OEMCrypto_Substring srm_restriction_data,
OEMCrypto_LicenseType license_type) {
// Validate message signature // Validate message signature
if (!ValidateMessage(message, message_length, signature, signature_length)) { if (!ValidateMessage(message, message_length, signature, signature_length)) {
return OEMCrypto_ERROR_SIGNATURE_FAILURE; return OEMCrypto_ERROR_SIGNATURE_FAILURE;
@@ -522,16 +524,16 @@ OEMCryptoResult SessionContext::LoadKeys(
StartTimer(); StartTimer();
if (srm_requirement) { if (srm_restriction_data.length != 0) {
const std::string kSRMVerificationString = "HDCPDATA"; const std::string kSRMVerificationString = "HDCPDATA";
if (memcmp(srm_requirement, kSRMVerificationString.c_str(), if (memcmp(message + srm_restriction_data.offset,
kSRMVerificationString.size())) { kSRMVerificationString.c_str(), kSRMVerificationString.size())) {
LOGE("SRM Requirement Data has bad verification string: %8s", LOGE("SRM Requirement Data has bad verification string: %8s",
srm_requirement); message + srm_restriction_data.offset);
return OEMCrypto_ERROR_INVALID_CONTEXT; return OEMCrypto_ERROR_INVALID_CONTEXT;
} }
uint32_t minimum_version = uint32_t minimum_version = htonl(*reinterpret_cast<const uint32_t*>(
htonl(*reinterpret_cast<const uint32_t*>(srm_requirement + 8)); message + srm_restriction_data.offset + 8));
uint16_t current_version = 0; uint16_t current_version = 0;
if (OEMCrypto_SUCCESS != ce_->current_srm_version(&current_version)) { if (OEMCrypto_SUCCESS != ce_->current_srm_version(&current_version)) {
LOGW("[LoadKeys: SRM Version not available."); LOGW("[LoadKeys: SRM Version not available.");
@@ -563,20 +565,25 @@ OEMCryptoResult SessionContext::LoadKeys(
std::vector<uint8_t> key_control; std::vector<uint8_t> key_control;
std::vector<uint8_t> key_control_iv; std::vector<uint8_t> key_control_iv;
for (unsigned int i = 0; i < num_keys; i++) { for (unsigned int i = 0; i < num_keys; i++) {
key_id.assign(key_array[i].key_id, key_id.assign(
key_array[i].key_id + key_array[i].key_id_length); message + key_array[i].key_id.offset,
enc_key_data.assign(key_array[i].key_data, message + key_array[i].key_id.offset + key_array[i].key_id.length);
key_array[i].key_data + key_array[i].key_data_length); enc_key_data.assign(
key_data_iv.assign(key_array[i].key_data_iv, message + key_array[i].key_data.offset,
key_array[i].key_data_iv + wvoec::KEY_IV_SIZE); message + key_array[i].key_data.offset + key_array[i].key_data.length);
if (key_array[i].key_control == NULL) { key_data_iv.assign(
message + key_array[i].key_data_iv.offset,
message + key_array[i].key_data_iv.offset + wvoec::KEY_IV_SIZE);
if (key_array[i].key_control.length == 0) {
status = OEMCrypto_ERROR_UNKNOWN_FAILURE; status = OEMCrypto_ERROR_UNKNOWN_FAILURE;
break; break;
} }
key_control.assign(key_array[i].key_control, key_control.assign(
key_array[i].key_control + wvoec::KEY_CONTROL_SIZE); message + key_array[i].key_control.offset,
key_control_iv.assign(key_array[i].key_control_iv, message + key_array[i].key_control.offset + wvoec::KEY_CONTROL_SIZE);
key_array[i].key_control_iv + wvoec::KEY_IV_SIZE); key_control_iv.assign(
message + key_array[i].key_control_iv.offset,
message + key_array[i].key_control_iv.offset + wvoec::KEY_IV_SIZE);
OEMCryptoResult result = OEMCryptoResult result =
InstallKey(key_id, enc_key_data, key_data_iv, key_control, InstallKey(key_id, enc_key_data, key_data_iv, key_control,
@@ -590,12 +597,14 @@ OEMCryptoResult SessionContext::LoadKeys(
if (status != OEMCrypto_SUCCESS) return status; if (status != OEMCrypto_SUCCESS) return status;
// enc_mac_key can be NULL if license renewal is not supported // enc_mac_key can be NULL if license renewal is not supported
if (enc_mac_keys != NULL) { if (enc_mac_keys.length != 0) {
// V2.1 license protocol: update mac keys after processing license response // V2.1 license protocol: update mac keys after processing license response
const std::vector<uint8_t> enc_mac_keys_str = std::vector<uint8_t>( const std::vector<uint8_t> enc_mac_keys_str = std::vector<uint8_t>(
enc_mac_keys, enc_mac_keys + 2 * wvoec::MAC_KEY_SIZE); message + enc_mac_keys.offset,
message + enc_mac_keys.offset + 2 * wvoec::MAC_KEY_SIZE);
const std::vector<uint8_t> enc_mac_key_iv_str = std::vector<uint8_t>( const std::vector<uint8_t> enc_mac_key_iv_str = std::vector<uint8_t>(
enc_mac_key_iv, enc_mac_key_iv + wvoec::KEY_IV_SIZE); message + enc_mac_keys_iv.offset,
message + enc_mac_keys_iv.offset + wvoec::KEY_IV_SIZE);
if (!UpdateMacKeys(enc_mac_keys_str, enc_mac_key_iv_str)) { if (!UpdateMacKeys(enc_mac_keys_str, enc_mac_key_iv_str)) {
LOGE("Failed to update mac keys.\n"); LOGE("Failed to update mac keys.\n");
@@ -606,13 +615,13 @@ OEMCryptoResult SessionContext::LoadKeys(
OEMCryptoResult result = OEMCrypto_SUCCESS; OEMCryptoResult result = OEMCrypto_SUCCESS;
switch (usage_entry_status_) { switch (usage_entry_status_) {
case kNoUsageEntry: case kNoUsageEntry:
if (pst_length > 0) { if (pst.length > 0) {
LOGE("LoadKeys: PST specified but no usage entry loaded."); LOGE("LoadKeys: PST specified but no usage entry loaded.");
return OEMCrypto_ERROR_INVALID_CONTEXT; return OEMCrypto_ERROR_INVALID_CONTEXT;
} }
break; // no extra check. break; // no extra check.
case kUsageEntryNew: case kUsageEntryNew:
result = usage_entry_->SetPST(pst, pst_length); result = usage_entry_->SetPST(message + pst.offset, pst.length);
if (result != OEMCrypto_SUCCESS) { if (result != OEMCrypto_SUCCESS) {
return result; return result;
} }
@@ -622,7 +631,7 @@ OEMCryptoResult SessionContext::LoadKeys(
} }
break; break;
case kUsageEntryLoaded: case kUsageEntryLoaded:
if (!usage_entry_->VerifyPST(pst, pst_length)) { if (!usage_entry_->VerifyPST(message + pst.offset, pst.length)) {
return OEMCrypto_ERROR_WRONG_PST; return OEMCrypto_ERROR_WRONG_PST;
} }
if (!usage_entry_->VerifyMacKeys(mac_key_server_, mac_key_client_)) { if (!usage_entry_->VerifyMacKeys(mac_key_server_, mac_key_client_)) {
@@ -637,7 +646,8 @@ OEMCryptoResult SessionContext::LoadKeys(
} }
OEMCryptoResult SessionContext::LoadEntitledContentKeys( OEMCryptoResult SessionContext::LoadEntitledContentKeys(
size_t num_keys, const OEMCrypto_EntitledContentKeyObject* key_array) { const uint8_t* message, size_t message_length, size_t num_keys,
const OEMCrypto_EntitledContentKeyObject* key_array) {
if (!key_array) { if (!key_array) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE; return OEMCrypto_ERROR_UNKNOWN_FAILURE;
} }
@@ -647,9 +657,9 @@ OEMCryptoResult SessionContext::LoadEntitledContentKeys(
for (size_t i = 0; i < num_keys; ++i) { for (size_t i = 0; i < num_keys; ++i) {
const OEMCrypto_EntitledContentKeyObject* key_data = &key_array[i]; const OEMCrypto_EntitledContentKeyObject* key_data = &key_array[i];
std::vector<uint8_t> entitlement_key_id; std::vector<uint8_t> entitlement_key_id;
entitlement_key_id.assign( entitlement_key_id.assign(message + key_data->entitlement_key_id.offset,
key_data->entitlement_key_id, message + key_data->entitlement_key_id.offset +
key_data->entitlement_key_id + key_data->entitlement_key_id_length); key_data->entitlement_key_id.length);
const std::vector<uint8_t>* entitlement_key = NULL; const std::vector<uint8_t>* entitlement_key = NULL;
if (!session_keys_->GetEntitlementKey(entitlement_key_id, if (!session_keys_->GetEntitlementKey(entitlement_key_id,
@@ -661,14 +671,14 @@ OEMCryptoResult SessionContext::LoadEntitledContentKeys(
std::vector<uint8_t> encrypted_content_key; std::vector<uint8_t> encrypted_content_key;
std::vector<uint8_t> content_key_id; std::vector<uint8_t> content_key_id;
iv.assign(key_data->content_key_data_iv, iv.assign(message + key_data->content_key_data_iv.offset,
key_data->content_key_data_iv + 16); message + key_data->content_key_data_iv.offset + 16);
encrypted_content_key.assign( encrypted_content_key.assign(message + key_data->content_key_data.offset,
key_data->content_key_data, message + key_data->content_key_data.offset +
key_data->content_key_data + key_data->content_key_data_length); key_data->content_key_data.length);
content_key_id.assign( content_key_id.assign(message + key_data->content_key_id.offset,
key_data->content_key_id, message + key_data->content_key_id.offset +
key_data->content_key_id + key_data->content_key_id_length); key_data->content_key_id.length);
if (!DecryptMessage(*entitlement_key, iv, encrypted_content_key, if (!DecryptMessage(*entitlement_key, iv, encrypted_content_key,
&content_key, 256 /* key size */)) { &content_key, 256 /* key size */)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE; return OEMCrypto_ERROR_UNKNOWN_FAILURE;
@@ -809,7 +819,7 @@ OEMCryptoResult SessionContext::RefreshKey(
if (NULL == content_key) { if (NULL == content_key) {
LOGE("Key ID not found."); LOGE("Key ID not found.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE; return OEMCrypto_ERROR_NO_CONTENT_KEY;
} }
if (key_control.empty()) { if (key_control.empty()) {
@@ -1156,8 +1166,9 @@ OEMCryptoResult SessionContext::SelectContentKey(
Key* content_key = session_keys_->Find(key_id); Key* content_key = session_keys_->Find(key_id);
if (NULL == content_key) { if (NULL == content_key) {
LOGE("No key matches key id"); LOGE("No key matches key id");
return OEMCrypto_KEY_NOT_LOADED; return OEMCrypto_ERROR_NO_CONTENT_KEY;
} }
compute_hash_ = false;
content_key->set_ctr_mode(cipher_mode == OEMCrypto_CipherMode_CTR); content_key->set_ctr_mode(cipher_mode == OEMCrypto_CipherMode_CTR);
current_content_key_ = content_key; current_content_key_ = content_key;
const KeyControlBlock& control = current_content_key()->control(); const KeyControlBlock& control = current_content_key()->control();
@@ -1275,6 +1286,29 @@ OEMCryptoResult SessionContext::DecryptCENC(
const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data, const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data,
size_t cipher_data_length, bool is_encrypted, uint8_t* clear_data, size_t cipher_data_length, bool is_encrypted, uint8_t* clear_data,
OEMCryptoBufferType buffer_type) { OEMCryptoBufferType buffer_type) {
OEMCryptoResult result =
ChooseDecrypt(iv, block_offset, pattern, cipher_data, cipher_data_length,
is_encrypted, clear_data, buffer_type);
if (compute_hash_) {
if (current_content_key() == NULL ||
(current_content_key()->control().control_bits() &
wvoec::kControlAllowHashVerification) == 0) {
// This should not happen: this check should already have occured in
// InitializeDecryptHash or the hash should have been discarded in
// SelectContentKey. But it doesn't hurt to double check.
LOGE("[DecryptCENC(): OEMCrypto_ERROR_UNKNOWN_FAILURE]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
current_hash_ = wvcrc32Cont(clear_data, cipher_data_length, current_hash_);
}
return result;
}
OEMCryptoResult SessionContext::ChooseDecrypt(
const uint8_t* iv, size_t block_offset,
const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data,
size_t cipher_data_length, bool is_encrypted, uint8_t* clear_data,
OEMCryptoBufferType buffer_type) {
// If the data is clear, we do not need a current key selected. // If the data is clear, we do not need a current key selected.
if (!is_encrypted) { if (!is_encrypted) {
if (buffer_type != OEMCrypto_BufferType_Direct) { if (buffer_type != OEMCrypto_BufferType_Direct) {
@@ -1492,4 +1526,62 @@ OEMCryptoResult SessionContext::DecryptCTR(const uint8_t* key_u8,
return OEMCrypto_SUCCESS; return OEMCrypto_SUCCESS;
} }
OEMCryptoResult SessionContext::InitializeDecryptHash() {
// Check there is a content key, and it is allowed.
if (current_content_key() == NULL ||
(current_content_key()->control().control_bits() &
wvoec::kControlAllowHashVerification) == 0) {
LOGE("[InitializeDecryptHash(): OEMCrypto_ERROR_UNKNOWN_FAILURE]");
compute_hash_ = false;
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
compute_hash_ = true;
current_hash_ = wvcrc32Init();
return OEMCrypto_SUCCESS;
}
OEMCryptoResult SessionContext::SetDecryptHash(uint32_t frame_number,
const uint8_t* hash,
size_t hash_length) {
// Check there is a content key, and it is allowed.
if (current_content_key() == NULL ||
(current_content_key()->control().control_bits() &
wvoec::kControlAllowHashVerification) == 0) {
LOGE("[SetDecryptHash(): OEMCrypto_ERROR_UNKNOWN_FAILURE]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!compute_hash_) {
// This would happen if somebody computes the hash, and then changes keys.
LOGE("[SetDecryptHash(): OEMCrypto_ERROR_UNKNOWN_FAILURE]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
compute_hash_ = false;
if (hash_length < sizeof(uint32_t)) {
LOGE("[SetDecryptHash(): short buffer]");
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if (hash_length > sizeof(uint32_t)) {
LOGE("[SetDecryptHash(): long buffer]");
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
}
uint32_t given_hash = *reinterpret_cast<const uint32_t*>(hash);
if (current_hash_ != given_hash) {
LOGE("CRC for frame %d is %08x, should be %08x\n", frame_number,
current_hash_, given_hash);
// Update bad_frame_number_ only if this is the first bad frame.
if (hash_error_ == OEMCrypto_SUCCESS) bad_frame_number_ = frame_number;
hash_error_ = OEMCrypto_ERROR_BAD_HASH;
}
// Return success if the hash was compared, even if there was an error.
return OEMCrypto_SUCCESS;
}
OEMCryptoResult SessionContext::GetHashErrorCode(
uint32_t* failed_frame_number) {
if (failed_frame_number == NULL) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
if (hash_error_ != OEMCrypto_SUCCESS)
*failed_frame_number = bad_frame_number_;
return hash_error_;
}
} // namespace wvoec_ref } // namespace wvoec_ref

View File

@@ -73,7 +73,11 @@ class SessionContext {
allowed_schemes_(kSign_RSASSA_PSS), allowed_schemes_(kSign_RSASSA_PSS),
usage_entry_(NULL), usage_entry_(NULL),
srm_requirements_status_(NoSRMVersion), srm_requirements_status_(NoSRMVersion),
usage_entry_status_(kNoUsageEntry) {} usage_entry_status_(kNoUsageEntry),
compute_hash_(false),
current_hash_(0),
bad_frame_number_(0),
hash_error_(OEMCrypto_SUCCESS) {}
virtual ~SessionContext(); virtual ~SessionContext();
bool isValid() { return valid_; } bool isValid() { return valid_; }
@@ -119,13 +123,14 @@ class SessionContext {
uint32_t CurrentTimer(); // (seconds). uint32_t CurrentTimer(); // (seconds).
virtual OEMCryptoResult LoadKeys( virtual OEMCryptoResult LoadKeys(
const uint8_t* message, size_t message_length, const uint8_t* signature, const uint8_t* message, size_t message_length, const uint8_t* signature,
size_t signature_length, const uint8_t* enc_mac_key_iv, size_t signature_length, OEMCrypto_Substring enc_mac_keys_iv,
const uint8_t* enc_mac_keys, size_t num_keys, OEMCrypto_Substring enc_mac_keys, size_t num_keys,
const OEMCrypto_KeyObject* key_array, const uint8_t* pst, const OEMCrypto_KeyObject* key_array, OEMCrypto_Substring pst,
size_t pst_length, const uint8_t* srm_requirement, OEMCrypto_Substring srm_restriction_data,
OEMCrypto_LicenseType license_type); OEMCrypto_LicenseType license_type);
OEMCryptoResult LoadEntitledContentKeys( OEMCryptoResult LoadEntitledContentKeys(
size_t num_keys, const OEMCrypto_EntitledContentKeyObject* key_array); const uint8_t* message, size_t message_length, size_t num_keys,
const OEMCrypto_EntitledContentKeyObject* key_array);
virtual OEMCryptoResult InstallKey(const KeyId& key_id, virtual OEMCryptoResult InstallKey(const KeyId& key_id,
const std::vector<uint8_t>& key_data, const std::vector<uint8_t>& key_data,
const std::vector<uint8_t>& key_data_iv, const std::vector<uint8_t>& key_data_iv,
@@ -147,6 +152,11 @@ class SessionContext {
virtual bool QueryKeyControlBlock(const KeyId& key_id, uint32_t* data); virtual bool QueryKeyControlBlock(const KeyId& key_id, uint32_t* data);
virtual OEMCryptoResult SelectContentKey(const KeyId& key_id, virtual OEMCryptoResult SelectContentKey(const KeyId& key_id,
OEMCryptoCipherMode cipher_mode); OEMCryptoCipherMode cipher_mode);
virtual OEMCryptoResult InitializeDecryptHash();
virtual OEMCryptoResult SetDecryptHash(uint32_t frame_number,
const uint8_t* hash,
size_t hash_length);
virtual OEMCryptoResult GetHashErrorCode(uint32_t* failed_frame_number);
const Key* current_content_key(void) { return current_content_key_; } const Key* current_content_key(void) { return current_content_key_; }
void set_mac_key_server(const std::vector<uint8_t>& mac_key_server) { void set_mac_key_server(const std::vector<uint8_t>& mac_key_server) {
mac_key_server_ = mac_key_server; mac_key_server_ = mac_key_server;
@@ -199,6 +209,12 @@ class SessionContext {
OEMCryptoResult CheckStatusOnline(uint32_t nonce, uint32_t control); OEMCryptoResult CheckStatusOnline(uint32_t nonce, uint32_t control);
// Check that the usage entry status is valid for offline use. // Check that the usage entry status is valid for offline use.
OEMCryptoResult CheckStatusOffline(uint32_t nonce, uint32_t control); OEMCryptoResult CheckStatusOffline(uint32_t nonce, uint32_t control);
OEMCryptoResult ChooseDecrypt(const uint8_t* iv, size_t block_offset,
const OEMCrypto_CENCEncryptPatternDesc* pattern,
const uint8_t* cipher_data,
size_t cipher_data_length, bool is_encrypted,
uint8_t* clear_data,
OEMCryptoBufferType buffer_type);
OEMCryptoResult DecryptCBC(const uint8_t* key, const uint8_t* iv, OEMCryptoResult DecryptCBC(const uint8_t* key, const uint8_t* iv,
const OEMCrypto_CENCEncryptPatternDesc* pattern, const OEMCrypto_CENCEncryptPatternDesc* pattern,
const uint8_t* cipher_data, const uint8_t* cipher_data,
@@ -238,6 +254,13 @@ class SessionContext {
kUsageEntryLoaded, // After loading entry or loading keys. kUsageEntryLoaded, // After loading entry or loading keys.
}; };
UsageEntryStatus usage_entry_status_; UsageEntryStatus usage_entry_status_;
// These are used when doing full decrypt path testing.
bool compute_hash_; // True if the current frame needs a hash.
uint32_t current_hash_; // Running CRC hash of frame.
uint32_t bad_frame_number_; // Frame number with bad hash.
OEMCryptoResult hash_error_; // Error code for first bad frame.
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext); CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext);
}; };

View File

@@ -69,16 +69,17 @@ UsageTableEntry::~UsageTableEntry() { usage_table_->ReleaseEntry(data_.index); }
OEMCryptoResult UsageTableEntry::SetPST(const uint8_t* pst, size_t pst_length) { OEMCryptoResult UsageTableEntry::SetPST(const uint8_t* pst, size_t pst_length) {
if (pst_length > kMaxPSTLength) return OEMCrypto_ERROR_BUFFER_TOO_LARGE; if (pst_length > kMaxPSTLength) return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
data_.pst_length = pst_length; data_.pst_length = pst_length;
if (!pst) return OEMCrypto_ERROR_INVALID_CONTEXT; if (!pst || !pst_length) return OEMCrypto_ERROR_INVALID_CONTEXT;
memcpy(data_.pst, pst, pst_length); memcpy(data_.pst, pst, pst_length);
data_.time_of_license_received = time(NULL); data_.time_of_license_received =
usage_table_->ce_->RollbackCorrectedOfflineTime();
return OEMCrypto_SUCCESS; return OEMCrypto_SUCCESS;
} }
bool UsageTableEntry::VerifyPST(const uint8_t* pst, size_t pst_length) { bool UsageTableEntry::VerifyPST(const uint8_t* pst, size_t pst_length) {
if (pst_length > kMaxPSTLength) return false; if (pst_length > kMaxPSTLength) return false;
if (data_.pst_length != pst_length) return false; if (data_.pst_length != pst_length) return false;
if (!pst) return false; if (!pst || !pst_length) return false;
return 0 == memcmp(pst, data_.pst, pst_length); return 0 == memcmp(pst, data_.pst, pst_length);
} }
@@ -105,7 +106,8 @@ bool UsageTableEntry::CheckForUse() {
recent_decrypt_ = true; recent_decrypt_ = true;
if (data_.status == kUnused) { if (data_.status == kUnused) {
data_.status = kActive; data_.status = kActive;
data_.time_of_first_decrypt = time(NULL); data_.time_of_first_decrypt =
usage_table_->ce_->RollbackCorrectedOfflineTime();
data_.generation_number++; data_.generation_number++;
usage_table_->IncrementGeneration(); usage_table_->IncrementGeneration();
} }
@@ -149,7 +151,7 @@ OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector<uint8_t>& pst,
return OEMCrypto_ERROR_INVALID_CONTEXT; return OEMCrypto_ERROR_INVALID_CONTEXT;
} }
wvcdm::Unpacked_PST_Report pst_report(buffer); wvcdm::Unpacked_PST_Report pst_report(buffer);
int64_t now = time(NULL); int64_t now = usage_table_->ce_->RollbackCorrectedOfflineTime();
pst_report.set_seconds_since_license_received(now - pst_report.set_seconds_since_license_received(now -
data_.time_of_license_received); data_.time_of_license_received);
pst_report.set_seconds_since_first_decrypt(now - data_.time_of_first_decrypt); pst_report.set_seconds_since_first_decrypt(now - data_.time_of_first_decrypt);
@@ -170,7 +172,8 @@ OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector<uint8_t>& pst,
void UsageTableEntry::UpdateAndIncrement() { void UsageTableEntry::UpdateAndIncrement() {
if (recent_decrypt_) { if (recent_decrypt_) {
data_.time_of_last_decrypt = time(NULL); data_.time_of_last_decrypt =
usage_table_->ce_->RollbackCorrectedOfflineTime();
recent_decrypt_ = false; recent_decrypt_ = false;
} }
data_.generation_number++; data_.generation_number++;
@@ -197,6 +200,10 @@ OEMCryptoResult UsageTableEntry::SaveData(CryptoEngine* ce,
// This should be encrypted and signed with a device specific key. // This should be encrypted and signed with a device specific key.
// For the reference implementation, I'm just going to use the keybox key. // For the reference implementation, I'm just going to use the keybox key.
const std::vector<uint8_t>& key = ce->DeviceRootKey(); const std::vector<uint8_t>& key = ce->DeviceRootKey();
if (key.empty()) {
LOGE("SaveUsageEntry: DeviceRootKey is unexpectedly empty.");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Encrypt the entry. // Encrypt the entry.
RAND_bytes(encrypted->iv, wvoec::KEY_IV_SIZE); RAND_bytes(encrypted->iv, wvoec::KEY_IV_SIZE);
@@ -235,6 +242,10 @@ OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index,
// This should be encrypted and signed with a device specific key. // This should be encrypted and signed with a device specific key.
// For the reference implementation, I'm just going to use the keybox key. // For the reference implementation, I'm just going to use the keybox key.
const std::vector<uint8_t>& key = ce->DeviceRootKey(); const std::vector<uint8_t>& key = ce->DeviceRootKey();
if (key.empty()) {
LOGE("LoadUsageEntry: DeviceRootKey is unexpectedly empty.");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Verify the signature of the usage entry. Sign encrypted into clear buffer. // Verify the signature of the usage entry. Sign encrypted into clear buffer.
unsigned int sig_length = SHA256_DIGEST_LENGTH; unsigned int sig_length = SHA256_DIGEST_LENGTH;
@@ -494,6 +505,10 @@ OEMCryptoResult UsageTable::SaveUsageTableHeader(uint8_t* signed_buffer,
// This should be encrypted and signed with a device specific key. // This should be encrypted and signed with a device specific key.
// For the reference implementation, I'm just going to use the keybox key. // For the reference implementation, I'm just going to use the keybox key.
const std::vector<uint8_t>& key = ce_->DeviceRootKey(); const std::vector<uint8_t>& key = ce_->DeviceRootKey();
if (key.empty()) {
LOGE("SaveUsageTableHeader: DeviceRootKey is unexpectedly empty.");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Encrypt the entry. // Encrypt the entry.
RAND_bytes(encrypted->iv, wvoec::KEY_IV_SIZE); RAND_bytes(encrypted->iv, wvoec::KEY_IV_SIZE);
@@ -537,6 +552,10 @@ OEMCryptoResult UsageTable::LoadUsageTableHeader(
// This should be encrypted and signed with a device specific key. // This should be encrypted and signed with a device specific key.
// For the reference implementation, I'm just going to use the keybox key. // For the reference implementation, I'm just going to use the keybox key.
const std::vector<uint8_t>& key = ce_->DeviceRootKey(); const std::vector<uint8_t>& key = ce_->DeviceRootKey();
if (key.empty()) {
LOGE("LoadUsageTableHeader: DeviceRootKey is unexpectedly empty.");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Verify the signature of the usage entry. Sign encrypted into clear buffer. // Verify the signature of the usage entry. Sign encrypted into clear buffer.
unsigned int sig_length = SHA256_DIGEST_LENGTH; unsigned int sig_length = SHA256_DIGEST_LENGTH;
@@ -741,7 +760,7 @@ OEMCryptoResult UsageTable::CreateOldUsageEntry(
std::vector<uint8_t> pstv(pst, pst + pst_length); std::vector<uint8_t> pstv(pst, pst + pst_length);
OldUsageTableEntry* old_entry = old_table_->CreateEntry(pstv); OldUsageTableEntry* old_entry = old_table_->CreateEntry(pstv);
int64_t now = time(NULL); int64_t now = ce_->RollbackCorrectedOfflineTime();
old_entry->time_of_license_received_ = now - time_since_license_received; old_entry->time_of_license_received_ = now - time_since_license_received;
old_entry->time_of_first_decrypt_ = now - time_since_first_decrypt; old_entry->time_of_first_decrypt_ = now - time_since_first_decrypt;
old_entry->time_of_last_decrypt_ = now - time_since_last_decrypt; old_entry->time_of_last_decrypt_ = now - time_since_last_decrypt;

View File

@@ -129,6 +129,8 @@ class UsageTable {
std::vector<int64_t> generation_numbers_; std::vector<int64_t> generation_numbers_;
std::vector<SessionContext*> sessions_; std::vector<SessionContext*> sessions_;
OldUsageTable* old_table_; OldUsageTable* old_table_;
friend class UsageTableEntry;
}; };
} // namespace wvoec_ref } // namespace wvoec_ref

View File

@@ -91,6 +91,14 @@ uint32_t wvcrc32(const uint8_t* p_begin, int i_count) {
return(wvrunningcrc32(p_begin, i_count, INIT_CRC32)); return(wvrunningcrc32(p_begin, i_count, INIT_CRC32));
} }
uint32_t wvcrc32Init() {
return INIT_CRC32;
}
uint32_t wvcrc32Cont(const uint8_t* p_begin, int i_count, uint32_t prev_crc) {
return(wvrunningcrc32(p_begin, i_count, prev_crc));
}
uint32_t wvcrc32n(const uint8_t* p_begin, int i_count) { uint32_t wvcrc32n(const uint8_t* p_begin, int i_count) {
return htonl(wvrunningcrc32(p_begin, i_count, INIT_CRC32)); return htonl(wvrunningcrc32(p_begin, i_count, INIT_CRC32));
} }

View File

@@ -10,6 +10,8 @@
#include <stdint.h> #include <stdint.h>
uint32_t wvcrc32(const uint8_t* p_begin, int i_count); uint32_t wvcrc32(const uint8_t* p_begin, int i_count);
uint32_t wvcrc32Init();
uint32_t wvcrc32Cont(const uint8_t* p_begin, int i_count, uint32_t prev_crc);
// Convert to network byte order // Convert to network byte order
uint32_t wvcrc32n(const uint8_t* p_begin, int i_count); uint32_t wvcrc32n(const uint8_t* p_begin, int i_count);

View File

@@ -29,6 +29,7 @@ void DeviceFeatures::Initialize(bool is_cast_receiver,
supports_rsa_3072 = false; supports_rsa_3072 = false;
api_version = 0; api_version = 0;
derive_key_method = NO_METHOD; derive_key_method = NO_METHOD;
OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox));
if (OEMCrypto_SUCCESS != OEMCrypto_Initialize()) { if (OEMCrypto_SUCCESS != OEMCrypto_Initialize()) {
printf("OEMCrypto_Initialize failed. All tests will fail.\n"); printf("OEMCrypto_Initialize failed. All tests will fail.\n");
return; return;
@@ -94,6 +95,19 @@ void DeviceFeatures::Initialize(bool is_cast_receiver,
} }
} }
printf("cast_receiver = %s.\n", cast_receiver ? "true" : "false"); printf("cast_receiver = %s.\n", cast_receiver ? "true" : "false");
resource_rating = OEMCrypto_ResourceRatingTier();
printf("resource_rating = %d, security leve %s.\n", resource_rating,
OEMCrypto_SecurityLevel());
uint32_t decrypt_hash_type = OEMCrypto_SupportsDecryptHash();
supports_crc = (decrypt_hash_type == OEMCrypto_CRC_Clear_Buffer);
if (supports_crc) {
printf("Decrypt hashes will be tested.\n");
} else {
printf("Decrypt hashes will not be tested -- %s.\n",
decrypt_hash_type == OEMCrypto_Hash_Not_Supported
? "not supported"
: "partner defined hash");
}
switch (derive_key_method) { switch (derive_key_method) {
case NO_METHOD: case NO_METHOD:
printf("NO_METHOD: Cannot derive known session keys.\n"); printf("NO_METHOD: Cannot derive known session keys.\n");
@@ -110,9 +124,6 @@ void DeviceFeatures::Initialize(bool is_cast_receiver,
case LOAD_TEST_RSA_KEY: case LOAD_TEST_RSA_KEY:
printf("LOAD_TEST_RSA_KEY: Call LoadTestRSAKey before deriving keys.\n"); printf("LOAD_TEST_RSA_KEY: Call LoadTestRSAKey before deriving keys.\n");
break; break;
case EXISTING_TEST_KEYBOX:
printf("EXISTING_TEST_KEYBOX: Keybox is already the test keybox.\n");
break;
case FORCE_TEST_KEYBOX: case FORCE_TEST_KEYBOX:
printf("FORCE_TEST_KEYBOX: User requested calling InstallKeybox.\n"); printf("FORCE_TEST_KEYBOX: User requested calling InstallKeybox.\n");
break; break;
@@ -120,6 +131,11 @@ void DeviceFeatures::Initialize(bool is_cast_receiver,
printf("TEST_PROVISION_30: Device provisioed with OEM Cert.\n"); printf("TEST_PROVISION_30: Device provisioed with OEM Cert.\n");
break; break;
} }
std::string security_level = OEMCrypto_SecurityLevel();
supports_level_1 = (security_level == "L1");
printf("SecurityLevel is %s (%s)",
supports_level_1 ? "Level 1" : "Not Level 1",
security_level.c_str());
OEMCrypto_Terminate(); OEMCrypto_Terminate();
} }
@@ -183,32 +199,12 @@ void DeviceFeatures::PickDerivedKey() {
// If device uses a keybox, try to load the test keybox. // If device uses a keybox, try to load the test keybox.
if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestKeybox(NULL, 0)) { if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestKeybox(NULL, 0)) {
derive_key_method = LOAD_TEST_KEYBOX; derive_key_method = LOAD_TEST_KEYBOX;
} else if (IsTestKeyboxInstalled()) {
derive_key_method = EXISTING_TEST_KEYBOX;
} }
} else if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) { } else if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) {
derive_key_method = LOAD_TEST_RSA_KEY; derive_key_method = LOAD_TEST_RSA_KEY;
} }
} }
bool DeviceFeatures::IsTestKeyboxInstalled() {
uint8_t key_data[256];
size_t key_data_len = sizeof(key_data);
if (OEMCrypto_GetKeyData(key_data, &key_data_len) != OEMCrypto_SUCCESS)
return false;
if (key_data_len != sizeof(kValidKeybox01.data_)) return false;
if (memcmp(key_data, kValidKeybox01.data_, key_data_len)) return false;
uint8_t dev_id[128] = {0};
size_t dev_id_len = 128;
if (OEMCrypto_GetDeviceID(dev_id, &dev_id_len) != OEMCrypto_SUCCESS)
return false;
// We use strncmp instead of memcmp because we don't really care about the
// multiple '\0' characters at the end of the device id.
return 0 == strncmp(reinterpret_cast<const char*>(dev_id),
reinterpret_cast<const char*>(kValidKeybox01.device_id_),
sizeof(kValidKeybox01.device_id_));
}
void DeviceFeatures::FilterOut(std::string* current_filter, void DeviceFeatures::FilterOut(std::string* current_filter,
const std::string& new_filter) { const std::string& new_filter) {
if (current_filter->find('-') == std::string::npos) { if (current_filter->find('-') == std::string::npos) {

View File

@@ -14,7 +14,6 @@ class DeviceFeatures {
NO_METHOD, // Cannot derive known session keys. NO_METHOD, // Cannot derive known session keys.
LOAD_TEST_KEYBOX, // Call LoadTestKeybox before deriving keys. LOAD_TEST_KEYBOX, // Call LoadTestKeybox before deriving keys.
LOAD_TEST_RSA_KEY, // Call LoadTestRSAKey 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. FORCE_TEST_KEYBOX, // User requested calling InstallKeybox.
TEST_PROVISION_30, // Device has OEM Certificate installed. TEST_PROVISION_30, // Device has OEM Certificate installed.
}; };
@@ -27,6 +26,9 @@ class DeviceFeatures {
bool cast_receiver; // Device supports alternate rsa signature padding. bool cast_receiver; // Device supports alternate rsa signature padding.
bool usage_table; // Device saves usage information. bool usage_table; // Device saves usage information.
bool supports_rsa_3072; // Device supports 3072 bit RSA keys. bool supports_rsa_3072; // Device supports 3072 bit RSA keys.
bool supports_level_1; // Device supports Level 1 security.
uint32_t resource_rating; // Device's resource rating tier.
bool supports_crc; // Supported decrypt hash type CRC.
uint32_t api_version; uint32_t api_version;
OEMCrypto_ProvisioningMethod provisioning_method; OEMCrypto_ProvisioningMethod provisioning_method;

View File

@@ -23,6 +23,7 @@
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <string> #include <string>
#include <sstream>
#include <vector> #include <vector>
#include "OEMCryptoCENC.h" #include "OEMCryptoCENC.h"
@@ -96,6 +97,26 @@ class boringssl_ptr {
CORE_DISALLOW_COPY_AND_ASSIGN(boringssl_ptr); CORE_DISALLOW_COPY_AND_ASSIGN(boringssl_ptr);
}; };
OEMCrypto_Substring GetSubstring(const std::string& message,
const std::string& field, bool set_zero) {
OEMCrypto_Substring substring;
if (set_zero || field.empty() || message.empty()) {
substring.offset = 0;
substring.length = 0;
} else {
size_t pos = message.find(field);
if (pos == std::string::npos) {
LOGW("GetSubstring : Cannot find offset for %s", field.c_str());
substring.offset = 0;
substring.length = 0;
} else {
substring.offset = pos;
substring.length = field.length();
}
}
return substring;
}
Session::Session() Session::Session()
: open_(false), : open_(false),
forced_session_id_(false), forced_session_id_(false),
@@ -253,129 +274,149 @@ void Session::GenerateDerivedKeysFromSessionKey() {
DeriveKeys(&session_key[0], mac_context, enc_context); DeriveKeys(&session_key[0], mac_context, enc_context);
} }
void Session::LoadTestKeys(const std::string& pst, bool new_mac_keys) { void Session::LoadTestKeys(const std::string& provider_session_token,
uint8_t* pst_ptr = NULL; bool new_mac_keys) {
if (pst.length() > 0) { std::string message =
pst_ptr = encrypted_license().pst; wvcdm::BytesToString(message_ptr(), sizeof(MessageData));
} OEMCrypto_Substring pst = GetSubstring(message, provider_session_token);
OEMCrypto_Substring enc_mac_keys_iv = GetSubstring(
message, wvcdm::BytesToString(encrypted_license().mac_key_iv,
sizeof(encrypted_license().mac_key_iv)));
OEMCrypto_Substring enc_mac_keys = GetSubstring(
message, wvcdm::BytesToString(encrypted_license().mac_keys,
sizeof(encrypted_license().mac_keys)));
if (new_mac_keys) { if (new_mac_keys) {
ASSERT_EQ(OEMCrypto_SUCCESS, ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_, OEMCrypto_LoadKeys(
&signature_[0], signature_.size(), session_id(), message_ptr(), message_size_, &signature_[0],
encrypted_license().mac_key_iv, signature_.size(), enc_mac_keys_iv, enc_mac_keys, num_keys_,
encrypted_license().mac_keys, num_keys_, key_array_, pst, GetSubstring(), OEMCrypto_ContentLicense));
key_array_, pst_ptr, pst.length(), NULL,
OEMCrypto_ContentLicense));
// Update new generated keys. // Update new generated keys.
memcpy(&mac_key_server_[0], license_.mac_keys, MAC_KEY_SIZE); memcpy(&mac_key_server_[0], license_.mac_keys, MAC_KEY_SIZE);
memcpy(&mac_key_client_[0], license_.mac_keys + MAC_KEY_SIZE, memcpy(&mac_key_client_[0], license_.mac_keys + MAC_KEY_SIZE, MAC_KEY_SIZE);
MAC_KEY_SIZE);
} else { } else {
ASSERT_EQ( ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_SUCCESS, OEMCrypto_LoadKeys(
OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_, session_id(), message_ptr(), message_size_, &signature_[0],
&signature_[0], signature_.size(), NULL, NULL, signature_.size(), GetSubstring(), GetSubstring(), num_keys_,
num_keys_, key_array_, pst_ptr, pst.length(), NULL, key_array_, pst, GetSubstring(), OEMCrypto_ContentLicense));
OEMCrypto_ContentLicense));
} }
VerifyTestKeys(); VerifyTestKeys();
} }
void Session::LoadEnitlementTestKeys(const std::string& pst, void Session::LoadEntitlementTestKeys(const std::string& provider_session_token,
bool new_mac_keys, bool new_mac_keys,
OEMCryptoResult expected_sts) { OEMCryptoResult expected_sts) {
uint8_t* pst_ptr = NULL; std::string message =
if (pst.length() > 0) { wvcdm::BytesToString(message_ptr(), sizeof(MessageData));
pst_ptr = encrypted_license().pst; OEMCrypto_Substring pst = GetSubstring(message, provider_session_token);
} OEMCrypto_Substring enc_mac_keys_iv = GetSubstring(
message, wvcdm::BytesToString(encrypted_license().mac_key_iv,
sizeof(encrypted_license().mac_key_iv)));
OEMCrypto_Substring enc_mac_keys = GetSubstring(
message, wvcdm::BytesToString(encrypted_license().mac_keys,
sizeof(encrypted_license().mac_keys)));
if (new_mac_keys) { if (new_mac_keys) {
ASSERT_EQ(expected_sts, ASSERT_EQ(
OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_, expected_sts,
&signature_[0], signature_.size(), OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_,
encrypted_license().mac_key_iv, &signature_[0], signature_.size(), enc_mac_keys_iv,
encrypted_license().mac_keys, num_keys_, enc_mac_keys, num_keys_, key_array_, pst,
key_array_, pst_ptr, pst.length(), NULL, GetSubstring(), OEMCrypto_EntitlementLicense));
OEMCrypto_EntitlementLicense));
// Update new generated keys. // Update new generated keys.
memcpy(&mac_key_server_[0], license_.mac_keys, MAC_KEY_SIZE); memcpy(&mac_key_server_[0], license_.mac_keys, MAC_KEY_SIZE);
memcpy(&mac_key_client_[0], license_.mac_keys + MAC_KEY_SIZE, memcpy(&mac_key_client_[0], license_.mac_keys + MAC_KEY_SIZE, MAC_KEY_SIZE);
MAC_KEY_SIZE);
} else { } else {
ASSERT_EQ( ASSERT_EQ(
expected_sts, expected_sts,
OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_, OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_,
&signature_[0], signature_.size(), NULL, NULL, &signature_[0], signature_.size(), GetSubstring(),
num_keys_, key_array_, pst_ptr, pst.length(), NULL, GetSubstring(), num_keys_, key_array_, pst,
OEMCrypto_EntitlementLicense)); GetSubstring(), OEMCrypto_EntitlementLicense));
} }
} }
void Session::FillEntitledKeyArray() { void Session::FillEntitledKeyArray() {
int offset = 0;
entitled_message_.clear();
for (size_t i = 0; i < num_keys_; ++i) { for (size_t i = 0; i < num_keys_; ++i) {
EntitledContentKeyData* key_data = &entitled_key_data_[i]; EntitledContentKeyData* key_data = &entitled_key_data_[i];
entitled_key_array_[i].entitlement_key_id = key_array_[i].key_id; entitled_key_array_[i].entitlement_key_id.offset = offset;
entitled_key_array_[i].entitlement_key_id_length = entitled_key_array_[i].entitlement_key_id.length =
key_array_[i].key_id_length; key_array_[i].key_id.length;
offset += key_array_[i].key_id.length;
entitled_message_ +=
wvcdm::BytesToString(message_ptr() + key_array_[i].key_id.offset,
key_array_[i].key_id.length);
EXPECT_EQ( EXPECT_EQ(1, GetRandBytes(key_data->content_key_id,
1, GetRandBytes(key_data->content_key_id, sizeof(key_data->content_key_id)));
sizeof(key_data->content_key_id))); entitled_key_array_[i].content_key_id.offset = offset;
entitled_key_array_[i].content_key_id = key_data->content_key_id; entitled_key_array_[i].content_key_id.length =
entitled_key_array_[i].content_key_id_length =
sizeof(key_data->content_key_id); sizeof(key_data->content_key_id);
offset += sizeof(key_data->content_key_id);
entitled_message_ += wvcdm::BytesToString(key_data->content_key_id,
sizeof(key_data->content_key_id));
EXPECT_EQ( EXPECT_EQ(1, GetRandBytes(key_data->content_key_data,
1, GetRandBytes(key_data->content_key_data, sizeof(key_data->content_key_data)));
sizeof(key_data->content_key_data))); entitled_key_array_[i].content_key_data.offset = offset;
entitled_key_array_[i].content_key_data = key_data->content_key_data; entitled_key_array_[i].content_key_data.length =
entitled_key_array_[i].content_key_data_length =
sizeof(key_data->content_key_data); sizeof(key_data->content_key_data);
offset += sizeof(key_data->content_key_data);
entitled_message_ += wvcdm::BytesToString(
key_data->content_key_data, sizeof(key_data->content_key_data));
EXPECT_EQ( EXPECT_EQ(1, GetRandBytes(key_data[i].content_key_data_iv,
1, GetRandBytes(entitled_key_data_[i].content_key_data_iv, sizeof(key_data[i].content_key_data_iv)));
sizeof(entitled_key_data_[i].content_key_data_iv))); entitled_key_array_[i].content_key_data_iv.offset = offset;
entitled_key_array_[i].content_key_data_iv = key_data->content_key_data_iv; entitled_key_array_[i].content_key_data_iv.length =
sizeof(key_data->content_key_data_iv);
offset += sizeof(key_data->content_key_data_iv);
entitled_message_ += wvcdm::BytesToString(
key_data->content_key_data_iv, sizeof(key_data->content_key_data_iv));
} }
} }
void Session::LoadEntitledContentKeys(OEMCryptoResult expected_sts) { void Session::LoadEntitledContentKeys(OEMCryptoResult expected_sts) {
// Create a copy of the stored |entitled_key_array_|. encrypted_entitled_message_ = entitled_message_;
std::vector<OEMCrypto_EntitledContentKeyObject> encrypted_entitled_key_array; std::vector<OEMCrypto_EntitledContentKeyObject> encrypted_entitled_key_array;
encrypted_entitled_key_array.resize(num_keys_); encrypted_entitled_key_array.resize(num_keys_);
memcpy(&encrypted_entitled_key_array[0], &entitled_key_array_[0], memcpy(&encrypted_entitled_key_array[0], &entitled_key_array_[0],
sizeof(OEMCrypto_EntitledContentKeyObject) * num_keys_); sizeof(OEMCrypto_EntitledContentKeyObject) * num_keys_);
// Create a encrypted version of all of the content keys stored in
// |entitled_key_array_|.
std::vector<std::vector<uint8_t> > encrypted_content_keys;
encrypted_content_keys.resize(num_keys_);
for (size_t i = 0; i < num_keys_; ++i) { for (size_t i = 0; i < num_keys_; ++i) {
// Load the entitlement key from |key_array_|. // Load the entitlement key from |key_array_|.
AES_KEY aes_key; AES_KEY aes_key;
AES_set_encrypt_key(&key_array_[i].key_data[0], 256, &aes_key); AES_set_encrypt_key(message_ptr() + key_array_[i].key_data.offset, 256,
encrypted_content_keys[i].resize( &aes_key);
encrypted_entitled_key_array[i].content_key_data_length);
// Encrypt the content key with the entitlement key. // Encrypt the content key with the entitlement key.
uint8_t iv[16]; uint8_t iv[16];
memcpy(&iv[0], &encrypted_entitled_key_array[i].content_key_data[0], 16); const uint8_t* content_key_data = reinterpret_cast<const uint8_t*>(
AES_cbc_encrypt( entitled_message_.data() +
&entitled_key_array_[i].content_key_data[0], entitled_key_array_[i].content_key_data.offset);
const_cast<uint8_t*>( const uint8_t* encrypted_content_key_data =
&encrypted_entitled_key_array[i].content_key_data[0]), reinterpret_cast<const uint8_t*>(
encrypted_entitled_key_array[i].content_key_data_length, encrypted_entitled_message_.data() +
&aes_key, iv, AES_ENCRYPT); encrypted_entitled_key_array[i].content_key_data.offset);
memcpy(&iv[0],
// Set the |encrypted_entitled_key_array| to point to the encrypted copy message_ptr() +
// of the content key. encrypted_entitled_key_array[i].content_key_data_iv.offset,
encrypted_entitled_key_array[i].content_key_data = 16);
encrypted_content_keys[i].data(); AES_cbc_encrypt(content_key_data,
const_cast<uint8_t*>(encrypted_content_key_data),
encrypted_entitled_key_array[i].content_key_data.length,
&aes_key, iv, AES_ENCRYPT);
} }
ASSERT_EQ(expected_sts, ASSERT_EQ(
OEMCrypto_LoadEntitledContentKeys( expected_sts,
session_id(), num_keys_, &encrypted_entitled_key_array[0])); OEMCrypto_LoadEntitledContentKeys(
session_id(),
reinterpret_cast<const uint8_t*>(encrypted_entitled_message_.data()),
encrypted_entitled_message_.size(), num_keys_,
&encrypted_entitled_key_array[0]));
if (expected_sts != OEMCrypto_SUCCESS) { if (expected_sts != OEMCrypto_SUCCESS) {
return; return;
} }
@@ -408,9 +449,12 @@ void Session::VerifyEntitlementTestKeys() {
for (unsigned int i = 0; i < num_keys_; i++) { for (unsigned int i = 0; i < num_keys_; i++) {
KeyControlBlock block; KeyControlBlock block;
size_t size = sizeof(block); size_t size = sizeof(block);
const uint8_t* content_key_id =
reinterpret_cast<const uint8_t*>(entitled_message_.data());
OEMCryptoResult sts = OEMCrypto_QueryKeyControl( OEMCryptoResult sts = OEMCrypto_QueryKeyControl(
session_id(), entitled_key_array_[i].content_key_id, session_id(),
entitled_key_array_[i].content_key_id_length, content_key_id + entitled_key_array_[i].content_key_id.offset,
entitled_key_array_[i].content_key_id.length,
reinterpret_cast<uint8_t*>(&block), &size); reinterpret_cast<uint8_t*>(&block), &size);
if (sts != OEMCrypto_ERROR_NOT_IMPLEMENTED) { if (sts != OEMCrypto_ERROR_NOT_IMPLEMENTED) {
ASSERT_EQ(OEMCrypto_SUCCESS, sts); ASSERT_EQ(OEMCrypto_SUCCESS, sts);
@@ -482,15 +526,12 @@ void Session::FillSimpleMessage(uint32_t duration, uint32_t control,
sizeof(license_.keys[i].key_iv))); sizeof(license_.keys[i].key_iv)));
EXPECT_EQ(1, GetRandBytes(license_.keys[i].control_iv, EXPECT_EQ(1, GetRandBytes(license_.keys[i].control_iv,
sizeof(license_.keys[i].control_iv))); sizeof(license_.keys[i].control_iv)));
if (global_features.api_version == 14) { if (global_features.api_version >= 12) {
// For version 14, we require OEMCrypto to handle kc14 for all licenses. // For version 12 and above, we require OEMCrypto to handle kcNN for all
memcpy(license_.keys[i].control.verification, "kc14", 4); // licenses.
} else if (global_features.api_version == 13) { std::stringstream stream;
// For version 13, we require OEMCrypto to handle kc13 for all licenses. stream << "kc" << global_features.api_version;
memcpy(license_.keys[i].control.verification, "kc13", 4); memcpy(license_.keys[i].control.verification, stream.str().c_str(), 4);
} else if (global_features.api_version == 12) {
// For version 12, we require OEMCrypto to handle kc12 for all licenses.
memcpy(license_.keys[i].control.verification, "kc12", 4);
} else if (control & wvoec::kControlSecurityPatchLevelMask) { } else if (control & wvoec::kControlSecurityPatchLevelMask) {
// For versions before 12, we require the special key control block only // For versions before 12, we require the special key control block only
// when there are newer features present. // when there are newer features present.
@@ -529,15 +570,12 @@ void Session::FillSimpleEntitlementMessage(
sizeof(license_.keys[i].key_iv))); sizeof(license_.keys[i].key_iv)));
EXPECT_EQ(1, GetRandBytes(license_.keys[i].control_iv, EXPECT_EQ(1, GetRandBytes(license_.keys[i].control_iv,
sizeof(license_.keys[i].control_iv))); sizeof(license_.keys[i].control_iv)));
if (global_features.api_version == 14) { if (global_features.api_version >= 12) {
// For version 13, we require OEMCrypto to handle kc14 for all licenses. // For version 12 and above, we require OEMCrypto to handle kcNN for all
memcpy(license_.keys[i].control.verification, "kc14", 4); // licenses.
} else if (global_features.api_version == 13) { std::stringstream stream;
// For version 13, we require OEMCrypto to handle kc13 for all licenses. stream << "kc" << global_features.api_version;
memcpy(license_.keys[i].control.verification, "kc13", 4); memcpy(license_.keys[i].control.verification, stream.str().c_str(), 4);
} else if (global_features.api_version == 12) {
// For version 12, we require OEMCrypto to handle kc12 for all licenses.
memcpy(license_.keys[i].control.verification, "kc12", 4);
} else if (control & wvoec::kControlSecurityPatchLevelMask) { } else if (control & wvoec::kControlSecurityPatchLevelMask) {
// For versions before 12, we require the special key control block only // For versions before 12, we require the special key control block only
// when there are newer features present. // when there are newer features present.
@@ -565,15 +603,13 @@ void Session::FillRefreshMessage(size_t key_count, uint32_t control_bits,
encrypted_license().keys[i].key_id_length = license_.keys[i].key_id_length; encrypted_license().keys[i].key_id_length = license_.keys[i].key_id_length;
memcpy(encrypted_license().keys[i].key_id, license_.keys[i].key_id, memcpy(encrypted_license().keys[i].key_id, license_.keys[i].key_id,
encrypted_license().keys[i].key_id_length); encrypted_license().keys[i].key_id_length);
if (global_features.api_version == 14) { if (global_features.api_version >= 12) {
// For version 14, we require OEMCrypto to handle kc14 for all licenses. // For version 12 and above, we require OEMCrypto to handle kcNN for all
memcpy(encrypted_license().keys[i].control.verification, "kc14", 4); // licenses.
} else if (global_features.api_version == 13) { std::stringstream stream;
// For version 13, we require OEMCrypto to handle kc13 for all licenses. stream << "kc" << global_features.api_version;
memcpy(encrypted_license().keys[i].control.verification, "kc13", 4); memcpy(encrypted_license().keys[i].control.verification,
} else if (global_features.api_version == 12) { stream.str().c_str(), 4);
// For version 12, we require OEMCrypto to handle kc12 for all licenses.
memcpy(encrypted_license().keys[i].control.verification, "kc12", 4);
} else { } else {
// For versions before 12, we require the special key control block only // For versions before 12, we require the special key control block only
// when there are newer features present. // when there are newer features present.
@@ -585,6 +621,27 @@ void Session::FillRefreshMessage(size_t key_count, uint32_t control_bits,
} }
} }
void Session::SetLoadKeysSubstringParams() {
load_keys_params_.resize(4);
std::string message =
wvcdm::BytesToString(message_ptr(), sizeof(MessageData));
OEMCrypto_Substring* enc_mac_keys_iv = &load_keys_params_[0];
*enc_mac_keys_iv = GetSubstring(
message, wvcdm::BytesToString(encrypted_license().mac_key_iv,
sizeof(encrypted_license().mac_key_iv)));
OEMCrypto_Substring* enc_mac_keys = &load_keys_params_[1];
*enc_mac_keys = GetSubstring(
message, wvcdm::BytesToString(encrypted_license().mac_keys,
sizeof(encrypted_license().mac_keys)));
OEMCrypto_Substring* pst = &load_keys_params_[2];
size_t pst_length =
strlen(reinterpret_cast<const char*>(encrypted_license().pst));
*pst = GetSubstring(
message, wvcdm::BytesToString(encrypted_license().pst, pst_length));
OEMCrypto_Substring* srm_req = &load_keys_params_[3];
*srm_req = GetSubstring();
}
void Session::EncryptAndSign() { void Session::EncryptAndSign() {
encrypted_license() = license_; encrypted_license() = license_;
@@ -613,6 +670,7 @@ void Session::EncryptAndSign() {
ServerSignBuffer(reinterpret_cast<const uint8_t*>(&padded_message_), ServerSignBuffer(reinterpret_cast<const uint8_t*>(&padded_message_),
message_size_, &signature_); message_size_, &signature_);
FillKeyArray(encrypted_license(), key_array_); FillKeyArray(encrypted_license(), key_array_);
SetLoadKeysSubstringParams();
} }
void Session::EncryptProvisioningMessage( void Session::EncryptProvisioningMessage(
@@ -671,31 +729,45 @@ void Session::VerifyClientSignature(size_t data_length) {
void Session::FillKeyArray(const MessageData& data, void Session::FillKeyArray(const MessageData& data,
OEMCrypto_KeyObject* key_array) { OEMCrypto_KeyObject* key_array) {
const uint8_t* data_ptr = reinterpret_cast<const uint8_t*>(&data);
std::string message = wvcdm::BytesToString(data_ptr, sizeof(MessageData));
for (unsigned int i = 0; i < num_keys_; i++) { for (unsigned int i = 0; i < num_keys_; i++) {
key_array[i].key_id = data.keys[i].key_id; key_array[i].key_id = GetSubstring(
key_array[i].key_id_length = data.keys[i].key_id_length; message,
key_array[i].key_data_iv = data.keys[i].key_iv; wvcdm::BytesToString(data.keys[i].key_id, data.keys[i].key_id_length));
key_array[i].key_data = data.keys[i].key_data; key_array[i].key_data_iv = GetSubstring(
key_array[i].key_data_length = data.keys[i].key_data_length; message,
key_array[i].key_control_iv = data.keys[i].control_iv; wvcdm::BytesToString(data.keys[i].key_iv, sizeof(data.keys[i].key_iv)));
key_array[i].key_control = key_array[i].key_data = GetSubstring(
message, wvcdm::BytesToString(data.keys[i].key_data,
data.keys[i].key_data_length));
key_array[i].key_control_iv = GetSubstring(
message, wvcdm::BytesToString(data.keys[i].control_iv,
sizeof(data.keys[i].control_iv)));
const uint8_t* key_control_ptr =
reinterpret_cast<const uint8_t*>(&data.keys[i].control); reinterpret_cast<const uint8_t*>(&data.keys[i].control);
key_array[i].key_control = GetSubstring(
message,
wvcdm::BytesToString(key_control_ptr, sizeof(data.keys[i].control)));
} }
} }
void Session::FillRefreshArray(OEMCrypto_KeyRefreshObject* key_array, void Session::FillRefreshArray(OEMCrypto_KeyRefreshObject* key_array,
size_t key_count) { size_t key_count) {
std::string message =
wvcdm::BytesToString(message_ptr(), sizeof(MessageData));
for (size_t i = 0; i < key_count; i++) { for (size_t i = 0; i < key_count; i++) {
if (key_count > 1) { key_array[i].key_id = GetSubstring(
key_array[i].key_id = encrypted_license().keys[i].key_id; message,
key_array[i].key_id_length = encrypted_license().keys[i].key_id_length; wvcdm::BytesToString(encrypted_license().keys[i].key_id,
} else { sizeof(encrypted_license().keys[i].key_id)),
key_array[i].key_id = NULL; key_count <= 1);
key_array[i].key_id_length = 0; key_array[i].key_control_iv = GetSubstring();
} key_array[i].key_control = GetSubstring(
key_array[i].key_control_iv = NULL; message,
key_array[i].key_control = wvcdm::BytesToString(reinterpret_cast<const uint8_t*>(
reinterpret_cast<const uint8_t*>(&encrypted_license().keys[i].control); &encrypted_license().keys[i].control),
sizeof(encrypted_license().keys[i].control)));
} }
} }
@@ -1297,4 +1369,8 @@ void Session::set_message_size(size_t size) {
ASSERT_LE(message_size_, kMaxMessageSize); ASSERT_LE(message_size_, kMaxMessageSize);
} }
const uint8_t* Session::encrypted_entitled_message_ptr() {
return reinterpret_cast<const uint8_t*>(encrypted_entitled_message_.data());
}
} // namespace wvoec } // namespace wvoec

View File

@@ -27,6 +27,7 @@ void PrintTo(const vector<uint8_t>& value, ostream* os);
namespace wvoec { namespace wvoec {
// Make sure this is larger than kMaxKeysPerSession, in oemcrypto_test.cpp
const size_t kMaxNumKeys = 20; const size_t kMaxNumKeys = 20;
namespace { namespace {
@@ -61,7 +62,6 @@ const int kDefaultKeyIdLength = 16;
const size_t kMaxTestRSAKeyLength = 2000; // Rough estimate. const size_t kMaxTestRSAKeyLength = 2000; // Rough estimate.
const size_t kMaxPSTLength = 255; // In specification. const size_t kMaxPSTLength = 255; // In specification.
const size_t kMaxMessageSize = 8 * 1024; // In specification. const size_t kMaxMessageSize = 8 * 1024; // In specification.
const size_t kMaxDecryptSize = 100 * 1024; // In specification.
typedef struct { typedef struct {
uint8_t key_id[kTestKeyIdMaxLength]; uint8_t key_id[kTestKeyIdMaxLength];
@@ -125,6 +125,13 @@ uint32_t htonl_fnc(uint32_t x);
// Prints error string from BoringSSL // Prints error string from BoringSSL
void dump_boringssl_error(); void dump_boringssl_error();
// Given a message and field, returns an OEMCrypto_Substring with the field's
// offset into the message and its length. If |set_zero| is true, both the
// offset and length will be zero.
OEMCrypto_Substring GetSubstring(const std::string& message = "",
const std::string& field = "",
bool set_zero = false);
class Session { class Session {
public: public:
Session(); Session();
@@ -165,12 +172,12 @@ class Session {
// using OEMCrypto_LoadKeys. This message should have already been created // using OEMCrypto_LoadKeys. This message should have already been created
// by FillSimpleEntitlementMessage, modified if needed, and then encrypted // by FillSimpleEntitlementMessage, modified if needed, and then encrypted
// and signed by the server's mac key in EncryptAndSign. // and signed by the server's mac key in EncryptAndSign.
void LoadEnitlementTestKeys(const std::string& pst = "", void LoadEntitlementTestKeys(const std::string& pst = "",
bool new_mac_keys = true, bool new_mac_keys = true,
OEMCryptoResult expected_sts = OEMCrypto_SUCCESS); OEMCryptoResult expected_sts = OEMCrypto_SUCCESS);
// Fills an OEMCrypto_EntitledContentKeyObject using the information from // Fills an OEMCrypto_EntitledContentKeyObject using the information from
// the license_ and randomly generated content keys. This method should be // the license_ and randomly generated content keys. This method should be
// called after LoadEnitlementTestKeys. // called after LoadEntitlementTestKeys.
void FillEntitledKeyArray(); void FillEntitledKeyArray();
// Encrypts and loads the entitled content keys via // Encrypts and loads the entitled content keys via
// OEMCrypto_LoadEntitledContentKeys. // OEMCrypto_LoadEntitledContentKeys.
@@ -196,7 +203,7 @@ class Session {
const std::string& pst = ""); const std::string& pst = "");
// This fills the data structure license_ with entitlement key information. // This fills the data structure license_ with entitlement key information.
// This data can be modified, and then should be encrypted and signed in // This data can be modified, and then should be encrypted and signed in
// EncryptAndSign before being loaded in LoadEnitlementTestKeys. // EncryptAndSign before being loaded in LoadEntitlementTestKeys.
void FillSimpleEntitlementMessage( void FillSimpleEntitlementMessage(
uint32_t duration, uint32_t control, uint32_t duration, uint32_t control,
uint32_t nonce, const std::string& pst = ""); uint32_t nonce, const std::string& pst = "");
@@ -205,6 +212,11 @@ class Session {
// is just signed. The signature is computed in RefreshTestKeys, above. // is just signed. The signature is computed in RefreshTestKeys, above.
void FillRefreshMessage(size_t key_count, uint32_t control_bits, void FillRefreshMessage(size_t key_count, uint32_t control_bits,
uint32_t nonce); uint32_t nonce);
// Sets the OEMCrypto_Substring parameters of the LoadKeys method.
// Specifically, it sets the |enc_mac_keys_iv|, |enc_mac_keys|, |pst|, and
// |srm_restriction_data| in that order. For testing purposes,
// |srm_restriction_data| will always be NULL.
void SetLoadKeysSubstringParams();
// This copies data from license_ to encrypted_license_, and then encrypts // This copies data from license_ to encrypted_license_, and then encrypts
// each field in the key array appropriately. It then signes the buffer with // 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 // the server mac keys. It then fills out the key_array_ so that pointers in
@@ -364,6 +376,12 @@ class Session {
// An array of key objects for use in LoadKeys. // An array of key objects for use in LoadKeys.
OEMCrypto_KeyObject* key_array() { return key_array_; } OEMCrypto_KeyObject* key_array() { return key_array_; }
// An array of key objects for LoadEntitledContentKeys.
OEMCrypto_EntitledContentKeyObject* entitled_key_array() {
return entitled_key_array_;
}
// The last signature generated with the server's mac key. // The last signature generated with the server's mac key.
std::vector<uint8_t>& signature() { return signature_; } std::vector<uint8_t>& signature() { return signature_; }
@@ -380,6 +398,19 @@ class Session {
// The size of the encrypted message. // The size of the encrypted message.
size_t message_size() { return message_size_; } size_t message_size() { return message_size_; }
// The OEMCrypto_Substrings associated with the encrypted license that are
// passed to LoadKeys.
vector<OEMCrypto_Substring> load_keys_params() { return load_keys_params_; }
OEMCrypto_Substring enc_mac_keys_iv_substr() { return load_keys_params_[0]; }
OEMCrypto_Substring enc_mac_keys_substr() { return load_keys_params_[1]; }
OEMCrypto_Substring pst_substr() { return load_keys_params_[2]; }
OEMCrypto_Substring srm_restriction_data_substr() {
return load_keys_params_[3];
}
// Pointer to buffer holding |encrypted_entitled_message_|
const uint8_t* encrypted_entitled_message_ptr();
private: private:
// Generate mac and enc keys give the master key. // Generate mac and enc keys give the master key.
void DeriveKeys(const uint8_t* master_key, void DeriveKeys(const uint8_t* master_key,
@@ -404,6 +435,7 @@ class Session {
} padded_message_; } padded_message_;
size_t message_size_; // How much of the padded message to use. size_t message_size_; // How much of the padded message to use.
OEMCrypto_KeyObject key_array_[kMaxNumKeys]; OEMCrypto_KeyObject key_array_[kMaxNumKeys];
vector<OEMCrypto_Substring> load_keys_params_;
std::vector<uint8_t> signature_; std::vector<uint8_t> signature_;
unsigned int num_keys_; unsigned int num_keys_;
vector<uint8_t> encrypted_usage_entry_; vector<uint8_t> encrypted_usage_entry_;
@@ -413,8 +445,11 @@ class Session {
// Clear Entitlement key data. This is the backing data for // Clear Entitlement key data. This is the backing data for
// |entitled_key_array_|. // |entitled_key_array_|.
EntitledContentKeyData entitled_key_data_[kMaxNumKeys]; EntitledContentKeyData entitled_key_data_[kMaxNumKeys];
// Message containing data from |key_array| and |entitled_key_data_|.
std::string entitled_message_;
// Entitled key object. Pointers are backed by |entitled_key_data_|. // Entitled key object. Pointers are backed by |entitled_key_data_|.
OEMCrypto_EntitledContentKeyObject entitled_key_array_[kMaxNumKeys]; OEMCrypto_EntitledContentKeyObject entitled_key_array_[kMaxNumKeys];
std::string encrypted_entitled_message_;
}; };
} // namespace wvoec } // namespace wvoec

View File

@@ -15,48 +15,10 @@
namespace wvoec { namespace wvoec {
// These are test keyboxes. They will not be accepted by production systems. // TODO(fredgc, b/119316243): REMOVE THIS KEYBOX!
// By using known keyboxes for these tests, the results for a given set of // This test keybox is used for testing with OEMCrypto v13.
// inputs to a test are predictable and can be compared to the actual results. // It should be removed before release!
// The first keybox, kTestKeybox, with deviceID "TestKey01" is used for most of static const WidevineKeybox kTestKeyboxForV13 = {
// the tests. It should be loaded by OEMCrypto when OEMCrypto_LoadTestKeybox
// is called.
static const wvoec::WidevineKeybox kTestKeybox = {
// Sample keybox used for test vectors
{
// deviceID = WidevineTestOnlyKeybox000
0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65,
0x54, 0x65, 0x73, 0x74, 0x4f, 0x6e, 0x6c, 0x79,
0x4b, 0x65, 0x79, 0x62, 0x6f, 0x78, 0x30, 0x30,
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}, {
// key
0xe4, 0xff, 0x57, 0x4c, 0x32, 0x2e, 0xf5, 0x34,
0x26, 0x21, 0x2c, 0xb3, 0xed, 0x37, 0xf3, 0x5e,
}, {
// data (system ID 7912).
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x1e, 0xe8,
0xca, 0x1e, 0x71, 0x7c, 0xfb, 0xe8, 0xa3, 0x94,
0x52, 0x0a, 0x6b, 0x71, 0x37, 0xd2, 0x69, 0xfa,
0x5a, 0xc6, 0xb5, 0x4c, 0x6b, 0x46, 0x63, 0x9b,
0xbe, 0x80, 0x3d, 0xbb, 0x4f, 0xf7, 0x4c, 0x5f,
0x6f, 0x55, 0x0e, 0x3d, 0x3d, 0x9a, 0xcf, 0x81,
0x12, 0x5d, 0x52, 0xe0, 0x47, 0x8c, 0xda, 0x0b,
0xf4, 0x31, 0x41, 0x13, 0xd0, 0xd5, 0x2d, 0xa0,
0x5b, 0x20, 0x9a, 0xed, 0x51, 0x5d, 0x13, 0xd6,
}, {
// magic
0x6b, 0x62, 0x6f, 0x78,
}, {
// Crc
0x39, 0xf2, 0x94, 0xa7,
}
};
// These are old test keyboxes. The first keybox can be used to update an
// older OEMCrypto because it is the same keybox that was previously used in
// unit tests.
static const wvoec::WidevineKeybox kValidKeybox01 = {
// Sample keybox used for test vectors // Sample keybox used for test vectors
{ {
// deviceID // deviceID
@@ -88,67 +50,38 @@ static const wvoec::WidevineKeybox kValidKeybox01 = {
} }
}; };
static const wvoec::WidevineKeybox kValidKeybox02 = { // This is a test keybox. They will not be accepted by production systems.
// By using known keyboxes for these tests, the results for a given set of
// inputs to a test are predictable and can be compared to the actual results.
static const WidevineKeybox kTestKeybox = {
// Sample keybox used for test vectors // Sample keybox used for test vectors
{ {
// deviceID // deviceID = WidevineTestOnlyKeybox000
0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x30, // TestKey02 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65,
0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x54, 0x65, 0x73, 0x74, 0x4f, 0x6e, 0x6c, 0x79,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x4b, 0x65, 0x79, 0x62, 0x6f, 0x78, 0x30, 0x30,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}, { }, {
// key // key
0x76, 0x5d, 0xce, 0x01, 0x04, 0x89, 0xb3, 0xd0, 0xe4, 0xff, 0x57, 0x4c, 0x32, 0x2e, 0xf5, 0x34,
0xdf, 0xce, 0x54, 0x8a, 0x49, 0xda, 0xdc, 0xb6, 0x26, 0x21, 0x2c, 0xb3, 0xed, 0x37, 0xf3, 0x5e,
}, { }, {
// data // data (system ID 7912 = 1EE8).
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x19, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x1e, 0xe8,
0x92, 0x27, 0x0b, 0x1f, 0x1a, 0xd5, 0xc6, 0x93, 0xca, 0x1e, 0x71, 0x7c, 0xfb, 0xe8, 0xa3, 0x94,
0x19, 0x3f, 0xaa, 0x74, 0x1f, 0xdd, 0x5f, 0xb4, 0x52, 0x0a, 0x6b, 0x71, 0x37, 0xd2, 0x69, 0xfa,
0xe9, 0x40, 0x2f, 0x34, 0xa4, 0x92, 0xf4, 0xae, 0x5a, 0xc6, 0xb5, 0x4c, 0x6b, 0x46, 0x63, 0x9b,
0x9a, 0x52, 0x39, 0xbc, 0xb7, 0x24, 0x38, 0x13, 0xbe, 0x80, 0x3d, 0xbb, 0x4f, 0xf7, 0x4c, 0x5f,
0xab, 0xf4, 0x92, 0x96, 0xc4, 0x81, 0x60, 0x33, 0x6f, 0x55, 0x0e, 0x3d, 0x3d, 0x9a, 0xcf, 0x81,
0xd8, 0xb8, 0x09, 0xc7, 0x55, 0x0e, 0x12, 0xfa, 0x12, 0x5d, 0x52, 0xe0, 0x47, 0x8c, 0xda, 0x0b,
0xa8, 0x98, 0x62, 0x8a, 0xec, 0xea, 0x74, 0x8a, 0xf4, 0x31, 0x41, 0x13, 0xd0, 0xd5, 0x2d, 0xa0,
0x4b, 0xfa, 0x5a, 0x9e, 0xb6, 0x49, 0x0d, 0x80, 0x5b, 0x20, 0x9a, 0xed, 0x51, 0x5d, 0x13, 0xd6,
}, { }, {
// magic // magic
0x6b, 0x62, 0x6f, 0x78, 0x6b, 0x62, 0x6f, 0x78,
}, { }, {
// Crc // Crc
0x2a, 0x3b, 0x3e, 0xe4, 0x39, 0xf2, 0x94, 0xa7,
}
};
static const wvoec::WidevineKeybox kValidKeybox03 = {
// Sample keybox used for test vectors
{
// deviceID
0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x30, // TestKey03
0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
}, {
// key
0x25, 0xe5, 0x2a, 0x02, 0x29, 0x68, 0x04, 0xa2,
0x92, 0xfd, 0x7c, 0x67, 0x0b, 0x67, 0x1f, 0x31,
}, {
// data
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x19,
0xf4, 0x0a, 0x0e, 0xa2, 0x0a, 0x71, 0xd5, 0x92,
0xfa, 0xa3, 0x25, 0xc6, 0x4b, 0x76, 0xf1, 0x64,
0xf4, 0x60, 0xa0, 0x30, 0x72, 0x23, 0xbe, 0x03,
0xcd, 0xde, 0x7a, 0x06, 0xd4, 0x01, 0xeb, 0xdc,
0xe0, 0x50, 0xc0, 0x53, 0x0a, 0x50, 0xb0, 0x37,
0xe5, 0x05, 0x25, 0x0e, 0xa4, 0xc8, 0x5a, 0xff,
0x46, 0x6e, 0xa5, 0x31, 0xf3, 0xdd, 0x94, 0xb7,
0xe0, 0xd3, 0xf9, 0x04, 0xb2, 0x54, 0xb1, 0x64,
}, {
// magic
0x6b, 0x62, 0x6f, 0x78,
}, {
// Crc
0xa1, 0x99, 0x5f, 0x46,
} }
}; };
@@ -783,6 +716,8 @@ static const uint8_t kTestKeyRSAEuler_2048[] = {
0x33, 0xe0, 0xdb, 0x03, 0x33, 0xe0, 0xdb, 0x03,
}; };
static const uint8_t kTestSandbox[] = { 0x01, 0x02, 0x03 };
} // namespace wvoec } // namespace wvoec
#endif // CDM_OEC_TEST_DATA_H_ #endif // CDM_OEC_TEST_DATA_H_

View File

@@ -103,11 +103,8 @@ void SessionUtil::EnsureTestKeys() {
switch (global_features.derive_key_method) { switch (global_features.derive_key_method) {
case DeviceFeatures::LOAD_TEST_KEYBOX: case DeviceFeatures::LOAD_TEST_KEYBOX:
keybox_ = kTestKeybox; keybox_ = kTestKeybox;
/* Note: If you are upgrading from an older version, it may be easier to // TODO(fredgc, b/119316243): REMOVE FOLLOWING LINE:
* force the following condition. This uses the same test keybox as we if (global_features.api_version < 14) keybox_ = kTestKeyboxForV13;
* used in older versions of this test.
*/
if (global_features.api_version < 14) keybox_ = kValidKeybox01;
ASSERT_EQ(OEMCrypto_SUCCESS, ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_LoadTestKeybox( OEMCrypto_LoadTestKeybox(
reinterpret_cast<const uint8_t*>(&keybox_), reinterpret_cast<const uint8_t*>(&keybox_),
@@ -116,10 +113,6 @@ void SessionUtil::EnsureTestKeys() {
case DeviceFeatures::LOAD_TEST_RSA_KEY: case DeviceFeatures::LOAD_TEST_RSA_KEY:
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestRSAKey()); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestRSAKey());
break; break;
case DeviceFeatures::EXISTING_TEST_KEYBOX:
// already has old test keybox.
keybox_ = kValidKeybox01;
break;
case DeviceFeatures::FORCE_TEST_KEYBOX: case DeviceFeatures::FORCE_TEST_KEYBOX:
keybox_ = kTestKeybox; keybox_ = kTestKeybox;
InstallKeybox(keybox_, true); InstallKeybox(keybox_, true);

File diff suppressed because it is too large Load Diff

View File

@@ -23,7 +23,10 @@ namespace wvoec {
// These tests are required for LollyPop Android devices. // These tests are required for LollyPop Android devices.
class OEMCryptoAndroidLMPTest : public ::testing::Test { class OEMCryptoAndroidLMPTest : public ::testing::Test {
protected: protected:
virtual void SetUp() { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); } virtual void SetUp() {
OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox));
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize());
}
virtual void TearDown() { OEMCrypto_Terminate(); } virtual void TearDown() { OEMCrypto_Terminate(); }
}; };
@@ -153,7 +156,7 @@ class OEMCryptoAndroidQTest : public OEMCryptoAndroidOCTest {};
TEST_F(OEMCryptoAndroidQTest, MinVersionNumber14) { TEST_F(OEMCryptoAndroidQTest, MinVersionNumber14) {
uint32_t version = OEMCrypto_APIVersion(); uint32_t version = OEMCrypto_APIVersion();
ASSERT_GE(version, 14u); ASSERT_GE(version, 15u);
} }
} // namespace wvoec } // namespace wvoec

View File

@@ -5,7 +5,7 @@
# Override the variables below for the location of various gyp files. # Override the variables below for the location of various gyp files.
# Alternatively, set the environment variable CDM_DIR to point to a recent # Alternatively, set the environment variable CDM_DIR to point to a recent
# version of the source CDM. # version of the source CDM.
'boringssl_dependency%': '<!(echo $CDM_DIR)/third_party/boringssl/boringssl.gyp:legacy_ssl', 'boringssl_dependency%': '<!(echo $CDM_DIR)/third_party/boringssl/boringssl.gyp:ssl',
'gtest_dependency%': '<!(echo $CDM_DIR)/third_party/gmock.gyp:gtest', 'gtest_dependency%': '<!(echo $CDM_DIR)/third_party/gmock.gyp:gtest',
'gmock_dependency%': '<!(echo $CDM_DIR)/third_party/gmock.gyp:gmock', 'gmock_dependency%': '<!(echo $CDM_DIR)/third_party/gmock.gyp:gmock',
'oemcrypto_dir%': '..', 'oemcrypto_dir%': '..',

View File

@@ -10,10 +10,12 @@
'oec_session_util.cpp', 'oec_session_util.cpp',
'oemcrypto_session_tests_helper.cpp', 'oemcrypto_session_tests_helper.cpp',
'oemcrypto_test.cpp', 'oemcrypto_test.cpp',
'<(oemcrypto_dir)/ref/src/wvcrc.cpp',
], ],
'include_dirs': [ 'include_dirs': [
'<(util_dir)/include', '<(util_dir)/include',
'<(oemcrypto_dir)/include', '<(oemcrypto_dir)/include',
'<(oemcrypto_dir)/ref/src',
'<(oemcrypto_dir)/test', '<(oemcrypto_dir)/test',
], ],
'defines': [ 'defines': [

View File

@@ -26,6 +26,7 @@ std::string HexEncode(const uint8_t* bytes, unsigned size);
std::string IntToString(int value); std::string IntToString(int value);
int64_t htonll64(int64_t x); int64_t htonll64(int64_t x);
inline int64_t ntohll64(int64_t x) { return htonll64(x); } inline int64_t ntohll64(int64_t x) { return htonll64(x); }
std::string BytesToString(const uint8_t* bytes, unsigned size);
} // namespace wvcdm } // namespace wvcdm

View File

@@ -292,4 +292,10 @@ int64_t htonll64(int64_t x) { // Convert to big endian (network-byte-order)
} }
} }
std::string BytesToString(const uint8_t* bytes, unsigned size) {
if (!bytes || !size) return "";
const char* char_bytes = reinterpret_cast<const char*>(bytes);
return std::string(char_bytes, char_bytes + size);
}
} // namespace wvcdm } // namespace wvcdm