ff3d7f4b83
This patch transitions keystore a threading model with one dispatcher thread and one worker thread per keymaster instance, i.e. fallback, TEE, Strongbox (if available). Singleton objects, such as the user state database, the enforcement policy, and grant database have been moved to KeyStore and were made concurrency safe. Other noteworthy changes in this patch: * Cached key characteristics. The key characteristics file used to hold a limited set of parameters used generate or import the key. This patch introduces a new blob type that holds full characteristics as returned by generate, import, or getKeyCharacteristics, with the original parameters mixed into the software enforced list. When keystore encounters a lagacy characteristics file it will grab the characteristics from keymaster, merge them with the cached parameters, and update the cache file to the new format. If keystore encounters the new cache no call to keymaster will be made for retrieving the key characteristics. * Changed semantic of list. The list call takes a prefix used for filtering key entries. By the old semantic, list would return a list of aliases stripped of the given prefix. By the new semantic list always returns a filtered list of full alias string. Callers may strip prefixes if they are so inclined. * Entertain per keymaster instance operation maps. With the introduction of Strongbox keystore had to deal with multiple keymaster instances. But until now it would entertain a single operations map. Keystore also enforces the invariant that no more than 15 operation slots are used so there is always a free slot available for vold. With a single operation map, this means no more than 15 slots can ever be used although with TEE and Strongbox there are a total of 32 slots. With strongbox implementation that have significantly fewer slots we see another effect of the single operation map. If a slot needs to be freed on Stronbox but the oldest operations are on TEE, the latter will be unnecessarily pruned before a Strongbox slot is freed up. With this patch each keymaster instance has its own operation map and pruning is performed on a per keymaster instance basis. * Introduce KeyBlobEntries which are independent from files. To allow concurrent access to the key blob data base, entries can be individually locked so that operations on entries become atomic. LockedKeyBlobEntries are move only objects that track ownership of an Entry on the stack or in functor object representing keymaster worker requests. Entries must only be locked by the dispatcher Thread. Worker threads can only be granted access to a LockedKeyBlobEntry by the dispatcher thread. This allows the dispatcher thread to execute a barrier that waits until all locks held by workers have been relinquished to perform blob database maintenance operations, e.g., clearing a uid of all entries. * Verification tokens are now acquired asynchronously. When a begin operation requires a verification token a request is submitted to the other keymaster worker while the begin call returns. When the operation commences with update or finish, we block until the verification token becomes available. As of this patch the keystore IPC interface is still synchronous. That is, the dispatcher thread dispatches a request to a worker and then waits until the worker has finished. In a followup patch the IPC interface shall be made asynchronous so that multiple requests may be in flight. Test: Ran full CTS test suite atest android.keystore.cts Bug: 111443219 Bug: 110495056 Change-Id: I305e28d784295a0095a34810d83202f7423498bd
213 lines
8.2 KiB
C++
213 lines
8.2 KiB
C++
/*
|
|
* 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 KEYSTORE_KEYMASTER_ENFORCEMENT_H
|
|
#define KEYSTORE_KEYMASTER_ENFORCEMENT_H
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <keystore/keymaster_types.h>
|
|
|
|
#include <list>
|
|
#include <mutex>
|
|
#include <optional>
|
|
|
|
namespace keystore {
|
|
|
|
typedef uint64_t km_id_t;
|
|
|
|
class KeymasterEnforcementContext {
|
|
public:
|
|
virtual ~KeymasterEnforcementContext() {}
|
|
/*
|
|
* Get current time.
|
|
*/
|
|
};
|
|
|
|
class AccessTimeMap {
|
|
public:
|
|
explicit 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:
|
|
mutable std::mutex list_lock_;
|
|
struct AccessTime {
|
|
km_id_t keyid;
|
|
uint32_t access_time;
|
|
uint32_t timeout;
|
|
};
|
|
std::list<AccessTime> last_access_list_;
|
|
const uint32_t max_size_;
|
|
};
|
|
|
|
class AccessCountMap {
|
|
public:
|
|
explicit 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:
|
|
mutable std::mutex list_lock_;
|
|
struct AccessCount {
|
|
km_id_t keyid;
|
|
uint64_t access_count;
|
|
};
|
|
std::list<AccessCount> access_count_list_;
|
|
const uint32_t max_size_;
|
|
};
|
|
|
|
class KeymasterEnforcement {
|
|
public:
|
|
/**
|
|
* Construct a KeymasterEnforcement.
|
|
*/
|
|
KeymasterEnforcement(uint32_t max_access_time_map_size, uint32_t 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.
|
|
*/
|
|
ErrorCode AuthorizeOperation(const KeyPurpose purpose, const km_id_t keyid,
|
|
const AuthorizationSet& auth_set,
|
|
const AuthorizationSet& operation_params,
|
|
const HardwareAuthToken& auth_token, uint64_t op_handle,
|
|
bool is_begin_operation);
|
|
|
|
/**
|
|
* 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. Used for encrypt, decrypt sign, and verify.
|
|
*/
|
|
ErrorCode AuthorizeBegin(const KeyPurpose purpose, const km_id_t keyid,
|
|
const AuthorizationSet& auth_set,
|
|
const AuthorizationSet& operation_params,
|
|
NullOr<const HardwareAuthToken&> auth_token);
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
ErrorCode AuthorizeUpdate(const AuthorizationSet& auth_set, const HardwareAuthToken& auth_token,
|
|
uint64_t op_handle) {
|
|
return AuthorizeUpdateOrFinish(auth_set, auth_token, op_handle);
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
ErrorCode AuthorizeFinish(const AuthorizationSet& auth_set, const HardwareAuthToken& auth_token,
|
|
uint64_t op_handle) {
|
|
return AuthorizeUpdateOrFinish(auth_set, auth_token, op_handle);
|
|
}
|
|
|
|
/**
|
|
* 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 std::optional<km_id_t> CreateKeyId(const hidl_vec<uint8_t>& key_blob);
|
|
|
|
//
|
|
// 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 HardwareAuthToken& 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 HardwareAuthToken& token) const = 0;
|
|
|
|
/*
|
|
* Returns true if the device screen is currently locked for the specified user.
|
|
*/
|
|
virtual bool is_device_locked(int32_t userId) const = 0;
|
|
|
|
private:
|
|
ErrorCode AuthorizeUpdateOrFinish(const AuthorizationSet& auth_set,
|
|
const HardwareAuthToken& auth_token, uint64_t op_handle);
|
|
|
|
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 HardwareAuthToken& auth_token,
|
|
const uint64_t user_secure_id, const int auth_type_index,
|
|
const int auth_timeout_index, const uint64_t op_handle,
|
|
bool is_begin_operation) const;
|
|
|
|
AccessTimeMap access_time_map_;
|
|
AccessCountMap access_count_map_;
|
|
};
|
|
|
|
}; /* namespace keystore */
|
|
|
|
#endif // KEYSTORE_KEYMASTER_ENFORCEMENT_H
|