1*ff1ff8a0Sjsing /* $OpenBSD: shutdowntest.c,v 1.3 2024/01/30 14:46:46 jsing Exp $ */
2acc63c60Sjsing /*
3acc63c60Sjsing * Copyright (c) 2020, 2021, 2024 Joel Sing <jsing@openbsd.org>
4acc63c60Sjsing *
5acc63c60Sjsing * Permission to use, copy, modify, and distribute this software for any
6acc63c60Sjsing * purpose with or without fee is hereby granted, provided that the above
7acc63c60Sjsing * copyright notice and this permission notice appear in all copies.
8acc63c60Sjsing *
9acc63c60Sjsing * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10acc63c60Sjsing * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11acc63c60Sjsing * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12acc63c60Sjsing * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13acc63c60Sjsing * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14acc63c60Sjsing * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15acc63c60Sjsing * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16acc63c60Sjsing */
17acc63c60Sjsing
18acc63c60Sjsing #include <err.h>
19acc63c60Sjsing
20acc63c60Sjsing #include <openssl/bio.h>
21acc63c60Sjsing #include <openssl/err.h>
22acc63c60Sjsing #include <openssl/ssl.h>
23acc63c60Sjsing
24acc63c60Sjsing const char *server_ca_file;
25acc63c60Sjsing const char *server_cert_file;
26acc63c60Sjsing const char *server_key_file;
27acc63c60Sjsing
28acc63c60Sjsing int debug = 0;
29acc63c60Sjsing
30acc63c60Sjsing static void
hexdump(const unsigned char * buf,size_t len)31acc63c60Sjsing hexdump(const unsigned char *buf, size_t len)
32acc63c60Sjsing {
33acc63c60Sjsing size_t i;
34acc63c60Sjsing
35acc63c60Sjsing for (i = 1; i <= len; i++)
36acc63c60Sjsing fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n");
37acc63c60Sjsing
38acc63c60Sjsing if (len % 8)
39acc63c60Sjsing fprintf(stderr, "\n");
40acc63c60Sjsing }
41acc63c60Sjsing
42acc63c60Sjsing static SSL *
tls_client(BIO * rbio,BIO * wbio)43acc63c60Sjsing tls_client(BIO *rbio, BIO *wbio)
44acc63c60Sjsing {
45acc63c60Sjsing SSL_CTX *ssl_ctx = NULL;
46acc63c60Sjsing SSL *ssl = NULL;
47acc63c60Sjsing
48acc63c60Sjsing if ((ssl_ctx = SSL_CTX_new(TLS_method())) == NULL)
49acc63c60Sjsing errx(1, "client context");
50acc63c60Sjsing
51acc63c60Sjsing if ((ssl = SSL_new(ssl_ctx)) == NULL)
52acc63c60Sjsing errx(1, "client ssl");
53acc63c60Sjsing
54acc63c60Sjsing BIO_up_ref(rbio);
55acc63c60Sjsing BIO_up_ref(wbio);
56acc63c60Sjsing
57acc63c60Sjsing SSL_set_bio(ssl, rbio, wbio);
58acc63c60Sjsing
59acc63c60Sjsing SSL_CTX_free(ssl_ctx);
60acc63c60Sjsing
61acc63c60Sjsing return ssl;
62acc63c60Sjsing }
63acc63c60Sjsing
64acc63c60Sjsing static SSL *
tls_server(BIO * rbio,BIO * wbio)65acc63c60Sjsing tls_server(BIO *rbio, BIO *wbio)
66acc63c60Sjsing {
67acc63c60Sjsing SSL_CTX *ssl_ctx = NULL;
68acc63c60Sjsing SSL *ssl = NULL;
69acc63c60Sjsing
70acc63c60Sjsing if ((ssl_ctx = SSL_CTX_new(TLS_method())) == NULL)
71acc63c60Sjsing errx(1, "server context");
72acc63c60Sjsing
73acc63c60Sjsing SSL_CTX_set_dh_auto(ssl_ctx, 2);
74acc63c60Sjsing
75acc63c60Sjsing if (SSL_CTX_use_certificate_file(ssl_ctx, server_cert_file,
76acc63c60Sjsing SSL_FILETYPE_PEM) != 1) {
77acc63c60Sjsing fprintf(stderr, "FAIL: Failed to load server certificate");
78acc63c60Sjsing goto failure;
79acc63c60Sjsing }
80acc63c60Sjsing if (SSL_CTX_use_PrivateKey_file(ssl_ctx, server_key_file,
81acc63c60Sjsing SSL_FILETYPE_PEM) != 1) {
82acc63c60Sjsing fprintf(stderr, "FAIL: Failed to load server private key");
83acc63c60Sjsing goto failure;
84acc63c60Sjsing }
85acc63c60Sjsing
86acc63c60Sjsing if ((ssl = SSL_new(ssl_ctx)) == NULL)
87acc63c60Sjsing errx(1, "server ssl");
88acc63c60Sjsing
89acc63c60Sjsing BIO_up_ref(rbio);
90acc63c60Sjsing BIO_up_ref(wbio);
91acc63c60Sjsing
92acc63c60Sjsing SSL_set_bio(ssl, rbio, wbio);
93acc63c60Sjsing
94acc63c60Sjsing failure:
95acc63c60Sjsing SSL_CTX_free(ssl_ctx);
96acc63c60Sjsing
97acc63c60Sjsing return ssl;
98acc63c60Sjsing }
99acc63c60Sjsing
100acc63c60Sjsing static int
ssl_error(SSL * ssl,const char * name,const char * desc,int ssl_ret)101acc63c60Sjsing ssl_error(SSL *ssl, const char *name, const char *desc, int ssl_ret)
102acc63c60Sjsing {
103acc63c60Sjsing int ssl_err;
104acc63c60Sjsing
105acc63c60Sjsing ssl_err = SSL_get_error(ssl, ssl_ret);
106acc63c60Sjsing
107acc63c60Sjsing if (ssl_err == SSL_ERROR_WANT_READ) {
108acc63c60Sjsing return 1;
109acc63c60Sjsing } else if (ssl_err == SSL_ERROR_WANT_WRITE) {
110acc63c60Sjsing return 1;
111acc63c60Sjsing } else if (ssl_err == SSL_ERROR_SYSCALL && errno == 0) {
112acc63c60Sjsing /* Yup, this is apparently a thing... */
113acc63c60Sjsing return 1;
114acc63c60Sjsing } else {
115acc63c60Sjsing fprintf(stderr, "FAIL: %s %s failed - ssl err = %d, errno = %d\n",
116acc63c60Sjsing name, desc, ssl_err, errno);
117acc63c60Sjsing ERR_print_errors_fp(stderr);
118acc63c60Sjsing return 0;
119acc63c60Sjsing }
120acc63c60Sjsing }
121acc63c60Sjsing
122acc63c60Sjsing static int
do_connect(SSL * ssl,const char * name,int * done)123acc63c60Sjsing do_connect(SSL *ssl, const char *name, int *done)
124acc63c60Sjsing {
125acc63c60Sjsing int ssl_ret;
126acc63c60Sjsing
127acc63c60Sjsing if ((ssl_ret = SSL_connect(ssl)) == 1) {
128acc63c60Sjsing fprintf(stderr, "INFO: %s connect done\n", name);
129acc63c60Sjsing *done = 1;
130acc63c60Sjsing return 1;
131acc63c60Sjsing }
132acc63c60Sjsing
133acc63c60Sjsing return ssl_error(ssl, name, "connect", ssl_ret);
134acc63c60Sjsing }
135acc63c60Sjsing
136acc63c60Sjsing static int
do_accept(SSL * ssl,const char * name,int * done)137acc63c60Sjsing do_accept(SSL *ssl, const char *name, int *done)
138acc63c60Sjsing {
139acc63c60Sjsing int ssl_ret;
140acc63c60Sjsing
141acc63c60Sjsing if ((ssl_ret = SSL_accept(ssl)) == 1) {
142acc63c60Sjsing fprintf(stderr, "INFO: %s accept done\n", name);
143acc63c60Sjsing *done = 1;
144acc63c60Sjsing return 1;
145acc63c60Sjsing }
146acc63c60Sjsing
147acc63c60Sjsing return ssl_error(ssl, name, "accept", ssl_ret);
148acc63c60Sjsing }
149acc63c60Sjsing
150acc63c60Sjsing static int
do_read(SSL * ssl,const char * name,int * done)151acc63c60Sjsing do_read(SSL *ssl, const char *name, int *done)
152acc63c60Sjsing {
153acc63c60Sjsing uint8_t buf[512];
154acc63c60Sjsing int ssl_ret;
155acc63c60Sjsing
156acc63c60Sjsing if ((ssl_ret = SSL_read(ssl, buf, sizeof(buf))) > 0) {
157acc63c60Sjsing fprintf(stderr, "INFO: %s read done\n", name);
158acc63c60Sjsing if (debug > 1)
159acc63c60Sjsing hexdump(buf, ssl_ret);
160acc63c60Sjsing *done = 1;
161acc63c60Sjsing return 1;
162acc63c60Sjsing }
163acc63c60Sjsing
164acc63c60Sjsing return ssl_error(ssl, name, "read", ssl_ret);
165acc63c60Sjsing }
166acc63c60Sjsing
167acc63c60Sjsing static int
do_write(SSL * ssl,const char * name,int * done)168acc63c60Sjsing do_write(SSL *ssl, const char *name, int *done)
169acc63c60Sjsing {
170acc63c60Sjsing const uint8_t buf[] = "Hello, World!\n";
171acc63c60Sjsing int ssl_ret;
172acc63c60Sjsing
173acc63c60Sjsing if ((ssl_ret = SSL_write(ssl, buf, sizeof(buf))) > 0) {
174acc63c60Sjsing fprintf(stderr, "INFO: %s write done\n", name);
175acc63c60Sjsing *done = 1;
176acc63c60Sjsing return 1;
177acc63c60Sjsing }
178acc63c60Sjsing
179acc63c60Sjsing return ssl_error(ssl, name, "write", ssl_ret);
180acc63c60Sjsing }
181acc63c60Sjsing
182acc63c60Sjsing static int
do_shutdown(SSL * ssl,const char * name,int * done)183acc63c60Sjsing do_shutdown(SSL *ssl, const char *name, int *done)
184acc63c60Sjsing {
185acc63c60Sjsing int ssl_ret;
186acc63c60Sjsing
187acc63c60Sjsing ssl_ret = SSL_shutdown(ssl);
188acc63c60Sjsing if (ssl_ret == 1) {
189acc63c60Sjsing fprintf(stderr, "INFO: %s shutdown done\n", name);
190acc63c60Sjsing *done = 1;
191acc63c60Sjsing return 1;
192acc63c60Sjsing }
193acc63c60Sjsing
194acc63c60Sjsing /* The astounding EOF condition. */
195acc63c60Sjsing if (ssl_ret == -1 &&
196acc63c60Sjsing SSL_get_error(ssl, ssl_ret) == SSL_ERROR_SYSCALL && errno == 0) {
197acc63c60Sjsing fprintf(stderr, "INFO: %s shutdown encountered EOF\n", name);
198acc63c60Sjsing *done = 1;
199acc63c60Sjsing return 1;
200acc63c60Sjsing }
201acc63c60Sjsing
202acc63c60Sjsing return ssl_error(ssl, name, "shutdown", ssl_ret);
203acc63c60Sjsing }
204acc63c60Sjsing
205acc63c60Sjsing typedef int (*ssl_func)(SSL *ssl, const char *name, int *done);
206acc63c60Sjsing
207acc63c60Sjsing static int
do_client_server_loop(SSL * client,ssl_func client_func,SSL * server,ssl_func server_func)208acc63c60Sjsing do_client_server_loop(SSL *client, ssl_func client_func, SSL *server,
209acc63c60Sjsing ssl_func server_func)
210acc63c60Sjsing {
211acc63c60Sjsing int client_done = 0, server_done = 0;
212acc63c60Sjsing int i = 0;
213acc63c60Sjsing
214acc63c60Sjsing do {
215acc63c60Sjsing if (!client_done) {
216acc63c60Sjsing if (debug)
217acc63c60Sjsing fprintf(stderr, "DEBUG: client loop\n");
218acc63c60Sjsing if (!client_func(client, "client", &client_done))
219acc63c60Sjsing return 0;
220acc63c60Sjsing }
221acc63c60Sjsing if (!server_done) {
222acc63c60Sjsing if (debug)
223acc63c60Sjsing fprintf(stderr, "DEBUG: server loop\n");
224acc63c60Sjsing if (!server_func(server, "server", &server_done))
225acc63c60Sjsing return 0;
226acc63c60Sjsing }
227acc63c60Sjsing } while (i++ < 100 && (!client_done || !server_done));
228acc63c60Sjsing
229acc63c60Sjsing if (!client_done || !server_done)
230acc63c60Sjsing fprintf(stderr, "FAIL: gave up\n");
231acc63c60Sjsing
232acc63c60Sjsing return client_done && server_done;
233acc63c60Sjsing }
234acc63c60Sjsing
235acc63c60Sjsing static int
do_shutdown_loop(SSL * client,SSL * server)236acc63c60Sjsing do_shutdown_loop(SSL *client, SSL *server)
237acc63c60Sjsing {
238acc63c60Sjsing int client_done = 0, server_done = 0;
239acc63c60Sjsing int i = 0;
240acc63c60Sjsing
241acc63c60Sjsing do {
242acc63c60Sjsing if (!client_done) {
243acc63c60Sjsing if (debug)
244acc63c60Sjsing fprintf(stderr, "DEBUG: client loop\n");
245acc63c60Sjsing if (!do_shutdown(client, "client", &client_done))
246acc63c60Sjsing return 0;
247acc63c60Sjsing if (client_done)
248acc63c60Sjsing BIO_set_mem_eof_return(SSL_get_wbio(client), 0);
249acc63c60Sjsing }
250acc63c60Sjsing if (!server_done) {
251acc63c60Sjsing if (debug)
252acc63c60Sjsing fprintf(stderr, "DEBUG: server loop\n");
253acc63c60Sjsing if (!do_shutdown(server, "server", &server_done))
254acc63c60Sjsing return 0;
255acc63c60Sjsing if (server_done)
256acc63c60Sjsing BIO_set_mem_eof_return(SSL_get_wbio(server), 0);
257acc63c60Sjsing }
258acc63c60Sjsing } while (i++ < 100 && (!client_done || !server_done));
259acc63c60Sjsing
260acc63c60Sjsing if (!client_done || !server_done)
261acc63c60Sjsing fprintf(stderr, "FAIL: gave up\n");
262acc63c60Sjsing
263acc63c60Sjsing return client_done && server_done;
264acc63c60Sjsing }
265acc63c60Sjsing
266acc63c60Sjsing static void
ssl_msg_callback(int is_write,int version,int content_type,const void * buf,size_t len,SSL * ssl,void * arg)267acc63c60Sjsing ssl_msg_callback(int is_write, int version, int content_type, const void *buf,
268acc63c60Sjsing size_t len, SSL *ssl, void *arg)
269acc63c60Sjsing {
270acc63c60Sjsing const uint8_t *msg = buf;
271acc63c60Sjsing int *close_notify = arg;
272acc63c60Sjsing
273acc63c60Sjsing if (is_write || content_type != SSL3_RT_ALERT)
274acc63c60Sjsing return;
275acc63c60Sjsing if (len == 2 && msg[0] == SSL3_AL_WARNING && msg[1] == SSL_AD_CLOSE_NOTIFY)
276acc63c60Sjsing *close_notify = 1;
277acc63c60Sjsing }
278acc63c60Sjsing
279acc63c60Sjsing struct shutdown_test {
280acc63c60Sjsing const unsigned char *desc;
281acc63c60Sjsing int client_quiet_shutdown;
282acc63c60Sjsing int client_set_shutdown;
283acc63c60Sjsing int want_client_shutdown;
284acc63c60Sjsing int want_client_close_notify;
285acc63c60Sjsing int server_quiet_shutdown;
286acc63c60Sjsing int server_set_shutdown;
287acc63c60Sjsing int want_server_shutdown;
288acc63c60Sjsing int want_server_close_notify;
289acc63c60Sjsing };
290acc63c60Sjsing
291acc63c60Sjsing static const struct shutdown_test shutdown_tests[] = {
292acc63c60Sjsing {
293acc63c60Sjsing .desc = "bidirectional shutdown",
294acc63c60Sjsing .want_client_close_notify = 1,
295acc63c60Sjsing .want_client_shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN,
296acc63c60Sjsing .want_server_close_notify = 1,
297acc63c60Sjsing .want_server_shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN,
298acc63c60Sjsing },
299acc63c60Sjsing {
300acc63c60Sjsing .desc = "client quiet shutdown",
301acc63c60Sjsing .client_quiet_shutdown = 1,
302acc63c60Sjsing .want_client_shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN,
303acc63c60Sjsing .want_server_shutdown = SSL_SENT_SHUTDOWN,
304acc63c60Sjsing },
305acc63c60Sjsing {
306acc63c60Sjsing .desc = "server quiet shutdown",
307acc63c60Sjsing .server_quiet_shutdown = 1,
308acc63c60Sjsing .want_client_shutdown = SSL_SENT_SHUTDOWN,
309acc63c60Sjsing .want_server_shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN,
310acc63c60Sjsing },
311acc63c60Sjsing {
312acc63c60Sjsing .desc = "both quiet shutdown",
313acc63c60Sjsing .client_quiet_shutdown = 1,
314acc63c60Sjsing .server_quiet_shutdown = 1,
315acc63c60Sjsing .want_client_shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN,
316acc63c60Sjsing .want_server_shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN,
317acc63c60Sjsing },
318acc63c60Sjsing {
319acc63c60Sjsing .desc = "client set sent shutdown",
320acc63c60Sjsing .client_set_shutdown = SSL_SENT_SHUTDOWN,
321acc63c60Sjsing .want_client_close_notify = 1,
322acc63c60Sjsing .want_client_shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN,
323acc63c60Sjsing .want_server_shutdown = SSL_SENT_SHUTDOWN,
324acc63c60Sjsing },
325acc63c60Sjsing {
326acc63c60Sjsing .desc = "client set received shutdown",
327acc63c60Sjsing .client_set_shutdown = SSL_RECEIVED_SHUTDOWN,
328acc63c60Sjsing .want_client_shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN,
329acc63c60Sjsing .want_server_close_notify = 1,
330acc63c60Sjsing .want_server_shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN,
331acc63c60Sjsing },
332acc63c60Sjsing {
333acc63c60Sjsing .desc = "client set sent/received shutdown",
334acc63c60Sjsing .client_set_shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN,
335acc63c60Sjsing .want_client_shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN,
336acc63c60Sjsing .want_server_shutdown = SSL_SENT_SHUTDOWN,
337acc63c60Sjsing },
338acc63c60Sjsing {
339acc63c60Sjsing .desc = "server set sent shutdown",
340acc63c60Sjsing .server_set_shutdown = SSL_SENT_SHUTDOWN,
341acc63c60Sjsing .want_client_shutdown = SSL_SENT_SHUTDOWN,
342acc63c60Sjsing .want_server_close_notify = 1,
343acc63c60Sjsing .want_server_shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN,
344acc63c60Sjsing },
345acc63c60Sjsing {
346acc63c60Sjsing .desc = "server set received shutdown",
347acc63c60Sjsing .server_set_shutdown = SSL_RECEIVED_SHUTDOWN,
348acc63c60Sjsing .want_client_close_notify = 1,
349acc63c60Sjsing .want_client_shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN,
350acc63c60Sjsing .want_server_shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN,
351acc63c60Sjsing },
352acc63c60Sjsing {
353acc63c60Sjsing .desc = "server set sent/received shutdown",
354acc63c60Sjsing .server_set_shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN,
355acc63c60Sjsing .want_client_shutdown = SSL_SENT_SHUTDOWN,
356acc63c60Sjsing .want_server_shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN,
357acc63c60Sjsing },
358acc63c60Sjsing };
359acc63c60Sjsing
360acc63c60Sjsing #define N_TLS_TESTS (sizeof(shutdown_tests) / sizeof(*shutdown_tests))
361acc63c60Sjsing
362acc63c60Sjsing static int
shutdown_test(uint16_t ssl_version,const char * ssl_version_name,const struct shutdown_test * st)363*ff1ff8a0Sjsing shutdown_test(uint16_t ssl_version, const char *ssl_version_name,
364acc63c60Sjsing const struct shutdown_test *st)
365acc63c60Sjsing {
366acc63c60Sjsing BIO *client_wbio = NULL, *server_wbio = NULL;
367acc63c60Sjsing SSL *client = NULL, *server = NULL;
368acc63c60Sjsing int client_close_notify = 0, server_close_notify = 0;
369acc63c60Sjsing int shutdown, ssl_err;
370acc63c60Sjsing int failed = 1;
371acc63c60Sjsing
372acc63c60Sjsing fprintf(stderr, "\n== Testing %s, %s... ==\n", ssl_version_name,
373acc63c60Sjsing st->desc);
374acc63c60Sjsing
375acc63c60Sjsing if ((client_wbio = BIO_new(BIO_s_mem())) == NULL)
376acc63c60Sjsing goto failure;
377acc63c60Sjsing if (BIO_set_mem_eof_return(client_wbio, -1) <= 0)
378acc63c60Sjsing goto failure;
379acc63c60Sjsing
380acc63c60Sjsing if ((server_wbio = BIO_new(BIO_s_mem())) == NULL)
381acc63c60Sjsing goto failure;
382acc63c60Sjsing if (BIO_set_mem_eof_return(server_wbio, -1) <= 0)
383acc63c60Sjsing goto failure;
384acc63c60Sjsing
385acc63c60Sjsing if ((client = tls_client(server_wbio, client_wbio)) == NULL)
386acc63c60Sjsing goto failure;
387acc63c60Sjsing if (!SSL_set_min_proto_version(client, ssl_version))
388acc63c60Sjsing goto failure;
389acc63c60Sjsing if (!SSL_set_max_proto_version(client, ssl_version))
390acc63c60Sjsing goto failure;
391acc63c60Sjsing
392acc63c60Sjsing if ((server = tls_server(client_wbio, server_wbio)) == NULL)
393acc63c60Sjsing goto failure;
394acc63c60Sjsing if (!SSL_set_min_proto_version(server, ssl_version))
395acc63c60Sjsing goto failure;
396acc63c60Sjsing if (!SSL_set_max_proto_version(server, ssl_version))
397acc63c60Sjsing goto failure;
398acc63c60Sjsing
399acc63c60Sjsing if (!do_client_server_loop(client, do_connect, server, do_accept)) {
400acc63c60Sjsing fprintf(stderr, "FAIL: client and server handshake failed\n");
401acc63c60Sjsing goto failure;
402acc63c60Sjsing }
403acc63c60Sjsing
404acc63c60Sjsing if (!do_client_server_loop(client, do_write, server, do_read)) {
405acc63c60Sjsing fprintf(stderr, "FAIL: client write and server read I/O failed\n");
406acc63c60Sjsing goto failure;
407acc63c60Sjsing }
408acc63c60Sjsing
409acc63c60Sjsing if (!do_client_server_loop(client, do_read, server, do_write)) {
410acc63c60Sjsing fprintf(stderr, "FAIL: client read and server write I/O failed\n");
411acc63c60Sjsing goto failure;
412acc63c60Sjsing }
413acc63c60Sjsing
414acc63c60Sjsing /* Seemingly this is the only way to find out about alerts... */
415acc63c60Sjsing SSL_set_msg_callback(client, ssl_msg_callback);
416acc63c60Sjsing SSL_set_msg_callback_arg(client, &client_close_notify);
417acc63c60Sjsing SSL_set_msg_callback(server, ssl_msg_callback);
418acc63c60Sjsing SSL_set_msg_callback_arg(server, &server_close_notify);
419acc63c60Sjsing
420acc63c60Sjsing SSL_set_shutdown(client, st->client_set_shutdown);
421acc63c60Sjsing SSL_set_shutdown(server, st->server_set_shutdown);
422acc63c60Sjsing
423acc63c60Sjsing SSL_set_quiet_shutdown(client, st->client_quiet_shutdown);
424acc63c60Sjsing SSL_set_quiet_shutdown(server, st->server_quiet_shutdown);
425acc63c60Sjsing
426acc63c60Sjsing if (!do_shutdown_loop(client, server)) {
427acc63c60Sjsing fprintf(stderr, "FAIL: client and server shutdown failed\n");
428acc63c60Sjsing goto failure;
429acc63c60Sjsing }
430acc63c60Sjsing
431acc63c60Sjsing if ((shutdown = SSL_get_shutdown(client)) != st->want_client_shutdown) {
432acc63c60Sjsing fprintf(stderr, "FAIL: client shutdown flags = %x, want %x\n",
433acc63c60Sjsing shutdown, st->want_client_shutdown);
434acc63c60Sjsing goto failure;
435acc63c60Sjsing }
436acc63c60Sjsing if ((shutdown = SSL_get_shutdown(server)) != st->want_server_shutdown) {
437acc63c60Sjsing fprintf(stderr, "FAIL: server shutdown flags = %x, want %x\n",
438acc63c60Sjsing shutdown, st->want_server_shutdown);
439acc63c60Sjsing goto failure;
440acc63c60Sjsing }
441acc63c60Sjsing
442acc63c60Sjsing if (client_close_notify != st->want_client_close_notify) {
443acc63c60Sjsing fprintf(stderr, "FAIL: client close notify = %d, want %d\n",
444acc63c60Sjsing client_close_notify, st->want_client_close_notify);
445acc63c60Sjsing goto failure;
446acc63c60Sjsing }
447acc63c60Sjsing if (server_close_notify != st->want_server_close_notify) {
448acc63c60Sjsing fprintf(stderr, "FAIL: server close notify = %d, want %d\n",
449acc63c60Sjsing server_close_notify, st->want_server_close_notify);
450acc63c60Sjsing goto failure;
451acc63c60Sjsing }
452acc63c60Sjsing
453acc63c60Sjsing if (st->want_client_close_notify) {
454acc63c60Sjsing if ((ssl_err = SSL_get_error(client, 0)) != SSL_ERROR_ZERO_RETURN) {
455acc63c60Sjsing fprintf(stderr, "FAIL: client ssl error = %d, want %d\n",
456acc63c60Sjsing ssl_err, SSL_ERROR_ZERO_RETURN);
457acc63c60Sjsing goto failure;
458acc63c60Sjsing }
459acc63c60Sjsing }
460acc63c60Sjsing if (st->want_server_close_notify) {
461acc63c60Sjsing if ((ssl_err = SSL_get_error(server, 0)) != SSL_ERROR_ZERO_RETURN) {
462acc63c60Sjsing fprintf(stderr, "FAIL: server ssl error = %d, want %d\n",
463acc63c60Sjsing ssl_err, SSL_ERROR_ZERO_RETURN);
464acc63c60Sjsing goto failure;
465acc63c60Sjsing }
466acc63c60Sjsing }
467acc63c60Sjsing
468acc63c60Sjsing fprintf(stderr, "INFO: Done!\n");
469acc63c60Sjsing
470acc63c60Sjsing failed = 0;
471acc63c60Sjsing
472acc63c60Sjsing failure:
473acc63c60Sjsing BIO_free(client_wbio);
474acc63c60Sjsing BIO_free(server_wbio);
475acc63c60Sjsing
476acc63c60Sjsing SSL_free(client);
477acc63c60Sjsing SSL_free(server);
478acc63c60Sjsing
479acc63c60Sjsing return failed;
480acc63c60Sjsing }
481acc63c60Sjsing
482*ff1ff8a0Sjsing static int
shutdown_sequence_test(uint16_t ssl_version,const char * ssl_version_name)483*ff1ff8a0Sjsing shutdown_sequence_test(uint16_t ssl_version, const char *ssl_version_name)
484*ff1ff8a0Sjsing {
485*ff1ff8a0Sjsing BIO *client_wbio = NULL, *server_wbio = NULL;
486*ff1ff8a0Sjsing SSL *client = NULL, *server = NULL;
487*ff1ff8a0Sjsing int shutdown, ret;
488*ff1ff8a0Sjsing int failed = 1;
489*ff1ff8a0Sjsing
490*ff1ff8a0Sjsing fprintf(stderr, "\n== Testing %s, shutdown sequence... ==\n",
491*ff1ff8a0Sjsing ssl_version_name);
492*ff1ff8a0Sjsing
493*ff1ff8a0Sjsing if ((client_wbio = BIO_new(BIO_s_mem())) == NULL)
494*ff1ff8a0Sjsing goto failure;
495*ff1ff8a0Sjsing if (BIO_set_mem_eof_return(client_wbio, -1) <= 0)
496*ff1ff8a0Sjsing goto failure;
497*ff1ff8a0Sjsing
498*ff1ff8a0Sjsing if ((server_wbio = BIO_new(BIO_s_mem())) == NULL)
499*ff1ff8a0Sjsing goto failure;
500*ff1ff8a0Sjsing if (BIO_set_mem_eof_return(server_wbio, -1) <= 0)
501*ff1ff8a0Sjsing goto failure;
502*ff1ff8a0Sjsing
503*ff1ff8a0Sjsing if ((client = tls_client(server_wbio, client_wbio)) == NULL)
504*ff1ff8a0Sjsing goto failure;
505*ff1ff8a0Sjsing if (!SSL_set_min_proto_version(client, ssl_version))
506*ff1ff8a0Sjsing goto failure;
507*ff1ff8a0Sjsing if (!SSL_set_max_proto_version(client, ssl_version))
508*ff1ff8a0Sjsing goto failure;
509*ff1ff8a0Sjsing
510*ff1ff8a0Sjsing if ((server = tls_server(client_wbio, server_wbio)) == NULL)
511*ff1ff8a0Sjsing goto failure;
512*ff1ff8a0Sjsing if (!SSL_set_min_proto_version(server, ssl_version))
513*ff1ff8a0Sjsing goto failure;
514*ff1ff8a0Sjsing if (!SSL_set_max_proto_version(server, ssl_version))
515*ff1ff8a0Sjsing goto failure;
516*ff1ff8a0Sjsing
517*ff1ff8a0Sjsing if (!do_client_server_loop(client, do_connect, server, do_accept)) {
518*ff1ff8a0Sjsing fprintf(stderr, "FAIL: client and server handshake failed\n");
519*ff1ff8a0Sjsing goto failure;
520*ff1ff8a0Sjsing }
521*ff1ff8a0Sjsing
522*ff1ff8a0Sjsing if (!do_client_server_loop(client, do_write, server, do_read)) {
523*ff1ff8a0Sjsing fprintf(stderr, "FAIL: client write and server read I/O failed\n");
524*ff1ff8a0Sjsing goto failure;
525*ff1ff8a0Sjsing }
526*ff1ff8a0Sjsing
527*ff1ff8a0Sjsing if (!do_client_server_loop(client, do_read, server, do_write)) {
528*ff1ff8a0Sjsing fprintf(stderr, "FAIL: client read and server write I/O failed\n");
529*ff1ff8a0Sjsing goto failure;
530*ff1ff8a0Sjsing }
531*ff1ff8a0Sjsing
532*ff1ff8a0Sjsing /*
533*ff1ff8a0Sjsing * Shutdown in lock step and check return value and shutdown flags.
534*ff1ff8a0Sjsing *
535*ff1ff8a0Sjsing * It is not documented, however some software relies on SSL_shutdown()
536*ff1ff8a0Sjsing * to only send a close-notify on the first call, then indicate that a
537*ff1ff8a0Sjsing * close-notify was received on a second (or later) call.
538*ff1ff8a0Sjsing */
539*ff1ff8a0Sjsing
540*ff1ff8a0Sjsing if ((shutdown = SSL_get_shutdown(client)) != 0) {
541*ff1ff8a0Sjsing fprintf(stderr, "FAIL: client shutdown flags = %x, want %x\n",
542*ff1ff8a0Sjsing shutdown, 0);
543*ff1ff8a0Sjsing goto failure;
544*ff1ff8a0Sjsing }
545*ff1ff8a0Sjsing if ((shutdown = SSL_get_shutdown(server)) != 0) {
546*ff1ff8a0Sjsing fprintf(stderr, "FAIL: server shutdown flags = %x, want %x\n",
547*ff1ff8a0Sjsing shutdown, 0);
548*ff1ff8a0Sjsing goto failure;
549*ff1ff8a0Sjsing }
550*ff1ff8a0Sjsing
551*ff1ff8a0Sjsing if ((ret = SSL_shutdown(client)) != 0) {
552*ff1ff8a0Sjsing fprintf(stderr, "FAIL: client SSL_shutdown() = %d, want %d\n",
553*ff1ff8a0Sjsing ret, 0);
554*ff1ff8a0Sjsing goto failure;
555*ff1ff8a0Sjsing }
556*ff1ff8a0Sjsing if ((shutdown = SSL_get_shutdown(client)) != SSL_SENT_SHUTDOWN) {
557*ff1ff8a0Sjsing fprintf(stderr, "FAIL: client shutdown flags = %x, want %x\n",
558*ff1ff8a0Sjsing shutdown, SSL_SENT_SHUTDOWN);
559*ff1ff8a0Sjsing goto failure;
560*ff1ff8a0Sjsing }
561*ff1ff8a0Sjsing
562*ff1ff8a0Sjsing if ((ret = SSL_shutdown(server)) != 0) {
563*ff1ff8a0Sjsing fprintf(stderr, "FAIL: server SSL_shutdown() = %d, want %d\n",
564*ff1ff8a0Sjsing ret, 0);
565*ff1ff8a0Sjsing goto failure;
566*ff1ff8a0Sjsing }
567*ff1ff8a0Sjsing if ((shutdown = SSL_get_shutdown(server)) != SSL_SENT_SHUTDOWN) {
568*ff1ff8a0Sjsing fprintf(stderr, "FAIL: server shutdown flags = %x, want %x\n",
569*ff1ff8a0Sjsing shutdown, SSL_SENT_SHUTDOWN);
570*ff1ff8a0Sjsing goto failure;
571*ff1ff8a0Sjsing }
572*ff1ff8a0Sjsing
573*ff1ff8a0Sjsing if ((ret = SSL_shutdown(client)) != 1) {
574*ff1ff8a0Sjsing fprintf(stderr, "FAIL: client SSL_shutdown() = %d, want %d\n",
575*ff1ff8a0Sjsing ret, 0);
576*ff1ff8a0Sjsing goto failure;
577*ff1ff8a0Sjsing }
578*ff1ff8a0Sjsing if ((shutdown = SSL_get_shutdown(client)) !=
579*ff1ff8a0Sjsing (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN)) {
580*ff1ff8a0Sjsing fprintf(stderr, "FAIL: client shutdown flags = %x, want %x\n",
581*ff1ff8a0Sjsing shutdown, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
582*ff1ff8a0Sjsing goto failure;
583*ff1ff8a0Sjsing }
584*ff1ff8a0Sjsing
585*ff1ff8a0Sjsing if ((ret = SSL_shutdown(server)) != 1) {
586*ff1ff8a0Sjsing fprintf(stderr, "FAIL: server SSL_shutdown() = %d, want %d\n",
587*ff1ff8a0Sjsing ret, 0);
588*ff1ff8a0Sjsing goto failure;
589*ff1ff8a0Sjsing }
590*ff1ff8a0Sjsing if ((shutdown = SSL_get_shutdown(server)) !=
591*ff1ff8a0Sjsing (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN)) {
592*ff1ff8a0Sjsing fprintf(stderr, "FAIL: server shutdown flags = %x, want %x\n",
593*ff1ff8a0Sjsing shutdown, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
594*ff1ff8a0Sjsing goto failure;
595*ff1ff8a0Sjsing }
596*ff1ff8a0Sjsing
597*ff1ff8a0Sjsing fprintf(stderr, "INFO: Done!\n");
598*ff1ff8a0Sjsing
599*ff1ff8a0Sjsing failed = 0;
600*ff1ff8a0Sjsing
601*ff1ff8a0Sjsing failure:
602*ff1ff8a0Sjsing BIO_free(client_wbio);
603*ff1ff8a0Sjsing BIO_free(server_wbio);
604*ff1ff8a0Sjsing
605*ff1ff8a0Sjsing SSL_free(client);
606*ff1ff8a0Sjsing SSL_free(server);
607*ff1ff8a0Sjsing
608*ff1ff8a0Sjsing return failed;
609*ff1ff8a0Sjsing }
610*ff1ff8a0Sjsing
611acc63c60Sjsing struct ssl_version {
612acc63c60Sjsing uint16_t version;
613acc63c60Sjsing const char *name;
614acc63c60Sjsing };
615acc63c60Sjsing
616acc63c60Sjsing struct ssl_version ssl_versions[] = {
617acc63c60Sjsing {
618acc63c60Sjsing .version = TLS1_2_VERSION,
619acc63c60Sjsing .name = SSL_TXT_TLSV1_2,
620acc63c60Sjsing },
621acc63c60Sjsing {
622acc63c60Sjsing .version = TLS1_3_VERSION,
623acc63c60Sjsing .name = SSL_TXT_TLSV1_3,
624acc63c60Sjsing },
625acc63c60Sjsing };
626acc63c60Sjsing
627acc63c60Sjsing #define N_SSL_VERSIONS (sizeof(ssl_versions) / sizeof(*ssl_versions))
628acc63c60Sjsing
629acc63c60Sjsing int
main(int argc,char ** argv)630acc63c60Sjsing main(int argc, char **argv)
631acc63c60Sjsing {
632acc63c60Sjsing const struct ssl_version *sv;
633acc63c60Sjsing int failed = 0;
634acc63c60Sjsing size_t i, j;
635acc63c60Sjsing
636acc63c60Sjsing if (argc != 4) {
637acc63c60Sjsing fprintf(stderr, "usage: %s keyfile certfile cafile\n",
638acc63c60Sjsing argv[0]);
639acc63c60Sjsing exit(1);
640acc63c60Sjsing }
641acc63c60Sjsing
642acc63c60Sjsing server_key_file = argv[1];
643acc63c60Sjsing server_cert_file = argv[2];
644acc63c60Sjsing server_ca_file = argv[3];
645acc63c60Sjsing
646acc63c60Sjsing for (i = 0; i < N_SSL_VERSIONS; i++) {
647acc63c60Sjsing sv = &ssl_versions[i];
648acc63c60Sjsing for (j = 0; j < N_TLS_TESTS; j++) {
649*ff1ff8a0Sjsing failed |= shutdown_test(sv->version, sv->name,
650acc63c60Sjsing &shutdown_tests[j]);
651acc63c60Sjsing }
652*ff1ff8a0Sjsing failed |= shutdown_sequence_test(sv->version, sv->name);
653acc63c60Sjsing }
654acc63c60Sjsing
655acc63c60Sjsing return failed;
656acc63c60Sjsing }
657