blob: c0fc9ffae19dd6c2e3686c6993b283c366645c98 [file] [log] [blame]
// 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_