Add KeyPurpose::ATTEST_KEY.

This allows applications to generate their own attestation keys and
then use them to attest other application-generated keys.

Bug: 171845652
Test: VtsAidlKeyMintTargetTest
Change-Id: I32add16dcc2d1b29665a88024610f7bef7e50200
This commit is contained in:
Shawn Willden
2020-12-21 09:58:22 -07:00
parent 0ace84a193
commit 7c13039711
18 changed files with 740 additions and 356 deletions

View File

@@ -833,9 +833,16 @@ bool parseAsn1Time(const ASN1_TIME* asn1Time, time_t* outTime) {
optional<vector<vector<uint8_t>>> createAttestation(
const EVP_PKEY* key, const vector<uint8_t>& applicationId, const vector<uint8_t>& challenge,
uint64_t activeTimeMilliSeconds, uint64_t expireTimeMilliSeconds, bool isTestCredential) {
// Pretend to be implemented in a trusted environment just so we can pass
// the VTS tests. Of course, this is a pretend-only game since hopefully no
// relying party is ever going to trust our batch key and those keys above
// it.
::keymaster::PureSoftKeymasterContext context(::keymaster::KmVersion::KEYMASTER_4_1,
KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT);
keymaster_error_t error;
::keymaster::CertificateChain attestation_chain =
::keymaster::getAttestationChain(KM_ALGORITHM_EC, &error);
context.GetAttestationChain(KM_ALGORITHM_EC, &error);
if (KM_ERROR_OK != error) {
LOG(ERROR) << "Error getting attestation chain " << error;
return {};
@@ -855,12 +862,6 @@ optional<vector<vector<uint8_t>>> createAttestation(
}
expireTimeMilliSeconds = bcNotAfter * 1000;
}
const keymaster_key_blob_t* attestation_signing_key =
::keymaster::getAttestationKey(KM_ALGORITHM_EC, nullptr);
if (attestation_signing_key == nullptr) {
LOG(ERROR) << "Error getting attestation key";
return {};
}
::keymaster::X509_NAME_Ptr subjectName;
if (KM_ERROR_OK !=
@@ -917,16 +918,8 @@ optional<vector<vector<uint8_t>>> createAttestation(
}
::keymaster::AuthorizationSet hwEnforced(hwEnforcedBuilder);
// Pretend to be implemented in a trusted environment just so we can pass
// the VTS tests. Of course, this is a pretend-only game since hopefully no
// relying party is ever going to trust our batch key and those keys above
// it.
::keymaster::PureSoftKeymasterContext context(::keymaster::KmVersion::KEYMINT_1,
KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT);
::keymaster::CertificateChain cert_chain_out = generate_attestation_from_EVP(
key, swEnforced, hwEnforced, auth_set, context, move(attestation_chain),
*attestation_signing_key, &error);
::keymaster::CertificateChain cert_chain_out = generate_attestation(
key, swEnforced, hwEnforced, auth_set, {} /* attest_key */, context, &error);
if (KM_ERROR_OK != error) {
LOG(ERROR) << "Error generating attestation from EVP key: " << error;

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.security.keymint;
@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
parcelable AttestationKey {
byte[] keyBlob;
android.hardware.security.keymint.KeyParameter[] attestKeyParams;
byte[] issuerSubjectName;
}

View File

@@ -113,6 +113,8 @@ enum ErrorCode {
UNSUPPORTED_MGF_DIGEST = -79,
MISSING_NOT_BEFORE = -80,
MISSING_NOT_AFTER = -81,
MISSING_ISSUER_SUBJECT = -82,
INVALID_ISSUER_SUBJECT = -83,
UNIMPLEMENTED = -100,
VERSION_MISMATCH = -101,
UNKNOWN_ERROR = -1000,

View File

@@ -35,14 +35,14 @@ package android.hardware.security.keymint;
interface IKeyMintDevice {
android.hardware.security.keymint.KeyMintHardwareInfo getHardwareInfo();
void addRngEntropy(in byte[] data);
android.hardware.security.keymint.KeyCreationResult generateKey(in android.hardware.security.keymint.KeyParameter[] keyParams);
android.hardware.security.keymint.KeyCreationResult importKey(in android.hardware.security.keymint.KeyParameter[] keyParams, in android.hardware.security.keymint.KeyFormat keyFormat, in byte[] keyData);
android.hardware.security.keymint.KeyCreationResult generateKey(in android.hardware.security.keymint.KeyParameter[] keyParams, in @nullable android.hardware.security.keymint.AttestationKey attestationKey);
android.hardware.security.keymint.KeyCreationResult importKey(in android.hardware.security.keymint.KeyParameter[] keyParams, in android.hardware.security.keymint.KeyFormat keyFormat, in byte[] keyData, in @nullable android.hardware.security.keymint.AttestationKey attestationKey);
android.hardware.security.keymint.KeyCreationResult importWrappedKey(in byte[] wrappedKeyData, in byte[] wrappingKeyBlob, in byte[] maskingKey, in android.hardware.security.keymint.KeyParameter[] unwrappingParams, in long passwordSid, in long biometricSid);
byte[] upgradeKey(in byte[] inKeyBlobToUpgrade, in android.hardware.security.keymint.KeyParameter[] inUpgradeParams);
void deleteKey(in byte[] inKeyBlob);
byte[] upgradeKey(in byte[] keyBlobToUpgrade, in android.hardware.security.keymint.KeyParameter[] upgradeParams);
void deleteKey(in byte[] keyBlob);
void deleteAllKeys();
void destroyAttestationIds();
android.hardware.security.keymint.BeginResult begin(in android.hardware.security.keymint.KeyPurpose inPurpose, in byte[] inKeyBlob, in android.hardware.security.keymint.KeyParameter[] inParams, in android.hardware.security.keymint.HardwareAuthToken inAuthToken);
android.hardware.security.keymint.BeginResult begin(in android.hardware.security.keymint.KeyPurpose purpose, in byte[] keyBlob, in android.hardware.security.keymint.KeyParameter[] params, in android.hardware.security.keymint.HardwareAuthToken authToken);
void deviceLocked(in boolean passwordOnly, in @nullable android.hardware.security.secureclock.TimeStampToken timestampToken);
void earlyBootEnded();
const int AUTH_TOKEN_MAC_LENGTH = 32;

View File

@@ -39,4 +39,5 @@ enum KeyPurpose {
VERIFY = 3,
WRAP_KEY = 5,
AGREE_KEY = 6,
ATTEST_KEY = 7,
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.security.keymint;
import android.hardware.security.keymint.KeyParameter;
/**
* Contains a key blob with Tag::ATTEST_KEY that can be used to sign an attestation certificate,
* and the DER-encoded X.501 Subject Name that will be placed in the Issuer field of the attestation
* certificate.
*/
@VintfStability
@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
parcelable AttestationKey {
byte[] keyBlob;
KeyParameter[] attestKeyParams;
byte[] issuerSubjectName;
}

View File

@@ -103,6 +103,8 @@ enum ErrorCode {
UNSUPPORTED_MGF_DIGEST = -79,
MISSING_NOT_BEFORE = -80,
MISSING_NOT_AFTER = -81,
MISSING_ISSUER_SUBJECT = -82,
INVALID_ISSUER_SUBJECT = -83,
UNIMPLEMENTED = -100,
VERSION_MISMATCH = -101,

View File

@@ -16,6 +16,7 @@
package android.hardware.security.keymint;
import android.hardware.security.keymint.AttestationKey;
import android.hardware.security.keymint.BeginResult;
import android.hardware.security.keymint.ByteArray;
import android.hardware.security.keymint.HardwareAuthToken;
@@ -315,9 +316,18 @@ interface IKeyMintDevice {
* provided in params. See above for detailed specifications of which tags are required
* for which types of keys.
*
* @param attestationKey, if provided, specifies the key that must be used to sign the
* attestation certificate. If `keyParams` does not contain a Tag::ATTESTATION_CHALLENGE
* but `attestationKey` is non-null, the IKeyMintDevice must return
* ErrorCode::INVALID_ARGUMENT. If the provided AttestationKey does not contain a key
* blob containing an asymmetric key with KeyPurpose::ATTEST_KEY, the IKeyMintDevice must
* return ErrorCode::INVALID_PURPOSE. If the provided AttestationKey has an empty issuer
* subject name, the IKeyMintDevice must return ErrorCode::INVALID_ARGUMENT.
*
* @return The result of key creation. See KeyCreationResult.aidl.
*/
KeyCreationResult generateKey(in KeyParameter[] keyParams);
KeyCreationResult generateKey(
in KeyParameter[] keyParams, in @nullable AttestationKey attestationKey);
/**
* Imports key material into an IKeyMintDevice. Key definition parameters and return values
@@ -345,10 +355,18 @@ interface IKeyMintDevice {
*
* @param inKeyData The key material to import, in the format specified in keyFormat.
*
* @param attestationKey, if provided, specifies the key that must be used to sign the
* attestation certificate. If `keyParams` does not contain a Tag::ATTESTATION_CHALLENGE
* but `attestationKey` is non-null, the IKeyMintDevice must return
* ErrorCode::INVALID_ARGUMENT. If the provided AttestationKey does not contain a key
* blob containing an asymmetric key with KeyPurpose::ATTEST_KEY, the IKeyMintDevice must
* return ErrorCode::INVALID_PURPOSE. If the provided AttestationKey has an empty issuer
* subject name, the IKeyMintDevice must return ErrorCode::INVALID_ARGUMENT.
*
* @return The result of key creation. See KeyCreationResult.aidl.
*/
KeyCreationResult importKey(
in KeyParameter[] keyParams, in KeyFormat keyFormat, in byte[] keyData);
KeyCreationResult importKey(in KeyParameter[] keyParams, in KeyFormat keyFormat,
in byte[] keyData, in @nullable AttestationKey attestationKey);
/**
* Securely imports a key, or key pair, returning a key blob and a description of the imported
@@ -467,7 +485,7 @@ interface IKeyMintDevice {
* @return A new key blob that references the same key as keyBlobToUpgrade, but is in the new
* format, or has the new version data.
*/
byte[] upgradeKey(in byte[] inKeyBlobToUpgrade, in KeyParameter[] inUpgradeParams);
byte[] upgradeKey(in byte[] keyBlobToUpgrade, in KeyParameter[] upgradeParams);
/**
* Deletes the key, or key pair, associated with the key blob. Calling this function on
@@ -477,7 +495,7 @@ interface IKeyMintDevice {
*
* @param inKeyBlob The opaque descriptor returned by generateKey() or importKey();
*/
void deleteKey(in byte[] inKeyBlob);
void deleteKey(in byte[] keyBlob);
/**
* Deletes all keys in the hardware keystore. Used when keystore is reset completely. After
@@ -703,8 +721,8 @@ interface IKeyMintDevice {
* from operations that generate an IV or nonce, and IKeyMintOperation object pointer
* which is used to perform update(), finish() or abort() operations.
*/
BeginResult begin(in KeyPurpose inPurpose, in byte[] inKeyBlob, in KeyParameter[] inParams,
in HardwareAuthToken inAuthToken);
BeginResult begin(in KeyPurpose purpose, in byte[] keyBlob, in KeyParameter[] params,
in HardwareAuthToken authToken);
/**
* Called by client to notify the IKeyMintDevice that the device is now locked, and keys with

View File

@@ -16,12 +16,11 @@
package android.hardware.security.keymint;
/**
* Possible purposes of a key (or pair).
*/
@VintfStability
@Backing(type = "int")
@Backing(type="int")
enum KeyPurpose {
/* Usable with RSA, EC and AES keys. */
ENCRYPT = 0,
@@ -42,5 +41,7 @@ enum KeyPurpose {
/* Key Agreement, usable with EC keys. */
AGREE_KEY = 6,
/* TODO(seleneh) add ATTEST_KEY and their corresponding codes and tests later*/
/* Usable as an attestation signing key. Keys with this purpose must not have any other
* purpose. */
ATTEST_KEY = 7,
}

View File

@@ -21,6 +21,7 @@ cc_test {
"use_libaidlvintf_gtest_helper_static",
],
srcs: [
"AttestKeyTest.cpp",
"KeyMintTest.cpp",
],
shared_libs: [

View File

@@ -0,0 +1,235 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "keymint_1_attest_key_test"
#include <cutils/log.h>
#include <keymint_support/key_param_output.h>
#include <keymint_support/openssl_utils.h>
#include "KeyMintAidlTestBase.h"
namespace aidl::android::hardware::security::keymint::test {
namespace {
vector<uint8_t> make_name_from_str(const string& name) {
X509_NAME_Ptr x509_name(X509_NAME_new());
EXPECT_TRUE(x509_name.get() != nullptr);
if (!x509_name) return {};
EXPECT_EQ(1, X509_NAME_add_entry_by_txt(x509_name.get(), //
"CN", //
MBSTRING_ASC,
reinterpret_cast<const uint8_t*>(name.c_str()),
-1, // len
-1, // loc
0 /* set */));
int len = i2d_X509_NAME(x509_name.get(), nullptr /* only return length */);
EXPECT_GT(len, 0);
vector<uint8_t> retval(len);
uint8_t* p = retval.data();
i2d_X509_NAME(x509_name.get(), &p);
return retval;
}
bool IsSelfSigned(const vector<Certificate>& chain) {
if (chain.size() != 1) return false;
return ChainSignaturesAreValid(chain);
}
} // namespace
using AttestKeyTest = KeyMintAidlTestBase;
TEST_P(AttestKeyTest, AllRsaSizes) {
for (auto size : ValidKeySizes(Algorithm::RSA)) {
/*
* Create attestaton key.
*/
AttestationKey attest_key;
vector<KeyCharacteristics> attest_key_characteristics;
vector<Certificate> attest_key_cert_chain;
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(size, 65537)
.AttestKey()
.SetDefaultValidity(),
{} /* attestation signing key */, &attest_key.keyBlob,
&attest_key_characteristics, &attest_key_cert_chain));
EXPECT_EQ(attest_key_cert_chain.size(), 1);
EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain)) << "Failed on size " << size;
/*
* Use attestation key to sign RSA key
*/
attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
vector<uint8_t> attested_key_blob;
vector<KeyCharacteristics> attested_key_characteristics;
vector<Certificate> attested_key_cert_chain;
EXPECT_EQ(ErrorCode::OK,
GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(2048, 65537)
.Authorization(TAG_NO_AUTH_REQUIRED)
.AttestationChallenge("foo")
.AttestationApplicationId("bar")
.SetDefaultValidity(),
attest_key, &attested_key_blob, &attested_key_characteristics,
&attested_key_cert_chain));
CheckedDeleteKey(&attested_key_blob);
AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
attested_key_cert_chain[0].encodedCertificate));
// Attestation by itself is not valid (last entry is not self-signed).
EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
// Appending the attest_key chain to the attested_key_chain should yield a valid chain.
if (attest_key_cert_chain.size() > 0) {
attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
}
EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
/*
* Use attestation key to sign EC key
*/
EXPECT_EQ(ErrorCode::OK,
GenerateKey(AuthorizationSetBuilder()
.EcdsaSigningKey(EcCurve::P_256)
.Authorization(TAG_NO_AUTH_REQUIRED)
.AttestationChallenge("foo")
.AttestationApplicationId("bar")
.SetDefaultValidity(),
attest_key, &attested_key_blob, &attested_key_characteristics,
&attested_key_cert_chain));
CheckedDeleteKey(&attested_key_blob);
CheckedDeleteKey(&attest_key.keyBlob);
hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
attested_key_cert_chain[0].encodedCertificate));
// Attestation by itself is not valid (last entry is not self-signed).
EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
// Appending the attest_key chain to the attested_key_chain should yield a valid chain.
if (attest_key_cert_chain.size() > 0) {
attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
}
EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
// Bail early if anything failed.
if (HasFailure()) return;
}
}
TEST_P(AttestKeyTest, AllEcCurves) {
for (auto curve : ValidCurves()) {
/*
* Create attestaton key.
*/
AttestationKey attest_key;
vector<KeyCharacteristics> attest_key_characteristics;
vector<Certificate> attest_key_cert_chain;
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.EcdsaSigningKey(curve)
.AttestKey()
.SetDefaultValidity(),
{} /* attestation siging key */, &attest_key.keyBlob,
&attest_key_characteristics, &attest_key_cert_chain));
EXPECT_EQ(attest_key_cert_chain.size(), 1);
EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain)) << "Failed on curve " << curve;
/*
* Use attestation key to sign RSA key
*/
attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
vector<uint8_t> attested_key_blob;
vector<KeyCharacteristics> attested_key_characteristics;
vector<Certificate> attested_key_cert_chain;
EXPECT_EQ(ErrorCode::OK,
GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(2048, 65537)
.Authorization(TAG_NO_AUTH_REQUIRED)
.AttestationChallenge("foo")
.AttestationApplicationId("bar")
.SetDefaultValidity(),
attest_key, &attested_key_blob, &attested_key_characteristics,
&attested_key_cert_chain));
CheckedDeleteKey(&attested_key_blob);
AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
attested_key_cert_chain[0].encodedCertificate));
// Attestation by itself is not valid (last entry is not self-signed).
EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
// Appending the attest_key chain to the attested_key_chain should yield a valid chain.
if (attest_key_cert_chain.size() > 0) {
attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
}
EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
/*
* Use attestation key to sign EC key
*/
EXPECT_EQ(ErrorCode::OK,
GenerateKey(AuthorizationSetBuilder()
.EcdsaSigningKey(EcCurve::P_256)
.Authorization(TAG_NO_AUTH_REQUIRED)
.AttestationChallenge("foo")
.AttestationApplicationId("bar")
.SetDefaultValidity(),
attest_key, &attested_key_blob, &attested_key_characteristics,
&attested_key_cert_chain));
CheckedDeleteKey(&attested_key_blob);
CheckedDeleteKey(&attest_key.keyBlob);
hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
attested_key_cert_chain[0].encodedCertificate));
// Attestation by itself is not valid (last entry is not self-signed).
EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
// Appending the attest_key chain to the attested_key_chain should yield a valid chain.
if (attest_key_cert_chain.size() > 0) {
attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
}
EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
// Bail early if anything failed.
if (HasFailure()) return;
}
}
INSTANTIATE_KEYMINT_AIDL_TEST(AttestKeyTest);
} // namespace aidl::android::hardware::security::keymint::test

