summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn Willden <swillden@google.com>2015-06-18 12:17:05 -0600
committerShawn Willden <swillden@google.com>2015-06-19 09:58:54 -0600
commitb5508298cdb1d42eaf8c81aa8a6ac2cbfdeef3c7 (patch)
tree8014729e24d0bb26f15f18474ea2a0f9a8651763
parent294a2db0e5f2eb46d84e4f5c9ce25245ac474147 (diff)
downloadkeymaster-b5508298cdb1d42eaf8c81aa8a6ac2cbfdeef3c7.tar.gz
Update KeymasterEnforcement.
This brings KeymasterEnforcement up to date and cleans it up, making the code more consistent with the rest of keymaster. It also makes it possible to use from Trusty, by virtualizing some time-related functions that don't work the same in Trusty-land. Bug: 19511945 Change-Id: I1141c953f227f3ef8a78751d9f04bf4e4922d1f5
-rw-r--r--Android.mk2
-rw-r--r--authorization_set.cpp10
-rw-r--r--include/keymaster/authorization_set.h2
-rw-r--r--include/keymaster/keymaster_enforcement.h175
-rw-r--r--include/keymaster/keymaster_tags.h1
-rw-r--r--keymaster_enforcement.cpp519
-rw-r--r--keymaster_enforcement.h196
-rw-r--r--keymaster_enforcement_test.cpp800
8 files changed, 1068 insertions, 637 deletions
diff --git a/Android.mk b/Android.mk
index 4db0d3b..ed1a06e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -60,6 +60,7 @@ LOCAL_SRC_FILES:= \
hmac_operation.cpp \
integrity_assured_key_blob.cpp \
key.cpp \
+ keymaster_enforcement.cpp \
ocb.c \
ocb_utils.cpp \
openssl_err.cpp \
@@ -119,7 +120,6 @@ LOCAL_SRC_FILES := \
hkdf_test.cpp \
hmac_test.cpp \
key_blob_test.cpp \
- keymaster_enforcement.cpp \
keymaster_enforcement_test.cpp
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include
diff --git a/authorization_set.cpp b/authorization_set.cpp
index c7c8d6c..d860873 100644
--- a/authorization_set.cpp
+++ b/authorization_set.cpp
@@ -197,18 +197,18 @@ keymaster_key_param_t AuthorizationSet::operator[](int at) const {
return empty;
}
-bool AuthorizationSet::push_back(const AuthorizationSet& set) {
+bool AuthorizationSet::push_back(const keymaster_key_param_set_t& set) {
if (is_valid() != OK)
return false;
- if (!reserve_elems(elems_size_ + set.elems_size_))
+ if (!reserve_elems(elems_size_ + set.length))
return false;
- if (!reserve_indirect(indirect_data_size_ + set.indirect_data_size_))
+ if (!reserve_indirect(indirect_data_size_ + ComputeIndirectDataSize(set.params, set.length)))
return false;
- for (size_t i = 0; i < set.size(); ++i)
- if (!push_back(set[i]))
+ for (size_t i = 0; i < set.length; ++i)
+ if (!push_back(set.params[i]))
return false;
return true;
diff --git a/include/keymaster/authorization_set.h b/include/keymaster/authorization_set.h
index c0c0686..a3d7a27 100644
--- a/include/keymaster/authorization_set.h
+++ b/include/keymaster/authorization_set.h
@@ -309,7 +309,7 @@ class AuthorizationSet : public Serializable, public keymaster_key_param_set_t {
*/
bool reserve_indirect(size_t length);
- bool push_back(const AuthorizationSet& set);
+ bool push_back(const keymaster_key_param_set_t& set);
/**
* Append the tag and enumerated value to the set.
diff --git a/include/keymaster/keymaster_enforcement.h b/include/keymaster/keymaster_enforcement.h
new file mode 100644
index 0000000..5b5d33b
--- /dev/null
+++ b/include/keymaster/keymaster_enforcement.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2014 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 ANDROID_LIBRARY_KEYMASTER_ENFORCEMENT_H
+#define ANDROID_LIBRARY_KEYMASTER_ENFORCEMENT_H
+
+#include <stdio.h>
+
+#include <utils/List.h>
+
+#include <keymaster/authorization_set.h>
+
+namespace keymaster {
+
+typedef uint64_t km_id_t;
+
+class KeymasterEnforcementContext {
+ public:
+ virtual ~KeymasterEnforcementContext() {}
+ /*
+ * Get current time.
+ */
+};
+
+class KeymasterEnforcement {
+
+ public:
+ /**
+ * Construct a KeymasterEnforcement. Takes ownership of the context.
+ */
+ explicit KeymasterEnforcement(uint32_t max_access_time_map_size,
+ uint32_t max_access_count_map_size)
+ : access_time_map_(max_access_time_map_size), access_count_map_(max_access_count_map_size) {
+ }
+ virtual ~KeymasterEnforcement() {}
+
+ /**
+ * Iterates through the authorization set and returns the corresponding keymaster error. Will
+ * return KM_ERROR_OK if all criteria is met for the given purpose in the authorization set with
+ * the given operation params and handle. Used for encrypt, decrypt sign, and verify.
+ */
+ keymaster_error_t AuthorizeOperation(const keymaster_purpose_t purpose, const km_id_t keyid,
+ const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params,
+ keymaster_operation_handle_t op_handle,
+ bool is_begin_operation);
+
+ /**
+ * Creates a key ID for use in subsequent calls to AuthorizeOperation. Clients needn't use this
+ * method of creating key IDs, as long as they use something consistent and unique. This method
+ * hashes the key blob.
+ *
+ * Returns false if an error in the crypto library prevents creation of an ID.
+ */
+ static bool CreateKeyId(const keymaster_key_blob_t& key_blob, km_id_t* keyid);
+
+ //
+ // Methods that must be implemented by subclasses
+ //
+ // The time-related methods address the fact that different enforcement contexts may have
+ // different time-related capabilities. In particular:
+ //
+ // - They may or may not be able to check dates against real-world clocks.
+ //
+ // - They may or may not be able to check timestampls against authentication trustlets (minters
+ // of hw_auth_token_t structs).
+ //
+ // - They must have some time source for relative times, but may not be able to provide more
+ // than reliability and monotonicity.
+
+ /*
+ * Returns true if the specified activation date has passed, or if activation cannot be
+ * enforced.
+ */
+ virtual bool activation_date_valid(uint64_t activation_date) const = 0;
+
+ /*
+ * Returns true if the specified expiration date has passed. Returns false if it has not, or if
+ * expiration cannot be enforced.
+ */
+ virtual bool expiration_date_passed(uint64_t expiration_date) const = 0;
+
+ /*
+ * Returns true if the specified auth_token is older than the specified timeout.
+ */
+ virtual bool auth_token_timed_out(const hw_auth_token_t& token, uint32_t timeout) const = 0;
+
+ /*
+ * Get current time in seconds from some starting point. This value is used to compute relative
+ * times between events. It must be monotonically increasing, and must not skip or lag. It
+ * need not have any relation to any external time standard (other than the duration of
+ * "second").
+ *
+ * On POSIX systems, it's recommented to use clock_gettime(CLOCK_MONOTONIC, ...) to implement
+ * this method.
+ */
+ virtual uint32_t get_current_time() const = 0;
+
+ /*
+ * Returns true if the specified auth_token has a valid signature, or if signature validation is
+ * not available.
+ */
+ virtual bool ValidateTokenSignature(const hw_auth_token_t& token) const = 0;
+
+ private:
+ bool MinTimeBetweenOpsPassed(uint32_t min_time_between, const km_id_t keyid);
+ bool MaxUsesPerBootNotExceeded(const km_id_t keyid, uint32_t max_uses);
+ bool AuthTokenMatches(const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params, const uint64_t user_secure_id,
+ const int auth_type_index, const int auth_timeout_index,
+ const keymaster_operation_handle_t op_handle,
+ bool is_begin_operation) const;
+
+ class AccessTimeMap {
+ public:
+ AccessTimeMap(uint32_t max_size) : max_size_(max_size) {}
+
+ /* If the key is found, returns true and fills \p last_access_time. If not found returns
+ * false. */
+ bool LastKeyAccessTime(km_id_t keyid, uint32_t* last_access_time) const;
+
+ /* Updates the last key access time with the currentTime parameter. Adds the key if
+ * needed, returning false if key cannot be added because list is full. */
+ bool UpdateKeyAccessTime(km_id_t keyid, uint32_t current_time, uint32_t timeout);
+
+ private:
+ struct AccessTime {
+ km_id_t keyid;
+ uint32_t access_time;
+ uint32_t timeout;
+ };
+ android::List<AccessTime> last_access_list_;
+ const uint32_t max_size_;
+ };
+
+ class AccessCountMap {
+ public:
+ AccessCountMap(uint32_t max_size) : max_size_(max_size) {}
+
+ /* If the key is found, returns true and fills \p count. If not found returns
+ * false. */
+ bool KeyAccessCount(km_id_t keyid, uint32_t* count) const;
+
+ /* Increments key access count, adding an entry if the key has never been used. Returns
+ * false if the list has reached maximum size. */
+ bool IncrementKeyAccessCount(km_id_t keyid);
+
+ private:
+ struct AccessCount {
+ km_id_t keyid;
+ uint64_t access_count;
+ };
+ android::List<AccessCount> access_count_list_;
+ const uint32_t max_size_;
+ };
+
+ AccessTimeMap access_time_map_;
+ AccessCountMap access_count_map_;
+};
+}; /* namespace keymaster */
+
+#endif // ANDROID_LIBRARY_KEYMASTER_ENFORCEMENT_H
diff --git a/include/keymaster/keymaster_tags.h b/include/keymaster/keymaster_tags.h
index 954a93d..5f98f2c 100644
--- a/include/keymaster/keymaster_tags.h
+++ b/include/keymaster/keymaster_tags.h
@@ -182,6 +182,7 @@ DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_ROOT_OF_TRUST);
DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_ASSOCIATED_DATA);
DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_NONCE);
DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_AUTH_TOKEN);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_BOOTLOADER_ONLY);
#ifdef KEYMASTER_NAME_TAGS
#define DEFINE_KEYMASTER_ENUM_TAG(type, name, enumtype) \
diff --git a/keymaster_enforcement.cpp b/keymaster_enforcement.cpp
index 353288b..2401a34 100644
--- a/keymaster_enforcement.cpp
+++ b/keymaster_enforcement.cpp
@@ -14,51 +14,103 @@
* limitations under the License.
*/
+#include <keymaster/keymaster_enforcement.h>
+
+#include <assert.h>
#include <string.h>
-#include <time.h>
-#include "android_keymaster_test_utils.h"
-#include "keymaster_enforcement.h"
+#include <limits>
+
+#include <openssl/evp.h>
+
+#include <hardware/hw_auth_token.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/logger.h>
+
+using android::List;
namespace keymaster {
-KeymasterEnforcement::KeymasterEnforcement() {
- last_auth_time = -1;
+bool is_public_key_algorithm(const AuthorizationSet& auth_set) {
+ keymaster_algorithm_t algorithm;
+ return auth_set.GetTagValue(TAG_ALGORITHM, &algorithm) &&
+ (algorithm == KM_ALGORITHM_RSA || algorithm == KM_ALGORITHM_EC);
}
-KeymasterEnforcement::~KeymasterEnforcement() {
-}
+static keymaster_error_t authorized_purpose(const keymaster_purpose_t purpose,
+ const AuthorizationSet& auth_set) {
+ switch (purpose) {
+ case KM_PURPOSE_VERIFY:
+ case KM_PURPOSE_ENCRYPT:
+ if (is_public_key_algorithm(auth_set) || auth_set.Contains(TAG_PURPOSE, purpose))
+ return KM_ERROR_OK;
+ return KM_ERROR_INCOMPATIBLE_PURPOSE;
-keymaster_error_t KeymasterEnforcement::AuthorizeOperation(const keymaster_purpose_t purpose,
- const km_id_t keyid,
- const AuthorizationSet& auth_set,
- const uid_t uid) {
- time_t current_time;
- keymaster_error_t return_error;
+ case KM_PURPOSE_SIGN:
+ case KM_PURPOSE_DECRYPT:
+ if (auth_set.Contains(TAG_PURPOSE, purpose))
+ return KM_ERROR_OK;
+ return KM_ERROR_INCOMPATIBLE_PURPOSE;
- /* Pairs of tags that are incompatible and should return an error. */
- bool tag_all_users_present = false;
- bool tag_user_id_present = false;
+ default:
+ return KM_ERROR_UNSUPPORTED_PURPOSE;
+ }
+}
- bool tag_user_auth_id_present = false;
- bool tag_no_auth_required_present = false;
+inline bool is_origination_purpose(keymaster_purpose_t purpose) {
+ return purpose == KM_PURPOSE_ENCRYPT || purpose == KM_PURPOSE_SIGN;
+}
- bool tag_all_applications_present = false;
- bool tag_application_id_present = false;
+inline bool is_usage_purpose(keymaster_purpose_t purpose) {
+ return purpose == KM_PURPOSE_DECRYPT || purpose == KM_PURPOSE_VERIFY;
+}
- return_error = KM_ERROR_OK;
- current_time = get_current_time();
+inline bool can_skip_authentication(bool is_begin_operation, bool is_auth_per_op_key) {
+ // Durign begin with auth-per-op keys, we don't require authentication because it can't be
+ // performed until after begin returns the operation handle used to for the authentication
+ // challenge.
+ return is_begin_operation && is_auth_per_op_key;
+}
- int auth_timeout_index = auth_set.find(KM_TAG_AUTH_TIMEOUT);
- if (auth_timeout_index < 0) {
- /* TODO: Require Authentication. Method TBD. */
+keymaster_error_t KeymasterEnforcement::AuthorizeOperation(const keymaster_purpose_t purpose,
+ const km_id_t keyid,
+ const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params,
+ keymaster_operation_handle_t op_handle,
+ bool is_begin_operation) {
+ // Find some entries that may be needed to handle KM_TAG_USER_SECURE_ID
+ int auth_timeout_index = -1;
+ int auth_type_index = -1;
+ int no_auth_required_index = -1;
+ for (size_t pos = 0; pos < auth_set.size(); ++pos) {
+ switch (auth_set[pos].tag) {
+ case KM_TAG_AUTH_TIMEOUT:
+ auth_timeout_index = pos;
+ break;
+ case KM_TAG_USER_AUTH_TYPE:
+ auth_type_index = pos;
+ break;
+ case KM_TAG_NO_AUTH_REQUIRED:
+ no_auth_required_index = pos;
+ break;
+ default:
+ break;
+ }
}
- if ((return_error = valid_purpose(purpose, auth_set)) != KM_ERROR_OK)
- return return_error;
+ keymaster_error_t error = authorized_purpose(purpose, auth_set);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ // If successful, and if key has a min time between ops, this will be set to the time limit
+ uint32_t min_ops_timeout = UINT32_MAX;
- for (unsigned int i = 0; i < auth_set.size(); i++) {
- keymaster_key_param_t param = auth_set[i];
+ bool update_access_count = false;
+ bool found_caller_nonce = false;
+ bool authentication_required = false;
+ bool auth_token_matched = false;
+
+ for (auto& param : auth_set) {
// KM_TAG_PADDING_OLD and KM_TAG_DIGEST_OLD aren't actually members of the enum, so we can't
// switch on them. There's nothing to validate for them, though, so just ignore them.
@@ -66,58 +118,58 @@ keymaster_error_t KeymasterEnforcement::AuthorizeOperation(const keymaster_purpo
continue;
switch (param.tag) {
+
case KM_TAG_ACTIVE_DATETIME:
- return_error = Active(param, current_time);
+ if (!activation_date_valid(param.date_time))
+ return KM_ERROR_KEY_NOT_YET_VALID;
break;
+
case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
- return_error = OriginationNotExpired(param, current_time, purpose);
+ if (is_origination_purpose(purpose) && expiration_date_passed(param.date_time))
+ return KM_ERROR_KEY_EXPIRED;
break;
+
case KM_TAG_USAGE_EXPIRE_DATETIME:
- return_error = UsageNotExpired(param, current_time, purpose);
+ if (is_usage_purpose(purpose) && expiration_date_passed(param.date_time))
+ return KM_ERROR_KEY_EXPIRED;
break;
+
case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
- return_error = MinTimeBetweenOpsPassed(param, keyid, current_time);
+ min_ops_timeout = param.integer;
+ if (!MinTimeBetweenOpsPassed(min_ops_timeout, keyid))
+ return KM_ERROR_KEY_RATE_LIMIT_EXCEEDED;
break;
+
case KM_TAG_MAX_USES_PER_BOOT:
- return_error = NotUsedSinceBoot(keyid);
- break;
- case KM_TAG_ALL_USERS:
- tag_all_users_present = true;
- return_error = KM_ERROR_OK;
- break;
- case KM_TAG_USER_ID:
- tag_user_id_present = true;
- return_error = UserAuthenticated(param, uid);
+ update_access_count = true;
+ if (!MaxUsesPerBootNotExceeded(keyid, param.integer))
+ return KM_ERROR_KEY_MAX_OPS_EXCEEDED;
break;
+
case KM_TAG_USER_SECURE_ID:
- // TODO(swillden): Handle this.
- break;
- case KM_TAG_AUTH_TOKEN:
- // TODO(swillden): Handle this.
- break;
- case KM_TAG_NO_AUTH_REQUIRED:
- return_error = KM_ERROR_OK;
- tag_no_auth_required_present = true;
- break;
- case KM_TAG_USER_AUTH_TYPE:
- tag_user_auth_id_present = true;
- return_error = KM_ERROR_OK;
- break;
- case KM_TAG_AUTH_TIMEOUT:
- return_error = AuthenticationIsFresh(param, current_time);
- break;
- case KM_TAG_ALL_APPLICATIONS:
- tag_all_applications_present = true;
- break;
- case KM_TAG_APPLICATION_ID:
- tag_application_id_present = true;
+ if (no_auth_required_index != -1) {
+ // Key has both KM_TAG_USER_SECURE_ID and KM_TAG_NO_AUTH_REQUIRED
+ return KM_ERROR_INVALID_KEY_BLOB;
+ } else if (!can_skip_authentication(is_begin_operation, auth_timeout_index == -1) ||
+ operation_params.find(KM_TAG_AUTH_TOKEN) != -1) {
+ authentication_required = true;
+ if (AuthTokenMatches(auth_set, operation_params, param.long_integer,
+ auth_type_index, auth_timeout_index, op_handle,
+ is_begin_operation))
+ auth_token_matched = true;
+ }
break;
+
case KM_TAG_CALLER_NONCE:
- // TODO(swillden): Handle this tag. For now it's ignored.
+ found_caller_nonce = true;
break;
- /* Invalid tag is not used for access control. */
+ /* Tags should never be in key auths. */
case KM_TAG_INVALID:
+ case KM_TAG_AUTH_TOKEN:
+ case KM_TAG_ROOT_OF_TRUST:
+ case KM_TAG_APPLICATION_DATA:
+ return KM_ERROR_INVALID_KEY_BLOB;
/* Tags used for cryptographic parameters. */
case KM_TAG_PURPOSE:
@@ -136,234 +188,237 @@ keymaster_error_t KeymasterEnforcement::AuthorizeOperation(const keymaster_purpo
case KM_TAG_RSA_PUBLIC_EXPONENT:
/* Informational tags. */
- case KM_TAG_APPLICATION_DATA:
case KM_TAG_CREATION_DATETIME:
case KM_TAG_ORIGIN:
case KM_TAG_ROLLBACK_RESISTANT:
- case KM_TAG_ROOT_OF_TRUST:
+
+ /* Tags handled when KM_TAG_USER_SECURE_ID is handled */
+ case KM_TAG_NO_AUTH_REQUIRED:
+ case KM_TAG_USER_AUTH_TYPE:
+ case KM_TAG_AUTH_TIMEOUT:
/* Tag to provide data to operations. */
case KM_TAG_ASSOCIATED_DATA:
- return_error = KM_ERROR_OK;
- break;
- default:
- // TODO(swillden): remove this default case.
- return_error = KM_ERROR_UNIMPLEMENTED;
+
+ /* Ignored pending removal */
+ case KM_TAG_ALL_APPLICATIONS:
+ case KM_TAG_APPLICATION_ID:
+ case KM_TAG_USER_ID:
+ case KM_TAG_ALL_USERS:
break;
- }
- if (return_error != KM_ERROR_OK) {
- return return_error;
+ case KM_TAG_BOOTLOADER_ONLY:
+ return KM_ERROR_INVALID_KEY_BLOB;
}
}
- if ((tag_all_users_present && tag_user_id_present) ||
- (tag_user_auth_id_present && tag_no_auth_required_present) ||
- (tag_all_applications_present && tag_application_id_present)) {
- return_error = KM_ERROR_INVALID_TAG;
- }
-
- if (return_error == KM_ERROR_OK) {
- update_key_access_time(keyid);
+ if (authentication_required && !auth_token_matched) {
+ LOG_E("Auth required but no matching auth token found", 0);
+ return KM_ERROR_KEY_USER_NOT_AUTHENTICATED;
}
- return return_error;
-}
+ if (!found_caller_nonce && operation_params.find(KM_TAG_NONCE) != -1)
+ return KM_ERROR_CALLER_NONCE_PROHIBITED;
-keymaster_error_t KeymasterEnforcement::Active(const keymaster_key_param_t param,
- const time_t current_time) {
- time_t activation_time = param.date_time;
- if (difftime(current_time, activation_time) < 0) {
- return KM_ERROR_KEY_NOT_YET_VALID;
+ if (min_ops_timeout != UINT32_MAX &&
+ !access_time_map_.UpdateKeyAccessTime(keyid, get_current_time(), min_ops_timeout)) {
+ LOG_E("Rate-limited keys table full. Entries will time out.", 0);
+ return KM_ERROR_TOO_MANY_OPERATIONS;
}
- return KM_ERROR_OK;
-}
-
-keymaster_error_t KeymasterEnforcement::is_time_expired(const keymaster_key_param_t param,
- const time_t current_time) {
- time_t expire_time = param.date_time;
- if (difftime(current_time, expire_time) > 0) {
- return KM_ERROR_KEY_EXPIRED;
+ if (update_access_count && !access_count_map_.IncrementKeyAccessCount(keyid)) {
+ LOG_E("Usage count-limited keys table full, until reboot.", 0);
+ return KM_ERROR_TOO_MANY_OPERATIONS;
}
+
return KM_ERROR_OK;
}
-keymaster_error_t KeymasterEnforcement::UsageNotExpired(const keymaster_key_param_t param,
- const time_t current_time,
- const keymaster_purpose_t purpose) {
- switch (purpose) {
- case KM_PURPOSE_VERIFY:
- case KM_PURPOSE_DECRYPT:
- break;
- case KM_PURPOSE_SIGN:
- case KM_PURPOSE_ENCRYPT:
- return KM_ERROR_OK;
- }
+class EvpMdCtx {
+ public:
+ EvpMdCtx() { EVP_MD_CTX_init(&ctx_); }
+ ~EvpMdCtx() { EVP_MD_CTX_cleanup(&ctx_); }
- return is_time_expired(param, current_time);
-}
+ EVP_MD_CTX* get() { return &ctx_; }
-keymaster_error_t KeymasterEnforcement::OriginationNotExpired(const keymaster_key_param_t param,
- const time_t current_time,
- const keymaster_purpose_t purpose) {
- switch (purpose) {
- case KM_PURPOSE_SIGN:
- case KM_PURPOSE_ENCRYPT:
- break;
- case KM_PURPOSE_DECRYPT:
- case KM_PURPOSE_VERIFY:
- return KM_ERROR_OK;
- }
- return is_time_expired(param, current_time);
-}
+ private:
+ EVP_MD_CTX ctx_;
+};
-keymaster_error_t KeymasterEnforcement::MinTimeBetweenOpsPassed(const keymaster_key_param_t param,
- const km_id_t keyid,
- const time_t current_time) {
- uint32_t min_time_between = param.integer;
+/* static */
+bool KeymasterEnforcement::CreateKeyId(const keymaster_key_blob_t& key_blob, km_id_t* keyid) {
+ EvpMdCtx ctx;
- if (difftime(current_time, get_last_access_time(keyid)) < min_time_between) {
- return KM_ERROR_TOO_MANY_OPERATIONS;
+ uint8_t hash[EVP_MAX_MD_SIZE];
+ unsigned int hash_len;
+ if (EVP_DigestInit_ex(ctx.get(), EVP_sha256(), nullptr /* ENGINE */) &&
+ EVP_DigestUpdate(ctx.get(), key_blob.key_material, key_blob.key_material_size) &&
+ EVP_DigestFinal_ex(ctx.get(), hash, &hash_len)) {
+ assert(hash_len >= sizeof(*keyid));
+ memcpy(keyid, hash, sizeof(*keyid));
+ return true;
}
- return KM_ERROR_OK;
+
+ return false;
}
-keymaster_error_t KeymasterEnforcement::NotUsedSinceBoot(const km_id_t keyid) {
- if (get_last_access_time(keyid) > -1) {
- return KM_ERROR_TOO_MANY_OPERATIONS;
- }
- return KM_ERROR_OK;
+bool KeymasterEnforcement::MinTimeBetweenOpsPassed(uint32_t min_time_between, const km_id_t keyid) {
+ uint32_t last_access_time;
+ if (!access_time_map_.LastKeyAccessTime(keyid, &last_access_time))
+ return true;
+ return min_time_between <= static_cast<int64_t>(get_current_time()) - last_access_time;
}
-keymaster_error_t KeymasterEnforcement::UserAuthenticated(const keymaster_key_param_t param,
- const uid_t uid) {
- uint32_t valid_user_id = param.integer;
- uint32_t user_id_to_test = get_user_id_from_uid(uid);
+bool KeymasterEnforcement::MaxUsesPerBootNotExceeded(const km_id_t keyid, uint32_t max_uses) {
+ uint32_t key_access_count;
+ if (!access_count_map_.KeyAccessCount(keyid, &key_access_count))
+ return true;
+ return key_access_count < max_uses;
+}
- if (valid_user_id == user_id_to_test) {
- return KM_ERROR_OK;
- } else {
- return KM_ERROR_INVALID_USER_ID;
+bool KeymasterEnforcement::AuthTokenMatches(const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params,
+ const uint64_t user_secure_id,
+ const int auth_type_index, const int auth_timeout_index,
+ const keymaster_operation_handle_t op_handle,
+ bool is_begin_operation) const {
+ assert(auth_type_index < static_cast<int>(auth_set.size()));
+ assert(auth_timeout_index < static_cast<int>(auth_set.size()));
+
+ keymaster_blob_t auth_token_blob;
+ if (!operation_params.GetTagValue(TAG_AUTH_TOKEN, &auth_token_blob)) {
+ LOG_E("Authentication required, but auth token not provided", 0);
+ return false;
}
-}
-keymaster_error_t KeymasterEnforcement::AuthenticationIsFresh(const keymaster_key_param_t param,
- const time_t current_time) const {
- time_t last_auth_time = get_last_auth_time();
- time_t required_time = param.integer;
- if (difftime(current_time, last_auth_time) > required_time) {
- return KM_ERROR_OK;
- } else {
- return KM_ERROR_KEY_USER_NOT_AUTHENTICATED;
+ if (auth_token_blob.data_length != sizeof(hw_auth_token_t)) {
+ LOG_E("Bug: Auth token is the wrong size (%d expected, %d found)", sizeof(hw_auth_token_t),
+ auth_token_blob.data_length);
+ return false;
}
-}
-void KeymasterEnforcement::update_key_access_time(const km_id_t keyid) {
- accessTimeMap.update_key_access_time(keyid, get_current_time());
-}
+ hw_auth_token_t auth_token;
+ memcpy(&auth_token, auth_token_blob.data, sizeof(hw_auth_token_t));
+ if (auth_token.version != HW_AUTH_TOKEN_VERSION) {
+ LOG_E("Bug: Auth token is the version %d (or is not an auth token). Expected %d",
+ auth_token.version, HW_AUTH_TOKEN_VERSION);
+ return false;
+ }
-time_t KeymasterEnforcement::get_current_time() const {
- return time(NULL);
-}
+ if (!ValidateTokenSignature(auth_token)) {
+ LOG_E("Auth token signature invalid", 0);
+ return false;
+ }
-time_t KeymasterEnforcement::get_last_access_time(km_id_t keyid) {
- return accessTimeMap.last_key_access_time(keyid);
-}
+ if (auth_timeout_index == -1 && op_handle && op_handle != auth_token.challenge) {
+ LOG_E("Auth token has the challenge %llu, need %llu", auth_token.challenge, op_handle);
+ return false;
+ }
-uint32_t KeymasterEnforcement::get_user_id_from_uid(uid_t uid) {
- uint32_t userId = uid / MULTIUSER_APP_PER_USER_RANGE;
- return userId;
-}
+ if (user_secure_id != auth_token.user_id && user_secure_id != auth_token.authenticator_id) {
+ LOG_I("Auth token SIDs %llu and %llu do not match key SID %llu", auth_token.user_id,
+ auth_token.authenticator_id, user_secure_id);
+ return false;
+ }
-time_t KeymasterEnforcement::get_last_auth_time() const {
- return last_auth_time;
-}
+ if (auth_type_index < 0 || auth_type_index > static_cast<int>(auth_set.size())) {
+ LOG_E("Auth required but no auth type found", 0);
+ return false;
+ }
-void KeymasterEnforcement::UpdateUserAuthenticationTime() {
- last_auth_time = get_current_time();
-}
+ assert(auth_set[auth_type_index].tag == KM_TAG_USER_AUTH_TYPE);
+ if (auth_set[auth_type_index].tag != KM_TAG_USER_AUTH_TYPE)
+ return false;
-bool KeymasterEnforcement::supported_purpose(const keymaster_purpose_t purpose) {
- switch (purpose) {
- case KM_PURPOSE_ENCRYPT:
- case KM_PURPOSE_DECRYPT:
- case KM_PURPOSE_SIGN:
- case KM_PURPOSE_VERIFY:
- return true;
- break;
+ uint32_t key_auth_type_mask = auth_set[auth_type_index].integer;
+ uint32_t token_auth_type = ntoh(auth_token.authenticator_type);
+ if ((key_auth_type_mask & token_auth_type) == 0) {
+ LOG_E("Key requires match of auth type mask 0%uo, but token contained 0%uo",
+ key_auth_type_mask, token_auth_type);
+ return false;
}
- return false;
-}
-bool KeymasterEnforcement::supported_purposes(const AuthorizationSet& auth_set) {
- int purpose_index;
- keymaster_purpose_t test_purpose;
+ if (auth_timeout_index != -1 && is_begin_operation) {
+ assert(auth_set[auth_timeout_index].tag == KM_TAG_AUTH_TIMEOUT);
+ if (auth_set[auth_timeout_index].tag != KM_TAG_AUTH_TIMEOUT)
+ return false;
- purpose_index = auth_set.find(KM_TAG_PURPOSE);
- for (; purpose_index >= 0; purpose_index = auth_set.find(KM_TAG_PURPOSE, purpose_index)) {
- test_purpose = static_cast<keymaster_purpose_t>(auth_set[purpose_index].enumerated);
- if (!supported_purpose(test_purpose)) {
+ if (auth_token_timed_out(auth_token, auth_set[auth_timeout_index].integer)) {
+ LOG_E("Auth token has timed out", 0);
return false;
}
}
+ // Survived the whole gauntlet. We have authentage!
return true;
}
-keymaster_error_t KeymasterEnforcement::valid_purpose(const keymaster_purpose_t purpose,
- const AuthorizationSet& auth_set) {
- if (!supported_purpose(purpose) || !supported_purposes(auth_set)) {
- return KM_ERROR_UNSUPPORTED_PURPOSE;
- }
+bool KeymasterEnforcement::AccessTimeMap::LastKeyAccessTime(km_id_t keyid,
+ uint32_t* last_access_time) const {
+ for (auto& entry : last_access_list_)
+ if (entry.keyid == keyid) {
+ *last_access_time = entry.access_time;
+ return true;
+ }
+ return false;
+}
- keymaster_purpose_t test_purpose;
- for (int purpose_index = auth_set.find(KM_TAG_PURPOSE); purpose_index >= 0;
- purpose_index = auth_set.find(KM_TAG_PURPOSE, purpose_index)) {
- test_purpose = static_cast<keymaster_purpose_t>(auth_set[purpose_index].enumerated);
- if (test_purpose == purpose) {
- return KM_ERROR_OK;
+bool KeymasterEnforcement::AccessTimeMap::UpdateKeyAccessTime(km_id_t keyid, uint32_t current_time,
+ uint32_t timeout) {
+ List<AccessTime>::iterator iter;
+ for (iter = last_access_list_.begin(); iter != last_access_list_.end();) {
+ if (iter->keyid == keyid) {
+ iter->access_time = current_time;
+ return true;
}
+
+ // Expire entry if possible.
+ assert(current_time >= iter->access_time);
+ if (current_time - iter->access_time >= iter->timeout)
+ iter = last_access_list_.erase(iter);
+ else
+ ++iter;
}
- return KM_ERROR_INCOMPATIBLE_PURPOSE;
-}
+ if (last_access_list_.size() >= max_size_)
+ return false;
-KeymasterEnforcement::AccessTimeMap::AccessTimeMap() {
+ AccessTime new_entry;
+ new_entry.keyid = keyid;
+ new_entry.access_time = current_time;
+ new_entry.timeout = timeout;
+ last_access_list_.push_front(new_entry);
+ return true;
}
-List<access_time_struct>::iterator KeymasterEnforcement::AccessTimeMap::find(uint32_t key_index) {
- List<access_time_struct>::iterator posn;
-
- posn = last_access_list.begin();
- for (; (*posn).keyid != key_index && posn != last_access_list.end(); posn++) {
- }
- return posn;
+bool KeymasterEnforcement::AccessCountMap::KeyAccessCount(km_id_t keyid, uint32_t* count) const {
+ for (auto& entry : access_count_list_)
+ if (entry.keyid == keyid) {
+ *count = entry.access_count;
+ return true;
+ }
+ return false;
}
-void KeymasterEnforcement::AccessTimeMap::update_key_access_time(uint32_t key_index,
- time_t current_time) {
- List<access_time_struct>::iterator posn;
-
- posn = find(key_index);
- if (posn != last_access_list.end()) {
- (*posn).access_time = current_time;
- } else {
- access_time_struct ac;
- ac.keyid = key_index;
- ac.access_time = current_time;
- last_access_list.push_front(ac);
- }
+template <typename T> T max_value(T) {
+ return std::numeric_limits<T>::max();
}
-time_t KeymasterEnforcement::AccessTimeMap::last_key_access_time(uint32_t key_index) {
- List<access_time_struct>::iterator posn;
+bool KeymasterEnforcement::AccessCountMap::IncrementKeyAccessCount(km_id_t keyid) {
+ for (auto& entry : access_count_list_)
+ if (entry.keyid == keyid) {
+ if (entry.access_count < max_value(entry.access_count))
+ ++entry.access_count;
+ return true;
+ }
- posn = find(key_index);
- if (posn != last_access_list.end()) {
- return (*posn).access_time;
- }
- return -1;
-}
+ if (access_count_list_.size() >= max_size_)
+ return false;
+ AccessCount new_entry;
+ new_entry.keyid = keyid;
+ new_entry.access_count = 1;
+ access_count_list_.push_front(new_entry);
+ return true;
+}
}; /* namespace keymaster */
diff --git a/keymaster_enforcement.h b/keymaster_enforcement.h
deleted file mode 100644
index 0f70ea9..0000000
--- a/keymaster_enforcement.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2014 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 ANDROID_LIBRARY_KEYMASTER_ENFORCEMENT_H
-#define ANDROID_LIBRARY_KEYMASTER_ENFORCEMENT_H
-
-#include <stdio.h>
-
-#include <utils/List.h>
-
-#include <keymaster/authorization_set.h>
-
-using namespace android;
-
-typedef uint32_t km_id_t;
-
-namespace keymaster {
-
-struct access_time_struct {
- uint32_t keyid;
- time_t access_time;
-};
-
-class KeymasterEnforcement {
-
- public:
- KeymasterEnforcement();
-
- ~KeymasterEnforcement();
-
- /**
- * Iterates through the authorization set and returns the corresponding keymaster error. Will
- * return KM_ERROR_OK if all criteria is met for the given purpose in the authorization
- * set. Used for encrypt, decrypt sign, and verify.
- */
- keymaster_error_t AuthorizeOperation(const keymaster_purpose_t purpose, const km_id_t keyid,
- const AuthorizationSet& auth_set, const uid_t uid);
-
- /**
- * This is maintained in system/core/include/cutiles/multiuser.h but copied here so that this
- * code can be reused without access to the core Android libs.
- */
- static const uint32_t MULTIUSER_APP_PER_USER_RANGE = 100000;
-
- private:
- /*
- * Handles the KM_TAG_ACTIVE_DATETIME tag. Returns KM_ERROR_OK if currentTime is greater than
- * the the time value associated with param.
- */
- keymaster_error_t Active(const keymaster_key_param_t param, const time_t current_time);
-
- /*
- * Handles the KM_TAG_USAGE_EXPIRE_DATETIME tag. Returns KM_ERROR_OK if currentTime is less
- * than the time value associated with param and if purpose is KM_PURPOSE_VERIFY. If purpose is
- * not KM_PURPOSE_VERIFY will return KM_ERROR_OK.
- */
- keymaster_error_t UsageNotExpired(const keymaster_key_param_t param, const time_t current_time,
- const keymaster_purpose_t purpose);
-
- /*
- * Handles the KM_TAG_ORIGINATION_EXPIRE_TIME tag. Returns KM_ERROR_OK if currentTime is less
- * than the time value associated with param and if purpose is KM_PURPOSE_SIGN. If purpose is
- * not KM_PURPOSE_SIGN will return KM_ERROR_OK.
- */
- keymaster_error_t OriginationNotExpired(const keymaster_key_param_t param,
- const time_t current_time,
- const keymaster_purpose_t purpose);
-
- /*
- * Handles the KM_TAG_MIN_SECONDS_BETWEEN_OPS tag. Returns KM_ERROR_OK if the difference
- * between currentTime and the last accessed time for the keyid is less than the time value
- * associated with param.
- */
- keymaster_error_t MinTimeBetweenOpsPassed(const keymaster_key_param_t param,
- const km_id_t keyid, const time_t current_time);
-
- /*
- * Handles the KM_TAG_SINGLE_USE_PER_BOOT tag. Returns KM_ERROR_OK if the keyid's last accessed
- * time is -1 (has not been accessed).
- */
- keymaster_error_t NotUsedSinceBoot(const km_id_t keyid);
-
- /*
- * Handles the KM_TAG_USER_ID tag. Returns KM_ERROR_OK if the integer value of the parameter is
- * equal to the appId derived from the uid.
- */
- keymaster_error_t UserAuthenticated(const keymaster_key_param_t param, const uid_t uid);
-
- /*
- * Handles KM_TAG_AUTH_TIMEOUT tags. Returns KM_ERROR_OK if the last time the user
- * authenticated is within the required freshness.
- */
- keymaster_error_t AuthenticationIsFresh(const keymaster_key_param_t param,
- const time_t current_time) const;
-
- /*
- * Updates the most recent user authentication time to the current time.
- */
- void UpdateUserAuthenticationTime();
-
- /*
- * Class to abstract the mechanism used to keep track of access times.
- */
- class AccessTimeMap {
- public:
- AccessTimeMap();
-
- /* Returns the last time the key was accessed. */
- time_t last_key_access_time(uint32_t index);
-
- /* Updates the last key access time with the currentTime parameter. */
- void update_key_access_time(uint32_t index, time_t current_time);
-
- private:
- /**
- * Internal datastructure that maps keyid to access time. Can be
- * replaced with the cutil hashmap, linked list, etc.
- */
- List<access_time_struct> last_access_list;
-
- /* Returns an iterator to the node with the keyid or end if not found. */
- List<access_time_struct>::iterator find(uint32_t keyid);
- };
-
- /*
- * Tests if the purpose is a valid member of keymaster_purpose_t and if the purpose is among
- * those listed in the AuthorizationSet and returns KM_ERROR_OK if so and an appropriate error
- * otherwise.
- */
- keymaster_error_t valid_purpose(const keymaster_purpose_t purpose,
- const AuthorizationSet& auth_set);
-
- /*
- * Tests that all of the purposes in the authorization set are valid. Returns KM_ERROR_OK if so
- * and KM_ERROR_UNSUPPORTED_PURPOSE otherwise.
- */
- bool supported_purposes(const AuthorizationSet& auth_set);
-
- /*
- * Returns true if the purpose is among supported purposes and false otherwise.
- */
- bool supported_purpose(const keymaster_purpose_t purpose);
-
- /*
- * Abstraction that currently just returns time(NULL). TODO: time() is a no-op in trusty. Still
- * need to handle this.
- */
- time_t get_current_time() const;
-
- /*
- * Updates the last time that the key was accessed to the current time.
- */
- void update_key_access_time(const km_id_t keyid);
-
- /*
- * Returns the last time that the key was accessed.
- */
- time_t get_last_access_time(const km_id_t keyid);
-
- /*
- * Generates the userId from the uid using the formula
- * userId = uid / MULTIUSER_APP_PER_USER_RAGE.
- */
- static uint32_t get_user_id_from_uid(const uid_t uid);
-
- /* Returns the last time that the user authenticated. */
- time_t get_last_auth_time() const;
-
- /*
- * Returns KM_ERROR_KEY_EXPIRED if the difference between the current time and the parameters's
- * date_time field is positive.
- */
- keymaster_error_t is_time_expired(const keymaster_key_param_t param, const time_t current_time);
-
- /* Hashmap of last access times. */
- AccessTimeMap accessTimeMap;
-
- /* The time of the most recent user authentication. */
- time_t last_auth_time;
-};
-}; /* namespace keymaster */
-
-#endif // ANDROID_LIBRARY_KEYMASTER_ENFORCEMENT_H
diff --git a/keymaster_enforcement_test.cpp b/keymaster_enforcement_test.cpp
index e729ef6..b43bcc5 100644
--- a/keymaster_enforcement_test.cpp
+++ b/keymaster_enforcement_test.cpp
@@ -14,19 +14,61 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
-
#include <errno.h>
-#include <keymaster/authorization_set.h>
-#include <keymaster/android_keymaster.h>
#include <stdio.h>
#include <time.h>
-#include "keymaster_enforcement.h"
+#include <keymaster/android_keymaster.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/keymaster_enforcement.h>
+
+#include "android_keymaster_test_utils.h"
namespace keymaster {
namespace test {
+class TestKeymasterEnforcement : public KeymasterEnforcement {
+ public:
+ TestKeymasterEnforcement()
+ : KeymasterEnforcement(3, 3), current_time_(10000), report_token_valid_(true) {}
+
+ keymaster_error_t AuthorizeOperation(const keymaster_purpose_t purpose, const km_id_t keyid,
+ const AuthorizationSet& auth_set) {
+ AuthorizationSet empty_set;
+ return KeymasterEnforcement::AuthorizeOperation(
+ purpose, keyid, auth_set, empty_set, 0 /* op_handle */, false /* is_begin_operation */);
+ }
+ using KeymasterEnforcement::AuthorizeOperation;
+
+ uint32_t get_current_time() const override { return current_time_; }
+ bool activation_date_valid(uint64_t activation_date) const override {
+ // Convert java date to time_t, non-portably.
+ time_t activation_time = activation_date / 1000;
+ return difftime(time(NULL), activation_time) >= 0;
+ }
+ bool expiration_date_passed(uint64_t expiration_date) const override {
+ // Convert jave date to time_t, non-portably.
+ time_t expiration_time = expiration_date / 1000;
+ return difftime(time(NULL), expiration_time) > 0;
+ }
+ bool auth_token_timed_out(const hw_auth_token_t& token, uint32_t timeout) const {
+ return current_time_ > ntoh(token.timestamp) + timeout;
+ }
+ bool ValidateTokenSignature(const hw_auth_token_t&) const override {
+ return report_token_valid_;
+ }
+
+ void tick(unsigned seconds = 1) { current_time_ += seconds; }
+ uint32_t current_time() { return current_time_; }
+ void set_report_token_valid(bool report_token_valid) {
+ report_token_valid_ = report_token_valid;
+ }
+
+ private:
+ uint32_t current_time_;
+ bool report_token_valid_;
+};
+
class KeymasterBaseTest : public ::testing::Test {
protected:
KeymasterBaseTest() {
@@ -35,331 +77,685 @@ class KeymasterBaseTest : public ::testing::Test {
time_t t = time(NULL);
future_tm = localtime(&t);
future_tm->tm_year += 1;
- future_time = mktime(future_tm);
+ future_time = static_cast<uint64_t>(mktime(future_tm)) * 1000;
sign_param = Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN);
}
virtual ~KeymasterBaseTest() {}
+ TestKeymasterEnforcement kmen;
+
tm past_tm;
tm* future_tm;
- time_t past_time;
- time_t future_time;
+ uint64_t past_time;
+ uint64_t future_time;
static const km_id_t key_id = 0xa;
static const uid_t uid = 0xf;
keymaster_key_param_t sign_param;
- keymaster_blob_t def_app_id;
- size_t def_app_id_size;
-
- static const uint32_t valid_user_id = 25;
- static const uint32_t invalid_user_id1 = 37;
- static const uint32_t invalid_user_id2 = 50;
- static const uint32_t appId1 = 51;
- static const uint32_t appId2 = 52;
-
- static const uint32_t validuid1 =
- valid_user_id * KeymasterEnforcement::MULTIUSER_APP_PER_USER_RANGE +
- (appId1 % KeymasterEnforcement::MULTIUSER_APP_PER_USER_RANGE);
- static const uint32_t validuid2 =
- valid_user_id * KeymasterEnforcement::MULTIUSER_APP_PER_USER_RANGE +
- (appId1 % KeymasterEnforcement::MULTIUSER_APP_PER_USER_RANGE);
-
- static const uint32_t invaliduid1 =
- invalid_user_id1 * KeymasterEnforcement::MULTIUSER_APP_PER_USER_RANGE +
- (appId1 % KeymasterEnforcement::MULTIUSER_APP_PER_USER_RANGE);
- static const uint32_t invaliduid2 =
- invalid_user_id1 * KeymasterEnforcement::MULTIUSER_APP_PER_USER_RANGE +
- (appId2 % KeymasterEnforcement::MULTIUSER_APP_PER_USER_RANGE);
- static const uint32_t invaliduid3 =
- invalid_user_id2 * KeymasterEnforcement::MULTIUSER_APP_PER_USER_RANGE +
- (appId1 % KeymasterEnforcement::MULTIUSER_APP_PER_USER_RANGE);
- static const uint32_t invaliduid4 =
- invalid_user_id2 * KeymasterEnforcement::MULTIUSER_APP_PER_USER_RANGE +
- (appId2 % KeymasterEnforcement::MULTIUSER_APP_PER_USER_RANGE);
};
-TEST_F(KeymasterBaseTest, TEST_VALID_KEY_PERIOD_NO_TAGS) {
+TEST_F(KeymasterBaseTest, TestValidKeyPeriodNoTags) {
keymaster_key_param_t params[] = {
sign_param,
};
- AuthorizationSet single_auth_set(params, 1);
- KeymasterEnforcement kmen;
+ AuthorizationSet single_auth_set(params, array_length(params));
- keymaster_error_t kmer = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, single_auth_set, uid);
+ keymaster_error_t kmer = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, single_auth_set);
ASSERT_EQ(KM_ERROR_OK, kmer);
}
-TEST_F(KeymasterBaseTest, TEST_INVALID_ACTIVE_TIME) {
+TEST_F(KeymasterBaseTest, TestInvalidActiveTime) {
keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_NO_AUTH_REQUIRED), Authorization(TAG_ACTIVE_DATETIME, future_time),
+ Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_NO_AUTH_REQUIRED),
+ Authorization(TAG_ACTIVE_DATETIME, future_time),
};
- KeymasterEnforcement kmen;
- AuthorizationSet auth_set(params, 4);
+ AuthorizationSet auth_set(params, array_length(params));
keymaster_error_t kmer_invalid_time =
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, uid);
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
ASSERT_EQ(KM_ERROR_KEY_NOT_YET_VALID, kmer_invalid_time);
}
-TEST_F(KeymasterBaseTest, TEST_VALID_ACTIVE_TIME) {
+TEST_F(KeymasterBaseTest, TestValidActiveTime) {
keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_ACTIVE_DATETIME, past_time),
+ Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ACTIVE_DATETIME, past_time),
};
- KeymasterEnforcement kmen;
- AuthorizationSet auth_set(params, 3);
+ AuthorizationSet auth_set(params, array_length(params));
- keymaster_error_t kmer_valid_time =
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, uid);
+ keymaster_error_t kmer_valid_time = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
ASSERT_EQ(KM_ERROR_OK, kmer_valid_time);
}
-TEST_F(KeymasterBaseTest, TEST_INVALID_ORIGINATION_EXPIRE_TIME) {
+TEST_F(KeymasterBaseTest, TestInvalidOriginationExpireTime) {
keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_ACTIVE_DATETIME, past_time),
+ Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, past_time),
};
- KeymasterEnforcement kmen;
- AuthorizationSet auth_set(params, 4);
+ AuthorizationSet auth_set(params, array_length(params));
keymaster_error_t kmer_invalid_origination =
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, uid);
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
ASSERT_EQ(KM_ERROR_KEY_EXPIRED, kmer_invalid_origination);
}
-TEST_F(KeymasterBaseTest, TEST_VALID_ORIGINATION_EXPIRE_TIME) {
+TEST_F(KeymasterBaseTest, TestInvalidOriginationExpireTimeOnUsgae) {
keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_ACTIVE_DATETIME, past_time),
+ Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+ Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, past_time),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ keymaster_error_t kmer_invalid_origination =
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set);
+ ASSERT_EQ(KM_ERROR_OK, kmer_invalid_origination);
+}
+
+TEST_F(KeymasterBaseTest, TestValidOriginationExpireTime) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, future_time),
};
- KeymasterEnforcement kmen;
- AuthorizationSet auth_set(params, 4);
+ AuthorizationSet auth_set(params, array_length(params));
keymaster_error_t kmer_valid_origination =
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, uid);
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
ASSERT_EQ(KM_ERROR_OK, kmer_valid_origination);
}
-TEST_F(KeymasterBaseTest, TEST_INVALID_USAGE_EXPIRE_TIME) {
+TEST_F(KeymasterBaseTest, TestInvalidUsageExpireTime) {
keymaster_key_param_t params[] = {
Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_ACTIVE_DATETIME, past_time),
- Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
Authorization(TAG_USAGE_EXPIRE_DATETIME, past_time),
};
- KeymasterEnforcement kmen;
- AuthorizationSet auth_set(params, 5);
+ AuthorizationSet auth_set(params, array_length(params));
keymaster_error_t kmer_invalid_origination =
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, uid);
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set);
ASSERT_EQ(KM_ERROR_KEY_EXPIRED, kmer_invalid_origination);
}
-TEST_F(KeymasterBaseTest, TEST_VALID_USAGE_EXPIRE_TIME) {
+TEST_F(KeymasterBaseTest, TestInvalidUsageExpireTimeOnOrigination) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+ Authorization(TAG_USAGE_EXPIRE_DATETIME, past_time),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ keymaster_error_t kmer_invalid_origination =
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
+ ASSERT_EQ(KM_ERROR_OK, kmer_invalid_origination);
+}
+
+TEST_F(KeymasterBaseTest, TestValidUsageExpireTime) {
keymaster_key_param_t params[] = {
Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_ACTIVE_DATETIME, past_time),
Authorization(TAG_USAGE_EXPIRE_DATETIME, future_time),
};
- KeymasterEnforcement kmen;
- AuthorizationSet auth_set(params, 4);
+ AuthorizationSet auth_set(params, array_length(params));
keymaster_error_t kmer_valid_usage =
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, uid);
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set);
ASSERT_EQ(KM_ERROR_OK, kmer_valid_usage);
}
-TEST_F(KeymasterBaseTest, TEST_VALID_SINGLE_USE_ACCESSES) {
+TEST_F(KeymasterBaseTest, TestValidSingleUseAccesses) {
keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_ACTIVE_DATETIME, past_time),
+ Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
};
- KeymasterEnforcement kmen;
- AuthorizationSet auth_set(params, 3);
+ AuthorizationSet auth_set(params, array_length(params));
- keymaster_error_t kmer1 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, uid);
- keymaster_error_t kmer2 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, uid);
+ keymaster_error_t kmer1 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
+ keymaster_error_t kmer2 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
ASSERT_EQ(KM_ERROR_OK, kmer1);
ASSERT_EQ(KM_ERROR_OK, kmer2);
}
-TEST_F(KeymasterBaseTest, TEST_INVALID_SINGLE_USE_ACCESSES) {
+TEST_F(KeymasterBaseTest, TestInvalidMaxOps) {
keymaster_key_param_t params[] = {
Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_ACTIVE_DATETIME, past_time), Authorization(TAG_MAX_USES_PER_BOOT, 1),
+ Authorization(TAG_MAX_USES_PER_BOOT, 4),
};
- KeymasterEnforcement kmen;
- AuthorizationSet auth_set(params, 4);
+ AuthorizationSet auth_set(params, array_length(params));
- keymaster_error_t kmer1 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, uid);
- keymaster_error_t kmer2 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, uid);
+ ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+ ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+ ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+ ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+ ASSERT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+}
- ASSERT_EQ(KM_ERROR_OK, kmer1);
- ASSERT_EQ(KM_ERROR_TOO_MANY_OPERATIONS, kmer2);
+TEST_F(KeymasterBaseTest, TestOverFlowMaxOpsTable) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_MAX_USES_PER_BOOT, 2),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set));
+
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 2 /* key_id */, auth_set));
+
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 3 /* key_id */, auth_set));
+
+ // Key 4 should fail, because table is full.
+ EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 4 /* key_id */, auth_set));
+
+ // Key 1 still works, because it's already in the table and hasn't reached max.
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set));
+
+ // Key 1 no longer works, because it's reached max.
+ EXPECT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set));
+
+ // Key 4 should fail, because table is (still and forever) full.
+ EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 4 /* key_id */, auth_set));
}
-TEST_F(KeymasterBaseTest, TEST_INVALID_TIME_BETWEEN_OPS) {
+TEST_F(KeymasterBaseTest, TestInvalidTimeBetweenOps) {
keymaster_key_param_t params[] = {
- Authorization(TAG_ALL_USERS), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_ACTIVE_DATETIME, past_time),
- Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 10),
+ Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 10),
};
- KeymasterEnforcement kmen;
- AuthorizationSet auth_set(params, 5);
+ AuthorizationSet auth_set(params, array_length(params));
- keymaster_error_t kmer1 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, uid);
- keymaster_error_t kmer2 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, uid);
+ keymaster_error_t kmer1 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
+ keymaster_error_t kmer2 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
ASSERT_EQ(KM_ERROR_OK, kmer1);
- sleep(2);
- ASSERT_EQ(KM_ERROR_TOO_MANY_OPERATIONS, kmer2);
+ kmen.tick(2);
+ ASSERT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, kmer2);
}
-TEST_F(KeymasterBaseTest, TEST_VALID_TIME_BETWEEN_OPS) {
+TEST_F(KeymasterBaseTest, TestValidTimeBetweenOps) {
keymaster_key_param_t params[] = {
Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
- Authorization(TAG_USAGE_EXPIRE_DATETIME, future_time),
- Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, future_time),
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_ACTIVE_DATETIME, past_time),
Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 2),
};
- KeymasterEnforcement kmen;
- AuthorizationSet auth_set(params, 7);
-
- keymaster_error_t kmer1 = kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, uid);
- sleep(3);
- keymaster_error_t kmer2 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, uid);
+ AuthorizationSet auth_set(params, array_length(params));
- ASSERT_EQ(KM_ERROR_OK, kmer1);
- ASSERT_EQ(KM_ERROR_OK, kmer2);
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
+ kmen.tick();
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+ kmen.tick();
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
}
-TEST_F(KeymasterBaseTest, TEST_USER_ID) {
+TEST_F(KeymasterBaseTest, TestOptTimeoutTableOverflow) {
keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_USER_ID, valid_user_id),
+ Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 4),
+ Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
};
- KeymasterEnforcement kmen;
- AuthorizationSet auth_set(params, 2);
+ AuthorizationSet auth_set(params, array_length(params));
+
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+
+ kmen.tick();
+
+ // Key 1 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
+
+ kmen.tick();
+
+ // Key 1 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+ // Key 2 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
+
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
+
+ kmen.tick();
+
+ // Key 1 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+ // Key 2 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
+ // Key 3 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
+ // Key 4 fails because the table is full
+ EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set));
+
+ kmen.tick();
+
+ // Key 4 succeeds because key 1 expired.
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set));
+
+ // Key 1 fails because the table is full... and key 1 is no longer in it.
+ EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+ // Key 2 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
+ // Key 3 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
+
+ kmen.tick();
+
+ // Key 1 succeeds because key 2 expired
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+ // Key 2 fails because the table is full... and key 2 is no longer in it.
+ EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
+ // Key 3 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
+ // Key 4 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set));
+
+ kmen.tick(4);
+
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidPurpose) {
+ keymaster_purpose_t invalidPurpose1 = static_cast<keymaster_purpose_t>(-1);
+ keymaster_purpose_t invalidPurpose2 = static_cast<keymaster_purpose_t>(4);
- keymaster_error_t valid_kmer1 =
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, validuid1);
- keymaster_error_t valid_kmer2 =
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, validuid2);
+ AuthorizationSet auth_set(
+ AuthorizationSetBuilder().Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY));
- keymaster_error_t invalid_kmer1 =
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, invaliduid1);
- keymaster_error_t invalid_kmer2 =
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, invaliduid2);
- keymaster_error_t invalid_kmer3 =
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, invaliduid3);
- keymaster_error_t invalid_kmer4 =
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, invaliduid4);
+ EXPECT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE,
+ kmen.AuthorizeOperation(invalidPurpose1, key_id, auth_set));
+ EXPECT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE,
+ kmen.AuthorizeOperation(invalidPurpose2, key_id, auth_set));
+}
- ASSERT_EQ(KM_ERROR_OK, valid_kmer1);
- ASSERT_EQ(KM_ERROR_OK, valid_kmer2);
+TEST_F(KeymasterBaseTest, TestIncompatiblePurposeSymmetricKey) {
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
- ASSERT_EQ(KM_ERROR_INVALID_USER_ID, invalid_kmer1);
- ASSERT_EQ(KM_ERROR_INVALID_USER_ID, invalid_kmer2);
- ASSERT_EQ(KM_ERROR_INVALID_USER_ID, invalid_kmer3);
- ASSERT_EQ(KM_ERROR_INVALID_USER_ID, invalid_kmer4);
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
+
+ EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE,
+ kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, auth_set));
+ EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE,
+ kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, auth_set));
}
-TEST_F(KeymasterBaseTest, TEST_INVALID_PURPOSE) {
- keymaster_purpose_t invalidPurpose1 = static_cast<keymaster_purpose_t>(-1);
- keymaster_purpose_t invalidPurpose2 = static_cast<keymaster_purpose_t>(4);
+TEST_F(KeymasterBaseTest, TestIncompatiblePurposeAssymmetricKey) {
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
- keymaster_key_param_t params1[] = {
- Authorization(TAG_PURPOSE, invalidPurpose1), Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_ACTIVE_DATETIME, past_time),
- };
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
- keymaster_key_param_t params2[] = {
- Authorization(TAG_PURPOSE, invalidPurpose2), Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_ACTIVE_DATETIME, past_time),
- };
+ // This one is allowed because it's a pubkey op.
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, auth_set));
+ EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE,
+ kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, auth_set));
+}
- KeymasterEnforcement kmen;
- AuthorizationSet auth_set1(params1, 3);
- AuthorizationSet auth_set2(params2, 3);
+TEST_F(KeymasterBaseTest, TestInvalidCallerNonce) {
+ AuthorizationSet no_caller_nonce(AuthorizationSetBuilder()
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA));
+ AuthorizationSet caller_nonce(AuthorizationSetBuilder()
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+ .Authorization(TAG_CALLER_NONCE));
+ AuthorizationSet begin_params(AuthorizationSetBuilder().Authorization(TAG_NONCE, "foo", 3));
+
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, caller_nonce, begin_params,
+ 0 /* challenge */, false /* is_begin_operation */));
+ EXPECT_EQ(KM_ERROR_CALLER_NONCE_PROHIBITED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, no_caller_nonce, begin_params,
+ 0 /* challenge */, false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestBootloaderOnly) {
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+ .Authorization(TAG_BOOTLOADER_ONLY));
+ EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+}
- keymaster_error_t kmer1 = kmen.AuthorizeOperation(invalidPurpose1, key_id, auth_set1, uid);
- keymaster_error_t kmer2 = kmen.AuthorizeOperation(invalidPurpose2, key_id, auth_set2, uid);
- keymaster_error_t kmer3 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set2, uid);
+TEST_F(KeymasterBaseTest, TestInvalidTag) {
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_INVALID)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, kmer1);
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, kmer2);
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, kmer3);
+ EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
}
-TEST_F(KeymasterBaseTest, TEST_INCOMPATIBLE_PURPOSE) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_ACTIVE_DATETIME, past_time), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
- };
- KeymasterEnforcement kmen;
- AuthorizationSet auth_set(params, 4);
+TEST_F(KeymasterBaseTest, TestAuthPerOpSuccess) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = 0;
+
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+ op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+ false /* is_begin_operation */));
+}
- keymaster_error_t kmer_invalid1 =
- kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, auth_set, uid);
- keymaster_error_t kmer_invalid2 =
- kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, auth_set, uid);
+TEST_F(KeymasterBaseTest, TestAuthPerOpInvalidTokenSignature) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = 0;
+
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+ op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+ kmen.set_report_token_valid(false);
+ EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+ false /* is_begin_operation */));
+}
- keymaster_error_t kmer_valid1 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, uid);
- keymaster_error_t kmer_valid2 =
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, uid);
+TEST_F(KeymasterBaseTest, TestAuthPerOpWrongChallenge) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = 0;
+
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+ op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+ EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+ token.challenge + 1 /* doesn't match token */,
+ false /* is_begin_operation */));
+}
- ASSERT_EQ(KM_ERROR_OK, kmer_valid1);
- ASSERT_EQ(KM_ERROR_OK, kmer_valid2);
- ASSERT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE, kmer_invalid1);
- ASSERT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE, kmer_invalid2);
+TEST_F(KeymasterBaseTest, TestAuthPerOpNoAuthType) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = 0;
+
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+ op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+ EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+ false /* is_begin_operation */));
}
-TEST_F(KeymasterBaseTest, TEST_INVALID_TAG_PAIRS) {
- const uint8_t* app_id = reinterpret_cast<const uint8_t*>("com.app");
- const size_t app_size = 7;
- keymaster_key_param_t params1[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_ACTIVE_DATETIME, past_time), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
- // Can't have "all users" and a specific user.
- Authorization(TAG_ALL_USERS), Authorization(TAG_USER_ID, valid_user_id),
- };
+TEST_F(KeymasterBaseTest, TestAuthPerOpWrongAuthType) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = 0;
+
+ AuthorizationSet auth_set(
+ AuthorizationSetBuilder()
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_FINGERPRINT /* doesn't match token */)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+ op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+ EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+ false /* is_begin_operation */));
+}
- keymaster_key_param_t params2[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_ACTIVE_DATETIME, past_time), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
- // Can't have "all applications" and a specific app ID.
- Authorization(TAG_ALL_APPLICATIONS), Authorization(TAG_APPLICATION_ID, app_id, app_size),
- };
+TEST_F(KeymasterBaseTest, TestAuthPerOpWrongSid) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = 0;
+
+ AuthorizationSet auth_set(
+ AuthorizationSetBuilder()
+ .Authorization(TAG_USER_SECURE_ID, token.user_id + 1 /* doesn't match token */)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+ op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+ EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+ false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthPerOpSuccessAlternateSid) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 10;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = 0;
+
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_USER_SECURE_ID, token.authenticator_id)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+ op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+ false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthPerOpMissingToken) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = 0;
+
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+
+ // During begin we can skip the auth token
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+ token.challenge, true /* is_begin_operation */));
+ // Afterwards we must have authentication
+ EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+ false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthAndNoAuth) {
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_USER_SECURE_ID, 1)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestTimedAuthSuccess) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = hton(kmen.current_time());
+
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_AUTH_TIMEOUT, 1)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+ op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+ 0 /* irrelevant */, false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestTimedAuthTimedOut) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = hton(static_cast<uint64_t>(kmen.current_time()));
+
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_AUTH_TIMEOUT, 1)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+ op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+ 0 /* irrelevant */, false /* is_begin_operation */));
+
+ kmen.tick(1);
+
+ // token still good
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+ 0 /* irrelevant */, false /* is_begin_operation */));
+
+ kmen.tick(1);
+
+ // token expired, not allowed during begin.
+ EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+ 0 /* irrelevant */, true /* is_begin_operation */));
+
+ // token expired, afterwards it's okay.
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+ 0 /* irrelevant */, false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestTimedAuthMissingToken) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = hton(static_cast<uint64_t>(kmen.current_time()));
+
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_AUTH_TIMEOUT, 1)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+
+ // Unlike auth-per-op, must have the auth token during begin.
+ EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+ true /* is_begin_operation */));
+
+ // And later (though begin would fail, so there wouldn't be a later).
+ EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+ false /* is_begin_operation */));
+}
- KeymasterEnforcement kmen;
- AuthorizationSet auth_set1(params1, array_length(params1));
- AuthorizationSet auth_set2(params2, array_length(params2));
+TEST_F(KeymasterBaseTest, TestCreateKeyId) {
+ keymaster_key_blob_t blob = {reinterpret_cast<const uint8_t*>("foobar"), 6};
- EXPECT_EQ(KM_ERROR_INVALID_TAG,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set1, validuid1));
- EXPECT_EQ(KM_ERROR_INVALID_TAG,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set2, validuid1));
+ km_id_t key_id = 0;
+ EXPECT_TRUE(KeymasterEnforcement::CreateKeyId(blob, &key_id));
+ EXPECT_NE(0U, key_id);
}
}; /* namespace test */