summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn Willden <swillden@google.com>2016-03-09 19:38:44 -0700
committerShawn Willden <swillden@google.com>2016-03-26 09:10:54 -0600
commit3609584c328ea66f95478dded394ad4697779450 (patch)
treebbed0effcf6f2aaeeb1f8a2beb71f5ef80cf9213
parente802a1e6cd0837fa9ba58a2a0b376a80ecdaec38 (diff)
downloadkeymaster-3609584c328ea66f95478dded394ad4697779450.tar.gz
Correct attestation record.
This CL updates the attestation record content and format to match the final version published in the keymaster2 implementation guide. Change-Id: I112c7557b1c650420fd2fad78c8ed3fc9e34f24e
-rw-r--r--android_keymaster_test.cpp75
-rw-r--r--asymmetric_key.cpp23
-rw-r--r--attestation_record.cpp242
-rw-r--r--attestation_record.h6
-rw-r--r--attestation_record_test.cpp66
-rw-r--r--include/keymaster/authorization_set.h7
-rw-r--r--include/keymaster/keymaster_context.h5
-rw-r--r--include/keymaster/soft_keymaster_context.h4
8 files changed, 237 insertions, 191 deletions
diff --git a/android_keymaster_test.cpp b/android_keymaster_test.cpp
index c02f670..70c2022 100644
--- a/android_keymaster_test.cpp
+++ b/android_keymaster_test.cpp
@@ -3500,9 +3500,11 @@ static ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
return attest_rec;
}
-static bool verify_attestation_record(const string& challenge, bool has_unique_id,
+static bool verify_attestation_record(const string& challenge,
AuthorizationSet expected_sw_enforced,
AuthorizationSet expected_tee_enforced,
+ uint32_t expected_keymaster_version,
+ keymaster_security_level_t expected_keymaster_security_level,
const keymaster_blob_t& attestation_cert) {
X509_Ptr cert(parse_cert_blob(attestation_cert));
@@ -3517,24 +3519,27 @@ static bool verify_attestation_record(const string& challenge, bool has_unique_i
AuthorizationSet att_sw_enforced;
AuthorizationSet att_tee_enforced;
+ uint32_t att_attestation_version;
uint32_t att_keymaster_version;
+ keymaster_security_level_t att_attestation_security_level;
+ keymaster_security_level_t att_keymaster_security_level;
keymaster_blob_t att_challenge = {};
keymaster_blob_t att_unique_id = {};
- EXPECT_EQ(KM_ERROR_OK,
- parse_attestation_record(attest_rec->data, attest_rec->length, &att_keymaster_version,
- &att_challenge, &att_sw_enforced, &att_tee_enforced,
- &att_unique_id));
+ EXPECT_EQ(KM_ERROR_OK, 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_tee_enforced, &att_unique_id));
+
+ EXPECT_EQ(1U, att_attestation_version);
+ EXPECT_EQ(KM_SECURITY_LEVEL_SOFTWARE, att_attestation_security_level);
+ EXPECT_EQ(expected_keymaster_version, att_keymaster_version);
+ EXPECT_EQ(expected_keymaster_security_level, att_keymaster_security_level);
EXPECT_EQ(challenge.length(), att_challenge.data_length);
EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data, challenge.length()));
- if (has_unique_id) {
- EXPECT_LT(0U, att_unique_id.data_length);
- } else {
- EXPECT_EQ(0U, att_unique_id.data_length);
- }
-
- // Add TAG_USER_ID to the attestation sw-enforced list, because user IDs are not included in
+ // Add TAG_USER_ID to the relevant attestation list, because user IDs are not included in
// attestations, since they're meaningless off-device.
uint32_t user_id;
if (expected_sw_enforced.GetTagValue(TAG_USER_ID, &user_id))
@@ -3542,6 +3547,13 @@ static bool verify_attestation_record(const string& challenge, bool has_unique_i
if (expected_tee_enforced.GetTagValue(TAG_USER_ID, &user_id))
att_tee_enforced.push_back(TAG_USER_ID, user_id);
+ // Add TAG_INCLUDE_UNIQUE_ID to the relevant attestation list, because that tag is not included
+ // in the attestation.
+ if (expected_sw_enforced.GetTagValue(TAG_INCLUDE_UNIQUE_ID))
+ att_sw_enforced.push_back(TAG_INCLUDE_UNIQUE_ID);
+ if (expected_tee_enforced.GetTagValue(TAG_INCLUDE_UNIQUE_ID))
+ att_tee_enforced.push_back(TAG_INCLUDE_UNIQUE_ID);
+
att_sw_enforced.Sort();
expected_sw_enforced.Sort();
EXPECT_EQ(expected_sw_enforced, att_sw_enforced);
@@ -3564,18 +3576,21 @@ TEST_P(AttestationTest, RsaAttestation) {
EXPECT_EQ(KM_ERROR_OK, AttestKey("challenge", &cert_chain));
EXPECT_EQ(3U, cert_chain.entry_count);
EXPECT_TRUE(verify_chain(cert_chain));
- EXPECT_TRUE(verify_attestation_record("challenge", true /* has_unique_id */, sw_enforced(),
- hw_enforced(), cert_chain.entries[0]));
- // Uncomment to write certificate files. This is a convenient way to generate certs to test
- // parsing with other tools.
+ uint32_t expected_keymaster_version;
+ keymaster_security_level_t expected_keymaster_security_level;
+ // TODO(swillden): Add a test KM1 that claims to be hardware.
+ if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) {
+ expected_keymaster_version = 0;
+ expected_keymaster_security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+ } else {
+ expected_keymaster_version = 2;
+ expected_keymaster_security_level = KM_SECURITY_LEVEL_SOFTWARE;
+ }
- // for (size_t i = 0; i < cert_chain.entry_count; ++i) {
- // ofstream out(string("cert_") + (char)('0' + i) + ".der", ofstream::out |
- // ofstream::trunc);
- // out.write(reinterpret_cast<const char*>(cert_chain.entries[i].data),
- // cert_chain.entries[i].data_length);
- // }
+ EXPECT_TRUE(verify_attestation_record(
+ "challenge", sw_enforced(), hw_enforced(), expected_keymaster_version,
+ expected_keymaster_security_level, cert_chain.entries[0]));
keymaster_free_cert_chain(&cert_chain);
}
@@ -3584,12 +3599,24 @@ TEST_P(AttestationTest, EcAttestation) {
ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(
KM_DIGEST_SHA_2_256)));
+ uint32_t expected_keymaster_version;
+ keymaster_security_level_t expected_keymaster_security_level;
+ // TODO(swillden): Add a test KM1 that claims to be hardware.
+ if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) {
+ expected_keymaster_version = 0;
+ expected_keymaster_security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+ } else {
+ expected_keymaster_version = 2;
+ expected_keymaster_security_level = KM_SECURITY_LEVEL_SOFTWARE;
+ }
+
keymaster_cert_chain_t cert_chain;
EXPECT_EQ(KM_ERROR_OK, AttestKey("challenge", &cert_chain));
EXPECT_EQ(3U, cert_chain.entry_count);
EXPECT_TRUE(verify_chain(cert_chain));
- EXPECT_TRUE(verify_attestation_record("challenge", false /* has_unique_id */, sw_enforced(),
- hw_enforced(), cert_chain.entries[0]));
+ EXPECT_TRUE(verify_attestation_record(
+ "challenge", sw_enforced(), hw_enforced(), expected_keymaster_version,
+ expected_keymaster_security_level, cert_chain.entries[0]));
keymaster_free_cert_chain(&cert_chain);
}
diff --git a/asymmetric_key.cpp b/asymmetric_key.cpp
index 2924144..4412618 100644
--- a/asymmetric_key.cpp
+++ b/asymmetric_key.cpp
@@ -32,7 +32,7 @@ namespace {
template <typename T> T min(T a, T b) {
return (a < b) ? a : b;
}
-} // anonymous namespace
+} // anonymous namespace
keymaster_error_t AsymmetricKey::formatted_key_material(keymaster_key_format_t format,
UniquePtr<uint8_t[]>* material,
@@ -68,6 +68,7 @@ keymaster_error_t AsymmetricKey::formatted_key_material(keymaster_key_format_t f
static keymaster_error_t build_attestation_extension(const AuthorizationSet& attest_params,
const AuthorizationSet& tee_enforced,
const AuthorizationSet& sw_enforced,
+ const KeymasterContext& context,
X509_EXTENSION_Ptr* extension) {
ASN1_OBJECT_Ptr oid(
OBJ_txt2obj(kAttestionRecordOid, 1 /* accept numerical dotted string form only */));
@@ -77,7 +78,7 @@ static keymaster_error_t build_attestation_extension(const AuthorizationSet& att
UniquePtr<uint8_t[]> attest_bytes;
size_t attest_bytes_len;
keymaster_error_t error = build_attestation_record(attest_params, sw_enforced, tee_enforced,
- &attest_bytes, &attest_bytes_len);
+ context, &attest_bytes, &attest_bytes_len);
if (error != KM_ERROR_OK)
return error;
@@ -104,11 +105,12 @@ static bool add_public_key(EVP_PKEY* key, X509* certificate, keymaster_error_t*
static bool add_attestation_extension(const AuthorizationSet& attest_params,
const AuthorizationSet& tee_enforced,
- const AuthorizationSet& sw_enforced, X509* certificate,
+ const AuthorizationSet& sw_enforced,
+ const KeymasterContext& context, X509* certificate,
keymaster_error_t* error) {
X509_EXTENSION_Ptr attest_extension;
- *error =
- build_attestation_extension(attest_params, tee_enforced, sw_enforced, &attest_extension);
+ *error = build_attestation_extension(attest_params, tee_enforced, sw_enforced, context,
+ &attest_extension);
if (*error != KM_ERROR_OK)
return false;
@@ -207,11 +209,7 @@ keymaster_error_t AsymmetricKey::GenerateAttestation(const KeymasterContext& con
return TranslateLastOpenSslError();
ASN1_INTEGER_Ptr serialNumber(ASN1_INTEGER_new());
- if (!serialNumber.get() ||
- !ASN1_INTEGER_set(
- serialNumber.get(),
- 10000 /* TODO(swillden): Figure out what should go in serial number; probably a random
- * value */) ||
+ if (!serialNumber.get() || !ASN1_INTEGER_set(serialNumber.get(), 1) ||
!X509_set_serialNumber(certificate.get(), serialNumber.get() /* Don't release; copied */))
return TranslateLastOpenSslError();
@@ -232,7 +230,6 @@ keymaster_error_t AsymmetricKey::GenerateAttestation(const KeymasterContext& con
!X509_set_subject_name(certificate.get(), subjectName.get() /* Don't release; copied */))
return TranslateLastOpenSslError();
- // TODO(swillden): Use key activity and expiration dates for notBefore and notAfter.
ASN1_TIME_Ptr notBefore(ASN1_TIME_new());
uint64_t activeDateTime = 0;
authorizations().GetTagValue(TAG_ACTIVE_DATETIME, &activeDateTime);
@@ -256,8 +253,8 @@ keymaster_error_t AsymmetricKey::GenerateAttestation(const KeymasterContext& con
if (!sign_key.get() || //
!add_public_key(pkey.get(), certificate.get(), &error) ||
- !add_attestation_extension(attest_params, tee_enforced, sw_enforced, certificate.get(),
- &error))
+ !add_attestation_extension(attest_params, tee_enforced, sw_enforced, context,
+ certificate.get(), &error))
return error;
if (!X509_sign(certificate.get(), sign_key.get(), EVP_sha256()))
diff --git a/attestation_record.cpp b/attestation_record.cpp
index 47a7d45..868613a 100644
--- a/attestation_record.cpp
+++ b/attestation_record.cpp
@@ -24,6 +24,7 @@
#include "openssl_utils.h"
#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/keymaster_context.h>
namespace keymaster {
@@ -43,14 +44,14 @@ struct ASN1_TYPE_Delete {
typedef struct km_root_of_trust {
ASN1_OCTET_STRING* verified_boot_key;
- ASN1_INTEGER* os_version;
- ASN1_INTEGER* os_patchlevel;
+ ASN1_BOOLEAN* device_locked;
+ ASN1_ENUMERATED* verified_boot_state;
} KM_ROOT_OF_TRUST;
ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = {
ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING),
- ASN1_SIMPLE(KM_ROOT_OF_TRUST, os_version, ASN1_INTEGER),
- ASN1_SIMPLE(KM_ROOT_OF_TRUST, os_patchlevel, ASN1_INTEGER),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED),
} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
@@ -58,66 +59,43 @@ typedef struct km_auth_list {
ASN1_INTEGER_SET* purpose;
ASN1_INTEGER* algorithm;
ASN1_INTEGER* key_size;
- ASN1_INTEGER_SET* block_mode;
ASN1_INTEGER_SET* digest;
ASN1_INTEGER_SET* padding;
- ASN1_NULL* caller_nonce;
- ASN1_INTEGER* min_mac_length;
ASN1_INTEGER_SET* kdf;
ASN1_INTEGER* ec_curve;
ASN1_INTEGER* rsa_public_exponent;
- ASN1_NULL* ecies_single_hash_mode;
- ASN1_NULL* include_unique_id;
- ASN1_INTEGER* blob_usage_requirement;
- ASN1_NULL* bootloader_only;
ASN1_INTEGER* active_date_time;
ASN1_INTEGER* origination_expire_date_time;
ASN1_INTEGER* usage_expire_date_time;
- ASN1_INTEGER* min_seconds_between_ops;
- ASN1_INTEGER* max_uses_per_boot;
ASN1_NULL* no_auth_required;
ASN1_INTEGER* user_auth_type;
ASN1_INTEGER* auth_timeout;
ASN1_NULL* allow_while_on_body;
ASN1_NULL* all_applications;
ASN1_OCTET_STRING* application_id;
- ASN1_OCTET_STRING* application_data;
ASN1_INTEGER* creation_date_time;
ASN1_INTEGER* origin;
ASN1_NULL* rollback_resistant;
KM_ROOT_OF_TRUST* root_of_trust;
ASN1_INTEGER* os_version;
ASN1_INTEGER* os_patchlevel;
- ASN1_OCTET_STRING* unique_id;
} KM_AUTH_LIST;
ASN1_SEQUENCE(KM_AUTH_LIST) = {
ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.masked_tag()),
ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.masked_tag()),
ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.masked_tag()),
- ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, block_mode, ASN1_INTEGER, TAG_BLOCK_MODE.masked_tag()),
ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.masked_tag()),
ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, caller_nonce, ASN1_NULL, TAG_CALLER_NONCE.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, min_mac_length, ASN1_INTEGER, TAG_MIN_MAC_LENGTH.masked_tag()),
ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, kdf, ASN1_INTEGER, TAG_KDF.masked_tag()),
ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.masked_tag()),
ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
TAG_RSA_PUBLIC_EXPONENT.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, ecies_single_hash_mode, ASN1_NULL,
- TAG_ECIES_SINGLE_HASH_MODE.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, include_unique_id, ASN1_NULL, TAG_INCLUDE_UNIQUE_ID.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, blob_usage_requirement, ASN1_INTEGER,
- TAG_BLOB_USAGE_REQUIREMENTS.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, bootloader_only, ASN1_NULL, TAG_BOOTLOADER_ONLY.masked_tag()),
ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.masked_tag()),
ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
TAG_ORIGINATION_EXPIRE_DATETIME.masked_tag()),
ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
TAG_USAGE_EXPIRE_DATETIME.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, min_seconds_between_ops, ASN1_INTEGER,
- TAG_MIN_SECONDS_BETWEEN_OPS.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, max_uses_per_boot, ASN1_INTEGER, TAG_MAX_USES_PER_BOOT.masked_tag()),
ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.masked_tag()),
ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.masked_tag()),
ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.masked_tag()),
@@ -125,18 +103,21 @@ ASN1_SEQUENCE(KM_AUTH_LIST) = {
TAG_ALLOW_WHILE_ON_BODY.masked_tag()),
ASN1_EXP_OPT(KM_AUTH_LIST, all_applications, ASN1_NULL, TAG_ALL_APPLICATIONS.masked_tag()),
ASN1_EXP_OPT(KM_AUTH_LIST, application_id, ASN1_OCTET_STRING, TAG_APPLICATION_ID.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, application_data, ASN1_OCTET_STRING,
- TAG_APPLICATION_DATA.masked_tag()),
ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER,
TAG_CREATION_DATETIME.masked_tag()),
ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.masked_tag()),
ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistant, ASN1_NULL, TAG_ROLLBACK_RESISTANT.masked_tag()),
ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.masked_tag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.masked_tag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.masked_tag()),
} ASN1_SEQUENCE_END(KM_AUTH_LIST);
IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
typedef struct km_key_description {
+ ASN1_INTEGER* attestation_version;
+ ASN1_ENUMERATED* attestation_security_level;
ASN1_INTEGER* keymaster_version;
+ ASN1_ENUMERATED* keymaster_security_level;
ASN1_OCTET_STRING* attestation_challenge;
KM_AUTH_LIST* software_enforced;
KM_AUTH_LIST* tee_enforced;
@@ -144,11 +125,14 @@ typedef struct km_key_description {
} KM_KEY_DESCRIPTION;
ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = {
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_version, ASN1_INTEGER),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_security_level, ASN1_ENUMERATED),
ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_version, ASN1_INTEGER),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_security_level, ASN1_ENUMERATED),
ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_challenge, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, unique_id, ASN1_OCTET_STRING),
ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST),
ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST),
- ASN1_OPT(KM_KEY_DESCRIPTION, unique_id, ASN1_OCTET_STRING),
} ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION);
IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION);
@@ -203,9 +187,11 @@ static keymaster_error_t insert_integer(ASN1_INTEGER* value, ASN1_INTEGER** dest
// Put the contents of the keymaster AuthorizationSet auth_list in to the ASN.1 record structure,
// record.
static keymaster_error_t build_auth_list(const AuthorizationSet& auth_list, KM_AUTH_LIST* record) {
-
assert(record);
+ if (auth_list.empty())
+ return KM_ERROR_OK;
+
for (auto entry : auth_list) {
ASN1_INTEGER_SET** integer_set = nullptr;
@@ -227,6 +213,18 @@ static keymaster_error_t build_auth_list(const AuthorizationSet& auth_list, KM_A
case KM_TAG_EXPORTABLE:
case KM_TAG_RESET_SINCE_ID_ROTATION:
case KM_TAG_ATTESTATION_CHALLENGE:
+ case KM_TAG_BLOCK_MODE:
+ case KM_TAG_CALLER_NONCE:
+ case KM_TAG_MIN_MAC_LENGTH:
+ case KM_TAG_ECIES_SINGLE_HASH_MODE:
+ case KM_TAG_INCLUDE_UNIQUE_ID:
+ case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+ case KM_TAG_BOOTLOADER_ONLY:
+ case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
+ case KM_TAG_MAX_USES_PER_BOOT:
+ case KM_TAG_APPLICATION_DATA:
+ case KM_TAG_UNIQUE_ID:
+ case KM_TAG_ROOT_OF_TRUST:
continue;
/* Non-repeating enumerations */
@@ -236,9 +234,6 @@ static keymaster_error_t build_auth_list(const AuthorizationSet& auth_list, KM_A
case KM_TAG_EC_CURVE:
integer_ptr = &record->ec_curve;
break;
- case KM_TAG_BLOB_USAGE_REQUIREMENTS:
- integer_ptr = &record->blob_usage_requirement;
- break;
case KM_TAG_USER_AUTH_TYPE:
integer_ptr = &record->user_auth_type;
break;
@@ -250,9 +245,6 @@ static keymaster_error_t build_auth_list(const AuthorizationSet& auth_list, KM_A
case KM_TAG_PURPOSE:
integer_set = &record->purpose;
break;
- case KM_TAG_BLOCK_MODE:
- integer_set = &record->block_mode;
- break;
case KM_TAG_PADDING:
integer_set = &record->padding;
break;
@@ -267,18 +259,15 @@ static keymaster_error_t build_auth_list(const AuthorizationSet& auth_list, KM_A
case KM_TAG_KEY_SIZE:
integer_ptr = &record->key_size;
break;
- case KM_TAG_MIN_MAC_LENGTH:
- integer_ptr = &record->min_mac_length;
- break;
- case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
- integer_ptr = &record->min_seconds_between_ops;
- break;
- case KM_TAG_MAX_USES_PER_BOOT:
- integer_ptr = &record->max_uses_per_boot;
- break;
case KM_TAG_AUTH_TIMEOUT:
integer_ptr = &record->auth_timeout;
break;
+ case KM_TAG_OS_VERSION:
+ integer_ptr = &record->os_version;
+ break;
+ case KM_TAG_OS_PATCHLEVEL:
+ integer_ptr = &record->os_patchlevel;
+ break;
/* Non-repeating long unsigned integers */
case KM_TAG_RSA_PUBLIC_EXPONENT:
@@ -300,15 +289,6 @@ static keymaster_error_t build_auth_list(const AuthorizationSet& auth_list, KM_A
break;
/* Booleans */
- case KM_TAG_CALLER_NONCE:
- bool_ptr = &record->caller_nonce;
- break;
- case KM_TAG_ECIES_SINGLE_HASH_MODE:
- bool_ptr = &record->ecies_single_hash_mode;
- break;
- case KM_TAG_BOOTLOADER_ONLY:
- bool_ptr = &record->bootloader_only;
- break;
case KM_TAG_NO_AUTH_REQUIRED:
bool_ptr = &record->no_auth_required;
break;
@@ -318,9 +298,6 @@ static keymaster_error_t build_auth_list(const AuthorizationSet& auth_list, KM_A
case KM_TAG_ROLLBACK_RESISTANT:
bool_ptr = &record->rollback_resistant;
break;
- case KM_TAG_INCLUDE_UNIQUE_ID:
- bool_ptr = &record->include_unique_id;
- break;
case KM_TAG_ALLOW_WHILE_ON_BODY:
bool_ptr = &record->allow_while_on_body;
break;
@@ -329,35 +306,6 @@ static keymaster_error_t build_auth_list(const AuthorizationSet& auth_list, KM_A
case KM_TAG_APPLICATION_ID:
string_ptr = &record->application_id;
break;
- case KM_TAG_APPLICATION_DATA:
- string_ptr = &record->application_data;
- break;
- case KM_TAG_UNIQUE_ID:
- string_ptr = &record->unique_id;
- break;
-
- /* Root of Trust components */
- case KM_TAG_OS_VERSION:
- case KM_TAG_OS_PATCHLEVEL:
- case KM_TAG_ROOT_OF_TRUST:
- if (!record->root_of_trust)
- record->root_of_trust = KM_ROOT_OF_TRUST_new();
- if (!record->root_of_trust)
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- switch (entry.tag) {
- case KM_TAG_OS_VERSION:
- integer_ptr = &record->root_of_trust->os_version;
- break;
- case KM_TAG_OS_PATCHLEVEL:
- integer_ptr = &record->root_of_trust->os_patchlevel;
- break;
- case KM_TAG_ROOT_OF_TRUST:
- string_ptr = &record->root_of_trust->verified_boot_key;
- break;
- default:
- assert(false); // Can't get here.
- }
- break;
}
keymaster_tag_type_t type = keymaster_tag_get_type(entry.tag);
@@ -438,6 +386,7 @@ static keymaster_error_t build_auth_list(const AuthorizationSet& auth_list, KM_A
keymaster_error_t build_attestation_record(const AuthorizationSet& attestation_params,
const AuthorizationSet& sw_enforced,
const AuthorizationSet& tee_enforced,
+ const KeymasterContext& context,
UniquePtr<uint8_t[]>* asn1_key_desc,
size_t* asn1_key_desc_len) {
assert(asn1_key_desc && asn1_key_desc_len);
@@ -446,9 +395,38 @@ keymaster_error_t build_attestation_record(const AuthorizationSet& attestation_p
if (!key_desc.get())
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- keymaster_error_t error;
+ keymaster_security_level_t keymaster_security_level;
+ uint32_t keymaster_version = UINT32_MAX;
+ if (tee_enforced.empty()) {
+ // Software key.
+ keymaster_security_level = KM_SECURITY_LEVEL_SOFTWARE;
+ keymaster_version = 2;
+ } else {
+ keymaster_security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+ switch (context.GetSecurityLevel()) {
+ case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT:
+ // We're running in a TEE, so the key is KM2.
+ keymaster_version = 2;
+ break;
+
+ case KM_SECURITY_LEVEL_SOFTWARE:
+ // We're running in software, wrapping some KM hardware. Is it KM0 or KM1? KM1 keys
+ // have the purpose in the tee_enforced list. It's possible that a key could be created
+ // without a purpose, which would fool this test into reporting it's a KM0 key. That
+ // corner case doesn't matter much, because purpose-less keys are not usable anyway.
+ // Also, KM1 TEEs should disappear rapidly.
+ keymaster_version = tee_enforced.Contains(TAG_PURPOSE) ? 1 : 0;
+ break;
+ }
+
+ if (keymaster_version == UINT32_MAX)
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
- if (!ASN1_INTEGER_set(key_desc->keymaster_version, 2))
+ if (!ASN1_INTEGER_set(key_desc->attestation_version, 1) ||
+ !ASN1_ENUMERATED_set(key_desc->attestation_security_level, context.GetSecurityLevel()) ||
+ !ASN1_INTEGER_set(key_desc->keymaster_version, keymaster_version) ||
+ !ASN1_ENUMERATED_set(key_desc->keymaster_security_level, keymaster_security_level))
return TranslateLastOpenSslError();
keymaster_blob_t attestation_challenge = {};
@@ -458,7 +436,7 @@ keymaster_error_t build_attestation_record(const AuthorizationSet& attestation_p
attestation_challenge.data_length))
return TranslateLastOpenSslError();
- error = build_auth_list(sw_enforced, key_desc->software_enforced);
+ keymaster_error_t error = build_auth_list(sw_enforced, key_desc->software_enforced);
if (error != KM_ERROR_OK)
return error;
@@ -528,6 +506,9 @@ static bool get_ulong(const ASN1_INTEGER* asn1_int, keymaster_tag_t tag,
// Extract the values from the specified ASN.1 record and place them in auth_list.
static keymaster_error_t extract_auth_list(const KM_AUTH_LIST* record,
AuthorizationSet* auth_list) {
+ if (!record)
+ return KM_ERROR_OK;
+
// Purpose
if (!get_repeated_enums(record->purpose, TAG_PURPOSE, auth_list))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
@@ -540,10 +521,6 @@ static keymaster_error_t extract_auth_list(const KM_AUTH_LIST* record,
if (record->key_size && !auth_list->push_back(TAG_KEY_SIZE, ASN1_INTEGER_get(record->key_size)))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- // Block mode
- if (!get_repeated_enums(record->block_mode, TAG_BLOCK_MODE, auth_list))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
// Digest
if (!get_repeated_enums(record->digest, TAG_DIGEST, auth_list))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
@@ -552,15 +529,6 @@ static keymaster_error_t extract_auth_list(const KM_AUTH_LIST* record,
if (!get_repeated_enums(record->padding, TAG_PADDING, auth_list))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- // Caller NONCE
- if (record->caller_nonce && !auth_list->push_back(TAG_CALLER_NONCE))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Min MAC length
- if (record->min_mac_length &&
- !auth_list->push_back(TAG_MIN_MAC_LENGTH, ASN1_INTEGER_get(record->min_mac_length)))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
// EC curve
if (!get_enum(record->ec_curve, TAG_EC_CURVE, auth_list))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
@@ -569,22 +537,6 @@ static keymaster_error_t extract_auth_list(const KM_AUTH_LIST* record,
if (!get_ulong(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- // ECIES single hash mode
- if (record->ecies_single_hash_mode && !auth_list->push_back(TAG_ECIES_SINGLE_HASH_MODE))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Include unique ID
- if (record->include_unique_id && !auth_list->push_back(TAG_INCLUDE_UNIQUE_ID))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Blob usage requirement
- if (!get_enum(record->blob_usage_requirement, TAG_BLOB_USAGE_REQUIREMENTS, auth_list))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Bootloader only
- if (record->bootloader_only && !auth_list->push_back(TAG_BOOTLOADER_ONLY))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
// Active date time
if (!get_ulong(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
@@ -598,17 +550,6 @@ static keymaster_error_t extract_auth_list(const KM_AUTH_LIST* record,
if (!get_ulong(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- // Min seconds between ops
- if (record->min_seconds_between_ops &&
- !auth_list->push_back(TAG_MIN_SECONDS_BETWEEN_OPS,
- ASN1_INTEGER_get(record->min_seconds_between_ops)))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Max uses per boot
- if (record->max_uses_per_boot &&
- !auth_list->push_back(TAG_MAX_USES_PER_BOOT, ASN1_INTEGER_get(record->max_uses_per_boot)))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
// No auth required
if (record->no_auth_required && !auth_list->push_back(TAG_NO_AUTH_REQUIRED))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
@@ -632,12 +573,6 @@ static keymaster_error_t extract_auth_list(const KM_AUTH_LIST* record,
record->application_id->length))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- // Application data
- if (record->application_data &&
- !auth_list->push_back(TAG_APPLICATION_DATA, record->application_data->data,
- record->application_data->length))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
// Creation date time
if (!get_ulong(record->creation_date_time, TAG_CREATION_DATETIME, auth_list))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
@@ -653,23 +588,32 @@ static keymaster_error_t extract_auth_list(const KM_AUTH_LIST* record,
// Root of trust
if (record->root_of_trust) {
KM_ROOT_OF_TRUST* rot = record->root_of_trust;
- if (!rot->verified_boot_key || !rot->os_version || !rot->os_patchlevel)
+ if (!rot->verified_boot_key)
return KM_ERROR_INVALID_KEY_BLOB;
- if (!auth_list->push_back(TAG_OS_VERSION, ASN1_INTEGER_get(rot->os_version)) ||
- !auth_list->push_back(TAG_OS_PATCHLEVEL, ASN1_INTEGER_get(rot->os_patchlevel)) ||
- !auth_list->push_back(TAG_ROOT_OF_TRUST, rot->verified_boot_key->data,
- rot->verified_boot_key->length))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ // Other root of trust fields are not mapped to auth set entries.
}
+ // OS Version
+ if (record->os_version &&
+ !auth_list->push_back(TAG_OS_VERSION, ASN1_INTEGER_get(record->os_version)))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // OS Patch level
+ if (record->os_patchlevel &&
+ !auth_list->push_back(TAG_OS_PATCHLEVEL, ASN1_INTEGER_get(record->os_patchlevel)))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
return KM_ERROR_OK;
}
// Parse the DER-encoded attestation record, placing the results in keymaster_version,
// attestation_challenge, software_enforced, tee_enforced and unique_id.
keymaster_error_t parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+ uint32_t* attestation_version, //
+ keymaster_security_level_t* attestation_security_level,
uint32_t* keymaster_version,
+ keymaster_security_level_t* keymaster_security_level,
keymaster_blob_t* attestation_challenge,
AuthorizationSet* software_enforced,
AuthorizationSet* tee_enforced,
@@ -680,17 +624,19 @@ keymaster_error_t parse_attestation_record(const uint8_t* asn1_key_desc, size_t
if (!record.get())
return TranslateLastOpenSslError();
+ *attestation_version = ASN1_INTEGER_get(record->attestation_version);
+ *attestation_security_level = static_cast<keymaster_security_level_t>(
+ ASN1_ENUMERATED_get(record->attestation_security_level));
*keymaster_version = ASN1_INTEGER_get(record->keymaster_version);
+ *keymaster_security_level = static_cast<keymaster_security_level_t>(
+ ASN1_ENUMERATED_get(record->keymaster_security_level));
+
attestation_challenge->data =
dup_buffer(record->attestation_challenge->data, record->attestation_challenge->length);
attestation_challenge->data_length = record->attestation_challenge->length;
- if (record->unique_id) {
- unique_id->data = dup_buffer(record->unique_id->data, record->unique_id->length);
- unique_id->data_length = record->unique_id->length;
- } else {
- *unique_id = {};
- }
+ unique_id->data = dup_buffer(record->unique_id->data, record->unique_id->length);
+ unique_id->data_length = record->unique_id->length;
keymaster_error_t error = extract_auth_list(record->software_enforced, software_enforced);
if (error != KM_ERROR_OK)
diff --git a/attestation_record.h b/attestation_record.h
index 40e40c5..64acabc 100644
--- a/attestation_record.h
+++ b/attestation_record.h
@@ -23,6 +23,8 @@
namespace keymaster {
+class KeymasterContext;
+
/**
* The OID for Android attestation records. For the curious, it breaks down as follows:
*
@@ -42,11 +44,15 @@ static const char kAttestionRecordOid[] = "1.3.6.1.4.1.11129.2.1.17";
keymaster_error_t build_attestation_record(const AuthorizationSet& attestation_params,
const AuthorizationSet& software_enforced,
const AuthorizationSet& tee_enforced,
+ const KeymasterContext& context,
UniquePtr<uint8_t[]>* asn1_key_desc,
size_t* asn1_key_desc_len);
keymaster_error_t parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+ uint32_t* attestation_version, //
+ keymaster_security_level_t* attestation_security_level,
uint32_t* keymaster_version,
+ keymaster_security_level_t* keymaster_security_level,
keymaster_blob_t* attestation_challenge,
AuthorizationSet* software_enforced,
AuthorizationSet* tee_enforced,
diff --git a/attestation_record_test.cpp b/attestation_record_test.cpp
index 2d1fc8c..2d7af3b 100644
--- a/attestation_record_test.cpp
+++ b/attestation_record_test.cpp
@@ -18,18 +18,67 @@
#include <gtest/gtest.h>
+#include <keymaster/keymaster_context.h>
+
#include "android_keymaster_test_utils.h"
#include "attestation_record.h"
namespace keymaster {
namespace test {
+class TestContext : public KeymasterContext {
+ public:
+ keymaster_security_level_t GetSecurityLevel() const override {
+ return KM_SECURITY_LEVEL_SOFTWARE;
+ }
+
+ KeyFactory* GetKeyFactory(keymaster_algorithm_t /* algorithm */) const override {
+ return nullptr;
+ }
+ OperationFactory* GetOperationFactory(keymaster_algorithm_t /* algorithm */,
+ keymaster_purpose_t /* purpose */) const override {
+ return nullptr;
+ }
+ keymaster_algorithm_t* GetSupportedAlgorithms(size_t* /* algorithms_count */) const override {
+ return nullptr;
+ }
+ keymaster_error_t CreateKeyBlob(const AuthorizationSet& /* key_description */,
+ keymaster_key_origin_t /* origin */,
+ const KeymasterKeyBlob& /* key_material */,
+ KeymasterKeyBlob* /* blob */,
+ AuthorizationSet* /* hw_enforced */,
+ AuthorizationSet* /* sw_enforced */) const override {
+ return KM_ERROR_UNIMPLEMENTED;
+ }
+ keymaster_error_t ParseKeyBlob(const KeymasterKeyBlob& /* blob */,
+ const AuthorizationSet& /* additional_params */,
+ KeymasterKeyBlob* /* key_material */,
+ AuthorizationSet* /* hw_enforced */,
+ AuthorizationSet* /* sw_enforced */) const override {
+ return KM_ERROR_UNIMPLEMENTED;
+ }
+ keymaster_error_t AddRngEntropy(const uint8_t* /* buf */, size_t /* length */) const override {
+ return KM_ERROR_UNIMPLEMENTED;
+ }
+ keymaster_error_t GenerateRandom(uint8_t* /* buf */, size_t /* length */) const override {
+ return KM_ERROR_UNIMPLEMENTED;
+ }
+ KeymasterEnforcement* enforcement_policy() { return nullptr; }
+ EVP_PKEY* AttestationKey(keymaster_algorithm_t /* algorithm */,
+ keymaster_error_t* /* error */) const override {
+ return nullptr;
+ }
+ keymaster_cert_chain_t* AttestationChain(keymaster_algorithm_t /* algorithm */,
+ keymaster_error_t* /* error */) const override {
+ return nullptr;
+ }
+};
+
TEST(AttestTest, Simple) {
AuthorizationSet hw_set(AuthorizationSetBuilder()
.RsaSigningKey(512, 3)
.Digest(KM_DIGEST_SHA_2_256)
.Digest(KM_DIGEST_SHA_2_384)
- .Authorization(TAG_ROOT_OF_TRUST, "foo", 3)
.Authorization(TAG_OS_VERSION, 60000)
.Authorization(TAG_OS_PATCHLEVEL, 201512)
.Authorization(TAG_APPLICATION_ID, "bar", 3));
@@ -39,8 +88,8 @@ TEST(AttestTest, Simple) {
size_t asn1_len;
AuthorizationSet attest_params(
AuthorizationSetBuilder().Authorization(TAG_ATTESTATION_CHALLENGE, "hello", 5));
- EXPECT_EQ(KM_ERROR_OK,
- build_attestation_record(attest_params, sw_set, hw_set, &asn1, &asn1_len));
+ EXPECT_EQ(KM_ERROR_OK, build_attestation_record(attest_params, sw_set, hw_set, TestContext(),
+ &asn1, &asn1_len));
EXPECT_GT(asn1_len, 0U);
std::ofstream output("attest.der",
@@ -51,12 +100,17 @@ TEST(AttestTest, Simple) {
AuthorizationSet parsed_hw_set;
AuthorizationSet parsed_sw_set;
+ uint32_t attestation_version;
uint32_t keymaster_version;
+ keymaster_security_level_t attestation_security_level;
+ keymaster_security_level_t keymaster_security_level;
keymaster_blob_t attestation_challenge = {};
keymaster_blob_t unique_id = {};
- EXPECT_EQ(KM_ERROR_OK, parse_attestation_record(asn1.get(), asn1_len, &keymaster_version,
- &attestation_challenge, &parsed_sw_set,
- &parsed_hw_set, &unique_id));
+ EXPECT_EQ(KM_ERROR_OK,
+ parse_attestation_record(asn1.get(), asn1_len, &attestation_version,
+ &attestation_security_level, &keymaster_version,
+ &keymaster_security_level, &attestation_challenge,
+ &parsed_sw_set, &parsed_hw_set, &unique_id));
hw_set.Sort();
sw_set.Sort();
diff --git a/include/keymaster/authorization_set.h b/include/keymaster/authorization_set.h
index 7999aba..f7fa28a 100644
--- a/include/keymaster/authorization_set.h
+++ b/include/keymaster/authorization_set.h
@@ -203,6 +203,13 @@ class AuthorizationSet : public Serializable, public keymaster_key_param_set_t {
keymaster_key_param_t operator[](int n) const;
/**
+ * Returns true if the set contains at least one instance of \p tag
+ */
+ bool Contains(keymaster_tag_t tag) const {
+ return find(tag) != -1;
+ }
+
+ /**
* Returns the number of \p tag entries.
*/
size_t GetTagCount(keymaster_tag_t tag) const;
diff --git a/include/keymaster/keymaster_context.h b/include/keymaster/keymaster_context.h
index c9802e4..d598acd 100644
--- a/include/keymaster/keymaster_context.h
+++ b/include/keymaster/keymaster_context.h
@@ -65,6 +65,11 @@ class KeymasterContext {
KeymasterContext() {}
virtual ~KeymasterContext(){};
+ /**
+ * Returns the security level (SW or TEE) of this keymaster implementation.
+ */
+ virtual keymaster_security_level_t GetSecurityLevel() const = 0;
+
virtual KeyFactory* GetKeyFactory(keymaster_algorithm_t algorithm) const = 0;
virtual OperationFactory* GetOperationFactory(keymaster_algorithm_t algorithm,
keymaster_purpose_t purpose) const = 0;
diff --git a/include/keymaster/soft_keymaster_context.h b/include/keymaster/soft_keymaster_context.h
index d9c02f2..65f9c14 100644
--- a/include/keymaster/soft_keymaster_context.h
+++ b/include/keymaster/soft_keymaster_context.h
@@ -53,6 +53,10 @@ class SoftKeymasterContext : public KeymasterContext {
*/
keymaster_error_t SetHardwareDevice(keymaster1_device_t* keymaster1_device);
+ keymaster_security_level_t GetSecurityLevel() const override {
+ return KM_SECURITY_LEVEL_SOFTWARE;
+ }
+
KeyFactory* GetKeyFactory(keymaster_algorithm_t algorithm) const override;
OperationFactory* GetOperationFactory(keymaster_algorithm_t algorithm,
keymaster_purpose_t purpose) const override;