Home | History | Annotate | Download | only in keystore
      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)
     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 
     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);
    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 
    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 
    127         void mark_completed() { operation_completed_ = true; }
    128 
    129         const HardwareAuthToken& token() const & { return token_; }
    130         time_t time_received() const { return time_received_; }
    131         bool completed() const { return operation_completed_; }
    132 
    133       private:
    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