xref: /openbsd-src/regress/lib/libssl/dtls/dtlstest.c (revision c9675a23de50ec5aa20be3956f170f2eccffb293)
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