View File

@@ -22,15 +22,23 @@
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <cutils/properties.h>
#include <openssl/mem.h>
#include <keymint_support/attestation_record.h>
#include <keymint_support/key_param_output.h>
#include <keymint_support/keymint_utils.h>
#include <keymint_support/openssl_utils.h>
namespace aidl::android::hardware::security::keymint {
using namespace std::literals::chrono_literals;
using std::endl;
using std::optional;
using std::unique_ptr;
using ::testing::AssertionFailure;
using ::testing::AssertionResult;
using ::testing::AssertionSuccess;
::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set) {
if (set.size() == 0)
@@ -73,8 +81,67 @@ bool KeyCharacteristicsBasicallyValid(SecurityLevel secLevel,
return true;
}
// Extract attestation record from cert. Returned object is still part of cert; don't free it
// separately.
ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
EXPECT_TRUE(!!oid.get());
if (!oid.get()) return nullptr;
int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
EXPECT_NE(-1, location) << "Attestation extension not found in certificate";
if (location == -1) return nullptr;
X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
EXPECT_TRUE(!!attest_rec_ext)
<< "Found attestation extension but couldn't retrieve it? Probably a BoringSSL bug.";
if (!attest_rec_ext) return nullptr;
ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data";
return attest_rec;
}
bool avb_verification_enabled() {
char value[PROPERTY_VALUE_MAX];
return property_get("ro.boot.vbmeta.device_state", value, "") != 0;
}
char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
// Attestations don't contain everything in key authorization lists, so we need to filter the key
// lists to produce the lists that we expect to match the attestations.
auto kTagsToFilter = {
Tag::BLOB_USAGE_REQUIREMENTS, //
Tag::CREATION_DATETIME, //
Tag::EC_CURVE,
Tag::HARDWARE_TYPE,
Tag::INCLUDE_UNIQUE_ID,
};
AuthorizationSet filtered_tags(const AuthorizationSet& set) {
AuthorizationSet filtered;
std::remove_copy_if(
set.begin(), set.end(), std::back_inserter(filtered), [](const auto& entry) -> bool {
return std::find(kTagsToFilter.begin(), kTagsToFilter.end(), entry.tag) !=
kTagsToFilter.end();
});
return filtered;
}
string x509NameToStr(X509_NAME* name) {
char* s = X509_NAME_oneline(name, nullptr, 0);
string retval(s);
OPENSSL_free(s);
return retval;
}
} // namespace
bool KeyMintAidlTestBase::arm_deleteAllKeys = false;
bool KeyMintAidlTestBase::dump_Attestations = false;
ErrorCode KeyMintAidlTestBase::GetReturnErrorCode(const Status& result) {
if (result.isOk()) return ErrorCode::OK;
@@ -110,48 +177,48 @@ void KeyMintAidlTestBase::SetUp() {
}
ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc,
const optional<AttestationKey>& attest_key,
vector<uint8_t>* key_blob,
vector<KeyCharacteristics>* key_characteristics) {
vector<KeyCharacteristics>* key_characteristics,
vector<Certificate>* cert_chain) {
EXPECT_NE(key_blob, nullptr) << "Key blob pointer must not be null. Test bug";
EXPECT_NE(key_characteristics, nullptr)
<< "Previous characteristics not deleted before generating key. Test bug.";
// Aidl does not clear these output parameters if the function returns
// error. This is different from hal where output parameter is always
// cleared due to hal returning void. So now we need to do our own clearing
// of the output variables prior to calling keyMint aidl libraries.
key_blob->clear();
key_characteristics->clear();
cert_chain_.clear();
KeyCreationResult creationResult;
Status result = keymint_->generateKey(key_desc.vector_data(), &creationResult);
Status result = keymint_->generateKey(key_desc.vector_data(), attest_key, &creationResult);
if (result.isOk()) {
EXPECT_PRED2(KeyCharacteristicsBasicallyValid, SecLevel(),
creationResult.keyCharacteristics);
EXPECT_GT(creationResult.keyBlob.size(), 0);
*key_blob = std::move(creationResult.keyBlob);
*key_characteristics = std::move(creationResult.keyCharacteristics);
cert_chain_ = std::move(creationResult.certificateChain);
*cert_chain = std::move(creationResult.certificateChain);
auto algorithm = key_desc.GetTagValue(TAG_ALGORITHM);
EXPECT_TRUE(algorithm);
if (algorithm &&
(algorithm.value() == Algorithm::RSA || algorithm.value() == Algorithm::EC)) {
EXPECT_GE(cert_chain_.size(), 1);
if (key_desc.Contains(TAG_ATTESTATION_CHALLENGE)) EXPECT_GT(cert_chain_.size(), 1);
EXPECT_GE(cert_chain->size(), 1);
if (key_desc.Contains(TAG_ATTESTATION_CHALLENGE)) {
if (attest_key) {
EXPECT_EQ(cert_chain->size(), 1);
} else {
EXPECT_GT(cert_chain->size(), 1);
}
}
} else {
// For symmetric keys there should be no certificates.
EXPECT_EQ(cert_chain_.size(), 0);
EXPECT_EQ(cert_chain->size(), 0);
}
}
return GetReturnErrorCode(result);
}
ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc) {
return GenerateKey(key_desc, &key_blob_, &key_characteristics_);
ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc,
const optional<AttestationKey>& attest_key) {
return GenerateKey(key_desc, attest_key, &key_blob_, &key_characteristics_, &cert_chain_);
}
ErrorCode KeyMintAidlTestBase::ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
@@ -166,7 +233,7 @@ ErrorCode KeyMintAidlTestBase::ImportKey(const AuthorizationSet& key_desc, KeyFo
KeyCreationResult creationResult;
result = keymint_->importKey(key_desc.vector_data(), format,
vector<uint8_t>(key_material.begin(), key_material.end()),
&creationResult);
{} /* attestationSigningKeyBlob */, &creationResult);
if (result.isOk()) {
EXPECT_PRED2(KeyCharacteristicsBasicallyValid, SecLevel(),
@@ -916,6 +983,240 @@ ErrorCode KeyMintAidlTestBase::UseEcdsaKey(const vector<uint8_t>& ecdsaKeyBlob)
return result;
}
bool verify_attestation_record(const string& challenge, //
const string& app_id, //
AuthorizationSet expected_sw_enforced, //
AuthorizationSet expected_hw_enforced, //
SecurityLevel security_level,
const vector<uint8_t>& attestation_cert) {
X509_Ptr cert(parse_cert_blob(attestation_cert));
EXPECT_TRUE(!!cert.get());
if (!cert.get()) return false;
ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
EXPECT_TRUE(!!attest_rec);
if (!attest_rec) return false;
AuthorizationSet att_sw_enforced;
AuthorizationSet att_hw_enforced;
uint32_t att_attestation_version;
uint32_t att_keymaster_version;
SecurityLevel att_attestation_security_level;
SecurityLevel att_keymaster_security_level;
vector<uint8_t> att_challenge;
vector<uint8_t> att_unique_id;
vector<uint8_t> att_app_id;
auto error = parse_attestation_record(attest_rec->data, //
attest_rec->length, //
&att_attestation_version, //
&att_attestation_security_level, //
&att_keymaster_version, //
&att_keymaster_security_level, //
&att_challenge, //
&att_sw_enforced, //
&att_hw_enforced, //
&att_unique_id);
EXPECT_EQ(ErrorCode::OK, error);
if (error != ErrorCode::OK) return false;
EXPECT_GE(att_attestation_version, 3U);
expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID,
vector<uint8_t>(app_id.begin(), app_id.end()));
EXPECT_GE(att_keymaster_version, 4U);
EXPECT_EQ(security_level, att_keymaster_security_level);
EXPECT_EQ(security_level, att_attestation_security_level);
EXPECT_EQ(challenge.length(), att_challenge.size());
EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length()));
char property_value[PROPERTY_VALUE_MAX] = {};
// TODO(b/136282179): When running under VTS-on-GSI the TEE-backed
// keymaster implementation will report YYYYMM dates instead of YYYYMMDD
// for the BOOT_PATCH_LEVEL.
if (avb_verification_enabled()) {
for (int i = 0; i < att_hw_enforced.size(); i++) {
if (att_hw_enforced[i].tag == TAG_BOOT_PATCHLEVEL ||
att_hw_enforced[i].tag == TAG_VENDOR_PATCHLEVEL) {
std::string date =
std::to_string(att_hw_enforced[i].value.get<KeyParameterValue::dateTime>());
// strptime seems to require delimiters, but the tag value will
// be YYYYMMDD
date.insert(6, "-");
date.insert(4, "-");
EXPECT_EQ(date.size(), 10);
struct tm time;
strptime(date.c_str(), "%Y-%m-%d", &time);
// Day of the month (0-31)
EXPECT_GE(time.tm_mday, 0);
EXPECT_LT(time.tm_mday, 32);
// Months since Jan (0-11)
EXPECT_GE(time.tm_mon, 0);
EXPECT_LT(time.tm_mon, 12);
// Years since 1900
EXPECT_GT(time.tm_year, 110);
EXPECT_LT(time.tm_year, 200);
}
}
}
// Check to make sure boolean values are properly encoded. Presence of a boolean tag
// indicates true. A provided boolean tag that can be pulled back out of the certificate
// indicates correct encoding. No need to check if it's in both lists, since the
// AuthorizationSet compare below will handle mismatches of tags.
if (security_level == SecurityLevel::SOFTWARE) {
EXPECT_TRUE(expected_sw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
} else {
EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
}
// Alternatively this checks the opposite - a false boolean tag (one that isn't provided in
// the authorization list during key generation) isn't being attested to in the certificate.
EXPECT_FALSE(expected_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
EXPECT_FALSE(att_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
EXPECT_FALSE(expected_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
EXPECT_FALSE(att_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
if (att_hw_enforced.Contains(TAG_ALGORITHM, Algorithm::EC)) {
// For ECDSA keys, either an EC_CURVE or a KEY_SIZE can be specified, but one must be.
EXPECT_TRUE(att_hw_enforced.Contains(TAG_EC_CURVE) ||
att_hw_enforced.Contains(TAG_KEY_SIZE));
}
// Test root of trust elements
vector<uint8_t> verified_boot_key;
VerifiedBoot verified_boot_state;
bool device_locked;
vector<uint8_t> verified_boot_hash;
error = parse_root_of_trust(attest_rec->data, attest_rec->length, &verified_boot_key,
&verified_boot_state, &device_locked, &verified_boot_hash);
EXPECT_EQ(ErrorCode::OK, error);
if (avb_verification_enabled()) {
EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
string prop_string(property_value);
EXPECT_EQ(prop_string.size(), 64);
EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
if (!strcmp(property_value, "unlocked")) {
EXPECT_FALSE(device_locked);
} else {
EXPECT_TRUE(device_locked);
}
// Check that the device is locked if not debuggable, e.g., user build
// images in CTS. For VTS, debuggable images are used to allow adb root
// and the device is unlocked.
if (!property_get_bool("ro.debuggable", false)) {
EXPECT_TRUE(device_locked);
} else {
EXPECT_FALSE(device_locked);
}
}
// Verified boot key should be all 0's if the boot state is not verified or self signed
std::string empty_boot_key(32, '\0');
std::string verified_boot_key_str((const char*)verified_boot_key.data(),
verified_boot_key.size());
EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
if (!strcmp(property_value, "green")) {
EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
verified_boot_key.size()));
} else if (!strcmp(property_value, "yellow")) {
EXPECT_EQ(verified_boot_state, VerifiedBoot::SELF_SIGNED);
EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
verified_boot_key.size()));
} else if (!strcmp(property_value, "orange")) {
EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
verified_boot_key.size()));
} else if (!strcmp(property_value, "red")) {
EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED);
} else {
EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
verified_boot_key.size()));
}
att_sw_enforced.Sort();
expected_sw_enforced.Sort();
auto a = filtered_tags(expected_sw_enforced);
auto b = filtered_tags(att_sw_enforced);
EXPECT_EQ(a, b);
att_hw_enforced.Sort();
expected_hw_enforced.Sort();
EXPECT_EQ(filtered_tags(expected_hw_enforced), filtered_tags(att_hw_enforced));
return true;
}
string bin2hex(const vector<uint8_t>& data) {
string retval;
retval.reserve(data.size() * 2 + 1);
for (uint8_t byte : data) {
retval.push_back(nibble2hex[0x0F & (byte >> 4)]);
retval.push_back(nibble2hex[0x0F & byte]);
}
return retval;
}
AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain) {
std::stringstream cert_data;
for (size_t i = 0; i < chain.size(); ++i) {
cert_data << bin2hex(chain[i].encodedCertificate) << std::endl;
X509_Ptr key_cert(parse_cert_blob(chain[i].encodedCertificate));
X509_Ptr signing_cert;
if (i < chain.size() - 1) {
signing_cert = parse_cert_blob(chain[i + 1].encodedCertificate);
} else {
signing_cert = parse_cert_blob(chain[i].encodedCertificate);
}
if (!key_cert.get() || !signing_cert.get()) return AssertionFailure() << cert_data.str();
EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
if (!signing_pubkey.get()) return AssertionFailure() << cert_data.str();
if (!X509_verify(key_cert.get(), signing_pubkey.get())) {
return AssertionFailure()
<< "Verification of certificate " << i << " failed "
<< "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL) << '\n'
<< cert_data.str();
}
string cert_issuer = x509NameToStr(X509_get_issuer_name(key_cert.get()));
string signer_subj = x509NameToStr(X509_get_subject_name(signing_cert.get()));
if (cert_issuer != signer_subj) {
return AssertionFailure() << "Cert " << i << " has wrong issuer.\n" << cert_data.str();
}
if (i == 0) {
string cert_sub = x509NameToStr(X509_get_subject_name(key_cert.get()));
if ("/CN=Android Keystore Key" != cert_sub) {
return AssertionFailure()
<< "Leaf cert has wrong subject, should be CN=Android Keystore Key, was "
<< cert_sub << '\n'
<< cert_data.str();
}
}
}
if (KeyMintAidlTestBase::dump_Attestations) std::cout << cert_data.str();
return AssertionSuccess();
}
X509_Ptr parse_cert_blob(const vector<uint8_t>& blob) {
const uint8_t* p = blob.data();
return X509_Ptr(d2i_X509(nullptr /* allocate new */, &p, blob.size()));
}
} // namespace test
} // namespace aidl::android::hardware::security::keymint

