diff options
author | Shawn Willden <swillden@google.com> | 2016-01-05 17:06:56 -0700 |
---|---|---|
committer | Shawn Willden <swillden@google.com> | 2016-01-26 14:15:51 -0700 |
commit | 239c1664173c941038a1d1d13626e58ce3cef819 (patch) | |
tree | cc74f95644378c37f0c1e1056d3dff66e0406d01 /attestation_record.cpp | |
parent | 78c5d8796c560deb2a0194f581f13a833437f012 (diff) | |
download | keymaster-239c1664173c941038a1d1d13626e58ce3cef819.tar.gz |
Add utilities to format/parse ASN.1 attestation records.
Bug: 22914603
Change-Id: I9279df29ec06e07fbd60427e22b8f7a74648c8ed
Diffstat (limited to 'attestation_record.cpp')
-rw-r--r-- | attestation_record.cpp | 651 |
1 files changed, 651 insertions, 0 deletions
diff --git a/attestation_record.cpp b/attestation_record.cpp new file mode 100644 index 0000000..85bec2a --- /dev/null +++ b/attestation_record.cpp @@ -0,0 +1,651 @@ +/* + * Copyright 2016 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. + */ + +#include "attestation_record.h" + +#include <assert.h> + +#include <openssl/asn1t.h> + +#include "openssl_err.h" +#include "openssl_utils.h" + +namespace keymaster { + +struct stack_st_ASN1_TYPE_Delete { + void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); } +}; + +struct ASN1_STRING_Delete { + void operator()(ASN1_STRING* p) { ASN1_STRING_free(p); } +}; + +struct ASN1_TYPE_Delete { + void operator()(ASN1_TYPE* p) { ASN1_TYPE_free(p); } +}; + +#define ASN1_INTEGER_SET STACK_OF(ASN1_INTEGER) + +typedef struct km_root_of_trust { + ASN1_OCTET_STRING* verified_boot_key; + ASN1_INTEGER* os_version; + ASN1_INTEGER* os_patchlevel; +} 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_SEQUENCE_END(KM_ROOT_OF_TRUST); +IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST); + +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* 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_IMP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.masked_tag()), + ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, block_mode, ASN1_INTEGER, TAG_BLOCK_MODE.masked_tag()), + ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.masked_tag()), + ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, caller_nonce, ASN1_NULL, TAG_CALLER_NONCE.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, min_mac_length, ASN1_INTEGER, TAG_MIN_MAC_LENGTH.masked_tag()), + ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, kdf, ASN1_INTEGER, TAG_KDF.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER, + TAG_RSA_PUBLIC_EXPONENT.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, ecies_single_hash_mode, ASN1_NULL, + TAG_ECIES_SINGLE_HASH_MODE.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, include_unique_id, ASN1_NULL, TAG_INCLUDE_UNIQUE_ID.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, blob_usage_requirement, ASN1_INTEGER, + TAG_BLOB_USAGE_REQUIREMENTS.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, bootloader_only, ASN1_NULL, TAG_BOOTLOADER_ONLY.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER, + TAG_ORIGINATION_EXPIRE_DATETIME.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER, + TAG_USAGE_EXPIRE_DATETIME.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, min_seconds_between_ops, ASN1_INTEGER, + TAG_MIN_SECONDS_BETWEEN_OPS.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, max_uses_per_boot, ASN1_INTEGER, TAG_MAX_USES_PER_BOOT.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, all_applications, ASN1_NULL, TAG_ALL_APPLICATIONS.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, application_id, ASN1_OCTET_STRING, TAG_APPLICATION_ID.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, application_data, ASN1_OCTET_STRING, + TAG_APPLICATION_DATA.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER, + TAG_CREATION_DATETIME.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, rollback_resistant, ASN1_NULL, TAG_ROLLBACK_RESISTANT.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.masked_tag()), + ASN1_IMP_OPT(KM_AUTH_LIST, unique_id, ASN1_NULL, TAG_UNIQUE_ID.masked_tag()), +} ASN1_SEQUENCE_END(KM_AUTH_LIST); +IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST); + +typedef struct km_key_description { + KM_AUTH_LIST* software_enforced; + KM_AUTH_LIST* tee_enforced; +} KM_KEY_DESCRIPTION; + +ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = { + ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST), +} ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION); +IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION); + +struct KM_AUTH_LIST_Delete { + void operator()(KM_AUTH_LIST* p) { KM_AUTH_LIST_free(p); } +}; + +struct KM_KEY_DESCRIPTION_Delete { + void operator()(KM_KEY_DESCRIPTION* p) { KM_KEY_DESCRIPTION_free(p); } +}; + +struct ASN1_INTEGER_Delete { + void operator()(ASN1_INTEGER* p) { ASN1_INTEGER_free(p); } +}; + +static uint32_t get_uint32_value(const keymaster_key_param_t& param) { + switch (keymaster_tag_get_type(param.tag)) { + case KM_ENUM: + case KM_ENUM_REP: + return param.enumerated; + case KM_UINT: + case KM_UINT_REP: + return param.integer; + default: + assert(false); + return 0xFFFFFFFF; + } +} + +// Insert value in either the dest_integer or the dest_integer_set, whichever is provided. +static keymaster_error_t insert_integer(ASN1_INTEGER* value, ASN1_INTEGER** dest_integer, + ASN1_INTEGER_SET** dest_integer_set) { + assert((dest_integer == nullptr) ^ (dest_integer_set == nullptr)); + assert(value); + + if (dest_integer_set) { + if (!*dest_integer_set) + *dest_integer_set = sk_ASN1_INTEGER_new_null(); + if (!*dest_integer_set) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + if (!sk_ASN1_INTEGER_push(*dest_integer_set, value)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + return KM_ERROR_OK; + + } else if (dest_integer) { + if (*dest_integer) + ASN1_INTEGER_free(*dest_integer); + *dest_integer = value; + return KM_ERROR_OK; + } + + assert(false); // Should never get here. + return KM_ERROR_OK; +} + +// 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); + + for (auto entry : auth_list) { + + ASN1_INTEGER_SET** integer_set = nullptr; + ASN1_INTEGER** integer_ptr = nullptr; + ASN1_OCTET_STRING** string_ptr = nullptr; + ASN1_NULL** bool_ptr = nullptr; + + switch (entry.tag) { + + /* Ignored tags */ + case KM_TAG_INVALID: + case KM_TAG_ASSOCIATED_DATA: + case KM_TAG_NONCE: + case KM_TAG_AUTH_TOKEN: + case KM_TAG_MAC_LENGTH: + case KM_TAG_ALL_USERS: + case KM_TAG_USER_ID: + case KM_TAG_USER_SECURE_ID: + case KM_TAG_EXPORTABLE: + case KM_TAG_RESET_SINCE_ID_ROTATION: + continue; + + /* Non-repeating enumerations */ + case KM_TAG_ALGORITHM: + integer_ptr = &record->algorithm; + break; + 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; + case KM_TAG_ORIGIN: + integer_ptr = &record->origin; + break; + + /* Repeating enumerations */ + 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; + case KM_TAG_DIGEST: + integer_set = &record->digest; + break; + case KM_TAG_KDF: + integer_set = &record->kdf; + break; + + /* Non-repeating unsigned integers */ + 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; + + /* Non-repeating long unsigned integers */ + case KM_TAG_RSA_PUBLIC_EXPONENT: + integer_ptr = &record->rsa_public_exponent; + break; + + /* Dates */ + case KM_TAG_ACTIVE_DATETIME: + integer_ptr = &record->active_date_time; + break; + case KM_TAG_ORIGINATION_EXPIRE_DATETIME: + integer_ptr = &record->origination_expire_date_time; + break; + case KM_TAG_USAGE_EXPIRE_DATETIME: + integer_ptr = &record->usage_expire_date_time; + break; + case KM_TAG_CREATION_DATETIME: + integer_ptr = &record->creation_date_time; + 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; + case KM_TAG_ALL_APPLICATIONS: + bool_ptr = &record->all_applications; + break; + case KM_TAG_ROLLBACK_RESISTANT: + bool_ptr = &record->rollback_resistant; + break; + case KM_TAG_INCLUDE_UNIQUE_ID: + bool_ptr = &record->include_unique_id; + + /* Byte arrays*/ + 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); + switch (type) { + case KM_ENUM: + case KM_ENUM_REP: + case KM_UINT: + case KM_UINT_REP: { + assert((keymaster_tag_repeatable(entry.tag) && integer_set) || + (!keymaster_tag_repeatable(entry.tag) && integer_ptr)); + + UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value(ASN1_INTEGER_new()); + if (!value.get()) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + if (!ASN1_INTEGER_set(value.get(), get_uint32_value(entry))) + return TranslateLastOpenSslError(); + + insert_integer(value.release(), integer_ptr, integer_set); + break; + } + + case KM_ULONG: + case KM_ULONG_REP: + case KM_DATE: { + assert((keymaster_tag_repeatable(entry.tag) && integer_set) || + (!keymaster_tag_repeatable(entry.tag) && integer_ptr)); + + UniquePtr<BIGNUM, BIGNUM_Delete> exponent(BN_new()); + if (!exponent.get()) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + if (type == KM_DATE) { + if (!BN_set_word(exponent.get(), entry.date_time)) + return TranslateLastOpenSslError(); + } else { + if (!BN_set_word(exponent.get(), entry.long_integer)) + return TranslateLastOpenSslError(); + } + + UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value( + BN_to_ASN1_INTEGER(exponent.get(), nullptr)); + if (!value.get()) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + insert_integer(value.release(), integer_ptr, integer_set); + break; + } + + case KM_BOOL: + assert(bool_ptr); + if (!*bool_ptr) + *bool_ptr = ASN1_NULL_new(); + if (!*bool_ptr) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + break; + + /* Byte arrays*/ + case KM_BYTES: + assert(string_ptr); + if (!*string_ptr) + *string_ptr = ASN1_OCTET_STRING_new(); + if (!*string_ptr) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + if (!ASN1_OCTET_STRING_set(*string_ptr, entry.blob.data, entry.blob.data_length)) + return TranslateLastOpenSslError(); + break; + + default: + return KM_ERROR_UNIMPLEMENTED; + } + } + + return KM_ERROR_OK; +} + +// Construct an ASN1.1 DER-encoded attestation record containing the values from sw_enforced and +// tee_enforced. +keymaster_error_t build_attestation_record(const AuthorizationSet& sw_enforced, + const AuthorizationSet& tee_enforced, + UniquePtr<uint8_t[]>* asn1_key_desc, + size_t* asn1_key_desc_len) { + assert(asn1_key_desc && asn1_key_desc_len); + + UniquePtr<KM_KEY_DESCRIPTION, KM_KEY_DESCRIPTION_Delete> key_desc(KM_KEY_DESCRIPTION_new()); + if (!key_desc.get()) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + keymaster_error_t error; + + error = build_auth_list(sw_enforced, key_desc->software_enforced); + if (error != KM_ERROR_OK) + return error; + error = build_auth_list(tee_enforced, key_desc->tee_enforced); + if (error != KM_ERROR_OK) + return error; + + int len = i2d_KM_KEY_DESCRIPTION(key_desc.get(), nullptr); + if (len < 0) + return TranslateLastOpenSslError(); + *asn1_key_desc_len = len; + asn1_key_desc->reset(new uint8_t[*asn1_key_desc_len]); + if (!asn1_key_desc->get()) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + uint8_t* p = asn1_key_desc->get(); + len = i2d_KM_KEY_DESCRIPTION(key_desc.get(), &p); + if (len < 0) + return TranslateLastOpenSslError(); + + return KM_ERROR_OK; +} + +// Copy all enumerated values with the specified tag from stack to auth_list. +static bool get_repeated_enums(const stack_st_ASN1_INTEGER* stack, keymaster_tag_t tag, + AuthorizationSet* auth_list) { + assert(keymaster_tag_get_type(tag) == KM_ENUM_REP); + for (size_t i = 0; i < sk_ASN1_INTEGER_num(stack); ++i) { + if (!auth_list->push_back( + keymaster_param_enum(tag, ASN1_INTEGER_get(sk_ASN1_INTEGER_value(stack, i))))) + return false; + } + return true; +} + +// Add the specified integer tag/value pair to auth_list. +template <keymaster_tag_type_t Type, keymaster_tag_t Tag, typename KeymasterEnum> +static bool get_enum(const ASN1_INTEGER* asn1_int, TypedEnumTag<Type, Tag, KeymasterEnum> tag, + AuthorizationSet* auth_list) { + if (!asn1_int) + return true; + return auth_list->push_back(tag, static_cast<KeymasterEnum>(ASN1_INTEGER_get(asn1_int))); +} + +// Add the specified ulong tag/value pair to auth_list. +static bool get_ulong(const ASN1_INTEGER* asn1_int, keymaster_tag_t tag, + AuthorizationSet* auth_list) { + if (!asn1_int) + return true; + UniquePtr<BIGNUM, BIGNUM_Delete> bn(ASN1_INTEGER_to_BN(asn1_int, nullptr)); + if (!bn.get()) + return false; + uint64_t ulong = BN_get_word(bn.get()); + return auth_list->push_back(keymaster_param_long(tag, ulong)); +} + +// 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) { + // Purpose + if (!get_repeated_enums(record->purpose, TAG_PURPOSE, auth_list)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Algorithm + if (!get_enum(record->algorithm, TAG_ALGORITHM, auth_list)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Key size + 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; + + // Padding + 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; + + // RSA public exponent + 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; + + // 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; + + // Origination expire date time + if (!get_ulong(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME, + auth_list)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Usage Expire date time + 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; + + // User auth type + if (!get_enum(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Auth timeout + if (record->auth_timeout && + !auth_list->push_back(TAG_AUTH_TIMEOUT, ASN1_INTEGER_get(record->auth_timeout))) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // All applications + if (record->all_applications && !auth_list->push_back(TAG_ALL_APPLICATIONS)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Application ID + if (record->application_id && + !auth_list->push_back(TAG_APPLICATION_ID, record->application_id->data, + 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; + + // Origin + if (!get_enum(record->origin, TAG_ORIGIN, auth_list)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Rollback resistant + if (record->rollback_resistant && !auth_list->push_back(TAG_ROLLBACK_RESISTANT)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // 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) + 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; + } + + return KM_ERROR_OK; +} + +// Parse the DER-encoded attestation record, placing the results in software_enforced and +// tee_enforced. +keymaster_error_t parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len, + AuthorizationSet* software_enforced, + AuthorizationSet* tee_enforced) { + const uint8_t* p = asn1_key_desc; + UniquePtr<KM_KEY_DESCRIPTION, KM_KEY_DESCRIPTION_Delete> record( + d2i_KM_KEY_DESCRIPTION(nullptr, &p, asn1_key_desc_len)); + if (!record.get()) + return TranslateLastOpenSslError(); + + keymaster_error_t error = extract_auth_list(record->software_enforced, software_enforced); + if (error != KM_ERROR_OK) + return error; + + return extract_auth_list(record->tee_enforced, tee_enforced); +} + +} // namepace keymaster |