15 :
public std::enable_shared_from_this<QuoteEndorsementsClient>
24 static constexpr size_t server_connection_timeout_s = 3;
28 static constexpr size_t max_server_retries_count = 3;
30 std::shared_ptr<RPCSessions> rpcsessions;
35 std::vector<uint8_t> endorsements_pem;
42 size_t last_received_request_id = 0;
43 bool has_completed =
false;
44 size_t server_retries_count = 0;
46 struct QuoteEndorsementsClientMsg
48 QuoteEndorsementsClientMsg(
49 const std::shared_ptr<QuoteEndorsementsClient>& self_,
50 const Server& server_) :
55 std::shared_ptr<QuoteEndorsementsClient> self;
59 struct QuoteEndorsementsClientTimeoutMsg
61 QuoteEndorsementsClientTimeoutMsg(
62 const std::shared_ptr<QuoteEndorsementsClient>& self_,
67 request_id(request_id_)
70 std::shared_ptr<QuoteEndorsementsClient> self;
75 std::shared_ptr<ClientSession> create_unauthenticated_client()
81 return rpcsessions->create_client(std::make_shared<::tls::Cert>(
82 nullptr, std::nullopt, std::nullopt, std::nullopt,
false));
85 std::shared_ptr<ClientSession> create_unencrypted_client()
87 return rpcsessions->create_unencrypted_client();
91 const std::shared_ptr<ClientSession>&
client,
96 for (
auto const& [k, v] : endpoint.
params)
100 for (
auto const& [k, v] : endpoint.
headers)
107 "Fetching endorsements for attestation report at {}{}{}",
111 client->send_request(std::move(r));
115 auto msg = std::make_unique<
117 [](std::unique_ptr<::threading::Tmsg<QuoteEndorsementsClientTimeoutMsg>>
119 std::lock_guard<ccf::pal::Mutex> guard(msg->data.self->lock);
120 if (msg->data.self->has_completed)
124 if (msg->data.request_id >= msg->data.self->last_received_request_id)
126 auto& servers = msg->data.self->config.servers;
127 msg->data.self->server_retries_count++;
129 msg->data.self->server_retries_count >= max_server_retries_count)
131 if (servers.size() > 1)
138 auto& server = servers.front();
140 "Giving up retrying fetching attestation endorsements from "
141 "{} after {} attempts",
143 max_server_retries_count);
148 msg->data.self->fetch(servers.front());
153 last_received_request_id);
157 std::chrono::milliseconds(server_connection_timeout_s * 1000));
160 void handle_success_response(
161 std::vector<uint8_t>&& data,
const EndpointInfo& response_endpoint)
165 auto& server = config.
servers.front();
170 auto endpoint = server.front();
171 if (has_completed || response_endpoint != endpoint)
179 endorsements_pem.insert(endorsements_pem.end(), raw.begin(), raw.end());
183 auto j = nlohmann::json::parse(data);
184 auto vcekCert = j.at(
"vcekCert").get<std::string>();
185 auto certificateChain = j.at(
"certificateChain").get<std::string>();
186 endorsements_pem.insert(
187 endorsements_pem.end(), vcekCert.begin(), vcekCert.end());
188 endorsements_pem.insert(
189 endorsements_pem.end(),
190 certificateChain.begin(),
191 certificateChain.end());
195 endorsements_pem.insert(
196 endorsements_pem.end(), data.begin(), data.end());
202 LOG_INFO_FMT(
"Complete endorsement chain successfully retrieved");
204 "{}", std::string(endorsements_pem.begin(), endorsements_pem.end()));
205 has_completed =
true;
206 done_cb(std::move(endorsements_pem));
214 void fetch(
const Server& server)
216 auto endpoint = server.front();
218 auto c = endpoint.
tls ? create_unauthenticated_client() :
219 create_unencrypted_client();
223 [
this, server, endpoint](
226 std::vector<uint8_t>&& data) {
227 std::lock_guard<ccf::pal::Mutex> guard(this->lock);
229 last_received_request_id++;
231 if (status == HTTP_STATUS_OK)
234 "Successfully retrieved endorsements for attestation report: "
238 handle_success_response(std::move(data), endpoint);
243 "Error fetching endorsements for attestation report: {}", status);
244 if (status == HTTP_STATUS_TOO_MANY_REQUESTS)
246 constexpr size_t default_retry_after_s = 3;
247 size_t retry_after_s = default_retry_after_s;
248 auto h = headers.find(http::headers::RETRY_AFTER);
249 if (h != headers.end())
251 const auto& retry_after_value = h->second;
254 retry_after_value.data(),
255 retry_after_value.data() + retry_after_value.size(),
263 msg) { msg->data.self->fetch(msg->data.server); },
268 "{} endorsements endpoint had too many requests. Retrying "
274 std::move(msg), std::chrono::milliseconds(retry_after_s * 1000));
278 [endpoint](
const std::string& error_msg) {
280 "TLS error when connecting to quote endorsements endpoint {}: {}",
284 send_request(c, endpoint);
289 const std::shared_ptr<RPCSessions>& rpcsessions_,
292 rpcsessions(rpcsessions_),
298 std::lock_guard<ccf::pal::Mutex> guard(this->lock);
299 auto const& server = config.servers.front();
302 throw std::logic_error(
"No server specified to fetch endorsements");