1*c9675a23Stb /* $OpenBSD: dtlstest.c,v 1.18 2022/11/26 16:08:56 tb Exp $ */
21a5a1f2aSjsing /*
3b48caa61Sjsing * Copyright (c) 2020, 2021 Joel Sing <jsing@openbsd.org>
41a5a1f2aSjsing *
51a5a1f2aSjsing * Permission to use, copy, modify, and distribute this software for any
61a5a1f2aSjsing * purpose with or without fee is hereby granted, provided that the above
71a5a1f2aSjsing * copyright notice and this permission notice appear in all copies.
81a5a1f2aSjsing *
91a5a1f2aSjsing * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
101a5a1f2aSjsing * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
111a5a1f2aSjsing * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
121a5a1f2aSjsing * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
131a5a1f2aSjsing * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
141a5a1f2aSjsing * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
151a5a1f2aSjsing * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
161a5a1f2aSjsing */
171a5a1f2aSjsing
181a5a1f2aSjsing #include <netinet/in.h>
191a5a1f2aSjsing #include <sys/socket.h>
201a5a1f2aSjsing
211a5a1f2aSjsing #include <err.h>
221bae8d68Sinoguchi #include <limits.h>
231a5a1f2aSjsing #include <poll.h>
241a5a1f2aSjsing #include <unistd.h>
251a5a1f2aSjsing
261a5a1f2aSjsing #include <openssl/bio.h>
271a5a1f2aSjsing #include <openssl/err.h>
281a5a1f2aSjsing #include <openssl/ssl.h>
291a5a1f2aSjsing
30605fe30eStb #include "bio_local.h"
31*c9675a23Stb #include "ssl_local.h"
3239e756f1Sjsing
331a5a1f2aSjsing const char *server_ca_file;
341a5a1f2aSjsing const char *server_cert_file;
351a5a1f2aSjsing const char *server_key_file;
361a5a1f2aSjsing
371a5a1f2aSjsing char dtls_cookie[32];
381a5a1f2aSjsing
3981b11609Sjsing int debug = 0;
4081b11609Sjsing
4139e756f1Sjsing void tls12_record_layer_set_initial_epoch(struct tls12_record_layer *rl,
4239e756f1Sjsing uint16_t epoch);
4339e756f1Sjsing
447d0fb893Sjsing static void
hexdump(const unsigned char * buf,size_t len)457d0fb893Sjsing hexdump(const unsigned char *buf, size_t len)
467d0fb893Sjsing {
477d0fb893Sjsing size_t i;
487d0fb893Sjsing
497d0fb893Sjsing for (i = 1; i <= len; i++)
507d0fb893Sjsing fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n");
517d0fb893Sjsing
527d0fb893Sjsing if (len % 8)
537d0fb893Sjsing fprintf(stderr, "\n");
547d0fb893Sjsing }
557d0fb893Sjsing
56b48caa61Sjsing #define BIO_C_DELAY_COUNT 1000
57b48caa61Sjsing #define BIO_C_DELAY_FLUSH 1001
58b48caa61Sjsing #define BIO_C_DELAY_PACKET 1002
59b48caa61Sjsing #define BIO_C_DROP_PACKET 1003
60b48caa61Sjsing #define BIO_C_DROP_RANDOM 1004
617d0fb893Sjsing
627d0fb893Sjsing struct bio_packet_monkey_ctx {
63b48caa61Sjsing unsigned int delay_count;
64b48caa61Sjsing unsigned int delay_mask;
657d0fb893Sjsing unsigned int drop_rand;
667d0fb893Sjsing unsigned int drop_mask;
67b48caa61Sjsing uint8_t *delayed_msg;
68b48caa61Sjsing size_t delayed_msg_len;
697d0fb893Sjsing };
707d0fb893Sjsing
717d0fb893Sjsing static int
bio_packet_monkey_new(BIO * bio)727d0fb893Sjsing bio_packet_monkey_new(BIO *bio)
737d0fb893Sjsing {
747d0fb893Sjsing struct bio_packet_monkey_ctx *ctx;
757d0fb893Sjsing
767d0fb893Sjsing if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
777d0fb893Sjsing return 0;
787d0fb893Sjsing
797d0fb893Sjsing bio->flags = 0;
807d0fb893Sjsing bio->init = 1;
817d0fb893Sjsing bio->num = 0;
827d0fb893Sjsing bio->ptr = ctx;
837d0fb893Sjsing
847d0fb893Sjsing return 1;
857d0fb893Sjsing }
867d0fb893Sjsing
877d0fb893Sjsing static int
bio_packet_monkey_free(BIO * bio)887d0fb893Sjsing bio_packet_monkey_free(BIO *bio)
897d0fb893Sjsing {
907d0fb893Sjsing struct bio_packet_monkey_ctx *ctx;
917d0fb893Sjsing
927d0fb893Sjsing if (bio == NULL)
937d0fb893Sjsing return 1;
947d0fb893Sjsing
957d0fb893Sjsing ctx = bio->ptr;
96b48caa61Sjsing free(ctx->delayed_msg);
977d0fb893Sjsing free(ctx);
987d0fb893Sjsing
997d0fb893Sjsing return 1;
1007d0fb893Sjsing }
1017d0fb893Sjsing
102b48caa61Sjsing static int
bio_packet_monkey_delay_flush(BIO * bio)103b48caa61Sjsing bio_packet_monkey_delay_flush(BIO *bio)
104b48caa61Sjsing {
105b48caa61Sjsing struct bio_packet_monkey_ctx *ctx = bio->ptr;
106b48caa61Sjsing
107b48caa61Sjsing if (ctx->delayed_msg == NULL)
108b48caa61Sjsing return 1;
109b48caa61Sjsing
110b48caa61Sjsing if (debug)
111b48caa61Sjsing fprintf(stderr, "DEBUG: flushing delayed packet...\n");
112b48caa61Sjsing if (debug > 1)
113b48caa61Sjsing hexdump(ctx->delayed_msg, ctx->delayed_msg_len);
114b48caa61Sjsing
115b48caa61Sjsing BIO_write(bio->next_bio, ctx->delayed_msg, ctx->delayed_msg_len);
116b48caa61Sjsing
117b48caa61Sjsing free(ctx->delayed_msg);
118b48caa61Sjsing ctx->delayed_msg = NULL;
119b48caa61Sjsing
120b48caa61Sjsing return BIO_ctrl(bio->next_bio, BIO_CTRL_FLUSH, 0, NULL);
121b48caa61Sjsing }
122b48caa61Sjsing
1237d0fb893Sjsing static long
bio_packet_monkey_ctrl(BIO * bio,int cmd,long num,void * ptr)1247d0fb893Sjsing bio_packet_monkey_ctrl(BIO *bio, int cmd, long num, void *ptr)
1257d0fb893Sjsing {
1267d0fb893Sjsing struct bio_packet_monkey_ctx *ctx;
1277d0fb893Sjsing
1287d0fb893Sjsing ctx = bio->ptr;
1297d0fb893Sjsing
1307d0fb893Sjsing switch (cmd) {
131b48caa61Sjsing case BIO_C_DELAY_COUNT:
132b48caa61Sjsing if (num < 1 || num > 31)
133b48caa61Sjsing return 0;
134b48caa61Sjsing ctx->delay_count = num;
135b48caa61Sjsing return 1;
136b48caa61Sjsing
137b48caa61Sjsing case BIO_C_DELAY_FLUSH:
138b48caa61Sjsing return bio_packet_monkey_delay_flush(bio);
139b48caa61Sjsing
140b48caa61Sjsing case BIO_C_DELAY_PACKET:
141b48caa61Sjsing if (num < 1 || num > 31)
142b48caa61Sjsing return 0;
143b48caa61Sjsing ctx->delay_mask |= 1 << ((unsigned int)num - 1);
144b48caa61Sjsing return 1;
145b48caa61Sjsing
1467d0fb893Sjsing case BIO_C_DROP_PACKET:
1477d0fb893Sjsing if (num < 1 || num > 31)
1487d0fb893Sjsing return 0;
1497d0fb893Sjsing ctx->drop_mask |= 1 << ((unsigned int)num - 1);
1507d0fb893Sjsing return 1;
1517d0fb893Sjsing
1527d0fb893Sjsing case BIO_C_DROP_RANDOM:
153c5ce5111Stb if (num < 0 || (size_t)num > UINT_MAX)
1547d0fb893Sjsing return 0;
1557d0fb893Sjsing ctx->drop_rand = (unsigned int)num;
1567d0fb893Sjsing return 1;
1577d0fb893Sjsing }
1587d0fb893Sjsing
1597d0fb893Sjsing if (bio->next_bio == NULL)
1607d0fb893Sjsing return 0;
1617d0fb893Sjsing
1627d0fb893Sjsing return BIO_ctrl(bio->next_bio, cmd, num, ptr);
1637d0fb893Sjsing }
1647d0fb893Sjsing
1657d0fb893Sjsing static int
bio_packet_monkey_read(BIO * bio,char * out,int out_len)1667d0fb893Sjsing bio_packet_monkey_read(BIO *bio, char *out, int out_len)
1677d0fb893Sjsing {
1687d0fb893Sjsing struct bio_packet_monkey_ctx *ctx = bio->ptr;
1697d0fb893Sjsing int ret;
1707d0fb893Sjsing
1717d0fb893Sjsing if (ctx == NULL || bio->next_bio == NULL)
1727d0fb893Sjsing return 0;
1737d0fb893Sjsing
1747d0fb893Sjsing ret = BIO_read(bio->next_bio, out, out_len);
1757d0fb893Sjsing
176b48caa61Sjsing if (ret > 0) {
177b48caa61Sjsing if (debug)
178b48caa61Sjsing fprintf(stderr, "DEBUG: read packet...\n");
179b48caa61Sjsing if (debug > 1)
180b48caa61Sjsing hexdump(out, ret);
181b48caa61Sjsing }
182b48caa61Sjsing
1837d0fb893Sjsing BIO_clear_retry_flags(bio);
1847d0fb893Sjsing if (ret <= 0 && BIO_should_retry(bio->next_bio))
1857d0fb893Sjsing BIO_set_retry_read(bio);
1867d0fb893Sjsing
1877d0fb893Sjsing return ret;
1887d0fb893Sjsing }
1897d0fb893Sjsing
1907d0fb893Sjsing static int
bio_packet_monkey_write(BIO * bio,const char * in,int in_len)1917d0fb893Sjsing bio_packet_monkey_write(BIO *bio, const char *in, int in_len)
1927d0fb893Sjsing {
1937d0fb893Sjsing struct bio_packet_monkey_ctx *ctx = bio->ptr;
194b48caa61Sjsing const char *label = "writing";
195b48caa61Sjsing int delay = 0, drop = 0;
1967d0fb893Sjsing int ret;
1977d0fb893Sjsing
1987d0fb893Sjsing if (ctx == NULL || bio->next_bio == NULL)
1997d0fb893Sjsing return 0;
2007d0fb893Sjsing
201b48caa61Sjsing if (ctx->delayed_msg != NULL && ctx->delay_count > 0)
202b48caa61Sjsing ctx->delay_count--;
203b48caa61Sjsing
204b48caa61Sjsing if (ctx->delayed_msg != NULL && ctx->delay_count == 0) {
205b48caa61Sjsing if (debug)
206b48caa61Sjsing fprintf(stderr, "DEBUG: writing delayed packet...\n");
207b48caa61Sjsing if (debug > 1)
208b48caa61Sjsing hexdump(ctx->delayed_msg, ctx->delayed_msg_len);
209b48caa61Sjsing
210b48caa61Sjsing ret = BIO_write(bio->next_bio, ctx->delayed_msg,
211b48caa61Sjsing ctx->delayed_msg_len);
212b48caa61Sjsing
213b48caa61Sjsing BIO_clear_retry_flags(bio);
214b48caa61Sjsing if (ret <= 0 && BIO_should_retry(bio->next_bio)) {
215b48caa61Sjsing BIO_set_retry_write(bio);
216b48caa61Sjsing return (ret);
217b48caa61Sjsing }
218b48caa61Sjsing
219b48caa61Sjsing free(ctx->delayed_msg);
220b48caa61Sjsing ctx->delayed_msg = NULL;
221b48caa61Sjsing }
222b48caa61Sjsing
223b48caa61Sjsing if (ctx->delay_mask > 0) {
224b48caa61Sjsing delay = ctx->delay_mask & 1;
225b48caa61Sjsing ctx->delay_mask >>= 1;
226b48caa61Sjsing }
2277d0fb893Sjsing if (ctx->drop_rand > 0) {
2287d0fb893Sjsing drop = arc4random_uniform(ctx->drop_rand) == 0;
2297d0fb893Sjsing } else if (ctx->drop_mask > 0) {
2307d0fb893Sjsing drop = ctx->drop_mask & 1;
2317d0fb893Sjsing ctx->drop_mask >>= 1;
2327d0fb893Sjsing }
233b48caa61Sjsing
234b48caa61Sjsing if (delay)
235b48caa61Sjsing label = "delaying";
236b48caa61Sjsing if (drop)
237b48caa61Sjsing label = "dropping";
238b48caa61Sjsing if (debug)
239b48caa61Sjsing fprintf(stderr, "DEBUG: %s packet...\n", label);
240311d0beaSjsing if (debug > 1)
2417d0fb893Sjsing hexdump(in, in_len);
242b48caa61Sjsing
2437d0fb893Sjsing if (drop)
2447d0fb893Sjsing return in_len;
2457d0fb893Sjsing
246b48caa61Sjsing if (delay) {
247b48caa61Sjsing if (ctx->delayed_msg != NULL)
248b48caa61Sjsing return 0;
249b48caa61Sjsing if ((ctx->delayed_msg = calloc(1, in_len)) == NULL)
250b48caa61Sjsing return 0;
251b48caa61Sjsing memcpy(ctx->delayed_msg, in, in_len);
252b48caa61Sjsing ctx->delayed_msg_len = in_len;
253b48caa61Sjsing return in_len;
254b48caa61Sjsing }
255b48caa61Sjsing
2567d0fb893Sjsing ret = BIO_write(bio->next_bio, in, in_len);
2577d0fb893Sjsing
2587d0fb893Sjsing BIO_clear_retry_flags(bio);
2597d0fb893Sjsing if (ret <= 0 && BIO_should_retry(bio->next_bio))
2607d0fb893Sjsing BIO_set_retry_write(bio);
2617d0fb893Sjsing
2627d0fb893Sjsing return ret;
2637d0fb893Sjsing }
2647d0fb893Sjsing
2657d0fb893Sjsing static int
bio_packet_monkey_puts(BIO * bio,const char * str)2667d0fb893Sjsing bio_packet_monkey_puts(BIO *bio, const char *str)
2677d0fb893Sjsing {
2687d0fb893Sjsing return bio_packet_monkey_write(bio, str, strlen(str));
2697d0fb893Sjsing }
2707d0fb893Sjsing
2717d0fb893Sjsing static const BIO_METHOD bio_packet_monkey = {
2727d0fb893Sjsing .type = BIO_TYPE_BUFFER,
2737d0fb893Sjsing .name = "packet monkey",
2747d0fb893Sjsing .bread = bio_packet_monkey_read,
2757d0fb893Sjsing .bwrite = bio_packet_monkey_write,
2767d0fb893Sjsing .bputs = bio_packet_monkey_puts,
2777d0fb893Sjsing .ctrl = bio_packet_monkey_ctrl,
2787d0fb893Sjsing .create = bio_packet_monkey_new,
2797d0fb893Sjsing .destroy = bio_packet_monkey_free
2807d0fb893Sjsing };
2817d0fb893Sjsing
2827d0fb893Sjsing static const BIO_METHOD *
BIO_f_packet_monkey(void)2837d0fb893Sjsing BIO_f_packet_monkey(void)
2847d0fb893Sjsing {
2857d0fb893Sjsing return &bio_packet_monkey;
2867d0fb893Sjsing }
2877d0fb893Sjsing
2887d0fb893Sjsing static BIO *
BIO_new_packet_monkey(void)2897d0fb893Sjsing BIO_new_packet_monkey(void)
2907d0fb893Sjsing {
2917d0fb893Sjsing return BIO_new(BIO_f_packet_monkey());
2927d0fb893Sjsing }
2937d0fb893Sjsing
2947d0fb893Sjsing static int
BIO_packet_monkey_delay(BIO * bio,int num,int count)295b48caa61Sjsing BIO_packet_monkey_delay(BIO *bio, int num, int count)
296b48caa61Sjsing {
297b48caa61Sjsing if (!BIO_ctrl(bio, BIO_C_DELAY_COUNT, count, NULL))
298b48caa61Sjsing return 0;
299b48caa61Sjsing
300b48caa61Sjsing return BIO_ctrl(bio, BIO_C_DELAY_PACKET, num, NULL);
301b48caa61Sjsing }
302b48caa61Sjsing
303b48caa61Sjsing static int
BIO_packet_monkey_delay_flush(BIO * bio)304b48caa61Sjsing BIO_packet_monkey_delay_flush(BIO *bio)
305b48caa61Sjsing {
306b48caa61Sjsing return BIO_ctrl(bio, BIO_C_DELAY_FLUSH, 0, NULL);
307b48caa61Sjsing }
308b48caa61Sjsing
309b48caa61Sjsing static int
BIO_packet_monkey_drop(BIO * bio,int num)3107d0fb893Sjsing BIO_packet_monkey_drop(BIO *bio, int num)
3117d0fb893Sjsing {
3127d0fb893Sjsing return BIO_ctrl(bio, BIO_C_DROP_PACKET, num, NULL);
3137d0fb893Sjsing }
3147d0fb893Sjsing
3157d0fb893Sjsing #if 0
3167d0fb893Sjsing static int
3177d0fb893Sjsing BIO_packet_monkey_drop_random(BIO *bio, int num)
3187d0fb893Sjsing {
3197d0fb893Sjsing return BIO_ctrl(bio, BIO_C_DROP_RANDOM, num, NULL);
3207d0fb893Sjsing }
3217d0fb893Sjsing #endif
3227d0fb893Sjsing
3231a5a1f2aSjsing static int
datagram_pair(int * client_sock,int * server_sock,struct sockaddr_in * server_sin)3241a5a1f2aSjsing datagram_pair(int *client_sock, int *server_sock,
3251a5a1f2aSjsing struct sockaddr_in *server_sin)
3261a5a1f2aSjsing {
3271a5a1f2aSjsing struct sockaddr_in sin;
3281a5a1f2aSjsing socklen_t sock_len;
3291a5a1f2aSjsing int cs = -1, ss = -1;
3301a5a1f2aSjsing
3311a5a1f2aSjsing memset(&sin, 0, sizeof(sin));
3321a5a1f2aSjsing sin.sin_family = AF_INET;
3331a5a1f2aSjsing sin.sin_port = 0;
3341a5a1f2aSjsing sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3351a5a1f2aSjsing
3361a5a1f2aSjsing if ((ss = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
3371a5a1f2aSjsing err(1, "server socket");
3381a5a1f2aSjsing if (bind(ss, (struct sockaddr *)&sin, sizeof(sin)) == -1)
3391a5a1f2aSjsing err(1, "server bind");
3401a5a1f2aSjsing sock_len = sizeof(sin);
3411a5a1f2aSjsing if (getsockname(ss, (struct sockaddr *)&sin, &sock_len) == -1)
3421a5a1f2aSjsing err(1, "server getsockname");
3431a5a1f2aSjsing
3441a5a1f2aSjsing if ((cs = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
3451a5a1f2aSjsing err(1, "client socket");
3461a5a1f2aSjsing if (connect(cs, (struct sockaddr *)&sin, sizeof(sin)) == -1)
3471a5a1f2aSjsing err(1, "client connect");
3481a5a1f2aSjsing
3491a5a1f2aSjsing *client_sock = cs;
3501a5a1f2aSjsing *server_sock = ss;
3511a5a1f2aSjsing memcpy(server_sin, &sin, sizeof(sin));
3521a5a1f2aSjsing
3531a5a1f2aSjsing return 1;
3541a5a1f2aSjsing }
3551a5a1f2aSjsing
3561a5a1f2aSjsing static int
poll_timeout(SSL * client,SSL * server)3571a5a1f2aSjsing poll_timeout(SSL *client, SSL *server)
3581a5a1f2aSjsing {
3591a5a1f2aSjsing int client_timeout = 0, server_timeout = 0;
3601a5a1f2aSjsing struct timeval timeout;
3611a5a1f2aSjsing
3621a5a1f2aSjsing if (DTLSv1_get_timeout(client, &timeout))
3631a5a1f2aSjsing client_timeout = timeout.tv_sec * 1000 + timeout.tv_usec / 1000;
3641a5a1f2aSjsing
3651a5a1f2aSjsing if (DTLSv1_get_timeout(server, &timeout))
3661a5a1f2aSjsing server_timeout = timeout.tv_sec * 1000 + timeout.tv_usec / 1000;
3671a5a1f2aSjsing
36801f6b374Stb if (client_timeout < 10)
36901f6b374Stb client_timeout = 10;
37001f6b374Stb if (server_timeout < 10)
37101f6b374Stb server_timeout = 10;
37201f6b374Stb
37301f6b374Stb /* XXX */
37481b11609Sjsing if (client_timeout <= 0)
37581b11609Sjsing return server_timeout;
37681b11609Sjsing if (client_timeout > 0 && server_timeout <= 0)
37781b11609Sjsing return client_timeout;
37881b11609Sjsing if (client_timeout < server_timeout)
3791a5a1f2aSjsing return client_timeout;
3801a5a1f2aSjsing
3811a5a1f2aSjsing return server_timeout;
3821a5a1f2aSjsing }
3831a5a1f2aSjsing
3841a5a1f2aSjsing static int
dtls_cookie_generate(SSL * ssl,unsigned char * cookie,unsigned int * cookie_len)3851a5a1f2aSjsing dtls_cookie_generate(SSL *ssl, unsigned char *cookie,
3861a5a1f2aSjsing unsigned int *cookie_len)
3871a5a1f2aSjsing {
3881a5a1f2aSjsing arc4random_buf(dtls_cookie, sizeof(dtls_cookie));
3891a5a1f2aSjsing memcpy(cookie, dtls_cookie, sizeof(dtls_cookie));
3901a5a1f2aSjsing *cookie_len = sizeof(dtls_cookie);
3911a5a1f2aSjsing
3921a5a1f2aSjsing return 1;
3931a5a1f2aSjsing }
3941a5a1f2aSjsing
3951a5a1f2aSjsing static int
dtls_cookie_verify(SSL * ssl,const unsigned char * cookie,unsigned int cookie_len)3961a5a1f2aSjsing dtls_cookie_verify(SSL *ssl, const unsigned char *cookie,
3971a5a1f2aSjsing unsigned int cookie_len)
3981a5a1f2aSjsing {
3991a5a1f2aSjsing return cookie_len == sizeof(dtls_cookie) &&
4001a5a1f2aSjsing memcmp(cookie, dtls_cookie, sizeof(dtls_cookie)) == 0;
4011a5a1f2aSjsing }
4021a5a1f2aSjsing
4037d0fb893Sjsing static void
dtls_info_callback(const SSL * ssl,int type,int val)4047d0fb893Sjsing dtls_info_callback(const SSL *ssl, int type, int val)
4057d0fb893Sjsing {
4067d0fb893Sjsing /*
407fbc84eb9Sjsing * Squeals ahead... remove the bbio from the info callback, so we can
4087d0fb893Sjsing * drop specific messages. Ideally this would be an option for the SSL.
4097d0fb893Sjsing */
4107d0fb893Sjsing if (ssl->wbio == ssl->bbio)
4117d0fb893Sjsing ((SSL *)ssl)->wbio = BIO_pop(ssl->wbio);
4127d0fb893Sjsing }
4137d0fb893Sjsing
4141a5a1f2aSjsing static SSL *
dtls_client(int sock,struct sockaddr_in * server_sin,long mtu)4151a5a1f2aSjsing dtls_client(int sock, struct sockaddr_in *server_sin, long mtu)
4161a5a1f2aSjsing {
4171a5a1f2aSjsing SSL_CTX *ssl_ctx = NULL;
4181a5a1f2aSjsing SSL *ssl = NULL;
4191a5a1f2aSjsing BIO *bio = NULL;
4201a5a1f2aSjsing
4211a5a1f2aSjsing if ((bio = BIO_new_dgram(sock, BIO_NOCLOSE)) == NULL)
4221a5a1f2aSjsing errx(1, "client bio");
4231a5a1f2aSjsing if (!BIO_socket_nbio(sock, 1))
4241a5a1f2aSjsing errx(1, "client nbio");
4251a5a1f2aSjsing if (!BIO_ctrl_set_connected(bio, 1, server_sin))
4261a5a1f2aSjsing errx(1, "client set connected");
4271a5a1f2aSjsing
4281a5a1f2aSjsing if ((ssl_ctx = SSL_CTX_new(DTLS_method())) == NULL)
4291a5a1f2aSjsing errx(1, "client context");
4301a5a1f2aSjsing
4311a5a1f2aSjsing if ((ssl = SSL_new(ssl_ctx)) == NULL)
4321a5a1f2aSjsing errx(1, "client ssl");
4331a5a1f2aSjsing
4341a5a1f2aSjsing SSL_set_bio(ssl, bio, bio);
4351a5a1f2aSjsing bio = NULL;
4361a5a1f2aSjsing
4371a5a1f2aSjsing if (mtu > 0) {
4381a5a1f2aSjsing SSL_set_options(ssl, SSL_OP_NO_QUERY_MTU);
4391a5a1f2aSjsing SSL_set_mtu(ssl, mtu);
4401a5a1f2aSjsing }
4411a5a1f2aSjsing
4421a5a1f2aSjsing SSL_CTX_free(ssl_ctx);
4431a5a1f2aSjsing BIO_free(bio);
4441a5a1f2aSjsing
4451a5a1f2aSjsing return ssl;
4461a5a1f2aSjsing }
4471a5a1f2aSjsing
4481a5a1f2aSjsing static SSL *
dtls_server(int sock,long options,long mtu)4491a5a1f2aSjsing dtls_server(int sock, long options, long mtu)
4501a5a1f2aSjsing {
4511a5a1f2aSjsing SSL_CTX *ssl_ctx = NULL;
4521a5a1f2aSjsing SSL *ssl = NULL;
4531a5a1f2aSjsing BIO *bio = NULL;
4541a5a1f2aSjsing
4551a5a1f2aSjsing if ((bio = BIO_new_dgram(sock, BIO_NOCLOSE)) == NULL)
4561a5a1f2aSjsing errx(1, "server bio");
4571a5a1f2aSjsing if (!BIO_socket_nbio(sock, 1))
4581a5a1f2aSjsing errx(1, "server nbio");
4591a5a1f2aSjsing
4601a5a1f2aSjsing if ((ssl_ctx = SSL_CTX_new(DTLS_method())) == NULL)
4611a5a1f2aSjsing errx(1, "server context");
4621a5a1f2aSjsing
4631a5a1f2aSjsing SSL_CTX_set_cookie_generate_cb(ssl_ctx, dtls_cookie_generate);
4641a5a1f2aSjsing SSL_CTX_set_cookie_verify_cb(ssl_ctx, dtls_cookie_verify);
4658420b909Sjsing SSL_CTX_set_dh_auto(ssl_ctx, 2);
4661a5a1f2aSjsing SSL_CTX_set_options(ssl_ctx, options);
4671a5a1f2aSjsing
4686a6c9bf4Stb if (SSL_CTX_use_certificate_chain_file(ssl_ctx, server_cert_file) != 1) {
4691a5a1f2aSjsing fprintf(stderr, "FAIL: Failed to load server certificate");
4701a5a1f2aSjsing goto failure;
4711a5a1f2aSjsing }
4721a5a1f2aSjsing if (SSL_CTX_use_PrivateKey_file(ssl_ctx, server_key_file,
4731a5a1f2aSjsing SSL_FILETYPE_PEM) != 1) {
4741a5a1f2aSjsing fprintf(stderr, "FAIL: Failed to load server private key");
4751a5a1f2aSjsing goto failure;
4761a5a1f2aSjsing }
4771a5a1f2aSjsing
4781a5a1f2aSjsing if ((ssl = SSL_new(ssl_ctx)) == NULL)
4791a5a1f2aSjsing errx(1, "server ssl");
4801a5a1f2aSjsing
4816a6c9bf4Stb if (SSL_use_certificate_chain_file(ssl, server_cert_file) != 1) {
4826a6c9bf4Stb fprintf(stderr, "FAIL: Failed to load server certificate");
4836a6c9bf4Stb goto failure;
4846a6c9bf4Stb }
4851a5a1f2aSjsing SSL_set_bio(ssl, bio, bio);
4861a5a1f2aSjsing bio = NULL;
4871a5a1f2aSjsing
4881a5a1f2aSjsing if (mtu > 0) {
4891a5a1f2aSjsing SSL_set_options(ssl, SSL_OP_NO_QUERY_MTU);
4901a5a1f2aSjsing SSL_set_mtu(ssl, mtu);
4911a5a1f2aSjsing }
4921a5a1f2aSjsing
4931a5a1f2aSjsing failure:
4941a5a1f2aSjsing SSL_CTX_free(ssl_ctx);
4951a5a1f2aSjsing BIO_free(bio);
4961a5a1f2aSjsing
4971a5a1f2aSjsing return ssl;
4981a5a1f2aSjsing }
4991a5a1f2aSjsing
5001a5a1f2aSjsing static int
ssl_error(SSL * ssl,const char * name,const char * desc,int ssl_ret,short * events)5011a5a1f2aSjsing ssl_error(SSL *ssl, const char *name, const char *desc, int ssl_ret,
5021a5a1f2aSjsing short *events)
5031a5a1f2aSjsing {
5041a5a1f2aSjsing int ssl_err;
5051a5a1f2aSjsing
5061a5a1f2aSjsing ssl_err = SSL_get_error(ssl, ssl_ret);
5071a5a1f2aSjsing
5081a5a1f2aSjsing if (ssl_err == SSL_ERROR_WANT_READ) {
5091a5a1f2aSjsing *events = POLLIN;
5101a5a1f2aSjsing } else if (ssl_err == SSL_ERROR_WANT_WRITE) {
5111a5a1f2aSjsing *events = POLLOUT;
5121a5a1f2aSjsing } else if (ssl_err == SSL_ERROR_SYSCALL && errno == 0) {
5131a5a1f2aSjsing /* Yup, this is apparently a thing... */
5141a5a1f2aSjsing } else {
5151a5a1f2aSjsing fprintf(stderr, "FAIL: %s %s failed - ssl err = %d, errno = %d\n",
5161a5a1f2aSjsing name, desc, ssl_err, errno);
5171a5a1f2aSjsing ERR_print_errors_fp(stderr);
5181a5a1f2aSjsing return 0;
5191a5a1f2aSjsing }
5201a5a1f2aSjsing
5211a5a1f2aSjsing return 1;
5221a5a1f2aSjsing }
5231a5a1f2aSjsing
5241a5a1f2aSjsing static int
do_connect(SSL * ssl,const char * name,int * done,short * events)5251a5a1f2aSjsing do_connect(SSL *ssl, const char *name, int *done, short *events)
5261a5a1f2aSjsing {
5271a5a1f2aSjsing int ssl_ret;
5281a5a1f2aSjsing
5292c9830feSjsing if ((ssl_ret = SSL_connect(ssl)) != 1)
5302c9830feSjsing return ssl_error(ssl, name, "connect", ssl_ret, events);
5312c9830feSjsing
5321a5a1f2aSjsing fprintf(stderr, "INFO: %s connect done\n", name);
5331a5a1f2aSjsing *done = 1;
5342c9830feSjsing
5351a5a1f2aSjsing return 1;
5361a5a1f2aSjsing }
5371a5a1f2aSjsing
5382c9830feSjsing static int
do_connect_read(SSL * ssl,const char * name,int * done,short * events)5392c9830feSjsing do_connect_read(SSL *ssl, const char *name, int *done, short *events)
5402c9830feSjsing {
5412c9830feSjsing uint8_t buf[2048];
5422c9830feSjsing int ssl_ret;
5432c9830feSjsing int i;
5442c9830feSjsing
5452c9830feSjsing if ((ssl_ret = SSL_connect(ssl)) != 1)
5461a5a1f2aSjsing return ssl_error(ssl, name, "connect", ssl_ret, events);
5472c9830feSjsing
5482c9830feSjsing fprintf(stderr, "INFO: %s connect done\n", name);
5492c9830feSjsing *done = 1;
5502c9830feSjsing
5512c9830feSjsing for (i = 0; i < 3; i++) {
5522c9830feSjsing fprintf(stderr, "INFO: %s reading after connect\n", name);
5532c9830feSjsing if ((ssl_ret = SSL_read(ssl, buf, sizeof(buf))) != 3) {
5542c9830feSjsing fprintf(stderr, "ERROR: %s read failed\n", name);
5552c9830feSjsing return 0;
5562c9830feSjsing }
5572c9830feSjsing }
5582c9830feSjsing
5592c9830feSjsing return 1;
5602c9830feSjsing }
5612c9830feSjsing
5622c9830feSjsing static int
do_connect_shutdown(SSL * ssl,const char * name,int * done,short * events)5632c9830feSjsing do_connect_shutdown(SSL *ssl, const char *name, int *done, short *events)
5642c9830feSjsing {
5652c9830feSjsing uint8_t buf[2048];
5662c9830feSjsing int ssl_ret;
5672c9830feSjsing
5682c9830feSjsing if ((ssl_ret = SSL_connect(ssl)) != 1)
5692c9830feSjsing return ssl_error(ssl, name, "connect", ssl_ret, events);
5702c9830feSjsing
5712c9830feSjsing fprintf(stderr, "INFO: %s connect done\n", name);
5722c9830feSjsing *done = 1;
5732c9830feSjsing
5742c9830feSjsing ssl_ret = SSL_read(ssl, buf, sizeof(buf));
5752c9830feSjsing if (SSL_get_error(ssl, ssl_ret) != SSL_ERROR_ZERO_RETURN) {
5762c9830feSjsing fprintf(stderr, "FAIL: %s did not receive close-notify\n", name);
5772c9830feSjsing return 0;
5782c9830feSjsing }
5792c9830feSjsing
5802c9830feSjsing fprintf(stderr, "INFO: %s received close-notify\n", name);
5812c9830feSjsing
5822c9830feSjsing return 1;
5831a5a1f2aSjsing }
5841a5a1f2aSjsing
5851a5a1f2aSjsing static int
do_accept(SSL * ssl,const char * name,int * done,short * events)5861a5a1f2aSjsing do_accept(SSL *ssl, const char *name, int *done, short *events)
5871a5a1f2aSjsing {
5881a5a1f2aSjsing int ssl_ret;
5891a5a1f2aSjsing
5902c9830feSjsing if ((ssl_ret = SSL_accept(ssl)) != 1)
5912c9830feSjsing return ssl_error(ssl, name, "accept", ssl_ret, events);
5922c9830feSjsing
5931a5a1f2aSjsing fprintf(stderr, "INFO: %s accept done\n", name);
5941a5a1f2aSjsing *done = 1;
5952c9830feSjsing
5962c9830feSjsing return 1;
5972c9830feSjsing }
5982c9830feSjsing
5992c9830feSjsing static int
do_accept_write(SSL * ssl,const char * name,int * done,short * events)6002c9830feSjsing do_accept_write(SSL *ssl, const char *name, int *done, short *events)
6012c9830feSjsing {
6022c9830feSjsing int ssl_ret;
6032c9830feSjsing BIO *bio;
6042c9830feSjsing int i;
6052c9830feSjsing
6062c9830feSjsing if ((ssl_ret = SSL_accept(ssl)) != 1)
6072c9830feSjsing return ssl_error(ssl, name, "accept", ssl_ret, events);
6082c9830feSjsing
6092c9830feSjsing fprintf(stderr, "INFO: %s accept done\n", name);
6102c9830feSjsing
6112c9830feSjsing for (i = 0; i < 3; i++) {
6122c9830feSjsing fprintf(stderr, "INFO: %s writing after accept\n", name);
6132c9830feSjsing if ((ssl_ret = SSL_write(ssl, "abc", 3)) != 3) {
6142c9830feSjsing fprintf(stderr, "ERROR: %s write failed\n", name);
6152c9830feSjsing return 0;
6162c9830feSjsing }
6172c9830feSjsing }
6182c9830feSjsing
6192c9830feSjsing if ((bio = SSL_get_wbio(ssl)) == NULL)
6202c9830feSjsing errx(1, "SSL has NULL bio");
6212c9830feSjsing
6222c9830feSjsing /* Flush any delayed packets. */
6232c9830feSjsing BIO_packet_monkey_delay_flush(bio);
6242c9830feSjsing
6252c9830feSjsing *done = 1;
6261a5a1f2aSjsing return 1;
6271a5a1f2aSjsing }
6281a5a1f2aSjsing
6292c9830feSjsing static int
do_accept_shutdown(SSL * ssl,const char * name,int * done,short * events)6302c9830feSjsing do_accept_shutdown(SSL *ssl, const char *name, int *done, short *events)
6312c9830feSjsing {
6322c9830feSjsing int ssl_ret;
6332c9830feSjsing BIO *bio;
6342c9830feSjsing
6352c9830feSjsing if ((ssl_ret = SSL_accept(ssl)) != 1)
6361a5a1f2aSjsing return ssl_error(ssl, name, "accept", ssl_ret, events);
6372c9830feSjsing
6382c9830feSjsing fprintf(stderr, "INFO: %s accept done\n", name);
6392c9830feSjsing
6402c9830feSjsing SSL_shutdown(ssl);
6412c9830feSjsing
6422c9830feSjsing if ((bio = SSL_get_wbio(ssl)) == NULL)
6432c9830feSjsing errx(1, "SSL has NULL bio");
6442c9830feSjsing
6452c9830feSjsing /* Flush any delayed packets. */
6462c9830feSjsing BIO_packet_monkey_delay_flush(bio);
6472c9830feSjsing
6482c9830feSjsing *done = 1;
6492c9830feSjsing return 1;
6501a5a1f2aSjsing }
6511a5a1f2aSjsing
6521a5a1f2aSjsing static int
do_read(SSL * ssl,const char * name,int * done,short * events)653fbc84eb9Sjsing do_read(SSL *ssl, const char *name, int *done, short *events)
654fbc84eb9Sjsing {
655fbc84eb9Sjsing uint8_t buf[512];
656fbc84eb9Sjsing int ssl_ret;
657fbc84eb9Sjsing
658fbc84eb9Sjsing if ((ssl_ret = SSL_read(ssl, buf, sizeof(buf))) > 0) {
659fbc84eb9Sjsing fprintf(stderr, "INFO: %s read done\n", name);
660311d0beaSjsing if (debug > 1)
661fbc84eb9Sjsing hexdump(buf, ssl_ret);
662fbc84eb9Sjsing *done = 1;
663fbc84eb9Sjsing return 1;
664fbc84eb9Sjsing }
665fbc84eb9Sjsing
666fbc84eb9Sjsing return ssl_error(ssl, name, "read", ssl_ret, events);
667fbc84eb9Sjsing }
668fbc84eb9Sjsing
669fbc84eb9Sjsing static int
do_write(SSL * ssl,const char * name,int * done,short * events)670fbc84eb9Sjsing do_write(SSL *ssl, const char *name, int *done, short *events)
671fbc84eb9Sjsing {
672fbc84eb9Sjsing const uint8_t buf[] = "Hello, World!\n";
673fbc84eb9Sjsing int ssl_ret;
674fbc84eb9Sjsing
675fbc84eb9Sjsing if ((ssl_ret = SSL_write(ssl, buf, sizeof(buf))) > 0) {
676fbc84eb9Sjsing fprintf(stderr, "INFO: %s write done\n", name);
677fbc84eb9Sjsing *done = 1;
678fbc84eb9Sjsing return 1;
679fbc84eb9Sjsing }
680fbc84eb9Sjsing
681fbc84eb9Sjsing return ssl_error(ssl, name, "write", ssl_ret, events);
682fbc84eb9Sjsing }
683fbc84eb9Sjsing
684fbc84eb9Sjsing static int
do_shutdown(SSL * ssl,const char * name,int * done,short * events)6851a5a1f2aSjsing do_shutdown(SSL *ssl, const char *name, int *done, short *events)
6861a5a1f2aSjsing {
6871a5a1f2aSjsing int ssl_ret;
6881a5a1f2aSjsing
6891a5a1f2aSjsing ssl_ret = SSL_shutdown(ssl);
6901a5a1f2aSjsing if (ssl_ret == 1) {
6911a5a1f2aSjsing fprintf(stderr, "INFO: %s shutdown done\n", name);
6921a5a1f2aSjsing *done = 1;
6931a5a1f2aSjsing return 1;
6941a5a1f2aSjsing }
6951a5a1f2aSjsing return ssl_error(ssl, name, "shutdown", ssl_ret, events);
6961a5a1f2aSjsing }
6971a5a1f2aSjsing
6982c9830feSjsing typedef int (ssl_func)(SSL *ssl, const char *name, int *done, short *events);
6991a5a1f2aSjsing
7001a5a1f2aSjsing static int
do_client_server_loop(SSL * client,ssl_func * client_func,SSL * server,ssl_func * server_func,struct pollfd pfd[2])7012c9830feSjsing do_client_server_loop(SSL *client, ssl_func *client_func, SSL *server,
7022c9830feSjsing ssl_func *server_func, struct pollfd pfd[2])
7031a5a1f2aSjsing {
7041a5a1f2aSjsing int client_done = 0, server_done = 0;
7051a5a1f2aSjsing int i = 0;
7061a5a1f2aSjsing
70781b11609Sjsing pfd[0].revents = POLLIN;
70881b11609Sjsing pfd[1].revents = POLLIN;
7091a5a1f2aSjsing
71081b11609Sjsing do {
7111a5a1f2aSjsing if (!client_done) {
71281b11609Sjsing if (debug)
71381b11609Sjsing fprintf(stderr, "DEBUG: client loop\n");
7141a5a1f2aSjsing if (DTLSv1_handle_timeout(client) > 0)
7151a5a1f2aSjsing fprintf(stderr, "INFO: client timeout\n");
7161a5a1f2aSjsing if (!client_func(client, "client", &client_done,
7171a5a1f2aSjsing &pfd[0].events))
7181a5a1f2aSjsing return 0;
71981b11609Sjsing if (client_done)
72081b11609Sjsing pfd[0].events = 0;
7211a5a1f2aSjsing }
7221a5a1f2aSjsing if (!server_done) {
72381b11609Sjsing if (debug)
72481b11609Sjsing fprintf(stderr, "DEBUG: server loop\n");
7251a5a1f2aSjsing if (DTLSv1_handle_timeout(server) > 0)
7261a5a1f2aSjsing fprintf(stderr, "INFO: server timeout\n");
7271a5a1f2aSjsing if (!server_func(server, "server", &server_done,
7281a5a1f2aSjsing &pfd[1].events))
7291a5a1f2aSjsing return 0;
73081b11609Sjsing if (server_done)
73181b11609Sjsing pfd[1].events = 0;
7321a5a1f2aSjsing }
73381b11609Sjsing if (poll(pfd, 2, poll_timeout(client, server)) == -1)
73481b11609Sjsing err(1, "poll");
73581b11609Sjsing
73681b11609Sjsing } while (i++ < 100 && (!client_done || !server_done));
7371a5a1f2aSjsing
7381a5a1f2aSjsing if (!client_done || !server_done)
7391a5a1f2aSjsing fprintf(stderr, "FAIL: gave up\n");
7401a5a1f2aSjsing
7411a5a1f2aSjsing return client_done && server_done;
7421a5a1f2aSjsing }
7431a5a1f2aSjsing
744b48caa61Sjsing #define MAX_PACKET_DELAYS 32
7457d0fb893Sjsing #define MAX_PACKET_DROPS 32
7467d0fb893Sjsing
747b48caa61Sjsing struct dtls_delay {
748b48caa61Sjsing uint8_t packet;
749b48caa61Sjsing uint8_t count;
750b48caa61Sjsing };
751b48caa61Sjsing
7521a5a1f2aSjsing struct dtls_test {
7531a5a1f2aSjsing const unsigned char *desc;
7547d0fb893Sjsing long mtu;
7557d0fb893Sjsing long ssl_options;
7567d0fb893Sjsing int client_bbio_off;
7577d0fb893Sjsing int server_bbio_off;
75839e756f1Sjsing uint16_t initial_epoch;
7592c9830feSjsing int write_after_accept;
7602c9830feSjsing int shutdown_after_accept;
761b48caa61Sjsing struct dtls_delay client_delays[MAX_PACKET_DELAYS];
762b48caa61Sjsing struct dtls_delay server_delays[MAX_PACKET_DELAYS];
7637d0fb893Sjsing uint8_t client_drops[MAX_PACKET_DROPS];
7647d0fb893Sjsing uint8_t server_drops[MAX_PACKET_DROPS];
7651a5a1f2aSjsing };
7661a5a1f2aSjsing
7677d0fb893Sjsing static const struct dtls_test dtls_tests[] = {
7681a5a1f2aSjsing {
7691a5a1f2aSjsing .desc = "DTLS without cookies",
7701a5a1f2aSjsing .ssl_options = 0,
7711a5a1f2aSjsing },
7721a5a1f2aSjsing {
77339e756f1Sjsing .desc = "DTLS without cookies (initial epoch 0xfffe)",
77439e756f1Sjsing .ssl_options = 0,
77539e756f1Sjsing .initial_epoch = 0xfffe,
77639e756f1Sjsing },
77739e756f1Sjsing {
77839e756f1Sjsing .desc = "DTLS without cookies (initial epoch 0xffff)",
77939e756f1Sjsing .ssl_options = 0,
78039e756f1Sjsing .initial_epoch = 0xffff,
78139e756f1Sjsing },
78239e756f1Sjsing {
7831a5a1f2aSjsing .desc = "DTLS with cookies",
7841a5a1f2aSjsing .ssl_options = SSL_OP_COOKIE_EXCHANGE,
7851a5a1f2aSjsing },
7861a5a1f2aSjsing {
7871a5a1f2aSjsing .desc = "DTLS with low MTU",
7881a5a1f2aSjsing .mtu = 256,
7897d0fb893Sjsing .ssl_options = 0,
7901a5a1f2aSjsing },
7911a5a1f2aSjsing {
7921a5a1f2aSjsing .desc = "DTLS with low MTU and cookies",
7931a5a1f2aSjsing .mtu = 256,
7941a5a1f2aSjsing .ssl_options = SSL_OP_COOKIE_EXCHANGE,
7951a5a1f2aSjsing },
7967d0fb893Sjsing {
7977d0fb893Sjsing .desc = "DTLS with dropped server response",
7987d0fb893Sjsing .ssl_options = 0,
7997d0fb893Sjsing .server_drops = { 1 },
8007d0fb893Sjsing },
8017d0fb893Sjsing {
8027d0fb893Sjsing .desc = "DTLS with two dropped server responses",
8037d0fb893Sjsing .ssl_options = 0,
8047d0fb893Sjsing .server_drops = { 1, 2 },
8057d0fb893Sjsing },
8067d0fb893Sjsing {
8077d0fb893Sjsing .desc = "DTLS with dropped ServerHello",
8088420b909Sjsing .ssl_options = SSL_OP_NO_TICKET,
8097d0fb893Sjsing .server_bbio_off = 1,
8107d0fb893Sjsing .server_drops = { 1 },
8117d0fb893Sjsing },
8127d0fb893Sjsing {
8137d0fb893Sjsing .desc = "DTLS with dropped server Certificate",
8148420b909Sjsing .ssl_options = SSL_OP_NO_TICKET,
8157d0fb893Sjsing .server_bbio_off = 1,
8167d0fb893Sjsing .server_drops = { 2 },
8177d0fb893Sjsing },
8187d0fb893Sjsing {
8197d0fb893Sjsing .desc = "DTLS with dropped ServerKeyExchange",
8208420b909Sjsing .ssl_options = SSL_OP_NO_TICKET,
8217d0fb893Sjsing .server_bbio_off = 1,
8227d0fb893Sjsing .server_drops = { 3 },
8237d0fb893Sjsing },
8247d0fb893Sjsing {
8257d0fb893Sjsing .desc = "DTLS with dropped ServerHelloDone",
8268420b909Sjsing .ssl_options = SSL_OP_NO_TICKET,
8277d0fb893Sjsing .server_bbio_off = 1,
8287d0fb893Sjsing .server_drops = { 4 },
8297d0fb893Sjsing },
8308420b909Sjsing #if 0
8318420b909Sjsing /*
8328420b909Sjsing * These two result in the server accept completing and the
8338420b909Sjsing * client looping on a timeout. Presumably the server should not
83466499ff6Sjsing * complete until the client Finished is received... this due to
83566499ff6Sjsing * a flaw in the DTLSv1.0 specification, which is addressed in
83666499ff6Sjsing * DTLSv1.2 (see references to "last flight" in RFC 6347 section
83766499ff6Sjsing * 4.2.4). Our DTLS server code still needs to support this.
8388420b909Sjsing */
8397d0fb893Sjsing {
8407d0fb893Sjsing .desc = "DTLS with dropped server CCS",
8417d0fb893Sjsing .ssl_options = 0,
8427d0fb893Sjsing .server_bbio_off = 1,
8437d0fb893Sjsing .server_drops = { 5 },
8447d0fb893Sjsing },
8457d0fb893Sjsing {
8467d0fb893Sjsing .desc = "DTLS with dropped server Finished",
8477d0fb893Sjsing .ssl_options = 0,
8487d0fb893Sjsing .server_bbio_off = 1,
8497d0fb893Sjsing .server_drops = { 6 },
8507d0fb893Sjsing },
8517d0fb893Sjsing #endif
8527d0fb893Sjsing {
8537d0fb893Sjsing .desc = "DTLS with dropped ClientKeyExchange",
8547d0fb893Sjsing .ssl_options = 0,
8557d0fb893Sjsing .client_bbio_off = 1,
8567d0fb893Sjsing .client_drops = { 2 },
8577d0fb893Sjsing },
8587d0fb893Sjsing {
8598420b909Sjsing .desc = "DTLS with dropped client CCS",
8607d0fb893Sjsing .ssl_options = 0,
8617d0fb893Sjsing .client_bbio_off = 1,
8627d0fb893Sjsing .client_drops = { 3 },
8637d0fb893Sjsing },
8647d0fb893Sjsing {
8657d0fb893Sjsing .desc = "DTLS with dropped client Finished",
8667d0fb893Sjsing .ssl_options = 0,
8677d0fb893Sjsing .client_bbio_off = 1,
8687d0fb893Sjsing .client_drops = { 4 },
8697d0fb893Sjsing },
870b48caa61Sjsing {
871b48caa61Sjsing /* Send CCS after client Finished. */
872b48caa61Sjsing .desc = "DTLS with delayed client CCS",
873b48caa61Sjsing .ssl_options = 0,
874b48caa61Sjsing .client_bbio_off = 1,
875b48caa61Sjsing .client_delays = { { 3, 2 } },
876b48caa61Sjsing },
8772c9830feSjsing {
8782c9830feSjsing /*
8792c9830feSjsing * Send CCS after server Finished - note app data will be
8802c9830feSjsing * dropped if we send the CCS after app data.
8812c9830feSjsing */
8822c9830feSjsing .desc = "DTLS with delayed server CCS",
8832c9830feSjsing .ssl_options = SSL_OP_NO_TICKET,
8842c9830feSjsing .server_bbio_off = 1,
8852c9830feSjsing .server_delays = { { 5, 2 } },
8862c9830feSjsing .write_after_accept = 1,
8872c9830feSjsing },
8882c9830feSjsing {
88939e756f1Sjsing .desc = "DTLS with delayed server CCS (initial epoch 0xfffe)",
89039e756f1Sjsing .ssl_options = SSL_OP_NO_TICKET,
89139e756f1Sjsing .server_bbio_off = 1,
89239e756f1Sjsing .initial_epoch = 0xfffe,
89339e756f1Sjsing .server_delays = { { 5, 2 } },
89439e756f1Sjsing .write_after_accept = 1,
89539e756f1Sjsing },
89639e756f1Sjsing {
89739e756f1Sjsing .desc = "DTLS with delayed server CCS (initial epoch 0xffff)",
89839e756f1Sjsing .ssl_options = SSL_OP_NO_TICKET,
89939e756f1Sjsing .server_bbio_off = 1,
90039e756f1Sjsing .initial_epoch = 0xffff,
90139e756f1Sjsing .server_delays = { { 5, 2 } },
90239e756f1Sjsing .write_after_accept = 1,
90339e756f1Sjsing },
90439e756f1Sjsing {
9052c9830feSjsing /* Send Finished after app data - this is currently buffered. */
9062c9830feSjsing .desc = "DTLS with delayed server Finished",
9072c9830feSjsing .ssl_options = SSL_OP_NO_TICKET,
9082c9830feSjsing .server_bbio_off = 1,
9092c9830feSjsing .server_delays = { { 6, 3 } },
9102c9830feSjsing .write_after_accept = 1,
9112c9830feSjsing },
9122c9830feSjsing {
9132c9830feSjsing /* Send CCS after server finished and close-notify. */
9142c9830feSjsing .desc = "DTLS with delayed server CCS (close-notify)",
9152c9830feSjsing .ssl_options = SSL_OP_NO_TICKET,
9162c9830feSjsing .server_bbio_off = 1,
9172c9830feSjsing .server_delays = { { 5, 3 } },
9182c9830feSjsing .shutdown_after_accept = 1,
9192c9830feSjsing },
9201a5a1f2aSjsing };
9211a5a1f2aSjsing
9221a5a1f2aSjsing #define N_DTLS_TESTS (sizeof(dtls_tests) / sizeof(*dtls_tests))
9231a5a1f2aSjsing
9247d0fb893Sjsing static void
dtlstest_packet_monkey(SSL * ssl,const struct dtls_delay delays[],const uint8_t drops[])925b48caa61Sjsing dtlstest_packet_monkey(SSL *ssl, const struct dtls_delay delays[],
926b48caa61Sjsing const uint8_t drops[])
9277d0fb893Sjsing {
9287d0fb893Sjsing BIO *bio_monkey;
9297d0fb893Sjsing BIO *bio;
9307d0fb893Sjsing int i;
9317d0fb893Sjsing
9327d0fb893Sjsing if ((bio_monkey = BIO_new_packet_monkey()) == NULL)
9337d0fb893Sjsing errx(1, "packet monkey");
9347d0fb893Sjsing
935b48caa61Sjsing for (i = 0; i < MAX_PACKET_DELAYS; i++) {
936b48caa61Sjsing if (delays[i].packet == 0)
937b48caa61Sjsing break;
938b48caa61Sjsing if (!BIO_packet_monkey_delay(bio_monkey, delays[i].packet,
939b48caa61Sjsing delays[i].count))
940b48caa61Sjsing errx(1, "delay failure");
941b48caa61Sjsing }
942b48caa61Sjsing
9437d0fb893Sjsing for (i = 0; i < MAX_PACKET_DROPS; i++) {
9447d0fb893Sjsing if (drops[i] == 0)
9457d0fb893Sjsing break;
9467d0fb893Sjsing if (!BIO_packet_monkey_drop(bio_monkey, drops[i]))
9477d0fb893Sjsing errx(1, "drop failure");
9487d0fb893Sjsing }
9497d0fb893Sjsing
9507d0fb893Sjsing if ((bio = SSL_get_wbio(ssl)) == NULL)
9517d0fb893Sjsing errx(1, "SSL has NULL bio");
9527d0fb893Sjsing
9537d0fb893Sjsing BIO_up_ref(bio);
9547d0fb893Sjsing bio = BIO_push(bio_monkey, bio);
9557d0fb893Sjsing
9567d0fb893Sjsing SSL_set_bio(ssl, bio, bio);
9577d0fb893Sjsing }
9587d0fb893Sjsing
9591a5a1f2aSjsing static int
dtlstest(const struct dtls_test * dt)9607d0fb893Sjsing dtlstest(const struct dtls_test *dt)
9611a5a1f2aSjsing {
9621a5a1f2aSjsing SSL *client = NULL, *server = NULL;
9632c9830feSjsing ssl_func *connect_func, *accept_func;
9641a5a1f2aSjsing struct sockaddr_in server_sin;
9651a5a1f2aSjsing struct pollfd pfd[2];
9661a5a1f2aSjsing int client_sock = -1;
9671a5a1f2aSjsing int server_sock = -1;
9681a5a1f2aSjsing int failed = 1;
9691a5a1f2aSjsing
9701a5a1f2aSjsing fprintf(stderr, "\n== Testing %s... ==\n", dt->desc);
9711a5a1f2aSjsing
9721a5a1f2aSjsing if (!datagram_pair(&client_sock, &server_sock, &server_sin))
9731a5a1f2aSjsing goto failure;
9741a5a1f2aSjsing
9751a5a1f2aSjsing if ((client = dtls_client(client_sock, &server_sin, dt->mtu)) == NULL)
9761a5a1f2aSjsing goto failure;
97739e756f1Sjsing
9781a5a1f2aSjsing if ((server = dtls_server(server_sock, dt->ssl_options, dt->mtu)) == NULL)
9791a5a1f2aSjsing goto failure;
9801a5a1f2aSjsing
9811ce7ecd4Sjsing tls12_record_layer_set_initial_epoch(client->rl, dt->initial_epoch);
9821ce7ecd4Sjsing tls12_record_layer_set_initial_epoch(server->rl, dt->initial_epoch);
98339e756f1Sjsing
9847d0fb893Sjsing if (dt->client_bbio_off)
9857d0fb893Sjsing SSL_set_info_callback(client, dtls_info_callback);
9867d0fb893Sjsing if (dt->server_bbio_off)
9877d0fb893Sjsing SSL_set_info_callback(server, dtls_info_callback);
9887d0fb893Sjsing
989b48caa61Sjsing dtlstest_packet_monkey(client, dt->client_delays, dt->client_drops);
990b48caa61Sjsing dtlstest_packet_monkey(server, dt->server_delays, dt->server_drops);
9917d0fb893Sjsing
9921a5a1f2aSjsing pfd[0].fd = client_sock;
9931a5a1f2aSjsing pfd[0].events = POLLOUT;
9941a5a1f2aSjsing pfd[1].fd = server_sock;
99581b11609Sjsing pfd[1].events = POLLIN;
9961a5a1f2aSjsing
9972c9830feSjsing accept_func = do_accept;
9982c9830feSjsing connect_func = do_connect;
9992c9830feSjsing
10002c9830feSjsing if (dt->write_after_accept) {
10012c9830feSjsing accept_func = do_accept_write;
10022c9830feSjsing connect_func = do_connect_read;
10032c9830feSjsing } else if (dt->shutdown_after_accept) {
10042c9830feSjsing accept_func = do_accept_shutdown;
10052c9830feSjsing connect_func = do_connect_shutdown;
10062c9830feSjsing }
10072c9830feSjsing
10082c9830feSjsing if (!do_client_server_loop(client, connect_func, server, accept_func, pfd)) {
10091a5a1f2aSjsing fprintf(stderr, "FAIL: client and server handshake failed\n");
10101a5a1f2aSjsing goto failure;
10111a5a1f2aSjsing }
10121a5a1f2aSjsing
10132c9830feSjsing if (dt->write_after_accept || dt->shutdown_after_accept)
10142c9830feSjsing goto done;
10152c9830feSjsing
1016fbc84eb9Sjsing pfd[0].events = POLLIN;
1017fbc84eb9Sjsing pfd[1].events = POLLOUT;
1018fbc84eb9Sjsing
1019fbc84eb9Sjsing if (!do_client_server_loop(client, do_read, server, do_write, pfd)) {
1020fbc84eb9Sjsing fprintf(stderr, "FAIL: client read and server write I/O failed\n");
1021fbc84eb9Sjsing goto failure;
1022fbc84eb9Sjsing }
1023fbc84eb9Sjsing
1024fbc84eb9Sjsing pfd[0].events = POLLOUT;
1025fbc84eb9Sjsing pfd[1].events = POLLIN;
1026fbc84eb9Sjsing
1027fbc84eb9Sjsing if (!do_client_server_loop(client, do_write, server, do_read, pfd)) {
1028fbc84eb9Sjsing fprintf(stderr, "FAIL: client write and server read I/O failed\n");
1029fbc84eb9Sjsing goto failure;
1030fbc84eb9Sjsing }
10311a5a1f2aSjsing
103281b11609Sjsing pfd[0].events = POLLOUT;
103381b11609Sjsing pfd[1].events = POLLOUT;
103481b11609Sjsing
10351a5a1f2aSjsing if (!do_client_server_loop(client, do_shutdown, server, do_shutdown, pfd)) {
10361a5a1f2aSjsing fprintf(stderr, "FAIL: client and server shutdown failed\n");
10371a5a1f2aSjsing goto failure;
10381a5a1f2aSjsing }
10391a5a1f2aSjsing
10402c9830feSjsing done:
10411a5a1f2aSjsing fprintf(stderr, "INFO: Done!\n");
10421a5a1f2aSjsing
10431a5a1f2aSjsing failed = 0;
10441a5a1f2aSjsing
10451a5a1f2aSjsing failure:
10461a5a1f2aSjsing if (client_sock != -1)
10471a5a1f2aSjsing close(client_sock);
10481a5a1f2aSjsing if (server_sock != -1)
10491a5a1f2aSjsing close(server_sock);
10501a5a1f2aSjsing
10511a5a1f2aSjsing SSL_free(client);
10521a5a1f2aSjsing SSL_free(server);
10531a5a1f2aSjsing
10541a5a1f2aSjsing return failed;
10551a5a1f2aSjsing }
10561a5a1f2aSjsing
10571a5a1f2aSjsing int
main(int argc,char ** argv)10581a5a1f2aSjsing main(int argc, char **argv)
10591a5a1f2aSjsing {
10601a5a1f2aSjsing int failed = 0;
10611a5a1f2aSjsing size_t i;
10621a5a1f2aSjsing
10631a5a1f2aSjsing if (argc != 4) {
10641a5a1f2aSjsing fprintf(stderr, "usage: %s keyfile certfile cafile\n",
10651a5a1f2aSjsing argv[0]);
10661a5a1f2aSjsing exit(1);
10671a5a1f2aSjsing }
10681a5a1f2aSjsing
10691a5a1f2aSjsing server_key_file = argv[1];
10701a5a1f2aSjsing server_cert_file = argv[2];
10711a5a1f2aSjsing server_ca_file = argv[3];
10721a5a1f2aSjsing
10731a5a1f2aSjsing for (i = 0; i < N_DTLS_TESTS; i++)
10741a5a1f2aSjsing failed |= dtlstest(&dtls_tests[i]);
10751a5a1f2aSjsing
10761a5a1f2aSjsing return failed;
10771a5a1f2aSjsing }
1078