diff options
author | Shawn Willden <swillden@google.com> | 2020-12-06 19:20:41 -0700 |
---|---|---|
committer | Shawn Willden <swillden@google.com> | 2020-12-09 16:26:41 -0700 |
commit | f73e952ea46e4ff394efa1c77bab4cfecba301ed (patch) | |
tree | f59f83accc5327ffeb7724d077fa134eb54a6663 /security/keymint/support | |
parent | 8523de7588208ab10c605c7d783885c5b0c56fc7 (diff) |
Move keymint to android.hardware.security.
Test: VtsAidlKeyMintTargetTest
Change-Id: I2498073aa834584229e9a4955a97f279a94d1dd5
Diffstat (limited to 'security/keymint/support')
12 files changed, 2100 insertions, 0 deletions
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp new file mode 100644 index 0000000000..ddac92fc6b --- /dev/null +++ b/security/keymint/support/Android.bp @@ -0,0 +1,39 @@ +// +// Copyright (C) 2020 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. +// + +cc_library { + name: "libkeymint_support", + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], + srcs: [ + "attestation_record.cpp", + "authorization_set.cpp", + "keymint_utils.cpp", + "key_param_output.cpp", + ], + export_include_dirs: [ + "include", + ], + shared_libs: [ + "android.hardware.security.keymint-cpp", + "libbase", + "libcrypto", + "libutils", + ], +} diff --git a/security/keymint/support/OWNERS b/security/keymint/support/OWNERS new file mode 100644 index 0000000000..a93b171b00 --- /dev/null +++ b/security/keymint/support/OWNERS @@ -0,0 +1,4 @@ +jbires@google.com +jdanis@google.com +seleneh@google.com +swillden@google.com diff --git a/security/keymint/support/attestation_record.cpp b/security/keymint/support/attestation_record.cpp new file mode 100644 index 0000000000..afdb208221 --- /dev/null +++ b/security/keymint/support/attestation_record.cpp @@ -0,0 +1,384 @@ +/* + * Copyright 2020 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 <keymint_support/attestation_record.h> + +#include <assert.h> + +#include <android-base/logging.h> + +#include <openssl/asn1t.h> +#include <openssl/bn.h> +#include <openssl/evp.h> +#include <openssl/x509.h> + +#include <android/hardware/security/keymint/Tag.h> +#include <android/hardware/security/keymint/TagType.h> + +#include <keymint_support/authorization_set.h> +#include <keymint_support/openssl_utils.h> + +#define AT __FILE__ ":" << __LINE__ + +namespace android::hardware::security::keymint { + +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_BOOLEAN device_locked; + ASN1_ENUMERATED* verified_boot_state; + ASN1_OCTET_STRING* verified_boot_hash; +} 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, device_locked, ASN1_BOOLEAN), + ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED), + ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_hash, ASN1_OCTET_STRING), +} 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* digest; + ASN1_INTEGER_SET* padding; + ASN1_INTEGER* ec_curve; + ASN1_INTEGER* rsa_public_exponent; + ASN1_INTEGER* active_date_time; + ASN1_INTEGER* origination_expire_date_time; + ASN1_INTEGER* usage_expire_date_time; + 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_INTEGER* creation_date_time; + ASN1_INTEGER* origin; + ASN1_NULL* rollback_resistance; + KM_ROOT_OF_TRUST* root_of_trust; + ASN1_INTEGER* os_version; + ASN1_INTEGER* os_patchlevel; + ASN1_OCTET_STRING* attestation_application_id; + ASN1_NULL* trusted_user_presence_required; + ASN1_NULL* trusted_confirmation_required; + ASN1_NULL* unlocked_device_required; + ASN1_INTEGER* vendor_patchlevel; + ASN1_INTEGER* boot_patchlevel; + ASN1_NULL* early_boot_only; + ASN1_NULL* device_unique_attestation; + ASN1_NULL* storage_key; + ASN1_NULL* identity_credential; +} KM_AUTH_LIST; + +ASN1_SEQUENCE(KM_AUTH_LIST) = { + ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.maskedTag()), + ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.maskedTag()), + ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER, + TAG_RSA_PUBLIC_EXPONENT.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL, + TAG_ROLLBACK_RESISTANCE.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER, + TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER, + TAG_USAGE_EXPIRE_DATETIME.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL, + TAG_ALLOW_WHILE_ON_BODY.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, trusted_user_presence_required, ASN1_NULL, + TAG_TRUSTED_USER_PRESENCE_REQUIRED.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, trusted_confirmation_required, ASN1_NULL, + TAG_TRUSTED_CONFIRMATION_REQUIRED.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, unlocked_device_required, ASN1_NULL, + TAG_UNLOCKED_DEVICE_REQUIRED.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER, + TAG_CREATION_DATETIME.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, vendor_patchlevel, ASN1_INTEGER, + TAG_VENDOR_PATCHLEVEL.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, boot_patchlevel, ASN1_INTEGER, TAG_BOOT_PATCHLEVEL.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING, + TAG_ATTESTATION_APPLICATION_ID.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, device_unique_attestation, ASN1_NULL, + TAG_DEVICE_UNIQUE_ATTESTATION.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, storage_key, ASN1_NULL, TAG_STORAGE_KEY.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, identity_credential, ASN1_NULL, + TAG_IDENTITY_CREDENTIAL_KEY.maskedTag()), + +} 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* keymint_version; + ASN1_ENUMERATED* keymint_security_level; + ASN1_OCTET_STRING* attestation_challenge; + KM_AUTH_LIST* software_enforced; + KM_AUTH_LIST* tee_enforced; + ASN1_INTEGER* unique_id; +} 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, keymint_version, ASN1_INTEGER), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymint_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_SEQUENCE_END(KM_KEY_DESCRIPTION); +IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION); + +template <Tag tag> +void copyAuthTag(const stack_st_ASN1_INTEGER* stack, TypedTag<TagType::ENUM_REP, tag> ttag, + AuthorizationSet* auth_list) { + typedef typename TypedTag2ValueType<decltype(ttag)>::type ValueT; + for (size_t i = 0; i < sk_ASN1_INTEGER_num(stack); ++i) { + auth_list->push_back( + ttag, static_cast<ValueT>(ASN1_INTEGER_get(sk_ASN1_INTEGER_value(stack, i)))); + } +} + +template <Tag tag> +void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ENUM, tag> ttag, + AuthorizationSet* auth_list) { + typedef typename TypedTag2ValueType<decltype(ttag)>::type ValueT; + if (!asn1_int) return; + auth_list->push_back(ttag, static_cast<ValueT>(ASN1_INTEGER_get(asn1_int))); +} + +template <Tag tag> +void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::UINT, tag> ttag, + AuthorizationSet* auth_list) { + if (!asn1_int) return; + auth_list->push_back(ttag, ASN1_INTEGER_get(asn1_int)); +} + +BIGNUM* construct_uint_max() { + BIGNUM* value = BN_new(); + BIGNUM_Ptr one(BN_new()); + BN_one(one.get()); + BN_lshift(value, one.get(), 32); + return value; +} + +uint64_t BignumToUint64(BIGNUM* num) { + static_assert((sizeof(BN_ULONG) == sizeof(uint32_t)) || (sizeof(BN_ULONG) == sizeof(uint64_t)), + "This implementation only supports 32 and 64-bit BN_ULONG"); + if (sizeof(BN_ULONG) == sizeof(uint32_t)) { + BIGNUM_Ptr uint_max(construct_uint_max()); + BIGNUM_Ptr hi(BN_new()), lo(BN_new()); + BN_CTX_Ptr ctx(BN_CTX_new()); + BN_div(hi.get(), lo.get(), num, uint_max.get(), ctx.get()); + return static_cast<uint64_t>(BN_get_word(hi.get())) << 32 | BN_get_word(lo.get()); + } else if (sizeof(BN_ULONG) == sizeof(uint64_t)) { + return BN_get_word(num); + } else { + return 0; + } +} + +template <Tag tag> +void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ULONG, tag> ttag, + AuthorizationSet* auth_list) { + if (!asn1_int) return; + BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr)); + auth_list->push_back(ttag, BignumToUint64(num.get())); +} + +template <Tag tag> +void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::DATE, tag> ttag, + AuthorizationSet* auth_list) { + if (!asn1_int) return; + BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr)); + auth_list->push_back(ttag, BignumToUint64(num.get())); +} + +template <Tag tag> +void copyAuthTag(const ASN1_NULL* asn1_null, TypedTag<TagType::BOOL, tag> ttag, + AuthorizationSet* auth_list) { + if (!asn1_null) return; + auth_list->push_back(ttag); +} + +template <Tag tag> +void copyAuthTag(const ASN1_OCTET_STRING* asn1_string, TypedTag<TagType::BYTES, tag> ttag, + AuthorizationSet* auth_list) { + if (!asn1_string) return; + vector<uint8_t> buf(asn1_string->data, asn1_string->data + asn1_string->length); + auth_list->push_back(ttag, buf); +} + +// Extract the values from the specified ASN.1 record and place them in auth_list. +static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* auth_list) { + if (!record) return ErrorCode::OK; + + copyAuthTag(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list); + copyAuthTag(record->algorithm, TAG_ALGORITHM, auth_list); + copyAuthTag(record->application_id, TAG_APPLICATION_ID, auth_list); + copyAuthTag(record->auth_timeout, TAG_AUTH_TIMEOUT, auth_list); + copyAuthTag(record->creation_date_time, TAG_CREATION_DATETIME, auth_list); + copyAuthTag(record->digest, TAG_DIGEST, auth_list); + copyAuthTag(record->ec_curve, TAG_EC_CURVE, auth_list); + copyAuthTag(record->key_size, TAG_KEY_SIZE, auth_list); + copyAuthTag(record->no_auth_required, TAG_NO_AUTH_REQUIRED, auth_list); + copyAuthTag(record->origin, TAG_ORIGIN, auth_list); + copyAuthTag(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME, auth_list); + copyAuthTag(record->os_patchlevel, TAG_OS_PATCHLEVEL, auth_list); + copyAuthTag(record->os_version, TAG_OS_VERSION, auth_list); + copyAuthTag(record->padding, TAG_PADDING, auth_list); + copyAuthTag(record->purpose, TAG_PURPOSE, auth_list); + copyAuthTag(record->rollback_resistance, TAG_ROLLBACK_RESISTANCE, auth_list); + copyAuthTag(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list); + copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list); + copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list); + copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list); + copyAuthTag(record->vendor_patchlevel, TAG_VENDOR_PATCHLEVEL, auth_list); + copyAuthTag(record->boot_patchlevel, TAG_BOOT_PATCHLEVEL, auth_list); + copyAuthTag(record->trusted_user_presence_required, TAG_TRUSTED_USER_PRESENCE_REQUIRED, + auth_list); + copyAuthTag(record->trusted_confirmation_required, TAG_TRUSTED_CONFIRMATION_REQUIRED, + auth_list); + copyAuthTag(record->unlocked_device_required, TAG_UNLOCKED_DEVICE_REQUIRED, auth_list); + copyAuthTag(record->early_boot_only, TAG_EARLY_BOOT_ONLY, auth_list); + copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list); + copyAuthTag(record->storage_key, TAG_STORAGE_KEY, auth_list); + copyAuthTag(record->identity_credential, TAG_IDENTITY_CREDENTIAL_KEY, auth_list); + + return ErrorCode::OK; +} + +MAKE_OPENSSL_PTR_TYPE(KM_KEY_DESCRIPTION) + +// Parse the DER-encoded attestation record, placing the results in keymint_version, +// attestation_challenge, software_enforced, tee_enforced and unique_id. +ErrorCode parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len, + uint32_t* attestation_version, // + SecurityLevel* attestation_security_level, + uint32_t* keymint_version, SecurityLevel* keymint_security_level, + vector<uint8_t>* attestation_challenge, + AuthorizationSet* software_enforced, + AuthorizationSet* tee_enforced, // + vector<uint8_t>* unique_id) { + const uint8_t* p = asn1_key_desc; + KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, asn1_key_desc_len)); + if (!record.get()) return ErrorCode::UNKNOWN_ERROR; + + *attestation_version = ASN1_INTEGER_get(record->attestation_version); + *attestation_security_level = + static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->attestation_security_level)); + *keymint_version = ASN1_INTEGER_get(record->keymint_version); + *keymint_security_level = + static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->keymint_security_level)); + + auto& chall = record->attestation_challenge; + attestation_challenge->resize(chall->length); + memcpy(attestation_challenge->data(), chall->data, chall->length); + auto& uid = record->unique_id; + unique_id->resize(uid->length); + memcpy(unique_id->data(), uid->data, uid->length); + + ErrorCode error = extract_auth_list(record->software_enforced, software_enforced); + if (error != ErrorCode::OK) return error; + + return extract_auth_list(record->tee_enforced, tee_enforced); +} + +ErrorCode parse_root_of_trust(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len, + vector<uint8_t>* verified_boot_key, + keymint_verified_boot_t* verified_boot_state, bool* device_locked, + vector<uint8_t>* verified_boot_hash) { + if (!verified_boot_key || !verified_boot_state || !device_locked || !verified_boot_hash) { + LOG(ERROR) << AT << "null pointer input(s)"; + return ErrorCode::INVALID_ARGUMENT; + } + const uint8_t* p = asn1_key_desc; + KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, asn1_key_desc_len)); + if (!record.get()) { + LOG(ERROR) << AT << "Failed record parsing"; + return ErrorCode::UNKNOWN_ERROR; + } + + KM_ROOT_OF_TRUST* root_of_trust = nullptr; + if (record->tee_enforced && record->tee_enforced->root_of_trust) { + root_of_trust = record->tee_enforced->root_of_trust; + } else if (record->software_enforced && record->software_enforced->root_of_trust) { + root_of_trust = record->software_enforced->root_of_trust; + } else { + LOG(ERROR) << AT << " Failed root of trust parsing"; + return ErrorCode::INVALID_ARGUMENT; + } + if (!root_of_trust->verified_boot_key) { + LOG(ERROR) << AT << " Failed verified boot key parsing"; + return ErrorCode::INVALID_ARGUMENT; + } + + auto& vb_key = root_of_trust->verified_boot_key; + verified_boot_key->resize(vb_key->length); + memcpy(verified_boot_key->data(), vb_key->data, vb_key->length); + + *verified_boot_state = static_cast<keymint_verified_boot_t>( + ASN1_ENUMERATED_get(root_of_trust->verified_boot_state)); + if (!verified_boot_state) { + LOG(ERROR) << AT << " Failed verified boot state parsing"; + return ErrorCode::INVALID_ARGUMENT; + } + + *device_locked = root_of_trust->device_locked; + if (!device_locked) { + LOG(ERROR) << AT << " Failed device locked parsing"; + return ErrorCode::INVALID_ARGUMENT; + } + + auto& vb_hash = root_of_trust->verified_boot_hash; + if (!vb_hash) { + LOG(ERROR) << AT << " Failed verified boot hash parsing"; + return ErrorCode::INVALID_ARGUMENT; + } + verified_boot_hash->resize(vb_hash->length); + memcpy(verified_boot_hash->data(), vb_hash->data, vb_hash->length); + return ErrorCode::OK; // KM_ERROR_OK; +} + +} // namespace android::hardware::security::keymint diff --git a/security/keymint/support/authorization_set.cpp b/security/keymint/support/authorization_set.cpp new file mode 100644 index 0000000000..aa9638f256 --- /dev/null +++ b/security/keymint/support/authorization_set.cpp @@ -0,0 +1,526 @@ +/* + * Copyright 2020 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 <keymint_support/authorization_set.h> + +#include <assert.h> +#include <sstream> + +#include <android-base/logging.h> + +#include <android/hardware/security/keymint/Algorithm.h> +#include <android/hardware/security/keymint/BlockMode.h> +#include <android/hardware/security/keymint/Digest.h> +#include <android/hardware/security/keymint/KeyParameter.h> +#include <android/hardware/security/keymint/KeyPurpose.h> +#include <android/hardware/security/keymint/TagType.h> + +namespace android::hardware::security::keymint { + +void AuthorizationSet::Sort() { + std::sort(data_.begin(), data_.end()); +} + +void AuthorizationSet::Deduplicate() { + if (data_.empty()) return; + + Sort(); + std::vector<KeyParameter> result; + + auto curr = data_.begin(); + auto prev = curr++; + for (; curr != data_.end(); ++prev, ++curr) { + if (prev->tag == Tag::INVALID) continue; + + if (*prev != *curr) { + result.push_back(std::move(*prev)); + } + } + result.push_back(std::move(*prev)); + + std::swap(data_, result); +} + +void AuthorizationSet::Union(const AuthorizationSet& other) { + data_.insert(data_.end(), other.data_.begin(), other.data_.end()); + Deduplicate(); +} + +void AuthorizationSet::Subtract(const AuthorizationSet& other) { + Deduplicate(); + + auto i = other.begin(); + while (i != other.end()) { + int pos = -1; + do { + pos = find(i->tag, pos); + if (pos != -1 && (*i == data_[pos])) { + data_.erase(data_.begin() + pos); + break; + } + } while (pos != -1); + ++i; + } +} + +void AuthorizationSet::Filter(std::function<bool(const KeyParameter&)> doKeep) { + std::vector<KeyParameter> result; + for (auto& param : data_) { + if (doKeep(param)) { + result.push_back(std::move(param)); + } + } + std::swap(data_, result); +} + +KeyParameter& AuthorizationSet::operator[](int at) { + return data_[at]; +} + +const KeyParameter& AuthorizationSet::operator[](int at) const { + return data_[at]; +} + +void AuthorizationSet::Clear() { + data_.clear(); +} + +size_t AuthorizationSet::GetTagCount(Tag tag) const { + size_t count = 0; + for (int pos = -1; (pos = find(tag, pos)) != -1;) ++count; + return count; +} + +int AuthorizationSet::find(Tag tag, int begin) const { + auto iter = data_.begin() + (1 + begin); + + while (iter != data_.end() && iter->tag != tag) ++iter; + + if (iter != data_.end()) return iter - data_.begin(); + return -1; +} + +bool AuthorizationSet::erase(int index) { + auto pos = data_.begin() + index; + if (pos != data_.end()) { + data_.erase(pos); + return true; + } + return false; +} + +NullOr<const KeyParameter&> AuthorizationSet::GetEntry(Tag tag) const { + int pos = find(tag); + if (pos == -1) return {}; + return data_[pos]; +} + +/** + * Persistent format is: + * | 32 bit indirect_size | + * -------------------------------- + * | indirect_size bytes of data | this is where the blob data is stored + * -------------------------------- + * | 32 bit element_count | number of entries + * | 32 bit elements_size | total bytes used by entries (entries have variable length) + * -------------------------------- + * | elementes_size bytes of data | where the elements are stored + */ + +/** + * Persistent format of blobs and bignums: + * | 32 bit tag | + * | 32 bit blob_length | + * | 32 bit indirect_offset | + */ + +struct OutStreams { + std::ostream& indirect; + std::ostream& elements; + size_t skipped; +}; + +OutStreams& serializeParamValue(OutStreams& out, const vector<uint8_t>& blob) { + uint32_t buffer; + + // write blob_length + auto blob_length = blob.size(); + if (blob_length > std::numeric_limits<uint32_t>::max()) { + out.elements.setstate(std::ios_base::badbit); + return out; + } + buffer = blob_length; + out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t)); + + // write indirect_offset + auto offset = out.indirect.tellp(); + if (offset < 0 || offset > std::numeric_limits<uint32_t>::max() || + uint32_t(offset) + uint32_t(blob_length) < uint32_t(offset)) { // overflow check + out.elements.setstate(std::ios_base::badbit); + return out; + } + buffer = offset; + out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t)); + + // write blob to indirect stream + if (blob_length) out.indirect.write(reinterpret_cast<const char*>(&blob[0]), blob_length); + + return out; +} + +template <typename T> +OutStreams& serializeParamValue(OutStreams& out, const T& value) { + out.elements.write(reinterpret_cast<const char*>(&value), sizeof(T)); + return out; +} + +OutStreams& serialize(TAG_INVALID_t&&, OutStreams& out, const KeyParameter&) { + // skip invalid entries. + ++out.skipped; + return out; +} +template <typename T> +OutStreams& serialize(T ttag, OutStreams& out, const KeyParameter& param) { + out.elements.write(reinterpret_cast<const char*>(¶m.tag), sizeof(int32_t)); + return serializeParamValue(out, accessTagValue(ttag, param)); +} + +template <typename... T> +struct choose_serializer; +template <typename... Tags> +struct choose_serializer<MetaList<Tags...>> { + static OutStreams& serialize(OutStreams& out, const KeyParameter& param) { + return choose_serializer<Tags...>::serialize(out, param); + } +}; + +template <> +struct choose_serializer<> { + static OutStreams& serialize(OutStreams& out, const KeyParameter& param) { + LOG(WARNING) << "Trying to serialize unknown tag " << unsigned(param.tag) + << ". Did you forget to add it to all_tags_t?"; + ++out.skipped; + return out; + } +}; + +template <TagType tag_type, Tag tag, typename... Tail> +struct choose_serializer<android::hardware::security::keymint::TypedTag<tag_type, tag>, Tail...> { + static OutStreams& serialize(OutStreams& out, const KeyParameter& param) { + if (param.tag == tag) { + return android::hardware::security::keymint::serialize(TypedTag<tag_type, tag>(), out, + param); + } else { + return choose_serializer<Tail...>::serialize(out, param); + } + } +}; + +OutStreams& serialize(OutStreams& out, const KeyParameter& param) { + return choose_serializer<all_tags_t>::serialize(out, param); +} + +std::ostream& serialize(std::ostream& out, const std::vector<KeyParameter>& params) { + std::stringstream indirect; + std::stringstream elements; + OutStreams streams = {indirect, elements, 0}; + for (const auto& param : params) { + serialize(streams, param); + } + if (indirect.bad() || elements.bad()) { + out.setstate(std::ios_base::badbit); + return out; + } + auto pos = indirect.tellp(); + if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) { + out.setstate(std::ios_base::badbit); + return out; + } + uint32_t indirect_size = pos; + pos = elements.tellp(); + if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) { + out.setstate(std::ios_base::badbit); + return out; + } + uint32_t elements_size = pos; + uint32_t element_count = params.size() - streams.skipped; + + out.write(reinterpret_cast<const char*>(&indirect_size), sizeof(uint32_t)); + + pos = out.tellp(); + if (indirect_size) out << indirect.rdbuf(); + assert(out.tellp() - pos == indirect_size); + + out.write(reinterpret_cast<const char*>(&element_count), sizeof(uint32_t)); + out.write(reinterpret_cast<const char*>(&elements_size), sizeof(uint32_t)); + + pos = out.tellp(); + if (elements_size) out << elements.rdbuf(); + assert(out.tellp() - pos == elements_size); + + return out; +} + +struct InStreams { + std::istream& indirect; + std::istream& elements; + size_t invalids; +}; + +InStreams& deserializeParamValue(InStreams& in, vector<uint8_t>* blob) { + uint32_t blob_length = 0; + uint32_t offset = 0; + in.elements.read(reinterpret_cast<char*>(&blob_length), sizeof(uint32_t)); + blob->resize(blob_length); + in.elements.read(reinterpret_cast<char*>(&offset), sizeof(uint32_t)); + in.indirect.seekg(offset); + in.indirect.read(reinterpret_cast<char*>(&(*blob)[0]), blob->size()); + return in; +} + +template <typename T> +InStreams& deserializeParamValue(InStreams& in, T* value) { + in.elements.read(reinterpret_cast<char*>(value), sizeof(T)); + return in; +} + +InStreams& deserialize(TAG_INVALID_t&&, InStreams& in, KeyParameter*) { + // there should be no invalid KeyParameters but if handle them as zero sized. + ++in.invalids; + return in; +} + +template <typename T> +InStreams& deserialize(T&& ttag, InStreams& in, KeyParameter* param) { + return deserializeParamValue(in, &accessTagValue(ttag, *param)); +} + +template <typename... T> +struct choose_deserializer; +template <typename... Tags> +struct choose_deserializer<MetaList<Tags...>> { + static InStreams& deserialize(InStreams& in, KeyParameter* param) { + return choose_deserializer<Tags...>::deserialize(in, param); + } +}; +template <> +struct choose_deserializer<> { + static InStreams& deserialize(InStreams& in, KeyParameter*) { + // encountered an unknown tag -> fail parsing + in.elements.setstate(std::ios_base::badbit); + return in; + } +}; +template <TagType tag_type, Tag tag, typename... Tail> +struct choose_deserializer<TypedTag<tag_type, tag>, Tail...> { + static InStreams& deserialize(InStreams& in, KeyParameter* param) { + if (param->tag == tag) { + return android::hardware::security::keymint::deserialize(TypedTag<tag_type, tag>(), in, + param); + } else { + return choose_deserializer<Tail...>::deserialize(in, param); + } + } +}; + +InStreams& deserialize(InStreams& in, KeyParameter* param) { + in.elements.read(reinterpret_cast<char*>(¶m->tag), sizeof(Tag)); + return choose_deserializer<all_tags_t>::deserialize(in, param); +} + +std::istream& deserialize(std::istream& in, std::vector<KeyParameter>* params) { + uint32_t indirect_size = 0; + in.read(reinterpret_cast<char*>(&indirect_size), sizeof(uint32_t)); + std::string indirect_buffer(indirect_size, '\0'); + if (indirect_buffer.size() != indirect_size) { + in.setstate(std::ios_base::badbit); + return in; + } + in.read(&indirect_buffer[0], indirect_buffer.size()); + + uint32_t element_count = 0; + in.read(reinterpret_cast<char*>(&element_count), sizeof(uint32_t)); + uint32_t elements_size = 0; + in.read(reinterpret_cast<char*>(&elements_size), sizeof(uint32_t)); + + std::string elements_buffer(elements_size, '\0'); + if (elements_buffer.size() != elements_size) { + in.setstate(std::ios_base::badbit); + return in; + } + in.read(&elements_buffer[0], elements_buffer.size()); + + if (in.bad()) return in; + + // TODO write one-shot stream buffer to avoid copying here + std::stringstream indirect(indirect_buffer); + std::stringstream elements(elements_buffer); + InStreams streams = {indirect, elements, 0}; + + params->resize(element_count); + + for (uint32_t i = 0; i < element_count; ++i) { + deserialize(streams, &(*params)[i]); + } + + /* + * There are legacy blobs which have invalid tags in them due to a bug during serialization. + * This makes sure that invalid tags are filtered from the result before it is returned. + */ + if (streams.invalids > 0) { + std::vector<KeyParameter> filtered(element_count - streams.invalids); + auto ifiltered = filtered.begin(); + for (auto& p : *params) { + if (p.tag != Tag::INVALID) { + *ifiltered++ = std::move(p); + } + } + *params = std::move(filtered); + } + return in; +} + +void AuthorizationSet::Serialize(std::ostream* out) const { + serialize(*out, data_); +} + +void AuthorizationSet::Deserialize(std::istream* in) { + deserialize(*in, &data_); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size, + uint64_t public_exponent) { + Authorization(TAG_ALGORITHM, Algorithm::RSA); + Authorization(TAG_KEY_SIZE, key_size); + Authorization(TAG_RSA_PUBLIC_EXPONENT, public_exponent); + return *this; +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(uint32_t key_size) { + Authorization(TAG_ALGORITHM, Algorithm::EC); + Authorization(TAG_KEY_SIZE, key_size); + return *this; +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(EcCurve curve) { + Authorization(TAG_ALGORITHM, Algorithm::EC); + Authorization(TAG_EC_CURVE, curve); + return *this; +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::AesKey(uint32_t key_size) { + Authorization(TAG_ALGORITHM, Algorithm::AES); + return Authorization(TAG_KEY_SIZE, key_size); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::TripleDesKey(uint32_t key_size) { + Authorization(TAG_ALGORITHM, Algorithm::TRIPLE_DES); + return Authorization(TAG_KEY_SIZE, key_size); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) { + Authorization(TAG_ALGORITHM, Algorithm::HMAC); + Authorization(TAG_KEY_SIZE, key_size); + return SigningKey(); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::RsaSigningKey(uint32_t key_size, + uint64_t public_exponent) { + RsaKey(key_size, public_exponent); + return SigningKey(); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::RsaEncryptionKey(uint32_t key_size, + uint64_t public_exponent) { + RsaKey(key_size, public_exponent); + return EncryptionKey(); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(uint32_t key_size) { + EcdsaKey(key_size); + return SigningKey(); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(EcCurve curve) { + EcdsaKey(curve); + return SigningKey(); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::AesEncryptionKey(uint32_t key_size) { + AesKey(key_size); + return EncryptionKey(); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::TripleDesEncryptionKey(uint32_t key_size) { + TripleDesKey(key_size); + return EncryptionKey(); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() { + Authorization(TAG_PURPOSE, KeyPurpose::SIGN); + return Authorization(TAG_PURPOSE, KeyPurpose::VERIFY); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::EncryptionKey() { + Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT); + return Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() { + Authorization(TAG_DIGEST, Digest::NONE); + return Authorization(TAG_PADDING, PaddingMode::NONE); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::EcbMode() { + return Authorization(TAG_BLOCK_MODE, BlockMode::ECB); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::GcmModeMinMacLen(uint32_t minMacLength) { + return BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MIN_MAC_LENGTH, minMacLength); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::GcmModeMacLen(uint32_t macLength) { + return BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAC_LENGTH, macLength); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::BlockMode( + std::initializer_list<android::hardware::security::keymint::BlockMode> blockModes) { + for (auto mode : blockModes) { + push_back(TAG_BLOCK_MODE, mode); + } + return *this; +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::Digest(std::vector<keymint::Digest> digests) { + for (auto digest : digests) { + push_back(TAG_DIGEST, digest); + } + return *this; +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::Padding( + std::initializer_list<PaddingMode> paddingModes) { + for (auto paddingMode : paddingModes) { + push_back(TAG_PADDING, paddingMode); + } + return *this; +} + +} // namespace android::hardware::security::keymint diff --git a/security/keymint/support/include/keymint_support/attestation_record.h b/security/keymint/support/include/keymint_support/attestation_record.h new file mode 100644 index 0000000000..d71624c978 --- /dev/null +++ b/security/keymint/support/include/keymint_support/attestation_record.h @@ -0,0 +1,87 @@ +/* + * Copyright 2020 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. + */ + +#pragma once + +#include <android/hardware/security/keymint/ErrorCode.h> +#include <android/hardware/security/keymint/IKeyMintDevice.h> + +#include <keymint_support/attestation_record.h> +#include <keymint_support/authorization_set.h> +#include <keymint_support/openssl_utils.h> + +namespace android::hardware::security::keymint { + +class AuthorizationSet; + +/** + * The OID for Android attestation records. For the curious, it breaks down as follows: + * + * 1 = ISO + * 3 = org + * 6 = DoD (Huh? OIDs are weird.) + * 1 = IANA + * 4 = Private + * 1 = Enterprises + * 11129 = Google + * 2 = Google security + * 1 = certificate extension + * 17 = Android attestation extension. + */ +static const char kAttestionRecordOid[] = "1.3.6.1.4.1.11129.2.1.17"; + +enum keymint_verified_boot_t { + KM_VERIFIED_BOOT_VERIFIED = 0, + KM_VERIFIED_BOOT_SELF_SIGNED = 1, + KM_VERIFIED_BOOT_UNVERIFIED = 2, + KM_VERIFIED_BOOT_FAILED = 3, +}; + +struct RootOfTrust { + SecurityLevel security_level; + vector<uint8_t> verified_boot_key; + vector<uint8_t> verified_boot_hash; + keymint_verified_boot_t verified_boot_state; + bool device_locked; +}; + +struct AttestationRecord { + RootOfTrust root_of_trust; + uint32_t attestation_version; + SecurityLevel attestation_security_level; + uint32_t keymint_version; + SecurityLevel keymint_security_level; + std::vector<uint8_t> attestation_challenge; + AuthorizationSet software_enforced; + AuthorizationSet hardware_enforced; + std::vector<uint8_t> unique_id; +}; + +ErrorCode parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len, + uint32_t* attestation_version, // + SecurityLevel* attestation_security_level, + uint32_t* keymint_version, SecurityLevel* keymint_security_level, + std::vector<uint8_t>* attestation_challenge, + AuthorizationSet* software_enforced, + AuthorizationSet* tee_enforced, // + std::vector<uint8_t>* unique_id); + +ErrorCode parse_root_of_trust(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len, + std::vector<uint8_t>* verified_boot_key, + keymint_verified_boot_t* verified_boot_state, bool* device_locked, + std::vector<uint8_t>* verified_boot_hash); + +} // namespace android::hardware::security::keymint diff --git a/security/keymint/support/include/keymint_support/authorization_set.h b/security/keymint/support/include/keymint_support/authorization_set.h new file mode 100644 index 0000000000..97e10224d3 --- /dev/null +++ b/security/keymint/support/include/keymint_support/authorization_set.h @@ -0,0 +1,320 @@ +/* + * Copyright 2020 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. + */ + +#ifndef SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_ +#define SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_ + +#include <vector> + +#include <android/hardware/security/keymint/BlockMode.h> +#include <android/hardware/security/keymint/Digest.h> +#include <android/hardware/security/keymint/EcCurve.h> +#include <android/hardware/security/keymint/PaddingMode.h> + +#include <keymint_support/keymint_tags.h> + +namespace android::hardware::security::keymint { + +using std::vector; + +class AuthorizationSetBuilder; + +/** + * An ordered collection of KeyParameters. It provides memory ownership and some convenient + * functionality for sorting, deduplicating, joining, and subtracting sets of KeyParameters. + * For serialization, wrap the backing store of this structure in a vector<KeyParameter>. + */ +class AuthorizationSet { + public: + typedef KeyParameter value_type; + + /** + * Construct an empty, dynamically-allocated, growable AuthorizationSet. + */ + AuthorizationSet(){}; + + // Copy constructor. + AuthorizationSet(const AuthorizationSet& other) : data_(other.data_) {} + + // Move constructor. + AuthorizationSet(AuthorizationSet&& other) noexcept : data_(std::move(other.data_)) {} + + // Constructor from vector<KeyParameter> + AuthorizationSet(const vector<KeyParameter>& other) { *this = other; } + + // Copy assignment. + AuthorizationSet& operator=(const AuthorizationSet& other) { + data_ = other.data_; + return *this; + } + + // Move assignment. + AuthorizationSet& operator=(AuthorizationSet&& other) noexcept { + data_ = std::move(other.data_); + return *this; + } + + AuthorizationSet& operator=(const vector<KeyParameter>& other) { + if (other.size() > 0) { + data_.resize(other.size()); + for (size_t i = 0; i < data_.size(); ++i) { + /* This makes a deep copy even of embedded blobs. + * See assignment operator/copy constructor of vector.*/ + data_[i] = other[i]; + } + } + return *this; + } + + /** + * Clear existing authorization set data + */ + void Clear(); + + ~AuthorizationSet() = default; + + /** + * Returns the size of the set. + */ + size_t size() const { return data_.size(); } + + /** + * Returns true if the set is empty. + */ + bool empty() const { return size() == 0; } + + /** + * Returns the data in the set, directly. Be careful with this. + */ + const KeyParameter* data() const { return data_.data(); } + + /** + * Sorts the set + */ + void Sort(); + + /** + * Sorts the set and removes duplicates (inadvertently duplicating tags is easy to do with the + * AuthorizationSetBuilder). + */ + void Deduplicate(); + + /** + * Adds all elements from \p set that are not already present in this AuthorizationSet. As a + * side-effect, if \p set is not null this AuthorizationSet will end up sorted. + */ + void Union(const AuthorizationSet& set); + + /** + * Removes all elements in \p set from this AuthorizationSet. + */ + void Subtract(const AuthorizationSet& set); + + /** + * Returns the offset of the next entry that matches \p tag, starting from the element after \p + * begin. If not found, returns -1. + */ + int find(Tag tag, int begin = -1) const; + + /** + * Removes the entry at the specified index. Returns true if successful, false if the index was + * out of bounds. + */ + bool erase(int index); + + /** + * Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration + */ + std::vector<KeyParameter>::const_iterator begin() const { return data_.begin(); } + + /** + * Returns iterator (pointer) one past end of elems array, to enable STL-style iteration + */ + std::vector<KeyParameter>::const_iterator end() const { return data_.end(); } + + /** + * Modifies this Authorization set such that it only keeps the entries for which doKeep + * returns true. + */ + void Filter(std::function<bool(const KeyParameter&)> doKeep); + /** + * Returns the nth element of the set. + * Like for std::vector::operator[] there is no range check performed. Use of out of range + * indices is undefined. + */ + KeyParameter& operator[](int n); + + /** + * Returns the nth element of the set. + * Like for std::vector::operator[] there is no range check performed. Use of out of range + * indices is undefined. + */ + const KeyParameter& operator[](int n) const; + + /** + * Returns true if the set contains at least one instance of \p tag + */ + bool Contains(Tag tag) const { return find(tag) != -1; } + + template <TagType tag_type, Tag tag, typename ValueT> + bool Contains(TypedTag<tag_type, tag> ttag, const ValueT& value) const { + for (const auto& param : data_) { + auto entry = authorizationValue(ttag, param); + if (entry.isOk() && static_cast<ValueT>(entry.value()) == value) return true; + } + return false; + } + /** + * Returns the number of \p tag entries. + */ + size_t GetTagCount(Tag tag) const; + + template <typename T> + inline NullOr<const typename TypedTag2ValueType<T>::type&> GetTagValue(T tag) const { + auto entry = GetEntry(tag); + if (entry.isOk()) return authorizationValue(tag, entry.value()); + return {}; + } + + void push_back(const KeyParameter& param) { data_.push_back(param); } + void push_back(KeyParameter&& param) { data_.push_back(std::move(param)); } + void push_back(const AuthorizationSet& set) { + for (auto& entry : set) { + push_back(entry); + } + } + void push_back(AuthorizationSet&& set) { + std::move(set.begin(), set.end(), std::back_inserter(*this)); + } + + /** + * Append the tag and enumerated value to the set. + * "val" may be exactly one parameter unless a boolean parameter is added. + * In this case "val" is omitted. This condition is checked at compile time by Authorization() + */ + template <typename TypedTagT, typename... Value> + void push_back(TypedTagT tag, Value&&... val) { + push_back(Authorization(tag, std::forward<Value>(val)...)); + } + + template <typename Iterator> + void append(Iterator begin, Iterator end) { + while (begin != end) { + push_back(*begin); + ++begin; + } + } + + vector<KeyParameter> vector_data() const { + vector<KeyParameter> result(begin(), end()); + return result; + } + + void Serialize(std::ostream* out) const; + void Deserialize(std::istream* in); + + private: + NullOr<const KeyParameter&> GetEntry(Tag tag) const; + + std::vector<KeyParameter> data_; +}; + +class AuthorizationSetBuilder : public AuthorizationSet { + public: + template <typename TagType, typename... ValueType> + AuthorizationSetBuilder& Authorization(TagType ttag, ValueType&&... value) { + push_back(ttag, std::forward<ValueType>(value)...); + return *this; + } + + template <Tag tag> + AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const uint8_t* data, + size_t data_length) { + vector<uint8_t> new_blob(data, data + data_length); + push_back(ttag, new_blob); + return *this; + } + + template <Tag tag> + AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const char* data, + size_t data_length) { + return Authorization(ttag, reinterpret_cast<const uint8_t*>(data), data_length); + } + + template <Tag tag> + AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, char* data, + size_t data_length) { + return Authorization(ttag, reinterpret_cast<const uint8_t*>(data), data_length); + } + + template <Tag tag, size_t size> + AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, + const char (&data)[size]) { + return Authorization(ttag, reinterpret_cast<const uint8_t*>(&data[0]), + size - 1); // drop the terminating '\0' + } + + AuthorizationSetBuilder& Authorizations(const AuthorizationSet& set) { + for (const auto& entry : set) { + push_back(entry); + } + return *this; + } + + AuthorizationSetBuilder& RsaKey(uint32_t key_size, uint64_t public_exponent); + AuthorizationSetBuilder& EcdsaKey(uint32_t key_size); + AuthorizationSetBuilder& EcdsaKey(EcCurve curve); + AuthorizationSetBuilder& AesKey(uint32_t key_size); + AuthorizationSetBuilder& TripleDesKey(uint32_t key_size); + AuthorizationSetBuilder& HmacKey(uint32_t key_size); + + AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent); + AuthorizationSetBuilder& RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent); + AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size); + AuthorizationSetBuilder& EcdsaSigningKey(EcCurve curve); + AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size); + AuthorizationSetBuilder& TripleDesEncryptionKey(uint32_t key_size); + + AuthorizationSetBuilder& SigningKey(); + AuthorizationSetBuilder& EncryptionKey(); + + AuthorizationSetBuilder& NoDigestOrPadding(); + + AuthorizationSetBuilder& EcbMode(); + AuthorizationSetBuilder& GcmModeMinMacLen(uint32_t minMacLength); + AuthorizationSetBuilder& GcmModeMacLen(uint32_t macLength); + + AuthorizationSetBuilder& BlockMode(std::initializer_list<BlockMode> blockModes); + AuthorizationSetBuilder& Digest(std::vector<Digest> digests); + AuthorizationSetBuilder& Padding(std::initializer_list<PaddingMode> paddings); + + template <typename... T> + AuthorizationSetBuilder& BlockMode(T&&... a) { + return BlockMode({std::forward<T>(a)...}); + } + template <typename... T> + AuthorizationSetBuilder& Digest(T&&... a) { + return Digest({std::forward<T>(a)...}); + } + template <typename... T> + AuthorizationSetBuilder& Padding(T&&... a) { + return Padding({std::forward<T>(a)...}); + } +}; + +} // namespace android::hardware::security::keymint + +#endif // SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_ diff --git a/security/keymint/support/include/keymint_support/key_param_output.h b/security/keymint/support/include/keymint_support/key_param_output.h new file mode 100644 index 0000000000..82c9689329 --- /dev/null +++ b/security/keymint/support/include/keymint_support/key_param_output.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2020 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. + */ + +#ifndef HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEY_PARAM_OUTPUT_H_ +#define HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEY_PARAM_OUTPUT_H_ + +#include <iostream> +#include <vector> + +#include <android/hardware/security/keymint/Algorithm.h> +#include <android/hardware/security/keymint/BlockMode.h> +#include <android/hardware/security/keymint/Digest.h> +#include <android/hardware/security/keymint/EcCurve.h> +#include <android/hardware/security/keymint/ErrorCode.h> +#include <android/hardware/security/keymint/HardwareAuthenticatorType.h> +#include <android/hardware/security/keymint/KeyCharacteristics.h> +#include <android/hardware/security/keymint/KeyOrigin.h> +#include <android/hardware/security/keymint/KeyParameter.h> +#include <android/hardware/security/keymint/KeyPurpose.h> +#include <android/hardware/security/keymint/PaddingMode.h> +#include <android/hardware/security/keymint/SecurityLevel.h> +#include <android/hardware/security/keymint/Tag.h> +#include <android/hardware/security/keymint/TagType.h> + +#include "keymint_tags.h" + +namespace android::hardware::security::keymint { + +inline ::std::ostream& operator<<(::std::ostream& os, Algorithm value) { + return os << toString(value); +} + +inline ::std::ostream& operator<<(::std::ostream& os, BlockMode value) { + return os << toString(value); +} + +inline ::std::ostream& operator<<(::std::ostream& os, Digest value) { + return os << toString(value); +} + +inline ::std::ostream& operator<<(::std::ostream& os, EcCurve value) { + return os << toString(value); +} + +inline ::std::ostream& operator<<(::std::ostream& os, ErrorCode value) { + return os << toString(value); +} + +inline ::std::ostream& operator<<(::std::ostream& os, KeyOrigin value) { + return os << toString(value); +} + +inline ::std::ostream& operator<<(::std::ostream& os, PaddingMode value) { + return os << toString(value); +} + +inline ::std::ostream& operator<<(::std::ostream& os, SecurityLevel value) { + return os << toString(value); +} + +template <typename ValueT> +::std::ostream& operator<<(::std::ostream& os, const NullOr<ValueT>& value) { + if (!value.isOk()) { + os << "(value not present)"; + } else { + os << value.value(); + } + return os; +} + +::std::ostream& operator<<(::std::ostream& os, const ::std::vector<KeyParameter>& set); +::std::ostream& operator<<(::std::ostream& os, const KeyParameter& param); + +inline ::std::ostream& operator<<(::std::ostream& os, const KeyCharacteristics& value) { + return os << "SW: " << value.softwareEnforced << ::std::endl + << "HW: " << value.hardwareEnforced << ::std::endl; +} + +inline ::std::ostream& operator<<(::std::ostream& os, KeyPurpose value) { + return os << toString(value); +} + +inline ::std::ostream& operator<<(::std::ostream& os, Tag tag) { + return os << toString(tag); +} + +} // namespace android::hardware::security::keymint + +#endif // HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEY_PARAM_OUTPUT_H_ diff --git a/security/keymint/support/include/keymint_support/keymint_tags.h b/security/keymint/support/include/keymint_support/keymint_tags.h new file mode 100644 index 0000000000..f23e4f2ce2 --- /dev/null +++ b/security/keymint/support/include/keymint_support/keymint_tags.h @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEYMINT_TAGS_H_ +#define HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEYMINT_TAGS_H_ + +#include <android/hardware/security/keymint/Algorithm.h> +#include <android/hardware/security/keymint/BlockMode.h> +#include <android/hardware/security/keymint/Digest.h> +#include <android/hardware/security/keymint/EcCurve.h> +#include <android/hardware/security/keymint/HardwareAuthenticatorType.h> +#include <android/hardware/security/keymint/KeyOrigin.h> +#include <android/hardware/security/keymint/KeyParameter.h> +#include <android/hardware/security/keymint/KeyPurpose.h> +#include <android/hardware/security/keymint/PaddingMode.h> +#include <android/hardware/security/keymint/SecurityLevel.h> +#include <android/hardware/security/keymint/Tag.h> +#include <android/hardware/security/keymint/TagType.h> + +namespace android::hardware::security::keymint { + +// The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have. We +// need these old values to be able to support old keys that use them. +// TODO(seleneh) we should delete this code when we stop supporting keymaster1 +// and deletes it. +static const int32_t KM_TAG_DIGEST_OLD = static_cast<int32_t>(TagType::ENUM) | 5; +static const int32_t KM_TAG_PADDING_OLD = static_cast<int32_t>(TagType::ENUM) | 7; + +constexpr TagType typeFromTag(Tag tag) { + return static_cast<TagType>(static_cast<uint32_t>(tag) & static_cast<uint32_t>(0xf0000000)); +} + +/** + * TypedTag is a templatized version of Tag, which provides compile-time checking of + * keymint tag types. Instances are convertible to Tag, so they can be used wherever + * Tag is expected, and because they encode the tag type it's possible to create + * function overloads that only operate on tags with a particular type. + */ +template <TagType tag_type, Tag tag> +struct TypedTag { + inline TypedTag() { + // Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type + // 'tag_type'. Attempting to instantiate a tag with the wrong type will result in a compile + // error (no match for template specialization StaticAssert<false>), with no run-time cost. + static_assert(typeFromTag(tag) == tag_type, "mismatch between tag and tag_type"); + } + operator Tag() const { return tag; } + int32_t maskedTag() { return static_cast<uint32_t>(tag) & 0x0FFFFFFF; } +}; + +template <Tag tag> +struct Tag2TypedTag { + typedef TypedTag<typeFromTag(tag), tag> type; +}; + +#define DECLARE_TYPED_TAG(name) \ + typedef typename Tag2TypedTag<Tag::name>::type TAG_##name##_t; \ + static TAG_##name##_t TAG_##name; + +DECLARE_TYPED_TAG(ACTIVE_DATETIME); +DECLARE_TYPED_TAG(ALGORITHM); +DECLARE_TYPED_TAG(ALLOW_WHILE_ON_BODY); +DECLARE_TYPED_TAG(APPLICATION_DATA); +DECLARE_TYPED_TAG(APPLICATION_ID); +DECLARE_TYPED_TAG(ASSOCIATED_DATA); +DECLARE_TYPED_TAG(ATTESTATION_APPLICATION_ID); +DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE); +DECLARE_TYPED_TAG(ATTESTATION_ID_BRAND); +DECLARE_TYPED_TAG(ATTESTATION_ID_DEVICE); +DECLARE_TYPED_TAG(ATTESTATION_ID_PRODUCT); +DECLARE_TYPED_TAG(ATTESTATION_ID_MANUFACTURER); +DECLARE_TYPED_TAG(ATTESTATION_ID_MODEL); +DECLARE_TYPED_TAG(AUTH_TIMEOUT); +DECLARE_TYPED_TAG(BLOCK_MODE); +DECLARE_TYPED_TAG(BOOTLOADER_ONLY); +DECLARE_TYPED_TAG(BOOT_PATCHLEVEL); +DECLARE_TYPED_TAG(CALLER_NONCE); +DECLARE_TYPED_TAG(CONFIRMATION_TOKEN); +DECLARE_TYPED_TAG(CREATION_DATETIME); +DECLARE_TYPED_TAG(DEVICE_UNIQUE_ATTESTATION); +DECLARE_TYPED_TAG(DIGEST); +DECLARE_TYPED_TAG(EARLY_BOOT_ONLY); +DECLARE_TYPED_TAG(EC_CURVE); +DECLARE_TYPED_TAG(HARDWARE_TYPE); +DECLARE_TYPED_TAG(IDENTITY_CREDENTIAL_KEY); +DECLARE_TYPED_TAG(INCLUDE_UNIQUE_ID); +DECLARE_TYPED_TAG(INVALID); +DECLARE_TYPED_TAG(KEY_SIZE); +DECLARE_TYPED_TAG(MAC_LENGTH); +DECLARE_TYPED_TAG(MAX_USES_PER_BOOT); +DECLARE_TYPED_TAG(MIN_MAC_LENGTH); +DECLARE_TYPED_TAG(MIN_SECONDS_BETWEEN_OPS); +DECLARE_TYPED_TAG(NONCE); +DECLARE_TYPED_TAG(NO_AUTH_REQUIRED); +DECLARE_TYPED_TAG(ORIGIN); +DECLARE_TYPED_TAG(ORIGINATION_EXPIRE_DATETIME); +DECLARE_TYPED_TAG(OS_PATCHLEVEL); +DECLARE_TYPED_TAG(OS_VERSION); +DECLARE_TYPED_TAG(PADDING); +DECLARE_TYPED_TAG(PURPOSE); +DECLARE_TYPED_TAG(RESET_SINCE_ID_ROTATION); +DECLARE_TYPED_TAG(ROLLBACK_RESISTANCE); +DECLARE_TYPED_TAG(ROOT_OF_TRUST); +DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT); +DECLARE_TYPED_TAG(STORAGE_KEY); +DECLARE_TYPED_TAG(TRUSTED_CONFIRMATION_REQUIRED); +DECLARE_TYPED_TAG(TRUSTED_USER_PRESENCE_REQUIRED); +DECLARE_TYPED_TAG(UNIQUE_ID); +DECLARE_TYPED_TAG(UNLOCKED_DEVICE_REQUIRED); +DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME); +DECLARE_TYPED_TAG(USER_AUTH_TYPE); +DECLARE_TYPED_TAG(USER_ID); +DECLARE_TYPED_TAG(USER_SECURE_ID); +DECLARE_TYPED_TAG(VENDOR_PATCHLEVEL); + +template <typename... Elems> +struct MetaList {}; + +using all_tags_t = MetaList< + TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t, TAG_MIN_MAC_LENGTH_t, + TAG_RSA_PUBLIC_EXPONENT_t, TAG_INCLUDE_UNIQUE_ID_t, TAG_ACTIVE_DATETIME_t, + TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t, + TAG_MIN_SECONDS_BETWEEN_OPS_t, TAG_MAX_USES_PER_BOOT_t, TAG_USER_ID_t, TAG_USER_SECURE_ID_t, + TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t, TAG_ALLOW_WHILE_ON_BODY_t, + TAG_UNLOCKED_DEVICE_REQUIRED_t, TAG_APPLICATION_ID_t, TAG_APPLICATION_DATA_t, + TAG_CREATION_DATETIME_t, TAG_ROLLBACK_RESISTANCE_t, TAG_HARDWARE_TYPE_t, + TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t, TAG_BOOTLOADER_ONLY_t, + TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t, TAG_ATTESTATION_CHALLENGE_t, + TAG_ATTESTATION_APPLICATION_ID_t, TAG_ATTESTATION_ID_BRAND_t, TAG_ATTESTATION_ID_DEVICE_t, + TAG_ATTESTATION_ID_PRODUCT_t, TAG_ATTESTATION_ID_MANUFACTURER_t, TAG_ATTESTATION_ID_MODEL_t, + TAG_RESET_SINCE_ID_ROTATION_t, TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, + TAG_DIGEST_t, TAG_PADDING_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_EC_CURVE_t, + TAG_BOOT_PATCHLEVEL_t, TAG_VENDOR_PATCHLEVEL_t, TAG_TRUSTED_CONFIRMATION_REQUIRED_t, + TAG_TRUSTED_USER_PRESENCE_REQUIRED_t>; + +template <typename TypedTagType> +struct TypedTag2ValueType; + +#define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name) \ + template <Tag tag> \ + struct TypedTag2ValueType<TypedTag<tag_type, tag>> { \ + typedef decltype(static_cast<KeyParameter*>(nullptr)->field_name) type; \ + }; \ + template <Tag tag> \ + inline auto accessTagValue(TypedTag<tag_type, tag>, const KeyParameter& param) \ + ->const decltype(param.field_name)& { \ + return param.field_name; \ + } \ + template <Tag tag> \ + inline auto accessTagValue(TypedTag<tag_type, tag>, KeyParameter& param) \ + ->decltype(param.field_name)& { \ + return param.field_name; \ + } + +MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG, longInteger) +MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG_REP, longInteger) +MAKE_TAG_VALUE_ACCESSOR(TagType::DATE, longInteger) +MAKE_TAG_VALUE_ACCESSOR(TagType::UINT, integer) +MAKE_TAG_VALUE_ACCESSOR(TagType::UINT_REP, integer) +MAKE_TAG_VALUE_ACCESSOR(TagType::BOOL, boolValue) +MAKE_TAG_VALUE_ACCESSOR(TagType::BYTES, blob) +MAKE_TAG_VALUE_ACCESSOR(TagType::BIGNUM, blob) + +// TODO(seleneh) change these MAKE_TAG_ENUM_VALUE_ACCESSOR back to the 2 parameter +// version when aidl supports union +#define MAKE_TAG_ENUM_VALUE_ACCESSOR(typed_tag, field_name, field_type) \ + template <> \ + struct TypedTag2ValueType<decltype(typed_tag)> { \ + typedef field_type type; \ + }; \ + inline auto accessTagValue(decltype(typed_tag), const KeyParameter& param) \ + ->const field_type& { \ + return *reinterpret_cast<const field_type*>(¶m.field_name); \ + } \ + inline auto accessTagValue(decltype(typed_tag), KeyParameter& param)->field_type& { \ + return *reinterpret_cast<field_type*>(¶m.field_name); \ + } + +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ALGORITHM, integer, Algorithm) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOCK_MODE, integer, BlockMode) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_DIGEST, integer, Digest) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_EC_CURVE, integer, EcCurve) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ORIGIN, integer, KeyOrigin) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PADDING, integer, PaddingMode) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PURPOSE, integer, KeyPurpose) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_USER_AUTH_TYPE, integer, HardwareAuthenticatorType) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_HARDWARE_TYPE, integer, SecurityLevel) + +template <TagType tag_type, Tag tag, typename ValueT> +inline KeyParameter makeKeyParameter(TypedTag<tag_type, tag> ttag, ValueT&& value) { + KeyParameter param; + param.tag = tag; + param.longInteger = 0; + accessTagValue(ttag, param) = std::forward<ValueT>(value); + return param; +} + +// the boolean case +template <Tag tag> +inline KeyParameter makeKeyParameter(TypedTag<TagType::BOOL, tag>) { + KeyParameter param; + param.tag = tag; + param.boolValue = true; + return param; +} + +template <typename... Pack> +struct FirstOrNoneHelper; +template <typename First> +struct FirstOrNoneHelper<First> { + typedef First type; +}; +template <> +struct FirstOrNoneHelper<> { + struct type {}; +}; + +template <typename... Pack> +using FirstOrNone = typename FirstOrNoneHelper<Pack...>::type; + +template <TagType tag_type, Tag tag, typename... Args> +inline KeyParameter Authorization(TypedTag<tag_type, tag> ttag, Args&&... args) { + static_assert(tag_type != TagType::BOOL || (sizeof...(args) == 0), + "TagType::BOOL Authorizations do not take parameters. Presence is truth."); + static_assert(tag_type == TagType::BOOL || (sizeof...(args) == 1), + "Authorization other then TagType::BOOL take exactly one parameter."); + static_assert( + tag_type == TagType::BOOL || + std::is_convertible< + std::remove_cv_t<std::remove_reference_t<FirstOrNone<Args...>>>, + typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type>::value, + "Invalid argument type for given tag."); + + return makeKeyParameter(ttag, std::forward<Args>(args)...); +} + +/** + * This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out + * of band. Note that if the wrapped value is a reference it is unsafe to access the value if + * !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the + * wrapped value. In this case the pointer will be NULL though, and the value will be default + * constructed. + * + * TODO(seleneh) replace this with std::optional. + */ +template <typename ValueT> +class NullOr { + using internal_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value, + std::remove_reference_t<ValueT>*, ValueT>; + + struct pointer_initializer { + static std::nullptr_t init() { return nullptr; } + }; + struct value_initializer { + static ValueT init() { return ValueT(); } + }; + struct value_pointer_deref_t { + static ValueT& deref(ValueT& v) { return v; } + }; + struct reference_deref_t { + static auto& deref(internal_t v) { return *v; } + }; + using initializer_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value || + std::is_pointer<ValueT>::value, + pointer_initializer, value_initializer>; + using deref_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value, reference_deref_t, + value_pointer_deref_t>; + + public: + NullOr() : value_(initializer_t::init()), null_(true) {} + template <typename T> + NullOr(T&& value, typename std::enable_if< + !std::is_lvalue_reference<ValueT>::value && + std::is_same<std::decay_t<ValueT>, std::decay_t<T>>::value, + int>::type = 0) + : value_(std::forward<ValueT>(value)), null_(false) {} + template <typename T> + NullOr(T& value, typename std::enable_if< + std::is_lvalue_reference<ValueT>::value && + std::is_same<std::decay_t<ValueT>, std::decay_t<T>>::value, + int>::type = 0) + : value_(&value), null_(false) {} + + bool isOk() const { return !null_; } + + const ValueT& value() const& { return deref_t::deref(value_); } + ValueT& value() & { return deref_t::deref(value_); } + ValueT&& value() && { return std::move(deref_t::deref(value_)); } + + private: + internal_t value_; + bool null_; +}; + +template <typename T> +std::remove_reference_t<T> NullOrOr(T&& v) { + if (v.isOk()) return v; + return {}; +} + +template <typename Head, typename... Tail> +std::remove_reference_t<Head> NullOrOr(Head&& head, Tail&&... tail) { + if (head.isOk()) return head; + return NullOrOr(std::forward<Tail>(tail)...); +} + +template <typename Default, typename Wrapped> +std::remove_reference_t<Wrapped> defaultOr(NullOr<Wrapped>&& optional, Default&& def) { + static_assert(std::is_convertible<std::remove_reference_t<Default>, + std::remove_reference_t<Wrapped>>::value, + "Type of default value must match the type wrapped by NullOr"); + if (optional.isOk()) return optional.value(); + return def; +} + +template <TagType tag_type, Tag tag> +inline NullOr<const typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type&> authorizationValue( + TypedTag<tag_type, tag> ttag, const KeyParameter& param) { + if (tag != param.tag) return {}; + return accessTagValue(ttag, param); +} + +} // namespace android::hardware::security::keymint + +#endif // HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEYMINT_TAGS_H_ diff --git a/security/keymint/support/include/keymint_support/keymint_utils.h b/security/keymint/support/include/keymint_support/keymint_utils.h new file mode 100644 index 0000000000..fda1b6c9b2 --- /dev/null +++ b/security/keymint/support/include/keymint_support/keymint_utils.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2020 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. + */ + +#pragma once + +#ifndef HARDWARE_INTERFACES_KEYMINT_10_SUPPORT_KEYMINT_UTILS_H_ +#define HARDWARE_INTERFACES_KEYMINT_10_SUPPORT_KEYMINT_UTILS_H_ + +#include <android/hardware/security/keymint/HardwareAuthToken.h> + +namespace android::hardware::security::keymint { + +using std::vector; + +inline static std::vector<uint8_t> blob2vector(const uint8_t* data, const size_t length) { + std::vector<uint8_t> result(data, data + length); + return result; +} + +inline static std::vector<uint8_t> blob2vector(const std::string& value) { + vector<uint8_t> result(reinterpret_cast<const uint8_t*>(value.data()), + reinterpret_cast<const uint8_t*>(value.data()) + value.size()); + return result; +} + +HardwareAuthToken vector2AuthToken(const vector<uint8_t>& buffer); +vector<uint8_t> authToken2vector(const HardwareAuthToken& token); + +uint32_t getOsVersion(); +uint32_t getOsPatchlevel(); + +} // namespace android::hardware::security::keymint + +#endif // HARDWARE_INTERFACES_KEYMINT_10_SUPPORT_KEYMINT_UTILS_H_ diff --git a/security/keymint/support/include/keymint_support/openssl_utils.h b/security/keymint/support/include/keymint_support/openssl_utils.h new file mode 100644 index 0000000000..cb099680d4 --- /dev/null +++ b/security/keymint/support/include/keymint_support/openssl_utils.h @@ -0,0 +1,67 @@ +/* + * Copyright 2017 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. + */ + +#ifndef HARDWARE_INTERFACES_KEYMINT_1_0_SUPPORT_OPENSSL_UTILS_H_ +#define HARDWARE_INTERFACES_KEYMINT_1_0_SUPPORT_OPENSSL_UTILS_H_ + +#include <android/hardware/security/keymint/Digest.h> + +#include <openssl/evp.h> +#include <openssl/x509.h> + +namespace android::hardware::security::keymint { + +template <typename T, void (*F)(T*)> +struct UniquePtrDeleter { + void operator()(T* p) const { F(p); } +}; + +typedef UniquePtrDeleter<EVP_PKEY, EVP_PKEY_free> EVP_PKEY_Delete; + +#define MAKE_OPENSSL_PTR_TYPE(type) \ + typedef std::unique_ptr<type, UniquePtrDeleter<type, type##_free>> type##_Ptr; + +MAKE_OPENSSL_PTR_TYPE(ASN1_OBJECT) +MAKE_OPENSSL_PTR_TYPE(EVP_PKEY) +MAKE_OPENSSL_PTR_TYPE(RSA) +MAKE_OPENSSL_PTR_TYPE(X509) +MAKE_OPENSSL_PTR_TYPE(BN_CTX) + +typedef std::unique_ptr<BIGNUM, UniquePtrDeleter<BIGNUM, BN_free>> BIGNUM_Ptr; + +inline const EVP_MD* openssl_digest(Digest digest) { + switch (digest) { + case Digest::NONE: + return nullptr; + case Digest::MD5: + return EVP_md5(); + case Digest::SHA1: + return EVP_sha1(); + case Digest::SHA_2_224: + return EVP_sha224(); + case Digest::SHA_2_256: + return EVP_sha256(); + case Digest::SHA_2_384: + return EVP_sha384(); + case Digest::SHA_2_512: + return EVP_sha512(); + } + return nullptr; +} + +} // namespace android::hardware::security::keymint + +#endif // HARDWARE_INTERFACES_KEYMINT_1_0_SUPPORT_OPENSSL_UTILS_H_ diff --git a/security/keymint/support/key_param_output.cpp b/security/keymint/support/key_param_output.cpp new file mode 100644 index 0000000000..b699b2289e --- /dev/null +++ b/security/keymint/support/key_param_output.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2017 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 <keymint_support/key_param_output.h> + +#include <iomanip> + +#include <keymint_support/keymint_tags.h> + +namespace android::hardware::security::keymint { + +using ::std::endl; +using ::std::ostream; + +ostream& operator<<(ostream& os, const ::std::vector<KeyParameter>& set) { + if (set.size() == 0) { + os << "(Empty)" << endl; + } else { + os << "\n"; + for (const auto& elem : set) os << elem << endl; + } + return os; +} + +// TODO(seleneh) update this to a parsing that looks at each tags individually +// such as ALGORITHM BLOCK_MODE when aidl union support is added. +ostream& operator<<(ostream& os, const KeyParameter& param) { + os << param.tag << ": "; + switch (typeFromTag(param.tag)) { + case TagType::INVALID: + return os << " Invalid"; + case TagType::ENUM_REP: + case TagType::ENUM: + case TagType::UINT_REP: + case TagType::UINT: + return os << param.integer; + case TagType::ULONG_REP: + case TagType::ULONG: + case TagType::DATE: + return os << param.longInteger; + case TagType::BOOL: + return os << "true"; + case TagType::BIGNUM: + os << " Bignum: "; + for (size_t i = 0; i < param.blob.size(); ++i) { + os << std::hex << ::std::setw(2) << static_cast<int>(param.blob[i]) << ::std::dec; + } + return os; + case TagType::BYTES: + os << " Bytes: "; + for (size_t i = 0; i < param.blob.size(); ++i) { + os << ::std::hex << ::std::setw(2) << static_cast<int>(param.blob[i]) << ::std::dec; + } + return os; + } + return os << "UNKNOWN TAG TYPE!"; +} + +} // namespace android::hardware::security::keymint diff --git a/security/keymint/support/keymint_utils.cpp b/security/keymint/support/keymint_utils.cpp new file mode 100644 index 0000000000..cd4cca222a --- /dev/null +++ b/security/keymint/support/keymint_utils.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2018 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 <regex.h> + +#include <android-base/properties.h> +#include <hardware/hw_auth_token.h> +#include <keymint_support/keymint_utils.h> + +#include <arpa/inet.h> + +namespace android::hardware::security::keymint { + +namespace { + +constexpr char kPlatformVersionProp[] = "ro.build.version.release"; +constexpr char kPlatformVersionRegex[] = "^([0-9]{1,2})(\\.([0-9]{1,2}))?(\\.([0-9]{1,2}))?"; +constexpr size_t kMajorVersionMatch = 1; +constexpr size_t kMinorVersionMatch = 3; +constexpr size_t kSubminorVersionMatch = 5; +constexpr size_t kPlatformVersionMatchCount = kSubminorVersionMatch + 1; + +constexpr char kPlatformPatchlevelProp[] = "ro.build.version.security_patch"; +constexpr char kPlatformPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-[0-9]{2}$"; +constexpr size_t kYearMatch = 1; +constexpr size_t kMonthMatch = 2; +constexpr size_t kPlatformPatchlevelMatchCount = kMonthMatch + 1; + +uint32_t match_to_uint32(const char* expression, const regmatch_t& match) { + if (match.rm_so == -1) return 0; + + size_t len = match.rm_eo - match.rm_so; + std::string s(expression + match.rm_so, len); + return std::stoul(s); +} + +std::string wait_and_get_property(const char* prop) { + std::string prop_value; + while (!::android::base::WaitForPropertyCreation(prop)) + ; + prop_value = ::android::base::GetProperty(prop, "" /* default */); + return prop_value; +} + +} // anonymous namespace + +uint32_t getOsVersion(const char* version_str) { + regex_t regex; + if (regcomp(®ex, kPlatformVersionRegex, REG_EXTENDED)) { + return 0; + } + + regmatch_t matches[kPlatformVersionMatchCount]; + int not_match = + regexec(®ex, version_str, kPlatformVersionMatchCount, matches, 0 /* flags */); + regfree(®ex); + if (not_match) { + return 0; + } + + uint32_t major = match_to_uint32(version_str, matches[kMajorVersionMatch]); + uint32_t minor = match_to_uint32(version_str, matches[kMinorVersionMatch]); + uint32_t subminor = match_to_uint32(version_str, matches[kSubminorVersionMatch]); + + return (major * 100 + minor) * 100 + subminor; +} + +uint32_t getOsVersion() { + std::string version = wait_and_get_property(kPlatformVersionProp); + return getOsVersion(version.c_str()); +} + +uint32_t getOsPatchlevel(const char* patchlevel_str) { + regex_t regex; + if (regcomp(®ex, kPlatformPatchlevelRegex, REG_EXTENDED) != 0) { + return 0; + } + + regmatch_t matches[kPlatformPatchlevelMatchCount]; + int not_match = + regexec(®ex, patchlevel_str, kPlatformPatchlevelMatchCount, matches, 0 /* flags */); + regfree(®ex); + if (not_match) { + return 0; + } + + uint32_t year = match_to_uint32(patchlevel_str, matches[kYearMatch]); + uint32_t month = match_to_uint32(patchlevel_str, matches[kMonthMatch]); + + if (month < 1 || month > 12) { + return 0; + } + return year * 100 + month; +} + +uint32_t getOsPatchlevel() { + std::string patchlevel = wait_and_get_property(kPlatformPatchlevelProp); + return getOsPatchlevel(patchlevel.c_str()); +} + +} // namespace android::hardware::security::keymint |