]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/include/seastar/net/tls.hh
import quincy beta 17.1.0
[ceph.git] / ceph / src / seastar / include / seastar / net / tls.hh
1 /*
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18 /*
19 * Copyright 2015 Cloudius Systems
20 */
21 #pragma once
22
23 #include <functional>
24 #include <unordered_set>
25
26 #include <boost/any.hpp>
27
28 #include <seastar/core/future.hh>
29 #include <seastar/core/sstring.hh>
30 #include <seastar/core/shared_ptr.hh>
31 #include <seastar/net/socket_defs.hh>
32 #include <seastar/util/std-compat.hh>
33 #include <seastar/net/api.hh>
34 #include "../core/internal/api-level.hh"
35
36 namespace seastar {
37
38 class socket;
39
40 class server_socket;
41 class connected_socket;
42 class socket_address;
43
44 /**
45 * Relatively thin SSL wrapper for socket IO.
46 * (Can be expanded to other IO forms).
47 *
48 * The current underlying mechanism is
49 * gnutls, however, all interfaces are kept
50 * agnostic, so in theory it could be replaced
51 * with OpenSSL or similar.
52 *
53 */
54 namespace tls {
55 enum class x509_crt_format {
56 DER,
57 PEM,
58 };
59
60 typedef std::basic_string_view<char> blob;
61
62 class session;
63 class server_session;
64 class server_credentials;
65 class certificate_credentials;
66 class credentials_builder;
67
68 /**
69 * Diffie-Hellman parameters for
70 * wire encryption.
71 */
72 class dh_params {
73 public:
74 // Key strength
75 enum class level {
76 LEGACY = 2,
77 MEDIUM = 3,
78 HIGH = 4,
79 ULTRA = 5
80 };
81 dh_params(level = level::LEGACY);
82 // loads a key from data
83 dh_params(const blob&, x509_crt_format);
84 ~dh_params();
85
86 dh_params(dh_params&&) noexcept;
87 dh_params& operator=(dh_params&&) noexcept;
88
89 dh_params(const dh_params&) = delete;
90 dh_params& operator=(const dh_params&) = delete;
91
92 /** loads a key from file */
93 static future<dh_params> from_file(const sstring&, x509_crt_format);
94 private:
95 class impl;
96 friend class server_credentials;
97 friend class certificate_credentials;
98 std::unique_ptr<impl> _impl;
99 };
100
101 class x509_cert {
102 x509_cert(const blob&, x509_crt_format);
103
104 static future<x509_cert> from_file(const sstring&, x509_crt_format);
105 private:
106 class impl;
107 x509_cert(shared_ptr<impl>);
108 shared_ptr<impl> _impl;
109 };
110
111 class abstract_credentials {
112 public:
113 virtual ~abstract_credentials() {};
114
115 virtual void set_x509_trust(const blob&, x509_crt_format) = 0;
116 virtual void set_x509_crl(const blob&, x509_crt_format) = 0;
117 virtual void set_x509_key(const blob& cert, const blob& key, x509_crt_format) = 0;
118
119 virtual void set_simple_pkcs12(const blob&, x509_crt_format, const sstring& password) = 0;
120
121 virtual future<> set_x509_trust_file(const sstring& cafile, x509_crt_format);
122 virtual future<> set_x509_crl_file(const sstring& crlfile, x509_crt_format);
123 virtual future<> set_x509_key_file(const sstring& cf, const sstring& kf, x509_crt_format);
124
125 virtual future<> set_simple_pkcs12_file(const sstring& pkcs12file, x509_crt_format, const sstring& password);
126 };
127
128 template<typename Base>
129 class reloadable_credentials;
130
131 /**
132 * Enum like tls::session::type but independent of gnutls headers
133 *
134 * \warning Uses a different internal encoding than tls::session::type
135 */
136 enum class session_type {
137 CLIENT, SERVER,
138 };
139
140 /**
141 * Callback prototype for receiving Distinguished Name (DN) information
142 *
143 * \param type Our own role in the TLS handshake (client vs. server)
144 * \param subject The subject DN string
145 * \param issuer The issuer DN string
146 */
147 using dn_callback = noncopyable_function<void(session_type type, sstring subject, sstring issuer)>;
148
149 /**
150 * Holds certificates and keys.
151 *
152 * Typically, credentials are shared for multiple client/server
153 * sessions. Changes to the credentials object will affect all
154 * sessions instantiated with it.
155 * You should probably set it up once, before starting client/server
156 * connections.
157 */
158 class certificate_credentials : public abstract_credentials {
159 public:
160 certificate_credentials();
161 ~certificate_credentials();
162
163 certificate_credentials(certificate_credentials&&) noexcept;
164 certificate_credentials& operator=(certificate_credentials&&) noexcept;
165
166 certificate_credentials(const certificate_credentials&) = delete;
167 certificate_credentials& operator=(const certificate_credentials&) = delete;
168
169 void set_x509_trust(const blob&, x509_crt_format) override;
170 void set_x509_crl(const blob&, x509_crt_format) override;
171 void set_x509_key(const blob& cert, const blob& key, x509_crt_format) override;
172 void set_simple_pkcs12(const blob&, x509_crt_format, const sstring& password) override;
173
174 /**
175 * Loads default system cert trust file
176 * into this object.
177 */
178 future<> set_system_trust();
179
180 // TODO add methods for certificate verification
181
182 /**
183 * TLS handshake priority string. See gnutls docs and syntax at
184 * https://gnutls.org/manual/html_node/Priority-Strings.html
185 *
186 * Allows specifying order and allowance for handshake alg.
187 */
188 void set_priority_string(const sstring&);
189
190 /**
191 * Register a callback for receiving Distinguished Name (DN) information
192 * during the TLS handshake, extracted from the certificate as sent by the peer.
193 *
194 * The callback is not invoked in case the peer did not send a certificate.
195 * (This could e.g. happen when we are the server, and a client connects while
196 * client_auth is not set to REQUIRE.)
197 *
198 * If, based upon the extracted DN information, you want to abort the handshake,
199 * then simply throw an exception (e.g., from the callback) like verification_error.
200 *
201 * Registering this callback does not bypass the 'standard' certificate verification
202 * procedure; instead it merely extracts the DN information from the peer certificate
203 * (i.e., the 'leaf' certificate from the chain of certificates sent by the peer)
204 * and allows for extra checks.
205 *
206 * To keep the API simple, you can unregister the callback by means of registering
207 * an empty callback, i.e. dn_callback{}
208 *
209 * The callback prototype is documented in the dn_callback typedef.
210 */
211 void set_dn_verification_callback(dn_callback);
212
213 private:
214 class impl;
215 friend class session;
216 friend class server_session;
217 friend class server_credentials;
218 friend class credentials_builder;
219 template<typename Base>
220 friend class reloadable_credentials;
221 shared_ptr<impl> _impl;
222 };
223
224 /** Exception thrown on certificate validation error */
225 class verification_error : public std::runtime_error {
226 public:
227 using runtime_error::runtime_error;
228 };
229
230 enum class client_auth {
231 NONE, REQUEST, REQUIRE
232 };
233
234 /**
235 * Extending certificates and keys for server usage.
236 * More probably goes in here...
237 */
238 class server_credentials : public certificate_credentials {
239 public:
240 server_credentials();
241 server_credentials(shared_ptr<dh_params>);
242 server_credentials(const dh_params&);
243
244 server_credentials(server_credentials&&) noexcept;
245 server_credentials& operator=(server_credentials&&) noexcept;
246
247 server_credentials(const server_credentials&) = delete;
248 server_credentials& operator=(const server_credentials&) = delete;
249
250 void set_client_auth(client_auth);
251 };
252
253 class reloadable_credentials_base;
254
255 using reload_callback = std::function<void(const std::unordered_set<sstring>&, std::exception_ptr)>;
256
257 /**
258 * Intentionally "primitive", and more importantly, copyable
259 * container for certificate credentials options.
260 * The intendend use case is to be able to use across shards,
261 * at, say, initialization of tls objects
262 *
263 * Note that loading invalid objects (malformed certs etc) will
264 * _not_ generate exceptions until, earliest, the build functions
265 * are called.
266 */
267 class credentials_builder : public abstract_credentials {
268 public:
269 void set_dh_level(dh_params::level = dh_params::level::LEGACY);
270
271 void set_x509_trust(const blob&, x509_crt_format) override ;
272 void set_x509_crl(const blob&, x509_crt_format) override;
273 void set_x509_key(const blob& cert, const blob& key, x509_crt_format) override;
274 void set_simple_pkcs12(const blob&, x509_crt_format, const sstring& password) override;
275
276 future<> set_x509_trust_file(const sstring& cafile, x509_crt_format) override;
277 future<> set_x509_crl_file(const sstring& crlfile, x509_crt_format) override;
278 future<> set_x509_key_file(const sstring& cf, const sstring& kf, x509_crt_format) override;
279 future<> set_simple_pkcs12_file(const sstring& pkcs12file, x509_crt_format, const sstring& password) override;
280
281 future<> set_system_trust();
282 void set_client_auth(client_auth);
283 void set_priority_string(const sstring&);
284
285 void apply_to(certificate_credentials&) const;
286
287 shared_ptr<certificate_credentials> build_certificate_credentials() const;
288 shared_ptr<server_credentials> build_server_credentials() const;
289
290 // same as above, but any files used for certs/keys etc will be watched
291 // for modification and reloaded if changed
292 future<shared_ptr<certificate_credentials>> build_reloadable_certificate_credentials(reload_callback = {}, std::optional<std::chrono::milliseconds> tolerance = {}) const;
293 future<shared_ptr<server_credentials>> build_reloadable_server_credentials(reload_callback = {}, std::optional<std::chrono::milliseconds> tolerance = {}) const;
294 private:
295 friend class reloadable_credentials_base;
296
297 std::multimap<sstring, boost::any> _blobs;
298 client_auth _client_auth = client_auth::NONE;
299 sstring _priority;
300 };
301
302 /**
303 * Creates a TLS client connection using the default network stack and the
304 * supplied credentials.
305 * Typically these should contain enough information
306 * to validate the remote certificate (i.e. trust info).
307 *
308 * \param name An optional expected server name for the remote end point
309 */
310 /// @{
311 future<connected_socket> connect(shared_ptr<certificate_credentials>, socket_address, sstring name = {});
312 future<connected_socket> connect(shared_ptr<certificate_credentials>, socket_address, socket_address local, sstring name = {});
313 /// @}
314
315 /**
316 * Creates a socket through which a TLS client connection can be created,
317 * using the default network stack and the supplied credentials.
318 * Typically these should contain enough information
319 * to validate the remote certificate (i.e. trust info).
320 *
321 * \param name An optional expected server name for the remote end point
322 */
323 /// @{
324 ::seastar::socket socket(shared_ptr<certificate_credentials>, sstring name = {});
325 /// @}
326
327 /** Wraps an existing connection in SSL/TLS. */
328 /// @{
329 future<connected_socket> wrap_client(shared_ptr<certificate_credentials>, connected_socket&&, sstring name = {});
330 future<connected_socket> wrap_server(shared_ptr<server_credentials>, connected_socket&&);
331 /// @}
332
333 /**
334 * Creates a server socket that accepts SSL/TLS clients using default network stack
335 * and the supplied credentials.
336 * The credentials object should contain certificate info
337 * for the server and optionally trust/crl data.
338 */
339 /// @{
340 server_socket listen(shared_ptr<server_credentials>, socket_address sa, listen_options opts = listen_options());
341 // Wraps an existing server socket in SSL
342 server_socket listen(shared_ptr<server_credentials>, server_socket);
343 /// @}
344 }
345 }
346