X-Git-Url: https://git.openssl.org/gitweb/?a=blobdiff_plain;f=test%2Fdtlstest.c;h=8517eae54e5f62b37ab5f9412fe110dde3468ffd;hb=2cf7fd698ec1375421f91338ff8a44e7da5238b6;hp=cb58b180c27c836ea7cfcd9aab2bc4df72b51fc1;hpb=745dec3aed750d681a81a049152edbb57c1f8c2d;p=openssl.git diff --git a/test/dtlstest.c b/test/dtlstest.c index cb58b180c2..8517eae54e 100644 --- a/test/dtlstest.c +++ b/test/dtlstest.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 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,9 +59,12 @@ static int test_dtls_unprocessed(int testidx) BIO *c_to_s_fbio, *c_to_s_mempacket; int testresult = 0; + timer_cb_count = 0; + if (!TEST_true(create_ssl_ctx_pair(DTLS_server_method(), - DTLS_client_method(), &sctx, - &cctx, cert, privkey))) + DTLS_client_method(), + DTLS1_VERSION, DTLS_MAX_VERSION, + &sctx, &cctx, cert, privkey))) return 0; if (!TEST_true(SSL_CTX_set_cipher_list(cctx, "AES128-SHA"))) @@ -65,24 +79,35 @@ static int test_dtls_unprocessed(int testidx) NULL, c_to_s_fbio))) goto end; + DTLS_set_timer_cb(clientssl1, timer_cb); + if (testidx == 1) certstatus[RECORD_SEQUENCE] = 0xff; /* * 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 (!TEST_true(create_ssl_connection(serverssl1, clientssl1, - SSL_ERROR_NONE))) + /* + * 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; + } testresult = 1; end: @@ -94,22 +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; + + 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; + } + + 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; + } - if (!TEST_int_eq(argc, 3)) - return 1; + DTLS_set_timer_cb(clientssl, timer_cb); + DTLS_set_timer_cb(serverssl, timer_cb); - cert = argv[1]; - privkey = argv[2]; + /* 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; }