OEMCrypto and OPK v17.5

This commit is contained in:
John W. Bruce
2024-09-05 07:17:13 +00:00
parent 4080a1a1de
commit cca31312fe
20 changed files with 301 additions and 62 deletions

View File

@@ -2,6 +2,37 @@
[TOC]
## [Version 17.5][v17.5]
This release is mostly testing-focused, including new tests that provide
stricter enforcement of the existing OEMCrypto specification.
This release of OPK fixes a rare but possible null dereference bug.
### Tests
- Added new tests to better validate the behavior of
`OEMCrypto_BuildInformation()`
- Verifies output length is set correctly
- Verifies content is ASCII text without trailing null bytes
- Removed OEMCryptoLicenseTest.RejectCbc1API16
- Fixed erroneous failures on devices with low TEE memory caused by sending an
output buffer to decrypt that was much larger than necessary
### API
- Clarified the expected handling of the pattern (0,0) in cbcs mode. For more
information, please check the [OEMCrypto v17 Delta Document][delta-17].
### OPK
- Fixed a potential null dereference in `OPK_DispatchMessage()` if the allocator
runs out of memory
- Fixed incorrect behavior of `OEMCrypto_RemoveEntitledKeySession()` when the
session is already closed
[delta-17]: https://developers.google.com/widevine/drm/client/oemcrypto/v17/delta
## [Version 17.4][v17.4]
This is a minor release that includes a few security fixes.
@@ -289,3 +320,4 @@ Public release for OEMCrypto API and ODK library version 16.4.
[v17.2.1]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v17.2.1
[v17.3]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v17.3
[v17.4]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v17.4
[v17.5]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v17.5

Binary file not shown.

View File

@@ -3,7 +3,7 @@
// License Agreement.
/**
* @mainpage OEMCrypto API v17.4
* @mainpage OEMCrypto API v17.5
*
* OEMCrypto is the low level library implemented by the OEM to provide key and
* content protection, usually in a separate secure memory or process space. The
@@ -2495,10 +2495,20 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session,
* usually be non-zero. This mode allows devices to decrypt FMP4 HLS content,
* SAMPLE-AES HLS content, as well as content using the DASH 'cbcs' scheme.
*
* The skip field of OEMCrypto_CENCEncryptPatternDesc may also be zero. If
* the skip field is zero, then patterns are not in use and all crypto blocks
* in the encrypted part of the subsample are encrypted. It is not valid for
* the encrypt field to be zero.
* The skip field of OEMCrypto_CENCEncryptPatternDesc may be zero. If the skip
* field is zero, then patterns are not in use and all crypto blocks in the
* encrypted part of the subsample are encrypted, except for any partial crypto
* blocks at the end. The most common pattern with a skip field of zero is
* (10,0), but all patterns with a skip field of zero are functionally the same.
*
* If the skip field of OEMCrypto_CENCEncryptPatternDesc is zero, the encrypt
* field may also be zero. This pattern sometimes appears in content,
* particularly in audio tracks. This (0,0) pattern should be treated as
* equivalent to the pattern (10,0). e.g. All complete crypto blocks should be
* decrypted.
*
* It is not valid for the encrypt field of OEMCrypto_CENCEncryptPatternDesc to
* be zero if the skip field is non-zero.
*
* The length of a crypto block in AES-128 is 16 bytes. In the 'cbcs' scheme,
* if the encrypted part of a subsample has a length that is not a multiple

View File

@@ -25,9 +25,9 @@ struct CoreMessageFeatures {
// This is the published version of the ODK Core Message library. The default
// behavior is for the server to restrict messages to at most this version
// number. The default is 17.4.
// number. The default is 17.5.
uint32_t maximum_major_version = 17;
uint32_t maximum_minor_version = 4;
uint32_t maximum_minor_version = 5;
bool operator==(const CoreMessageFeatures &other) const;
bool operator!=(const CoreMessageFeatures &other) const {

View File

@@ -16,10 +16,10 @@ extern "C" {
/* The version of this library. */
#define ODK_MAJOR_VERSION 17
#define ODK_MINOR_VERSION 4
#define ODK_MINOR_VERSION 5
/* ODK Version string. Date changed automatically on each release. */
#define ODK_RELEASE_DATE "ODK v17.4 2024-06-04"
#define ODK_RELEASE_DATE "ODK v17.5 2024-09-04"
/* The lowest version number for an ODK message. */
#define ODK_FIRST_VERSION 16

View File

