• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <mutex>
19 #include <vector>
20 
21 #include <keystore/keymaster_types.h>
22 
23 #ifndef KEYSTORE_AUTH_TOKEN_TABLE_H_
24 #define KEYSTORE_AUTH_TOKEN_TABLE_H_
25 
26 namespace keystore {
27 
28 using keymaster::HardwareAuthToken;
29 
30 namespace test {
31 class AuthTokenTableTest;
32 }  // namespace test
33 
34 time_t clock_gettime_raw();
35 
36 /**
37  * AuthTokenTable manages a set of received authorization tokens and can provide the appropriate
38  * token for authorizing a key operation.
39  *
40  * To keep the table from growing without bound, superseded entries are removed when possible, and
41  * least recently used entries are automatically pruned when when the table exceeds a size limit,
42  * which is expected to be relatively small, since the implementation uses a linear search.
43  */
44 class AuthTokenTable {
45   public:
46     explicit AuthTokenTable(size_t max_entries = 32, time_t (*clock_function)() = clock_gettime_raw)
max_entries_(max_entries)47         : max_entries_(max_entries), last_off_body_(clock_function()),
48           clock_function_(clock_function) {}
49 
50     enum Error {
51         OK,
52         AUTH_NOT_REQUIRED = -1,
53         AUTH_TOKEN_EXPIRED = -2,    // Found a matching token, but it's too old.
54         AUTH_TOKEN_WRONG_SID = -3,  // Found a token with the right challenge, but wrong SID.  This
55                                     // most likely indicates that the authenticator was updated
56                                     // (e.g. new fingerprint enrolled).
57         OP_HANDLE_REQUIRED = -4,    // The key requires auth per use but op_handle was zero.
58         AUTH_TOKEN_NOT_FOUND = -5,
59     };
60 
61     /**
62      * Add an authorization token to the table.
63      */
64     void AddAuthenticationToken(HardwareAuthToken&& auth_token);
65 
66     /**
67      * Find an authorization token that authorizes the operation specified by \p operation_handle on
68      * a key with the characteristics specified in \p key_info.
69      *
70      * This method is O(n * m), where n is the number of KM_TAG_USER_SECURE_ID entries in key_info
71      * and m is the number of entries in the table.  It could be made better, but n and m should
72      * always be small.
73      *
74      * The table retains ownership of the returned object.
75      */
76     std::tuple<Error, HardwareAuthToken> FindAuthorization(const AuthorizationSet& key_info,
77                                                            KeyPurpose purpose, uint64_t op_handle);
78 
79     /**
80      * Mark operation completed.  This allows tokens associated with the specified operation to be
81      * superseded by new tokens.
82      */
83     void MarkCompleted(const uint64_t op_handle);
84 
85     /**
86      * Update the last_off_body_ timestamp so that tokens which remain authorized only so long as
87      * the device stays on body can be revoked.
88      */
89     void onDeviceOffBody();
90 
91     void Clear();
92 
93     /**
94      * This function shall only be used for testing.
95      *
96      * BEWARE: Since the auth token table can be accessed
97      * concurrently, the size may be out dated as soon as it returns.
98      */
99     size_t size() const;
100 
101   private:
102     friend class AuthTokenTableTest;
103 
104     class Entry {
105       public:
106         Entry(HardwareAuthToken&& token, time_t current_time);
Entry(Entry && entry)107         Entry(Entry&& entry) noexcept { *this = std::move(entry); }
108 
109         void operator=(Entry&& rhs) noexcept {
110             token_ = std::move(rhs.token_);
111             time_received_ = rhs.time_received_;
112             last_use_ = rhs.last_use_;
113             operation_completed_ = rhs.operation_completed_;
114         }
115 
116         bool operator<(const Entry& rhs) const { return last_use_ < rhs.last_use_; }
117 
118         void UpdateLastUse(time_t time);
119 
120         bool Supersedes(const Entry& entry) const;
121         bool SatisfiesAuth(const std::vector<uint64_t>& sids, HardwareAuthenticatorType auth_type);
122 
is_newer_than(const Entry * entry)123         bool is_newer_than(const Entry* entry) const {
124             if (!entry) return true;
125             uint64_t ts = token_.timestamp;
126             uint64_t other_ts = entry->token_.timestamp;
127             // Normally comparing timestamp_host_order alone is sufficient, but here is an
128             // additional hack to compare time_received value for some devices where their auth
129             // tokens contain fixed timestamp (due to the a stuck secure RTC on them)
130             return (ts > other_ts) ||
131                    ((ts == other_ts) && (time_received_ > entry->time_received_));
132         }
133 
mark_completed()134         void mark_completed() { operation_completed_ = true; }
135 
token()136         const HardwareAuthToken& token() const & { return token_; }
time_received()137         time_t time_received() const { return time_received_; }
completed()138         bool completed() const { return operation_completed_; }
139 
140       private:
SatisfiesAuth(uint64_t sid,HardwareAuthenticatorType auth_type)141         bool SatisfiesAuth(uint64_t sid, HardwareAuthenticatorType auth_type) const {
142             return (sid == token_.userId || sid == token_.authenticatorId) &&
143                    (auth_type & token_.authenticatorType) != 0;
144         }
145 
146         HardwareAuthToken token_;
147         time_t time_received_;
148         time_t last_use_;
149         bool operation_completed_;
150     };
151 
152     std::tuple<Error, HardwareAuthToken>
153     FindAuthPerOpAuthorization(const std::vector<uint64_t>& sids,
154                                HardwareAuthenticatorType auth_type, uint64_t op_handle);
155     std::tuple<Error, HardwareAuthToken> FindTimedAuthorization(const std::vector<uint64_t>& sids,
156                                                                 HardwareAuthenticatorType auth_type,
157                                                                 const AuthorizationSet& key_info);
158     void ExtractSids(const AuthorizationSet& key_info, std::vector<uint64_t>* sids);
159     void RemoveEntriesSupersededBy(const Entry& entry);
160     bool IsSupersededBySomeEntry(const Entry& entry);
161 
162     /**
163      * Guards the entries_ vector against concurrent modification. All public facing methods
164      * reading of modifying the vector must grab this mutex.
165      */
166     mutable std::mutex entries_mutex_;
167     std::vector<Entry> entries_;
168     size_t max_entries_;
169     time_t last_off_body_;
170     time_t (*clock_function_)();
171 };
172 
173 }  // namespace keystore
174 
175 #endif  // KEYSTORE_AUTH_TOKEN_TABLE_H_
176