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; |