@@ -23,7 +23,7 @@ CoreMessageFeatures CoreMessageFeatures::DefaultFeatures(
features.maximum_minor_version = 5; // 16.5
break;
case 17:
features.maximum_minor_version = 4; // 17.4
features.maximum_minor_version = 5; // 17.5
break;
default:
features.maximum_minor_version = 0;

View File

@@ -274,7 +274,7 @@ OEMCryptoResult ODK_InitializeSessionValues(ODK_TimerLimits* timer_limits,
nonce_values->api_minor_version = 5;
break;
case 17:
nonce_values->api_minor_version = 4;
nonce_values->api_minor_version = 5;
break;
case 18:
nonce_values->api_minor_version = 3;

View File

@@ -875,6 +875,7 @@ std::vector<VersionParameters> TestCases() {
{17, 17, 2, 17, 2},
{17, 17, 3, 17, 3},
{17, 17, 4, 17, 4},
{17, 17, 5, 17, 5},
};
return test_cases;
}

View File

@@ -3243,7 +3243,13 @@ OEMCryptoResult OEMCrypto_RemoveEntitledKeySession(
OEMCryptoEntitledKeySession* key_session_context = NULL;
OEMCryptoResult result =
GetSessionContext(key_session, &session_context, &key_session_context);
if (result != OEMCrypto_SUCCESS) return result;
if (result != OEMCrypto_SUCCESS) {
// In case that the entitlement session is closed prior to the entitled key
// session, the result of OPKI_GetSession() will not be OEMCrypto_SUCCESS,
// and that's ok. This entitled key session should already be released when
// its entitlement session was closed. Just return success here.
return OEMCrypto_SUCCESS;
}
ABORT_IF(session_context == NULL,
"Failed to get the entitlement session context.");
ABORT_IF(key_session_context == NULL,

View File

@@ -31,7 +31,7 @@
// version bumps to v17.1, the first released OPK implementation would be
// v17.1.0
#define API_MAJOR_VERSION 17
#define API_MINOR_VERSION 4
#define API_MINOR_VERSION 5
#define OPK_PATCH_VERSION 0
#endif /* OEMCRYPTO_TA_OEMCRYPTO_API_MACROS_H_ */

View File

@@ -67,10 +67,9 @@ ODK_MessageStatus Tuner_DispatchMessage(ODK_Message* request,
OEMCrypto_CENCEncryptPatternDesc* pattern =
(OEMCrypto_CENCEncryptPatternDesc*)OPK_VarAlloc(
sizeof(OEMCrypto_CENCEncryptPatternDesc));
if (!pattern) goto handle_out_of_memory;
OPK_Init_OEMCrypto_CENCEncryptPatternDesc(
(OEMCrypto_CENCEncryptPatternDesc*)pattern);
// OPK_Unpack_DecryptCENC_Request(request, &session, &samples,
// &samples_length, &pattern);
OPK_Unpack_TunerHal_Decrypt_Request(request, &key_token,
&key_token_length, &key_parity,
&samples, &samples_length, &pattern);
@@ -90,6 +89,12 @@ handle_invalid_request:
LOGE("invalid request");
*response = CreateEmptyMessage();
return MESSAGE_STATUS_OK;
handle_out_of_memory:
LOGE("out of memory");
ODK_Message_SetStatus(request, MESSAGE_STATUS_OUT_OF_MEMORY);
*response = CreateEmptyMessage();
return MESSAGE_STATUS_OK;
}
void OPK_Unpack_TunerHal_Decrypt_Request(

View File

@@ -331,12 +331,14 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
size_t message_length;
OPK_Init_size_t((size_t*)&message_length);
size_t* signature_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (signature_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(signature_length);
OEMCrypto_SESSION session;
OPK_Init_uint32_t((uint32_t*)&session);
uint8_t* message;
OPK_InitPointer((uint8_t**)&message);
size_t* core_message_size = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (core_message_size == NULL) goto handle_out_of_memory;
OPK_Init_size_t(core_message_size);
uint8_t* signature;
OPK_InitPointer((uint8_t**)&signature);
@@ -360,12 +362,14 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
size_t message_length;
OPK_Init_size_t((size_t*)&message_length);
size_t* signature_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (signature_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(signature_length);
OEMCrypto_SESSION session;
OPK_Init_uint32_t((uint32_t*)&session);
uint8_t* message;
OPK_InitPointer((uint8_t**)&message);
size_t* core_message_size = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (core_message_size == NULL) goto handle_out_of_memory;
OPK_Init_size_t(core_message_size);
uint8_t* signature;
OPK_InitPointer((uint8_t**)&signature);
@@ -469,6 +473,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
OEMCrypto_KeyRefreshObject* key_array =
(OEMCrypto_KeyRefreshObject*)OPK_VarAlloc(
sizeof(OEMCrypto_KeyRefreshObject));
if (key_array == NULL) goto handle_out_of_memory;
OPK_Init_OEMCrypto_KeyRefreshObject(
(OEMCrypto_KeyRefreshObject*)key_array);
OPK_Unpack_RefreshKeys_Request(request, &session, &message,
@@ -516,6 +521,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
size_t content_key_id_length;
OPK_Init_size_t((size_t*)&content_key_id_length);
size_t* key_control_block_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (key_control_block_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(key_control_block_length);
OEMCrypto_SESSION session;
OPK_Init_uint32_t((uint32_t*)&session);
@@ -610,13 +616,20 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
}
case 120: /* OEMCrypto_LoadCasECMKeys */
{
if (!Handle_OEMCrypto_LoadCasECMKeys(request, response))
goto handle_invalid_request;
ODK_MessageStatus status = MESSAGE_STATUS_OK;
if (!Handle_OEMCrypto_LoadCasECMKeys(request, response, &status)) {
if (status == MESSAGE_STATUS_OUT_OF_MEMORY) {
goto handle_out_of_memory;
} else {
goto handle_invalid_request;
}
}
break;
}
case 130: /* OEMCrypto_GetOEMKeyToken */
{
size_t* key_token_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (key_token_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(key_token_length);
OEMCrypto_SESSION key_session;
OPK_Init_uint32_t((uint32_t*)&key_session);
@@ -665,6 +678,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
OEMCrypto_CENCEncryptPatternDesc* pattern =
(OEMCrypto_CENCEncryptPatternDesc*)OPK_VarAlloc(
sizeof(OEMCrypto_CENCEncryptPatternDesc));
if (pattern == NULL) goto handle_out_of_memory;
OPK_Init_OEMCrypto_CENCEncryptPatternDesc(
(OEMCrypto_CENCEncryptPatternDesc*)pattern);
OPK_Unpack_DecryptCENC_Request(request, &session, &samples,
@@ -687,6 +701,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
OEMCrypto_DestBufferDesc* out_buffer_descriptor =
(OEMCrypto_DestBufferDesc*)OPK_VarAlloc(
sizeof(OEMCrypto_DestBufferDesc));
if (out_buffer_descriptor == NULL) goto handle_out_of_memory;
OPK_Init_OEMCrypto_DestBufferDesc(
(OEMCrypto_DestBufferDesc*)out_buffer_descriptor);
uint8_t subsample_flags;
@@ -761,6 +776,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
size_t buffer_length;
OPK_Init_size_t((size_t*)&buffer_length);
size_t* signature_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (signature_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(signature_length);
OEMCrypto_SESSION session;
OPK_Init_uint32_t((uint32_t*)&session);
@@ -815,6 +831,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
OPK_Init_size_t((size_t*)&keybox_or_cert_length);
size_t* wrapped_keybox_or_cert_length =
(size_t*)OPK_VarAlloc(sizeof(size_t));
if (wrapped_keybox_or_cert_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(wrapped_keybox_or_cert_length);
size_t transport_key_length;
OPK_Init_size_t((size_t*)&transport_key_length);
@@ -881,6 +898,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
case 7: /* OEMCrypto_GetDeviceID */
{
size_t* device_id_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (device_id_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(device_id_length);
uint8_t* device_id;
OPK_InitPointer((uint8_t**)&device_id);
@@ -898,9 +916,11 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
{
size_t* wrapped_private_key_length =
(size_t*)OPK_VarAlloc(sizeof(size_t));
if (wrapped_private_key_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(wrapped_private_key_length);
uint8_t* clear_private_key_bytes =
(uint8_t*)OPK_VarAlloc(sizeof(uint8_t));
if (clear_private_key_bytes == NULL) goto handle_out_of_memory;
OPK_Init_uint8_t((uint8_t*)clear_private_key_bytes);
size_t clear_private_key_length;
OPK_Init_size_t((size_t*)&clear_private_key_length);
@@ -923,6 +943,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
case 4: /* OEMCrypto_GetKeyData */
{
size_t* key_data_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (key_data_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(key_data_length);
uint8_t* key_data;
OPK_InitPointer((uint8_t**)&key_data);
@@ -967,6 +988,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
case 104: /* OEMCrypto_GetOEMPublicCertificate */
{
size_t* public_cert_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (public_cert_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(public_cert_length);
uint8_t* public_cert;
OPK_InitPointer((uint8_t**)&public_cert);
@@ -1023,6 +1045,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
case 125: /* OEMCrypto_BuildInformation */
{
size_t* buffer_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (buffer_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(buffer_length);
char* buffer;
OPK_InitPointer((uint8_t**)&buffer);
@@ -1221,6 +1244,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
OPK_Init_size_t((size_t*)&signature_length);
size_t* wrapped_private_key_length =
(size_t*)OPK_VarAlloc(sizeof(size_t));
if (wrapped_private_key_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(wrapped_private_key_length);
OEMCrypto_SESSION session;
OPK_Init_uint32_t((uint32_t*)&session);
@@ -1285,6 +1309,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
size_t message_length;
OPK_Init_size_t((size_t*)&message_length);
size_t* signature_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (signature_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(signature_length);
OEMCrypto_SESSION session;
OPK_Init_uint32_t((uint32_t*)&session);
@@ -1313,12 +1338,14 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
size_t message_length;
OPK_Init_size_t((size_t*)&message_length);
size_t* signature_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (signature_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(signature_length);
OEMCrypto_SESSION session;
OPK_Init_uint32_t((uint32_t*)&session);
uint8_t* message;
OPK_InitPointer((uint8_t**)&message);
size_t* core_message_size = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (core_message_size == NULL) goto handle_out_of_memory;
OPK_Init_size_t(core_message_size);
uint8_t* signature;
OPK_InitPointer((uint8_t**)&signature);
@@ -1340,6 +1367,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
case 61: /* OEMCrypto_CreateUsageTableHeader */
{
size_t* header_buffer_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (header_buffer_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(header_buffer_length);
uint8_t* header_buffer;
OPK_InitPointer((uint8_t**)&header_buffer);
@@ -1427,8 +1455,10 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
case 65: /* OEMCrypto_UpdateUsageEntry */
{
size_t* header_buffer_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (header_buffer_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(header_buffer_length);
size_t* entry_buffer_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (entry_buffer_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(entry_buffer_length);
OEMCrypto_SESSION session;
OPK_Init_uint32_t((uint32_t*)&session);
@@ -1474,6 +1504,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
size_t pst_length;
OPK_Init_size_t((size_t*)&pst_length);
size_t* buffer_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (buffer_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(buffer_length);
OEMCrypto_SESSION session;
OPK_Init_uint32_t((uint32_t*)&session);
@@ -1510,6 +1541,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
case 67: /* OEMCrypto_ShrinkUsageTableHeader */
{
size_t* header_buffer_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (header_buffer_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(header_buffer_length);
uint32_t new_entry_count;
OPK_Init_uint32_t((uint32_t*)&new_entry_count);
@@ -1530,9 +1562,11 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
case 116: /* OEMCrypto_GetBootCertificateChain */
{
size_t* bcc_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (bcc_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(bcc_length);
size_t* additional_signature_length =
(size_t*)OPK_VarAlloc(sizeof(size_t));
if (additional_signature_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(additional_signature_length);
uint8_t* bcc;
OPK_InitPointer((uint8_t**)&bcc);
@@ -1555,12 +1589,15 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
case 117: /* OEMCrypto_GenerateCertificateKeyPair */
{
size_t* public_key_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (public_key_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(public_key_length);
size_t* public_key_signature_length =
(size_t*)OPK_VarAlloc(sizeof(size_t));
if (public_key_signature_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(public_key_signature_length);
size_t* wrapped_private_key_length =
(size_t*)OPK_VarAlloc(sizeof(size_t));
if (wrapped_private_key_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(wrapped_private_key_length);
OEMCrypto_SESSION session;
OPK_Init_uint32_t((uint32_t*)&session);
@@ -1690,6 +1727,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
OEMCrypto_DestBufferDesc* output_descriptor =
(OEMCrypto_DestBufferDesc*)OPK_VarAlloc(
sizeof(OEMCrypto_DestBufferDesc));
if (output_descriptor == NULL) goto handle_out_of_memory;
OPK_Init_OEMCrypto_DestBufferDesc(output_descriptor);
int secure_fd;
OPK_Init_int((int*)&secure_fd);
@@ -1707,8 +1745,10 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
case 115: /* OEMCrypto_OPK_SerializationVersion */
{
uint32_t* ree_major = (uint32_t*)OPK_VarAlloc(sizeof(uint32_t));
if (ree_major == NULL) goto handle_out_of_memory;
OPK_Init_uint32_t(ree_major);
uint32_t* ree_minor = (uint32_t*)OPK_VarAlloc(sizeof(uint32_t));
if (ree_minor == NULL) goto handle_out_of_memory;
OPK_Init_uint32_t(ree_minor);
uint32_t* tee_major;
OPK_InitPointer((uint8_t**)&tee_major);
@@ -1729,6 +1769,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request,
case 113: /* OEMCrypto_GenerateOTARequest */
{
size_t* buffer_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
if (buffer_length == NULL) goto handle_out_of_memory;
OPK_Init_size_t(buffer_length);
OEMCrypto_SESSION session;
OPK_Init_uint32_t((uint32_t*)&session);
@@ -1778,4 +1819,10 @@ handle_invalid_request:
LOGE("invalid request");
*response = CreateEmptyMessage();
return MESSAGE_STATUS_OK;
handle_out_of_memory:
LOGE("out of memory");
ODK_Message_SetStatus(request, MESSAGE_STATUS_OUT_OF_MEMORY);
*response = CreateEmptyMessage();
return MESSAGE_STATUS_OK;
}

View File

@@ -18,7 +18,8 @@ void OPK_Init_OEMCrypto_EntitledContentKeyObject(
OEMCrypto_EntitledContentKeyObject* obj);
bool Handle_OEMCrypto_LoadCasECMKeys(ODK_Message* request,
ODK_Message* response) {
ODK_Message* response,
ODK_MessageStatus* status) {
size_t message_length;
OPK_Init_size_t((size_t*)&message_length);
OEMCrypto_SESSION session;
@@ -28,11 +29,19 @@ bool Handle_OEMCrypto_LoadCasECMKeys(ODK_Message* request,
OEMCrypto_EntitledContentKeyObject* even_key =
(OEMCrypto_EntitledContentKeyObject*)OPK_VarAlloc(
sizeof(OEMCrypto_EntitledContentKeyObject));
if (!even_key) {
*status = MESSAGE_STATUS_OUT_OF_MEMORY;
return false;
}
OPK_Init_OEMCrypto_EntitledContentKeyObject(
(OEMCrypto_EntitledContentKeyObject*)even_key);
OEMCrypto_EntitledContentKeyObject* odd_key =
(OEMCrypto_EntitledContentKeyObject*)OPK_VarAlloc(
sizeof(OEMCrypto_EntitledContentKeyObject));
if (!odd_key) {
*status = MESSAGE_STATUS_OUT_OF_MEMORY;
return false;
}
OPK_Init_OEMCrypto_EntitledContentKeyObject(
(OEMCrypto_EntitledContentKeyObject*)odd_key);
OPK_Unpack_LoadCasECMKeys_Request(request, &session, &message,
@@ -44,5 +53,6 @@ bool Handle_OEMCrypto_LoadCasECMKeys(ODK_Message* request,
result = OEMCrypto_LoadCasECMKeys(session, message, message_length, even_key,
odd_key);
*response = OPK_Pack_LoadCasECMKeys_Response(result);
*status = MESSAGE_STATUS_OK;
return true;
}

View File

@@ -16,7 +16,8 @@ extern "C" {
#include "odk_message.h"
bool Handle_OEMCrypto_LoadCasECMKeys(ODK_Message* request,
ODK_Message* response);
ODK_Message* response,
ODK_MessageStatus* status);
#ifdef __cplusplus
} // extern "C"

View File

@@ -17,7 +17,6 @@ void advance_dest_buffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) {
switch (dest_buffer->type) {
case OEMCrypto_BufferType_Clear:
dest_buffer->buffer.clear.clear_buffer += bytes;
dest_buffer->buffer.clear.clear_buffer_length -= bytes;
break;
case OEMCrypto_BufferType_Secure:
@@ -96,6 +95,11 @@ OEMCryptoResult DecryptFallbackChain::DecryptSample(
const size_t length =
subsample.num_bytes_clear + subsample.num_bytes_encrypted;
fake_sample.buffers.input_data_length = length;
if (fake_sample.buffers.output_descriptor.type ==
OEMCrypto_BufferType_Clear) {
fake_sample.buffers.output_descriptor.buffer.clear.clear_buffer_length =
length;
}
fake_sample.subsamples = &subsample;
fake_sample.subsamples_length = 1;
@@ -138,6 +142,11 @@ OEMCryptoResult DecryptFallbackChain::DecryptSubsample(
if (subsample.num_bytes_clear > 0) {
fake_sample.buffers.input_data_length = subsample.num_bytes_clear;
if (fake_sample.buffers.output_descriptor.type ==
OEMCrypto_BufferType_Clear) {
fake_sample.buffers.output_descriptor.buffer.clear.clear_buffer_length =
subsample.num_bytes_clear;
}
fake_subsample.num_bytes_clear = subsample.num_bytes_clear;
fake_subsample.num_bytes_encrypted = 0;
fake_subsample.block_offset = 0;
@@ -160,6 +169,11 @@ OEMCryptoResult DecryptFallbackChain::DecryptSubsample(
if (subsample.num_bytes_encrypted > 0) {
fake_sample.buffers.input_data_length = subsample.num_bytes_encrypted;
if (fake_sample.buffers.output_descriptor.type ==
OEMCrypto_BufferType_Clear) {
fake_sample.buffers.output_descriptor.buffer.clear.clear_buffer_length =
subsample.num_bytes_encrypted;
}
fake_subsample.num_bytes_clear = 0;
fake_subsample.num_bytes_encrypted = subsample.num_bytes_encrypted;
fake_subsample.block_offset = subsample.block_offset;

View File

@@ -10,7 +10,9 @@
#include <cstring>
#include "log.h"
#include "oec_test_data.h"
#include "string_conversions.h"
#include "test_sleep.h"
namespace wvoec {
@@ -58,6 +60,12 @@ void DeviceFeatures::Initialize() {
loads_certificate = false;
}
printf("loads_certificate = %s.\n", loads_certificate ? "true" : "false");
if (rsa_test_key().empty()) {
set_rsa_test_key(
std::vector<uint8_t>(kTestRSAPKCS8PrivateKeyInfo2_2048,
kTestRSAPKCS8PrivateKeyInfo2_2048 +
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048)));
}
generic_crypto =
(OEMCrypto_ERROR_NOT_IMPLEMENTED !=
OEMCrypto_Generic_Encrypt(session, buffer, 0, iv,
@@ -113,6 +121,9 @@ void DeviceFeatures::Initialize() {
case LOAD_TEST_RSA_KEY:
printf("LOAD_TEST_RSA_KEY: Call LoadTestRSAKey before deriving keys.\n");
break;
case PRELOADED_RSA_KEY:
printf("PRELOADED_RSA_KEY: Device has test RSA key baked in.\n");
break;
case TEST_PROVISION_30:
printf("TEST_PROVISION_30: Device provisioned with OEM Cert.\n");
break;
@@ -181,9 +192,10 @@ void DeviceFeatures::PickDerivedKey() {
derive_key_method = TEST_PROVISION_30;
return;
case OEMCrypto_DrmCertificate:
if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) {
derive_key_method = LOAD_TEST_RSA_KEY;
}
derive_key_method =
(OEMCrypto_ERROR_NOT_IMPLEMENTED == OEMCrypto_LoadTestRSAKey())
? PRELOADED_RSA_KEY
: LOAD_TEST_RSA_KEY;
return;
case OEMCrypto_Keybox:
// Fall through to api_version < 12 case.

View File

@@ -38,6 +38,7 @@ class DeviceFeatures {
LOAD_TEST_RSA_KEY, // Call LoadTestRSAKey before deriving keys.
TEST_PROVISION_30, // Device has OEM Certificate installed.
TEST_PROVISION_40, // Device has Boot Certificate Chain installed.
PRELOADED_RSA_KEY, // Device has test RSA key baked in.
};
enum DeriveMethod derive_key_method;
@@ -69,6 +70,16 @@ class DeviceFeatures {
// Get a list of output types that should be tested.
const std::vector<OutputType>& GetOutputTypes();
// If the device has a baked in cert, then this is the public key that should
// be used for testing.
const std::vector<uint8_t>& rsa_test_key() const { return rsa_test_key_; };
void set_rsa_test_key(const std::vector<uint8_t>& rsa_test_key) {
rsa_test_key_ = rsa_test_key;
}
void set_rsa_test_key(std::vector<uint8_t>&& rsa_test_key) {
rsa_test_key_ = std::move(rsa_test_key);
}
private:
// Decide which method should be used to derive session keys, based on
// supported featuers.
@@ -81,6 +92,7 @@ class DeviceFeatures {
// A list of possible output types.
std::vector<OutputType> output_types_;
bool initialized_ = false;
std::vector<uint8_t> rsa_test_key_;
};
// There is one global set of features for the version of OEMCrypto being

View File

@@ -1771,10 +1771,9 @@ void Session::LoadOEMCert(bool verify_cert) {
void Session::SetTestRsaPublicKey() {
public_ec_.reset();
public_rsa_ = util::RsaPublicKey::LoadPrivateKeyInfo(
kTestRSAPKCS8PrivateKeyInfo2_2048,
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048));
ASSERT_TRUE(public_rsa_) << "Could not parse test RSA public key #2";
public_rsa_ =
util::RsaPublicKey::LoadPrivateKeyInfo(global_features.rsa_test_key());
ASSERT_TRUE(public_rsa_) << "Could not parse test RSA public key";
}
void Session::SetPublicKeyFromPrivateKeyInfo(OEMCrypto_PrivateKeyType key_type,

View File

@@ -63,6 +63,9 @@ void SessionUtil::EnsureTestKeys() {
case DeviceFeatures::TEST_PROVISION_30:
// Can use oem certificate to install test rsa key.
break;
case DeviceFeatures::PRELOADED_RSA_KEY:
// There is already a key.
break;
case wvoec::DeviceFeatures::TEST_PROVISION_40:
// OEM certificate is retrieved from the server.
break;

View File

@@ -292,7 +292,7 @@ TEST_F(OEMCryptoClientTest, FreeUnallocatedSecureBufferNoFailure) {
*/
TEST_F(OEMCryptoClientTest, VersionNumber) {
const std::string log_message =
"OEMCrypto unit tests for API 17.4. Tests last updated 2024-06-04";
"OEMCrypto unit tests for API 17.5. Tests last updated 2024-09-04";
cout << " " << log_message << "\n";
cout << " "
<< "These tests are part of Android T."
@@ -301,7 +301,7 @@ TEST_F(OEMCryptoClientTest, VersionNumber) {
// If any of the following fail, then it is time to update the log message
// above.
EXPECT_EQ(ODK_MAJOR_VERSION, 17);
EXPECT_EQ(ODK_MINOR_VERSION, 4);
EXPECT_EQ(ODK_MINOR_VERSION, 5);
EXPECT_EQ(kCurrentAPI, 17u);
OEMCrypto_Security_Level level = OEMCrypto_SecurityLevel();
EXPECT_GT(level, OEMCrypto_Level_Unknown);
@@ -548,6 +548,118 @@ TEST_F(OEMCryptoClientTest, CheckNullBuildInformationAPI17) {
}
}
// Verifies that OEMCrypto_BuildInformation() is behaving as expected
// by assigning appropriate values to the build info size.
TEST_F(OEMCryptoClientTest, CheckBuildInformation_OutputLengthAPI17) {
constexpr size_t kZero = 0;
constexpr char kNullChar = '\0';
// Allocating single byte to avoid potential null dereference.
std::string build_info(1, kNullChar);
size_t build_info_length = 0;
OEMCryptoResult result =
OEMCrypto_BuildInformation(&build_info[0], &build_info_length);
ASSERT_EQ(result, OEMCrypto_ERROR_SHORT_BUFFER);
ASSERT_GT(build_info_length, kZero)
<< "Signaling ERROR_SHORT_BUFFER should have assigned a length";
// Force a ERROR_SHORT_BUFFER using a non-zero value.
// Note: It is assumed that vendors will provide more than a single
// character of info.
const size_t second_attempt_length =
(build_info_length >= 2) ? build_info_length / 2 : 1;
build_info.assign(second_attempt_length, kNullChar);
build_info_length = build_info.size();
result = OEMCrypto_BuildInformation(&build_info[0], &build_info_length);
ASSERT_EQ(result, OEMCrypto_ERROR_SHORT_BUFFER)
<< "second_attempt_length = " << second_attempt_length
<< ", build_info_length" << build_info_length;
// OEM specified build info length should be larger than the
// original length if returning ERROR_SHORT_BUFFER.
ASSERT_GT(build_info_length, second_attempt_length);
// Final attempt with a buffer large enough buffer, padding to
// ensure the caller truncates.
constexpr size_t kBufferPadSize = 42;
const size_t expected_length = build_info_length;
const size_t final_attempt_length = expected_length + kBufferPadSize;
build_info.assign(final_attempt_length, kNullChar);
build_info_length = build_info.size();
result = OEMCrypto_BuildInformation(&build_info[0], &build_info_length);
ASSERT_EQ(result, OEMCrypto_SUCCESS)
<< "final_attempt_length = " << final_attempt_length
<< ", expected_length = " << expected_length
<< ", build_info_length = " << build_info_length;
// Ensure not empty.
ASSERT_GT(build_info_length, kZero) << "Build info cannot be empty";
// Ensure it was truncated down from the padded length.
ASSERT_LT(build_info_length, final_attempt_length)
<< "Should have truncated from oversized buffer: expected_length = "
<< expected_length;
// Ensure the real length is within the size originally specified.
// OK if final length is smaller than estimated length.
ASSERT_LE(build_info_length, expected_length);
}
// Verifies that OEMCrypto_BuildInformation() is behaving as expected
// by checking the resulting contents.
TEST_F(OEMCryptoClientTest, CheckBuildInformation_OutputContentAPI17) {
constexpr size_t kZero = 0;
constexpr char kNullChar = '\0';
// Allocating single byte to avoid potential null dereference.
std::string build_info(1, kNullChar);
size_t build_info_length = 0;
OEMCryptoResult result =
OEMCrypto_BuildInformation(&build_info[0], &build_info_length);
ASSERT_EQ(result, OEMCrypto_ERROR_SHORT_BUFFER);
ASSERT_GT(build_info_length, kZero)
<< "Signaling ERROR_SHORT_BUFFER should have assigned a length";
// Expect successful acquisition of build information.
const size_t expected_length = build_info_length;
build_info.assign(expected_length, kNullChar);
result = OEMCrypto_BuildInformation(&build_info[0], &build_info_length);
ASSERT_EQ(result, OEMCrypto_SUCCESS)
<< "expected_length = " << expected_length
<< ", build_info_length = " << build_info_length;
// Ensure not empty.
ASSERT_GT(build_info_length, kZero) << "Build info cannot be empty";
// Ensure the real length is within the size originally specified.
ASSERT_LE(build_info_length, expected_length)
<< "Cannot specify success if buffer was too small";
build_info.resize(build_info_length);
// Ensure there isn't a trailing null byte.
ASSERT_NE(build_info.back(), kNullChar)
<< "Build info must not contain trailing null byte";
// Ensure all build info characters are printable, or a limited
// set of white space characters (case of JSON build info).
const auto is_valid_build_info_white_space = [](const char& ch) -> bool {
constexpr char kSpace = ' ';
constexpr char kLineFeed = '\n';
constexpr char kTab = '\t';
return ch == kLineFeed || ch == kTab || ch == kSpace;
};
const auto is_valid_build_info_char = [&](const char& ch) -> bool {
return ::isprint(ch) || is_valid_build_info_white_space(ch);
};
ASSERT_TRUE(std::all_of(build_info.begin(), build_info.end(),
is_valid_build_info_char))
<< "Build info is not printable: " << wvutil::b2a_hex(build_info);
// Ensure build info isn't just white space.
ASSERT_FALSE(std::all_of(build_info.begin(), build_info.end(),
is_valid_build_info_white_space))
<< "Build info is just white space: " << wvutil::b2a_hex(build_info);
}
TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) {
size_t sessions_count;
ASSERT_EQ(OEMCrypto_SUCCESS,
@@ -3258,10 +3370,15 @@ TEST_P(OEMCryptoLicenseTest,
// Close the OEMCrypto session.
session_.close();
// All entitled key sessions associated with the OEMCrypto session should
// already be been destroyed,
// already be destroyed.
OEMCryptoResult sts = OEMCrypto_RemoveEntitledKeySession(key_session_id_1);
// For v17, there is a discrepancy in the L3 and OPK implementation for when
// the entitlement session is closed prior to the entitled key session. This
// is because it is difficult to update L3 for Android T. To accommodate this,
// we accept both error codes and OEMCrypto_SUCCESS.
EXPECT_TRUE(sts == OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION ||
sts == OEMCrypto_ERROR_INVALID_SESSION);
sts == OEMCrypto_ERROR_INVALID_SESSION ||
sts == OEMCrypto_SUCCESS);
// Open a new session just for OEMCryptoLicenseTest TearDown.
session_.open();
}
@@ -3496,36 +3613,6 @@ TEST_P(OEMCryptoLicenseTest, RejectCensAPI16) {
EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts);
}
// 'cbc1' mode is no longer supported in v16
TEST_P(OEMCryptoLicenseTest, RejectCbc1API16) {
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
OEMCryptoResult sts;
sts = OEMCrypto_SelectKey(
session_.session_id(), session_.license().keys[0].key_id,
session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CBCS);
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
vector<uint8_t> in_buffer(256);
vector<uint8_t> out_buffer(in_buffer.size());
OEMCrypto_SampleDescription sample_description;
OEMCrypto_SubSampleDescription subsample_description;
GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description,
&subsample_description);
// Create a zero pattern to indicate this is 'cbc1'
OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0};
// Try to decrypt the data
sts = OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1,
&pattern);
EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts);
}
TEST_P(OEMCryptoLicenseTest, RejectCbcsWithBlockOffset) {
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
@@ -9637,7 +9724,7 @@ TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntries) {
ASSERT_NO_FATAL_FAILURE(
FailReloadLicense(&entries[3], OEMCrypto_ERROR_UNKNOWN_FAILURE));
}
TEST_P(OEMCryptoUsageTableDefragTest, MakeAndMoveEntry) {
// 1. Make an entry then close.
LicenseWithUsageEntry entry;