summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/regress/lib/libssl/dtls/dtlstest.c304
1 files changed, 299 insertions, 5 deletions
diff --git a/src/regress/lib/libssl/dtls/dtlstest.c b/src/regress/lib/libssl/dtls/dtlstest.c
index 166302db48..c25800be19 100644
--- a/src/regress/lib/libssl/dtls/dtlstest.c
+++ b/src/regress/lib/libssl/dtls/dtlstest.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: dtlstest.c,v 1.2 2020/10/15 17:51:58 jsing Exp $ */ 1/* $OpenBSD: dtlstest.c,v 1.3 2020/10/15 18:05:06 jsing Exp $ */
2/* 2/*
3 * Copyright (c) 2020 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2020 Joel Sing <jsing@openbsd.org>
4 * 4 *
@@ -35,6 +35,177 @@ char dtls_cookie[32];
35 35
36int debug = 0; 36int debug = 0;
37 37
38static void
39hexdump(const unsigned char *buf, size_t len)
40{
41 size_t i;
42
43 for (i = 1; i <= len; i++)
44 fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n");
45
46 if (len % 8)
47 fprintf(stderr, "\n");
48}
49
50#define BIO_C_DROP_PACKET 1000
51#define BIO_C_DROP_RANDOM 1001
52
53struct bio_packet_monkey_ctx {
54 unsigned int drop_rand;
55 unsigned int drop_mask;
56};
57
58static int
59bio_packet_monkey_new(BIO *bio)
60{
61 struct bio_packet_monkey_ctx *ctx;
62
63 if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
64 return 0;
65
66 bio->flags = 0;
67 bio->init = 1;
68 bio->num = 0;
69 bio->ptr = ctx;
70
71 return 1;
72}
73
74static int
75bio_packet_monkey_free(BIO *bio)
76{
77 struct bio_packet_monkey_ctx *ctx;
78
79 if (bio == NULL)
80 return 1;
81
82 ctx = bio->ptr;
83 free(ctx);
84
85 return 1;
86}
87
88static long
89bio_packet_monkey_ctrl(BIO *bio, int cmd, long num, void *ptr)
90{
91 struct bio_packet_monkey_ctx *ctx;
92
93 ctx = bio->ptr;
94
95 switch (cmd) {
96 case BIO_C_DROP_PACKET:
97 if (num < 1 || num > 31)
98 return 0;
99 ctx->drop_mask |= 1 << ((unsigned int)num - 1);
100 return 1;
101
102 case BIO_C_DROP_RANDOM:
103 if (num < 0 || num > UINT_MAX)
104 return 0;
105 ctx->drop_rand = (unsigned int)num;
106 return 1;
107 }
108
109 if (bio->next_bio == NULL)
110 return 0;
111
112 return BIO_ctrl(bio->next_bio, cmd, num, ptr);
113}
114
115static int
116bio_packet_monkey_read(BIO *bio, char *out, int out_len)
117{
118 struct bio_packet_monkey_ctx *ctx = bio->ptr;
119 int ret;
120
121 if (ctx == NULL || bio->next_bio == NULL)
122 return 0;
123
124 ret = BIO_read(bio->next_bio, out, out_len);
125
126 BIO_clear_retry_flags(bio);
127 if (ret <= 0 && BIO_should_retry(bio->next_bio))
128 BIO_set_retry_read(bio);
129
130 return ret;
131}
132
133static int
134bio_packet_monkey_write(BIO *bio, const char *in, int in_len)
135{
136 struct bio_packet_monkey_ctx *ctx = bio->ptr;
137 int drop = 0;
138 int ret;
139
140 if (ctx == NULL || bio->next_bio == NULL)
141 return 0;
142
143 if (ctx->drop_rand > 0) {
144 drop = arc4random_uniform(ctx->drop_rand) == 0;
145 } else if (ctx->drop_mask > 0) {
146 drop = ctx->drop_mask & 1;
147 ctx->drop_mask >>= 1;
148 }
149 if (debug) {
150 fprintf(stderr, "DEBUG: %s packet...\n",
151 drop ? "dropping" : "writing");
152 hexdump(in, in_len);
153 }
154 if (drop)
155 return in_len;
156
157 ret = BIO_write(bio->next_bio, in, in_len);
158
159 BIO_clear_retry_flags(bio);
160 if (ret <= 0 && BIO_should_retry(bio->next_bio))
161 BIO_set_retry_write(bio);
162
163 return ret;
164}
165
166static int
167bio_packet_monkey_puts(BIO *bio, const char *str)
168{
169 return bio_packet_monkey_write(bio, str, strlen(str));
170}
171
172static const BIO_METHOD bio_packet_monkey = {
173 .type = BIO_TYPE_BUFFER,
174 .name = "packet monkey",
175 .bread = bio_packet_monkey_read,
176 .bwrite = bio_packet_monkey_write,
177 .bputs = bio_packet_monkey_puts,
178 .ctrl = bio_packet_monkey_ctrl,
179 .create = bio_packet_monkey_new,
180 .destroy = bio_packet_monkey_free
181};
182
183static const BIO_METHOD *
184BIO_f_packet_monkey(void)
185{
186 return &bio_packet_monkey;
187}
188
189static BIO *
190BIO_new_packet_monkey(void)
191{
192 return BIO_new(BIO_f_packet_monkey());
193}
194
195static int
196BIO_packet_monkey_drop(BIO *bio, int num)
197{
198 return BIO_ctrl(bio, BIO_C_DROP_PACKET, num, NULL);
199}
200
201#if 0
202static int
203BIO_packet_monkey_drop_random(BIO *bio, int num)
204{
205 return BIO_ctrl(bio, BIO_C_DROP_RANDOM, num, NULL);
206}
207#endif
208
38static int 209static int
39datagram_pair(int *client_sock, int *server_sock, 210datagram_pair(int *client_sock, int *server_sock,
40 struct sockaddr_in *server_sin) 211 struct sockaddr_in *server_sin)
@@ -109,6 +280,17 @@ dtls_cookie_verify(SSL *ssl, const unsigned char *cookie,
109 memcmp(cookie, dtls_cookie, sizeof(dtls_cookie)) == 0; 280 memcmp(cookie, dtls_cookie, sizeof(dtls_cookie)) == 0;
110} 281}
111 282
283static void
284dtls_info_callback(const SSL *ssl, int type, int val)
285{
286 /*
287 * Squeal's ahead... remove the bbio from the info callback, so we can
288 * drop specific messages. Ideally this would be an option for the SSL.
289 */
290 if (ssl->wbio == ssl->bbio)
291 ((SSL *)ssl)->wbio = BIO_pop(ssl->wbio);
292}
293
112static SSL * 294static SSL *
113dtls_client(int sock, struct sockaddr_in *server_sin, long mtu) 295dtls_client(int sock, struct sockaddr_in *server_sin, long mtu)
114{ 296{
@@ -305,13 +487,19 @@ do_client_server_loop(SSL *client, ssl_func client_func, SSL *server,
305 return client_done && server_done; 487 return client_done && server_done;
306} 488}
307 489
490#define MAX_PACKET_DROPS 32
491
308struct dtls_test { 492struct dtls_test {
309 const unsigned char *desc; 493 const unsigned char *desc;
310 const long mtu; 494 long mtu;
311 const long ssl_options; 495 long ssl_options;
496 int client_bbio_off;
497 int server_bbio_off;
498 uint8_t client_drops[MAX_PACKET_DROPS];
499 uint8_t server_drops[MAX_PACKET_DROPS];
312}; 500};
313 501
314static struct dtls_test dtls_tests[] = { 502static const struct dtls_test dtls_tests[] = {
315 { 503 {
316 .desc = "DTLS without cookies", 504 .desc = "DTLS without cookies",
317 .ssl_options = 0, 505 .ssl_options = 0,
@@ -323,18 +511,116 @@ static struct dtls_test dtls_tests[] = {
323 { 511 {
324 .desc = "DTLS with low MTU", 512 .desc = "DTLS with low MTU",
325 .mtu = 256, 513 .mtu = 256,
514 .ssl_options = 0,
326 }, 515 },
327 { 516 {
328 .desc = "DTLS with low MTU and cookies", 517 .desc = "DTLS with low MTU and cookies",
329 .mtu = 256, 518 .mtu = 256,
330 .ssl_options = SSL_OP_COOKIE_EXCHANGE, 519 .ssl_options = SSL_OP_COOKIE_EXCHANGE,
331 }, 520 },
521 {
522 .desc = "DTLS with dropped server response",
523 .ssl_options = 0,
524 .server_drops = { 1 },
525 },
526 {
527 .desc = "DTLS with two dropped server responses",
528 .ssl_options = 0,
529 .server_drops = { 1, 2 },
530 },
531 {
532 .desc = "DTLS with dropped ServerHello",
533 .ssl_options = 0,
534 .server_bbio_off = 1,
535 .server_drops = { 1 },
536 },
537 {
538 .desc = "DTLS with dropped server Certificate",
539 .ssl_options = 0,
540 .server_bbio_off = 1,
541 .server_drops = { 2 },
542 },
543 {
544 .desc = "DTLS with dropped ServerKeyExchange",
545 .ssl_options = 0,
546 .server_bbio_off = 1,
547 .server_drops = { 3 },
548 },
549#if 0
550 /*
551 * These three currently result in the server accept completing and the
552 * client looping on a timeout. Presumably the server should not
553 * complete until the client Finished is received...
554 */
555 {
556 .desc = "DTLS with dropped ServerHelloDone",
557 .ssl_options = 0,
558 .server_bbio_off = 1,
559 .server_drops = { 4 },
560 },
561 {
562 .desc = "DTLS with dropped server CCS",
563 .ssl_options = 0,
564 .server_bbio_off = 1,
565 .server_drops = { 5 },
566 },
567 {
568 .desc = "DTLS with dropped server Finished",
569 .ssl_options = 0,
570 .server_bbio_off = 1,
571 .server_drops = { 6 },
572 },
573#endif
574 {
575 .desc = "DTLS with dropped ClientKeyExchange",
576 .ssl_options = 0,
577 .client_bbio_off = 1,
578 .client_drops = { 2 },
579 },
580 {
581 .desc = "DTLS with dropped Client CCS",
582 .ssl_options = 0,
583 .client_bbio_off = 1,
584 .client_drops = { 3 },
585 },
586 {
587 .desc = "DTLS with dropped client Finished",
588 .ssl_options = 0,
589 .client_bbio_off = 1,
590 .client_drops = { 4 },
591 },
332}; 592};
333 593
334#define N_DTLS_TESTS (sizeof(dtls_tests) / sizeof(*dtls_tests)) 594#define N_DTLS_TESTS (sizeof(dtls_tests) / sizeof(*dtls_tests))
335 595
596static void
597dtlstest_packet_monkey(SSL *ssl, const uint8_t drops[])
598{
599 BIO *bio_monkey;
600 BIO *bio;
601 int i;
602
603 if ((bio_monkey = BIO_new_packet_monkey()) == NULL)
604 errx(1, "packet monkey");
605
606 for (i = 0; i < MAX_PACKET_DROPS; i++) {
607 if (drops[i] == 0)
608 break;
609 if (!BIO_packet_monkey_drop(bio_monkey, drops[i]))
610 errx(1, "drop failure");
611 }
612
613 if ((bio = SSL_get_wbio(ssl)) == NULL)
614 errx(1, "SSL has NULL bio");
615
616 BIO_up_ref(bio);
617 bio = BIO_push(bio_monkey, bio);
618
619 SSL_set_bio(ssl, bio, bio);
620}
621
336static int 622static int
337dtlstest(struct dtls_test *dt) 623dtlstest(const struct dtls_test *dt)
338{ 624{
339 SSL *client = NULL, *server = NULL; 625 SSL *client = NULL, *server = NULL;
340 struct sockaddr_in server_sin; 626 struct sockaddr_in server_sin;
@@ -353,6 +639,14 @@ dtlstest(struct dtls_test *dt)
353 if ((server = dtls_server(server_sock, dt->ssl_options, dt->mtu)) == NULL) 639 if ((server = dtls_server(server_sock, dt->ssl_options, dt->mtu)) == NULL)
354 goto failure; 640 goto failure;
355 641
642 if (dt->client_bbio_off)
643 SSL_set_info_callback(client, dtls_info_callback);
644 if (dt->server_bbio_off)
645 SSL_set_info_callback(server, dtls_info_callback);
646
647 dtlstest_packet_monkey(client, dt->client_drops);
648 dtlstest_packet_monkey(server, dt->server_drops);
649
356 pfd[0].fd = client_sock; 650 pfd[0].fd = client_sock;
357 pfd[0].events = POLLOUT; 651 pfd[0].events = POLLOUT;
358 pfd[1].fd = server_sock; 652 pfd[1].fd = server_sock;