/* * 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 <keymaster/attestation_record.h> #include <assert.h> #include <openssl/asn1t.h> #include <keymaster/android_keymaster_utils.h> #include <keymaster/km_openssl/openssl_err.h> #include <keymaster/km_openssl/openssl_utils.h> namespace keymaster { constexpr uint kCurrentKeymasterVersion = 3; constexpr uint kCurrentAttestationVersion = 2; constexpr size_t kMaximumAttestationChallengeLength = 128; IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST); IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST); IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION); static const keymaster_tag_t kDeviceAttestationTags[] = { KM_TAG_ATTESTATION_ID_BRAND, KM_TAG_ATTESTATION_ID_DEVICE, KM_TAG_ATTESTATION_ID_PRODUCT, KM_TAG_ATTESTATION_ID_SERIAL, KM_TAG_ATTESTATION_ID_IMEI, KM_TAG_ATTESTATION_ID_MEID, KM_TAG_ATTESTATION_ID_MANUFACTURER, KM_TAG_ATTESTATION_ID_MODEL, }; 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); } }; 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. 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; ASN1_INTEGER** integer_ptr = nullptr; ASN1_OCTET_STRING** string_ptr = nullptr; ASN1_NULL** bool_ptr = nullptr; switch (entry.tag) { /* Tags ignored because they should never exist */ case KM_TAG_INVALID: /* Tags ignored because they're not used. */ case KM_TAG_ALL_USERS: case KM_TAG_EXPORTABLE: case KM_TAG_ECIES_SINGLE_HASH_MODE: /* Tags ignored because they're used only to provide information to operations */ case KM_TAG_ASSOCIATED_DATA: case KM_TAG_NONCE: case KM_TAG_AUTH_TOKEN: case KM_TAG_MAC_LENGTH: case KM_TAG_ATTESTATION_CHALLENGE: case KM_TAG_RESET_SINCE_ID_ROTATION: /* Tags ignored because they have no meaning off-device */ case KM_TAG_USER_ID: case KM_TAG_USER_SECURE_ID: case KM_TAG_BLOB_USAGE_REQUIREMENTS: /* Tags ignored because they're not usable by app keys */ case KM_TAG_BOOTLOADER_ONLY: case KM_TAG_INCLUDE_UNIQUE_ID: case KM_TAG_MAX_USES_PER_BOOT: case KM_TAG_MIN_SECONDS_BETWEEN_OPS: case KM_TAG_UNIQUE_ID: /* Tags ignored because they contain data that should not be exported */ case KM_TAG_APPLICATION_DATA: case KM_TAG_ROOT_OF_TRUST: 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_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_PADDING: integer_set = &record->padding; break; case KM_TAG_DIGEST: integer_set = &record->digest; break; case KM_TAG_KDF: integer_set = &record->kdf; break; case KM_TAG_BLOCK_MODE: integer_set = &record->block_mode; break; /* Non-repeating unsigned integers */ case KM_TAG_KEY_SIZE: integer_ptr = &record->key_size; 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; case KM_TAG_MIN_MAC_LENGTH: integer_ptr = &record->min_mac_length; 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_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_ALLOW_WHILE_ON_BODY: bool_ptr = &record->allow_while_on_body; break; case KM_TAG_UNLOCKED_DEVICE_REQUIRED: bool_ptr = &record->unlocked_device_required; break; case KM_TAG_CALLER_NONCE: bool_ptr = &record->caller_nonce; break; /* Byte arrays*/ case KM_TAG_APPLICATION_ID: string_ptr = &record->application_id; break; case KM_TAG_ATTESTATION_APPLICATION_ID: string_ptr = &record->attestation_application_id; break; case KM_TAG_ATTESTATION_ID_BRAND: string_ptr = &record->attestation_id_brand; break; case KM_TAG_ATTESTATION_ID_DEVICE: string_ptr = &record->attestation_id_device; break; case KM_TAG_ATTESTATION_ID_PRODUCT: string_ptr = &record->attestation_id_product; break; case KM_TAG_ATTESTATION_ID_SERIAL: string_ptr = &record->attestation_id_serial; break; case KM_TAG_ATTESTATION_ID_IMEI: string_ptr = &record->attestation_id_imei; break; case KM_TAG_ATTESTATION_ID_MEID: string_ptr = &record->attestation_id_meid; break; case KM_TAG_ATTESTATION_ID_MANUFACTURER: string_ptr = &record->attestation_id_manufacturer; break; case KM_TAG_ATTESTATION_ID_MODEL: string_ptr = &record->attestation_id_model; 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> bn_value(BN_new()); if (!bn_value.get()) return KM_ERROR_MEMORY_ALLOCATION_FAILED; if (type == KM_DATE) { if (!BN_set_u64(bn_value.get(), entry.date_time)) { return TranslateLastOpenSslError(); } } else { if (!BN_set_u64(bn_value.get(), entry.long_integer)) { return TranslateLastOpenSslError(); } } UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value( BN_to_ASN1_INTEGER(bn_value.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; } } keymaster_ec_curve_t ec_curve; uint32_t key_size; if (auth_list.Contains(TAG_ALGORITHM, KM_ALGORITHM_EC) && // !auth_list.Contains(TAG_EC_CURVE) && // auth_list.GetTagValue(TAG_KEY_SIZE, &key_size)) { // This must be a keymaster1 key. It's an EC key with no curve. Insert the curve. keymaster_error_t error = EcKeySizeToCurve(key_size, &ec_curve); if (error != KM_ERROR_OK) return error; 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(), ec_curve)) return TranslateLastOpenSslError(); insert_integer(value.release(), &record->ec_curve, nullptr); } 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& attestation_params, AuthorizationSet sw_enforced, AuthorizationSet tee_enforced, const AttestationRecordContext& context, 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_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 = kCurrentKeymasterVersion; } else { keymaster_security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT; switch (context.GetSecurityLevel()) { case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT: { keymaster_version = kCurrentKeymasterVersion; // Root of trust is only available in TEE KM_AUTH_LIST* tee_record = key_desc->tee_enforced; tee_record->root_of_trust = KM_ROOT_OF_TRUST_new(); keymaster_blob_t verified_boot_key; keymaster_verified_boot_t verified_boot_state; bool device_locked; keymaster_error_t error = context.GetVerifiedBootParams( &verified_boot_key, &verified_boot_state, &device_locked); if (error != KM_ERROR_OK) return error; if (verified_boot_key.data_length && !ASN1_OCTET_STRING_set(tee_record->root_of_trust->verified_boot_key, verified_boot_key.data, verified_boot_key.data_length)) return TranslateLastOpenSslError(); tee_record->root_of_trust->device_locked = (int*)device_locked; if (!ASN1_ENUMERATED_set(tee_record->root_of_trust->verified_boot_state, verified_boot_state)) return TranslateLastOpenSslError(); 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->attestation_version, kCurrentAttestationVersion) || !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 = {nullptr, 0}; if (!attestation_params.GetTagValue(TAG_ATTESTATION_CHALLENGE, &attestation_challenge)) return KM_ERROR_ATTESTATION_CHALLENGE_MISSING; if (attestation_challenge.data_length > kMaximumAttestationChallengeLength) return KM_ERROR_INVALID_INPUT_LENGTH; if (!ASN1_OCTET_STRING_set(key_desc->attestation_challenge, attestation_challenge.data, attestation_challenge.data_length)) return TranslateLastOpenSslError(); keymaster_blob_t attestation_app_id; if (!attestation_params.GetTagValue(TAG_ATTESTATION_APPLICATION_ID, &attestation_app_id)) return KM_ERROR_ATTESTATION_APPLICATION_ID_MISSING; sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, attestation_app_id); keymaster_error_t error = context.VerifyAndCopyDeviceIds(attestation_params, keymaster_security_level == KM_SECURITY_LEVEL_SOFTWARE ? &sw_enforced : &tee_enforced); if (error == KM_ERROR_UNIMPLEMENTED) { // The KeymasterContext implementation does not support device ID attestation. Bail out if // device ID attestation is being attempted. for (const auto& tag : kDeviceAttestationTags) { if (attestation_params.find(tag) != -1) { return KM_ERROR_CANNOT_ATTEST_IDS; } } } else if (error != KM_ERROR_OK) { return 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; // Only check tee_enforced for TAG_INCLUDE_UNIQUE_ID. If we don't have hardware we can't // generate unique IDs. if (tee_enforced.GetTagValue(TAG_INCLUDE_UNIQUE_ID)) { uint64_t creation_datetime; // Only check sw_enforced for TAG_CREATION_DATETIME, since it shouldn't be in tee_enforced, // since this implementation has no secure wall clock. if (!sw_enforced.GetTagValue(TAG_CREATION_DATETIME, &creation_datetime)) { LOG_E("Unique ID cannot be created without creation datetime", 0); return KM_ERROR_INVALID_KEY_BLOB; } keymaster_blob_t application_id = {nullptr, 0}; sw_enforced.GetTagValue(TAG_APPLICATION_ID, &application_id); Buffer unique_id; error = context.GenerateUniqueId( creation_datetime, application_id, attestation_params.GetTagValue(TAG_RESET_SINCE_ID_ROTATION), &unique_id); if (error != KM_ERROR_OK) return error; key_desc->unique_id = ASN1_OCTET_STRING_new(); if (!key_desc->unique_id || !ASN1_OCTET_STRING_set(key_desc->unique_id, unique_id.peek_read(), unique_id.available_read())) return TranslateLastOpenSslError(); } 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(std::nothrow) 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 ASN1_INTEGER_SET* 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. 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; // 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 (!get_ulong(record->min_mac_length, TAG_MIN_MAC_LENGTH, auth_list)) 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; // 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; // 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; // 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) return KM_ERROR_INVALID_KEY_BLOB; // 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; // Brand name if (record->attestation_id_brand && !auth_list->push_back(TAG_ATTESTATION_ID_BRAND, record->attestation_id_brand->data, record->attestation_id_brand->length)) return KM_ERROR_MEMORY_ALLOCATION_FAILED; // Device name if (record->attestation_id_device && !auth_list->push_back(TAG_ATTESTATION_ID_DEVICE, record->attestation_id_device->data, record->attestation_id_device->length)) return KM_ERROR_MEMORY_ALLOCATION_FAILED; // Product name if (record->attestation_id_product && !auth_list->push_back(TAG_ATTESTATION_ID_PRODUCT, record->attestation_id_product->data, record->attestation_id_product->length)) return KM_ERROR_MEMORY_ALLOCATION_FAILED; // Serial number if (record->attestation_id_serial && !auth_list->push_back(TAG_ATTESTATION_ID_SERIAL, record->attestation_id_serial->data, record->attestation_id_serial->length)) return KM_ERROR_MEMORY_ALLOCATION_FAILED; // IMEI if (record->attestation_id_imei && !auth_list->push_back(TAG_ATTESTATION_ID_IMEI, record->attestation_id_imei->data, record->attestation_id_imei->length)) return KM_ERROR_MEMORY_ALLOCATION_FAILED; // MEID if (record->attestation_id_meid && !auth_list->push_back(TAG_ATTESTATION_ID_MEID, record->attestation_id_meid->data, record->attestation_id_meid->length)) return KM_ERROR_MEMORY_ALLOCATION_FAILED; // Manufacturer name if (record->attestation_id_manufacturer && !auth_list->push_back(TAG_ATTESTATION_ID_MANUFACTURER, record->attestation_id_manufacturer->data, record->attestation_id_manufacturer->length)) return KM_ERROR_MEMORY_ALLOCATION_FAILED; // Model name if (record->attestation_id_model && !auth_list->push_back(TAG_ATTESTATION_ID_MODEL, record->attestation_id_model->data, record->attestation_id_model->length)) 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, keymaster_blob_t* unique_id) { 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(); *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; 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) return error; return extract_auth_list(record->tee_enforced, tee_enforced); } } // namespace keymaster