/src/openvswitch/lib/stream-ssl.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2008-2016, 2019 Nicira, Inc. |
3 | | * |
4 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | * you may not use this file except in compliance with the License. |
6 | | * You may obtain a copy of the License at: |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | #include <config.h> |
18 | | #include "stream-ssl.h" |
19 | | #include "dhparams.h" |
20 | | #include <ctype.h> |
21 | | #include <errno.h> |
22 | | #include <inttypes.h> |
23 | | #include <string.h> |
24 | | #include <sys/types.h> |
25 | | #include <sys/socket.h> |
26 | | #include <netinet/tcp.h> |
27 | | #include <openssl/err.h> |
28 | | #include <openssl/rand.h> |
29 | | #include <openssl/ssl.h> |
30 | | #include <openssl/x509v3.h> |
31 | | #include <poll.h> |
32 | | #include <fcntl.h> |
33 | | #include <sys/stat.h> |
34 | | #include <unistd.h> |
35 | | #include "bitmap.h" |
36 | | #include "coverage.h" |
37 | | #include "openvswitch/dynamic-string.h" |
38 | | #include "entropy.h" |
39 | | #include "openvswitch/ofpbuf.h" |
40 | | #include "openflow/openflow.h" |
41 | | #include "packets.h" |
42 | | #include "openvswitch/poll-loop.h" |
43 | | #include "openvswitch/shash.h" |
44 | | #include "socket-util.h" |
45 | | #include "util.h" |
46 | | #include "sset.h" |
47 | | #include "stream-provider.h" |
48 | | #include "stream.h" |
49 | | #include "timeval.h" |
50 | | #include "openvswitch/vlog.h" |
51 | | |
52 | | #ifdef _WIN32 |
53 | | /* Ref: https://www.openssl.org/support/faq.html#PROG2 |
54 | | * Your application must link against the same version of the Win32 C-Runtime |
55 | | * against which your openssl libraries were linked. The default version for |
56 | | * OpenSSL is /MD - "Multithreaded DLL". If we compile Open vSwitch with |
57 | | * something other than /MD, instead of re-compiling OpenSSL |
58 | | * toolkit, openssl/applink.c can be #included. Also, it is important |
59 | | * to add CRYPTO_malloc_init prior first call to OpenSSL. |
60 | | * |
61 | | * XXX: The behavior of the following #include when Open vSwitch is |
62 | | * compiled with /MD is not tested. */ |
63 | | #include <openssl/applink.c> |
64 | | #define SHUT_RDWR SD_BOTH |
65 | | #endif |
66 | | |
67 | | VLOG_DEFINE_THIS_MODULE(stream_ssl); |
68 | | |
69 | | /* Active SSL/TLS. */ |
70 | | |
71 | | enum ssl_state { |
72 | | STATE_TCP_CONNECTING, |
73 | | STATE_SSL_CONNECTING |
74 | | }; |
75 | | |
76 | | enum session_type { |
77 | | CLIENT, |
78 | | SERVER |
79 | | }; |
80 | | |
81 | | struct ssl_stream |
82 | | { |
83 | | struct stream stream; |
84 | | enum ssl_state state; |
85 | | enum session_type type; |
86 | | int fd; |
87 | | SSL *ssl; |
88 | | struct ofpbuf *txbuf; |
89 | | unsigned int session_nr; |
90 | | |
91 | | /* rx_want and tx_want record the result of the last call to SSL_read() |
92 | | * and SSL_write(), respectively: |
93 | | * |
94 | | * - If the call reported that data needed to be read from the file |
95 | | * descriptor, the corresponding member is set to SSL_READING. |
96 | | * |
97 | | * - If the call reported that data needed to be written to the file |
98 | | * descriptor, the corresponding member is set to SSL_WRITING. |
99 | | * |
100 | | * - Otherwise, the member is set to SSL_NOTHING, indicating that the |
101 | | * call completed successfully (or with an error) and that there is no |
102 | | * need to block. |
103 | | * |
104 | | * These are needed because there is no way to ask OpenSSL what a data read |
105 | | * or write would require without giving it a buffer to receive into or |
106 | | * data to send, respectively. (Note that the SSL_want() status is |
107 | | * overwritten by each SSL_read() or SSL_write() call, so we can't rely on |
108 | | * its value.) |
109 | | * |
110 | | * A single call to SSL_read() or SSL_write() can perform both reading |
111 | | * and writing and thus invalidate not one of these values but actually |
112 | | * both. Consider this situation, for example: |
113 | | * |
114 | | * - SSL_write() blocks on a read, so tx_want gets SSL_READING. |
115 | | * |
116 | | * - SSL_read() laters succeeds reading from 'fd' and clears out the |
117 | | * whole receive buffer, so rx_want gets SSL_READING. |
118 | | * |
119 | | * - Client calls stream_wait(STREAM_RECV) and stream_wait(STREAM_SEND) |
120 | | * and blocks. |
121 | | * |
122 | | * - Now we're stuck blocking until the peer sends us data, even though |
123 | | * SSL_write() could now succeed, which could easily be a deadlock |
124 | | * condition. |
125 | | * |
126 | | * On the other hand, we can't reset both tx_want and rx_want on every call |
127 | | * to SSL_read() or SSL_write(), because that would produce livelock, |
128 | | * e.g. in this situation: |
129 | | * |
130 | | * - SSL_write() blocks, so tx_want gets SSL_READING or SSL_WRITING. |
131 | | * |
132 | | * - SSL_read() blocks, so rx_want gets SSL_READING or SSL_WRITING, |
133 | | * but tx_want gets reset to SSL_NOTHING. |
134 | | * |
135 | | * - Client calls stream_wait(STREAM_RECV) and stream_wait(STREAM_SEND) |
136 | | * and blocks. |
137 | | * |
138 | | * - Client wakes up immediately since SSL_NOTHING in tx_want indicates |
139 | | * that no blocking is necessary. |
140 | | * |
141 | | * The solution we adopt here is to set tx_want to SSL_NOTHING after |
142 | | * calling SSL_read() only if the SSL state of the connection changed, |
143 | | * which indicates that an SSL-level renegotiation made some progress, and |
144 | | * similarly for rx_want and SSL_write(). This prevents both the |
145 | | * deadlock and livelock situations above. |
146 | | */ |
147 | | int rx_want, tx_want; |
148 | | |
149 | | /* A few bytes of header data in case SSL negotiation fails. */ |
150 | | uint8_t head[2]; |
151 | | short int n_head; |
152 | | }; |
153 | | |
154 | | /* SSL context created by ssl_init(). */ |
155 | | static SSL_CTX *ctx; |
156 | | |
157 | | struct ssl_config_file { |
158 | | bool read; /* Whether the file was successfully read. */ |
159 | | char *file_name; /* Configured file name, if any. */ |
160 | | struct timespec mtime; /* File mtime as of last time we read it. */ |
161 | | }; |
162 | | |
163 | | /* SSL configuration files. */ |
164 | | static struct ssl_config_file private_key; |
165 | | static struct ssl_config_file certificate; |
166 | | static struct ssl_config_file ca_cert; |
167 | | static char *ssl_protocols = "TLSv1.2+"; |
168 | | static char *ssl_ciphers = "DEFAULT:@SECLEVEL=2"; |
169 | | static char *ssl_ciphersuites = ""; /* Using default ones, unless specified. */ |
170 | | |
171 | | /* Ordinarily, the SSL client and server verify each other's certificates using |
172 | | * a CA certificate. Setting this to false disables this behavior. (This is a |
173 | | * security risk.) */ |
174 | | static bool verify_peer_cert = true; |
175 | | |
176 | | /* Ordinarily, we require a CA certificate for the peer to be locally |
177 | | * available. We can, however, bootstrap the CA certificate from the peer at |
178 | | * the beginning of our first connection then use that certificate on all |
179 | | * subsequent connections, saving it to a file for use in future runs also. In |
180 | | * this case, 'bootstrap_ca_cert' is true. */ |
181 | | static bool bootstrap_ca_cert; |
182 | | |
183 | | /* Session number. Used in debug logging messages to uniquely identify a |
184 | | * session. */ |
185 | | static unsigned int next_session_nr; |
186 | | |
187 | | /* Who knows what can trigger various SSL errors, so let's throttle them down |
188 | | * quite a bit. */ |
189 | | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 25); |
190 | | |
191 | | static int ssl_init(void); |
192 | | static int do_ssl_init(void); |
193 | | static bool ssl_wants_io(int ssl_error); |
194 | | static void ssl_close(struct stream *); |
195 | | static void ssl_clear_txbuf(struct ssl_stream *); |
196 | | static void interpret_queued_ssl_error(const char *function); |
197 | | static int interpret_ssl_error(const char *function, int ret, int error, |
198 | | int *want); |
199 | | #if OPENSSL_VERSION_NUMBER < 0x3000000fL |
200 | | static DH *tmp_dh_callback(SSL *ssl, int is_export OVS_UNUSED, int keylength); |
201 | | #endif |
202 | | static void log_ca_cert(const char *file_name, X509 *cert); |
203 | | static void stream_ssl_set_ca_cert_file__(const char *file_name, |
204 | | bool bootstrap, bool force); |
205 | | static void ssl_protocol_cb(int write_p, int version, int content_type, |
206 | | const void *, size_t, SSL *, void *sslv_); |
207 | | static bool update_ssl_config(struct ssl_config_file *, const char *file_name); |
208 | | static int sock_errno(void); |
209 | | |
210 | | static short int |
211 | | want_to_poll_events(int want) |
212 | 0 | { |
213 | 0 | switch (want) { |
214 | 0 | case SSL_NOTHING: |
215 | 0 | OVS_NOT_REACHED(); |
216 | | |
217 | 0 | case SSL_READING: |
218 | 0 | return POLLIN; |
219 | | |
220 | 0 | case SSL_WRITING: |
221 | 0 | return POLLOUT; |
222 | | |
223 | 0 | default: |
224 | 0 | OVS_NOT_REACHED(); |
225 | 0 | } |
226 | 0 | } |
227 | | |
228 | | /* Creates a new SSL connection based on socket 'fd', as either a client or a |
229 | | * server according to 'type', initially in 'state'. On success, returns 0 and |
230 | | * stores the new stream in '*streamp', otherwise returns an errno value and |
231 | | * doesn't bother with '*streamp'. |
232 | | * |
233 | | * Takes ownership of 'name', which should be the name of the connection in the |
234 | | * format that would be used to connect to it, e.g. "ssl:1.2.3.4:5". |
235 | | * |
236 | | * For client connections, 'server_name' should be the host name of the server |
237 | | * being connected to, for use with SSL SNI (server name indication). Takes |
238 | | * ownership of 'server_name'. */ |
239 | | static int |
240 | | new_ssl_stream(char *name, char *server_name, int fd, enum session_type type, |
241 | | enum ssl_state state, struct stream **streamp) |
242 | 0 | { |
243 | 0 | struct ssl_stream *sslv; |
244 | 0 | SSL *ssl = NULL; |
245 | 0 | int retval; |
246 | | |
247 | | /* Check for all the needful configuration. */ |
248 | 0 | retval = 0; |
249 | 0 | if (!private_key.read) { |
250 | 0 | VLOG_ERR("Private key must be configured to use SSL"); |
251 | 0 | retval = ENOPROTOOPT; |
252 | 0 | } |
253 | 0 | if (!certificate.read) { |
254 | 0 | VLOG_ERR("Certificate must be configured to use SSL"); |
255 | 0 | retval = ENOPROTOOPT; |
256 | 0 | } |
257 | 0 | if (!ca_cert.read && verify_peer_cert && !bootstrap_ca_cert) { |
258 | 0 | VLOG_ERR("CA certificate must be configured to use SSL"); |
259 | 0 | retval = ENOPROTOOPT; |
260 | 0 | } |
261 | 0 | if (!retval && !SSL_CTX_check_private_key(ctx)) { |
262 | 0 | VLOG_ERR("Private key does not match certificate public key: %s", |
263 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
264 | 0 | retval = ENOPROTOOPT; |
265 | 0 | } |
266 | 0 | if (retval) { |
267 | 0 | goto error; |
268 | 0 | } |
269 | | |
270 | | /* Disable Nagle. |
271 | | * On windows platforms, this can only be called upon TCP connected. |
272 | | */ |
273 | 0 | if (state == STATE_SSL_CONNECTING) { |
274 | 0 | setsockopt_tcp_nodelay(fd); |
275 | 0 | } |
276 | | |
277 | | /* Create and configure OpenSSL stream. */ |
278 | 0 | ssl = SSL_new(ctx); |
279 | 0 | if (ssl == NULL) { |
280 | 0 | VLOG_ERR("SSL_new: %s", ERR_error_string(ERR_get_error(), NULL)); |
281 | 0 | retval = ENOPROTOOPT; |
282 | 0 | goto error; |
283 | 0 | } |
284 | 0 | if (SSL_set_fd(ssl, fd) == 0) { |
285 | 0 | VLOG_ERR("SSL_set_fd: %s", ERR_error_string(ERR_get_error(), NULL)); |
286 | 0 | retval = ENOPROTOOPT; |
287 | 0 | goto error; |
288 | 0 | } |
289 | 0 | if (!verify_peer_cert || (bootstrap_ca_cert && type == CLIENT)) { |
290 | 0 | SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL); |
291 | 0 | } |
292 | 0 | if (server_name && !SSL_set_tlsext_host_name(ssl, server_name)) { |
293 | 0 | VLOG_ERR("%s: failed to set server name indication (%s)", |
294 | 0 | server_name, ERR_error_string(ERR_get_error(), NULL)); |
295 | 0 | retval = ENOPROTOOPT; |
296 | 0 | goto error; |
297 | 0 | } |
298 | | |
299 | | /* Create and return the ssl_stream. */ |
300 | 0 | sslv = xmalloc(sizeof *sslv); |
301 | 0 | stream_init(&sslv->stream, &ssl_stream_class, EAGAIN, name); |
302 | 0 | sslv->state = state; |
303 | 0 | sslv->type = type; |
304 | 0 | sslv->fd = fd; |
305 | 0 | sslv->ssl = ssl; |
306 | 0 | sslv->txbuf = NULL; |
307 | 0 | sslv->rx_want = sslv->tx_want = SSL_NOTHING; |
308 | 0 | sslv->session_nr = next_session_nr++; |
309 | 0 | sslv->n_head = 0; |
310 | |
|
311 | 0 | if (VLOG_IS_DBG_ENABLED()) { |
312 | 0 | SSL_set_msg_callback(ssl, ssl_protocol_cb); |
313 | 0 | SSL_set_msg_callback_arg(ssl, sslv); |
314 | 0 | } |
315 | |
|
316 | 0 | *streamp = &sslv->stream; |
317 | 0 | free(server_name); |
318 | 0 | return 0; |
319 | | |
320 | 0 | error: |
321 | 0 | if (ssl) { |
322 | 0 | SSL_free(ssl); |
323 | 0 | } |
324 | 0 | closesocket(fd); |
325 | 0 | free(name); |
326 | 0 | free(server_name); |
327 | 0 | return retval; |
328 | 0 | } |
329 | | |
330 | | static struct ssl_stream * |
331 | | ssl_stream_cast(struct stream *stream) |
332 | 0 | { |
333 | 0 | stream_assert_class(stream, &ssl_stream_class); |
334 | 0 | return CONTAINER_OF(stream, struct ssl_stream, stream); |
335 | 0 | } |
336 | | |
337 | | /* Extracts and returns the server name from 'suffix'. The caller must |
338 | | * eventually free it. |
339 | | * |
340 | | * Returns NULL if there is no server name, and particularly if it is an IP |
341 | | * address rather than a host name, since RFC 3546 is explicit that IP |
342 | | * addresses are unsuitable as server name indication (SNI). */ |
343 | | static char * |
344 | | get_server_name(const char *suffix_) |
345 | 0 | { |
346 | 0 | char *suffix = xstrdup(suffix_); |
347 | |
|
348 | 0 | char *host, *port; |
349 | 0 | inet_parse_host_port_tokens(suffix, &host, &port); |
350 | |
|
351 | 0 | ovs_be32 ipv4; |
352 | 0 | struct in6_addr ipv6; |
353 | 0 | char *server_name = (ip_parse(host, &ipv4) || ipv6_parse(host, &ipv6) |
354 | 0 | ? NULL : xstrdup(host)); |
355 | |
|
356 | 0 | free(suffix); |
357 | |
|
358 | 0 | return server_name; |
359 | 0 | } |
360 | | |
361 | | static int |
362 | | ssl_open(const char *name, char *suffix, struct stream **streamp, uint8_t dscp) |
363 | 0 | { |
364 | 0 | int error, fd; |
365 | |
|
366 | 0 | error = ssl_init(); |
367 | 0 | if (error) { |
368 | 0 | return error; |
369 | 0 | } |
370 | | |
371 | 0 | error = inet_open_active(SOCK_STREAM, suffix, OFP_PORT, NULL, &fd, |
372 | 0 | dscp); |
373 | 0 | if (fd >= 0) { |
374 | 0 | int state = error ? STATE_TCP_CONNECTING : STATE_SSL_CONNECTING; |
375 | 0 | return new_ssl_stream(xstrdup(name), get_server_name(suffix), |
376 | 0 | fd, CLIENT, state, streamp); |
377 | 0 | } else { |
378 | 0 | VLOG_ERR("%s: connect: %s", name, ovs_strerror(error)); |
379 | 0 | return error; |
380 | 0 | } |
381 | 0 | } |
382 | | |
383 | | static int |
384 | | do_ca_cert_bootstrap(struct stream *stream) |
385 | 0 | { |
386 | 0 | struct ssl_stream *sslv = ssl_stream_cast(stream); |
387 | 0 | STACK_OF(X509) *chain; |
388 | 0 | X509 *cert; |
389 | 0 | FILE *file; |
390 | 0 | int error; |
391 | 0 | int fd; |
392 | |
|
393 | 0 | chain = SSL_get_peer_cert_chain(sslv->ssl); |
394 | 0 | if (!chain || !sk_X509_num(chain)) { |
395 | 0 | VLOG_ERR("could not bootstrap CA cert: no certificate presented by " |
396 | 0 | "peer"); |
397 | 0 | return EPROTO; |
398 | 0 | } |
399 | 0 | cert = sk_X509_value(chain, sk_X509_num(chain) - 1); |
400 | | |
401 | | /* Check that 'cert' is self-signed. Otherwise it is not a CA |
402 | | * certificate and we should not attempt to use it as one. */ |
403 | 0 | error = X509_check_issued(cert, cert); |
404 | 0 | if (error) { |
405 | 0 | VLOG_ERR("could not bootstrap CA cert: obtained certificate is " |
406 | 0 | "not self-signed (%s)", |
407 | 0 | X509_verify_cert_error_string(error)); |
408 | 0 | if (sk_X509_num(chain) < 2) { |
409 | 0 | VLOG_ERR("only one certificate was received, so probably the peer " |
410 | 0 | "is not configured to send its CA certificate"); |
411 | 0 | } |
412 | 0 | return EPROTO; |
413 | 0 | } |
414 | | |
415 | 0 | fd = open(ca_cert.file_name, O_CREAT | O_EXCL | O_WRONLY, 0444); |
416 | 0 | if (fd < 0) { |
417 | 0 | if (errno == EEXIST) { |
418 | 0 | VLOG_INFO_RL(&rl, "reading CA cert %s created by another process", |
419 | 0 | ca_cert.file_name); |
420 | 0 | stream_ssl_set_ca_cert_file__(ca_cert.file_name, true, true); |
421 | 0 | return EPROTO; |
422 | 0 | } else { |
423 | 0 | VLOG_ERR("could not bootstrap CA cert: creating %s failed: %s", |
424 | 0 | ca_cert.file_name, ovs_strerror(errno)); |
425 | 0 | return errno; |
426 | 0 | } |
427 | 0 | } |
428 | | |
429 | 0 | file = fdopen(fd, "w"); |
430 | 0 | if (!file) { |
431 | 0 | error = errno; |
432 | 0 | VLOG_ERR("could not bootstrap CA cert: fdopen failed: %s", |
433 | 0 | ovs_strerror(error)); |
434 | 0 | unlink(ca_cert.file_name); |
435 | 0 | return error; |
436 | 0 | } |
437 | | |
438 | 0 | if (!PEM_write_X509(file, cert)) { |
439 | 0 | VLOG_ERR("could not bootstrap CA cert: PEM_write_X509 to %s failed: " |
440 | 0 | "%s", ca_cert.file_name, |
441 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
442 | 0 | fclose(file); |
443 | 0 | unlink(ca_cert.file_name); |
444 | 0 | return EIO; |
445 | 0 | } |
446 | | |
447 | 0 | if (fclose(file)) { |
448 | 0 | error = errno; |
449 | 0 | VLOG_ERR("could not bootstrap CA cert: writing %s failed: %s", |
450 | 0 | ca_cert.file_name, ovs_strerror(error)); |
451 | 0 | unlink(ca_cert.file_name); |
452 | 0 | return error; |
453 | 0 | } |
454 | | |
455 | 0 | VLOG_INFO("successfully bootstrapped CA cert to %s", ca_cert.file_name); |
456 | 0 | log_ca_cert(ca_cert.file_name, cert); |
457 | 0 | bootstrap_ca_cert = false; |
458 | 0 | ca_cert.read = true; |
459 | | |
460 | | /* SSL_CTX_add_client_CA makes a copy of cert's relevant data. */ |
461 | 0 | SSL_CTX_add_client_CA(ctx, cert); |
462 | |
|
463 | 0 | SSL_CTX_set_cert_store(ctx, X509_STORE_new()); |
464 | 0 | if (SSL_CTX_load_verify_locations(ctx, ca_cert.file_name, NULL) != 1) { |
465 | 0 | VLOG_ERR("SSL_CTX_load_verify_locations: %s", |
466 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
467 | 0 | return EPROTO; |
468 | 0 | } |
469 | 0 | VLOG_INFO("killing successful connection to retry using CA cert"); |
470 | 0 | return EPROTO; |
471 | 0 | } |
472 | | |
473 | | static char * |
474 | | get_peer_common_name(const struct ssl_stream *sslv) |
475 | 0 | { |
476 | 0 | char *peer_name = NULL; |
477 | 0 | #if OPENSSL_VERSION_NUMBER < 0x3000000fL |
478 | 0 | X509 *peer_cert = SSL_get_peer_certificate(sslv->ssl); |
479 | | #else |
480 | | X509 *peer_cert = SSL_get1_peer_certificate(sslv->ssl); |
481 | | #endif |
482 | 0 | if (!peer_cert) { |
483 | 0 | return NULL; |
484 | 0 | } |
485 | | |
486 | 0 | int cn_index = X509_NAME_get_index_by_NID(X509_get_subject_name(peer_cert), |
487 | 0 | NID_commonName, -1); |
488 | 0 | if (cn_index < 0) { |
489 | 0 | goto error; |
490 | 0 | } |
491 | | |
492 | 0 | X509_NAME_ENTRY *cn_entry = X509_NAME_get_entry( |
493 | 0 | X509_get_subject_name(peer_cert), cn_index); |
494 | 0 | if (!cn_entry) { |
495 | 0 | goto error; |
496 | 0 | } |
497 | | |
498 | 0 | ASN1_STRING *cn_data = X509_NAME_ENTRY_get_data(cn_entry); |
499 | 0 | if (!cn_data) { |
500 | 0 | goto error; |
501 | 0 | } |
502 | | |
503 | 0 | peer_name = xstrdup((const char *) ASN1_STRING_get0_data(cn_data)); |
504 | |
|
505 | 0 | error: |
506 | 0 | X509_free(peer_cert); |
507 | 0 | return peer_name; |
508 | 0 | } |
509 | | |
510 | | static int |
511 | | ssl_connect(struct stream *stream) |
512 | 0 | { |
513 | 0 | struct ssl_stream *sslv = ssl_stream_cast(stream); |
514 | 0 | int retval; |
515 | |
|
516 | 0 | switch (sslv->state) { |
517 | 0 | case STATE_TCP_CONNECTING: |
518 | 0 | retval = check_connection_completion(sslv->fd); |
519 | 0 | if (retval) { |
520 | 0 | return retval; |
521 | 0 | } |
522 | 0 | sslv->state = STATE_SSL_CONNECTING; |
523 | 0 | setsockopt_tcp_nodelay(sslv->fd); |
524 | | /* Fall through. */ |
525 | |
|
526 | 0 | case STATE_SSL_CONNECTING: |
527 | | /* Capture the first few bytes of received data so that we can guess |
528 | | * what kind of funny data we've been sent if SSL negotiation fails. */ |
529 | 0 | if (sslv->n_head <= 0) { |
530 | 0 | sslv->n_head = recv(sslv->fd, sslv->head, sizeof sslv->head, |
531 | 0 | MSG_PEEK); |
532 | 0 | } |
533 | |
|
534 | 0 | retval = (sslv->type == CLIENT |
535 | 0 | ? SSL_connect(sslv->ssl) : SSL_accept(sslv->ssl)); |
536 | 0 | if (retval != 1) { |
537 | 0 | int error = SSL_get_error(sslv->ssl, retval); |
538 | 0 | if (retval < 0 && ssl_wants_io(error)) { |
539 | 0 | return EAGAIN; |
540 | 0 | } else { |
541 | 0 | int unused; |
542 | |
|
543 | 0 | interpret_ssl_error((sslv->type == CLIENT ? "SSL_connect" |
544 | 0 | : "SSL_accept"), retval, error, &unused); |
545 | 0 | shutdown(sslv->fd, SHUT_RDWR); |
546 | 0 | stream_report_content(sslv->head, sslv->n_head, STREAM_SSL, |
547 | 0 | &this_module, stream_get_name(stream)); |
548 | 0 | return EPROTO; |
549 | 0 | } |
550 | 0 | } else if (bootstrap_ca_cert) { |
551 | 0 | return do_ca_cert_bootstrap(stream); |
552 | 0 | } else if (verify_peer_cert |
553 | 0 | && ((SSL_get_verify_mode(sslv->ssl) |
554 | 0 | & (SSL_VERIFY_NONE | SSL_VERIFY_PEER)) |
555 | 0 | != SSL_VERIFY_PEER)) { |
556 | | /* Two or more SSL connections completed at the same time while we |
557 | | * were in bootstrap mode. Only one of these can finish the |
558 | | * bootstrap successfully. The other one(s) must be rejected |
559 | | * because they were not verified against the bootstrapped CA |
560 | | * certificate. (Alternatively we could verify them against the CA |
561 | | * certificate, but that's more trouble than it's worth. These |
562 | | * connections will succeed the next time they retry, assuming that |
563 | | * they have a certificate against the correct CA.) */ |
564 | 0 | VLOG_INFO( |
565 | 0 | "rejecting SSL/TLS connection during bootstrap race window"); |
566 | 0 | return EPROTO; |
567 | 0 | } else { |
568 | 0 | const char *servername = SSL_get_servername( |
569 | 0 | sslv->ssl, TLSEXT_NAMETYPE_host_name); |
570 | 0 | if (servername) { |
571 | 0 | VLOG_DBG("connection indicated server name %s", servername); |
572 | 0 | } |
573 | |
|
574 | 0 | char *cn = get_peer_common_name(sslv); |
575 | |
|
576 | 0 | if (cn) { |
577 | 0 | stream_set_peer_id(stream, cn); |
578 | 0 | free(cn); |
579 | 0 | } |
580 | 0 | return 0; |
581 | 0 | } |
582 | 0 | } |
583 | | |
584 | 0 | OVS_NOT_REACHED(); |
585 | 0 | } |
586 | | |
587 | | static void |
588 | | ssl_close(struct stream *stream) |
589 | 0 | { |
590 | 0 | struct ssl_stream *sslv = ssl_stream_cast(stream); |
591 | 0 | ssl_clear_txbuf(sslv); |
592 | | |
593 | | /* Attempt clean shutdown of the SSL connection. This will work most of |
594 | | * the time, as long as the kernel send buffer has some free space and the |
595 | | * SSL connection isn't renegotiating, etc. That has to be good enough, |
596 | | * since we don't have any way to continue the close operation in the |
597 | | * background. */ |
598 | 0 | SSL_shutdown(sslv->ssl); |
599 | | |
600 | | /* SSL_shutdown() might have signaled an error, in which case we need to |
601 | | * flush it out of the OpenSSL error queue or the next OpenSSL operation |
602 | | * will falsely signal an error. */ |
603 | 0 | ERR_clear_error(); |
604 | |
|
605 | 0 | SSL_free(sslv->ssl); |
606 | 0 | closesocket(sslv->fd); |
607 | 0 | free(sslv); |
608 | 0 | } |
609 | | |
610 | | static void |
611 | | interpret_queued_ssl_error(const char *function) |
612 | 0 | { |
613 | 0 | int queued_error = ERR_get_error(); |
614 | 0 | if (queued_error != 0) { |
615 | 0 | VLOG_WARN_RL(&rl, "%s: %s", |
616 | 0 | function, ERR_error_string(queued_error, NULL)); |
617 | 0 | } else { |
618 | 0 | VLOG_ERR_RL(&rl, "%s: SSL_ERROR_SSL without queued error", function); |
619 | 0 | } |
620 | 0 | } |
621 | | |
622 | | static int |
623 | | interpret_ssl_error(const char *function, int ret, int error, |
624 | | int *want) |
625 | 0 | { |
626 | 0 | *want = SSL_NOTHING; |
627 | |
|
628 | 0 | switch (error) { |
629 | 0 | case SSL_ERROR_NONE: |
630 | 0 | VLOG_ERR_RL(&rl, "%s: unexpected SSL_ERROR_NONE", function); |
631 | 0 | break; |
632 | | |
633 | 0 | case SSL_ERROR_ZERO_RETURN: |
634 | 0 | VLOG_ERR_RL(&rl, "%s: unexpected SSL_ERROR_ZERO_RETURN", function); |
635 | 0 | break; |
636 | | |
637 | 0 | case SSL_ERROR_WANT_READ: |
638 | 0 | *want = SSL_READING; |
639 | 0 | return EAGAIN; |
640 | | |
641 | 0 | case SSL_ERROR_WANT_WRITE: |
642 | 0 | *want = SSL_WRITING; |
643 | 0 | return EAGAIN; |
644 | | |
645 | 0 | case SSL_ERROR_WANT_CONNECT: |
646 | 0 | VLOG_ERR_RL(&rl, "%s: unexpected SSL_ERROR_WANT_CONNECT", function); |
647 | 0 | break; |
648 | | |
649 | 0 | case SSL_ERROR_WANT_ACCEPT: |
650 | 0 | VLOG_ERR_RL(&rl, "%s: unexpected SSL_ERROR_WANT_ACCEPT", function); |
651 | 0 | break; |
652 | | |
653 | 0 | case SSL_ERROR_WANT_X509_LOOKUP: |
654 | 0 | VLOG_ERR_RL(&rl, "%s: unexpected SSL_ERROR_WANT_X509_LOOKUP", |
655 | 0 | function); |
656 | 0 | break; |
657 | | |
658 | 0 | case SSL_ERROR_SYSCALL: { |
659 | 0 | int queued_error = ERR_get_error(); |
660 | 0 | if (queued_error == 0) { |
661 | 0 | if (ret < 0) { |
662 | 0 | int status = errno; |
663 | 0 | VLOG_WARN_RL(&rl, "%s: system error (%s)", |
664 | 0 | function, ovs_strerror(status)); |
665 | 0 | return status; |
666 | 0 | } else { |
667 | 0 | VLOG_WARN_RL(&rl, "%s: unexpected SSL/TLS connection close", |
668 | 0 | function); |
669 | 0 | return EPROTO; |
670 | 0 | } |
671 | 0 | } else { |
672 | 0 | VLOG_WARN_RL(&rl, "%s: %s", |
673 | 0 | function, ERR_error_string(queued_error, NULL)); |
674 | 0 | break; |
675 | 0 | } |
676 | 0 | } |
677 | | |
678 | 0 | case SSL_ERROR_SSL: |
679 | 0 | interpret_queued_ssl_error(function); |
680 | 0 | break; |
681 | | |
682 | 0 | default: |
683 | 0 | VLOG_ERR_RL(&rl, "%s: bad SSL error code %d", function, error); |
684 | 0 | break; |
685 | 0 | } |
686 | 0 | return EIO; |
687 | 0 | } |
688 | | |
689 | | static ssize_t |
690 | | ssl_recv(struct stream *stream, void *buffer, size_t n) |
691 | 0 | { |
692 | 0 | struct ssl_stream *sslv = ssl_stream_cast(stream); |
693 | 0 | int old_state; |
694 | 0 | ssize_t ret; |
695 | | |
696 | | /* Behavior of zero-byte SSL_read is poorly defined. */ |
697 | 0 | ovs_assert(n > 0); |
698 | |
|
699 | 0 | old_state = SSL_get_state(sslv->ssl); |
700 | 0 | ret = SSL_read(sslv->ssl, buffer, n); |
701 | 0 | if (old_state != SSL_get_state(sslv->ssl)) { |
702 | 0 | sslv->tx_want = SSL_NOTHING; |
703 | 0 | } |
704 | 0 | sslv->rx_want = SSL_NOTHING; |
705 | |
|
706 | 0 | if (ret > 0) { |
707 | 0 | return ret; |
708 | 0 | } else { |
709 | 0 | int error = SSL_get_error(sslv->ssl, ret); |
710 | 0 | if (error == SSL_ERROR_ZERO_RETURN) { |
711 | 0 | return 0; |
712 | 0 | } else { |
713 | 0 | return -interpret_ssl_error("SSL_read", ret, error, |
714 | 0 | &sslv->rx_want); |
715 | 0 | } |
716 | 0 | } |
717 | 0 | } |
718 | | |
719 | | static void |
720 | | ssl_clear_txbuf(struct ssl_stream *sslv) |
721 | 0 | { |
722 | 0 | ofpbuf_delete(sslv->txbuf); |
723 | 0 | sslv->txbuf = NULL; |
724 | 0 | } |
725 | | |
726 | | static int |
727 | | ssl_do_tx(struct stream *stream) |
728 | 0 | { |
729 | 0 | struct ssl_stream *sslv = ssl_stream_cast(stream); |
730 | |
|
731 | 0 | for (;;) { |
732 | 0 | int old_state = SSL_get_state(sslv->ssl); |
733 | 0 | int ret = SSL_write(sslv->ssl, sslv->txbuf->data, sslv->txbuf->size); |
734 | 0 | if (old_state != SSL_get_state(sslv->ssl)) { |
735 | 0 | sslv->rx_want = SSL_NOTHING; |
736 | 0 | } |
737 | 0 | sslv->tx_want = SSL_NOTHING; |
738 | 0 | if (ret > 0) { |
739 | 0 | ofpbuf_pull(sslv->txbuf, ret); |
740 | 0 | if (sslv->txbuf->size == 0) { |
741 | 0 | return 0; |
742 | 0 | } |
743 | 0 | } else { |
744 | 0 | int ssl_error = SSL_get_error(sslv->ssl, ret); |
745 | 0 | if (ssl_error == SSL_ERROR_ZERO_RETURN) { |
746 | 0 | VLOG_WARN_RL(&rl, "SSL_write: connection closed"); |
747 | 0 | return EPIPE; |
748 | 0 | } else { |
749 | 0 | return interpret_ssl_error("SSL_write", ret, ssl_error, |
750 | 0 | &sslv->tx_want); |
751 | 0 | } |
752 | 0 | } |
753 | 0 | } |
754 | 0 | } |
755 | | |
756 | | static ssize_t |
757 | | ssl_send(struct stream *stream, const void *buffer, size_t n) |
758 | 0 | { |
759 | 0 | struct ssl_stream *sslv = ssl_stream_cast(stream); |
760 | |
|
761 | 0 | if (sslv->txbuf) { |
762 | 0 | return -EAGAIN; |
763 | 0 | } else { |
764 | 0 | struct ofpbuf buf; |
765 | 0 | int error; |
766 | |
|
767 | 0 | ofpbuf_use_const(&buf, buffer, n); |
768 | 0 | sslv->txbuf = &buf; |
769 | 0 | error = ssl_do_tx(stream); |
770 | 0 | switch (error) { |
771 | 0 | case 0: |
772 | 0 | sslv->txbuf = NULL; |
773 | 0 | return n; |
774 | 0 | case EAGAIN: |
775 | | /* Copy remaining data. */ |
776 | 0 | sslv->txbuf = ofpbuf_clone_data(buf.data, buf.size); |
777 | 0 | return n; |
778 | 0 | default: |
779 | 0 | sslv->txbuf = NULL; |
780 | 0 | return -error; |
781 | 0 | } |
782 | 0 | } |
783 | 0 | } |
784 | | |
785 | | static void |
786 | | ssl_run(struct stream *stream) |
787 | 0 | { |
788 | 0 | struct ssl_stream *sslv = ssl_stream_cast(stream); |
789 | |
|
790 | 0 | if (sslv->txbuf && ssl_do_tx(stream) != EAGAIN) { |
791 | 0 | ssl_clear_txbuf(sslv); |
792 | 0 | } |
793 | 0 | } |
794 | | |
795 | | static void |
796 | | ssl_run_wait(struct stream *stream) |
797 | 0 | { |
798 | 0 | struct ssl_stream *sslv = ssl_stream_cast(stream); |
799 | |
|
800 | 0 | if (sslv->tx_want != SSL_NOTHING) { |
801 | 0 | poll_fd_wait(sslv->fd, want_to_poll_events(sslv->tx_want)); |
802 | 0 | } |
803 | 0 | } |
804 | | |
805 | | static void |
806 | | ssl_wait(struct stream *stream, enum stream_wait_type wait) |
807 | 0 | { |
808 | 0 | struct ssl_stream *sslv = ssl_stream_cast(stream); |
809 | |
|
810 | 0 | switch (wait) { |
811 | 0 | case STREAM_CONNECT: |
812 | 0 | if (stream_connect(stream) != EAGAIN) { |
813 | 0 | poll_immediate_wake(); |
814 | 0 | } else { |
815 | 0 | switch (sslv->state) { |
816 | 0 | case STATE_TCP_CONNECTING: |
817 | 0 | poll_fd_wait(sslv->fd, POLLOUT); |
818 | 0 | break; |
819 | | |
820 | 0 | case STATE_SSL_CONNECTING: |
821 | | /* ssl_connect() called SSL_accept() or SSL_connect(), which |
822 | | * set up the status that we test here. */ |
823 | 0 | poll_fd_wait(sslv->fd, |
824 | 0 | want_to_poll_events(SSL_want(sslv->ssl))); |
825 | 0 | break; |
826 | | |
827 | 0 | default: |
828 | 0 | OVS_NOT_REACHED(); |
829 | 0 | } |
830 | 0 | } |
831 | 0 | break; |
832 | | |
833 | 0 | case STREAM_RECV: |
834 | 0 | if (sslv->rx_want != SSL_NOTHING) { |
835 | 0 | poll_fd_wait(sslv->fd, want_to_poll_events(sslv->rx_want)); |
836 | 0 | } else { |
837 | 0 | poll_immediate_wake(); |
838 | 0 | } |
839 | 0 | break; |
840 | | |
841 | 0 | case STREAM_SEND: |
842 | 0 | if (!sslv->txbuf) { |
843 | | /* We have room in our tx queue. */ |
844 | 0 | poll_immediate_wake(); |
845 | 0 | } else { |
846 | | /* stream_run_wait() will do the right thing; don't bother with |
847 | | * redundancy. */ |
848 | 0 | } |
849 | 0 | break; |
850 | | |
851 | 0 | default: |
852 | 0 | OVS_NOT_REACHED(); |
853 | 0 | } |
854 | 0 | } |
855 | | |
856 | | const struct stream_class ssl_stream_class = { |
857 | | "ssl", /* name */ |
858 | | true, /* needs_probes */ |
859 | | ssl_open, /* open */ |
860 | | ssl_close, /* close */ |
861 | | ssl_connect, /* connect */ |
862 | | ssl_recv, /* recv */ |
863 | | ssl_send, /* send */ |
864 | | ssl_run, /* run */ |
865 | | ssl_run_wait, /* run_wait */ |
866 | | ssl_wait, /* wait */ |
867 | | }; |
868 | | |
869 | | /* Passive SSL/TLS. */ |
870 | | |
871 | | struct pssl_pstream |
872 | | { |
873 | | struct pstream pstream; |
874 | | int fd; |
875 | | }; |
876 | | |
877 | | const struct pstream_class pssl_pstream_class; |
878 | | |
879 | | static struct pssl_pstream * |
880 | | pssl_pstream_cast(struct pstream *pstream) |
881 | 0 | { |
882 | 0 | pstream_assert_class(pstream, &pssl_pstream_class); |
883 | 0 | return CONTAINER_OF(pstream, struct pssl_pstream, pstream); |
884 | 0 | } |
885 | | |
886 | | static int |
887 | | pssl_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp, |
888 | | uint8_t dscp) |
889 | 0 | { |
890 | 0 | struct sockaddr_storage ss; |
891 | 0 | struct pssl_pstream *pssl; |
892 | 0 | uint16_t port; |
893 | 0 | int retval; |
894 | 0 | int fd; |
895 | |
|
896 | 0 | retval = ssl_init(); |
897 | 0 | if (retval) { |
898 | 0 | return retval; |
899 | 0 | } |
900 | | |
901 | 0 | fd = inet_open_passive(SOCK_STREAM, suffix, OFP_PORT, &ss, dscp, true); |
902 | 0 | if (fd < 0) { |
903 | 0 | return -fd; |
904 | 0 | } |
905 | | |
906 | 0 | port = ss_get_port(&ss); |
907 | |
|
908 | 0 | struct ds bound_name = DS_EMPTY_INITIALIZER; |
909 | 0 | ds_put_format(&bound_name, "pssl:%"PRIu16":", port); |
910 | 0 | ss_format_address(&ss, &bound_name); |
911 | |
|
912 | 0 | pssl = xmalloc(sizeof *pssl); |
913 | 0 | pstream_init(&pssl->pstream, &pssl_pstream_class, |
914 | 0 | ds_steal_cstr(&bound_name)); |
915 | 0 | pstream_set_bound_port(&pssl->pstream, htons(port)); |
916 | 0 | pssl->fd = fd; |
917 | 0 | *pstreamp = &pssl->pstream; |
918 | |
|
919 | 0 | return 0; |
920 | 0 | } |
921 | | |
922 | | static void |
923 | | pssl_close(struct pstream *pstream) |
924 | 0 | { |
925 | 0 | struct pssl_pstream *pssl = pssl_pstream_cast(pstream); |
926 | 0 | closesocket(pssl->fd); |
927 | 0 | free(pssl); |
928 | 0 | } |
929 | | |
930 | | static int |
931 | | pssl_accept(struct pstream *pstream, struct stream **new_streamp) |
932 | 0 | { |
933 | 0 | struct pssl_pstream *pssl = pssl_pstream_cast(pstream); |
934 | 0 | struct sockaddr_storage ss; |
935 | 0 | socklen_t ss_len = sizeof ss; |
936 | 0 | int new_fd; |
937 | 0 | int error; |
938 | |
|
939 | 0 | new_fd = accept(pssl->fd, (struct sockaddr *) &ss, &ss_len); |
940 | 0 | if (new_fd < 0) { |
941 | 0 | error = sock_errno(); |
942 | | #ifdef _WIN32 |
943 | | if (error == WSAEWOULDBLOCK) { |
944 | | error = EAGAIN; |
945 | | } |
946 | | #endif |
947 | 0 | if (error != EAGAIN) { |
948 | 0 | VLOG_DBG_RL(&rl, "accept: %s", sock_strerror(error)); |
949 | 0 | } |
950 | 0 | return error; |
951 | 0 | } |
952 | | |
953 | 0 | error = set_nonblocking(new_fd); |
954 | 0 | if (error) { |
955 | 0 | closesocket(new_fd); |
956 | 0 | return error; |
957 | 0 | } |
958 | | |
959 | 0 | struct ds name = DS_EMPTY_INITIALIZER; |
960 | 0 | ds_put_cstr(&name, "ssl:"); |
961 | 0 | ss_format_address(&ss, &name); |
962 | 0 | ds_put_format(&name, ":%"PRIu16, ss_get_port(&ss)); |
963 | 0 | return new_ssl_stream(ds_steal_cstr(&name), NULL, new_fd, SERVER, |
964 | 0 | STATE_SSL_CONNECTING, new_streamp); |
965 | 0 | } |
966 | | |
967 | | static void |
968 | | pssl_wait(struct pstream *pstream) |
969 | 0 | { |
970 | 0 | struct pssl_pstream *pssl = pssl_pstream_cast(pstream); |
971 | 0 | poll_fd_wait(pssl->fd, POLLIN); |
972 | 0 | } |
973 | | |
974 | | const struct pstream_class pssl_pstream_class = { |
975 | | "pssl", |
976 | | true, |
977 | | pssl_open, |
978 | | pssl_close, |
979 | | pssl_accept, |
980 | | pssl_wait, |
981 | | }; |
982 | | |
983 | | /* |
984 | | * Returns true if OpenSSL error is WANT_READ or WANT_WRITE, indicating that |
985 | | * OpenSSL is requesting that we call it back when the socket is ready for read |
986 | | * or writing, respectively. |
987 | | */ |
988 | | static bool |
989 | | ssl_wants_io(int ssl_error) |
990 | 0 | { |
991 | 0 | return (ssl_error == SSL_ERROR_WANT_WRITE |
992 | 0 | || ssl_error == SSL_ERROR_WANT_READ); |
993 | 0 | } |
994 | | |
995 | | static int |
996 | | ssl_init(void) |
997 | 0 | { |
998 | 0 | static int init_status = -1; |
999 | 0 | if (init_status < 0) { |
1000 | 0 | init_status = do_ssl_init(); |
1001 | 0 | ovs_assert(init_status >= 0); |
1002 | 0 | } |
1003 | 0 | return init_status; |
1004 | 0 | } |
1005 | | |
1006 | | static int |
1007 | | do_ssl_init(void) |
1008 | 0 | { |
1009 | 0 | if (!RAND_status()) { |
1010 | | /* We occasionally see OpenSSL fail to seed its random number generator |
1011 | | * in heavily loaded hypervisors. I suspect the following scenario: |
1012 | | * |
1013 | | * 1. OpenSSL calls read() to get 32 bytes from /dev/urandom. |
1014 | | * 2. The kernel generates 10 bytes of randomness and copies it out. |
1015 | | * 3. A signal arrives (perhaps SIGALRM). |
1016 | | * 4. The kernel interrupts the system call to service the signal. |
1017 | | * 5. Userspace gets 10 bytes of entropy. |
1018 | | * 6. OpenSSL doesn't read again to get the final 22 bytes. Therefore |
1019 | | * OpenSSL doesn't have enough entropy to consider itself |
1020 | | * initialized. |
1021 | | * |
1022 | | * The only part I'm not entirely sure about is #6, because the OpenSSL |
1023 | | * code is so hard to read. */ |
1024 | 0 | uint8_t seed[32]; |
1025 | 0 | int retval; |
1026 | |
|
1027 | 0 | VLOG_WARN("OpenSSL random seeding failed, reseeding ourselves"); |
1028 | |
|
1029 | 0 | retval = get_entropy(seed, sizeof seed); |
1030 | 0 | if (retval) { |
1031 | 0 | VLOG_ERR("failed to obtain entropy (%s)", |
1032 | 0 | ovs_retval_to_string(retval)); |
1033 | 0 | return retval > 0 ? retval : ENOPROTOOPT; |
1034 | 0 | } |
1035 | | |
1036 | 0 | RAND_seed(seed, sizeof seed); |
1037 | 0 | } |
1038 | | |
1039 | | /* Using version-flexible "connection method". Allowed versions will |
1040 | | * be restricted below. |
1041 | | * |
1042 | | * The context can be used for both client and server connections, so |
1043 | | * not using specific TLS_server_method() or TLS_client_method() here. */ |
1044 | 0 | const SSL_METHOD *method = TLS_method(); |
1045 | 0 | if (method == NULL) { |
1046 | 0 | VLOG_ERR("TLS_method: %s", ERR_error_string(ERR_get_error(), NULL)); |
1047 | 0 | return ENOPROTOOPT; |
1048 | 0 | } |
1049 | | |
1050 | 0 | ctx = SSL_CTX_new(method); |
1051 | 0 | if (ctx == NULL) { |
1052 | 0 | VLOG_ERR("SSL_CTX_new: %s", ERR_error_string(ERR_get_error(), NULL)); |
1053 | 0 | return ENOPROTOOPT; |
1054 | 0 | } |
1055 | | |
1056 | | #ifdef SSL_OP_IGNORE_UNEXPECTED_EOF |
1057 | | SSL_CTX_set_options(ctx, SSL_OP_IGNORE_UNEXPECTED_EOF); |
1058 | | #endif |
1059 | | |
1060 | | /* Only allow TLSv1.2 or later. */ |
1061 | 0 | SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); |
1062 | 0 | SSL_CTX_set_max_proto_version(ctx, 0); |
1063 | |
|
1064 | 0 | #if OPENSSL_VERSION_NUMBER < 0x3000000fL |
1065 | 0 | SSL_CTX_set_tmp_dh_callback(ctx, tmp_dh_callback); |
1066 | | #else |
1067 | | SSL_CTX_set_dh_auto(ctx, 1); |
1068 | | #endif |
1069 | 0 | SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); |
1070 | 0 | SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); |
1071 | 0 | SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, |
1072 | 0 | NULL); |
1073 | 0 | SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); |
1074 | 0 | SSL_CTX_set_cipher_list(ctx, "DEFAULT:@SECLEVEL=2"); |
1075 | |
|
1076 | 0 | return 0; |
1077 | 0 | } |
1078 | | |
1079 | | #if OPENSSL_VERSION_NUMBER < 0x3000000fL |
1080 | | static DH * |
1081 | | tmp_dh_callback(SSL *ssl OVS_UNUSED, int is_export OVS_UNUSED, int keylength) |
1082 | 0 | { |
1083 | 0 | struct dh { |
1084 | 0 | int keylength; |
1085 | 0 | DH *dh; |
1086 | 0 | DH *(*constructor)(void); |
1087 | 0 | }; |
1088 | |
|
1089 | 0 | static struct dh dh_table[] = { |
1090 | 0 | {2048, NULL, get_dh2048}, |
1091 | 0 | {4096, NULL, get_dh4096}, |
1092 | 0 | }; |
1093 | |
|
1094 | 0 | struct dh *dh; |
1095 | |
|
1096 | 0 | for (dh = dh_table; dh < &dh_table[ARRAY_SIZE(dh_table)]; dh++) { |
1097 | 0 | if (dh->keylength >= keylength) { |
1098 | 0 | if (!dh->dh) { |
1099 | 0 | dh->dh = dh->constructor(); |
1100 | 0 | if (!dh->dh) { |
1101 | 0 | out_of_memory(); |
1102 | 0 | } |
1103 | 0 | } |
1104 | 0 | return dh->dh; |
1105 | 0 | } |
1106 | 0 | } |
1107 | 0 | VLOG_ERR_RL(&rl, "no Diffie-Hellman parameters for key length %d", |
1108 | 0 | keylength); |
1109 | 0 | return NULL; |
1110 | 0 | } |
1111 | | #endif |
1112 | | |
1113 | | /* Returns true if SSL/TLS is at least partially configured. */ |
1114 | | bool |
1115 | | stream_ssl_is_configured(void) |
1116 | 0 | { |
1117 | 0 | return private_key.file_name || certificate.file_name || ca_cert.file_name; |
1118 | 0 | } |
1119 | | |
1120 | | static bool |
1121 | | update_ssl_config(struct ssl_config_file *config, const char *file_name) |
1122 | 0 | { |
1123 | 0 | struct timespec mtime; |
1124 | 0 | int error; |
1125 | |
|
1126 | 0 | if (ssl_init() || !file_name) { |
1127 | 0 | return false; |
1128 | 0 | } |
1129 | | |
1130 | | /* If the file name hasn't changed and neither has the file contents, stop |
1131 | | * here. */ |
1132 | 0 | error = get_mtime(file_name, &mtime); |
1133 | 0 | if (error && error != ENOENT) { |
1134 | 0 | VLOG_ERR_RL(&rl, "%s: stat failed (%s)", |
1135 | 0 | file_name, ovs_strerror(error)); |
1136 | 0 | } |
1137 | 0 | if (config->file_name |
1138 | 0 | && !strcmp(config->file_name, file_name) |
1139 | 0 | && mtime.tv_sec == config->mtime.tv_sec |
1140 | 0 | && mtime.tv_nsec == config->mtime.tv_nsec) { |
1141 | 0 | return false; |
1142 | 0 | } |
1143 | | |
1144 | | /* Update 'config'. */ |
1145 | 0 | config->mtime = mtime; |
1146 | 0 | if (file_name != config->file_name) { |
1147 | 0 | free(config->file_name); |
1148 | 0 | config->file_name = xstrdup(file_name); |
1149 | 0 | } |
1150 | 0 | return true; |
1151 | 0 | } |
1152 | | |
1153 | | static void |
1154 | | stream_ssl_set_private_key_file__(const char *file_name) |
1155 | 0 | { |
1156 | 0 | if (SSL_CTX_use_PrivateKey_file(ctx, file_name, SSL_FILETYPE_PEM) == 1) { |
1157 | 0 | private_key.read = true; |
1158 | 0 | } else { |
1159 | 0 | VLOG_ERR("SSL_use_PrivateKey_file: %s", |
1160 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
1161 | 0 | } |
1162 | 0 | } |
1163 | | |
1164 | | void |
1165 | | stream_ssl_set_private_key_file(const char *file_name) |
1166 | 0 | { |
1167 | 0 | if (update_ssl_config(&private_key, file_name)) { |
1168 | 0 | stream_ssl_set_private_key_file__(file_name); |
1169 | 0 | } |
1170 | 0 | } |
1171 | | |
1172 | | static void |
1173 | | stream_ssl_set_certificate_file__(const char *file_name) |
1174 | 0 | { |
1175 | 0 | if (SSL_CTX_use_certificate_file(ctx, file_name, SSL_FILETYPE_PEM) == 1) { |
1176 | 0 | certificate.read = true; |
1177 | 0 | } else { |
1178 | 0 | VLOG_ERR("SSL_use_certificate_file: %s", |
1179 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
1180 | 0 | } |
1181 | 0 | } |
1182 | | |
1183 | | void |
1184 | | stream_ssl_set_certificate_file(const char *file_name) |
1185 | 0 | { |
1186 | 0 | if (update_ssl_config(&certificate, file_name)) { |
1187 | 0 | stream_ssl_set_certificate_file__(file_name); |
1188 | 0 | } |
1189 | 0 | } |
1190 | | |
1191 | | /* Sets the private key and certificate files in one operation. Use this |
1192 | | * interface, instead of calling stream_ssl_set_private_key_file() and |
1193 | | * stream_ssl_set_certificate_file() individually, in the main loop of a |
1194 | | * long-running program whose key and certificate might change at runtime. |
1195 | | * |
1196 | | * This is important because of OpenSSL's behavior. If an OpenSSL context |
1197 | | * already has a certificate, and stream_ssl_set_private_key_file() is called |
1198 | | * to install a new private key, OpenSSL will report an error because the new |
1199 | | * private key does not match the old certificate. The other order, of setting |
1200 | | * a new certificate, then setting a new private key, does work. |
1201 | | * |
1202 | | * If this were the only problem, calling stream_ssl_set_certificate_file() |
1203 | | * before stream_ssl_set_private_key_file() would fix it. But, if the private |
1204 | | * key is changed before the certificate (e.g. someone "scp"s or "mv"s the new |
1205 | | * private key in place before the certificate), then OpenSSL would reject that |
1206 | | * change, and then the change of certificate would succeed, but there would be |
1207 | | * no associated private key (because it had only changed once and therefore |
1208 | | * there was no point in re-reading it). |
1209 | | * |
1210 | | * This function avoids both problems by, whenever either the certificate or |
1211 | | * the private key file changes, re-reading both of them, in the correct order. |
1212 | | */ |
1213 | | void |
1214 | | stream_ssl_set_key_and_cert(const char *private_key_file, |
1215 | | const char *certificate_file) |
1216 | 0 | { |
1217 | 0 | if (update_ssl_config(&private_key, private_key_file) |
1218 | 0 | && update_ssl_config(&certificate, certificate_file)) { |
1219 | 0 | stream_ssl_set_certificate_file__(certificate_file); |
1220 | 0 | stream_ssl_set_private_key_file__(private_key_file); |
1221 | 0 | } |
1222 | 0 | } |
1223 | | |
1224 | | /* Sets SSL/TLS ciphers for TLSv1.2 based on string input. |
1225 | | * Aborts with an error message if 'arg' is not valid. */ |
1226 | | void |
1227 | | stream_ssl_set_ciphers(const char *arg) |
1228 | 0 | { |
1229 | 0 | if (ssl_init() || !arg || !strcmp(ssl_ciphers, arg)) { |
1230 | 0 | return; |
1231 | 0 | } |
1232 | 0 | if (SSL_CTX_set_cipher_list(ctx,arg) == 0) { |
1233 | 0 | VLOG_ERR("SSL_CTX_set_cipher_list: %s", |
1234 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
1235 | 0 | } |
1236 | 0 | ssl_ciphers = xstrdup(arg); |
1237 | 0 | } |
1238 | | |
1239 | | /* Sets TLS ciphersuites for TLSv1.3 and later based on string input. |
1240 | | * Aborts with an error message if 'arg' is not valid. */ |
1241 | | void |
1242 | | stream_ssl_set_ciphersuites(const char *arg) |
1243 | 0 | { |
1244 | 0 | if (ssl_init() || !arg || !strcmp(ssl_ciphersuites, arg)) { |
1245 | 0 | return; |
1246 | 0 | } |
1247 | 0 | if (SSL_CTX_set_ciphersuites(ctx, arg) == 0) { |
1248 | 0 | VLOG_ERR("SSL_CTX_set_ciphersuites: %s", |
1249 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
1250 | 0 | } |
1251 | 0 | ssl_ciphersuites = xstrdup(arg); |
1252 | 0 | } |
1253 | | |
1254 | | /* Set SSL/TLS protocols based on the string input. Aborts with an error |
1255 | | * message if 'arg' is invalid. */ |
1256 | | void |
1257 | | stream_ssl_set_protocols(const char *arg) |
1258 | 0 | { |
1259 | 0 | if (ssl_init() || !arg || !strcmp(arg, ssl_protocols)) { |
1260 | 0 | return; |
1261 | 0 | } |
1262 | | |
1263 | 0 | struct sset set = SSET_INITIALIZER(&set); |
1264 | 0 | struct { |
1265 | 0 | const char *name; |
1266 | 0 | int version; |
1267 | 0 | bool deprecated; |
1268 | 0 | } protocols[] = { |
1269 | 0 | {"later", 0 /* any version */, false}, |
1270 | 0 | {"TLSv1.2", TLS1_2_VERSION, false}, |
1271 | 0 | {"TLSv1.3", TLS1_3_VERSION, false}, |
1272 | 0 | }; |
1273 | 0 | char *dash = strchr(arg, '-'); |
1274 | 0 | bool or_later = false; |
1275 | 0 | int len = strlen(arg); |
1276 | |
|
1277 | 0 | if (len && arg[len - 1] == '+') { |
1278 | | /* We only support full ranges, so more than one version or later "X+" |
1279 | | * doesn't make a lot of sense. */ |
1280 | 0 | sset_add_and_free(&set, xmemdup0(arg, len - 1)); |
1281 | 0 | or_later = true; |
1282 | 0 | } else if (dash) { |
1283 | | /* Again, do not attempt to parse multiple ranges. The range should |
1284 | | * always be a single "X-Y". */ |
1285 | 0 | sset_add_and_free(&set, xmemdup0(arg, dash - arg)); |
1286 | 0 | sset_add_and_free(&set, xstrdup(dash + 1)); |
1287 | 0 | } else { |
1288 | | /* Otherwise, it's a list that should not include ranges. */ |
1289 | 0 | sset_from_delimited_string(&set, arg, " ,\t"); |
1290 | 0 | } |
1291 | |
|
1292 | 0 | if (sset_is_empty(&set)) { |
1293 | 0 | VLOG_ERR("SSL/TLS protocol settings invalid"); |
1294 | 0 | goto exit; |
1295 | 0 | } |
1296 | | |
1297 | 0 | size_t min_version = ARRAY_SIZE(protocols) + 1; |
1298 | 0 | size_t max_version = 0; |
1299 | 0 | unsigned long map = 0; |
1300 | |
|
1301 | 0 | for (size_t i = 1; i < ARRAY_SIZE(protocols); i++) { |
1302 | 0 | if (sset_contains(&set, protocols[i].name)) { |
1303 | 0 | min_version = MIN(min_version, i); |
1304 | 0 | max_version = MAX(max_version, i); |
1305 | 0 | if (protocols[i].deprecated) { |
1306 | 0 | VLOG_WARN("%s protocol is deprecated", protocols[i].name); |
1307 | 0 | } |
1308 | 0 | bitmap_set1(&map, i); |
1309 | 0 | sset_find_and_delete(&set, protocols[i].name); |
1310 | 0 | } |
1311 | 0 | } |
1312 | |
|
1313 | 0 | if (!sset_is_empty(&set)) { |
1314 | 0 | const char *word; |
1315 | |
|
1316 | 0 | SSET_FOR_EACH (word, &set) { |
1317 | 0 | VLOG_ERR("%s: SSL/TLS protocol not recognized", word); |
1318 | 0 | } |
1319 | 0 | goto exit; |
1320 | 0 | } |
1321 | | |
1322 | | /* At this point we must have parsed at least one protocol. */ |
1323 | 0 | ovs_assert(min_version && min_version < ARRAY_SIZE(protocols)); |
1324 | 0 | ovs_assert(max_version && max_version < ARRAY_SIZE(protocols)); |
1325 | 0 | if (!or_later && !dash) { |
1326 | 0 | for (size_t i = min_version + 1; i < max_version; i++) { |
1327 | 0 | if (!bitmap_is_set(&map, i)) { |
1328 | 0 | VLOG_WARN("SSL/TLS protocol %s" |
1329 | 0 | " is not configured, but will be enabled anyway.", |
1330 | 0 | protocols[i].name); |
1331 | 0 | } |
1332 | 0 | } |
1333 | 0 | } |
1334 | |
|
1335 | 0 | if (or_later) { |
1336 | 0 | ovs_assert(min_version == max_version); |
1337 | 0 | max_version = 0; |
1338 | 0 | } |
1339 | | |
1340 | | /* Set the actual versions. */ |
1341 | 0 | SSL_CTX_set_min_proto_version(ctx, protocols[min_version].version); |
1342 | 0 | SSL_CTX_set_max_proto_version(ctx, protocols[max_version].version); |
1343 | 0 | VLOG_DBG("Enabled protocol range: %s%s%s", protocols[min_version].name, |
1344 | 0 | max_version ? " - " : " or ", |
1345 | 0 | protocols[max_version].name); |
1346 | 0 | ssl_protocols = xstrdup(arg); |
1347 | |
|
1348 | 0 | exit: |
1349 | 0 | sset_destroy(&set); |
1350 | 0 | } |
1351 | | |
1352 | | /* Reads the X509 certificate or certificates in file 'file_name'. On success, |
1353 | | * stores the address of the first element in an array of pointers to |
1354 | | * certificates in '*certs' and the number of certificates in the array in |
1355 | | * '*n_certs', and returns 0. On failure, stores a null pointer in '*certs', 0 |
1356 | | * in '*n_certs', and returns a positive errno value. |
1357 | | * |
1358 | | * The caller is responsible for freeing '*certs'. */ |
1359 | | static int |
1360 | | read_cert_file(const char *file_name, X509 ***certs, size_t *n_certs) |
1361 | 0 | { |
1362 | 0 | FILE *file; |
1363 | 0 | size_t allocated_certs = 0; |
1364 | |
|
1365 | 0 | *certs = NULL; |
1366 | 0 | *n_certs = 0; |
1367 | |
|
1368 | 0 | file = fopen(file_name, "r"); |
1369 | 0 | if (!file) { |
1370 | 0 | VLOG_ERR("failed to open %s for reading: %s", |
1371 | 0 | file_name, ovs_strerror(errno)); |
1372 | 0 | return errno; |
1373 | 0 | } |
1374 | | |
1375 | 0 | for (;;) { |
1376 | 0 | X509 *cert; |
1377 | 0 | int c; |
1378 | | |
1379 | | /* Read certificate from file. */ |
1380 | 0 | cert = PEM_read_X509(file, NULL, NULL, NULL); |
1381 | 0 | if (!cert) { |
1382 | 0 | size_t i; |
1383 | |
|
1384 | 0 | VLOG_ERR("PEM_read_X509 failed reading %s: %s", |
1385 | 0 | file_name, ERR_error_string(ERR_get_error(), NULL)); |
1386 | 0 | for (i = 0; i < *n_certs; i++) { |
1387 | 0 | X509_free((*certs)[i]); |
1388 | 0 | } |
1389 | 0 | free(*certs); |
1390 | 0 | *certs = NULL; |
1391 | 0 | *n_certs = 0; |
1392 | 0 | fclose(file); |
1393 | 0 | return EIO; |
1394 | 0 | } |
1395 | | |
1396 | | /* Add certificate to array. */ |
1397 | 0 | if (*n_certs >= allocated_certs) { |
1398 | 0 | *certs = x2nrealloc(*certs, &allocated_certs, sizeof **certs); |
1399 | 0 | } |
1400 | 0 | (*certs)[(*n_certs)++] = cert; |
1401 | | |
1402 | | /* Are there additional certificates in the file? */ |
1403 | 0 | do { |
1404 | 0 | c = getc(file); |
1405 | 0 | } while (isspace(c)); |
1406 | 0 | if (c == EOF) { |
1407 | 0 | break; |
1408 | 0 | } |
1409 | 0 | ungetc(c, file); |
1410 | 0 | } |
1411 | 0 | fclose(file); |
1412 | 0 | return 0; |
1413 | 0 | } |
1414 | | |
1415 | | |
1416 | | /* Sets 'file_name' as the name of a file containing one or more X509 |
1417 | | * certificates to send to the peer. Typical use in OpenFlow is to send the CA |
1418 | | * certificate to the peer, which enables a switch to pick up the controller's |
1419 | | * CA certificate on its first connection. */ |
1420 | | void |
1421 | | stream_ssl_set_peer_ca_cert_file(const char *file_name) |
1422 | 0 | { |
1423 | 0 | X509 **certs; |
1424 | 0 | size_t n_certs; |
1425 | 0 | size_t i; |
1426 | |
|
1427 | 0 | if (ssl_init()) { |
1428 | 0 | return; |
1429 | 0 | } |
1430 | | |
1431 | 0 | if (!read_cert_file(file_name, &certs, &n_certs)) { |
1432 | 0 | for (i = 0; i < n_certs; i++) { |
1433 | 0 | if (SSL_CTX_add_extra_chain_cert(ctx, certs[i]) != 1) { |
1434 | 0 | VLOG_ERR("SSL_CTX_add_extra_chain_cert: %s", |
1435 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
1436 | 0 | } |
1437 | 0 | } |
1438 | 0 | free(certs); |
1439 | 0 | } |
1440 | 0 | } |
1441 | | |
1442 | | /* Logs fingerprint of CA certificate 'cert' obtained from 'file_name'. */ |
1443 | | static void |
1444 | | log_ca_cert(const char *file_name, X509 *cert) |
1445 | 0 | { |
1446 | 0 | unsigned char digest[EVP_MAX_MD_SIZE]; |
1447 | 0 | unsigned int n_bytes; |
1448 | 0 | struct ds fp; |
1449 | 0 | char *subject; |
1450 | |
|
1451 | 0 | ds_init(&fp); |
1452 | 0 | if (!X509_digest(cert, EVP_sha1(), digest, &n_bytes)) { |
1453 | 0 | ds_put_cstr(&fp, "<out of memory>"); |
1454 | 0 | } else { |
1455 | 0 | unsigned int i; |
1456 | 0 | for (i = 0; i < n_bytes; i++) { |
1457 | 0 | if (i) { |
1458 | 0 | ds_put_char(&fp, ':'); |
1459 | 0 | } |
1460 | 0 | ds_put_format(&fp, "%02x", digest[i]); |
1461 | 0 | } |
1462 | 0 | } |
1463 | 0 | subject = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); |
1464 | 0 | VLOG_INFO("Trusting CA cert from %s (%s) (fingerprint %s)", file_name, |
1465 | 0 | subject ? subject : "<out of memory>", ds_cstr(&fp)); |
1466 | 0 | OPENSSL_free(subject); |
1467 | 0 | ds_destroy(&fp); |
1468 | 0 | } |
1469 | | |
1470 | | static void |
1471 | | stream_ssl_set_ca_cert_file__(const char *file_name, |
1472 | | bool bootstrap, bool force) |
1473 | 0 | { |
1474 | 0 | struct stat s; |
1475 | |
|
1476 | 0 | if (!update_ssl_config(&ca_cert, file_name) && !force) { |
1477 | 0 | return; |
1478 | 0 | } |
1479 | | |
1480 | 0 | if (!strcmp(file_name, "none")) { |
1481 | 0 | verify_peer_cert = false; |
1482 | 0 | VLOG_WARN("Peer certificate validation disabled " |
1483 | 0 | "(this is a security risk)"); |
1484 | 0 | } else if (bootstrap && stat(file_name, &s) && errno == ENOENT) { |
1485 | 0 | bootstrap_ca_cert = true; |
1486 | 0 | } else { |
1487 | 0 | STACK_OF(X509_NAME) *cert_names = SSL_load_client_CA_file(file_name); |
1488 | 0 | if (cert_names) { |
1489 | | /* Set up list of CAs that the server will accept from the |
1490 | | * client. */ |
1491 | 0 | SSL_CTX_set_client_CA_list(ctx, cert_names); |
1492 | | |
1493 | | /* Set up CAs for OpenSSL to trust in verifying the peer's |
1494 | | * certificate. */ |
1495 | 0 | SSL_CTX_set_cert_store(ctx, X509_STORE_new()); |
1496 | 0 | if (SSL_CTX_load_verify_locations(ctx, file_name, NULL) != 1) { |
1497 | 0 | VLOG_ERR("SSL_CTX_load_verify_locations: %s", |
1498 | 0 | ERR_error_string(ERR_get_error(), NULL)); |
1499 | 0 | return; |
1500 | 0 | } |
1501 | 0 | bootstrap_ca_cert = false; |
1502 | 0 | } else { |
1503 | 0 | VLOG_ERR("failed to load client certificates from %s: %s", |
1504 | 0 | file_name, ERR_error_string(ERR_get_error(), NULL)); |
1505 | 0 | } |
1506 | 0 | } |
1507 | 0 | ca_cert.read = true; |
1508 | 0 | } |
1509 | | |
1510 | | /* Sets 'file_name' as the name of the file from which to read the CA |
1511 | | * certificate used to verify the peer within SSL/TLS connections. If |
1512 | | * 'bootstrap' is false, the file must exist. If 'bootstrap' is false, then |
1513 | | * the file is read if it is exists; if it does not, then it will be created |
1514 | | * from the CA certificate received from the peer on the first SSL/TLS |
1515 | | * connection. */ |
1516 | | void |
1517 | | stream_ssl_set_ca_cert_file(const char *file_name, bool bootstrap) |
1518 | 0 | { |
1519 | 0 | stream_ssl_set_ca_cert_file__(file_name, bootstrap, false); |
1520 | 0 | } |
1521 | | |
1522 | | /* SSL/TLS protocol logging. */ |
1523 | | |
1524 | | static const char * |
1525 | | ssl_alert_level_to_string(uint8_t type) |
1526 | 0 | { |
1527 | 0 | switch (type) { |
1528 | 0 | case 1: return "warning"; |
1529 | 0 | case 2: return "fatal"; |
1530 | 0 | default: return "<unknown>"; |
1531 | 0 | } |
1532 | 0 | } |
1533 | | |
1534 | | static const char * |
1535 | | ssl_alert_description_to_string(uint8_t type) |
1536 | 0 | { |
1537 | 0 | switch (type) { |
1538 | 0 | case 0: return "close_notify"; |
1539 | 0 | case 10: return "unexpected_message"; |
1540 | 0 | case 20: return "bad_record_mac"; |
1541 | 0 | case 21: return "decryption_failed"; |
1542 | 0 | case 22: return "record_overflow"; |
1543 | 0 | case 30: return "decompression_failure"; |
1544 | 0 | case 40: return "handshake_failure"; |
1545 | 0 | case 42: return "bad_certificate"; |
1546 | 0 | case 43: return "unsupported_certificate"; |
1547 | 0 | case 44: return "certificate_revoked"; |
1548 | 0 | case 45: return "certificate_expired"; |
1549 | 0 | case 46: return "certificate_unknown"; |
1550 | 0 | case 47: return "illegal_parameter"; |
1551 | 0 | case 48: return "unknown_ca"; |
1552 | 0 | case 49: return "access_denied"; |
1553 | 0 | case 50: return "decode_error"; |
1554 | 0 | case 51: return "decrypt_error"; |
1555 | 0 | case 60: return "export_restriction"; |
1556 | 0 | case 70: return "protocol_version"; |
1557 | 0 | case 71: return "insufficient_security"; |
1558 | 0 | case 80: return "internal_error"; |
1559 | 0 | case 90: return "user_canceled"; |
1560 | 0 | case 100: return "no_renegotiation"; |
1561 | 0 | default: return "<unknown>"; |
1562 | 0 | } |
1563 | 0 | } |
1564 | | |
1565 | | static const char * |
1566 | | ssl_handshake_type_to_string(uint8_t type) |
1567 | 0 | { |
1568 | 0 | switch (type) { |
1569 | 0 | case 0: return "hello_request"; |
1570 | 0 | case 1: return "client_hello"; |
1571 | 0 | case 2: return "server_hello"; |
1572 | 0 | case 11: return "certificate"; |
1573 | 0 | case 12: return "server_key_exchange"; |
1574 | 0 | case 13: return "certificate_request"; |
1575 | 0 | case 14: return "server_hello_done"; |
1576 | 0 | case 15: return "certificate_verify"; |
1577 | 0 | case 16: return "client_key_exchange"; |
1578 | 0 | case 20: return "finished"; |
1579 | 0 | default: return "<unknown>"; |
1580 | 0 | } |
1581 | 0 | } |
1582 | | |
1583 | | static void |
1584 | | ssl_protocol_cb(int write_p, int version OVS_UNUSED, int content_type, |
1585 | | const void *buf_, size_t len, SSL *ssl OVS_UNUSED, void *sslv_) |
1586 | 0 | { |
1587 | 0 | const struct ssl_stream *sslv = sslv_; |
1588 | 0 | const uint8_t *buf = buf_; |
1589 | 0 | struct ds details; |
1590 | |
|
1591 | 0 | if (!VLOG_IS_DBG_ENABLED()) { |
1592 | 0 | return; |
1593 | 0 | } |
1594 | | |
1595 | 0 | ds_init(&details); |
1596 | 0 | if (content_type == 20) { |
1597 | 0 | ds_put_cstr(&details, "change_cipher_spec"); |
1598 | 0 | } else if (content_type == 21) { |
1599 | 0 | ds_put_format(&details, "alert: %s, %s", |
1600 | 0 | ssl_alert_level_to_string(buf[0]), |
1601 | 0 | ssl_alert_description_to_string(buf[1])); |
1602 | 0 | } else if (content_type == 22) { |
1603 | 0 | ds_put_format(&details, "handshake: %s", |
1604 | 0 | ssl_handshake_type_to_string(buf[0])); |
1605 | 0 | } else { |
1606 | 0 | ds_put_format(&details, "type %d", content_type); |
1607 | 0 | } |
1608 | |
|
1609 | 0 | VLOG_DBG("%s%u%s%s %s (%"PRIuSIZE" bytes)", |
1610 | 0 | sslv->type == CLIENT ? "client" : "server", |
1611 | 0 | sslv->session_nr, write_p ? "-->" : "<--", |
1612 | 0 | stream_get_name(&sslv->stream), ds_cstr(&details), len); |
1613 | |
|
1614 | 0 | ds_destroy(&details); |
1615 | 0 | } |