Source release 19.5.0

This commit is contained in:
Cong Lin
2025-04-02 10:27:18 -07:00
parent 4407acee62
commit f7ec4fdeff
295 changed files with 32196 additions and 21748 deletions

View File

@@ -3,7 +3,7 @@
// License Agreement.
/**
* @mainpage OEMCrypto API v19.4
* @mainpage OEMCrypto API v19.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
@@ -764,6 +764,8 @@ typedef enum OEMCrypto_SignatureHashAlgorithm {
#define OEMCrypto_WrapClearPrivateKey _oecc154
#define OEMCrypto_SetSessionUsage _oecc155
#define OEMCrypto_GetBCCSignatureType _oecc156
#define OEMCrypto_GetPVRKey _oecc157
#define OEMCrypto_LoadPVRKey _oecc158
// clang-format on
/// @addtogroup initcontrol
@@ -1984,6 +1986,72 @@ OEMCryptoResult OEMCrypto_GetOEMKeyToken(OEMCrypto_SESSION key_session,
OEMCryptoResult OEMCrypto_SetSessionUsage(OEMCrypto_SESSION session,
uint32_t intent, uint32_t mode);
/**
* Retrieves the key used for Personal Video Recorder (PVR) re-encrypting
* recorded content. The returned key is encrypted by a device specific key for
* storage on the filesystem. The format of the wrapped key is
* platform-specific. This method is currently used exclusively by CAS with PVR
* support.
*
* @param[in] session: session id.
* @param[out] wrapped_pvr_key: pointer to a buffer where the wrapped PVR key
* will be stored. May be null on the first call to determine the required
* buffer size.
* @param[in,out] wrapped_pvr_key_length: length of the buffer for the wrapped
* PVR key, in bytes.
*
* @retval OEMCrypto_SUCCESS on success
* @retval OEMCrypto_ERROR_INVALID_SESSION
* @retval OEMCrypto_ERROR_SHORT_BUFFER
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
* @retval OEMCrypto_ERROR_NOT_IMPLEMENTED
*
* @threading
* This is a "Session Function" and may be called simultaneously with session
* functions for other sessions but not simultaneously with other functions
* for this session. It is as if the CDM holds a write lock for this session,
* and a read lock on the OEMCrypto system.
*
* @version
* This method is new in API version 18.
*/
OEMCryptoResult OEMCrypto_GetPVRKey(OEMCrypto_SESSION session,
uint8_t* wrapped_pvr_key,
size_t* wrapped_pvr_key_length);
/**
* Loads a wrapped PVR key into secure memory. This key is used for decrypting
* content that has been re-encrypted for PVR storage. The wrapped PVR key
* is typically obtained from persistent storage, having been previously
* retrieved using OEMCrypto_GetPVRKey(). This method is currently used
* exclusively by CAS with PVR support.
*
* @param[in] session: session id.
* @param[in] wrapped_pvr_key: Pointer to the buffer containing the wrapped PVR
* key.
* @param[in] wrapped_pvr_key_length: Length of the wrapped PVR key buffer, in
* bytes.
*
* @retval OEMCrypto_SUCCESS on success.
* @retval OEMCrypto_ERROR_INVALID_SESSION
* @retval OEMCrypto_ERROR_INVALID_KEY
* @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
* @retval OEMCrypto_ERROR_NOT_IMPLEMENTED
*
* @threading
* This is a "Session Function" and may be called simultaneously with session
* functions for other sessions but not simultaneously with other functions
* for this session. It is as if the CDM holds a write lock for this session,
* and a read lock on the OEMCrypto system.
*
* @version
* This method is new in API version 18.
*/
OEMCryptoResult OEMCrypto_LoadPVRKey(OEMCrypto_SESSION session,
const uint8_t* wrapped_pvr_key,
size_t wrapped_pvr_key_length);
/// @}
/// @addtogroup decryption
@@ -5206,11 +5274,15 @@ OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader(uint32_t new_entry_count,
* @param[in,out] bcc_length - on input, size of the caller's bcc buffer. On
* output, the number of bytes written into the buffer.
* @param[out] additional_signature: pointer to the buffer that receives
* additional device key signature (certificate chain). This field is only
* used by the signing model where either a vendor certificate or a keybox is
* available on the device. Please work with your Widevine Partner Engineer
* before implementing this field to make sure the generated signature is in the
* expected format.
* additional device key signature (Unique Device Secret certificate chain).
* This field is used by (1) the signing model where either a vendor
* certificate or a keybox is available on the device, or (2) the
* Provisioning 4.0 phase 3 uploading model. For details on the format of
* additional_signature in the scenarios mentioned above, please refer to the
* definition of enum OEMCrypto_BCCSignatureType and
* OEMCrypto_GetBCCSignatureType(). Please work with your Widevine Partner
* Engineer before implementing this field to make sure the generated
* signature is in the expected format.
* @param[in,out] additional_signature_length - on input, size of the caller's
* additional_signature buffer. On output, the number of bytes written into
* the buffer.

View File

@@ -113,6 +113,7 @@ cc_test {
"test/odk_golden_v16.cpp",
"test/odk_golden_v17.cpp",
"test/odk_golden_v18.cpp",
"test/odk_golden_v19.cpp",
"test/odk_test.cpp",
"test/odk_test_helper.cpp",
"test/odk_timer_test.cpp",

View File

@@ -26,9 +26,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 19.4.
// number. The default is 19.5.
uint32_t maximum_major_version = 19;
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 19
#define ODK_MINOR_VERSION 4
#define ODK_MINOR_VERSION 5
/* ODK Version string. Date changed automatically on each release. */
#define ODK_RELEASE_DATE "ODK v19.4 2024-11-04"
#define ODK_RELEASE_DATE "ODK v19.5 2025-03-11"
/* The lowest version number for an ODK message. */
#define ODK_FIRST_VERSION 16

View File

@@ -77,7 +77,8 @@ bool ParseRequest(uint32_t message_type,
!(message_type == ODK_Renewal_Request_Type &&
core_message.message_type == ODK_Release_Request_Type) &&
!(message_type == ODK_Provisioning_Request_Type &&
core_message.message_type == ODK_Renewed_Provisioning_Request_Type)) {
(core_message.message_type == ODK_Renewed_Provisioning_Request_Type ||
core_message.message_type == ODK_Provisioning40_Request_Type))) {
return false;
}
// Verify that the amount of buffer we read, which is GetOffset, is not more

View File

@@ -33,7 +33,7 @@ CoreMessageFeatures CoreMessageFeatures::DefaultFeatures(
features.maximum_minor_version = 4; // 18.4
break;
case 19:
features.maximum_minor_version = 4; // 19.4
features.maximum_minor_version = 5; // 19.5
break;
default:
features.maximum_minor_version = 0;

View File

@@ -277,7 +277,7 @@ OEMCryptoResult ODK_InitializeSessionValues(ODK_TimerLimits* timer_limits,
nonce_values->api_minor_version = 4;
break;
case 19:
nonce_values->api_minor_version = 4;
nonce_values->api_minor_version = 5;
break;
default:
nonce_values->api_minor_version = 0;

File diff suppressed because it is too large Load Diff

View File

@@ -1275,7 +1275,7 @@ std::vector<VersionParameters> TestCases() {
{16, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 16, 5},
{17, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 17, 2},
{18, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 18, 4},
{19, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 19, 4},
{19, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 19, 5},
// Here are some known good versions. Make extra sure they work.
{ODK_MAJOR_VERSION, 16, 3, 16, 3},
{ODK_MAJOR_VERSION, 16, 4, 16, 4},
@@ -1290,6 +1290,7 @@ std::vector<VersionParameters> TestCases() {
{ODK_MAJOR_VERSION, 19, 2, 19, 2},
{ODK_MAJOR_VERSION, 19, 3, 19, 3},
{ODK_MAJOR_VERSION, 19, 4, 19, 4},
{ODK_MAJOR_VERSION, 19, 5, 19, 5},
{0, 16, 3, 16, 3},
{0, 16, 4, 16, 4},
{0, 16, 5, 16, 5},
@@ -1302,6 +1303,7 @@ std::vector<VersionParameters> TestCases() {
{0, 19, 2, 19, 2},
{0, 19, 3, 19, 3},
{0, 19, 4, 19, 4},
{0, 19, 5, 19, 5},
};
return test_cases;
}

View File

@@ -7,6 +7,7 @@
'odk_golden_v16.cpp',
'odk_golden_v17.cpp',
'odk_golden_v18.cpp',
'odk_golden_v19.cpp',
'odk_test.cpp',
'odk_test_helper.cpp',
'odk_test_helper.h',

View File

@@ -441,3 +441,12 @@ OEMCryptoResult _oecc155(OEMCrypto_SESSION session, uint32_t intent,
// OEMCrypto_GetBCCSignatureType defined in v19.4
OEMCryptoResult _oecc156(OEMCrypto_BCCSignatureType* bcc_signature_type);
// OEMCrypto_GetPVRKey defined in v18.9
OEMCryptoResult _oecc157(OEMCrypto_SESSION session, uint8_t* wrapped_pvr_key,
size_t* wrapped_pvr_key_length);
// OEMCrypto_LoadPVRKey defined in v18.9
OEMCryptoResult _oecc158(OEMCrypto_SESSION session,
const uint8_t* wrapped_pvr_key,
size_t wrapped_pvr_key_length);

View File

@@ -317,14 +317,14 @@ TEST_F(OEMCryptoClientTest, FreeUnallocatedSecureBufferNoFailure) {
*/
TEST_F(OEMCryptoClientTest, VersionNumber) {
const std::string log_message =
"OEMCrypto unit tests for API 19.4. Tests last updated 2024-11-04";
"OEMCrypto unit tests for API 19.5. Tests last updated 2025-03-11";
cout << " " << log_message << "\n";
cout << " " << "These tests are part of Android V." << "\n";
LOGI("%s", log_message.c_str());
// If any of the following fail, then it is time to update the log message
// above.
EXPECT_EQ(ODK_MAJOR_VERSION, 19);
EXPECT_EQ(ODK_MINOR_VERSION, 4);
EXPECT_EQ(ODK_MINOR_VERSION, 5);
EXPECT_EQ(kCurrentAPI, static_cast<unsigned>(ODK_MAJOR_VERSION));
RecordWvProperty("test_major_version", std::to_string(ODK_MAJOR_VERSION));
RecordWvProperty("test_minor_version", std::to_string(ODK_MINOR_VERSION));

View File

@@ -252,7 +252,13 @@ TEST_F(OEMCryptoProv40Test, GetBootCertificateChainSuccess) {
OEMCrypto_SUCCESS);
util::BccValidator validator;
EXPECT_EQ(util::CborMessageStatus::kCborParseOk, validator.Parse(bcc));
EXPECT_EQ(util::CborMessageStatus::kCborValidateOk, validator.Validate());
util::CborMessageStatus status = validator.Validate();
EXPECT_LT(status, util::CborMessageStatus::kCborValidateError);
if (status >= util::CborMessageStatus::kCborValidateError) {
const std::string parsed_bcc = validator.GetFormattedMessage();
LOGE("%s", parsed_bcc.c_str());
LOGE("Validation results\n%s", validator.PrintValidateMessage().c_str());
}
}
// Verifies BCC signature and its type if they are available.

View File

@@ -52,6 +52,7 @@ class CborValidator {
GetValidateMessages() const {
return validate_messages_;
}
std::string PrintValidateMessage() const;
// Prints |parse_result_| in readable format. Requires that Parse() is called
// first and |parse_result_| contains a valid CBOR message.
virtual std::string GetFormattedMessage() const;

View File

@@ -24,16 +24,20 @@ std::string StatusToString(FieldStatus status);
void ApplyStatus(CborMessageStatus& status, CborMessageStatus new_status);
// Validates that the given field name is present, and prints error messages
// if not.
// if not. It is acceptable that some field, although specified as required by
// DICE specification, is not present in practice. This function will return
// kCborValidateWarning instead of the default kCborValidateError in those
// cases.
template <typename T>
CborMessageStatus ValidateRequiredField(
const std::string& name, const std::string& component,
const std::pair<FieldStatus, T>& p,
std::vector<std::pair<CborMessageStatus, std::string>>& msgs) {
std::vector<std::pair<CborMessageStatus, std::string>>& msgs,
CborMessageStatus error = kCborValidateError) {
if (p.first != kPresent) {
msgs.push_back(std::make_pair(
kCborValidateError, component + ": missing required field " + name));
return kCborValidateError;
msgs.push_back(
std::make_pair(error, component + ": missing required field " + name));
return error;
}
return kCborValidateOk;
}

View File

@@ -245,8 +245,8 @@ CborMessageStatus ConfigurationDescriptor::Validate(
bool* is_widevine_entry) const {
CborMessageStatus status = kCborParseOk;
const std::string component = "ConfigurationDescriptor";
CborMessageStatus cur_status =
ValidateRequiredField("component_name", component, component_name, msgs);
CborMessageStatus cur_status = ValidateRequiredField(
"component_name", component, component_name, msgs, kCborValidateWarning);
ApplyStatus(status, cur_status);
if (cur_status == kCborValidateOk) {
std::string name = component_name.second;
@@ -299,14 +299,14 @@ CborMessageStatus BccEntryPayload::Validate(
if (!is_degenerated) {
cur_status = ValidateRequiredField("code_hash", component, code_hash, msgs);
ApplyStatus(status, cur_status);
cur_status =
ValidateRequiredField("config_hash", component, config_hash, msgs);
cur_status = ValidateRequiredField("config_hash", component, config_hash,
msgs, kCborValidateWarning);
ApplyStatus(status, cur_status);
if (config_descriptor.first == kAbsent) {
msgs.push_back(std::make_pair(
kCborValidateError,
kCborValidateWarning,
component + ": missing required field config_descriptor"));
ApplyStatus(status, kCborValidateError);
ApplyStatus(status, kCborValidateWarning);
} else {
cur_status = config_descriptor.second.Validate(msgs, is_widevine_entry);
ApplyStatus(status, cur_status);
@@ -393,9 +393,11 @@ CborMessageStatus Bcc::Validate(
if (is_widevine_entry) found_widevine_entry = true;
}
if (!is_degenerated && !found_widevine_entry) {
msgs.push_back(std::make_pair(kCborValidateError,
component + ": Widevine cert not found."));
ApplyStatus(status, kCborValidateError);
msgs.push_back(
std::make_pair(kCborValidateWarning,
component + ": Widevine cert not found. Expect a BCC "
"entry with component_name: widevine"));
ApplyStatus(status, kCborValidateWarning);
}
return status;
}
@@ -538,39 +540,45 @@ CborMessageStatus BccValidator::Validate() {
for (size_t i = 1; i < bcc_array->size(); ++i) {
const cppbor::Array* bcc_entry = (*bcc_array)[i]->asArray();
if (bcc_entry == nullptr) {
AddValidationMessage(kCborValidateError,
"BCC entry is empty at index " + std::to_string(i));
AddValidationMessage(kCborValidateWarning,
"BCC entry is empty at index " + std::to_string(i) +
". Skip current item.");
continue;
}
if (bcc_entry->size() != 4) {
AddValidationMessage(kCborValidateError,
AddValidationMessage(kCborValidateWarning,
"BCC entry index " + std::to_string(i) +
" should contain 4 items. Actual: " +
std::to_string(bcc_entry->size()));
std::to_string(bcc_entry->size()) +
". Skip current item.");
continue;
}
if ((*bcc_entry)[0]->type() != cppbor::BSTR) {
AddValidationMessage(kCborValidateError,
"BCC entry index " + std::to_string(i) +
" protected field is not a CBOR bstr.");
AddValidationMessage(
kCborValidateWarning,
"BCC entry index " + std::to_string(i) +
" protected field is not a CBOR bstr. Skip current item.");
continue;
}
if ((*bcc_entry)[1]->type() != cppbor::MAP) {
AddValidationMessage(kCborValidateError,
"BCC entry index " + std::to_string(i) +
" unprotected field is not a CBOR map.");
AddValidationMessage(
kCborValidateWarning,
"BCC entry index " + std::to_string(i) +
" unprotected field is not a CBOR map. Skip current item.");
continue;
}
if ((*bcc_entry)[2]->type() != cppbor::BSTR) {
AddValidationMessage(kCborValidateError,
"BCC entry index " + std::to_string(i) +
" payload field is not a CBOR bstr.");
AddValidationMessage(
kCborValidateWarning,
"BCC entry index " + std::to_string(i) +
" payload field is not a CBOR bstr. Skip current item.");
continue;
}
if ((*bcc_entry)[3]->type() != cppbor::BSTR) {
AddValidationMessage(kCborValidateError,
"BCC entry index " + std::to_string(i) +
" signature field is not a CBOR bstr.");
AddValidationMessage(
kCborValidateWarning,
"BCC entry index " + std::to_string(i) +
" signature field is not a CBOR bstr. Skip current item.");
continue;
}
@@ -578,9 +586,9 @@ CborMessageStatus BccValidator::Validate() {
const std::vector<uint8_t>& encoded_protected_data =
(*bcc_entry)[0]->asBstr()->value();
if (encoded_protected_data.empty()) {
AddValidationMessage(
kCborValidateError,
"BCC entry index " + std::to_string(i) + " empty protected data.");
AddValidationMessage(kCborValidateWarning,
"BCC entry index " + std::to_string(i) +
" empty protected data. Skip current item.");
continue;
}
auto parse_result = cppbor::parse(encoded_protected_data);
@@ -588,23 +596,25 @@ CborMessageStatus BccValidator::Validate() {
std::move(std::get<0>(parse_result));
std::string error_message = std::move(std::get<2>(parse_result));
if (sub_item == nullptr || !error_message.empty()) {
AddValidationMessage(kCborValidateError,
AddValidationMessage(kCborValidateWarning,
"BCC entry index " + std::to_string(i) +
" unable to parse protected: " + error_message);
" unable to parse protected: " + error_message +
" Skip current item.");
continue;
}
if (sub_item->type() != cppbor::MAP) {
AddValidationMessage(kCborValidateError,
AddValidationMessage(kCborValidateWarning,
"BCC entry index " + std::to_string(i) +
" unexpected protected type: " +
CppborMajorTypeToString(sub_item->type()));
CppborMajorTypeToString(sub_item->type()) +
". Skip current item.");
continue;
}
const cppbor::Map* protected_map = sub_item->asMap();
if (protected_map == nullptr) {
AddValidationMessage(
kCborValidateError,
"BCC entry index " + std::to_string(i) + " protected map is null.");
AddValidationMessage(kCborValidateWarning,
"BCC entry index " + std::to_string(i) +
" protected map is null. Skip current item.");
continue;
}
BccEntry entry;
@@ -614,9 +624,7 @@ CborMessageStatus BccValidator::Validate() {
status =
ProcessBccEntryProtected(protected_map, &entry.protected_data.second);
if (status == kCborValidateFatal) return status;
if (status != kCborValidateError) {
entry.protected_data.first = kPresent;
}
entry.protected_data.first = kPresent;
}
// Unprotected data in BCC entry is always empty, which is ignored.
entry.unprotected.first = kEmpty;
@@ -645,9 +653,9 @@ CborMessageStatus BccValidator::Validate() {
// Parse and verify the payload
if (encoded_payload.empty()) {
AddValidationMessage(
kCborValidateError,
"BCC entry index " + std::to_string(i) + " empty payload.");
AddValidationMessage(kCborValidateWarning,
"BCC entry index " + std::to_string(i) +
" empty payload. Skip current item.");
continue;
}
parse_result = cppbor::parse(encoded_payload);
@@ -655,24 +663,26 @@ CborMessageStatus BccValidator::Validate() {
std::move(std::get<0>(parse_result));
error_message = std::move(std::get<2>(parse_result));
if (sub_item_payload == nullptr || !error_message.empty()) {
AddValidationMessage(kCborValidateError,
AddValidationMessage(kCborValidateWarning,
"BCC entry index " + std::to_string(i) +
" unable to parse payload: " + error_message);
" unable to parse payload: " + error_message +
" Skip current item.");
continue;
}
if (sub_item_payload->type() != cppbor::MAP) {
AddValidationMessage(
kCborValidateError,
kCborValidateWarning,
"BCC entry index " + std::to_string(i) +
" unexpected payload type: " +
CppborMajorTypeToString(sub_item_payload->type()));
CppborMajorTypeToString(sub_item_payload->type()) +
". Skip current item.");
continue;
}
const cppbor::Map* payload_map = sub_item_payload->asMap();
if (payload_map == nullptr) {
AddValidationMessage(
kCborValidateError,
"BCC entry index " + std::to_string(i) + " payload is empty.");
AddValidationMessage(kCborValidateWarning,
"BCC entry index " + std::to_string(i) +
" payload is empty. Skip current item.");
continue;
}
if (payload_map->size() == 0) {
@@ -680,10 +690,8 @@ CborMessageStatus BccValidator::Validate() {
} else {
status = ProcessDiceChainEntryPayload(payload_map, &entry.payload.second);
if (status == kCborValidateFatal) return status;
if (status != kCborValidateError) {
entry.payload.first = kPresent;
leaf_pub_key = entry.payload.second.subject_public_key.second;
}
entry.payload.first = kPresent;
leaf_pub_key = entry.payload.second.subject_public_key.second;
}
bcc.entries.push_back(std::move(entry));
}
@@ -704,6 +712,7 @@ CborMessageStatus BccValidator::Validate() {
CborMessageStatus BccValidator::ProcessConfigurationDescriptor(
const cppbor::Map* config_descriptor_map, ConfigurationDescriptor* cd) {
CborMessageStatus status = kCborValidateOk;
for (size_t index = 0; index < config_descriptor_map->size(); ++index) {
std::pair<const std::unique_ptr<cppbor::Item>&,
const std::unique_ptr<cppbor::Item>&>
@@ -711,9 +720,11 @@ CborMessageStatus BccValidator::ProcessConfigurationDescriptor(
if (entry.first->type() != cppbor::NINT &&
entry.first->type() != cppbor::UINT) {
AddValidationMessage(
kCborValidateError,
kCborValidateWarning,
"Invalid key type in configuration descriptor map: " +
CppborMajorTypeToString(entry.first->type()));
CppborMajorTypeToString(entry.first->type()) +
". Skip current item.");
ApplyStatus(status, kCborValidateWarning);
continue;
}
const int64_t map_key = entry.first->asInt()->value();
@@ -721,10 +732,12 @@ CborMessageStatus BccValidator::ProcessConfigurationDescriptor(
case kComponentNameLabel: {
if (entry.second->type() != cppbor::TSTR) {
AddValidationMessage(
kCborValidateError,
kCborValidateWarning,
"Invalid value type in configuration descriptor map for "
"key component name: " +
CppborMajorTypeToString(entry.second->type()));
CppborMajorTypeToString(entry.second->type()) +
". Skip current item.");
ApplyStatus(status, kCborValidateWarning);
continue;
}
cd->component_name.second = entry.second->asTstr()->value();
@@ -742,10 +755,12 @@ CborMessageStatus BccValidator::ProcessConfigurationDescriptor(
cd->component_version.first = kPresent;
} else {
AddValidationMessage(
kCborValidateError,
kCborValidateWarning,
"Invalid value type in configuration descriptor map for "
"component version: " +
CppborMajorTypeToString(entry.second->type()));
CppborMajorTypeToString(entry.second->type()) +
". Skip current item.");
ApplyStatus(status, kCborValidateWarning);
continue;
}
} break;
@@ -759,7 +774,9 @@ CborMessageStatus BccValidator::ProcessConfigurationDescriptor(
kCborValidateError,
"Invalid value type in configuration descriptor map for "
"security version: " +
CppborMajorTypeToString(entry.second->type()));
CppborMajorTypeToString(entry.second->type()) +
". Skip current item.");
ApplyStatus(status, kCborValidateWarning);
continue;
} else {
cd->security_version.second = entry.second->asUint()->value();
@@ -772,11 +789,12 @@ CborMessageStatus BccValidator::ProcessConfigurationDescriptor(
}
}
}
return message_status_;
return status;
}
CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo(
const cppbor::Map* public_key_map, BccPublicKeyInfo* public_key) {
CborMessageStatus status = kCborValidateOk;
std::vector<uint8_t> device_key_bytes_0;
std::vector<uint8_t> device_key_bytes_1;
for (size_t index = 0; index < public_key_map->size(); ++index) {
@@ -787,7 +805,9 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo(
entry.first->type() != cppbor::UINT) {
AddValidationMessage(kCborValidateError,
"Invalid key type in public key info map: " +
CppborMajorTypeToString(entry.first->type()));
CppborMajorTypeToString(entry.first->type()) +
". Skip current item.");
ApplyStatus(status, kCborValidateError);
continue;
}
const int64_t map_key = entry.first->asInt()->value();
@@ -798,7 +818,9 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo(
kCborValidateError,
"Invalid value type in public key info map for "
"key MAP_KEY_DEVICE_KEY_TYPE: " +
CppborMajorTypeToString(entry.second->type()));
CppborMajorTypeToString(entry.second->type()) +
". Skip current item.");
ApplyStatus(status, kCborValidateError);
continue;
}
public_key->key_type.first = kPresent;
@@ -812,7 +834,10 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo(
AddValidationMessage(kCborValidateError,
"Invalid value in public key info map for key "
"MAP_KEY_DEVICE_KEY_TYPE: " +
std::to_string(value));
std::to_string(value) +
". Skip current item.");
ApplyStatus(status, kCborValidateError);
continue;
}
} break;
case MAP_KEY_DEVICE_KEY_ALGORITHM: {
@@ -821,7 +846,9 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo(
kCborValidateError,
"Invalid value type in public key info map for "
"key MAP_KEY_DEVICE_KEY_ALGORITHM: " +
CppborMajorTypeToString(entry.second->type()));
CppborMajorTypeToString(entry.second->type()) +
". Skip current item.");
ApplyStatus(status, kCborValidateError);
continue;
}
public_key->signature_algorithm.first = kPresent;
@@ -837,7 +864,10 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo(
AddValidationMessage(kCborValidateError,
"Invalid value in public key info map for key "
"MAP_KEY_DEVICE_KEY_ALGORITHM: " +
std::to_string(value));
std::to_string(value) +
". Skip current item.");
ApplyStatus(status, kCborValidateError);
continue;
}
} break;
case MAP_KEY_DEVICE_KEY_OPS:
@@ -849,7 +879,9 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo(
kCborValidateError,
"Invalid value type in public key info map for "
"key MAP_KEY_DEVICE_KEY_CURVE: " +
CppborMajorTypeToString(entry.second->type()));
CppborMajorTypeToString(entry.second->type()) +
". Skip current item.");
ApplyStatus(status, kCborValidateError);
continue;
}
public_key->curve.first = kPresent;
@@ -865,7 +897,10 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo(
AddValidationMessage(kCborValidateError,
"Invalid value in public key info map for key "
"MAP_KEY_DEVICE_KEY_CURVE: " +
std::to_string(value));
std::to_string(value) +
". Skip current item.");
ApplyStatus(status, kCborValidateError);
continue;
}
} break;
case MAP_KEY_DEVICE_KEY_BYTES_0:
@@ -877,7 +912,9 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo(
kCborValidateError,
"Invalid value type in public key info map for "
"key MAP_KEY_DEVICE_KEY_BYTES_0/1: " +
CppborMajorTypeToString(entry.second->type()));
CppborMajorTypeToString(entry.second->type()) +
". Skip current item.");
ApplyStatus(status, kCborValidateError);
continue;
}
const std::vector<uint8_t>& key_bytes = entry.second->asBstr()->value();
@@ -887,7 +924,9 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo(
key_bytes.size() != kP384KeyComponentSize) {
AddValidationMessage(kCborValidateError,
"Malformed public key data size of: " +
std::to_string(key_bytes.size()));
std::to_string(key_bytes.size()) +
". Skip current item.");
ApplyStatus(status, kCborValidateError);
continue;
}
public_key->key_bytes.first = kPresent;
@@ -904,7 +943,8 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo(
AddValidationMessage(
kCborValidateError,
"Malformed public key definition. Missing device public key bytes.");
return message_status_;
ApplyStatus(status, kCborValidateError);
return status;
}
std::vector<uint8_t> device_key_bytes;
if (public_key->key_type.second == DEVICE_KEY_OCTET_PAIR) {
@@ -921,7 +961,8 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo(
AddValidationMessage(kCborValidateError,
"Invalid ECDSA public key size: " +
std::to_string(device_key_bytes.size()));
return message_status_;
ApplyStatus(status, kCborValidateError);
return status;
}
} else {
device_key_bytes = std::move(device_key_bytes_0);
@@ -930,11 +971,12 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo(
if (public_key->key_bytes.second.empty()) {
public_key->key_bytes.first = kEmpty;
}
return message_status_;
return status;
}
CborMessageStatus BccValidator::ProcessBccEntryProtected(
const cppbor::Map* protected_map, BccEntryProtected* protected_data) {
CborMessageStatus status = kCborValidateOk;
for (size_t index = 0; index < protected_map->size(); ++index) {
std::pair<const std::unique_ptr<cppbor::Item>&,
const std::unique_ptr<cppbor::Item>&>
@@ -942,9 +984,11 @@ CborMessageStatus BccValidator::ProcessBccEntryProtected(
if (entry.first->type() != cppbor::NINT &&
entry.first->type() != cppbor::UINT) {
AddValidationMessage(
kCborValidateError,
kCborValidateWarning,
"Invalid key type in protected data map in bcc entry: " +
CppborMajorTypeToString(entry.first->type()));
CppborMajorTypeToString(entry.first->type()) +
". Skip current item.");
ApplyStatus(status, kCborValidateWarning);
continue;
}
const int64_t map_key = entry.first->asInt()->value();
@@ -953,10 +997,12 @@ CborMessageStatus BccValidator::ProcessBccEntryProtected(
if (entry.second->type() != cppbor::NINT &&
entry.second->type() != cppbor::UINT) {
AddValidationMessage(
kCborValidateError,
kCborValidateWarning,
"Invalid value type in protected data map for "
"key 1: " +
CppborMajorTypeToString(entry.second->type()));
CppborMajorTypeToString(entry.second->type()) +
". Skip current item.");
ApplyStatus(status, kCborValidateWarning);
continue;
}
protected_data->algorithm.first = kPresent;
@@ -964,11 +1010,12 @@ CborMessageStatus BccValidator::ProcessBccEntryProtected(
} break;
}
}
return message_status_;
return status;
}
CborMessageStatus BccValidator::ProcessDiceChainEntryPayload(
const cppbor::Map* payload_map, BccEntryPayload* payload) {
CborMessageStatus status = kCborValidateOk;
for (size_t i = 0; i < payload_map->size(); ++i) {
const auto& entry = (*payload_map)[i];
if (entry.first == nullptr || entry.first->asInt() == nullptr ||
@@ -991,7 +1038,9 @@ CborMessageStatus BccValidator::ProcessDiceChainEntryPayload(
} else if (key == kSubjectPublicKeyLabel) {
const auto& value = entry.second->asBstr()->value();
if (value.empty()) {
AddValidationMessage(kCborValidateError, "Empty public key.");
AddValidationMessage(kCborValidateWarning,
"Empty public key. Skip current item.");
ApplyStatus(status, kCborValidateWarning);
continue;
}
auto parse_result = cppbor::parse(value);
@@ -999,14 +1048,18 @@ CborMessageStatus BccValidator::ProcessDiceChainEntryPayload(
std::move(std::get<0>(parse_result));
std::string error_message = std::move(std::get<2>(parse_result));
if (sub_item == nullptr || !error_message.empty()) {
AddValidationMessage(kCborValidateError,
"Unable to parse public key: " + error_message);
AddValidationMessage(kCborValidateWarning,
"Unable to parse public key: " + error_message +
" Skip current item.");
ApplyStatus(status, kCborValidateWarning);
continue;
}
if (sub_item->type() != cppbor::MAP || sub_item->asMap() == nullptr) {
AddValidationMessage(kCborValidateError,
AddValidationMessage(kCborValidateWarning,
"Unexpected public key type: " +
CppborMajorTypeToString(sub_item->type()));
CppborMajorTypeToString(sub_item->type()) +
". Skip current item.");
ApplyStatus(status, kCborValidateWarning);
continue;
}
const cppbor::Map* public_key_map = sub_item->asMap();
@@ -1014,9 +1067,10 @@ CborMessageStatus BccValidator::ProcessDiceChainEntryPayload(
payload->subject_public_key.first = kEmpty;
} else {
payload->subject_public_key.first = kPresent;
CborMessageStatus status = ProcessSubjectPublicKeyInfo(
CborMessageStatus cur_status = ProcessSubjectPublicKeyInfo(
public_key_map, &(payload->subject_public_key.second));
if (status == kCborValidateFatal) return status;
if (cur_status == kCborValidateFatal) return cur_status;
ApplyStatus(status, cur_status);
}
} else if (key == kKeyUsageLabel) {
payload->key_usage.second = entry.second->asBstr()->value();
@@ -1037,8 +1091,10 @@ CborMessageStatus BccValidator::ProcessDiceChainEntryPayload(
} else if (key == kConfigurationDescriptorLabel) {
const auto& encoded_cd = entry.second->asBstr()->value();
if (encoded_cd.empty()) {
AddValidationMessage(kCborValidateError,
"Empty configuration descriptor.");
AddValidationMessage(
kCborValidateWarning,
"Empty configuration descriptor. Skip current item.");
ApplyStatus(status, kCborValidateWarning);
continue;
}
auto parse_result = cppbor::parse(encoded_cd);
@@ -1046,15 +1102,18 @@ CborMessageStatus BccValidator::ProcessDiceChainEntryPayload(
std::move(std::get<0>(parse_result));
std::string error_message = std::move(std::get<2>(parse_result));
if (sub_item == nullptr || !error_message.empty()) {
AddValidationMessage(
kCborValidateError,
"Unable to parse configuration descriptor: " + error_message);
AddValidationMessage(kCborValidateWarning,
"Unable to parse configuration descriptor: " +
error_message + " Skip current item.");
ApplyStatus(status, kCborValidateWarning);
continue;
}
if (sub_item->type() != cppbor::MAP) {
AddValidationMessage(kCborValidateError,
AddValidationMessage(kCborValidateWarning,
"Unexpected configuration descriptor type: " +
CppborMajorTypeToString(sub_item->type()));
CppborMajorTypeToString(sub_item->type()) +
". Skip current item.");
ApplyStatus(status, kCborValidateWarning);
continue;
}
const cppbor::Map* config_descriptor_map = sub_item->asMap();
@@ -1063,12 +1122,11 @@ CborMessageStatus BccValidator::ProcessDiceChainEntryPayload(
// OK, configuration descriptor is optional.
payload->config_descriptor.first = kEmpty;
} else {
CborMessageStatus status = ProcessConfigurationDescriptor(
CborMessageStatus cur_status = ProcessConfigurationDescriptor(
config_descriptor_map, &(payload->config_descriptor.second));
if (status == kCborValidateFatal) return status;
if (status != kCborValidateError) {
payload->config_descriptor.first = kPresent;
}
if (cur_status == kCborValidateFatal) return cur_status;
ApplyStatus(status, cur_status);
payload->config_descriptor.first = kPresent;
}
} else if (key == kAuthorityHashLabel) {
payload->authority_hash.second = entry.second->asBstr()->value();
@@ -1083,7 +1141,7 @@ CborMessageStatus BccValidator::ProcessDiceChainEntryPayload(
payload->mode.first = payload->mode.second.empty() ? kEmpty : kPresent;
}
}
return message_status_;
return status;
}
std::string BccValidator::GetFormattedMessage() const {

View File

@@ -98,6 +98,14 @@ std::string CborValidator::GetFormattedMessage() const {
return GetRawMessage();
}
std::string CborValidator::PrintValidateMessage() const {
std::stringstream ss;
for (auto& msg : validate_messages_) {
ss << CborMessageStatusToString(msg.first) << ": " << msg.second << "\n";
}
return ss.str();
}
void CborValidator::AddValidationMessage(CborMessageStatus status,
const std::string& msg) {
validate_messages_.push_back({status, msg});

View File

@@ -234,9 +234,7 @@ const std::vector<uint8_t> kBccMissingIssuer = {
static void DumpValidatorOutput(const BccValidator& validator) {
const std::string out = validator.GetFormattedMessage();
LOGI("%s", out.c_str());
for (auto& msg : validator.GetValidateMessages()) {
LOGE("Error code %d: %s", msg.first, msg.second.c_str());
}
LOGE("Validation results\n%s", validator.PrintValidateMessage().c_str());
}
TEST(OEMCryptoBccValidatorTest, BccParseError) {

View File

@@ -65,9 +65,7 @@ std::vector<uint8_t> BuildDeviceInfo(int version) {
static void DumpValidatorOutput(const DeviceInfoValidator& validator) {
const std::string out = validator.GetFormattedMessage();
LOGI("%s", out.c_str());
for (auto& msg : validator.GetValidateMessages()) {
LOGE("Error code %d: %s", msg.first, msg.second.c_str());
}
LOGE("Validation results\n%s", validator.PrintValidateMessage().c_str());
}
TEST(OEMCryptoDeviceInfoValidatorTest, DeviceInfoParseError) {

View File

@@ -91,9 +91,7 @@ std::vector<uint8_t> GetDefaultSignedCsrPayload() {
static void DumpValidatorOutput(const SignedCsrPayloadValidator& validator) {
const std::string out = validator.GetFormattedMessage();
LOGI("%s", out.c_str());
for (auto& msg : validator.GetValidateMessages()) {
LOGE("Error code %d: %s", msg.first, msg.second.c_str());
}
LOGE("Validation results\n%s", validator.PrintValidateMessage().c_str());
}
} // namespace