CCF
Loading...
Searching...
No Matches
ccf_acme_client.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
5#include "ccf/http_status.h"
11#include "node/acme_client.h"
13
14#include <chrono>
15
16namespace ccf
17{
18 namespace
19 {
20 static inline ACME::ClientConfig get_client_config(
21 const ACMEClientConfig& cfg)
22 {
23 return {
24 cfg.ca_certs,
25 cfg.directory_url,
26 cfg.service_dns_name,
27 cfg.alternative_names,
28 cfg.contact,
29 cfg.terms_of_service_agreed,
30 cfg.challenge_type,
31 cfg.not_before,
32 cfg.not_after};
33 }
34 }
35
36 class ACMEClient : public ACME::Client
37 {
38 protected:
39 // Default challenge handler is the http-01 frontend
41 {
42 public:
47 virtual ~DefaultChallengeHandler() = default;
48
49 virtual bool ready(const std::string& token) override
50 {
51 auto rit = token_responses.find(token);
52 if (rit == token_responses.end())
53 {
54 return false;
55 }
56 challenge_frontend->add(token, rit->second);
57 return true;
58 }
59
60 virtual void remove(const std::string& token) override
61 {
62 token_responses.erase(token);
64 {
65 challenge_frontend->remove(token);
66 }
67 }
68
69 protected:
70 std::shared_ptr<ACMERpcFrontend> challenge_frontend;
71 };
72
73 public:
75 const std::string& config_name,
77 std::shared_ptr<RPCMap> rpc_map,
78 std::shared_ptr<RPCSessions> rpc_sessions,
79 std::shared_ptr<ACMERpcFrontend> challenge_frontend,
80 std::shared_ptr<ccf::kv::Store> store,
81 std::shared_ptr<ccf::crypto::KeyPair> account_key_pair = nullptr,
82 std::shared_ptr<ACMEChallengeHandler> challenge_handler_ = nullptr) :
83 ACME::Client(get_client_config(config), account_key_pair),
88 store(store),
89 challenge_handler(challenge_handler_)
90 {
92 {
94 std::make_shared<DefaultChallengeHandler>(challenge_frontend);
95 }
96 }
97
98 virtual ~ACMEClient() {}
99
100 virtual void set_account_key(
101 std::shared_ptr<ccf::crypto::KeyPair> new_account_key_pair) override
102 {
103 ACME::Client::set_account_key(new_account_key_pair);
105 }
106
107 virtual void check_expiry(
108 std::shared_ptr<ccf::kv::Store> tables,
109 std::unique_ptr<NetworkIdentity>& identity)
110 {
111 auto now = std::chrono::system_clock::now();
112 bool renew = false;
113 auto tx = tables->create_read_only_tx();
114 auto certs = tx.ro<ACMECertificates>(Tables::ACME_CERTIFICATES);
115 auto cert = certs->get(config_name);
116 if (cert)
117 {
118 auto v = ccf::crypto::make_verifier(*cert);
119 double rem_pct = v->remaining_percentage(now);
121 "ACME: remaining certificate validity for '{}': {}%, {} seconds",
123 100.0 * rem_pct,
124 v->remaining_seconds(now));
125 renew = rem_pct < 0.33;
126 }
127
128 if (renew || !cert)
129 {
130 get_certificate(make_key_pair(identity->priv_key));
131 }
132 }
133
135 std::shared_ptr<ACMEChallengeHandler> h)
136 {
139 }
140
141 protected:
142 std::string config_name;
143 std::shared_ptr<RPCMap> rpc_map;
144 std::shared_ptr<RPCSessions> rpc_sessions;
145 std::shared_ptr<ACMERpcFrontend> challenge_frontend;
146 std::shared_ptr<ccf::kv::Store> store;
147 std::shared_ptr<ACMEChallengeHandler> challenge_handler;
148
150 {
151 // Register a wildcard-response for all challenge tokens. If we use a
152 // shared account key, we can use this response on all nodes without
153 // further communication.
155 {
156 challenge_handler->token_responses[""] = make_challenge_response();
157 }
158 }
159
160 virtual void on_http_request(
161 const ::http::URL& url,
162 ::http::Request&& req,
163 std::function<bool(
164 ccf::http_status status, http::HeaderMap&&, std::vector<uint8_t>&&)>
165 callback) override
166 {
167 auto ca = std::make_shared<::tls::CA>(config.ca_certs, true);
168 auto ca_cert = std::make_shared<::tls::Cert>(ca);
169 auto client = rpc_sessions->create_client(ca_cert);
170
171 client->connect(
172 url.host,
173 url.port,
174 [callback](
175 ccf::http_status status,
176 http::HeaderMap&& headers,
177 std::vector<uint8_t>&& data) {
178 return callback(status, std::move(headers), std::move(data));
179 });
180 client->send_request(std::move(req));
181 }
182
184 {
187 const std::shared_ptr<ACMEChallengeHandler> handler,
188 const std::string& token) :
189 client(client),
191 token(token)
192 {}
194 std::shared_ptr<ACMEChallengeHandler> handler;
195 std::string token;
196 };
197
198 virtual void on_challenge(
199 const std::string& token, const std::string& response) override
200 {
202 {
203 throw std::runtime_error("No ACME challenge handler");
204 }
205
206 using namespace ::threading;
207
208 challenge_handler->token_responses[token] = response;
209
210 auto msg = std::make_unique<Tmsg<ACMEClientMsg>>(
211 [](std::unique_ptr<Tmsg<ACMEClientMsg>> msg) {
212 auto& client = msg->data.client;
213 auto& handler = msg->data.handler;
214 auto& token = msg->data.token;
215 if (handler->ready(token))
216 {
217 client.start_challenge(token);
218 }
219 else
220 {
221 ThreadMessaging::instance().add_task_after(
222 std::move(msg), std::chrono::seconds(1));
223 }
224 },
225 *this,
227 token);
228
229 ThreadMessaging::instance().add_task_after(
230 std::move(msg), std::chrono::seconds(1));
231 }
232
233 virtual void on_challenge_finished(const std::string& token) override
234 {
236 {
237 challenge_handler->remove(token);
238 }
239 }
240
241 virtual void on_certificate(const std::string& certificate) override
242 {
243 // Write the endorsed certificate to the certificate table; all nodes
244 // will install it later, in the global hook on that table.
245 auto tx = store->create_tx();
246 auto certs = tx.rw<ACMECertificates>(Tables::ACME_CERTIFICATES);
247 certs->put(config_name, ccf::crypto::Pem(certificate));
248 tx.commit();
249 }
250 };
251}
Definition acme_client.h:64
void get_certificate(std::shared_ptr< ccf::crypto::KeyPair > service_key_, bool override_time=false)
Definition acme_client.h:76
virtual void set_account_key(std::shared_ptr< ccf::crypto::KeyPair > new_account_key_pair)
Definition acme_client.h:151
std::shared_ptr< ccf::crypto::KeyPair > account_key_pair
Definition acme_client.h:368
std::string make_challenge_response() const
Definition acme_client.h:875
ClientConfig config
Definition acme_client.h:366
Client(const ClientConfig &config, std::shared_ptr< ccf::crypto::KeyPair > account_key_pair=nullptr)
Definition acme_client.h:66
Definition acme_client_config.h:62
std::map< std::string, std::string > token_responses
Definition acme_client_config.h:64
Definition ccf_acme_client.h:41
std::shared_ptr< ACMERpcFrontend > challenge_frontend
Definition ccf_acme_client.h:70
DefaultChallengeHandler(std::shared_ptr< ACMERpcFrontend > challenge_frontend)
Definition ccf_acme_client.h:43
virtual void remove(const std::string &token) override
Definition ccf_acme_client.h:60
virtual bool ready(const std::string &token) override
Definition ccf_acme_client.h:49
Definition ccf_acme_client.h:37
std::shared_ptr< ccf::kv::Store > store
Definition ccf_acme_client.h:146
std::shared_ptr< ACMEChallengeHandler > challenge_handler
Definition ccf_acme_client.h:147
virtual void on_challenge(const std::string &token, const std::string &response) override
Definition ccf_acme_client.h:198
virtual void check_expiry(std::shared_ptr< ccf::kv::Store > tables, std::unique_ptr< NetworkIdentity > &identity)
Definition ccf_acme_client.h:107
virtual ~ACMEClient()
Definition ccf_acme_client.h:98
virtual void on_challenge_finished(const std::string &token) override
Definition ccf_acme_client.h:233
virtual void on_http_request(const ::http::URL &url, ::http::Request &&req, std::function< bool(ccf::http_status status, http::HeaderMap &&, std::vector< uint8_t > &&)> callback) override
Definition ccf_acme_client.h:160
std::string config_name
Definition ccf_acme_client.h:142
std::shared_ptr< ACMERpcFrontend > challenge_frontend
Definition ccf_acme_client.h:145
virtual void on_certificate(const std::string &certificate) override
Definition ccf_acme_client.h:241
virtual void set_account_key(std::shared_ptr< ccf::crypto::KeyPair > new_account_key_pair) override
Definition ccf_acme_client.h:100
ACMEClient(const std::string &config_name, const ACMEClientConfig &config, std::shared_ptr< RPCMap > rpc_map, std::shared_ptr< RPCSessions > rpc_sessions, std::shared_ptr< ACMERpcFrontend > challenge_frontend, std::shared_ptr< ccf::kv::Store > store, std::shared_ptr< ccf::crypto::KeyPair > account_key_pair=nullptr, std::shared_ptr< ACMEChallengeHandler > challenge_handler_=nullptr)
Definition ccf_acme_client.h:74
std::shared_ptr< RPCMap > rpc_map
Definition ccf_acme_client.h:143
void install_wildcard_response()
Definition ccf_acme_client.h:149
std::shared_ptr< RPCSessions > rpc_sessions
Definition ccf_acme_client.h:144
virtual void install_custom_challenge_handler(std::shared_ptr< ACMEChallengeHandler > h)
Definition ccf_acme_client.h:134
Definition pem.h:18
Definition map.h:30
Definition http_builder.h:118
#define LOG_TRACE_FMT
Definition logger.h:356
Definition acme_client.h:30
VerifierPtr make_verifier(const std::vector< uint8_t > &cert)
Definition verifier.cpp:18
std::map< std::string, std::string, std::less<> > HeaderMap
Definition http_header_map.h:10
Definition app_interface.h:14
llhttp_status http_status
Definition http_status.h:9
Definition perf_client.h:12
Definition thread_messaging.h:14
Definition acme_client.h:32
std::vector< std::string > ca_certs
Definition acme_client.h:35
Definition acme_client_config.h:14
Definition ccf_acme_client.h:184
std::string token
Definition ccf_acme_client.h:195
std::shared_ptr< ACMEChallengeHandler > handler
Definition ccf_acme_client.h:194
ACMEClientMsg(ACMEClient &client, const std::shared_ptr< ACMEChallengeHandler > handler, const std::string &token)
Definition ccf_acme_client.h:185
ACMEClient & client
Definition ccf_acme_client.h:193