From 4d49ab634264c59f6fd66e9403ea0354923d7966 Mon Sep 17 00:00:00 2001 From: Hideki Miyazaki Date: Tue, 14 Sep 2021 08:22:16 +0900 Subject: [PATCH] add store finished message on Tls13 (#4381) * add to store finished message on Tls13 * addressed jenkins failure * jenkins failures sanity check for size before copying memory * remove check of finishSz * addressed review comments --- src/internal.c | 23 ++++-- src/ssl.c | 37 +++++---- src/tls13.c | 21 ++++- tests/api.c | 187 +++++++++++++++++++++++++++++++++++++++++++++ wolfssl/internal.h | 8 +- 5 files changed, 253 insertions(+), 23 deletions(-) diff --git a/src/internal.c b/src/internal.c index b070afde2..46ecb217f 100644 --- a/src/internal.c +++ b/src/internal.c @@ -6795,7 +6795,12 @@ void SSL_ResourceFree(WOLFSSL* ssl) ForceZero(&ssl->serverSecret, sizeof(ssl->serverSecret)); } #endif - +#if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS) + ForceZero(&ssl->clientFinished, TLS_FINISHED_SZ_MAX); + ForceZero(&ssl->serverFinished, TLS_FINISHED_SZ_MAX); + ssl->serverFinished_len = 0; + ssl->clientFinished_len = 0; +#endif #ifndef NO_DH if (ssl->buffers.serverDH_Priv.buffer) { ForceZero(ssl->buffers.serverDH_Priv.buffer, @@ -13186,12 +13191,16 @@ int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size, } #endif #if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS) - if (ssl->options.side == WOLFSSL_CLIENT_END) + if (ssl->options.side == WOLFSSL_CLIENT_END) { XMEMCPY(ssl->serverFinished, input + *inOutIdx, TLS_FINISHED_SZ); - else + ssl->serverFinished_len = TLS_FINISHED_SZ; + } + else { XMEMCPY(ssl->clientFinished, input + *inOutIdx, TLS_FINISHED_SZ); + ssl->clientFinished_len = TLS_FINISHED_SZ; + } #endif /* force input exhaustion at ProcessReply consuming padSz */ @@ -18165,12 +18174,16 @@ int SendFinished(WOLFSSL* ssl) } #endif #if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS) - if (ssl->options.side == WOLFSSL_CLIENT_END) + if (ssl->options.side == WOLFSSL_CLIENT_END) { XMEMCPY(ssl->clientFinished, hashes, TLS_FINISHED_SZ); - else + ssl->clientFinished_len = TLS_FINISHED_SZ; + } + else { XMEMCPY(ssl->serverFinished, hashes, TLS_FINISHED_SZ); + ssl->serverFinished_len = TLS_FINISHED_SZ; + } #endif #ifdef WOLFSSL_DTLS diff --git a/src/ssl.c b/src/ssl.c index 5402d765b..521afb811 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -28316,37 +28316,44 @@ int wolfSSL_i2d_ASN1_OBJECT(WOLFSSL_ASN1_OBJECT *a, unsigned char **pp) WOLFSSL_API size_t wolfSSL_get_finished(const WOLFSSL *ssl, void *buf, size_t count) { WOLFSSL_ENTER("SSL_get_finished"); + byte len = 0; if (!ssl || !buf || count < TLS_FINISHED_SZ) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } - if (ssl->options.side == WOLFSSL_SERVER_END) - XMEMCPY(buf, ssl->serverFinished, - TLS_FINISHED_SZ); - else - XMEMCPY(buf, ssl->clientFinished, - TLS_FINISHED_SZ); - return TLS_FINISHED_SZ; + if (ssl->options.side == WOLFSSL_SERVER_END) { + len = ssl->serverFinished_len; + XMEMCPY(buf, ssl->serverFinished, len); + } + else { + len = ssl->clientFinished_len; + XMEMCPY(buf, ssl->clientFinished, len); + } + return len; } WOLFSSL_API size_t wolfSSL_get_peer_finished(const WOLFSSL *ssl, void *buf, size_t count) { + byte len = 0; WOLFSSL_ENTER("SSL_get_peer_finished"); - + if (!ssl || !buf || count < TLS_FINISHED_SZ) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } - if (ssl->options.side == WOLFSSL_CLIENT_END) - XMEMCPY(buf, ssl->serverFinished, - TLS_FINISHED_SZ); - else - XMEMCPY(buf, ssl->clientFinished, - TLS_FINISHED_SZ); - return TLS_FINISHED_SZ; + if (ssl->options.side == WOLFSSL_CLIENT_END) { + len = ssl->serverFinished_len; + XMEMCPY(buf, ssl->serverFinished, len); + } + else { + len = ssl->clientFinished_len; + XMEMCPY(buf, ssl->clientFinished, len); + } + + return len; } #endif /* WOLFSSL_HAPROXY */ diff --git a/src/tls13.c b/src/tls13.c index 99e40a1cd..bcea4f261 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -6868,6 +6868,16 @@ int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (sniff == NO_SNIFF) { ret = BuildTls13HandshakeHmac(ssl, secret, mac, &finishedSz); + #if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS) + if (ssl->options.side == WOLFSSL_CLIENT_END) { + XMEMCPY(ssl->serverFinished, mac, finishedSz); + ssl->serverFinished_len = finishedSz; + } + else { + XMEMCPY(ssl->clientFinished, mac, finishedSz); + ssl->clientFinished_len = finishedSz; + } + #endif if (ret != 0) return ret; if (size != finishedSz) @@ -6983,7 +6993,16 @@ static int SendTls13Finished(WOLFSSL* ssl) ret = BuildTls13HandshakeHmac(ssl, secret, &input[headerSz], NULL); if (ret != 0) return ret; - + #if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS) + if (ssl->options.side == WOLFSSL_CLIENT_END) { + XMEMCPY(ssl->clientFinished, &input[headerSz], finishedSz); + ssl->clientFinished_len = finishedSz; + } + else { + XMEMCPY(ssl->serverFinished, &input[headerSz], finishedSz); + ssl->serverFinished_len = finishedSz; + } + #endif /* This message is always encrypted. */ sendSz = BuildTls13Message(ssl, output, outputSz, input, headerSz + finishedSz, handshake, 1, 0, 0); diff --git a/tests/api.c b/tests/api.c index 30d699f2d..9ea681c65 100644 --- a/tests/api.c +++ b/tests/api.c @@ -3803,6 +3803,13 @@ static int nonblocking_accept_read(void* args, WOLFSSL* ssl, SOCKET_T* sockfd) } #endif +#if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS) + #define MD_MAX_SIZE WC_SHA512_DIGEST_SIZE + byte server_side_msg1[MD_MAX_SIZE] = {0};/* msg sent by server */ + byte server_side_msg2[MD_MAX_SIZE] = {0};/* msg received from client */ + byte client_side_msg1[MD_MAX_SIZE] = {0};/* msg sent by client */ + byte client_side_msg2[MD_MAX_SIZE] = {0};/* msg received from server */ +#endif static THREAD_RETURN WOLFSSL_THREAD test_server_nofail(void* args) { SOCKET_T sockfd = 0; @@ -3818,6 +3825,9 @@ static THREAD_RETURN WOLFSSL_THREAD test_server_nofail(void* args) int idx; int ret, err = 0; int sharedCtx = 0; +#if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS) + size_t msg_len = 0; +#endif #ifdef WOLFSSL_TIRTOS fdOpenSession(Task_self()); @@ -4001,6 +4011,15 @@ static THREAD_RETURN WOLFSSL_THREAD test_server_nofail(void* args) goto done; } +#if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS) + XMEMSET(server_side_msg2, 0, MD_MAX_SIZE); + msg_len = wolfSSL_get_peer_finished(ssl, server_side_msg2, MD_MAX_SIZE); + AssertIntGE(msg_len, 0); + + XMEMSET(server_side_msg1, 0, MD_MAX_SIZE); + msg_len = wolfSSL_get_finished(ssl, server_side_msg1, MD_MAX_SIZE); + AssertIntGE(msg_len, 0); +#endif idx = wolfSSL_read(ssl, input, sizeof(input)-1); if (idx > 0) { input[idx] = '\0'; @@ -5239,6 +5258,171 @@ static void test_wolfSSL_CTX_verifyDepth_ServerClient(void) #endif /* (OPENSSL_EXTRA) && !(WOLFSSL_TIRTOS) && (NO_WOLFSSL_CLIENT) */ } +static void test_client_get_finished(void* args, cbType cb) +{ + (void) args; + (void) cb; +#if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS) + SOCKET_T sockfd = 0; + callback_functions* cbf; + + WOLFSSL_CTX* ctx = 0; + WOLFSSL* ssl = 0; + + char msg[64] = "hello wolfssl!"; + char reply[1024]; + int input; + int msgSz = (int)XSTRLEN(msg); + int ret, err = 0; + WOLFSSL_METHOD* method = NULL; + size_t msg_len = 0; + + ((func_args*)args)->return_code = TEST_FAIL; + cbf = ((func_args*)args)->callbacks; + + if (cbf != NULL && cbf->method != NULL) { + method = cbf->method(); + } + else { + method = wolfSSLv23_client_method(); + } + ctx = wolfSSL_CTX_new(method); + + /* Do connect here so server detects failures */ + tcp_connect(&sockfd, wolfSSLIP, ((func_args*)args)->signal->port, + 0, 0, NULL); + + if (wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0) != WOLFSSL_SUCCESS) + { + /* err_sys("can't load ca file, Please run from wolfSSL home dir");*/ + goto done; + } + + if (wolfSSL_CTX_use_certificate_file(ctx, cliCertFile, + WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS) { + goto done; + } + if (wolfSSL_CTX_use_PrivateKey_file(ctx, cliKeyFile, + WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS) { + goto done; + } + + /* call ctx setup callback */ + if (cbf != NULL && cbf->ctx_ready != NULL) { + cbf->ctx_ready(ctx); + } + + ssl = wolfSSL_new(ctx); + if (ssl == NULL) { + goto done; + } + + if (wolfSSL_set_fd(ssl, sockfd) != WOLFSSL_SUCCESS) { + goto done; + } + + /* call ssl setup callback */ + if (cbf != NULL && cbf->ssl_ready != NULL) { + cbf->ssl_ready(ssl); + } + + do { +#ifdef WOLFSSL_ASYNC_CRYPT + if (err == WC_PENDING_E) { + ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW); + if (ret < 0) { break; } else if (ret == 0) { continue; } + } +#endif + + err = 0; /* Reset error */ + ret = wolfSSL_connect(ssl); + if (ret != WOLFSSL_SUCCESS) { + err = wolfSSL_get_error(ssl, 0); + } + } while (ret != WOLFSSL_SUCCESS && err == WC_PENDING_E); + + if (ret != WOLFSSL_SUCCESS) { + char buff[WOLFSSL_MAX_ERROR_SZ]; + printf("error = %d, %s\n", err, wolfSSL_ERR_error_string(err, buff)); + goto done; + } + + /* get_finished test */ + /* 1. get own sent message */ + XMEMSET(client_side_msg1, 0, MD_MAX_SIZE); + msg_len = wolfSSL_get_finished(ssl, client_side_msg1, MD_MAX_SIZE); + AssertIntGE(msg_len, 0); + /* 2. get peer message */ + XMEMSET(client_side_msg2, 0, MD_MAX_SIZE); + msg_len = wolfSSL_get_peer_finished(ssl, client_side_msg2, MD_MAX_SIZE); + AssertIntGE(msg_len, 0); + + if (cb != NULL) + (cb)(ctx, ssl); + + if (wolfSSL_write(ssl, msg, msgSz) != msgSz) { + /*err_sys("SSL_write failed");*/ + goto done; + } + + input = wolfSSL_read(ssl, reply, sizeof(reply)-1); + if (input > 0) { + reply[input] = '\0'; + printf("Server response: %s\n", reply); + } + + + ((func_args*)args)->return_code = TEST_SUCCESS; + +done: + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + CloseSocket(sockfd); + + return; +#endif +} + +static void test_wolfSSL_get_finished(void) +{ +#if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS) + + tcp_ready ready; + func_args client_args; + func_args server_args; + THREAD_TYPE serverThread; + + XMEMSET(&client_args, 0, sizeof(func_args)); + XMEMSET(&server_args, 0, sizeof(func_args)); + + StartTCP(); + InitTcpReady(&ready); + +#if defined(USE_WINDOWS_API) + /* use RNG to get random port if using windows */ + ready.port = GetRandomPort(); +#endif + + server_args.signal = &ready; + client_args.signal = &ready; + + start_thread(test_server_nofail, &server_args, &serverThread); + wait_tcp_ready(&server_args); + test_client_get_finished(&client_args, NULL); + join_thread(serverThread); + + AssertTrue(client_args.return_code); + AssertTrue(server_args.return_code); + + /* test received msg vs sent msg */ + AssertIntEQ(0, XMEMCMP(client_side_msg1, server_side_msg2, MD_MAX_SIZE)); + AssertIntEQ(0, XMEMCMP(client_side_msg2, server_side_msg1, MD_MAX_SIZE)); + + FreeTcpReady(&ready); +#else + (void)test_client_get_finished; +#endif +} #if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) /* canned export of a session using older version 3 */ @@ -48547,6 +48731,9 @@ void ApiTest(void) #if (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)) && \ (!defined(NO_RSA) || defined(HAVE_ECC)) test_for_double_Free(); +#endif +#ifdef HAVE_IO_TESTS_DEPENDENCIES + test_wolfSSL_get_finished(); #endif test_SSL_CIPHER_get_xxx(); test_wolfSSL_ERR_strings(); diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 9439b6eba..1bcb5918e 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1376,6 +1376,8 @@ enum Misc { /* max size of buffer for exporting state */ FINISHED_LABEL_SZ = 15, /* TLS finished label size */ TLS_FINISHED_SZ = 12, /* TLS has a shorter size */ + TLS_FINISHED_SZ_MAX = WC_MAX_DIGEST_SIZE, + /* longest message digest size is SHA512, 64 */ EXT_MASTER_LABEL_SZ = 22, /* TLS extended master secret label sz */ MASTER_LABEL_SZ = 13, /* TLS master secret label sz */ KEY_LABEL_SZ = 13, /* TLS key block expansion sz */ @@ -4538,8 +4540,10 @@ struct WOLFSSL { * used in the EST protocol to bind an enrollment to a TLS session through * 'proof-of-possession' (https://tools.ietf.org/html/rfc7030#section-3.4 * and https://tools.ietf.org/html/rfc7030#section-3.5). */ - byte clientFinished[TLS_FINISHED_SZ]; - byte serverFinished[TLS_FINISHED_SZ]; + byte clientFinished[TLS_FINISHED_SZ_MAX]; + byte serverFinished[TLS_FINISHED_SZ_MAX]; + byte clientFinished_len; + byte serverFinished_len; #endif #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) || defined(HAVE_LIGHTY) WOLF_STACK_OF(WOLFSSL_X509_NAME)* ca_names;