Merge latest oemcrypto-v17 change
No-Typo-Check: Not related to this change. Bug: 161477208 Change-Id: I99e4780f6855b7045aa0cd5a49c13d2d0d51ed64
This commit is contained in:
committed by
Fred Gylys-Colwell
parent
c924960962
commit
642965c678
@@ -91,64 +91,65 @@ static OEMCryptoResult ODK_PrepareRequest(
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
static OEMCryptoResult ODK_ParseResponse(
|
||||
const uint8_t* message, size_t message_length, size_t core_message_length,
|
||||
ODK_MessageType message_type, const ODK_NonceValues* nonce_values,
|
||||
void* response_buffer, uint32_t response_buffer_length) {
|
||||
if (message == NULL || response_buffer == NULL ||
|
||||
core_message_length > message_length) {
|
||||
/* Parse the core message and verify that it has the right type. The nonce
|
||||
* values are updated to hold the response's API version.
|
||||
*/
|
||||
static OEMCryptoResult ODK_ParseCoreHeader(const uint8_t* message,
|
||||
size_t message_length,
|
||||
size_t core_message_length,
|
||||
ODK_MessageType message_type,
|
||||
ODK_NonceValues* nonce_values) {
|
||||
// The core_message_length is the length of the core message, which is a
|
||||
// substring of the complete message.
|
||||
if (message == NULL || core_message_length > message_length) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
ODK_CoreMessage core_message;
|
||||
ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length);
|
||||
|
||||
/* The core message should be at the beginning of the buffer, and with a
|
||||
* shorter length. The core message is the part we are parsing. */
|
||||
/* The core message should be at the beginning of the buffer. The core message
|
||||
* is the part we are parsing. */
|
||||
ODK_Message_SetSize(&msg, core_message_length);
|
||||
Unpack_ODK_CoreMessage(&msg, &core_message);
|
||||
|
||||
/* Parse message and unpack it into response buffer. */
|
||||
switch (message_type) {
|
||||
case ODK_License_Response_Type: {
|
||||
if (sizeof(ODK_LicenseResponse) > response_buffer_length) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
Unpack_ODK_LicenseResponse(&msg, (ODK_LicenseResponse*)response_buffer);
|
||||
break;
|
||||
}
|
||||
case ODK_Renewal_Response_Type: {
|
||||
if (sizeof(ODK_RenewalResponse) > response_buffer_length) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
Unpack_ODK_RenewalResponse(&msg, (ODK_RenewalResponse*)response_buffer);
|
||||
break;
|
||||
}
|
||||
case ODK_Provisioning_Response_Type: {
|
||||
if (sizeof(ODK_ProvisioningResponse) > response_buffer_length) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
Unpack_ODK_ProvisioningResponse(
|
||||
&msg, (ODK_ProvisioningResponse*)response_buffer);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
}
|
||||
|
||||
ODK_CoreMessage* core_message = (ODK_CoreMessage*)response_buffer;
|
||||
if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
|
||||
message_type != core_message->message_type ||
|
||||
ODK_Message_GetOffset(&msg) != core_message->message_length) {
|
||||
message_type != core_message.message_type) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
// The current offset should be the end of the header, which is the message
|
||||
// type, message length, api version, and nonce fields. The header can't be
|
||||
// larger than the whole core message. Also, the core message specifies its
|
||||
// length, which should be exactly the length of the core message buffer.
|
||||
if (ODK_Message_GetOffset(&msg) > core_message.message_length ||
|
||||
core_message.message_length != core_message_length) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
/* We do not support future API version. Also, this function should not be
|
||||
* used for legacy licenses without a core message. */
|
||||
if (core_message.nonce_values.api_major_version > ODK_MAJOR_VERSION ||
|
||||
core_message.nonce_values.api_major_version < ODK_FIRST_VERSION) {
|
||||
return ODK_UNSUPPORTED_API;
|
||||
}
|
||||
if (nonce_values) {
|
||||
/* always verify nonce_values for Renewal and Provisioning responses */
|
||||
if (!ODK_NonceValuesEqual(nonce_values, &(core_message->nonce_values))) {
|
||||
return OEMCrypto_ERROR_INVALID_NONCE;
|
||||
/* If the server sent us an older format, record the message's API version.
|
||||
*/
|
||||
if (nonce_values->api_major_version >
|
||||
core_message.nonce_values.api_major_version) {
|
||||
// If the major version is smaller, use both values from the server.
|
||||
nonce_values->api_major_version =
|
||||
core_message.nonce_values.api_major_version;
|
||||
nonce_values->api_minor_version =
|
||||
core_message.nonce_values.api_minor_version;
|
||||
} else if (nonce_values->api_major_version ==
|
||||
core_message.nonce_values.api_major_version &&
|
||||
nonce_values->api_minor_version >
|
||||
core_message.nonce_values.api_minor_version) {
|
||||
// Otherwise, if the major versions are equal, but the minor is smaller,
|
||||
// then we should lower the minor version.
|
||||
nonce_values->api_minor_version =
|
||||
core_message.nonce_values.api_minor_version;
|
||||
}
|
||||
}
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -162,9 +163,7 @@ OEMCryptoResult ODK_PrepareCoreLicenseRequest(
|
||||
if (core_message_length == NULL || nonce_values == NULL) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
ODK_PreparedLicenseRequest license_request = {
|
||||
{0, 0, {}},
|
||||
};
|
||||
ODK_PreparedLicenseRequest license_request = {0};
|
||||
return ODK_PrepareRequest(
|
||||
message, message_length, core_message_length, ODK_License_Request_Type,
|
||||
nonce_values, &license_request, sizeof(ODK_PreparedLicenseRequest));
|
||||
@@ -192,7 +191,7 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message,
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
ODK_PreparedRenewalRequest renewal_request = {{0, 0, {}}, 0};
|
||||
ODK_PreparedRenewalRequest renewal_request = {0};
|
||||
/* First, we compute the time this request was made relative to the playback
|
||||
* clock. */
|
||||
if (clock_values->time_of_first_decrypt == 0) {
|
||||
@@ -225,11 +224,7 @@ OEMCryptoResult ODK_PrepareCoreProvisioningRequest(
|
||||
if (core_message_length == NULL || nonce_values == NULL) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
ODK_PreparedProvisioningRequest provisioning_request = {
|
||||
{0, 0, {}},
|
||||
0,
|
||||
{0},
|
||||
};
|
||||
ODK_PreparedProvisioningRequest provisioning_request = {0};
|
||||
if (device_id_length > sizeof(provisioning_request.device_id)) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
@@ -248,47 +243,88 @@ OEMCryptoResult ODK_PrepareCoreProvisioningRequest(
|
||||
OEMCryptoResult ODK_ParseLicense(
|
||||
const uint8_t* message, size_t message_length, size_t core_message_length,
|
||||
bool initial_license_load, bool usage_entry_present,
|
||||
const uint8_t* request_hash, ODK_TimerLimits* timer_limits,
|
||||
ODK_ClockValues* clock_values, ODK_NonceValues* nonce_values,
|
||||
ODK_ParsedLicense* parsed_license) {
|
||||
if (message == NULL || request_hash == NULL || timer_limits == NULL ||
|
||||
clock_values == NULL || nonce_values == NULL || parsed_license == NULL) {
|
||||
ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values,
|
||||
ODK_NonceValues* nonce_values, ODK_ParsedLicense* parsed_license) {
|
||||
if (message == NULL || timer_limits == NULL || clock_values == NULL ||
|
||||
nonce_values == NULL || parsed_license == NULL) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
ODK_LicenseResponse license_response = {{{0, 0, {}}}, NULL, {0}};
|
||||
license_response.parsed_license = parsed_license;
|
||||
|
||||
const OEMCryptoResult err = ODK_ParseResponse(
|
||||
message, message_length, core_message_length, ODK_License_Response_Type,
|
||||
NULL, &license_response, sizeof(ODK_LicenseResponse));
|
||||
|
||||
const OEMCryptoResult err =
|
||||
ODK_ParseCoreHeader(message, message_length, core_message_length,
|
||||
ODK_License_Response_Type, nonce_values);
|
||||
if (err != OEMCrypto_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* We do not support future API version. Also, this function should not be
|
||||
* used for legacy licenses. */
|
||||
if (license_response.request.core_message.nonce_values.api_major_version >
|
||||
ODK_MAJOR_VERSION ||
|
||||
license_response.request.core_message.nonce_values.api_major_version <
|
||||
ODK_FIRST_VERSION) {
|
||||
return ODK_UNSUPPORTED_API;
|
||||
ODK_LicenseResponse license_response = {0};
|
||||
license_response.parsed_license = parsed_license;
|
||||
|
||||
ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length);
|
||||
ODK_Message_SetSize(&msg, core_message_length);
|
||||
if (nonce_values->api_major_version == 16) {
|
||||
ODK_LicenseResponseV16 license_response_v16 = {0};
|
||||
Unpack_ODK_LicenseResponseV16(&msg, &license_response_v16);
|
||||
|
||||
if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
|
||||
ODK_Message_GetOffset(&msg) != core_message_length) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
// Need to manually set parsed_license fields to
|
||||
// license_response_v16.parsed_license field values since
|
||||
// license_response_v16 is no longer a pointer so parsed_license doesn't get
|
||||
// updated during the unpacking.
|
||||
parsed_license->enc_mac_keys_iv =
|
||||
license_response_v16.parsed_license.enc_mac_keys_iv;
|
||||
parsed_license->enc_mac_keys =
|
||||
license_response_v16.parsed_license.enc_mac_keys;
|
||||
parsed_license->pst = license_response_v16.parsed_license.pst;
|
||||
parsed_license->srm_restriction_data =
|
||||
license_response_v16.parsed_license.srm_restriction_data;
|
||||
parsed_license->license_type =
|
||||
license_response_v16.parsed_license.license_type;
|
||||
parsed_license->nonce_required =
|
||||
license_response_v16.parsed_license.nonce_required;
|
||||
parsed_license->timer_limits =
|
||||
license_response_v16.parsed_license.timer_limits;
|
||||
parsed_license->key_array_length =
|
||||
license_response_v16.parsed_license.key_array_length;
|
||||
uint32_t i;
|
||||
for (i = 0; i < parsed_license->key_array_length; i++) {
|
||||
parsed_license->key_array[i] =
|
||||
license_response_v16.parsed_license.key_array[i];
|
||||
}
|
||||
// Set fields not used in V16 to default values.
|
||||
parsed_license->watermarking = 0;
|
||||
// Set fields not used in V16 to default values.
|
||||
parsed_license->dtcp2_required.dtcp2_required = 0;
|
||||
parsed_license->dtcp2_required.cmi_descriptor_0.id = 0;
|
||||
parsed_license->dtcp2_required.cmi_descriptor_0.extension = 0;
|
||||
parsed_license->dtcp2_required.cmi_descriptor_0.length = 1;
|
||||
parsed_license->dtcp2_required.cmi_descriptor_0.data = 0;
|
||||
parsed_license->dtcp2_required.cmi_descriptor_1.id = 1;
|
||||
parsed_license->dtcp2_required.cmi_descriptor_1.extension = 0;
|
||||
parsed_license->dtcp2_required.cmi_descriptor_1.length = 3;
|
||||
parsed_license->dtcp2_required.cmi_descriptor_1.data[0] = 0;
|
||||
parsed_license->dtcp2_required.cmi_descriptor_1.data[1] = 0;
|
||||
parsed_license->dtcp2_required.cmi_descriptor_1.data[2] = 0;
|
||||
parsed_license->dtcp2_required.cmi_descriptor_2.id = 2;
|
||||
parsed_license->dtcp2_required.cmi_descriptor_2.extension = 0;
|
||||
parsed_license->dtcp2_required.cmi_descriptor_2.length = 3;
|
||||
parsed_license->dtcp2_required.cmi_descriptor_2.data[0] = 0;
|
||||
parsed_license->dtcp2_required.cmi_descriptor_2.data[1] = 0;
|
||||
parsed_license->dtcp2_required.cmi_descriptor_2.data[2] = 0;
|
||||
license_response.request = license_response_v16.request;
|
||||
} else {
|
||||
Unpack_ODK_LicenseResponse(&msg, &license_response);
|
||||
|
||||
if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
|
||||
ODK_Message_GetOffset(&msg) != core_message_length) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the server sent us an older format, record the license's API version. */
|
||||
if (nonce_values->api_major_version >
|
||||
license_response.request.core_message.nonce_values.api_major_version) {
|
||||
nonce_values->api_major_version =
|
||||
license_response.request.core_message.nonce_values.api_major_version;
|
||||
nonce_values->api_minor_version =
|
||||
license_response.request.core_message.nonce_values.api_minor_version;
|
||||
} else if (nonce_values->api_minor_version >
|
||||
license_response.request.core_message.nonce_values
|
||||
.api_minor_version) {
|
||||
nonce_values->api_minor_version =
|
||||
license_response.request.core_message.nonce_values.api_minor_version;
|
||||
}
|
||||
/* If the license has a provider session token (pst), then OEMCrypto should
|
||||
* have a usage entry loaded. The opposite is also an error. */
|
||||
if ((usage_entry_present && parsed_license->pst.length == 0) ||
|
||||
@@ -315,15 +351,6 @@ OEMCryptoResult ODK_ParseLicense(
|
||||
nonce_values->session_id =
|
||||
license_response.request.core_message.nonce_values.session_id;
|
||||
}
|
||||
/* For v16, in order to be backwards compatible with a v15 license server,
|
||||
* OEMCrypto stores a hash of the core license request and only signs the
|
||||
* message body. Here, when we process the license response, we verify that
|
||||
* the server has the same hash of the core request. */
|
||||
if (initial_license_load && parsed_license->nonce_required &&
|
||||
crypto_memcmp(request_hash, license_response.request_hash,
|
||||
ODK_SHA256_HASH_SIZE)) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
*timer_limits = parsed_license->timer_limits;
|
||||
/* And update the clock values state. */
|
||||
clock_values->timer_status = ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED;
|
||||
@@ -342,17 +369,27 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
ODK_RenewalResponse renewal_response = {
|
||||
{{0, 0, {}}, 0},
|
||||
0,
|
||||
};
|
||||
const OEMCryptoResult err = ODK_ParseResponse(
|
||||
message, message_length, core_message_length, ODK_Renewal_Response_Type,
|
||||
nonce_values, &renewal_response, sizeof(ODK_RenewalResponse));
|
||||
|
||||
const OEMCryptoResult err =
|
||||
ODK_ParseCoreHeader(message, message_length, core_message_length,
|
||||
ODK_Renewal_Response_Type, NULL);
|
||||
if (err != OEMCrypto_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
ODK_RenewalResponse renewal_response = {0};
|
||||
ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length);
|
||||
ODK_Message_SetSize(&msg, core_message_length);
|
||||
Unpack_ODK_RenewalResponse(&msg, &renewal_response);
|
||||
|
||||
if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
|
||||
ODK_Message_GetOffset(&msg) != core_message_length) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
/* always verify nonce_values for Renewal and Provisioning responses */
|
||||
if (!ODK_NonceValuesEqualExcludingVersion(
|
||||
nonce_values,
|
||||
&(renewal_response.request.core_message.nonce_values))) {
|
||||
return OEMCrypto_ERROR_INVALID_NONCE;
|
||||
}
|
||||
|
||||
/* Reference:
|
||||
* Doc: License Duration and Renewal (Changes for OEMCrypto v16)
|
||||
@@ -381,21 +418,31 @@ OEMCryptoResult ODK_ParseProvisioning(
|
||||
parsed_response == NULL) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
ODK_ProvisioningResponse provisioning_response = {{{0, 0, {}}, 0, {0}}, NULL};
|
||||
const OEMCryptoResult err =
|
||||
ODK_ParseCoreHeader(message, message_length, core_message_length,
|
||||
ODK_Provisioning_Response_Type, NULL);
|
||||
if (err != OEMCrypto_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
ODK_ProvisioningResponse provisioning_response = {0};
|
||||
provisioning_response.parsed_provisioning = parsed_response;
|
||||
|
||||
if (device_id_length > ODK_DEVICE_ID_LEN_MAX) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
const OEMCryptoResult err = ODK_ParseResponse(
|
||||
message, message_length, core_message_length,
|
||||
ODK_Provisioning_Response_Type, nonce_values, &provisioning_response,
|
||||
sizeof(ODK_ProvisioningResponse));
|
||||
|
||||
if (err != OEMCrypto_SUCCESS) {
|
||||
return err;
|
||||
ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length);
|
||||
ODK_Message_SetSize(&msg, core_message_length);
|
||||
Unpack_ODK_ProvisioningResponse(&msg, &provisioning_response);
|
||||
if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
|
||||
ODK_Message_GetOffset(&msg) != core_message_length) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
/* always verify nonce_values for Renewal and Provisioning responses */
|
||||
if (!ODK_NonceValuesEqualExcludingVersion(
|
||||
nonce_values,
|
||||
&(provisioning_response.request.core_message.nonce_values))) {
|
||||
return OEMCrypto_ERROR_INVALID_NONCE;
|
||||
}
|
||||
|
||||
if (crypto_memcmp(device_id, provisioning_response.request.device_id,
|
||||
@@ -413,3 +460,10 @@ OEMCryptoResult ODK_ParseProvisioning(
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
bool CheckApiVersionAtMost(const ODK_NonceValues* nonce_values,
|
||||
uint16_t major_version, uint16_t minor_version) {
|
||||
return nonce_values->api_major_version < major_version ||
|
||||
(nonce_values->api_major_version == major_version &&
|
||||
nonce_values->api_minor_version <= minor_version);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user