| // Copyright (c) 2023 The Chromium 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 QUICHE_BLIND_SIGN_AUTH_CACHED_BLIND_SIGN_AUTH_H_ | |
| #define QUICHE_BLIND_SIGN_AUTH_CACHED_BLIND_SIGN_AUTH_H_ | |
| #include <string> | |
| #include <vector> | |
| #include "absl/base/thread_annotations.h" | |
| #include "absl/status/statusor.h" | |
| #include "absl/synchronization/mutex.h" | |
| #include "absl/types/span.h" | |
| #include "quiche/blind_sign_auth/blind_sign_auth_interface.h" | |
| #include "quiche/common/platform/api/quiche_export.h" | |
| #include "quiche/common/quiche_circular_deque.h" | |
| namespace quiche { | |
| inline constexpr int kBlindSignAuthRequestMaxTokens = 1024; | |
| // CachedBlindSignAuth caches signed tokens generated by BlindSignAuth. | |
| // This class does not guarantee that tokens returned are fresh. | |
| // Tokens may be stale if the backend has rotated its signing key since tokens | |
| // were generated. | |
| // This class is thread-safe. | |
| class QUICHE_EXPORT CachedBlindSignAuth : public BlindSignAuthInterface { | |
| public: | |
| CachedBlindSignAuth( | |
| BlindSignAuthInterface* blind_sign_auth, | |
| int max_tokens_per_request = kBlindSignAuthRequestMaxTokens) | |
| : blind_sign_auth_(blind_sign_auth), | |
| max_tokens_per_request_(max_tokens_per_request) {} | |
| // Returns signed unblinded tokens and expiration time in a callback. | |
| // Tokens are single-use. They will not be usable after the expiration time. | |
| // | |
| // The GetTokens callback may be called synchronously on the calling thread, | |
| // or asynchronously on BlindSignAuth's BlindSignMessageInterface thread. | |
| // The GetTokens callback must not acquire any locks that the calling thread | |
| // owns, otherwise the callback will deadlock. | |
| void GetTokens(std::optional<std::string> oauth_token, int num_tokens, | |
| ProxyLayer proxy_layer, BlindSignAuthServiceType service_type, | |
| SignedTokenCallback callback) override; | |
| // Removes all tokens in the cache. | |
| void ClearCache() { | |
| absl::WriterMutexLock lock(&mutex_); | |
| cached_tokens_.clear(); | |
| } | |
| // Returns an attestation challenge in a callback. | |
| // GetAttestationTokens callbacks will run on the same thread as the | |
| // BlindSignMessageInterface callbacks. | |
| // Callers can make multiple concurrent requests to GetTokens. | |
| // ProxyLayer must be either ProxyB or TerminalLayer, NOT ProxyA. | |
| // AttestationDataCallback should call AttestAndSign with a separate callback | |
| // in order to complete the token issuance protocol. | |
| void GetAttestationTokens(int num_tokens, ProxyLayer layer, | |
| AttestationDataCallback callback, | |
| SignedTokenCallback token_callback) override; | |
| private: | |
| void HandleGetTokensResponse( | |
| SignedTokenCallback callback, int num_tokens, | |
| absl::StatusOr<absl::Span<BlindSignToken>> tokens); | |
| std::vector<BlindSignToken> CreateOutputTokens(int num_tokens) | |
| ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); | |
| void RemoveExpiredTokens() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); | |
| BlindSignAuthInterface* blind_sign_auth_; | |
| int max_tokens_per_request_; | |
| absl::Mutex mutex_; | |
| QuicheCircularDeque<BlindSignToken> cached_tokens_ ABSL_GUARDED_BY(mutex_); | |
| }; | |
| } // namespace quiche | |
| #endif // QUICHE_BLIND_SIGN_AUTH_CACHED_BLIND_SIGN_AUTH_H_ |