| // Copyright 2020 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef ATTESTATION_SERVER_CERTIFICATE_QUEUE_H_ |
| #define ATTESTATION_SERVER_CERTIFICATE_QUEUE_H_ |
| |
| #include <memory> |
| #include <unordered_map> |
| #include <vector> |
| |
| #include "attestation/server/attestation_flow.h" |
| |
| namespace attestation { |
| |
| // This class maintains a collection of attestation flow data entries of |
| // |GetCertificateRequest|s. In this class, the entries of the same |aca_type|, |
| // |username|, and |key_label| are considered as aliases. See the docs of public |
| // APIs for more information. |
| class CertificateQueue { |
| public: |
| enum class PushResult { |
| kSuccess, |
| kAliasLimit, |
| kInconsistentConfig, |
| }; |
| |
| // Constructs an instance where |alias_limit| is the size limit for each |
| // alias. |
| explicit CertificateQueue(size_t alias_limit); |
| ~CertificateQueue() = default; |
| |
| // Puts |data| into the queue. Returns |kSuccess| if the operation succeeds. |
| // Otherwise there are 2 categories of failures as below: 1) if too many |
| // aliases of |data| are already in the queue (i.e., >= |alias_limit_|), |
| // returns |kAliasLimit|; or 2) if any field of |data| doesn't match its |
| // alias(es) (e.g., key type, profile,...), returns |kInconsistentProfile|. |
| PushResult Push(const std::shared_ptr<AttestationFlowData>& data); |
| |
| // Checks if there is any alias of |data| in the queue already. |
| bool HasAnyAlias(const std::shared_ptr<AttestationFlowData>& data) const; |
| |
| // Clears the returns the aliases of |data| in the queue. |
| std::vector<std::shared_ptr<AttestationFlowData>> PopAllAliases( |
| const std::shared_ptr<AttestationFlowData>& data); |
| |
| private: |
| // Size limit for each alias group. |
| const size_t alias_limit_; |
| |
| // Custom definition of hash function for |data| based on the |username| and |
| // |key_label| in the |GetCertificateRequest|. |
| // Note that the definition of alias includes the same |aca_type| in the |
| // request, but in practice it is not supposed to happen so we don't count |
| // |aca_type| as an input of the hash function. This decision is |
| // also driven by the fact that standard library doesn't provide a standard |
| // way to combine hashes. Thus, we sacrifice the accuracy for runtime |
| // efficiency IRL and simplicity. |
| class DataHash { |
| public: |
| size_t operator()(const std::shared_ptr<AttestationFlowData>& data) const; |
| }; |
| // Comparator class that tells if 2 |AttestationFlowData|s' |username|, |
| // |key_label|, and |aca_type| are all identical. |
| class DataEqual { |
| public: |
| bool operator()(const std::shared_ptr<AttestationFlowData>& data1, |
| const std::shared_ptr<AttestationFlowData>& data2) const; |
| }; |
| |
| // Hash table that stores |AttestationFlowData|s. See |DataHash| and |
| // |DataEqual| more information. |
| std::unordered_map<std::shared_ptr<AttestationFlowData>, |
| std::vector<std::shared_ptr<AttestationFlowData>>, |
| DataHash, |
| DataEqual> |
| table_; |
| }; |
| |
| // Synchronized implementation of |CertificateQueue|; behind the scene it just |
| // wraps all the public interfaces of |CertificateQueue| with the same |mutex_| |
| // instance. |
| class SynchronizedCertificateQueue { |
| public: |
| explicit SynchronizedCertificateQueue(size_t alias_limit) |
| : certificate_queue_(alias_limit) {} |
| ~SynchronizedCertificateQueue() = default; |
| |
| CertificateQueue::PushResult Push( |
| const std::shared_ptr<AttestationFlowData>& data) { |
| std::lock_guard<decltype(mutex_)> lock(mutex_); |
| return certificate_queue_.Push(data); |
| } |
| |
| bool HasAnyAlias(const std::shared_ptr<AttestationFlowData>& data) const { |
| std::lock_guard<decltype(mutex_)> lock(mutex_); |
| return certificate_queue_.HasAnyAlias(data); |
| } |
| |
| std::vector<std::shared_ptr<AttestationFlowData>> PopAllAliases( |
| const std::shared_ptr<AttestationFlowData>& data) { |
| std::lock_guard<decltype(mutex_)> lock(mutex_); |
| return certificate_queue_.PopAllAliases(data); |
| } |
| |
| private: |
| CertificateQueue certificate_queue_; |
| mutable std::mutex mutex_; |
| }; |
| |
| } // namespace attestation |
| |
| #endif // ATTESTATION_SERVER_CERTIFICATE_QUEUE_H_ |