summaryrefslogtreecommitdiffstats
path: root/keymaster_enforcement.cpp
diff options
context:
space:
mode:
authorShawn Willden <swillden@google.com>2015-06-25 06:26:05 -0700
committerShawn Willden <swillden@google.com>2015-06-26 08:37:01 -0700
commitada4850659d484dd5ece26dde73072bef16c1517 (patch)
treea1174a1b2d933a3466b70cb04dd9ecc7de80b06c /keymaster_enforcement.cpp
parentbf9fa99611e64aa797c10d5458624ed93cc4f50b (diff)
downloadandroid_system_keymaster-ada4850659d484dd5ece26dde73072bef16c1517.tar.gz
android_system_keymaster-ada4850659d484dd5ece26dde73072bef16c1517.tar.bz2
android_system_keymaster-ada4850659d484dd5ece26dde73072bef16c1517.zip
Add authorization enforcement to AndroidKeymaster.
Note: Moving List.h into system/keymaster is unfortunate, but required to allow Trusty to use it. b/22088154 tracks cleaning this up. Bug: 19511945 Change-Id: Ia1dfe5fda5ea78935611b0a7656b323770edcbae
Diffstat (limited to 'keymaster_enforcement.cpp')
-rw-r--r--keymaster_enforcement.cpp116
1 files changed, 94 insertions, 22 deletions
diff --git a/keymaster_enforcement.cpp b/keymaster_enforcement.cpp
index 8273cf5..2dc0d01 100644
--- a/keymaster_enforcement.cpp
+++ b/keymaster_enforcement.cpp
@@ -17,20 +17,64 @@
#include <keymaster/keymaster_enforcement.h>
#include <assert.h>
+#include <limits.h>
#include <string.h>
-#include <limits>
-
#include <openssl/evp.h>
#include <hardware/hw_auth_token.h>
#include <keymaster/android_keymaster_utils.h>
#include <keymaster/logger.h>
+#include "List.h"
+
using android::List;
namespace keymaster {
+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_;
+};
+
bool is_public_key_algorithm(const AuthorizationSet& auth_set) {
keymaster_algorithm_t algorithm;
return auth_set.GetTagValue(TAG_ALGORITHM, &algorithm) &&
@@ -65,6 +109,16 @@ inline bool is_usage_purpose(keymaster_purpose_t purpose) {
return purpose == KM_PURPOSE_DECRYPT || purpose == KM_PURPOSE_VERIFY;
}
+KeymasterEnforcement::KeymasterEnforcement(uint32_t max_access_time_map_size,
+ uint32_t max_access_count_map_size)
+ : access_time_map_(new (std::nothrow) AccessTimeMap(max_access_time_map_size)),
+ access_count_map_(new (std::nothrow) AccessCountMap(max_access_count_map_size)) {}
+
+KeymasterEnforcement::~KeymasterEnforcement() {
+ delete access_time_map_;
+ delete access_count_map_;
+}
+
keymaster_error_t KeymasterEnforcement::AuthorizeOperation(const keymaster_purpose_t purpose,
const km_id_t keyid,
const AuthorizationSet& auth_set,
@@ -273,15 +327,28 @@ keymaster_error_t KeymasterEnforcement::AuthorizeBegin(const keymaster_purpose_t
operation_params.find(KM_TAG_NONCE) != -1)
return KM_ERROR_CALLER_NONCE_PROHIBITED;
- 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;
+ if (min_ops_timeout != UINT32_MAX) {
+ if (!access_time_map_) {
+ LOG_S("Rate-limited keys table not allocated. Rate-limited keys disabled", 0);
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+
+ if (!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;
+ }
}
- 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;
+ if (update_access_count) {
+ if (!access_count_map_) {
+ LOG_S("Usage-count limited keys tabel not allocated. Count-limited keys disabled", 0);
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+
+ if (!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;
@@ -316,15 +383,21 @@ bool KeymasterEnforcement::CreateKeyId(const keymaster_key_blob_t& key_blob, km_
}
bool KeymasterEnforcement::MinTimeBetweenOpsPassed(uint32_t min_time_between, const km_id_t keyid) {
+ if (!access_time_map_)
+ return false;
+
uint32_t last_access_time;
- if (!access_time_map_.LastKeyAccessTime(keyid, &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;
}
bool KeymasterEnforcement::MaxUsesPerBootNotExceeded(const km_id_t keyid, uint32_t max_uses) {
+ if (!access_count_map_)
+ return false;
+
uint32_t key_access_count;
- if (!access_count_map_.KeyAccessCount(keyid, &key_access_count))
+ if (!access_count_map_->KeyAccessCount(keyid, &key_access_count))
return true;
return key_access_count < max_uses;
}
@@ -406,8 +479,7 @@ bool KeymasterEnforcement::AuthTokenMatches(const AuthorizationSet& auth_set,
return true;
}
-bool KeymasterEnforcement::AccessTimeMap::LastKeyAccessTime(km_id_t keyid,
- uint32_t* last_access_time) const {
+bool 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;
@@ -416,8 +488,7 @@ bool KeymasterEnforcement::AccessTimeMap::LastKeyAccessTime(km_id_t keyid,
return false;
}
-bool KeymasterEnforcement::AccessTimeMap::UpdateKeyAccessTime(km_id_t keyid, uint32_t current_time,
- uint32_t timeout) {
+bool 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) {
@@ -444,7 +515,7 @@ bool KeymasterEnforcement::AccessTimeMap::UpdateKeyAccessTime(km_id_t keyid, uin
return true;
}
-bool KeymasterEnforcement::AccessCountMap::KeyAccessCount(km_id_t keyid, uint32_t* count) const {
+bool AccessCountMap::KeyAccessCount(km_id_t keyid, uint32_t* count) const {
for (auto& entry : access_count_list_)
if (entry.keyid == keyid) {
*count = entry.access_count;
@@ -453,14 +524,15 @@ bool KeymasterEnforcement::AccessCountMap::KeyAccessCount(km_id_t keyid, uint32_
return false;
}
-template <typename T> T max_value(T) {
- return std::numeric_limits<T>::max();
-}
-
-bool KeymasterEnforcement::AccessCountMap::IncrementKeyAccessCount(km_id_t keyid) {
+bool 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))
+ // Note that the 'if' below will always be true because KM_TAG_MAX_USES_PER_BOOT is a
+ // uint32_t, and as soon as entry.access_count reaches the specified maximum value
+ // operation requests will be rejected and access_count won't be incremented any more.
+ // And, besides, UINT64_MAX is huge. But we ensure that it doesn't wrap anyway, out of
+ // an abundance of caution.
+ if (entry.access_count < UINT64_MAX)
++entry.access_count;
return true;
}