View File

@@ -21,20 +21,27 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <gtest/gtest.h>
#include <openssl/x509.h>
#include <aidl/android/hardware/security/keymint/ErrorCode.h>
#include <aidl/android/hardware/security/keymint/IKeyMintDevice.h>
#include <keymint_support/authorization_set.h>
#include <keymint_support/openssl_utils.h>
namespace aidl::android::hardware::security::keymint {
::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set);
inline bool operator==(const keymint::AuthorizationSet& a, const keymint::AuthorizationSet& b) {
return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
}
namespace test {
using ::android::sp;
using Status = ::ndk::ScopedAStatus;
using ::std::optional;
using ::std::shared_ptr;
using ::std::string;
using ::std::vector;
@@ -48,6 +55,9 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam<string> {
vector<KeyCharacteristics> characteristics;
};
static bool arm_deleteAllKeys;
static bool dump_Attestations;
void SetUp() override;
void TearDown() override {
if (key_blob_.size()) {
@@ -62,10 +72,19 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam<string> {
uint32_t os_patch_level() { return os_patch_level_; }
ErrorCode GetReturnErrorCode(const Status& result);
ErrorCode GenerateKey(const AuthorizationSet& key_desc, vector<uint8_t>* key_blob,
vector<KeyCharacteristics>* key_characteristics);
ErrorCode GenerateKey(const AuthorizationSet& key_desc);
ErrorCode GenerateKey(const AuthorizationSet& key_desc, vector<uint8_t>* key_blob,
vector<KeyCharacteristics>* key_characteristics) {
return GenerateKey(key_desc, std::nullopt /* attest_key */, key_blob, key_characteristics,
&cert_chain_);
}
ErrorCode GenerateKey(const AuthorizationSet& key_desc,
const optional<AttestationKey>& attest_key, vector<uint8_t>* key_blob,
vector<KeyCharacteristics>* key_characteristics,
vector<Certificate>* cert_chain);
ErrorCode GenerateKey(const AuthorizationSet& key_desc,
const optional<AttestationKey>& attest_key = std::nullopt);
ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
const string& key_material, vector<uint8_t>* key_blob,
vector<KeyCharacteristics>* key_characteristics);
@@ -254,6 +273,16 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam<string> {
long challenge_;
};
bool verify_attestation_record(const string& challenge, //
const string& app_id, //
AuthorizationSet expected_sw_enforced, //
AuthorizationSet expected_hw_enforced, //
SecurityLevel security_level,
const vector<uint8_t>& attestation_cert);
string bin2hex(const vector<uint8_t>& data);
X509_Ptr parse_cert_blob(const vector<uint8_t>& blob);
::testing::AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain);
#define INSTANTIATE_KEYMINT_AIDL_TEST(name) \
INSTANTIATE_TEST_SUITE_P(PerInstance, name, \
testing::ValuesIn(KeyMintAidlTestBase::build_params()), \

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
#define LOG_TAG "keymint_5_test"
#define LOG_TAG "keymint_1_test"
#include <cutils/log.h>
#include <signal.h>
@@ -23,34 +23,21 @@
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <cutils/properties.h>
#include <aidl/android/hardware/security/keymint/KeyFormat.h>
#include <keymint_support/attestation_record.h>
#include <keymint_support/key_param_output.h>
#include <keymint_support/openssl_utils.h>
#include "KeyMintAidlTestBase.h"
static bool arm_deleteAllKeys = false;
static bool dump_Attestations = false;
using aidl::android::hardware::security::keymint::AuthorizationSet;
using aidl::android::hardware::security::keymint::KeyCharacteristics;
using aidl::android::hardware::security::keymint::KeyFormat;
namespace aidl::android::hardware::security::keymint {
bool operator==(const keymint::AuthorizationSet& a, const keymint::AuthorizationSet& b) {
return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
}
} // namespace aidl::android::hardware::security::keymint
namespace std {
using namespace aidl::android::hardware::security::keymint;
@@ -183,281 +170,6 @@ struct RSA_Delete {
void operator()(RSA* p) { RSA_free(p); }
};
char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
string bin2hex(const vector<uint8_t>& data) {
string retval;
retval.reserve(data.size() * 2 + 1);
for (uint8_t byte : data) {
retval.push_back(nibble2hex[0x0F & (byte >> 4)]);
retval.push_back(nibble2hex[0x0F & byte]);
}
return retval;
}
X509* parse_cert_blob(const vector<uint8_t>& blob) {
const uint8_t* p = blob.data();
return d2i_X509(nullptr, &p, blob.size());
}
bool verify_chain(const vector<Certificate>& chain) {
for (size_t i = 0; i < chain.size(); ++i) {
X509_Ptr key_cert(parse_cert_blob(chain[i].encodedCertificate));
X509_Ptr signing_cert;
if (i < chain.size() - 1) {
signing_cert.reset(parse_cert_blob(chain[i + 1].encodedCertificate));
} else {
signing_cert.reset(parse_cert_blob(chain[i].encodedCertificate));
}
EXPECT_TRUE(!!key_cert.get() && !!signing_cert.get());
if (!key_cert.get() || !signing_cert.get()) return false;
EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
EXPECT_TRUE(!!signing_pubkey.get());
if (!signing_pubkey.get()) return false;
EXPECT_EQ(1, X509_verify(key_cert.get(), signing_pubkey.get()))
<< "Verification of certificate " << i << " failed "
<< "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
char* cert_issuer = //
X509_NAME_oneline(X509_get_issuer_name(key_cert.get()), nullptr, 0);
char* signer_subj =
X509_NAME_oneline(X509_get_subject_name(signing_cert.get()), nullptr, 0);
EXPECT_STREQ(cert_issuer, signer_subj) << "Cert " << i << " has wrong issuer.";
if (i == 0) {
char* cert_sub = X509_NAME_oneline(X509_get_subject_name(key_cert.get()), nullptr, 0);
EXPECT_STREQ("/CN=Android Keystore Key", cert_sub)
<< "Cert " << i << " has wrong subject.";
OPENSSL_free(cert_sub);
}
OPENSSL_free(cert_issuer);
OPENSSL_free(signer_subj);
if (dump_Attestations) std::cout << bin2hex(chain[i].encodedCertificate) << std::endl;
}
return true;
}
// Extract attestation record from cert. Returned object is still part of cert; don't free it
// separately.
ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
EXPECT_TRUE(!!oid.get());
if (!oid.get()) return nullptr;
int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
EXPECT_NE(-1, location) << "Attestation extension not found in certificate";
if (location == -1) return nullptr;
X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
EXPECT_TRUE(!!attest_rec_ext)
<< "Found attestation extension but couldn't retrieve it? Probably a BoringSSL bug.";
if (!attest_rec_ext) return nullptr;
ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data";
return attest_rec;
}
bool tag_in_list(const KeyParameter& entry) {
// Attestations don't contain everything in key authorization lists, so we need to filter
// the key lists to produce the lists that we expect to match the attestations.
auto tag_list = {
Tag::BLOB_USAGE_REQUIREMENTS, //
Tag::CREATION_DATETIME, //
Tag::EC_CURVE,
Tag::HARDWARE_TYPE,
Tag::INCLUDE_UNIQUE_ID,
};
return std::find(tag_list.begin(), tag_list.end(), entry.tag) != tag_list.end();
}
AuthorizationSet filtered_tags(const AuthorizationSet& set) {
AuthorizationSet filtered;
std::remove_copy_if(set.begin(), set.end(), std::back_inserter(filtered), tag_in_list);
return filtered;
}
bool avb_verification_enabled() {
char value[PROPERTY_VALUE_MAX];
return property_get("ro.boot.vbmeta.device_state", value, "") != 0;
}
bool verify_attestation_record(const string& challenge, //
const string& app_id, //
AuthorizationSet expected_sw_enforced, //
AuthorizationSet expected_hw_enforced, //
SecurityLevel security_level,
const vector<uint8_t>& attestation_cert) {
X509_Ptr cert(parse_cert_blob(attestation_cert));
EXPECT_TRUE(!!cert.get());
if (!cert.get()) return false;
ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
EXPECT_TRUE(!!attest_rec);
if (!attest_rec) return false;
AuthorizationSet att_sw_enforced;
AuthorizationSet att_hw_enforced;
uint32_t att_attestation_version;
uint32_t att_keymaster_version;
SecurityLevel att_attestation_security_level;
SecurityLevel att_keymaster_security_level;
vector<uint8_t> att_challenge;
vector<uint8_t> att_unique_id;
vector<uint8_t> att_app_id;
auto error = parse_attestation_record(attest_rec->data, //
attest_rec->length, //
&att_attestation_version, //
&att_attestation_security_level, //
&att_keymaster_version, //
&att_keymaster_security_level, //
&att_challenge, //
&att_sw_enforced, //
&att_hw_enforced, //
&att_unique_id);
EXPECT_EQ(ErrorCode::OK, error);
if (error != ErrorCode::OK) return false;
EXPECT_GE(att_attestation_version, 3U);
expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID,
vector<uint8_t>(app_id.begin(), app_id.end()));
EXPECT_GE(att_keymaster_version, 4U);
EXPECT_EQ(security_level, att_keymaster_security_level);
EXPECT_EQ(security_level, att_attestation_security_level);
EXPECT_EQ(challenge.length(), att_challenge.size());
EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length()));
char property_value[PROPERTY_VALUE_MAX] = {};
// TODO(b/136282179): When running under VTS-on-GSI the TEE-backed
// keymaster implementation will report YYYYMM dates instead of YYYYMMDD
// for the BOOT_PATCH_LEVEL.
if (avb_verification_enabled()) {
for (int i = 0; i < att_hw_enforced.size(); i++) {
if (att_hw_enforced[i].tag == TAG_BOOT_PATCHLEVEL ||
att_hw_enforced[i].tag == TAG_VENDOR_PATCHLEVEL) {
std::string date =
std::to_string(att_hw_enforced[i].value.get<KeyParameterValue::dateTime>());
// strptime seems to require delimiters, but the tag value will
// be YYYYMMDD
date.insert(6, "-");
date.insert(4, "-");
EXPECT_EQ(date.size(), 10);
struct tm time;
strptime(date.c_str(), "%Y-%m-%d", &time);
// Day of the month (0-31)
EXPECT_GE(time.tm_mday, 0);
EXPECT_LT(time.tm_mday, 32);
// Months since Jan (0-11)
EXPECT_GE(time.tm_mon, 0);
EXPECT_LT(time.tm_mon, 12);
// Years since 1900
EXPECT_GT(time.tm_year, 110);
EXPECT_LT(time.tm_year, 200);
}
}
}
// Check to make sure boolean values are properly encoded. Presence of a boolean tag indicates
// true. A provided boolean tag that can be pulled back out of the certificate indicates correct
// encoding. No need to check if it's in both lists, since the AuthorizationSet compare below
// will handle mismatches of tags.
if (security_level == SecurityLevel::SOFTWARE) {
EXPECT_TRUE(expected_sw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
} else {
EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
}
// Alternatively this checks the opposite - a false boolean tag (one that isn't provided in
// the authorization list during key generation) isn't being attested to in the certificate.
EXPECT_FALSE(expected_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
EXPECT_FALSE(att_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
EXPECT_FALSE(expected_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
EXPECT_FALSE(att_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
if (att_hw_enforced.Contains(TAG_ALGORITHM, Algorithm::EC)) {
// For ECDSA keys, either an EC_CURVE or a KEY_SIZE can be specified, but one must be.
EXPECT_TRUE(att_hw_enforced.Contains(TAG_EC_CURVE) ||
att_hw_enforced.Contains(TAG_KEY_SIZE));
}
// Test root of trust elements
vector<uint8_t> verified_boot_key;
VerifiedBoot verified_boot_state;
bool device_locked;
vector<uint8_t> verified_boot_hash;
error = parse_root_of_trust(attest_rec->data, attest_rec->length, &verified_boot_key,
&verified_boot_state, &device_locked, &verified_boot_hash);
EXPECT_EQ(ErrorCode::OK, error);
if (avb_verification_enabled()) {
EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
string prop_string(property_value);
EXPECT_EQ(prop_string.size(), 64);
EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
if (!strcmp(property_value, "unlocked")) {
EXPECT_FALSE(device_locked);
} else {
EXPECT_TRUE(device_locked);
}
// Check that the device is locked if not debuggable, e.g., user build
// images in CTS. For VTS, debuggable images are used to allow adb root
// and the device is unlocked.
if (!property_get_bool("ro.debuggable", false)) {
EXPECT_TRUE(device_locked);
} else {
EXPECT_FALSE(device_locked);
}
}
// Verified boot key should be all 0's if the boot state is not verified or self signed
std::string empty_boot_key(32, '\0');
std::string verified_boot_key_str((const char*)verified_boot_key.data(),
verified_boot_key.size());
EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
if (!strcmp(property_value, "green")) {
EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
verified_boot_key.size()));
} else if (!strcmp(property_value, "yellow")) {
EXPECT_EQ(verified_boot_state, VerifiedBoot::SELF_SIGNED);
EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
verified_boot_key.size()));
} else if (!strcmp(property_value, "orange")) {
EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
verified_boot_key.size()));
} else if (!strcmp(property_value, "red")) {
EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED);
} else {
EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
verified_boot_key.size()));
}
att_sw_enforced.Sort();
expected_sw_enforced.Sort();
EXPECT_EQ(filtered_tags(expected_sw_enforced), filtered_tags(att_sw_enforced));
att_hw_enforced.Sort();
expected_hw_enforced.Sort();
EXPECT_EQ(filtered_tags(expected_hw_enforced), filtered_tags(att_hw_enforced));
return true;
}
std::string make_string(const uint8_t* data, size_t length) {
return std::string(reinterpret_cast<const char*>(data), length);
}
@@ -596,7 +308,7 @@ TEST_P(NewKeyGenerationTest, RsaWithAttestation) {
<< "Key size " << key_size << "missing";
EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
EXPECT_TRUE(verify_chain(cert_chain_));
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
ASSERT_GT(cert_chain_.size(), 0);
AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
@@ -692,7 +404,7 @@ TEST_P(NewKeyGenerationTest, LimitedUsageRsaWithAttestation) {
<< "key usage count limit " << 1U << " missing";
// Check the usage count limit tag also appears in the attestation.
EXPECT_TRUE(verify_chain(cert_chain_));
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
ASSERT_GT(cert_chain_.size(), 0);
AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
@@ -5111,14 +4823,26 @@ INSTANTIATE_KEYMINT_AIDL_TEST(UnlockedDeviceRequiredTest);
} // namespace aidl::android::hardware::security::keymint::test
int main(int argc, char** argv) {
std::cout << "Testing ";
auto halInstances =
aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::build_params();
std::cout << "HAL instances:\n";
for (auto& entry : halInstances) {
std::cout << " " << entry << '\n';
}
::testing::InitGoogleTest(&argc, argv);
for (int i = 1; i < argc; ++i) {
if (argv[i][0] == '-') {
if (std::string(argv[i]) == "--arm_deleteAllKeys") {
arm_deleteAllKeys = true;
aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::
arm_deleteAllKeys = true;
}
if (std::string(argv[i]) == "--dump_attestations") {
dump_Attestations = true;
aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::
dump_Attestations = true;
} else {
std::cout << "NOT dumping attestations" << std::endl;
}
}
}

View File

@@ -80,7 +80,7 @@ INSTANTIATE_REM_PROV_AIDL_TEST(GenerateKeyTests);
/**
* Generate and validate a production-mode key. MAC tag can't be verified.
*/
TEST_P(GenerateKeyTests, generateEcdsaP256Key_prodMode) {
TEST_P(GenerateKeyTests, DISABLED_generateEcdsaP256Key_prodMode) {
MacedPublicKey macedPubKey;
bytevec privateKeyBlob;
bool testMode = false;
@@ -133,7 +133,7 @@ TEST_P(GenerateKeyTests, generateEcdsaP256Key_prodMode) {
/**
* Generate and validate a test-mode key.
*/
TEST_P(GenerateKeyTests, generateEcdsaP256Key_testMode) {
TEST_P(GenerateKeyTests, DISABLED_generateEcdsaP256Key_testMode) {
MacedPublicKey macedPubKey;
bytevec privateKeyBlob;
bool testMode = true;
@@ -224,7 +224,7 @@ class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
* Generate an empty certificate request in test mode, and decrypt and verify the structure and
* content.
*/
TEST_P(CertificateRequestTest, EmptyRequest_testMode) {
TEST_P(CertificateRequestTest, DISABLED_EmptyRequest_testMode) {
bool testMode = true;
bytevec keysToSignMac;
ProtectedData protectedData;
@@ -294,7 +294,7 @@ TEST_P(CertificateRequestTest, EmptyRequest_testMode) {
* TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
* able to decrypt.
*/
TEST_P(CertificateRequestTest, EmptyRequest_prodMode) {
TEST_P(CertificateRequestTest, DISABLED_EmptyRequest_prodMode) {
bool testMode = false;
bytevec keysToSignMac;
ProtectedData protectedData;
@@ -309,7 +309,7 @@ TEST_P(CertificateRequestTest, EmptyRequest_prodMode) {
/**
* Generate a non-empty certificate request in test mode. Decrypt, parse and validate the contents.
*/
TEST_P(CertificateRequestTest, NonEmptyRequest_testMode) {
TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_testMode) {
bool testMode = true;
generateKeys(testMode, 4 /* numKeys */);
@@ -379,7 +379,7 @@ TEST_P(CertificateRequestTest, NonEmptyRequest_testMode) {
* TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
* able to decrypt.
*/
TEST_P(CertificateRequestTest, NonEmptyRequest_prodMode) {
TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_prodMode) {
bool testMode = false;
generateKeys(testMode, 4 /* numKeys */);
@@ -396,7 +396,7 @@ TEST_P(CertificateRequestTest, NonEmptyRequest_prodMode) {
* Generate a non-empty certificate request in test mode, with prod keys. Must fail with
* STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
*/
TEST_P(CertificateRequestTest, NonEmptyRequest_prodKeyInTestCert) {
TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_prodKeyInTestCert) {
generateKeys(false /* testMode */, 2 /* numKeys */);
bytevec keysToSignMac;
@@ -414,7 +414,7 @@ TEST_P(CertificateRequestTest, NonEmptyRequest_prodKeyInTestCert) {
* Generate a non-empty certificate request in prod mode, with test keys. Must fail with
* STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
*/
TEST_P(CertificateRequestTest, NonEmptyRequest_testKeyInProdCert) {
TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_testKeyInProdCert) {
generateKeys(true /* testMode */, 2 /* numKeys */);
bytevec keysToSignMac;

View File

@@ -191,6 +191,10 @@ AuthorizationSetBuilder& AuthorizationSetBuilder::EncryptionKey() {
return Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT);
}
AuthorizationSetBuilder& AuthorizationSetBuilder::AttestKey() {
return Authorization(TAG_PURPOSE, KeyPurpose::ATTEST_KEY);
}
AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() {
Authorization(TAG_DIGEST, Digest::NONE);
return Authorization(TAG_PADDING, PaddingMode::NONE);

View File

@@ -288,6 +288,7 @@ class AuthorizationSetBuilder : public AuthorizationSet {
AuthorizationSetBuilder& SigningKey();
AuthorizationSetBuilder& EncryptionKey();
AuthorizationSetBuilder& AttestKey();
AuthorizationSetBuilder& NoDigestOrPadding();

View File

@@ -34,13 +34,14 @@ typedef UniquePtrDeleter<EVP_PKEY, EVP_PKEY_free> EVP_PKEY_Delete;
typedef std::unique_ptr<type, UniquePtrDeleter<type, type##_free>> type##_Ptr;
MAKE_OPENSSL_PTR_TYPE(ASN1_OBJECT)
MAKE_OPENSSL_PTR_TYPE(EC_KEY)
MAKE_OPENSSL_PTR_TYPE(BN_CTX)
MAKE_OPENSSL_PTR_TYPE(EC_GROUP)
MAKE_OPENSSL_PTR_TYPE(EC_KEY)
MAKE_OPENSSL_PTR_TYPE(EVP_PKEY)
MAKE_OPENSSL_PTR_TYPE(EVP_PKEY_CTX)
MAKE_OPENSSL_PTR_TYPE(RSA)
MAKE_OPENSSL_PTR_TYPE(X509)
MAKE_OPENSSL_PTR_TYPE(BN_CTX)
MAKE_OPENSSL_PTR_TYPE(X509_NAME)
typedef std::unique_ptr<BIGNUM, UniquePtrDeleter<BIGNUM, BN_free>> BIGNUM_Ptr;