diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/regress/lib/libssl/dtls/dtlstest.c | 304 |
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 | ||
36 | int debug = 0; | 36 | int debug = 0; |
37 | 37 | ||
38 | static void | ||
39 | hexdump(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 | |||
53 | struct bio_packet_monkey_ctx { | ||
54 | unsigned int drop_rand; | ||
55 | unsigned int drop_mask; | ||
56 | }; | ||
57 | |||
58 | static int | ||
59 | bio_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 | |||
74 | static int | ||
75 | bio_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 | |||
88 | static long | ||
89 | bio_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 | |||
115 | static int | ||
116 | bio_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 | |||
133 | static int | ||
134 | bio_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 | |||
166 | static int | ||
167 | bio_packet_monkey_puts(BIO *bio, const char *str) | ||
168 | { | ||
169 | return bio_packet_monkey_write(bio, str, strlen(str)); | ||
170 | } | ||
171 | |||
172 | static 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 | |||
183 | static const BIO_METHOD * | ||
184 | BIO_f_packet_monkey(void) | ||
185 | { | ||
186 | return &bio_packet_monkey; | ||
187 | } | ||
188 | |||
189 | static BIO * | ||
190 | BIO_new_packet_monkey(void) | ||
191 | { | ||
192 | return BIO_new(BIO_f_packet_monkey()); | ||
193 | } | ||
194 | |||
195 | static int | ||
196 | BIO_packet_monkey_drop(BIO *bio, int num) | ||
197 | { | ||
198 | return BIO_ctrl(bio, BIO_C_DROP_PACKET, num, NULL); | ||
199 | } | ||
200 | |||
201 | #if 0 | ||
202 | static int | ||
203 | BIO_packet_monkey_drop_random(BIO *bio, int num) | ||
204 | { | ||
205 | return BIO_ctrl(bio, BIO_C_DROP_RANDOM, num, NULL); | ||
206 | } | ||
207 | #endif | ||
208 | |||
38 | static int | 209 | static int |
39 | datagram_pair(int *client_sock, int *server_sock, | 210 | datagram_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 | ||
283 | static void | ||
284 | dtls_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 | |||
112 | static SSL * | 294 | static SSL * |
113 | dtls_client(int sock, struct sockaddr_in *server_sin, long mtu) | 295 | dtls_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 | |||
308 | struct dtls_test { | 492 | struct 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 | ||
314 | static struct dtls_test dtls_tests[] = { | 502 | static 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 | ||
596 | static void | ||
597 | dtlstest_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 | |||
336 | static int | 622 | static int |
337 | dtlstest(struct dtls_test *dt) | 623 | dtlstest(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; |