Implement keymint V1 aidl interfaces, service module, and vts tests.
Bug: b/160968242
Test: atest VtsHalKeyMintV1_0TargetTest
Change-Id: I5f9d642f96e262dd567d88f4d582e621d168dceb
diff --git a/keymint/support/Android.bp b/keymint/support/Android.bp
new file mode 100644
index 0000000..432416e
--- /dev/null
+++ b/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: "libkeymintSupport",
+ 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.keymint-cpp",
+ "libbase",
+ "libcrypto",
+ "libutils",
+ ],
+}
diff --git a/keymint/support/OWNERS b/keymint/support/OWNERS
new file mode 100644
index 0000000..a93b171
--- /dev/null
+++ b/keymint/support/OWNERS
@@ -0,0 +1,4 @@
+jbires@google.com
+jdanis@google.com
+seleneh@google.com
+swillden@google.com
diff --git a/keymint/support/attestation_record.cpp b/keymint/support/attestation_record.cpp
new file mode 100644
index 0000000..e565974
--- /dev/null
+++ b/keymint/support/attestation_record.cpp
@@ -0,0 +1,387 @@
+/*
+ * 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 <keymintSupport/attestation_record.h>
+
+#include <android/hardware/keymint/Tag.h>
+#include <android/hardware/keymint/TagType.h>
+
+#include <android-base/logging.h>
+#include <assert.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <keymintSupport/authorization_set.h>
+#include <keymintSupport/openssl_utils.h>
+
+#define AT __FILE__ ":" << __LINE__
+
+namespace android {
+namespace hardware {
+namespace 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 keymint
+} // namespace hardware
+} // namespace android
diff --git a/keymint/support/authorization_set.cpp b/keymint/support/authorization_set.cpp
new file mode 100644
index 0000000..9fc4e13
--- /dev/null
+++ b/keymint/support/authorization_set.cpp
@@ -0,0 +1,529 @@
+/*
+ * 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 <keymintSupport/authorization_set.h>
+
+#include <assert.h>
+
+#include <android-base/logging.h>
+#include <sstream>
+
+#include <android/hardware/keymint/Algorithm.h>
+#include <android/hardware/keymint/BlockMode.h>
+#include <android/hardware/keymint/Digest.h>
+#include <android/hardware/keymint/KeyParameter.h>
+#include <android/hardware/keymint/KeyPurpose.h>
+#include <android/hardware/keymint/TagType.h>
+
+namespace android {
+namespace hardware {
+namespace 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::keymint::TypedTag<tag_type, tag>, Tail...> {
+ static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+ if (param.tag == tag) {
+ return android::hardware::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::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::keymint::BlockMode> blockModes) {
+ for (auto mode : blockModes) {
+ push_back(TAG_BLOCK_MODE, mode);
+ }
+ return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::Digest(
+ std::vector<android::hardware::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 keymint
+} // namespace hardware
+} // namespace android
diff --git a/keymint/support/include/keymintSupport/attestation_record.h b/keymint/support/include/keymintSupport/attestation_record.h
new file mode 100644
index 0000000..7a69789
--- /dev/null
+++ b/keymint/support/include/keymintSupport/attestation_record.h
@@ -0,0 +1,95 @@
+/*
+ * 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/keymint/ErrorCode.h>
+#include <android/hardware/keymint/IKeyMintDevice.h>
+
+#include <keymintSupport/attestation_record.h>
+#include <keymintSupport/authorization_set.h>
+#include <keymintSupport/openssl_utils.h>
+
+namespace android {
+namespace hardware {
+namespace keymint {
+
+using android::hardware::keymint::KeyParameter;
+using android::hardware::keymint::Tag;
+using android::hardware::keymint::TAG_ALGORITHM;
+
+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 keymint
+} // namespace hardware
+} // namespace android
diff --git a/keymint/support/include/keymintSupport/authorization_set.h b/keymint/support/include/keymintSupport/authorization_set.h
new file mode 100644
index 0000000..141426a
--- /dev/null
+++ b/keymint/support/include/keymintSupport/authorization_set.h
@@ -0,0 +1,329 @@
+/*
+ * 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/keymint/BlockMode.h>
+#include <android/hardware/keymint/Digest.h>
+#include <android/hardware/keymint/EcCurve.h>
+#include <android/hardware/keymint/PaddingMode.h>
+
+#include <keymintSupport/keymint_tags.h>
+
+namespace android {
+namespace hardware {
+namespace keymint {
+
+using android::hardware::keymint::BlockMode;
+using android::hardware::keymint::Digest;
+using android::hardware::keymint::EcCurve;
+using android::hardware::keymint::PaddingMode;
+
+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 keymint
+} // namespace hardware
+} // namespace android
+
+#endif // SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_
diff --git a/keymint/support/include/keymintSupport/key_param_output.h b/keymint/support/include/keymintSupport/key_param_output.h
new file mode 100644
index 0000000..a35a981
--- /dev/null
+++ b/keymint/support/include/keymintSupport/key_param_output.h
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+#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 "keymint_tags.h"
+
+#include <android/hardware/keymint/Algorithm.h>
+#include <android/hardware/keymint/BlockMode.h>
+#include <android/hardware/keymint/Digest.h>
+#include <android/hardware/keymint/EcCurve.h>
+#include <android/hardware/keymint/ErrorCode.h>
+#include <android/hardware/keymint/HardwareAuthenticatorType.h>
+#include <android/hardware/keymint/KeyCharacteristics.h>
+#include <android/hardware/keymint/KeyOrigin.h>
+#include <android/hardware/keymint/KeyParameter.h>
+#include <android/hardware/keymint/KeyPurpose.h>
+#include <android/hardware/keymint/PaddingMode.h>
+#include <android/hardware/keymint/SecurityLevel.h>
+#include <android/hardware/keymint/Tag.h>
+#include <android/hardware/keymint/TagType.h>
+
+namespace android {
+namespace hardware {
+namespace keymint {
+
+using namespace ::android::hardware::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 keymint
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEY_PARAM_OUTPUT_H_
diff --git a/keymint/support/include/keymintSupport/keymint_tags.h b/keymint/support/include/keymintSupport/keymint_tags.h
new file mode 100644
index 0000000..f1060a9
--- /dev/null
+++ b/keymint/support/include/keymintSupport/keymint_tags.h
@@ -0,0 +1,414 @@
+/*
+ * 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/keymint/Algorithm.h>
+#include <android/hardware/keymint/BlockMode.h>
+#include <android/hardware/keymint/Digest.h>
+#include <android/hardware/keymint/EcCurve.h>
+#include <android/hardware/keymint/HardwareAuthenticatorType.h>
+#include <android/hardware/keymint/KeyOrigin.h>
+#include <android/hardware/keymint/KeyParameter.h>
+#include <android/hardware/keymint/KeyPurpose.h>
+#include <android/hardware/keymint/PaddingMode.h>
+#include <android/hardware/keymint/SecurityLevel.h>
+#include <android/hardware/keymint/Tag.h>
+#include <android/hardware/keymint/TagType.h>
+
+namespace android::hardware::keymint {
+
+using android::hardware::keymint::KeyParameter;
+using android::hardware::keymint::Tag;
+using android::hardware::keymint::TagType;
+
+// 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::keymint
+
+namespace std {
+
+using namespace android::hardware::keymint;
+
+// Aidl generates KeyParameter operator<, >, ==, != for cpp translation but not ndk
+// translations. So we cannot straight forward overload these operators.
+// However we need our custom comparison for KeyParameters. So we will
+// overload std::less, equal_to instead.
+template <>
+struct std::less<KeyParameter> {
+ bool operator()(const KeyParameter& a, const KeyParameter& b) const {
+ if (a.tag != b.tag) return a.tag < b.tag;
+ int retval;
+ switch (typeFromTag(a.tag)) {
+ case TagType::INVALID:
+ case TagType::BOOL:
+ return false;
+ case TagType::ENUM:
+ case TagType::ENUM_REP:
+ case TagType::UINT:
+ case TagType::UINT_REP:
+ return a.integer < b.integer;
+ case TagType::ULONG:
+ case TagType::ULONG_REP:
+ case TagType::DATE:
+ return a.longInteger < b.longInteger;
+ case TagType::BIGNUM:
+ case TagType::BYTES:
+ // Handle the empty cases.
+ if (a.blob.size() == 0) return b.blob.size() != 0;
+ if (b.blob.size() == 0) return false;
+ retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size()));
+ // if one is the prefix of the other the longer wins
+ if (retval == 0) return a.blob.size() < b.blob.size();
+ // Otherwise a is less if a is less.
+ else
+ return retval < 0;
+ }
+ return false;
+ }
+};
+
+template <>
+struct std::equal_to<KeyParameter> {
+ bool operator()(const KeyParameter& a, const KeyParameter& b) const {
+ if (a.tag != b.tag) {
+ return false;
+ }
+ switch (typeFromTag(a.tag)) {
+ case TagType::INVALID:
+ case TagType::BOOL:
+ return true;
+ case TagType::ENUM:
+ case TagType::ENUM_REP:
+ case TagType::UINT:
+ case TagType::UINT_REP:
+ return a.integer == b.integer;
+ case TagType::ULONG:
+ case TagType::ULONG_REP:
+ case TagType::DATE:
+ return a.longInteger == b.longInteger;
+ case TagType::BIGNUM:
+ case TagType::BYTES:
+ if (a.blob.size() != b.blob.size()) return false;
+ return a.blob.size() == 0 || memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0;
+ }
+ return false;
+ }
+};
+
+} // namespace std
+
+#endif // HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEYMINT_TAGS_H_
diff --git a/keymint/support/include/keymintSupport/keymint_utils.h b/keymint/support/include/keymintSupport/keymint_utils.h
new file mode 100644
index 0000000..aa1e93b
--- /dev/null
+++ b/keymint/support/include/keymintSupport/keymint_utils.h
@@ -0,0 +1,51 @@
+/*
+ * 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/keymint/HardwareAuthToken.h>
+
+namespace android {
+namespace hardware {
+namespace 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 keymint
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_KEYMINT_10_SUPPORT_KEYMINT_UTILS_H_
diff --git a/keymint/support/include/keymintSupport/openssl_utils.h b/keymint/support/include/keymintSupport/openssl_utils.h
new file mode 100644
index 0000000..39633ed
--- /dev/null
+++ b/keymint/support/include/keymintSupport/openssl_utils.h
@@ -0,0 +1,63 @@
+/*
+ * 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/keymint/Digest.h>
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+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(android::hardware::keymint::Digest digest) {
+ switch (digest) {
+ case android::hardware::keymint::Digest::NONE:
+ return nullptr;
+ case android::hardware::keymint::Digest::MD5:
+ return EVP_md5();
+ case android::hardware::keymint::Digest::SHA1:
+ return EVP_sha1();
+ case android::hardware::keymint::Digest::SHA_2_224:
+ return EVP_sha224();
+ case android::hardware::keymint::Digest::SHA_2_256:
+ return EVP_sha256();
+ case android::hardware::keymint::Digest::SHA_2_384:
+ return EVP_sha384();
+ case android::hardware::keymint::Digest::SHA_2_512:
+ return EVP_sha512();
+ }
+ return nullptr;
+}
+
+#endif // HARDWARE_INTERFACES_KEYMINT_1_0_SUPPORT_OPENSSL_UTILS_H_
diff --git a/keymint/support/key_param_output.cpp b/keymint/support/key_param_output.cpp
new file mode 100644
index 0000000..6e33558
--- /dev/null
+++ b/keymint/support/key_param_output.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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 <keymintSupport/key_param_output.h>
+
+#include <keymintSupport/keymint_tags.h>
+
+#include <iomanip>
+
+namespace android {
+namespace hardware {
+namespace 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 keymint
+} // namespace hardware
+} // namespace android
diff --git a/keymint/support/keymint_utils.cpp b/keymint/support/keymint_utils.cpp
new file mode 100644
index 0000000..fd57cf5
--- /dev/null
+++ b/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 <keymintSupport/keymint_utils.h>
+
+#include <arpa/inet.h>
+
+namespace android::hardware::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::keymint