X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=test%2Fdtlstest.c;h=8517eae54e5f62b37ab5f9412fe110dde3468ffd;hp=bc22d3254c2075b712cab9b44f870887970331ad;hb=24020351dc2f1565347a93ad60d70b065415c84f;hpb=8e2236eff8e38109a57347c8ad795040b380c936 diff --git a/test/dtlstest.c b/test/dtlstest.c index bc22d3254c..8517eae54e 100644 --- a/test/dtlstest.c +++ b/test/dtlstest.c @@ -1,5 +1,5 @@ /* - * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -7,6 +7,7 @@ * https://www.openssl.org/source/license.html */ +#include #include #include #include @@ -14,10 +15,10 @@ #include "ssltestlib.h" #include "testutil.h" -#include "test_main_custom.h" static char *cert = NULL; static char *privkey = NULL; +static unsigned int timer_cb_count; #define NUM_TESTS 2 @@ -41,6 +42,16 @@ static unsigned char certstatus[] = { #define RECORD_SEQUENCE 10 +static unsigned int timer_cb(SSL *s, unsigned int timer_us) +{ + ++timer_cb_count; + + if (timer_us == 0) + return 50000; + else + return 2 * timer_us; +} + static int test_dtls_unprocessed(int testidx) { SSL_CTX *sctx = NULL, *cctx = NULL; @@ -48,31 +59,27 @@ static int test_dtls_unprocessed(int testidx) BIO *c_to_s_fbio, *c_to_s_mempacket; int testresult = 0; - printf("Starting Test %d\n", testidx); + timer_cb_count = 0; - if (!create_ssl_ctx_pair(DTLS_server_method(), DTLS_client_method(), &sctx, - &cctx, cert, privkey)) { - printf("Unable to create SSL_CTX pair\n"); + if (!TEST_true(create_ssl_ctx_pair(DTLS_server_method(), + DTLS_client_method(), + DTLS1_VERSION, DTLS_MAX_VERSION, + &sctx, &cctx, cert, privkey))) return 0; - } - if (!SSL_CTX_set_cipher_list(cctx, "AES128-SHA")) { - printf("Failed setting cipher list\n"); - } + if (!TEST_true(SSL_CTX_set_cipher_list(cctx, "AES128-SHA"))) + goto end; c_to_s_fbio = BIO_new(bio_f_tls_dump_filter()); - if (c_to_s_fbio == NULL) { - printf("Failed to create filter BIO\n"); + if (!TEST_ptr(c_to_s_fbio)) goto end; - } /* BIO is freed by create_ssl_connection on error */ - if (!create_ssl_objects(sctx, cctx, &serverssl1, &clientssl1, NULL, - c_to_s_fbio)) { - printf("Unable to create SSL objects\n"); - ERR_print_errors_fp(stdout); + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl1, &clientssl1, + NULL, c_to_s_fbio))) goto end; - } + + DTLS_set_timer_cb(clientssl1, timer_cb); if (testidx == 1) certstatus[RECORD_SEQUENCE] = 0xff; @@ -80,18 +87,25 @@ static int test_dtls_unprocessed(int testidx) /* * Inject a dummy record from the next epoch. In test 0, this should never * get used because the message sequence number is too big. In test 1 we set - * the record sequence number to be way off in the future. This should not - * have an impact on the record replay protection because the record should - * be dropped before it is marked as arrived + * the record sequence number to be way off in the future. */ c_to_s_mempacket = SSL_get_wbio(clientssl1); c_to_s_mempacket = BIO_next(c_to_s_mempacket); mempacket_test_inject(c_to_s_mempacket, (char *)certstatus, sizeof(certstatus), 1, INJECT_PACKET_IGNORE_REC_SEQ); - if (!create_ssl_connection(serverssl1, clientssl1, SSL_ERROR_NONE)) { - printf("Unable to create SSL connection\n"); - ERR_print_errors_fp(stdout); + /* + * Create the connection. We use "create_bare_ssl_connection" here so that + * we can force the connection to not do "SSL_read" once partly conencted. + * We don't want to accidentally read the dummy records we injected because + * they will fail to decrypt. + */ + if (!TEST_true(create_bare_ssl_connection(serverssl1, clientssl1, + SSL_ERROR_NONE, 0))) + goto end; + + if (timer_cb_count == 0) { + printf("timer_callback was not called.\n"); goto end; } @@ -105,24 +119,231 @@ static int test_dtls_unprocessed(int testidx) return testresult; } -int test_main(int argc, char *argv[]) +#define CLI_TO_SRV_EPOCH_0_RECS 3 +#define CLI_TO_SRV_EPOCH_1_RECS 1 +#if !defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH) +# define SRV_TO_CLI_EPOCH_0_RECS 12 +#else +/* + * In this case we have no ServerKeyExchange message, because we don't have + * ECDHE or DHE. When it is present it gets fragmented into 3 records in this + * test. + */ +# define SRV_TO_CLI_EPOCH_0_RECS 9 +#endif +#define SRV_TO_CLI_EPOCH_1_RECS 1 +#define TOTAL_FULL_HAND_RECORDS \ + (CLI_TO_SRV_EPOCH_0_RECS + CLI_TO_SRV_EPOCH_1_RECS + \ + SRV_TO_CLI_EPOCH_0_RECS + SRV_TO_CLI_EPOCH_1_RECS) + +#define CLI_TO_SRV_RESUME_EPOCH_0_RECS 3 +#define CLI_TO_SRV_RESUME_EPOCH_1_RECS 1 +#define SRV_TO_CLI_RESUME_EPOCH_0_RECS 2 +#define SRV_TO_CLI_RESUME_EPOCH_1_RECS 1 +#define TOTAL_RESUME_HAND_RECORDS \ + (CLI_TO_SRV_RESUME_EPOCH_0_RECS + CLI_TO_SRV_RESUME_EPOCH_1_RECS + \ + SRV_TO_CLI_RESUME_EPOCH_0_RECS + SRV_TO_CLI_RESUME_EPOCH_1_RECS) + +#define TOTAL_RECORDS (TOTAL_FULL_HAND_RECORDS + TOTAL_RESUME_HAND_RECORDS) + +static int test_dtls_drop_records(int idx) { - int testresult = 1; + SSL_CTX *sctx = NULL, *cctx = NULL; + SSL *serverssl = NULL, *clientssl = NULL; + BIO *c_to_s_fbio, *mempackbio; + int testresult = 0; + int epoch = 0; + SSL_SESSION *sess = NULL; + int cli_to_srv_epoch0, cli_to_srv_epoch1, srv_to_cli_epoch0; + + if (!TEST_true(create_ssl_ctx_pair(DTLS_server_method(), + DTLS_client_method(), + DTLS1_VERSION, DTLS_MAX_VERSION, + &sctx, &cctx, cert, privkey))) + return 0; + + if (idx >= TOTAL_FULL_HAND_RECORDS) { + /* We're going to do a resumption handshake. Get a session first. */ + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, + NULL, NULL)) + || !TEST_true(create_ssl_connection(serverssl, clientssl, + SSL_ERROR_NONE)) + || !TEST_ptr(sess = SSL_get1_session(clientssl))) + goto end; + + SSL_shutdown(clientssl); + SSL_shutdown(serverssl); + SSL_free(serverssl); + SSL_free(clientssl); + serverssl = clientssl = NULL; - if (argc != 3) { - printf("Invalid argument count\n"); - return 1; + cli_to_srv_epoch0 = CLI_TO_SRV_RESUME_EPOCH_0_RECS; + cli_to_srv_epoch1 = CLI_TO_SRV_RESUME_EPOCH_1_RECS; + srv_to_cli_epoch0 = SRV_TO_CLI_RESUME_EPOCH_0_RECS; + idx -= TOTAL_FULL_HAND_RECORDS; + } else { + cli_to_srv_epoch0 = CLI_TO_SRV_EPOCH_0_RECS; + cli_to_srv_epoch1 = CLI_TO_SRV_EPOCH_1_RECS; + srv_to_cli_epoch0 = SRV_TO_CLI_EPOCH_0_RECS; } - cert = argv[1]; - privkey = argv[2]; + c_to_s_fbio = BIO_new(bio_f_tls_dump_filter()); + if (!TEST_ptr(c_to_s_fbio)) + goto end; + + /* BIO is freed by create_ssl_connection on error */ + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, + NULL, c_to_s_fbio))) + goto end; + + if (sess != NULL) { + if (!TEST_true(SSL_set_session(clientssl, sess))) + goto end; + } + + DTLS_set_timer_cb(clientssl, timer_cb); + DTLS_set_timer_cb(serverssl, timer_cb); + + /* Work out which record to drop based on the test number */ + if (idx >= cli_to_srv_epoch0 + cli_to_srv_epoch1) { + mempackbio = SSL_get_wbio(serverssl); + idx -= cli_to_srv_epoch0 + cli_to_srv_epoch1; + if (idx >= srv_to_cli_epoch0) { + epoch = 1; + idx -= srv_to_cli_epoch0; + } + } else { + mempackbio = SSL_get_wbio(clientssl); + if (idx >= cli_to_srv_epoch0) { + epoch = 1; + idx -= cli_to_srv_epoch0; + } + mempackbio = BIO_next(mempackbio); + } + BIO_ctrl(mempackbio, MEMPACKET_CTRL_SET_DROP_EPOCH, epoch, NULL); + BIO_ctrl(mempackbio, MEMPACKET_CTRL_SET_DROP_REC, idx, NULL); + + if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) + goto end; + + if (sess != NULL && !TEST_true(SSL_session_reused(clientssl))) + goto end; + + /* If the test did what we planned then it should have dropped a record */ + if (!TEST_int_eq((int)BIO_ctrl(mempackbio, MEMPACKET_CTRL_GET_DROP_REC, 0, + NULL), -1)) + goto end; + + testresult = 1; + end: + SSL_SESSION_free(sess); + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + + return testresult; +} + +static const char dummy_cookie[] = "0123456"; + +static int generate_cookie_cb(SSL *ssl, unsigned char *cookie, + unsigned int *cookie_len) +{ + memcpy(cookie, dummy_cookie, sizeof(dummy_cookie)); + *cookie_len = sizeof(dummy_cookie); + return 1; +} + +static int verify_cookie_cb(SSL *ssl, const unsigned char *cookie, + unsigned int cookie_len) +{ + return TEST_mem_eq(cookie, cookie_len, dummy_cookie, sizeof(dummy_cookie)); +} + +static int test_cookie(void) +{ + SSL_CTX *sctx = NULL, *cctx = NULL; + SSL *serverssl = NULL, *clientssl = NULL; + int testresult = 0; + + if (!TEST_true(create_ssl_ctx_pair(DTLS_server_method(), + DTLS_client_method(), + DTLS1_VERSION, DTLS_MAX_VERSION, + &sctx, &cctx, cert, privkey))) + return 0; + + SSL_CTX_set_options(sctx, SSL_OP_COOKIE_EXCHANGE); + SSL_CTX_set_cookie_generate_cb(sctx, generate_cookie_cb); + SSL_CTX_set_cookie_verify_cb(sctx, verify_cookie_cb); + + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, + NULL, NULL)) + || !TEST_true(create_ssl_connection(serverssl, clientssl, + SSL_ERROR_NONE))) + goto end; + + testresult = 1; + end: + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + + return testresult; +} + +static int test_dtls_duplicate_records(void) +{ + SSL_CTX *sctx = NULL, *cctx = NULL; + SSL *serverssl = NULL, *clientssl = NULL; + int testresult = 0; + + if (!TEST_true(create_ssl_ctx_pair(DTLS_server_method(), + DTLS_client_method(), + DTLS1_VERSION, DTLS_MAX_VERSION, + &sctx, &cctx, cert, privkey))) + return 0; + + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, + NULL, NULL))) + goto end; + + DTLS_set_timer_cb(clientssl, timer_cb); + DTLS_set_timer_cb(serverssl, timer_cb); + + BIO_ctrl(SSL_get_wbio(clientssl), MEMPACKET_CTRL_SET_DUPLICATE_REC, 1, NULL); + BIO_ctrl(SSL_get_wbio(serverssl), MEMPACKET_CTRL_SET_DUPLICATE_REC, 1, NULL); + + if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) + goto end; + + testresult = 1; + end: + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + + return testresult; +} + +int setup_tests(void) +{ + if (!TEST_ptr(cert = test_get_argument(0)) + || !TEST_ptr(privkey = test_get_argument(1))) + return 0; ADD_ALL_TESTS(test_dtls_unprocessed, NUM_TESTS); + ADD_ALL_TESTS(test_dtls_drop_records, TOTAL_RECORDS); + ADD_TEST(test_cookie); + ADD_TEST(test_dtls_duplicate_records); - testresult = run_tests(argv[0]); + return 1; +} +void cleanup_tests(void) +{ bio_f_tls_dump_filter_free(); bio_s_mempacket_test_free(); - - return testresult; }