mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
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:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -39,4 +39,5 @@ enum KeyPurpose {
|
||||
VERIFY = 3,
|
||||
WRAP_KEY = 5,
|
||||
AGREE_KEY = 6,
|
||||
ATTEST_KEY = 7,
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ cc_test {
|
||||
"use_libaidlvintf_gtest_helper_static",
|
||||
],
|
||||
srcs: [
|
||||
"AttestKeyTest.cpp",
|
||||
"KeyMintTest.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
|
||||
235
security/keymint/aidl/vts/functional/AttestKeyTest.cpp
Normal file
235
security/keymint/aidl/vts/functional/AttestKeyTest.cpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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()), \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -288,6 +288,7 @@ class AuthorizationSetBuilder : public AuthorizationSet {
|
||||
|
||||
AuthorizationSetBuilder& SigningKey();
|
||||
AuthorizationSetBuilder& EncryptionKey();
|
||||
AuthorizationSetBuilder& AttestKey();
|
||||
|
||||
AuthorizationSetBuilder& NoDigestOrPadding();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user