KeyMint: add VTS test with all IDs am: ef1123b24e
Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/3106417 Change-Id: Icfc31847731c3ca48492234751033d4be8ada033 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
acb80cfdf2
4 changed files with 151 additions and 57 deletions
|
@ -16,7 +16,6 @@
|
|||
|
||||
#define LOG_TAG "keymint_1_attest_key_test"
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <cutils/log.h>
|
||||
#include <cutils/properties.h>
|
||||
|
||||
|
@ -29,66 +28,12 @@
|
|||
namespace aidl::android::hardware::security::keymint::test {
|
||||
|
||||
namespace {
|
||||
string TELEPHONY_CMD_GET_IMEI = "cmd phone get-imei ";
|
||||
|
||||
bool IsSelfSigned(const vector<Certificate>& chain) {
|
||||
if (chain.size() != 1) return false;
|
||||
return ChainSignaturesAreValid(chain);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run a shell command and collect the output of it. If any error, set an empty string as the
|
||||
* output.
|
||||
*/
|
||||
string exec_command(string command) {
|
||||
char buffer[128];
|
||||
string result = "";
|
||||
|
||||
FILE* pipe = popen(command.c_str(), "r");
|
||||
if (!pipe) {
|
||||
LOG(ERROR) << "popen failed.";
|
||||
return result;
|
||||
}
|
||||
|
||||
// read till end of process:
|
||||
while (!feof(pipe)) {
|
||||
if (fgets(buffer, 128, pipe) != NULL) {
|
||||
result += buffer;
|
||||
}
|
||||
}
|
||||
|
||||
pclose(pipe);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get IMEI using Telephony service shell command. If any error while executing the command
|
||||
* then empty string will be returned as output.
|
||||
*/
|
||||
string get_imei(int slot) {
|
||||
string cmd = TELEPHONY_CMD_GET_IMEI + std::to_string(slot);
|
||||
string output = exec_command(cmd);
|
||||
|
||||
if (output.empty()) {
|
||||
LOG(ERROR) << "Command failed. Cmd: " << cmd;
|
||||
return "";
|
||||
}
|
||||
|
||||
vector<string> out = ::android::base::Tokenize(::android::base::Trim(output), "Device IMEI:");
|
||||
|
||||
if (out.size() != 1) {
|
||||
LOG(ERROR) << "Error in parsing the command output. Cmd: " << cmd;
|
||||
return "";
|
||||
}
|
||||
|
||||
string imei = ::android::base::Trim(out[0]);
|
||||
if (imei.compare("null") == 0) {
|
||||
LOG(WARNING) << "Failed to get IMEI from Telephony service: value is null. Cmd: " << cmd;
|
||||
return "";
|
||||
}
|
||||
|
||||
return imei;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class AttestKeyTest : public KeyMintAidlTestBase {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "keymint_support/keymint_tags.h"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <android/binder_manager.h>
|
||||
#include <android/content/pm/IPackageManagerNative.h>
|
||||
#include <cppbor_parse.h>
|
||||
|
@ -1588,7 +1589,7 @@ ErrorCode KeyMintAidlTestBase::GenerateAttestKey(const AuthorizationSet& key_des
|
|||
// with any other key purpose, but the original VTS tests incorrectly did exactly that.
|
||||
// This means that a device that launched prior to Android T (API level 33) may
|
||||
// accept or even require KeyPurpose::SIGN too.
|
||||
if (property_get_int32("ro.board.first_api_level", 0) < __ANDROID_API_T__) {
|
||||
if (get_vsr_api_level() < __ANDROID_API_T__) {
|
||||
AuthorizationSet key_desc_plus_sign = key_desc;
|
||||
key_desc_plus_sign.push_back(TAG_PURPOSE, KeyPurpose::SIGN);
|
||||
|
||||
|
@ -2337,6 +2338,67 @@ std::optional<int32_t> keymint_feature_value(bool strongbox) {
|
|||
return result;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
std::string TELEPHONY_CMD_GET_IMEI = "cmd phone get-imei ";
|
||||
|
||||
/*
|
||||
* Run a shell command and collect the output of it. If any error, set an empty string as the
|
||||
* output.
|
||||
*/
|
||||
std::string exec_command(const std::string& command) {
|
||||
char buffer[128];
|
||||
std::string result = "";
|
||||
|
||||
FILE* pipe = popen(command.c_str(), "r");
|
||||
if (!pipe) {
|
||||
LOG(ERROR) << "popen failed.";
|
||||
return result;
|
||||
}
|
||||
|
||||
// read till end of process:
|
||||
while (!feof(pipe)) {
|
||||
if (fgets(buffer, 128, pipe) != NULL) {
|
||||
result += buffer;
|
||||
}
|
||||
}
|
||||
|
||||
pclose(pipe);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/*
|
||||
* Get IMEI using Telephony service shell command. If any error while executing the command
|
||||
* then empty string will be returned as output.
|
||||
*/
|
||||
std::string get_imei(int slot) {
|
||||
std::string cmd = TELEPHONY_CMD_GET_IMEI + std::to_string(slot);
|
||||
std::string output = exec_command(cmd);
|
||||
|
||||
if (output.empty()) {
|
||||
LOG(ERROR) << "Command failed. Cmd: " << cmd;
|
||||
return "";
|
||||
}
|
||||
|
||||
vector<std::string> out =
|
||||
::android::base::Tokenize(::android::base::Trim(output), "Device IMEI:");
|
||||
|
||||
if (out.size() != 1) {
|
||||
LOG(ERROR) << "Error in parsing the command output. Cmd: " << cmd;
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string imei = ::android::base::Trim(out[0]);
|
||||
if (imei.compare("null") == 0) {
|
||||
LOG(WARNING) << "Failed to get IMEI from Telephony service: value is null. Cmd: " << cmd;
|
||||
return "";
|
||||
}
|
||||
|
||||
return imei;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
} // namespace aidl::android::hardware::security::keymint
|
||||
|
|
|
@ -430,6 +430,7 @@ void p256_pub_key(const vector<uint8_t>& coseKeyData, EVP_PKEY_Ptr* signingKey);
|
|||
void device_id_attestation_check_acceptable_error(Tag tag, const ErrorCode& result);
|
||||
bool check_feature(const std::string& name);
|
||||
std::optional<int32_t> keymint_feature_value(bool strongbox);
|
||||
std::string get_imei(int slot);
|
||||
|
||||
AuthorizationSet HwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
|
||||
AuthorizationSet SwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
|
||||
|
|
|
@ -2026,7 +2026,7 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestationTags) {
|
|||
* NewKeyGenerationTest.EcdsaAttestationIdTags
|
||||
*
|
||||
* Verifies that creation of an attested ECDSA key includes various ID tags in the
|
||||
* attestation extension.
|
||||
* attestation extension one by one.
|
||||
*/
|
||||
TEST_P(NewKeyGenerationTest, EcdsaAttestationIdTags) {
|
||||
auto challenge = "hello";
|
||||
|
@ -2054,6 +2054,15 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestationIdTags) {
|
|||
add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_MANUFACTURER, "manufacturer");
|
||||
add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_MODEL, "model");
|
||||
add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
|
||||
string imei = get_imei(0);
|
||||
if (!imei.empty()) {
|
||||
extra_tags.Authorization(TAG_ATTESTATION_ID_IMEI, imei.data(), imei.size());
|
||||
}
|
||||
string second_imei = get_imei(1);
|
||||
if (!second_imei.empty()) {
|
||||
extra_tags.Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, second_imei.data(),
|
||||
second_imei.size());
|
||||
}
|
||||
|
||||
for (const KeyParameter& tag : extra_tags) {
|
||||
SCOPED_TRACE(testing::Message() << "tag-" << tag);
|
||||
|
@ -2090,6 +2099,83 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestationIdTags) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* NewKeyGenerationTest.EcdsaAttestationIdAllTags
|
||||
*
|
||||
* Verifies that creation of an attested ECDSA key includes various ID tags in the
|
||||
* attestation extension all together.
|
||||
*/
|
||||
TEST_P(NewKeyGenerationTest, EcdsaAttestationIdAllTags) {
|
||||
auto challenge = "hello";
|
||||
auto app_id = "foo";
|
||||
auto subject = "cert subj 2";
|
||||
vector<uint8_t> subject_der(make_name_from_str(subject));
|
||||
uint64_t serial_int = 0x1010;
|
||||
vector<uint8_t> serial_blob(build_serial_blob(serial_int));
|
||||
AuthorizationSetBuilder builder = AuthorizationSetBuilder()
|
||||
.Authorization(TAG_NO_AUTH_REQUIRED)
|
||||
.EcdsaSigningKey(EcCurve::P_256)
|
||||
.Digest(Digest::NONE)
|
||||
.AttestationChallenge(challenge)
|
||||
.AttestationApplicationId(app_id)
|
||||
.Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
|
||||
.Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
|
||||
.SetDefaultValidity();
|
||||
|
||||
// Various ATTESTATION_ID_* tags that map to fields in the attestation extension ASN.1 schema.
|
||||
auto extra_tags = AuthorizationSetBuilder();
|
||||
add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_BRAND, "brand");
|
||||
add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_DEVICE, "device");
|
||||
add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_PRODUCT, "name");
|
||||
add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_MANUFACTURER, "manufacturer");
|
||||
add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_MODEL, "model");
|
||||
add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
|
||||
string imei = get_imei(0);
|
||||
if (!imei.empty()) {
|
||||
extra_tags.Authorization(TAG_ATTESTATION_ID_IMEI, imei.data(), imei.size());
|
||||
}
|
||||
string second_imei = get_imei(1);
|
||||
if (!second_imei.empty()) {
|
||||
extra_tags.Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, second_imei.data(),
|
||||
second_imei.size());
|
||||
}
|
||||
for (const KeyParameter& tag : extra_tags) {
|
||||
builder.push_back(tag);
|
||||
}
|
||||
|
||||
vector<uint8_t> key_blob;
|
||||
vector<KeyCharacteristics> key_characteristics;
|
||||
auto result = GenerateKey(builder, &key_blob, &key_characteristics);
|
||||
if (result == ErrorCode::CANNOT_ATTEST_IDS && !isDeviceIdAttestationRequired()) {
|
||||
// ID attestation was optional till api level 32, from api level 33 it is mandatory.
|
||||
return;
|
||||
}
|
||||
ASSERT_EQ(result, ErrorCode::OK);
|
||||
KeyBlobDeleter deleter(keymint_, key_blob);
|
||||
ASSERT_GT(key_blob.size(), 0U);
|
||||
|
||||
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
|
||||
ASSERT_GT(cert_chain_.size(), 0);
|
||||
verify_subject_and_serial(cert_chain_[0], serial_int, subject, /* self_signed = */ false);
|
||||
|
||||
AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
|
||||
AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
|
||||
|
||||
// The attested key characteristics will not contain APPLICATION_ID_* fields (their
|
||||
// spec definitions all have "Must never appear in KeyCharacteristics"), but the
|
||||
// attestation extension should contain them, so make sure the extra tags are added.
|
||||
for (const KeyParameter& tag : extra_tags) {
|
||||
hw_enforced.push_back(tag);
|
||||
}
|
||||
|
||||
// Verifying the attestation record will check for the specific tag because
|
||||
// it's included in the authorizations.
|
||||
EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id, sw_enforced,
|
||||
hw_enforced, SecLevel(),
|
||||
cert_chain_[0].encodedCertificate))
|
||||
<< "failed to verify " << bin2hex(cert_chain_[0].encodedCertificate);
|
||||
}
|
||||
|
||||
/*
|
||||
* NewKeyGenerationTest.EcdsaAttestationUniqueId
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue