Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2015 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include <memory> |
| 18 | #include <vector> |
| 19 | |
Shawn Willden | 0329a82 | 2017-12-04 13:55:14 -0700 | [diff] [blame] | 20 | #include <keystore/keymaster_types.h> |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 21 | |
Shawn Willden | 6507c27 | 2016-01-05 22:51:48 -0700 | [diff] [blame] | 22 | #ifndef KEYSTORE_AUTH_TOKEN_TABLE_H_ |
| 23 | #define KEYSTORE_AUTH_TOKEN_TABLE_H_ |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 24 | |
Janis Danisevskis | c7a9fa2 | 2016-10-13 18:43:45 +0100 | [diff] [blame] | 25 | namespace keystore { |
| 26 | |
Shawn Willden | 0329a82 | 2017-12-04 13:55:14 -0700 | [diff] [blame] | 27 | using keymaster::HardwareAuthToken; |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 28 | |
| 29 | namespace test { |
| 30 | class AuthTokenTableTest; |
| 31 | } // namespace test |
| 32 | |
| 33 | time_t clock_gettime_raw(); |
| 34 | |
| 35 | /** |
| 36 | * AuthTokenTable manages a set of received authorization tokens and can provide the appropriate |
| 37 | * token for authorizing a key operation. |
| 38 | * |
| 39 | * To keep the table from growing without bound, superseded entries are removed when possible, and |
| 40 | * least recently used entries are automatically pruned when when the table exceeds a size limit, |
| 41 | * which is expected to be relatively small, since the implementation uses a linear search. |
| 42 | */ |
| 43 | class AuthTokenTable { |
| 44 | public: |
Chih-Hung Hsieh | d7791be | 2016-07-12 11:58:02 -0700 | [diff] [blame] | 45 | explicit AuthTokenTable(size_t max_entries = 32, time_t (*clock_function)() = clock_gettime_raw) |
Janis Danisevskis | c7a9fa2 | 2016-10-13 18:43:45 +0100 | [diff] [blame] | 46 | : max_entries_(max_entries), last_off_body_(clock_function()), |
| 47 | clock_function_(clock_function) {} |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 48 | |
| 49 | enum Error { |
| 50 | OK, |
| 51 | AUTH_NOT_REQUIRED = -1, |
| 52 | AUTH_TOKEN_EXPIRED = -2, // Found a matching token, but it's too old. |
| 53 | AUTH_TOKEN_WRONG_SID = -3, // Found a token with the right challenge, but wrong SID. This |
| 54 | // most likely indicates that the authenticator was updated |
| 55 | // (e.g. new fingerprint enrolled). |
| 56 | OP_HANDLE_REQUIRED = -4, // The key requires auth per use but op_handle was zero. |
| 57 | AUTH_TOKEN_NOT_FOUND = -5, |
| 58 | }; |
| 59 | |
| 60 | /** |
Shawn Willden | bb22a6c | 2017-12-06 19:35:28 -0700 | [diff] [blame] | 61 | * Add an authorization token to the table. |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 62 | */ |
Shawn Willden | 0329a82 | 2017-12-04 13:55:14 -0700 | [diff] [blame] | 63 | void AddAuthenticationToken(HardwareAuthToken&& auth_token); |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 64 | |
| 65 | /** |
| 66 | * Find an authorization token that authorizes the operation specified by \p operation_handle on |
| 67 | * a key with the characteristics specified in \p key_info. |
| 68 | * |
| 69 | * This method is O(n * m), where n is the number of KM_TAG_USER_SECURE_ID entries in key_info |
| 70 | * and m is the number of entries in the table. It could be made better, but n and m should |
| 71 | * always be small. |
| 72 | * |
| 73 | * The table retains ownership of the returned object. |
| 74 | */ |
Janis Danisevskis | c7a9fa2 | 2016-10-13 18:43:45 +0100 | [diff] [blame] | 75 | Error FindAuthorization(const AuthorizationSet& key_info, KeyPurpose purpose, |
Shawn Willden | d3ed3a2 | 2017-03-28 00:39:16 +0000 | [diff] [blame] | 76 | uint64_t op_handle, const HardwareAuthToken** found); |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 77 | |
| 78 | /** |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 79 | * Mark operation completed. This allows tokens associated with the specified operation to be |
| 80 | * superseded by new tokens. |
| 81 | */ |
Janis Danisevskis | c7a9fa2 | 2016-10-13 18:43:45 +0100 | [diff] [blame] | 82 | void MarkCompleted(const uint64_t op_handle); |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 83 | |
Tucker Sylvestro | 0ab28b7 | 2016-08-05 18:02:47 -0400 | [diff] [blame] | 84 | /** |
| 85 | * Update the last_off_body_ timestamp so that tokens which remain authorized only so long as |
| 86 | * the device stays on body can be revoked. |
| 87 | */ |
| 88 | void onDeviceOffBody(); |
| 89 | |
Chad Brubaker | bbc7648 | 2015-04-16 15:16:44 -0700 | [diff] [blame] | 90 | void Clear(); |
| 91 | |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 92 | size_t size() { return entries_.size(); } |
| 93 | |
| 94 | private: |
| 95 | friend class AuthTokenTableTest; |
| 96 | |
| 97 | class Entry { |
| 98 | public: |
Shawn Willden | 0329a82 | 2017-12-04 13:55:14 -0700 | [diff] [blame] | 99 | Entry(HardwareAuthToken&& token, time_t current_time); |
Chih-Hung Hsieh | f73b198 | 2018-09-25 12:03:21 -0700 | [diff] [blame^] | 100 | Entry(Entry&& entry) noexcept { *this = std::move(entry); } |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 101 | |
Chih-Hung Hsieh | f73b198 | 2018-09-25 12:03:21 -0700 | [diff] [blame^] | 102 | void operator=(Entry&& rhs) noexcept { |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 103 | token_ = std::move(rhs.token_); |
| 104 | time_received_ = rhs.time_received_; |
| 105 | last_use_ = rhs.last_use_; |
| 106 | operation_completed_ = rhs.operation_completed_; |
| 107 | } |
| 108 | |
| 109 | bool operator<(const Entry& rhs) const { return last_use_ < rhs.last_use_; } |
| 110 | |
| 111 | void UpdateLastUse(time_t time); |
| 112 | |
| 113 | bool Supersedes(const Entry& entry) const; |
Janis Danisevskis | c7a9fa2 | 2016-10-13 18:43:45 +0100 | [diff] [blame] | 114 | bool SatisfiesAuth(const std::vector<uint64_t>& sids, HardwareAuthenticatorType auth_type); |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 115 | |
Rubin Xu | bfb01d9 | 2017-10-23 17:04:25 +0100 | [diff] [blame] | 116 | bool is_newer_than(const Entry* entry) const { |
Janis Danisevskis | c7a9fa2 | 2016-10-13 18:43:45 +0100 | [diff] [blame] | 117 | if (!entry) return true; |
Shawn Willden | 0329a82 | 2017-12-04 13:55:14 -0700 | [diff] [blame] | 118 | uint64_t ts = token_.timestamp; |
| 119 | uint64_t other_ts = entry->token_.timestamp; |
Rubin Xu | bfb01d9 | 2017-10-23 17:04:25 +0100 | [diff] [blame] | 120 | // Normally comparing timestamp_host_order alone is sufficient, but here is an |
| 121 | // additional hack to compare time_received value for some devices where their auth |
| 122 | // tokens contain fixed timestamp (due to the a stuck secure RTC on them) |
| 123 | return (ts > other_ts) || |
| 124 | ((ts == other_ts) && (time_received_ > entry->time_received_)); |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 125 | } |
| 126 | |
| 127 | void mark_completed() { operation_completed_ = true; } |
| 128 | |
Shawn Willden | 0329a82 | 2017-12-04 13:55:14 -0700 | [diff] [blame] | 129 | const HardwareAuthToken& token() const & { return token_; } |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 130 | time_t time_received() const { return time_received_; } |
| 131 | bool completed() const { return operation_completed_; } |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 132 | |
| 133 | private: |
Shawn Willden | 0329a82 | 2017-12-04 13:55:14 -0700 | [diff] [blame] | 134 | bool SatisfiesAuth(uint64_t sid, HardwareAuthenticatorType auth_type) const { |
| 135 | return (sid == token_.userId || sid == token_.authenticatorId) && |
| 136 | (auth_type & token_.authenticatorType) != 0; |
| 137 | } |
| 138 | |
| 139 | HardwareAuthToken token_; |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 140 | time_t time_received_; |
| 141 | time_t last_use_; |
| 142 | bool operation_completed_; |
| 143 | }; |
| 144 | |
| 145 | Error FindAuthPerOpAuthorization(const std::vector<uint64_t>& sids, |
Janis Danisevskis | c7a9fa2 | 2016-10-13 18:43:45 +0100 | [diff] [blame] | 146 | HardwareAuthenticatorType auth_type, uint64_t op_handle, |
Shawn Willden | d3ed3a2 | 2017-03-28 00:39:16 +0000 | [diff] [blame] | 147 | const HardwareAuthToken** found); |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 148 | Error FindTimedAuthorization(const std::vector<uint64_t>& sids, |
Janis Danisevskis | c7a9fa2 | 2016-10-13 18:43:45 +0100 | [diff] [blame] | 149 | HardwareAuthenticatorType auth_type, |
Shawn Willden | d3ed3a2 | 2017-03-28 00:39:16 +0000 | [diff] [blame] | 150 | const AuthorizationSet& key_info, const HardwareAuthToken** found); |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 151 | void ExtractSids(const AuthorizationSet& key_info, std::vector<uint64_t>* sids); |
| 152 | void RemoveEntriesSupersededBy(const Entry& entry); |
| 153 | bool IsSupersededBySomeEntry(const Entry& entry); |
| 154 | |
| 155 | std::vector<Entry> entries_; |
| 156 | size_t max_entries_; |
Tucker Sylvestro | 0ab28b7 | 2016-08-05 18:02:47 -0400 | [diff] [blame] | 157 | time_t last_off_body_; |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 158 | time_t (*clock_function_)(); |
| 159 | }; |
| 160 | |
Shawn Willden | 0329a82 | 2017-12-04 13:55:14 -0700 | [diff] [blame] | 161 | } // namespace keystore |
Shawn Willden | 489dfe1 | 2015-03-17 10:13:27 -0600 | [diff] [blame] | 162 | |
Shawn Willden | 6507c27 | 2016-01-05 22:51:48 -0700 | [diff] [blame] | 163 | #endif // KEYSTORE_AUTH_TOKEN_TABLE_H_ |