diff --git a/tests/api.c b/tests/api.c index 92063eab0..ea0df1598 100644 --- a/tests/api.c +++ b/tests/api.c @@ -58699,6 +58699,263 @@ static int test_wolfSSL_DTLS_fragment_buckets(void) } #endif +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) + +static int test_wolfSSL_dtls_stateless2(void) +{ + WOLFSSL *ssl_c, *ssl_c2, *ssl_s; + struct test_memio_ctx test_ctx; + WOLFSSL_CTX *ctx_c, *ctx_s; + int ret; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ret = test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method); + if (ret != 0) + return -1; + ssl_c2 = wolfSSL_new(ctx_c); + if (ssl_c2 == NULL) + return -2; + wolfSSL_SetIOWriteCtx(ssl_c2, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_c2, &test_ctx); + /* send CH */ + ret = wolfSSL_connect(ssl_c2); + if (ret == 0 || ssl_c2->error != WANT_READ) + return -3; + ret = wolfSSL_accept(ssl_s); + if (ret == 0 || ssl_s->error != WANT_READ) + return -4; + if (test_ctx.c_len == 0) + return -5; + /* consume HRR */ + test_ctx.c_len = 0; + ret = test_memio_do_handshake(ssl_c, ssl_s, 10, NULL); + if (ret != 0) + return -6; + wolfSSL_free(ssl_c2); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return TEST_SUCCESS; +} + +#ifdef HAVE_MAX_FRAGMENT +static int test_wolfSSL_dtls_stateless_maxfrag(void) +{ + WOLFSSL *ssl_c, *ssl_c2, *ssl_s; + struct test_memio_ctx test_ctx; + WOLFSSL_CTX *ctx_c, *ctx_s; + word16 max_fragment; + int ret; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ret = test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method); + if (ret != 0) + return -1; + ssl_c2 = wolfSSL_new(ctx_c); + if (ssl_c2 == NULL) + return -2; + ret = wolfSSL_UseMaxFragment(ssl_c2, WOLFSSL_MFL_2_8); + if (ret != WOLFSSL_SUCCESS) + return -3; + wolfSSL_SetIOWriteCtx(ssl_c2, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_c2, &test_ctx); + max_fragment = ssl_s->max_fragment; + /* send CH */ + ret = wolfSSL_connect(ssl_c2); + if (ret == 0 || ssl_c2->error != WANT_READ) + return -4; + ret = wolfSSL_accept(ssl_s); + if (ret == 0 || ssl_s->error != WANT_READ) + return -5; + /* CH without cookie shouldn't change state */ + if (ssl_s->max_fragment != max_fragment) + return -6; + if (test_ctx.c_len == 0) + return -7; + /* consume HRR from buffer */ + test_ctx.c_len = 0; + ret = test_memio_do_handshake(ssl_c, ssl_s, 10, NULL); + if (ret != 0) + return -8; + wolfSSL_free(ssl_c2); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return TEST_SUCCESS; +} +#endif /* HAVE_MAX_FRAGMENT */ + +#if defined(WOLFSSL_DTLS_NO_HVR_ON_RESUME) +#define ROUNDS_WITH_HVR 4 +#define ROUNDS_WITHOUT_HVR 2 +#define HANDSHAKE_TYPE_OFFSET DTLS_RECORD_HEADER_SZ +static int buf_is_hvr(const byte *data, int len) +{ + if (len < DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ) + return 0; + return data[HANDSHAKE_TYPE_OFFSET] == hello_verify_request; +} + +static int _test_wolfSSL_dtls_stateless_resume(byte useticket, byte bad) +{ + struct test_memio_ctx test_ctx; + WOLFSSL_CTX *ctx_c, *ctx_s; + WOLFSSL *ssl_c, *ssl_s; + WOLFSSL_SESSION *sess; + int ret, round_trips; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ret = test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method); + if (ret != 0) + return -1; +#ifdef HAVE_SESSION_TICKET + if (useticket) { + ret = wolfSSL_UseSessionTicket(ssl_c); + if (ret != WOLFSSL_SUCCESS) + return -2; + } +#endif + round_trips = ROUNDS_WITH_HVR; + ret = test_memio_do_handshake(ssl_c, ssl_s, round_trips, &round_trips); + if (ret != 0) + return -3; + if (round_trips != ROUNDS_WITH_HVR) + return -4; + sess = wolfSSL_get1_session(ssl_c); + if (sess == NULL) + return -5; + wolfSSL_shutdown(ssl_c); + wolfSSL_shutdown(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + test_ctx.c_len = test_ctx.s_len = 0; + /* make resumption invalid */ + if (bad) { + if (useticket) { +#ifdef HAVE_SESSION_TICKET + sess->ticket[0] = !sess->ticket[0]; +#endif /* HAVE_SESSION_TICKET */ + } + else { + sess->sessionID[0] = !sess->sessionID[0]; + } + } + ssl_c = wolfSSL_new(ctx_c); + ssl_s = wolfSSL_new(ctx_s); + wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_c, &test_ctx); + wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_s, &test_ctx); + ret = wolfSSL_set_session(ssl_c, sess); + if (ret != WOLFSSL_SUCCESS) + return -6; + ret = wolfSSL_connect(ssl_c); + if (ret == WOLFSSL_SUCCESS || ssl_c->error != WANT_READ) + return -7; + ret = wolfSSL_accept(ssl_s); + if (ret == WOLFSSL_SUCCESS || ssl_s->error != WANT_READ) + return -8; + if (bad && !buf_is_hvr(test_ctx.c_buff, test_ctx.c_len)) + return -9; + if (!bad && buf_is_hvr(test_ctx.c_buff, test_ctx.c_len)) + return -10; + if (!useticket) { + ret = test_memio_do_handshake(ssl_c, ssl_s, 10, &round_trips); + if (ret != 0) + return -11; + if (bad && round_trips != ROUNDS_WITH_HVR - 1) + return -12; + if (!bad && round_trips != ROUNDS_WITHOUT_HVR - 1) + return -13; + } + wolfSSL_SESSION_free(sess); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return TEST_SUCCESS; +} + +static int test_wolfSSL_dtls_stateless_resume(void) +{ + int ret; +#ifdef HAVE_SESSION_TICKET + ret = _test_wolfSSL_dtls_stateless_resume(1, 0); + if (ret != 0) + return ret; + ret = _test_wolfSSL_dtls_stateless_resume(1, 1); + if (ret != 0) + return ret - 100; +#endif /* HAVE_SESION_TICKET */ + ret = _test_wolfSSL_dtls_stateless_resume(0, 0); + if (ret != 0) + return ret - 200; + ret = _test_wolfSSL_dtls_stateless_resume(0, 1); + if (ret != 0) + return ret - 300; + return TEST_SUCCESS; +} +#endif /* WOLFSSL_DTLS_NO_HVR_ON_RESUME */ + +#if !defined(NO_OLD_TLS) +static int test_wolfSSL_dtls_stateless_downgrade(void) +{ + WOLFSSL_CTX *ctx_c, *ctx_c2, *ctx_s; + WOLFSSL *ssl_c, *ssl_c2, *ssl_s; + struct test_memio_ctx test_ctx; + int ret; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ret = test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method); + if (ret != 0) + return -1; + ret = wolfSSL_CTX_SetMinVersion(ctx_s, WOLFSSL_DTLSV1); + if (ret != WOLFSSL_SUCCESS) + return -2; + ctx_c2 = wolfSSL_CTX_new(wolfDTLSv1_client_method()); + if (ctx_c2 == NULL) + return -3; + wolfSSL_SetIORecv(ctx_c2, test_memio_read_cb); + wolfSSL_SetIOSend(ctx_c2, test_memio_write_cb); + ssl_c2 = wolfSSL_new(ctx_c2); + if (ssl_c2 == NULL) + return -4; + wolfSSL_SetIOWriteCtx(ssl_c2, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_c2, &test_ctx); + /* send CH */ + ret = wolfSSL_connect(ssl_c2); + if (ret == 0 || ssl_c2->error != WANT_READ) + return -5; + ret = wolfSSL_accept(ssl_s); + if (ret == 0 || ssl_s->error != WANT_READ) + return -6; + if (test_ctx.c_len == 0) + return -7; + /* consume HRR */ + test_ctx.c_len = 0; + ret = test_memio_do_handshake(ssl_c, ssl_s, 10, NULL); + if (ret != 0) + return -8; + wolfSSL_free(ssl_c2); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_c2); + wolfSSL_CTX_free(ctx_s); + + return TEST_SUCCESS; +} +#endif /* !defined(NO_OLD_TLS) */ + +#endif /* defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)*/ #if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ @@ -59882,6 +60139,20 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_DtlsUpdateWindow), TEST_DECL(test_wolfSSL_DTLS_fragment_buckets), #endif +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) +#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME + TEST_DECL(test_wolfSSL_dtls_stateless_resume), +#endif /* WOLFSSL_DTLS_NO_HVR_ON_RESUME */ +#ifdef HAVE_MAX_FRAGMENT + TEST_DECL(test_wolfSSL_dtls_stateless_maxfrag), +#endif /* HAVE_MAX_FRAGMENT */ + TEST_DECL(test_wolfSSL_dtls_stateless2), +#if !defined(NO_OLD_TLS) + TEST_DECL(test_wolfSSL_dtls_stateless_downgrade), +#endif /* !defined(NO_OLD_TLS) */ +#endif /* defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ + * !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) */ TEST_DECL(test_WOLFSSL_dtls_version_alert), TEST_DECL(test_ForceZero), diff --git a/wolfssl/test.h b/wolfssl/test.h index 8697c5866..72105526e 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -5136,8 +5136,7 @@ void DEBUG_WRITE_DER(const byte* der, int derSz, const char* fileName); (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))\ || \ (defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ - !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ - !defined(NO_OLD_TLS)) + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)) #define TEST_MEMIO_BUF_SZ (64 * 1024) struct test_memio_ctx { @@ -5206,6 +5205,51 @@ static WC_INLINE int test_memio_read_cb(WOLFSSL *ssl, char *data, int sz, return read_sz; } +static WC_INLINE int test_memio_do_handshake(WOLFSSL *ssl_c, WOLFSSL *ssl_s, + int max_rounds, int *rounds) +{ + byte handshake_complete = 0, hs_c = 0, hs_s = 0; + int ret, err; + + if (rounds != NULL) + *rounds = 0; + while (!handshake_complete && max_rounds > 0) { + if (!hs_c) { + ret = wolfSSL_connect(ssl_c); + if (ret == WOLFSSL_SUCCESS) { + hs_c = 1; + } + else { + err = wolfSSL_get_error(ssl_c, ret); + if (err != WOLFSSL_ERROR_WANT_READ && + err != WOLFSSL_ERROR_WANT_WRITE) + return -1; + } + } + if (!hs_s) { + ret = wolfSSL_accept(ssl_s); + if (ret == WOLFSSL_SUCCESS) { + hs_s = 1; + } + else { + err = wolfSSL_get_error(ssl_c, ret); + if (err != WOLFSSL_ERROR_WANT_READ && + err != WOLFSSL_ERROR_WANT_WRITE) + return -1; + } + } + handshake_complete = hs_c && hs_s; + max_rounds--; + if (rounds != NULL) + *rounds = *rounds + 1; + } + + if (!handshake_complete) + return -1; + + return 0; +} + static WC_INLINE int test_memio_setup(struct test_memio_ctx *ctx, WOLFSSL_CTX **ctx_c, WOLFSSL_CTX **ctx_s, WOLFSSL **ssl_c, WOLFSSL **ssl_s, method_provider method_c, method_provider method_s) @@ -5224,6 +5268,9 @@ static WC_INLINE int test_memio_setup(struct test_memio_ctx *ctx, ret = wolfSSL_CTX_use_certificate_file(*ctx_s, svrCertFile, WOLFSSL_FILETYPE_PEM); + if (ret != WOLFSSL_SUCCESS) + return -1; + ret = wolfSSL_CTX_load_verify_locations(*ctx_c, caCertFile, 0); if (ret != WOLFSSL_SUCCESS) return -1; wolfSSL_SetIORecv(*ctx_c, test_memio_read_cb);