• 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 <vector>
19 
20 #include <keystore/keymaster_types.h>
21 
22 #ifndef KEYSTORE_AUTH_TOKEN_TABLE_H_
23 #define KEYSTORE_AUTH_TOKEN_TABLE_H_
24 
25 namespace keystore {
26 
27 using keymaster::HardwareAuthToken;
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:
45     explicit AuthTokenTable(size_t max_entries = 32, time_t (*clock_function)() = clock_gettime_raw)
max_entries_(max_entries)46         : max_entries_(max_entries), last_off_body_(clock_function()),
47           clock_function_(clock_function) {}
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     /**
61      * Add an authorization token to the table.
62      */
63     void AddAuthenticationToken(HardwareAuthToken&& auth_token);
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      */
75     Error FindAuthorization(const AuthorizationSet& key_info, KeyPurpose purpose,
76                             uint64_t op_handle, const HardwareAuthToken** found);
77 
78     /**
79      * Mark operation completed.  This allows tokens associated with the specified operation to be
80      * superseded by new tokens.
81      */
82     void MarkCompleted(const uint64_t op_handle);
83 
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 
90     void Clear();
91 
size()92     size_t size() { return entries_.size(); }
93 
94   private:
95     friend class AuthTokenTableTest;
96 
97     class Entry {
98       public:
99         Entry(HardwareAuthToken&& token, time_t current_time);
Entry(Entry && entry)100         Entry(Entry&& entry) { *this = std::move(entry); }
101 
102         void operator=(Entry&& rhs) {
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;
114         bool SatisfiesAuth(const std::vector<uint64_t>& sids, HardwareAuthenticatorType auth_type);
115 
is_newer_than(const Entry * entry)116         bool is_newer_than(const Entry* entry) const {
117             if (!entry) return true;
118             uint64_t ts = token_.timestamp;
119             uint64_t other_ts = entry->token_.timestamp;
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_));
125         }
126 
mark_completed()127         void mark_completed() { operation_completed_ = true; }
128 
token()129         const HardwareAuthToken& token() const & { return token_; }
time_received()130         time_t time_received() const { return time_received_; }
completed()131         bool completed() const { return operation_completed_; }
132 
133       private:
SatisfiesAuth(uint64_t sid,HardwareAuthenticatorType auth_type)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_;
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,
146                                      HardwareAuthenticatorType auth_type, uint64_t op_handle,
147                                      const HardwareAuthToken** found);
148     Error FindTimedAuthorization(const std::vector<uint64_t>& sids,
149                                  HardwareAuthenticatorType auth_type,
150                                  const AuthorizationSet& key_info, const HardwareAuthToken** found);
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_;
157     time_t last_off_body_;
158     time_t (*clock_function_)();
159 };
160 
161 }  // namespace keystore
162 
163 #endif  // KEYSTORE_AUTH_TOKEN_TABLE_H_
164