diff --git a/examples/client/client.c b/examples/client/client.c index d5bc0d544..c637fcc07 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -189,6 +189,50 @@ static void ShowVersions(void) printf("\n"); } +#ifdef WOLFSSL_TLS13 +static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519) +{ + (void)useX25519; + + WOLFSSL_START(WC_FUNC_CLIENT_KEY_EXCHANGE_SEND); + if (onlyKeyShare == 0 || onlyKeyShare == 2) { + #ifdef HAVE_CURVE25519 + if (useX25519) { + int groups[1] = { WOLFSSL_ECC_X25519 }; + if (wolfSSL_UseKeyShare(ssl, WOLFSSL_ECC_X25519) != WOLFSSL_SUCCESS) + err_sys("unable to use curve x25519"); + if (wolfSSL_set_groups(ssl, groups, 1) != WOLFSSL_SUCCESS) + err_sys("unable to set groups: x25519"); + } + else + #endif + { + #ifdef HAVE_ECC + #if defined(HAVE_ECC256) || defined(HAVE_ALL_CURVES) + int groups[1] = { WOLFSSL_ECC_SECP256R1 }; + if (wolfSSL_UseKeyShare(ssl, WOLFSSL_ECC_SECP256R1) + != WOLFSSL_SUCCESS) { + err_sys("unable to use curve secp256r1"); + } + if (wolfSSL_set_groups(ssl, groups, 1) != WOLFSSL_SUCCESS) + err_sys("unable to set groups: secp256r1"); + #endif + #endif + } + } + if (onlyKeyShare == 0 || onlyKeyShare == 1) { + #ifdef HAVE_FFDHE_2048 + int groups[1] = { WOLFSSL_FFDHE_2048 }; + if (wolfSSL_UseKeyShare(ssl, WOLFSSL_FFDHE_2048) != WOLFSSL_SUCCESS) + err_sys("unable to use DH 2048-bit parameters"); + if (wolfSSL_set_groups(ssl, groups, 1) != WOLFSSL_SUCCESS) + err_sys("unable to set groups: DH 2048-bit"); + #endif + } + WOLFSSL_END(WC_FUNC_CLIENT_KEY_EXCHANGE_SEND); +} +#endif + /* Measures average time to create, connect and disconnect a connection (TPS). Benchmark = number of connections. */ static int ClientBenchmarkConnections(WOLFSSL_CTX* ctx, char* host, word16 port, @@ -230,55 +274,21 @@ static int ClientBenchmarkConnections(WOLFSSL_CTX* ctx, char* host, word16 port, if (ssl == NULL) err_sys("unable to get SSL object"); + #ifndef NO_SESSION_CACHE + if (benchResume) + wolfSSL_set_session(ssl, benchSession); + #endif #ifdef WOLFSSL_TLS13 - if (version >= 4) { - if (!helloRetry) { - WOLFSSL_START(WC_FUNC_CLIENT_KEY_EXCHANGE_SEND); - if (onlyKeyShare == 0 || onlyKeyShare == 2) { - #ifdef HAVE_CURVE25519 - if (useX25519) { - if (wolfSSL_UseKeyShare(ssl, WOLFSSL_ECC_X25519) - != WOLFSSL_SUCCESS) { - err_sys("unable to use curve x25519"); - } - } - else - #endif - #ifdef HAVE_ECC - #if defined(HAVE_ECC256) || defined(HAVE_ALL_CURVES) - if (wolfSSL_UseKeyShare(ssl, WOLFSSL_ECC_SECP256R1) - != WOLFSSL_SUCCESS) { - err_sys("unable to use curve secp256r1"); - } - else - #endif - #endif - { - } - } - if (onlyKeyShare == 0 || onlyKeyShare == 1) { - #ifdef HAVE_FFDHE_2048 - if (wolfSSL_UseKeyShare(ssl, WOLFSSL_FFDHE_2048) - != WOLFSSL_SUCCESS) { - err_sys("unable to use DH 2048-bit parameters"); - } - #endif - } - WOLFSSL_END(WC_FUNC_CLIENT_KEY_EXCHANGE_SEND); - } - else { + else if (version >= 4) { + if (!helloRetry) + SetKeyShare(ssl, onlyKeyShare, useX25519); + else wolfSSL_NoKeyShares(ssl); - } } #endif tcp_connect(&sockfd, host, port, dtlsUDP, dtlsSCTP, ssl); - #ifndef NO_SESSION_CACHE - if (benchResume) - wolfSSL_set_session(ssl, benchSession); - #endif - if (wolfSSL_set_fd(ssl, sockfd) != WOLFSSL_SUCCESS) { err_sys("error in setting fd"); } @@ -1198,7 +1208,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #ifdef HAVE_MAX_FRAGMENT maxFragment = atoi(myoptarg); if (maxFragment < WOLFSSL_MFL_2_9 || - maxFragment > WOLFSSL_MFL_2_13) { + maxFragment > WOLFSSL_MFL_2_13) { Usage(); exit(MY_EX_USAGE); } @@ -1801,6 +1811,10 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) != WOLFSSL_SUCCESS) { err_sys("unable to support secp256r1"); } + if (wolfSSL_CTX_UseSupportedCurve(ctx, WOLFSSL_ECC_SECP384R1) + != WOLFSSL_SUCCESS) { + err_sys("unable to support secp384r1"); + } } #endif /* HAVE_CURVE25519 && HAVE_SUPPORTED_CURVES */ @@ -1893,7 +1907,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #ifdef HAVE_CURVE25519 if (useX25519) { if (wolfSSL_UseKeyShare(ssl, WOLFSSL_ECC_X25519) - != WOLFSSL_SUCCESS) { + != WOLFSSL_SUCCESS) { err_sys("unable to use curve x25519"); } } @@ -1901,13 +1915,13 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #ifdef HAVE_ECC #if defined(HAVE_ECC256) || defined(HAVE_ALL_CURVES) if (wolfSSL_UseKeyShare(ssl, WOLFSSL_ECC_SECP256R1) - != WOLFSSL_SUCCESS) { + != WOLFSSL_SUCCESS) { err_sys("unable to use curve secp256r1"); } #endif #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) if (wolfSSL_UseKeyShare(ssl, WOLFSSL_ECC_SECP384R1) - != WOLFSSL_SUCCESS) { + != WOLFSSL_SUCCESS) { err_sys("unable to use curve secp384r1"); } #endif @@ -2310,38 +2324,6 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) (void*)"resumed session"); #endif -#ifdef WOLFSSL_TLS13 - if (!helloRetry) { - #ifdef HAVE_CURVE25519 - if (useX25519) { - if (wolfSSL_UseKeyShare(ssl, WOLFSSL_ECC_X25519) != WOLFSSL_SUCCESS) { - err_sys("unable to use curve x25519"); - } - } - #endif - #ifdef HAVE_ECC - if (wolfSSL_UseKeyShare(sslResume, - WOLFSSL_ECC_SECP256R1) != WOLFSSL_SUCCESS) { - err_sys("unable to use curve secp256r1"); - } - #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) - if (wolfSSL_UseKeyShare(sslResume, - WOLFSSL_ECC_SECP384R1) != WOLFSSL_SUCCESS) { - err_sys("unable to use curve secp384r1"); - } - #endif - #endif - #ifdef HAVE_FFDHE_2048 - if (wolfSSL_UseKeyShare(sslResume, WOLFSSL_FFDHE_2048) != WOLFSSL_SUCCESS) { - err_sys("unable to use DH 2048-bit parameters"); - } - #endif - } - else { - wolfSSL_NoKeyShares(ssl); - } -#endif - #ifndef WOLFSSL_CALLBACKS if (nonBlocking) { wolfSSL_set_using_nonblock(sslResume, 1); @@ -2420,7 +2402,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #else timeout.tv_sec = DEFAULT_TIMEOUT_SEC; timeout.tv_usec = 0; - ret = NonBlockingSSL_Connect(ssl); /* will keep retrying on timeout */ + ret = NonBlockingSSL_Connect(sslResume); /* will keep retrying on timeout */ #endif if (ret != WOLFSSL_SUCCESS) { printf("wolfSSL_connect resume error %d, %s\n", err, diff --git a/examples/server/server.c b/examples/server/server.c index 896d4760a..36673be01 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -1206,10 +1206,10 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) #endif /* WOLFSSL_ASYNC_CRYPT */ #ifdef WOLFSSL_TLS13 - if (noPskDheKe) - wolfSSL_CTX_no_dhe_psk(ctx); - if (noTicket) - wolfSSL_CTX_no_ticket_TLSv13(ctx); + if (noPskDheKe) + wolfSSL_CTX_no_dhe_psk(ctx); + if (noTicket) + wolfSSL_CTX_no_ticket_TLSv13(ctx); #endif while (1) { @@ -1337,30 +1337,45 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) if (onlyKeyShare == 2) { if (useX25519 == 1) { #ifdef HAVE_CURVE25519 + int groups[1] = { WOLFSSL_ECC_X25519 }; + if (wolfSSL_UseKeyShare(ssl, WOLFSSL_ECC_X25519) != WOLFSSL_SUCCESS) { err_sys("unable to use curve x25519"); } + if (wolfSSL_set_groups(ssl, groups, 1) != WOLFSSL_SUCCESS) { + err_sys("unable to set groups: x25519"); + } #endif } else { #ifdef HAVE_ECC #if defined(HAVE_ECC256) || defined(HAVE_ALL_CURVES) - if (wolfSSL_UseKeyShare(ssl, WOLFSSL_ECC_SECP256R1) + int groups[1] = { WOLFSSL_ECC_SECP256R1 }; + + if (wolfSSL_UseKeyShare(ssl, WOLFSSL_ECC_SECP256R1) != WOLFSSL_SUCCESS) { - err_sys("unable to use curve secp256r1"); - } + err_sys("unable to use curve secp256r1"); + } + if (wolfSSL_set_groups(ssl, groups, 1) != WOLFSSL_SUCCESS) { + err_sys("unable to set groups: secp256r1"); + } #endif #endif } } else if (onlyKeyShare == 1) { #ifdef HAVE_FFDHE_2048 + int groups[1] = { WOLFSSL_FFDHE_2048 }; + if (wolfSSL_UseKeyShare(ssl, WOLFSSL_FFDHE_2048) != WOLFSSL_SUCCESS) { err_sys("unable to use DH 2048-bit parameters"); } + if (wolfSSL_set_groups(ssl, groups, 1) != WOLFSSL_SUCCESS) { + err_sys("unable to set groups: DH 2048-bit"); + } #endif } WOLFSSL_END(WC_FUNC_CLIENT_KEY_EXCHANGE_DO); diff --git a/scripts/tls13.test b/scripts/tls13.test index 4136c85e4..847b2626f 100755 --- a/scripts/tls13.test +++ b/scripts/tls13.test @@ -421,6 +421,71 @@ if [ $RESULT -ne 0 ]; then fi echo "" +# TLS Downgrade server / TLS Downgrade client. +echo -e "\n\nTLS server and client able to downgrade but don't" +port=0 +./examples/server/server -v d -R $ready_file -p $port & +server_pid=$! +create_port +./examples/client/client -v d -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nIssue with TLS not downgrading" + do_cleanup + exit 1 +fi +echo "" + +# TLS Downgrade server / TLS Downgrade client resumption. +echo -e "\n\nTLS server and client able to downgrade but don't and resume" +port=0 +./examples/server/server -v d -r -R $ready_file -p $port & +server_pid=$! +create_port +./examples/client/client -v d -r -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nIssue with TLS not downgrading and resumption" + do_cleanup + exit 1 +fi +echo "" + +# TLS Downgrade server / TLS 1.2 client and resume. +echo -e "\n\nTLS server downgrade and resume" +port=0 +./examples/server/server -v d -r -R $ready_file -p $port & +server_pid=$! +create_port +./examples/client/client -v 3 -r -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nIssue with TLS server downgrading and resumption" + do_cleanup + exit 1 +fi +echo "" + +# TLS 1.2 server / TLS downgrade client and resume. +echo -e "\n\nTLS client downgrade and resume" +port=0 +./examples/server/server -v 3 -r -R $ready_file -p $port & +server_pid=$! +create_port +./examples/client/client -v d -r -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nIssue with TLS client downgrading and resumption" + do_cleanup + exit 1 +fi +echo "" + +# TLS Downgrade server / TLS Downgrade client. # TLS 1.3 server / TLS 1.3 client send KeyUpdate before sending app data. echo -e "\n\nTLS v1.3 KeyUpdate" port=0 diff --git a/src/internal.c b/src/internal.c index c96189994..3607bcd02 100644 --- a/src/internal.c +++ b/src/internal.c @@ -4458,6 +4458,11 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) #if defined(WOLFSSL_POST_HANDSHAKE_AUTH) ssl->options.postHandshakeAuth = ctx->postHandshakeAuth; #endif + + if (ctx->numGroups > 0) { + XMEMCPY(ssl->group, ctx->group, sizeof(*ctx->group) * ctx->numGroups); + ssl->numGroups = ctx->numGroups; + } #endif #ifdef HAVE_TLS_EXTENSIONS @@ -9374,10 +9379,6 @@ exit_ppc: ssl->nonblockarg = NULL; #endif -#ifdef OPENSSL_EXTRA - ssl->options.serverState = SERVER_CERT_COMPLETE; -#endif - FreeKeyExchange(ssl); return ret; @@ -9394,6 +9395,10 @@ static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, ret = ProcessPeerCerts(ssl, input, inOutIdx, size); +#ifdef OPENSSL_EXTRA + ssl->options.serverState = SERVER_CERT_COMPLETE; +#endif + WOLFSSL_LEAVE("DoCertificateVerify", ret); WOLFSSL_END(WC_FUNC_CERTIFICATE_DO); @@ -11938,7 +11943,7 @@ int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx) #endif #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData) { + if (ssl->earlyData != no_early_data) { } else #endif @@ -11963,7 +11968,7 @@ int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx) return BUFFER_ERROR; } #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData) { + if (ssl->earlyData != no_early_data) { if (ssl->earlyDataSz + dataSz > ssl->options.maxEarlyDataSz) { SendAlert(ssl, alert_fatal, unexpected_message); return WOLFSSL_FATAL_ERROR; @@ -12592,7 +12597,7 @@ int ProcessReply(WOLFSSL* ssl) if (ssl->options.side == WOLFSSL_SERVER_END && ssl->earlyData && ssl->options.handShakeState == HANDSHAKE_DONE) { - ssl->earlyData = 0; + ssl->earlyData = no_early_data; ssl->options.processReply = doProcessInit; return ZERO_RETURN; } @@ -14435,7 +14440,7 @@ int SendData(WOLFSSL* ssl, const void* data, int sz) #endif /* WOLFSSL_DTLS */ #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData) { + if (ssl->earlyData != no_early_data) { if (ssl->options.handShakeState == HANDSHAKE_DONE) { WOLFSSL_MSG("handshake complete, trying to send early data"); return BUILD_MSG_ERROR; @@ -14599,7 +14604,7 @@ int ReceiveData(WOLFSSL* ssl, byte* output, int sz, int peek) } #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData) { + if (ssl->earlyData != no_early_data) { } else #endif @@ -16833,31 +16838,26 @@ void PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo, #endif if (sigAlgo == ssl->suites->sigAlgo || (sigAlgo == rsa_pss_sa_algo && ssl->suites->sigAlgo == rsa_sa_algo)) { - if (hashAlgo == sha_mac) { - ssl->suites->sigAlgo = sigAlgo; - break; - } + switch (hashAlgo) { + case sha_mac: #ifndef NO_SHA256 - else if (hashAlgo == sha256_mac) { - ssl->suites->hashAlgo = sha256_mac; - ssl->suites->sigAlgo = sigAlgo; - break; - } + case sha256_mac: #endif #ifdef WOLFSSL_SHA384 - else if (hashAlgo == sha384_mac) { - ssl->suites->hashAlgo = sha384_mac; - ssl->suites->sigAlgo = sigAlgo; - break; - } + case sha384_mac: #endif #ifdef WOLFSSL_SHA512 - else if (hashAlgo == sha512_mac) { - ssl->suites->hashAlgo = sha512_mac; - ssl->suites->sigAlgo = sigAlgo; - break; - } + case sha512_mac: #endif + if (hashAlgo < ssl->suites->hashAlgo) + continue; + ssl->suites->hashAlgo = hashAlgo; + ssl->suites->sigAlgo = sigAlgo; + break; + default: + continue; + } + break; } else if (ssl->specs.sig_algo == 0) { ssl->suites->hashAlgo = ssl->specs.mac_algorithm; @@ -17383,6 +17383,7 @@ void PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo, int CheckVersion(WOLFSSL *ssl, ProtocolVersion pv) { #ifdef WOLFSSL_TLS13 + #ifndef WOLFSSL_TLS13_FINAL /* TODO: [TLS13] Remove this. * Translate the draft TLS v1.3 version to final version. */ @@ -17390,6 +17391,7 @@ void PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo, pv.major = SSLv3_MAJOR; pv.minor = TLSv1_3_MINOR; } + #endif #endif #ifdef OPENSSL_EXTRA @@ -17520,38 +17522,43 @@ void PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo, return ret; #ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(pv)) - return DoTls13ServerHello(ssl, input, inOutIdx, helloSz); + if (IsAtLeastTLSv1_3(pv)) { + byte type = server_hello; + return DoTls13ServerHello(ssl, input, inOutIdx, helloSz, &type); + } #endif /* random */ XMEMCPY(ssl->arrays->serverRandom, input + i, RAN_LEN); i += RAN_LEN; + if (!ssl->options.resuming) { #ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(ssl->ctx->method->version)) { - /* TLS v1.3 capable client not allowed to downgrade when connecting - * to TLS v1.3 capable server. - */ - if (XMEMCMP(input + i - (TLS13_DOWNGRADE_SZ + 1), - tls13Downgrade, TLS13_DOWNGRADE_SZ) == 0 && + if (IsAtLeastTLSv1_3(ssl->ctx->method->version)) { + /* TLS v1.3 capable client not allowed to downgrade when + * connecting to TLS v1.3 capable server unless cipher suite + * demands it. + */ + if (XMEMCMP(input + i - (TLS13_DOWNGRADE_SZ + 1), + tls13Downgrade, TLS13_DOWNGRADE_SZ) == 0 && (*(input + i - 1) == 0 || *(input + i - 1) == 1)) { - SendAlert(ssl, alert_fatal, illegal_parameter); - return VERSION_ERROR; + SendAlert(ssl, alert_fatal, illegal_parameter); + return VERSION_ERROR; + } } - } - else + else #endif - if (ssl->ctx->method->version.major == SSLv3_MAJOR && + if (ssl->ctx->method->version.major == SSLv3_MAJOR && ssl->ctx->method->version.minor == TLSv1_2_MINOR) { - /* TLS v1.2 capable client not allowed to downgrade when connecting - * to TLS v1.2 capable server. - */ - if (XMEMCMP(input + i - (TLS13_DOWNGRADE_SZ + 1), - tls13Downgrade, TLS13_DOWNGRADE_SZ) == 0 && + /* TLS v1.2 capable client not allowed to downgrade when + * connecting to TLS v1.2 capable server. + */ + if (XMEMCMP(input + i - (TLS13_DOWNGRADE_SZ + 1), + tls13Downgrade, TLS13_DOWNGRADE_SZ) == 0 && *(input + i - 1) == 0) { - SendAlert(ssl, alert_fatal, illegal_parameter); - return VERSION_ERROR; + SendAlert(ssl, alert_fatal, illegal_parameter); + return VERSION_ERROR; + } } } @@ -22963,7 +22970,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #if defined(HAVE_SUPPORTED_CURVES) && defined(HAVE_ECC) if (!TLSX_ValidateSupportedCurves(ssl, first, second)) { WOLFSSL_MSG("Don't have matching curves"); - return 0; + return 0; } #endif @@ -22976,7 +22983,8 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ssl->options.haveQSH = 1; /* matched TLS_QSH */ } else { - WOLFSSL_MSG("Version of SSL connection does not support TLS_QSH"); + WOLFSSL_MSG("Version of SSL connection does not support " + "TLS_QSH"); } return 0; } @@ -22988,10 +22996,15 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* Try to establish a key share. */ int ret = TLSX_KeyShare_Establish(ssl); if (ret == KEY_SHARE_ERROR) - ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST; + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE; else if (ret != 0) return 0; } + else if (first == TLS13_BYTE) { + /* Can't negotiate TLS 1.3 ciphersuites with lower protocol + * version. */ + return 0; + } #endif return 1; @@ -23267,6 +23280,76 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif /* OLD_HELLO_ALLOWED */ + int HandleTlsResumption(WOLFSSL* ssl, int bogusID, Suites* clSuites) + { + int ret = 0; + WOLFSSL_SESSION* session = GetSession(ssl, + ssl->arrays->masterSecret, 1); + + (void)bogusID; + + #ifdef HAVE_SESSION_TICKET + if (ssl->options.useTicket == 1) { + session = &ssl->session; + } else if (bogusID == 1 && ssl->options.rejectTicket == 0) { + WOLFSSL_MSG("Bogus session ID without session ticket"); + return BUFFER_ERROR; + } + #endif + + if (!session) { + WOLFSSL_MSG("Session lookup for resume failed"); + ssl->options.resuming = 0; + } + else if (session->haveEMS != ssl->options.haveEMS) { + /* RFC 7627, 5.3, server-side */ + /* if old sess didn't have EMS, but new does, full handshake */ + if (!session->haveEMS && ssl->options.haveEMS) { + WOLFSSL_MSG("Attempting to resume a session that didn't " + "use EMS with a new session with EMS. Do full " + "handshake."); + ssl->options.resuming = 0; + } + /* if old sess used EMS, but new doesn't, MUST abort */ + else if (session->haveEMS && !ssl->options.haveEMS) { + WOLFSSL_MSG("Trying to resume a session with EMS without " + "using EMS"); + return EXT_MASTER_SECRET_NEEDED_E; + } + #ifdef HAVE_EXT_CACHE + wolfSSL_SESSION_free(session); + #endif + } + else { + #ifdef HAVE_EXT_CACHE + wolfSSL_SESSION_free(session); + #endif + if (MatchSuite(ssl, clSuites) < 0) { + WOLFSSL_MSG("Unsupported cipher suite, ClientHello"); + return UNSUPPORTED_SUITE; + } + + ret = wc_RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, + RAN_LEN); + if (ret != 0) + return ret; + + #ifdef NO_OLD_TLS + ret = DeriveTlsKeys(ssl); + #else + #ifndef NO_TLS + if (ssl->options.tls) + ret = DeriveTlsKeys(ssl); + #endif + if (!ssl->options.tls) + ret = DeriveKeys(ssl); + #endif + ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; + } + + return ret; + } + /* handle processing of client_hello (1) */ int DoClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, @@ -23331,6 +23414,10 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif /* WOLFSSL_DTLS */ i += OPAQUE16_LEN; + /* Legacy protocol version cannot negotiate TLS 1.3 or higher. */ + if (pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_3_MINOR) + pv.minor = TLSv1_2_MINOR; + if ((!ssl->options.dtls && ssl->version.minor > pv.minor) || (ssl->options.dtls && ssl->version.minor != DTLS_MINOR && ssl->version.minor != DTLSv1_2_MINOR && pv.minor != DTLS_MINOR @@ -23643,10 +23730,11 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #ifdef HAVE_QSH QSH_Init(ssl); #endif - if (TLSX_SupportExtensions(ssl)) { + if (TLSX_SupportExtensions(ssl)) #else - if (IsAtLeastTLSv1_2(ssl)) { + if (IsAtLeastTLSv1_2(ssl)) #endif + { /* Process the hello extension. Skip unsupported. */ word16 totalExtSz; @@ -23742,66 +23830,10 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* ProcessOld uses same resume code */ if (ssl->options.resuming) { - WOLFSSL_SESSION* session = GetSession(ssl, - ssl->arrays->masterSecret, 1); - #ifdef HAVE_SESSION_TICKET - if (ssl->options.useTicket == 1) { - session = &ssl->session; - } else if (bogusID == 1 && ssl->options.rejectTicket == 0) { - WOLFSSL_MSG("Bogus session ID without session ticket"); - return BUFFER_ERROR; - } - #endif - - if (!session) { - WOLFSSL_MSG("Session lookup for resume failed"); - ssl->options.resuming = 0; - } - else if (session->haveEMS != ssl->options.haveEMS) { - /* RFC 7627, 5.3, server-side */ - /* if old sess didn't have EMS, but new does, full handshake */ - if (!session->haveEMS && ssl->options.haveEMS) { - WOLFSSL_MSG("Attempting to resume a session that didn't " - "use EMS with a new session with EMS. Do full " - "handshake."); - ssl->options.resuming = 0; - } - /* if old sess used EMS, but new doesn't, MUST abort */ - else if (session->haveEMS && !ssl->options.haveEMS) { - WOLFSSL_MSG("Trying to resume a session with EMS without " - "using EMS"); - return EXT_MASTER_SECRET_NEEDED_E; - } -#ifdef HAVE_EXT_CACHE - wolfSSL_SESSION_free(session); -#endif - } - else { -#ifdef HAVE_EXT_CACHE - wolfSSL_SESSION_free(session); -#endif - if (MatchSuite(ssl, &clSuites) < 0) { - WOLFSSL_MSG("Unsupported cipher suite, ClientHello"); - return UNSUPPORTED_SUITE; - } - - ret = wc_RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, - RAN_LEN); - if (ret != 0) - return ret; - - #ifdef NO_OLD_TLS - ret = DeriveTlsKeys(ssl); - #else - #ifndef NO_TLS - if (ssl->options.tls) - ret = DeriveTlsKeys(ssl); - #endif - if (!ssl->options.tls) - ret = DeriveKeys(ssl); - #endif - ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; - + ret = HandleTlsResumption(ssl, bogusID, &clSuites); + if (ret != 0) + return ret; + if (ssl->options.clientState == CLIENT_KEYEXCHANGE_COMPLETE) { WOLFSSL_LEAVE("DoClientHello", ret); WOLFSSL_END(WC_FUNC_CLIENT_HELLO_DO); @@ -24227,7 +24259,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word16 haveEMS; /* have extended master secret */ #ifdef WOLFSSL_TLS13 word32 ageAdd; /* Obfuscation of age */ - byte namedGroup; /* Named group used */ + word16 namedGroup; /* Named group used */ #ifndef WOLFSSL_TLS13_DRAFT_18 TicketNonce ticketNonce; /* Ticket nonce */ #endif @@ -24278,7 +24310,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #ifdef WOLFSSL_TLS13 /* Client adds to ticket age to obfuscate. */ ret = wc_RNG_GenerateBlock(ssl->rng, (byte*)&it.ageAdd, - sizeof(it.ageAdd)); + sizeof(it.ageAdd)); if (ret != 0) return BAD_TICKET_ENCRYPT; ssl->session.ticketAdd = it.ageAdd; @@ -24387,6 +24419,23 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* get master secret */ if (ret == WOLFSSL_TICKET_RET_OK || ret == WOLFSSL_TICKET_RET_CREATE) { + if (ssl->version.minor < it->pv.minor) { + WOLFSSL_MSG("Ticket has greater version"); + return VERSION_ERROR; + } + else if (ssl->version.minor > it->pv.minor) { + if (!ssl->options.downgrade) { + WOLFSSL_MSG("Ticket has lesser version"); + return VERSION_ERROR; + } + + WOLFSSL_MSG("Downgrading protocol due to ticket"); + + if (it->pv.minor < ssl->options.minDowngrade) + return VERSION_ERROR; + ssl->version.minor = it->pv.minor; + } + if (!IsAtLeastTLSv1_3(ssl->version)) { XMEMCPY(ssl->arrays->masterSecret, it->msecret, SECRET_LEN); /* Copy the haveExtendedMasterSecret property from the ticket to diff --git a/src/ssl.c b/src/ssl.c index d410f7cf8..9cb763a17 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -1599,11 +1599,11 @@ int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz) return BAD_FUNC_ARG; #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData && (ret = wolfSSL_negotiate(ssl)) < 0) { + if (ssl->earlyData != no_early_data && (ret = wolfSSL_negotiate(ssl)) < 0) { ssl->error = ret; return WOLFSSL_FATAL_ERROR; } - ssl->earlyData = 0; + ssl->earlyData = no_early_data; #endif #ifdef HAVE_WRITE_DUP @@ -8581,6 +8581,10 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, #endif /* get response */ while (ssl->options.serverState < neededState) { + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_connect_TLSv13(ssl); + #endif if ( (ssl->error = ProcessReply(ssl)) < 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; @@ -8635,13 +8639,14 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, /* get response */ while (ssl->options.serverState < neededState) { if ( (ssl->error = ProcessReply(ssl)) < 0) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; } /* if resumption failed, reset needed state */ - else if (neededState == SERVER_FINISHED_COMPLETE) + if (neededState == SERVER_FINISHED_COMPLETE) { if (!ssl->options.resuming) neededState = SERVER_HELLODONE_COMPLETE; + } } } #endif @@ -9759,9 +9764,13 @@ int AddSession(WOLFSSL* ssl) session->cipherSuite = ssl->options.cipherSuite; } #endif /* SESSION_CERTS || (WOLFSSL_TLS13 & HAVE_SESSION_TICKET) */ -#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) +#if defined(WOLFSSL_TLS13) if (error == 0) { session->namedGroup = ssl->session.namedGroup; + } +#endif +#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) + if (error == 0) { session->ticketSeen = ssl->session.ticketSeen; session->ticketAdd = ssl->session.ticketAdd; #ifndef WOLFSSL_TLS13_DRAFT_18 diff --git a/src/tls.c b/src/tls.c index ed36fe93b..05deb6b11 100755 --- a/src/tls.c +++ b/src/tls.c @@ -56,6 +56,11 @@ #endif #endif /* HAVE_QSH */ +#if !defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \ + !defined(WOLFSSL_NO_SERVER_GROUPS_EXT) +static int TLSX_KeyShare_IsSupported(int namedGroup); +static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions); +#endif #ifndef NO_TLS @@ -3092,7 +3097,8 @@ static word16 TLSX_PointFormat_Write(PointFormat* list, byte* output) return offset; } -#ifndef NO_WOLFSSL_SERVER +#if !defined(NO_WOLFSSL_SERVER) || (defined(WOLFSSL_TLS13) && \ + !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) static int TLSX_SupportedCurve_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest) @@ -3113,7 +3119,34 @@ static int TLSX_SupportedCurve_Parse(WOLFSSL* ssl, byte* input, word16 length, if (length != OPAQUE16_LEN + offset) return BUFFER_ERROR; - for (offset = OPAQUE16_LEN; offset < length; offset += OPAQUE16_LEN) { + offset = OPAQUE16_LEN; + if (offset == length) + return 0; + +#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_SERVER_GROUPS_EXT) + if (!isRequest) { + TLSX* extension; + SupportedCurve* curve; + + extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS); + if (extension != NULL) { + /* Replace client list with server list of supported groups. */ + curve = (SupportedCurve*)extension->data; + extension->data = NULL; + TLSX_SupportedCurve_FreeAll(curve, ssl->heap); + + ato16(input + offset, &name); + offset += OPAQUE16_LEN; + + ret = TLSX_SupportedCurve_New(&curve, name, ssl->heap); + if (ret != 0) + return ret; /* throw error */ + extension->data = (void*)curve; + } + } +#endif + + for (; offset < length; offset += OPAQUE16_LEN) { ato16(input + offset, &name); ret = TLSX_UseSupportedCurve(&ssl->extensions, name, ssl->heap); @@ -3124,6 +3157,89 @@ static int TLSX_SupportedCurve_Parse(WOLFSSL* ssl, byte* input, word16 length, return 0; } +#endif + +#if !defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \ + !defined(WOLFSSL_NO_SERVER_GROUPS_EXT) + +/* Checks the priority of the groups on the server and set the supported groups + * response if there is a group not advertised by the client that is preferred. + * + * ssl SSL/TLS object. + * returns 0 on success, otherwise an error. + */ +int TLSX_SupportedCurve_CheckPriority(WOLFSSL* ssl) +{ + int ret; + TLSX* extension; + TLSX* priority = NULL; + TLSX* ext = NULL; + word16 name; + SupportedCurve* curve; + + extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS); + /* May be doing PSK with no key exchange. */ + if (extension == NULL) + return 0; + + if ((ret = TLSX_PopulateSupportedGroups(ssl, &priority)) != WOLFSSL_SUCCESS) + return ret; + + ext = TLSX_Find(priority, TLSX_SUPPORTED_GROUPS); + curve = (SupportedCurve*)ext->data; + name = curve->name; + + curve = (SupportedCurve*)extension->data; + while (curve != NULL) { + if (curve->name == name) + break; + curve = curve->next; + } + + if (curve == NULL) { + /* Couldn't find the preferred group in client list. */ + extension->resp = 1; + + /* Send server list back and free client list. */ + curve = (SupportedCurve*)extension->data; + extension->data = ext->data; + ext->data = curve; + } + + TLSX_FreeAll(priority, ssl->heap); + + return 0; +} + +/* Return the preferred group. + * + * ssl SSL/TLS object. + * checkSupported Whether to check for the first supported group. + * returns BAD_FUNC_ARG if no group found, otherwise the group. + */ +int TLSX_SupportedCurve_Preferred(WOLFSSL* ssl, int checkSupported) +{ + TLSX* extension; + SupportedCurve* curve; + + extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS); + if (extension == NULL) + return BAD_FUNC_ARG; + + curve = (SupportedCurve*)extension->data; + while (curve != NULL) { + if (!checkSupported || TLSX_KeyShare_IsSupported(curve->name)) + return curve->name; + curve = curve->next; + } + + return BAD_FUNC_ARG; +} + +#endif + +#ifndef NO_WOLFSSL_SERVER + static int TLSX_PointFormat_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest) { @@ -3444,7 +3560,7 @@ int TLSX_UseSupportedCurve(TLSX** extensions, word16 name, void* heap) { TLSX* extension = NULL; SupportedCurve* curve = NULL; - int ret = 0; + int ret; if (extensions == NULL) return BAD_FUNC_ARG; @@ -3469,9 +3585,7 @@ int TLSX_UseSupportedCurve(TLSX** extensions, word16 name, void* heap) return ret; } - return (TLSX_Find(*extensions, TLSX_EC_POINT_FORMATS) == NULL) - ? TLSX_UsePointFormat(extensions, WOLFSSL_EC_PF_UNCOMPRESSED, heap) - : WOLFSSL_SUCCESS; + return WOLFSSL_SUCCESS; } int TLSX_UsePointFormat(TLSX** extensions, byte format, void* heap) @@ -3517,7 +3631,8 @@ int TLSX_UsePointFormat(TLSX** extensions, byte format, void* heap) #define EC_WRITE(a, b) 0 #endif -#ifndef NO_WOLFSSL_SERVER +#if !defined(NO_WOLFSSL_SERVER) || (defined(WOLFSSL_TLS13) && \ + !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) #define EC_PARSE TLSX_SupportedCurve_Parse #else #define EC_PARSE(a, b, c, d) 0 @@ -4525,8 +4640,12 @@ static word16 TLSX_SupportedVersions_GetSize(void* data, byte msgType) int cnt = 2; #ifndef NO_OLD_TLS - /* TLS v1 and TLS v1.1 */ - cnt += 2; + /* TLS v1.1 */ + cnt++; + #ifdef WOLFSSL_ALLOW_TLSV10 + /* TLS v1.0 */ + cnt++; + #endif #endif if (!ssl->options.downgrade) @@ -4563,8 +4682,12 @@ static word16 TLSX_SupportedVersions_Write(void* data, byte* output, cnt = 2; #ifndef NO_OLD_TLS - /* TLS v1 and TLS v1.1 */ - cnt += 2; + /* TLS v1.1 */ + cnt++; + #ifdef WOLFSSL_ALLOW_TLSV10 + /* TLS v1.0 */ + cnt++; + #endif #endif if (!ssl->options.downgrade) @@ -4572,6 +4695,7 @@ static word16 TLSX_SupportedVersions_Write(void* data, byte* output, *(output++) = (byte)(cnt * OPAQUE16_LEN); for (i = 0; i < cnt; i++) { +#ifndef WOLFSSL_TLS13_FINAL /* TODO: [TLS13] Remove code when TLS v1.3 becomes an RFC. */ if (pv.minor - i == TLSv1_3_MINOR) { /* The TLS draft major number. */ @@ -4580,6 +4704,7 @@ static word16 TLSX_SupportedVersions_Write(void* data, byte* output, *(output++) = TLS_DRAFT_MINOR; continue; } +#endif *(output++) = pv.major; *(output++) = pv.minor - i; @@ -4607,13 +4732,14 @@ static word16 TLSX_SupportedVersions_Write(void* data, byte* output, * msgType The type of the message this extension is being parsed from. * returns 0 on success, otherwise failure. */ -static int TLSX_SupportedVersions_Parse(WOLFSSL *ssl, byte* input, +static int TLSX_SupportedVersions_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType) { ProtocolVersion pv = ssl->ctx->method->version; int i; int len; byte major, minor; + int newMinor = 0; if (msgType == client_hello) { /* Must contain a length and at least one version. */ @@ -4633,11 +4759,13 @@ static int TLSX_SupportedVersions_Parse(WOLFSSL *ssl, byte* input, major = input[i]; minor = input[i + OPAQUE8_LEN]; +#ifndef WOLFSSL_TLS13_FINAL /* TODO: [TLS13] Remove code when TLS v1.3 becomes an RFC. */ if (major == TLS_DRAFT_MAJOR && minor == TLS_DRAFT_MINOR) { major = SSLv3_MAJOR; minor = TLSv1_3_MINOR; } +#endif if (major != pv.major) continue; @@ -4664,8 +4792,13 @@ static int TLSX_SupportedVersions_Parse(WOLFSSL *ssl, byte* input, #ifndef WOLFSSL_TLS13_DRAFT_18 TLSX_SetResponse(ssl, TLSX_SUPPORTED_VERSIONS); #endif + newMinor = minor; } - break; + else if (ssl->options.oldMinor < minor) + ssl->options.oldMinor = minor; + + if (newMinor != 0 && ssl->options.oldMinor != 0) + break; } } #ifndef WOLFSSL_TLS13_DRAFT_18 @@ -4677,11 +4810,13 @@ static int TLSX_SupportedVersions_Parse(WOLFSSL *ssl, byte* input, major = input[0]; minor = input[OPAQUE8_LEN]; + #ifndef WOLFSSL_TLS13_FINAL /* TODO: [TLS13] Remove code when TLS v1.3 becomes an RFC. */ if (major == TLS_DRAFT_MAJOR && minor == TLS_DRAFT_MINOR) { major = SSLv3_MAJOR; minor = TLSv1_3_MINOR; } + #endif if (major != pv.major) return VERSION_ERROR; @@ -5591,8 +5726,6 @@ static int TLSX_KeyShare_ProcessDh(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) #ifndef NO_DH int ret; const DhParams* params; - word16 i; - byte b; DhKey dhKey; switch (keyShareEntry->group) { @@ -5630,42 +5763,24 @@ static int TLSX_KeyShare_ProcessDh(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen); #endif - if (params->p_len != keyShareEntry->keLen) - return BUFFER_ERROR; - ssl->options.dhKeySz = params->p_len; - - /* TODO: [TLS13] move this check down into wolfcrypt. */ - /* Check that public DH key is not 0 or 1. */ - b = 0; - for (i = 0; i < params->p_len - 1; i++) - b |= keyShareEntry->ke[i]; - if (b == 0 && (keyShareEntry->ke[i] == 0x00 || - keyShareEntry->ke[i] == 0x01)) { - return PEER_KEY_ERROR; - } - /* Check that public DH key is not mod, mod + 1 or mod - 1. */ - b = 0; - for (i = 0; i < params->p_len - 1; i++) - b |= params->p[i] ^ keyShareEntry->ke[i]; - if (b == 0 && (params->p[i] == keyShareEntry->ke[i] || - params->p[i] - 1 == keyShareEntry->ke[i] || - params->p[i] + 1 == keyShareEntry->ke[i])) { - return PEER_KEY_ERROR; - } - ret = wc_InitDhKey_ex(&dhKey, ssl->heap, ssl->devId); if (ret != 0) return ret; /* Set key */ - ret = wc_DhSetKey(&dhKey, - (byte*)params->p, params->p_len, - (byte*)params->g, params->g_len); + ret = wc_DhSetKey(&dhKey, (byte*)params->p, params->p_len, (byte*)params->g, + params->g_len); if (ret != 0) { wc_FreeDhKey(&dhKey); return ret; } + ret = wc_DhCheckPubKey(&dhKey, keyShareEntry->ke, keyShareEntry->keLen); + if (ret != 0) { + wc_FreeDhKey(&dhKey); + return PEER_KEY_ERROR; + } + /* Derive secret from private key and peer's public key. */ ret = wc_DhAgree(&dhKey, ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz, @@ -5947,8 +6062,11 @@ static int TLSX_KeyShare_Find(WOLFSSL* ssl, word16 group) KeyShareEntry* list; extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); - if (extension == NULL) - return 0; + if (extension == NULL) { + extension = TLSX_Find(ssl->ctx->extensions, TLSX_KEY_SHARE); + if (extension == NULL) + return 0; + } list = (KeyShareEntry*)extension->data; while (list != NULL) { @@ -5973,8 +6091,13 @@ static int TLSX_SupportedGroups_Find(WOLFSSL* ssl, word16 name) TLSX* extension; SupportedCurve* curve = NULL; - if ((extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS)) == NULL) - return 0; + if ((extension = TLSX_Find(ssl->extensions, + TLSX_SUPPORTED_GROUPS)) == NULL) { + if ((extension = TLSX_Find(ssl->ctx->extensions, + TLSX_SUPPORTED_GROUPS)) == NULL) { + return 0; + } + } for (curve = (SupportedCurve*)extension->data; curve; curve = curve->next) { if (curve->name == name) @@ -6003,6 +6126,7 @@ static int TLSX_KeyShare_Parse(WOLFSSL* ssl, byte* input, word16 length, { int ret; KeyShareEntry *keyShareEntry; + word16 group; if (msgType == client_hello) { int offset = 0; @@ -6041,6 +6165,20 @@ static int TLSX_KeyShare_Parse(WOLFSSL* ssl, byte* input, word16 length, else if (msgType == server_hello) { int len; + if (length < OPAQUE16_LEN) + return BUFFER_ERROR; + + /* The data is the named group the server wants to use. */ + ato16(input, &group); + + /* Check the selected group was supported by ClientHello extensions. */ + if (!TLSX_SupportedGroups_Find(ssl, group)) + return BAD_KEY_SHARE_DATA; + + /* Check if the group was sent. */ + if (!TLSX_KeyShare_Find(ssl, group)) + return BAD_KEY_SHARE_DATA; + /* ServerHello contains one key share entry. */ len = TLSX_KeyShareEntry_Parse(ssl, input, length, &keyShareEntry); if (len != length) @@ -6052,10 +6190,10 @@ static int TLSX_KeyShare_Parse(WOLFSSL* ssl, byte* input, word16 length, /* Process the entry to calculate the secret. */ ret = TLSX_KeyShare_Process(ssl, keyShareEntry); + if (ret == 0) + ssl->session.namedGroup = ssl->namedGroup = group; } else if (msgType == hello_retry_request) { - word16 group; - if (length != OPAQUE16_LEN) return BUFFER_ERROR; @@ -6264,6 +6402,68 @@ static int TLSX_KeyShare_IsSupported(int namedGroup) return 1; } +/* Examines the application specified group ranking and returns the rank of the + * group. + * If no group ranking set then all groups are rank 0 (highest). + * + * ssl The SSL/TLS object. + * group The group to check ranking for. + * returns ranking from 0 to MAX_GROUP_COUNT-1 or -1 when group not in list. + */ +static int TLSX_KeyShare_GroupRank(WOLFSSL* ssl, int group) +{ + byte i; + + if (ssl->numGroups == 0) { +#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES) + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + ssl->group[ssl->numGroups++] = WOLFSSL_ECC_SECP256R1; + #endif + #endif +#endif + #ifndef HAVE_FIPS + #if defined(HAVE_CURVE25519) + ssl->group[ssl->numGroups++] = WOLFSSL_ECC_X25519; + #endif + #endif +#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES) + #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + ssl->group[ssl->numGroups++] = WOLFSSL_ECC_SECP384R1; + #endif + #endif + #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + ssl->group[ssl->numGroups++] = WOLFSSL_ECC_SECP521R1; + #endif + #endif +#endif + /* Add FFDHE supported groups. */ + #ifdef HAVE_FFDHE_2048 + ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_2048; + #endif + #ifdef HAVE_FFDHE_3072 + ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_3072; + #endif + #ifdef HAVE_FFDHE_4096 + ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_4096; + #endif + #ifdef HAVE_FFDHE_6144 + ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_6144; + #endif + #ifdef HAVE_FFDHE_8192 + ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_8192; + #endif + } + + for (i = 0; i < ssl->numGroups; i++) + if (ssl->group[i] == group) + return i; + + return -1; +} + /* Set a key share that is supported by the client into extensions. * * ssl The SSL/TLS object. @@ -6272,21 +6472,32 @@ static int TLSX_KeyShare_IsSupported(int namedGroup) */ static int TLSX_KeyShare_SetSupported(WOLFSSL* ssl) { - int ret; + int ret; #ifdef HAVE_SUPPORTED_CURVES - TLSX* extension; + TLSX* extension; SupportedCurve* curve = NULL; + SupportedCurve* preferredCurve = NULL; + int preferredRank = WOLFSSL_MAX_GROUP_COUNT; + int rank; - /* Use SupportedGroup's order. */ extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS); if (extension != NULL) curve = (SupportedCurve*)extension->data; + /* Use server's preference order. */ for (; curve != NULL; curve = curve->next) { - if (TLSX_KeyShare_IsSupported(curve->name) && - !TLSX_KeyShare_Find(ssl, curve->name)) { - break; + if (!TLSX_KeyShare_IsSupported(curve->name)) + continue; + + rank = TLSX_KeyShare_GroupRank(ssl, curve->name); + if (rank == -1) + continue; + if (rank < preferredRank) { + preferredCurve = curve; + preferredRank = rank; } } + curve = preferredCurve; + if (curve == NULL) return BAD_KEY_SHARE_DATA; @@ -6326,6 +6537,9 @@ int TLSX_KeyShare_Establish(WOLFSSL *ssl) KeyShareEntry* clientKSE = NULL; KeyShareEntry* serverKSE; KeyShareEntry* list = NULL; + KeyShareEntry* preferredKSE = NULL; + int preferredRank = WOLFSSL_MAX_GROUP_COUNT; + int rank; /* Find the KeyShare extension if it exists. */ extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); @@ -6335,8 +6549,7 @@ int TLSX_KeyShare_Establish(WOLFSSL *ssl) if (extension && extension->resp == 1) return 0; - /* TODO: [TLS13] Server's preference and sending back SupportedGroups */ - /* Use client's preference. */ + /* Use server's preference order. */ for (clientKSE = list; clientKSE != NULL; clientKSE = clientKSE->next) { if (clientKSE->ke == NULL) continue; @@ -6346,13 +6559,25 @@ int TLSX_KeyShare_Establish(WOLFSSL *ssl) return BAD_KEY_SHARE_DATA; #ifdef OPENSSL_EXTRA - /* Check if server supports group. */ - if (ssl->ctx->disabledCurves & (1 << clientKSE->group)) - continue; + if ((clientKSE->group & NAMED_DH_MASK) == 0) { + /* Check if server supports group. */ + if (ssl->ctx->disabledCurves & (1 << clientKSE->group)) + continue; + } #endif - if (TLSX_KeyShare_IsSupported(clientKSE->group)) - break; + if (!TLSX_KeyShare_IsSupported(clientKSE->group)) + continue; + + rank = TLSX_KeyShare_GroupRank(ssl, clientKSE->group); + if (rank == -1) + continue; + if (rank < preferredRank) { + preferredKSE = clientKSE; + preferredRank = rank; + } } + clientKSE = preferredKSE; + /* No supported group found - send HelloRetryRequest. */ if (clientKSE == NULL) { ret = TLSX_KeyShare_SetSupported(ssl); @@ -6458,30 +6683,6 @@ static void TLSX_PreSharedKey_FreeAll(PreSharedKey* list, void* heap) (void)heap; } -/* Delete the extension. - * - * ssl The SSL object with the extension. - */ -static void TLSX_PreSharedKey_Delete(WOLFSSL* ssl) -{ - TLSX* extension = ssl->extensions; - TLSX* prev = NULL; - - while (extension && extension->type != TLSX_PRE_SHARED_KEY) { - prev = extension; - extension = extension->next; - } - - if (extension != NULL) { - if (prev) - prev->next = extension->next; - else - ssl->extensions = extension->next; - TLSX_PreSharedKey_FreeAll((PreSharedKey*)extension->data, ssl->heap); - XFREE(extension, ssl->heap, XFREE(extension, heap, DYNAMIC_TYPE_TLSX)); - } -} - /* Get the size of the encoded pre shared key extension. * * list The linked list of pre-shared key extensions. @@ -6659,7 +6860,7 @@ static int TLSX_PreSharedKey_Parse(WOLFSSL* ssl, byte* input, word16 length, word16 len; word16 idx = 0; - TLSX_PreSharedKey_Delete(ssl); + TLSX_Remove(&ssl->extensions, TLSX_PRE_SHARED_KEY, ssl->heap); /* Length of identities and of binders. */ if (length - idx < OPAQUE16_LEN + OPAQUE16_LEN) @@ -6747,6 +6948,10 @@ static int TLSX_PreSharedKey_Parse(WOLFSSL* ssl, byte* input, word16 length, return BUFFER_E; ato16(input, &idx); + #ifdef WOLFSSL_EARLY_DATA + ssl->options.pskIdIndex = idx + 1; + #endif + /* Find the list of identities sent to server. */ extension = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); if (extension == NULL) @@ -6763,18 +6968,14 @@ static int TLSX_PreSharedKey_Parse(WOLFSSL* ssl, byte* input, word16 length, #ifdef HAVE_SESSION_TICKET if (list->resumption) { /* Check that the session's details are the same as the server's. */ - if (ssl->options.cipherSuite0 != ssl->session.cipherSuite0 || - ssl->options.cipherSuite != ssl->session.cipherSuite || - ssl->session.version.major != ssl->version.major || - ssl->session.version.minor != ssl->version.minor ) { + if (ssl->options.cipherSuite0 != ssl->session.cipherSuite0 || + ssl->options.cipherSuite != ssl->session.cipherSuite || + ssl->session.version.major != ssl->ctx->method->version.major || + ssl->session.version.minor != ssl->ctx->method->version.minor) { return PSK_KEY_ERROR; } } #endif - /* TODO: [TLS13] More checks of consistency. - * the "key_share", and "signature_algorithms" extensions are - * consistent with the indicated ke_modes and auth_modes values - */ return 0; } @@ -7236,6 +7437,12 @@ static int TLSX_EarlyData_Parse(WOLFSSL* ssl, byte* input, word16 length, if (length != 0) return BUFFER_E; + /* Ensure the index of PSK identity chosen by server is 0. + * Index is plus one to handle 'not set' value of 0. + */ + if (ssl->options.pskIdIndex != 1) + return PSK_KEY_ERROR; + return TLSX_EarlyData_Use(ssl, 1); } if (msgType == session_ticket) { @@ -7309,6 +7516,24 @@ TLSX* TLSX_Find(TLSX* list, TLSX_Type type) return extension; } +/** Remove an extension. */ +void TLSX_Remove(TLSX** list, TLSX_Type type, void* heap) +{ + TLSX* extension = *list; + TLSX** next = list; + + while (extension && extension->type != type) { + next = &extension->next; + extension = extension->next; + } + + if (extension) { + *next = extension->next; + extension->next = NULL; + TLSX_FreeAll(extension, heap); + } +} + /** Releases all extensions in the provided list. */ void TLSX_FreeAll(TLSX* list, void* heap) { @@ -7593,7 +7818,7 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore, break; case TLSX_SUPPORTED_GROUPS: - WOLFSSL_MSG("Elliptic Curves extension to write"); + WOLFSSL_MSG("Supported Groups extension to write"); offset += EC_WRITE((SupportedCurve*)extension->data, output + offset); break; @@ -7904,6 +8129,168 @@ static byte* TLSX_QSHKeyFind_Pub(QSHKey* qsh, word16* pubLen, word16 name) } #endif /* HAVE_QSH */ +static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) +{ + int ret; +#ifdef WOLFSSL_TLS13 + int i; + +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + if (ssl->options.resuming && ssl->session.namedGroup != 0) { + return TLSX_UseSupportedCurve(extensions, ssl->session.namedGroup, + ssl->heap); + } +#endif + + if (ssl->numGroups != 0) { + for (i = 0; i < ssl->numGroups; i++) { + ret = TLSX_UseSupportedCurve(extensions, ssl->group[i], ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + } + return WOLFSSL_SUCCESS; + } +#endif + +#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES) + #ifndef HAVE_FIPS + #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP160R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #ifdef HAVE_ECC_SECPR2 + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP160R2, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #ifdef HAVE_ECC_KOBLITZ + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP160K1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #endif + #if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP192R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #ifdef HAVE_ECC_KOBLITZ + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP192K1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #endif + #endif + #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP224R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #ifdef HAVE_ECC_KOBLITZ + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP224K1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #endif + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP256R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #endif +#endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */ + #ifndef HAVE_FIPS + #if defined(HAVE_CURVE25519) + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_X25519, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #endif /* HAVE_FIPS */ +#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES) + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifdef HAVE_ECC_KOBLITZ + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP256K1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #ifdef HAVE_ECC_BRAINPOOL + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #endif + #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP384R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #ifdef HAVE_ECC_BRAINPOOL + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #endif + #if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES) + #ifdef HAVE_ECC_BRAINPOOL + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #endif + #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_ECC_SECP521R1, ssl->heap); + if (ret != WOLFSSL_SUCCESS) return ret; + #endif + #endif +#endif + + #ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) { + /* Add FFDHE supported groups. */ + #ifdef HAVE_FFDHE_2048 + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_FFDHE_2048, ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + #endif + #ifdef HAVE_FFDHE_3072 + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_FFDHE_3072, ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + #endif + #ifdef HAVE_FFDHE_4096 + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_FFDHE_4096, ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + #endif + #ifdef HAVE_FFDHE_6144 + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_FFDHE_6144, ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + #endif + #ifdef HAVE_FFDHE_8192 + ret = TLSX_UseSupportedCurve(extensions, + WOLFSSL_FFDHE_8192, ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + #endif + } + #endif + + return WOLFSSL_SUCCESS; +} + int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) { int ret = 0; @@ -7996,100 +8383,33 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) #endif #if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES) - if (!ssl->options.userCurves && !ssl->ctx->userCurves && - TLSX_Find(ssl->ctx->extensions, TLSX_SUPPORTED_GROUPS) == NULL) { - - #ifndef HAVE_FIPS - #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES) - #ifndef NO_ECC_SECP - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_ECC_SECP160R1, ssl->heap); - if (ret != WOLFSSL_SUCCESS) return ret; - #endif - #ifdef HAVE_ECC_SECPR2 - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_ECC_SECP160R2, ssl->heap); - if (ret != WOLFSSL_SUCCESS) return ret; - #endif - #ifdef HAVE_ECC_KOBLITZ - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_ECC_SECP160K1, ssl->heap); - if (ret != WOLFSSL_SUCCESS) return ret; - #endif - #endif - #if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES) - #ifndef NO_ECC_SECP - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_ECC_SECP192R1, ssl->heap); - if (ret != WOLFSSL_SUCCESS) return ret; - #endif - #ifdef HAVE_ECC_KOBLITZ - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_ECC_SECP192K1, ssl->heap); - if (ret != WOLFSSL_SUCCESS) return ret; - #endif - #endif - #endif - #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES) - #ifndef NO_ECC_SECP - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_ECC_SECP224R1, ssl->heap); - if (ret != WOLFSSL_SUCCESS) return ret; - #endif - #ifdef HAVE_ECC_KOBLITZ - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_ECC_SECP224K1, ssl->heap); - if (ret != WOLFSSL_SUCCESS) return ret; - #endif - #endif - #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) - #ifndef NO_ECC_SECP - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_ECC_SECP256R1, ssl->heap); - if (ret != WOLFSSL_SUCCESS) return ret; - #endif - #if defined(HAVE_CURVE25519) - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_ECC_X25519, ssl->heap); - if (ret != WOLFSSL_SUCCESS) return ret; - #endif - #ifdef HAVE_ECC_KOBLITZ - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_ECC_SECP256K1, ssl->heap); - if (ret != WOLFSSL_SUCCESS) return ret; - #endif - #ifdef HAVE_ECC_BRAINPOOL - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap); - if (ret != WOLFSSL_SUCCESS) return ret; - #endif - #endif - #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) - #ifndef NO_ECC_SECP - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_ECC_SECP384R1, ssl->heap); - if (ret != WOLFSSL_SUCCESS) return ret; - #endif - #ifdef HAVE_ECC_BRAINPOOL - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap); - if (ret != WOLFSSL_SUCCESS) return ret; - #endif - #endif - #if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES) - #ifdef HAVE_ECC_BRAINPOOL - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap); - if (ret != WOLFSSL_SUCCESS) return ret; - #endif - #endif - #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) - #ifndef NO_ECC_SECP - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_ECC_SECP521R1, ssl->heap); - if (ret != WOLFSSL_SUCCESS) return ret; - #endif - #endif + if (!ssl->options.userCurves && !ssl->ctx->userCurves) { + if (TLSX_Find(ssl->ctx->extensions, + TLSX_SUPPORTED_GROUPS) == NULL) { + ret = TLSX_PopulateSupportedGroups(ssl, &ssl->extensions); + if (ret != WOLFSSL_SUCCESS) + return ret; + if (!IsAtLeastTLSv1_3(ssl->version) && + TLSX_Find(ssl->ctx->extensions, + TLSX_EC_POINT_FORMATS) == NULL && + TLSX_Find(ssl->extensions, + TLSX_EC_POINT_FORMATS) == NULL) { + ret = TLSX_UsePointFormat(&ssl->extensions, + WOLFSSL_EC_PF_UNCOMPRESSED, + ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + } + } + else if (!IsAtLeastTLSv1_3(ssl->version) && + TLSX_Find(ssl->ctx->extensions, + TLSX_EC_POINT_FORMATS) == NULL) { + ret = TLSX_UsePointFormat(&ssl->ctx->extensions, + WOLFSSL_EC_PF_UNCOMPRESSED, + ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + } } #endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */ } /* is not server */ @@ -8105,48 +8425,20 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) /* Add mandatory TLS v1.3 extension: supported version */ WOLFSSL_MSG("Adding supported versions extension"); if ((ret = TLSX_SetSupportedVersions(&ssl->extensions, ssl, - ssl->heap)) != 0) + ssl->heap)) != 0) { return ret; - -#ifdef HAVE_SUPPORTED_CURVES - if (!ssl->options.userCurves && !ssl->ctx->userCurves && - TLSX_Find(ssl->ctx->extensions, TLSX_SUPPORTED_GROUPS) - == NULL) { - /* Add FFDHE supported groups. */ - #ifdef HAVE_FFDHE_2048 - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_FFDHE_2048, ssl->heap); - if (ret != WOLFSSL_SUCCESS) - return ret; - #endif - #ifdef HAVE_FFDHE_3072 - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_FFDHE_3072, ssl->heap); - if (ret != WOLFSSL_SUCCESS) - return ret; - #endif - #ifdef HAVE_FFDHE_4096 - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_FFDHE_4096, ssl->heap); - if (ret != WOLFSSL_SUCCESS) - return ret; - #endif - #ifdef HAVE_FFDHE_6144 - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_FFDHE_6144, ssl->heap); - if (ret != WOLFSSL_SUCCESS) - return ret; - #endif - #ifdef HAVE_FFDHE_8192 - ret = TLSX_UseSupportedCurve(&ssl->extensions, - WOLFSSL_FFDHE_8192, ssl->heap); - if (ret != WOLFSSL_SUCCESS) - return ret; - #endif - ret = 0; } -#endif + #if !defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES) + if (TLSX_Find(ssl->ctx->extensions, TLSX_SUPPORTED_GROUPS) == NULL) { + /* Put in DH groups for TLS 1.3 only. */ + ret = TLSX_PopulateSupportedGroups(ssl, &ssl->extensions); + if (ret != WOLFSSL_SUCCESS) + return ret; + ret = 0; + } + #endif /* !HAVE_ECC && HAVE_SUPPORTED_CURVES */ + #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22) if (ssl->certHashSigAlgoSz > 0) { WOLFSSL_MSG("Adding signature algorithms cert extension"); @@ -8158,39 +8450,46 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) #endif /* !WOLFSSL_TLS13_DRAFT_18 && !WOLFSSL_TLS13_DRAFT_22 */ if (TLSX_Find(ssl->extensions, TLSX_KEY_SHARE) == NULL) { + word16 namedGroup; + + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + if (ssl->options.resuming && ssl->session.namedGroup != 0) + namedGroup = ssl->session.namedGroup; + else + #endif + { #if defined(HAVE_ECC) && (!defined(NO_ECC256) || \ defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP) - ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_SECP256R1, 0, NULL, - NULL); + namedGroup = WOLFSSL_ECC_SECP256R1; #elif defined(HAVE_ECC) && defined(HAVE_CURVE25519) - ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_X25519, 0, NULL, NULL); + namedGroup = WOLFSSL_ECC_X25519; #elif defined(HAVE_ECC) && (!defined(NO_ECC384) || \ defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP) - ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_SECP384R1, 0, NULL, - NULL); + namedGroup = WOLFSSL_ECC_SECP384R1; #elif defined(HAVE_ECC) && (!defined(NO_ECC521) || \ defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP) - ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_SECP521R1, 0, NULL, - NULL); + namedGroup = WOLFSSL_ECC_SECP521R1; #elif defined(HAVE_FFDHE_2048) - ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_2048, 0, NULL, NULL); + namedGroup = WOLFSSL_FFDHE_2048; #elif defined(HAVE_FFDHE_3072) - ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_3072, 0, NULL, NULL); + namedGroup = WOLFSSL_FFDHE_3072; #elif defined(HAVE_FFDHE_4096) - ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_4096, 0, NULL, NULL); + namedGroup = WOLFSSL_FFDHE_4096; #elif defined(HAVE_FFDHE_6144) - ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_6144, 0, NULL, NULL); + namedGroup = WOLFSSL_FFDHE_6144; #elif defined(HAVE_FFDHE_8192) - ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_8192, 0, NULL, NULL); + namedGroup = WOLFSSL_FFDHE_8192; #else - ret = KEY_SHARE_ERROR; + return KEY_SHARE_ERROR; #endif + } + ret = TLSX_KeyShare_Use(ssl, namedGroup, 0, NULL, NULL); if (ret != 0) return ret; } #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) - TLSX_PreSharedKey_Delete(ssl); + TLSX_Remove(&ssl->extensions, TLSX_PRE_SHARED_KEY, ssl->heap); #endif #if defined(HAVE_SESSION_TICKET) if (ssl->options.resuming && ssl->session.ticketLen > 0) { @@ -8701,6 +9000,9 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, #ifdef HAVE_EXTENDED_MASTER byte pendingEMS = 0; #endif +#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) + int pskDone = 0; +#endif if (!ssl || !input || (isRequest && !suites)) return BAD_FUNC_ARG; @@ -8709,6 +9011,11 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, word16 type; word16 size; +#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) + if (msgType == client_hello && pskDone) + return PSK_KEY_ERROR; +#endif + if (length - offset < HELLO_EXT_TYPE_SZ + OPAQUE16_LEN) return BUFFER_ERROR; @@ -8752,14 +9059,14 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, WOLFSSL_MSG("Truncated HMAC extension received"); #ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(ssl->version)) - return EXT_NOT_ALLOWED; + if (IsAtLeastTLSv1_3(ssl->version) && !ssl->options.downgrade) + break; #endif ret = THM_PARSE(ssl, input + offset, size, isRequest); break; case TLSX_SUPPORTED_GROUPS: - WOLFSSL_MSG("Elliptic Curves extension received"); + WOLFSSL_MSG("Supported Groups extension received"); #ifdef WOLFSSL_TLS13 if (IsAtLeastTLSv1_3(ssl->version) && @@ -8775,11 +9082,8 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, WOLFSSL_MSG("Point Formats extension received"); #ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(ssl->version) && - msgType != client_hello && - msgType != encrypted_extensions) { - return EXT_NOT_ALLOWED; - } + if (IsAtLeastTLSv1_3(ssl->version) && !ssl->options.downgrade) + break; #endif ret = PF_PARSE(ssl, input + offset, size, isRequest); break; @@ -8788,11 +9092,8 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, WOLFSSL_MSG("Certificate Status Request extension received"); #ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(ssl->version) && - msgType != client_hello && - msgType != encrypted_extensions) { - return EXT_NOT_ALLOWED; - } + if (IsAtLeastTLSv1_3(ssl->version) && !ssl->options.downgrade) + break; #endif ret = CSR_PARSE(ssl, input + offset, size, isRequest); break; @@ -8803,7 +9104,8 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, #ifdef WOLFSSL_TLS13 if (IsAtLeastTLSv1_3(ssl->version) && msgType != client_hello && - msgType != encrypted_extensions) { + msgType != certificate_request && + msgType != certificate) { return EXT_NOT_ALLOWED; } #endif @@ -8815,13 +9117,11 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, WOLFSSL_MSG("Extended Master Secret extension received"); #ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(ssl->version) && - msgType != client_hello) { - return EXT_NOT_ALLOWED; - } + if (IsAtLeastTLSv1_3(ssl->version) && !ssl->options.downgrade) + break; #endif #ifndef NO_WOLFSSL_SERVER - if (isRequest && !IsAtLeastTLSv1_3(ssl->version)) + if (isRequest) ssl->options.haveEMS = 1; #endif pendingEMS = 1; @@ -8831,6 +9131,10 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, case TLSX_RENEGOTIATION_INFO: WOLFSSL_MSG("Secure Renegotiation extension received"); +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && !ssl->options.downgrade) + break; +#endif ret = SCR_PARSE(ssl, input + offset, size, isRequest); break; @@ -8850,8 +9154,8 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, WOLFSSL_MSG("Quantum-Safe-Hybrid extension received"); #ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(ssl->version)) - return EXT_NOT_ALLOWED; + if (IsAtLeastTLSv1_3(ssl->version) && !ssl->options.downgrade) + break; #endif ret = QSH_PARSE(ssl, input + offset, size, isRequest); break; @@ -8889,13 +9193,17 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, case TLSX_SUPPORTED_VERSIONS: WOLFSSL_MSG("Supported Versions extension received"); + if (!IsAtLeastTLSv1_3(ssl->ctx->method->version)) + break; + if (IsAtLeastTLSv1_3(ssl->version) && -#ifdef WOLFSSL_TLS13_DRAFT_18 + #ifdef WOLFSSL_TLS13_DRAFT_18 msgType != client_hello -#else - msgType != client_hello && msgType != server_hello && + #else + msgType != client_hello && + msgType != server_hello && msgType != hello_retry_request -#endif + #endif ) { return EXT_NOT_ALLOWED; } @@ -8920,14 +9228,16 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, case TLSX_PRE_SHARED_KEY: WOLFSSL_MSG("Pre-Shared Key extension received"); - if (!IsAtLeastTLSv1_3(ssl->version)) + if (!IsAtLeastTLSv1_3(ssl->ctx->method->version)) break; if (IsAtLeastTLSv1_3(ssl->version) && - msgType != client_hello && msgType != server_hello) { + msgType != client_hello && + msgType != server_hello) { return EXT_NOT_ALLOWED; } ret = PSK_PARSE(ssl, input + offset, size, msgType); + pskDone = 1; break; case TLSX_PSK_KEY_EXCHANGE_MODES: @@ -8952,7 +9262,8 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, break; if (IsAtLeastTLSv1_3(ssl->version) && - msgType != client_hello && msgType != session_ticket && + msgType != client_hello && + msgType != session_ticket && msgType != encrypted_extensions) { return EXT_NOT_ALLOWED; } @@ -8995,11 +9306,12 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, case TLSX_KEY_SHARE: WOLFSSL_MSG("Key Share extension received"); - if (!IsAtLeastTLSv1_3(ssl->version)) + if (!IsAtLeastTLSv1_3(ssl->ctx->method->version)) break; - if (IsAtLeastTLSv1_3(ssl->version) && - msgType != client_hello && msgType != server_hello && + if (IsAtLeastTLSv1_3(ssl->ctx->method->version) && + msgType != client_hello && + msgType != server_hello && msgType != hello_retry_request) { return EXT_NOT_ALLOWED; } diff --git a/src/tls13.c b/src/tls13.c index 66dc9c264..009b6341e 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -21,20 +21,55 @@ /* - * WOLFSSL_TLS13_DRAFT_18 - * Conform with Draft 18 of the TLS v1.3 specification. - * WOLFSSL_EARLY_DATA - * Allow 0-RTT Handshake using Early Data extensions and handshake message - * WOLFSSL_POST_HANDSHAKE_AUTH - * Allow TLS v1.3 code to perform post-handshake authentication of the - * client. - * WOLFSSL_TLS13_TICKET_BEFORE_FINISHED - * Allow a NewSessionTicket message to be sent by server before Client's - * Finished message. - * See TLS v.13 specification, Section 4.6.1, Paragraph 4 (Note). + * BUILD_GCM + * Enables AES-GCM ciphersuites. + * HAVE_AESCCM + * Enables AES-CCM ciphersuites. + * HAVE_SESSION_TICKET + * Enables session tickets - required for TLS 1.3 resumption. + * NO_PSK + * Do not enable Pre-Shared Keys. * TLS13_SUPPORTS_EXPORTERS * Gaurd to compile out any code for exporter keys. * Feature not supported yet. + * WOLFSSL_ASYNC_CRYPT + * Enables the use of asynchornous cryptographic operations. + * This is available for ciphers and certificates. + * HAVE_CHACHA && HAVE_POLY1305 + * Enables use of CHACHA20-POLY1305 ciphersuites. + * WOLFSSL_DEBUG_TLS + * Writes out details of TLS 1.3 protocol including hanshake message buffers + * and key generation input and output. + * WOLFSSL_EARLY_DATA + * Allow 0-RTT Handshake using Early Data extensions and handshake message + * WOLFSSL_NO_SERVER_GROUPS_EXT + * Do not send the server's groups in an extension when the server's top + * preference is not in client's list. + * WOLFSSL_POST_HANDSHAKE_AUTH + * Allow TLS v1.3 code to perform post-handshake authentication of the + * client. + * WOLFSSL_SEND_HRR_COOKIE + * Send a cookie in hello_retry_request message to enable stateless tracking + * of ClientHello replies. + * WOLFSSL_TLS13 + * Enable TLS 1.3 protocol implementation. + * WOLFSSL_TLS13_DRAFT_18 + * Conform with Draft 18 of the TLS v1.3 specification. + * WOLFSSL_TLS13_DRAFT_22 + * Conform with Draft 22 of the TLS v1.3 specification. + * WOLFSSL_TLS13_DRAFT_23 + * Conform with Draft 23 of the TLS v1.3 specification. + * WOLFSSL_TLS13_MIDDLEBOX_COMPAT + * Enable middlebox compatability in the TLS 1.3 handshake. + * This includes sending ChangeCipherSpec before encrypted messages and + * including a session id. + * WOLFSSL_TLS13_SHA512 + * Allow generation of SHA-512 digests in handshake - no ciphersuite + * requires SHA-512 at this time. + * WOLFSSL_TLS13_TICKET_BEFORE_FINISHED + * Allow a NewSessionTicket message to be sent by server before Client's + * Finished message. + * See TLS v1.3 specification, Section 4.6.1, Paragraph 4 (Note). */ #ifdef HAVE_CONFIG_H @@ -134,7 +169,7 @@ static int Tls13_HKDF_Extract(byte* prk, const byte* salt, int saltLen, break; #endif - #ifdef WOLFSSL_TLS13_TLS13_SHA512 + #ifdef WOLFSSL_TLS13_SHA512 case sha512_mac: hash = WC_SHA512; len = WC_SHA512_DIGEST_SIZE; @@ -842,13 +877,13 @@ static int DeriveResumptionPSK(WOLFSSL* ssl, byte* nonce, byte nonceLen, #ifdef WOLFSSL_SHA384 case sha384_mac: - digestAlg = WC_SHA256; + digestAlg = WC_SHA384; break; #endif - #ifdef WOLFSSL_TLS13_TLS13_SHA512 + #ifdef WOLFSSL_TLS13_SHA512 case sha512_mac: - digestAlg = WC_SHA256; + digestAlg = WC_SHA512; break; #endif @@ -2122,6 +2157,28 @@ exit_buildmsg: return ret; } +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +/* Find the cipher suite in the suites set in the SSL. + * + * ssl SSL/TLS object. + * suite Cipher suite to look for. + * returns 1 when suite is found in SSL/TLS object's list and 0 otherwise. + */ +static int FindSuite(WOLFSSL* ssl, byte* suite) +{ + int i; + + for (i = 0; i < ssl->suites->suiteSz; i += 2) { + if (ssl->suites->suites[i+0] == suite[0] && + ssl->suites->suites[i+1] == suite[1]) { + return 1; + } + } + + return 0; +} +#endif + #ifndef NO_WOLFSSL_CLIENT #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) /* Setup pre-shared key based on the details in the extension data. @@ -2134,6 +2191,15 @@ exit_buildmsg: static int SetupPskKey(WOLFSSL* ssl, PreSharedKey* psk) { int ret; + byte suite[2]; + + if (ssl->options.noPskDheKe && ssl->arrays->preMasterSz != 0) + return PSK_KEY_ERROR; + + suite[0] = psk->cipherSuite0; + suite[1] = psk->cipherSuite; + if (!FindSuite(ssl, suite)) + return PSK_KEY_ERROR; ssl->options.cipherSuite0 = psk->cipherSuite0; ssl->options.cipherSuite = psk->cipherSuite; @@ -2144,7 +2210,7 @@ static int SetupPskKey(WOLFSSL* ssl, PreSharedKey* psk) if (psk->resumption) { #ifdef WOLFSSL_EARLY_DATA if (ssl->session.maxEarlyDataSz == 0) - ssl->earlyData = 0; + ssl->earlyData = no_early_data; #endif /* Resumption PSK is master secret. */ ssl->arrays->psk_keySz = ssl->specs.hash_size; @@ -2169,6 +2235,12 @@ static int SetupPskKey(WOLFSSL* ssl, PreSharedKey* psk) ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { return PSK_KEY_ERROR; } + /* TODO: Callback should be able to specify ciphersuite. */ + + if (psk->cipherSuite0 != TLS13_BYTE || + psk->cipherSuite != WOLFSSL_DEF_PSK_CIPHER) { + return PSK_KEY_ERROR; + } } #endif @@ -2250,7 +2322,7 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) return ret; #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData) { + if (ssl->earlyData != no_early_data) { if ((ret = SetupPskKey(ssl, (PreSharedKey*)ext->data)) != 0) return ret; @@ -2327,9 +2399,15 @@ int SendTls13ClientHello(WOLFSSL* ssl) #else if (!ssl->options.resuming) #endif - ssl->earlyData = 0; - if (ssl->earlyData && (ret = TLSX_EarlyData_Use(ssl, 0)) < 0) + ssl->earlyData = no_early_data; + if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE) + ssl->earlyData = no_early_data; + if (ssl->earlyData == no_early_data) + TLSX_Remove(&ssl->extensions, TLSX_EARLY_DATA, ssl->heap); + if (ssl->earlyData != no_early_data && + (ret = TLSX_EarlyData_Use(ssl, 0)) < 0) { return ret; + } #endif #ifdef HAVE_QSH if (QSH_Init(ssl) != 0) @@ -2352,9 +2430,10 @@ int SendTls13ClientHello(WOLFSSL* ssl) /* Put the record and handshake headers on. */ AddTls13Headers(output, length, client_hello, ssl); - /* Protocol version. */ + /* Protocol version - negotiation now in extension: supported_versions. */ output[idx++] = SSLv3_MAJOR; output[idx++] = TLSv1_2_MINOR; + /* Keep for downgrade. */ ssl->chVersion = ssl->version; /* Client Random */ @@ -2375,6 +2454,7 @@ int SendTls13ClientHello(WOLFSSL* ssl) output[idx++] = 0; #else if (ssl->session.sessionIDSz > 0) { + /* Session resumption for old versions of protocol. */ output[idx++] = ID_LEN; XMEMCPY(output + idx, ssl->session.sessionID, ssl->session.sessionIDSz); idx += ID_LEN; @@ -2385,6 +2465,7 @@ int SendTls13ClientHello(WOLFSSL* ssl) XMEMCPY(output + idx, ssl->arrays->clientRandom, ID_LEN); idx += ID_LEN; #else + /* TLS v1.3 does not use session id - 0 length. */ output[idx++] = 0; #endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */ } @@ -2606,7 +2687,7 @@ static int DoTls13HelloRetryRequest(WOLFSSL* ssl, const byte* input, *inOutIdx = i + totalExtSz; ssl->options.tls1_3 = 1; - ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST; + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE; WOLFSSL_LEAVE("DoTls13HelloRetryRequest", ret); @@ -2639,7 +2720,7 @@ static byte helloRetryRequestRandom[] = { * returns 0 on success and otherwise failure. */ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, - word32 helloSz) + word32 helloSz, byte* extMsgType) { ProtocolVersion pv; word32 i = *inOutIdx; @@ -2655,7 +2736,6 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, TLSX* ext; PreSharedKey* psk = NULL; #endif - byte extMsgType = server_hello; WOLFSSL_START(WC_FUNC_SERVER_HELLO_DO); WOLFSSL_ENTER("DoTls13ServerHello"); @@ -2705,7 +2785,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, return BUFFER_ERROR; if (XMEMCMP(input + i, helloRetryRequestRandom, RAN_LEN) == 0) - extMsgType = hello_retry_request; + *extMsgType = hello_retry_request; #endif /* Server random - keep for debugging. */ @@ -2766,7 +2846,8 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ssl->version.minor = TLSv1_2_MINOR; #endif /* Parse and handle extensions. */ - ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz, extMsgType, NULL); + ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz, *extMsgType, + NULL); if (ret != 0) return ret; @@ -2837,7 +2918,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) #ifndef WOLFSSL_TLS13_DRAFT_18 - if (extMsgType == server_hello) + if (*extMsgType == server_hello) #endif { ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); @@ -2858,11 +2939,13 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #ifdef WOLFSSL_TLS13_DRAFT_18 ssl->keys.encryptionOn = 1; #else - if (extMsgType == server_hello) + if (*extMsgType == server_hello) { ssl->keys.encryptionOn = 1; + ssl->options.serverState = SERVER_HELLO_COMPLETE; + } else { ssl->options.tls1_3 = 1; - ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST; + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE; ret = RestartHandshakeHash(ssl); } @@ -2923,13 +3006,23 @@ static int DoTls13EncryptedExtensions(WOLFSSL* ssl, const byte* input, *inOutIdx += ssl->keys.padSz; #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData) { + if (ssl->earlyData != no_early_data) { TLSX* ext = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA); if (ext == NULL || !ext->val) - ssl->earlyData = 0; + ssl->earlyData = no_early_data; } #endif +#ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData == no_early_data) { + ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY); + if (ret != 0) + return ret; + } +#endif + + ssl->options.serverState = SERVER_ENCRYPTED_EXTENSIONS_COMPLETE; + WOLFSSL_LEAVE("DoTls13EncryptedExtensions", ret); WOLFSSL_END(WC_FUNC_ENCRYPTED_EXTENSIONS_DO); @@ -3090,6 +3183,31 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, #ifndef NO_WOLFSSL_SERVER #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +/* Refine list of supported cipher suites to those common to server and client. + * + * ssl SSL/TLS object. + * peerSuites The peer's advertised list of supported cipher suites. + */ +static void RefineSuites(WOLFSSL* ssl, Suites* peerSuites) +{ + byte suites[WOLFSSL_MAX_SUITE_SZ]; + int suiteSz = 0; + int i, j; + + for (i = 0; i < ssl->suites->suiteSz; i += 2) { + for (j = 0; j < peerSuites->suiteSz; j += 2) { + if (ssl->suites->suites[i+0] == peerSuites->suites[j+0] && + ssl->suites->suites[i+1] == peerSuites->suites[j+1]) { + suites[suiteSz++] = peerSuites->suites[j+0]; + suites[suiteSz++] = peerSuites->suites[j+1]; + } + } + } + + ssl->suites->suiteSz = suiteSz; + XMEMCPY(ssl->suites->suites, &suites, sizeof(suites)); +} + /* Handle any Pre-Shared Key (PSK) extension. * Must do this in ClientHello as it requires a hash of the truncated message. * Don't know size of binders until Pre-Shared Key extension has been parsed. @@ -3111,6 +3229,7 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, byte binder[WC_MAX_DIGEST_SIZE]; word32 binderLen; word16 modes; + byte suite[2]; #ifdef WOLFSSL_EARLY_DATA int pskCnt = 0; TLSX* extEarlyData; @@ -3121,7 +3240,7 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); if (ext == NULL) { #ifdef WOLFSSL_EARLY_DATA - ssl->earlyData = 0; + ssl->earlyData = no_early_data; #endif return 0; } @@ -3179,6 +3298,16 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, break; } + /* Check whether resumption is possible based on suites in SSL and + * ciphersuite in ticket. + */ + suite[0] = ssl->session.cipherSuite0; + suite[1] = ssl->session.cipherSuite; + if (!FindSuite(ssl, suite)) { + current = current->next; + continue; + } + #ifdef WOLFSSL_EARLY_DATA ssl->options.maxEarlyDataSz = ssl->session.maxEarlyDataSz; #endif @@ -3191,15 +3320,15 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, /* Resumption PSK is resumption master secret. */ ssl->arrays->psk_keySz = ssl->specs.hash_size; -#ifdef WOLFSSL_TLS13_DRAFT_18 + #ifdef WOLFSSL_TLS13_DRAFT_18 XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret, ssl->arrays->psk_keySz); -#else + #else if ((ret = DeriveResumptionPSK(ssl, ssl->session.ticketNonce.data, ssl->session.ticketNonce.len, ssl->arrays->psk_key)) != 0) { return ret; } -#endif + #endif /* Derive the early secret using the PSK. */ ret = DeriveEarlySecret(ssl); @@ -3219,15 +3348,23 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, MAX_PSK_KEY_LEN)) != 0) { if (ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) return PSK_KEY_ERROR; + /* TODO: Callback should be able to specify ciphersuite. */ + suite[0] = TLS13_BYTE; + suite[1] = WOLFSSL_DEF_PSK_CIPHER; + if (!FindSuite(ssl, suite)) { + current = current->next; + continue; + } + + /* Default to ciphersuite if cb doesn't specify. */ ssl->options.resuming = 0; /* PSK age is always zero. */ if (current->ticketAge != ssl->session.ticketAdd) return PSK_KEY_ERROR; - /* TODO: Callback should be able to change ciphersuite. */ - /* Default to ciphersuite if cb doesn't specify. */ + /* Check whether PSK ciphersuite is in SSL. */ ssl->options.cipherSuite0 = TLS13_BYTE; ssl->options.cipherSuite = WOLFSSL_DEF_PSK_CIPHER; ret = SetCipherSpecs(ssl); @@ -3274,8 +3411,17 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, break; } - if (current == NULL) + if (current == NULL) { +#ifdef WOLFSSL_PSK_ID_PROTECTION + #ifndef NO_CERTS + if (ssl->buffers.certChainCnt != 0) + return 0; + #endif + return BAD_BINDER; +#else return 0; +#endif + } /* Hash the rest of the ClientHello. */ ret = HashInputRaw(ssl, input + helloSz - bindersLen, bindersLen); @@ -3285,7 +3431,7 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, #ifdef WOLFSSL_EARLY_DATA extEarlyData = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA); if (extEarlyData != NULL) { - if (ssl->earlyData && current == ext->data) { + if (ssl->earlyData != no_early_data && current == ext->data) { extEarlyData->resp = 1; /* Derive early data decryption key. */ @@ -3295,7 +3441,7 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) return ret; - ssl->earlyData = 2; + ssl->earlyData = process_early_data; } else extEarlyData->resp = 0; @@ -3318,7 +3464,7 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, /* Pick key share and Generate a new key if not present. */ ret = TLSX_KeyShare_Establish(ssl); if (ret == KEY_SHARE_ERROR) { - ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST; + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE; ret = 0; } else if (ret < 0) @@ -3552,7 +3698,6 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie) } #endif -/* handle processing of TLS 1.3 client_hello (1) */ /* Handle a ClientHello handshake message. * If the protocol version in the message is not TLS v1.3 or higher, use * DoClientHello() @@ -3575,9 +3720,10 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, Suites clSuites; word32 i = *inOutIdx; word32 begin = i; - word16 totalExtSz; + word16 totalExtSz = 0; int usingPSK = 0; byte sessIdSz; + int bogusID = 0; WOLFSSL_START(WC_FUNC_CLIENT_HELLO_DO); WOLFSSL_ENTER("DoTls13ClientHello"); @@ -3595,10 +3741,20 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, XMEMCPY(&pv, input + i, OPAQUE16_LEN); ssl->chVersion = pv; /* store */ i += OPAQUE16_LEN; + /* Legacy protocol version cannot negotiate TLS 1.3 or higher. */ + if (pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_3_MINOR) + pv.minor = TLSv1_2_MINOR; if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor < TLSv1_3_MINOR) return DoClientHello(ssl, input, inOutIdx, helloSz); +#ifdef HAVE_SESSION_TICKET + if (ssl->options.downgrade) { + if ((ret = HashInput(ssl, input + begin, helloSz)) != 0) + return ret; + } +#endif + /* Client random */ XMEMCPY(ssl->arrays->clientRandom, input + i, RAN_LEN); i += RAN_LEN; @@ -3611,7 +3767,7 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #ifdef WOLFSSL_TLS13_DRAFT_18 /* Session id - empty in TLS v1.3 */ sessIdSz = input[i++]; - if (sessIdSz > 0) { + if (sessIdSz > 0 && !ssl->options.downgrade) { WOLFSSL_MSG("Client sent session id - not supported"); return BUFFER_ERROR; } @@ -3619,11 +3775,15 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, sessIdSz = input[i++]; if (sessIdSz != ID_LEN && sessIdSz != 0) return INVALID_PARAMETER; +#endif ssl->session.sessionIDSz = sessIdSz; if (sessIdSz == ID_LEN) { XMEMCPY(ssl->session.sessionID, input + i, sessIdSz); i += ID_LEN; } +#ifdef HAVE_SESSION_TICKET + if (sessIdSz > 0 && sessIdSz < ID_LEN) + bogusID = 1; #endif /* Cipher suites */ @@ -3654,37 +3814,38 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, return INVALID_PARAMETER; } - /* TLS v1.3 ClientHello messages will have extensions. */ - if ((i - begin) >= helloSz) { - WOLFSSL_MSG("ClientHello must have extensions in TLS v1.3"); - return BUFFER_ERROR; - } - if ((i - begin) + OPAQUE16_LEN > helloSz) - return BUFFER_ERROR; - ato16(&input[i], &totalExtSz); - i += OPAQUE16_LEN; - if ((i - begin) + totalExtSz > helloSz) - return BUFFER_ERROR; + if ((i - begin) < helloSz) { + if ((i - begin) + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + if ((i - begin) + totalExtSz > helloSz) + return BUFFER_ERROR; -#ifdef HAVE_QSH - QSH_Init(ssl); -#endif + #ifdef HAVE_QSH + QSH_Init(ssl); + #endif - /* Auto populate extensions supported unless user defined. */ - if ((ret = TLSX_PopulateExtensions(ssl, 1)) != 0) - return ret; + /* Auto populate extensions supported unless user defined. */ + if ((ret = TLSX_PopulateExtensions(ssl, 1)) != 0) + return ret; - /* Parse extensions */ - if ((ret = TLSX_Parse(ssl, (byte*)input + i, totalExtSz, client_hello, + /* Parse extensions */ + if ((ret = TLSX_Parse(ssl, (byte*)input + i, totalExtSz, client_hello, &clSuites))) { - return ret; + return ret; + } + +#if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_HAPROXY) + if ((ret = SNI_Callback(ssl)) != 0) + return ret; + ssl->options.side = WOLFSSL_SERVER_END; +#endif /* OPENSSL_ALL || HAVE_STUNNEL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ } -#if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) - if ((ret = SNI_Callback(ssl)) != 0) - return ret; - ssl->options.side = WOLFSSL_SERVER_END; -#endif /* OPENSSL_ALL || HAVE_STUNNEL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ + i += totalExtSz; + *inOutIdx = i; if (TLSX_Find(ssl->extensions, TLSX_SUPPORTED_VERSIONS) == NULL) { if (!ssl->options.downgrade) { @@ -3698,39 +3859,90 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ssl->version.minor = pv.minor; } -#if !defined(WOLFSSL_TLS13_DRAFT_18) && defined(WOLFSSL_SEND_HRR_COOKIE) - if (ssl->options.sendCookie && - ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) { - TLSX* ext; - - if ((ext = TLSX_Find(ssl->extensions, TLSX_COOKIE)) == NULL) - return HRR_COOKIE_ERROR; - /* Ensure the cookie came from client and isn't the one in the response - * - HelloRetryRequest. - */ - if (ext->resp == 1) - return HRR_COOKIE_ERROR; - ret = RestartHandshakeHashWithCookie(ssl, (Cookie*)ext->data); - if (ret != 0) - return ret; - } -#endif - ssl->options.sendVerify = SEND_CERT; -#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) - /* Process the Pre-Shared Key extension if present. */ - ret = DoPreSharedKeys(ssl, input + begin, helloSz, &usingPSK); - if (ret != 0) - return ret; + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + ssl->options.haveSessionId = 1; + + if (IsAtLeastTLSv1_3(ssl->version)) { +#if !defined(WOLFSSL_TLS13_DRAFT_18) && defined(WOLFSSL_SEND_HRR_COOKIE) + if (ssl->options.sendCookie && + ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE) { + TLSX* ext; + + if ((ext = TLSX_Find(ssl->extensions, TLSX_COOKIE)) == NULL) + return HRR_COOKIE_ERROR; + /* Ensure the cookie came from client and isn't the one in the + * response - HelloRetryRequest. + */ + if (ext->resp == 1) + return HRR_COOKIE_ERROR; + ret = RestartHandshakeHashWithCookie(ssl, (Cookie*)ext->data); + if (ret != 0) + return ret; + } #endif +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + if (ssl->options.downgrade) { + if ((ret = InitHandshakeHashes(ssl)) != 0) + return ret; + } + + /* Refine list for PSK processing. */ + RefineSuites(ssl, &clSuites); + + /* Process the Pre-Shared Key extension if present. */ + ret = DoPreSharedKeys(ssl, input + begin, helloSz, &usingPSK); + if (ret != 0) + return ret; +#endif + } + else if (ssl->options.resuming) { + ret = HandleTlsResumption(ssl, bogusID, &clSuites); + if (ret != 0) + return ret; + /* Check wheter resuming has been chosen */ + if (ssl->options.clientState == CLIENT_KEYEXCHANGE_COMPLETE) { + WOLFSSL_LEAVE("DoTls13ClientHello", ret); + WOLFSSL_END(WC_FUNC_CLIENT_HELLO_DO); + + return ret; + } + } + if (!usingPSK) { if ((ret = MatchSuite(ssl, &clSuites)) < 0) { WOLFSSL_MSG("Unsupported cipher suite, ClientHello"); return ret; } + /* Check that the negotiated ciphersuite matches protocol version. */ + if (IsAtLeastTLSv1_3(ssl->version)) { + if (ssl->options.cipherSuite0 != TLS13_BYTE) { + TLSX* ext; + + if (!ssl->options.downgrade) { + WOLFSSL_MSG("Negotiated ciphersuite from lesser version " + "than TLS v1.3"); + return VERSION_ERROR; + } + + WOLFSSL_MSG("Downgrading protocol due to cipher suite"); + + if (pv.minor < ssl->options.minDowngrade) + return VERSION_ERROR; + ssl->version.minor = ssl->options.oldMinor; + + /* Downgrade from TLS v1.3 */ + ssl->options.tls1_3 = 0; + ext = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_VERSIONS); + if (ext != NULL) + ext->resp = 0; + } + } + /* VerifyServerSuite handles when version is less than 1.3 */ + #ifdef HAVE_SESSION_TICKET if (ssl->options.resuming) { ssl->options.resuming = 0; @@ -3741,20 +3953,21 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } #endif - if ((ret = HashInput(ssl, input + begin, helloSz)) != 0) - return ret; +#ifdef HAVE_SESSION_TICKET + if (IsAtLeastTLSv1_3(ssl->version) || !ssl->options.downgrade) +#endif + { + if ((ret = HashInput(ssl, input + begin, helloSz)) != 0) + return ret; + } - /* Derive early secret for handshake secret. */ - if ((ret = DeriveEarlySecret(ssl)) != 0) - return ret; + if (IsAtLeastTLSv1_3(ssl->version)) { + /* Derive early secret for handshake secret. */ + if ((ret = DeriveEarlySecret(ssl)) != 0) + return ret; + } } - i += totalExtSz; - *inOutIdx = i; - - ssl->options.clientState = CLIENT_HELLO_COMPLETE; - ssl->options.haveSessionId = 1; - WOLFSSL_LEAVE("DoTls13ClientHello", ret); WOLFSSL_END(WC_FUNC_CLIENT_HELLO_DO); @@ -3998,6 +4211,11 @@ static int SendTls13EncryptedExtensions(WOLFSSL* ssl) ssl->keys.encryptionOn = 1; +#ifndef WOLFSSL_NO_SERVER_GROUPS_EXT + if ((ret = TLSX_SupportedCurve_CheckPriority(ssl)) != 0) + return ret; +#endif + /* Derive the handshake secret now that we are at first message to be * encrypted under the keys. */ @@ -4011,7 +4229,7 @@ static int SendTls13EncryptedExtensions(WOLFSSL* ssl) #ifdef WOLFSSL_EARLY_DATA if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) return ret; - if (ssl->earlyData != 2) { + if (ssl->earlyData != process_early_data) { if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) return ret; } @@ -5192,16 +5410,21 @@ static int DoTls13Certificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, WOLFSSL_ENTER("DoTls13Certificate"); ret = ProcessPeerCerts(ssl, input, inOutIdx, totalSz); - -#if !defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) - if (ret == 0 && ssl->options.side == WOLFSSL_SERVER_END && - ssl->options.handShakeState == HANDSHAKE_DONE) { - /* reset handshake states */ - ssl->options.serverState = SERVER_FINISHED_COMPLETE; - ssl->options.acceptState = TICKET_SENT; - ssl->options.handShakeState = SERVER_FINISHED_COMPLETE; - } + if (ret == 0) { +#if !defined(NO_WOLFSSL_CLIENT) + if (ssl->options.side == WOLFSSL_CLIENT_END) + ssl->options.serverState = SERVER_CERT_COMPLETE; #endif +#if !defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->options.handShakeState == HANDSHAKE_DONE) { + /* reset handshake states */ + ssl->options.serverState = SERVER_FINISHED_COMPLETE; + ssl->options.acceptState = TICKET_SENT; + ssl->options.handShakeState = SERVER_FINISHED_COMPLETE; + } +#endif + } WOLFSSL_LEAVE("DoTls13Certificate", ret); WOLFSSL_END(WC_FUNC_CERTIFICATE_DO); @@ -5511,7 +5734,10 @@ exit_dcv: return ret; } + else #endif /* WOLFSSL_ASYNC_CRYPT */ + if (ret != 0) + SendAlert(ssl, alert_fatal, decrypt_error); /* Final cleanup */ FreeDcv13Args(ssl, args); @@ -5581,6 +5807,7 @@ static int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* Actually check verify data. */ if (XMEMCMP(input + *inOutIdx, mac, size) != 0){ WOLFSSL_MSG("Verify finished error on hashes"); + SendAlert(ssl, alert_fatal, decrypt_error); return VERIFY_FINISHED_ERROR; } } @@ -5591,7 +5818,7 @@ static int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (ssl->options.side == WOLFSSL_SERVER_END && !ssl->options.handShakeDone) { #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData) { + if (ssl->earlyData != no_early_data) { if ((ret = DeriveTls13Keys(ssl, no_key, DECRYPT_SIDE_ONLY, 1)) != 0) return ret; } @@ -5709,7 +5936,7 @@ static int SendTls13Finished(WOLFSSL* ssl) return ret; } if ((ret = DeriveTls13Keys(ssl, traffic_key, DECRYPT_SIDE_ONLY, - !ssl->earlyData)) != 0) { + ssl->earlyData == no_early_data)) != 0) { return ret; } #else @@ -5725,7 +5952,7 @@ static int SendTls13Finished(WOLFSSL* ssl) if (ssl->options.side == WOLFSSL_CLIENT_END && !ssl->options.handShakeDone) { #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData) { + if (ssl->earlyData != no_early_data) { if ((ret = DeriveTls13Keys(ssl, no_key, ENCRYPT_AND_DECRYPT_SIDE, 1)) != 0) { return ret; @@ -5741,18 +5968,16 @@ static int SendTls13Finished(WOLFSSL* ssl) #endif } - if (ssl->options.resuming) { - if (ssl->options.side == WOLFSSL_CLIENT_END) { - ssl->options.handShakeState = HANDSHAKE_DONE; - ssl->options.handShakeDone = 1; - } - } #ifndef NO_WOLFSSL_CLIENT if (ssl->options.side == WOLFSSL_CLIENT_END) { - if (!ssl->options.resuming) { - ssl->options.handShakeState = HANDSHAKE_DONE; - ssl->options.handShakeDone = 1; - } + ssl->options.clientState = CLIENT_FINISHED_COMPLETE; + ssl->options.handShakeState = HANDSHAKE_DONE; + ssl->options.handShakeDone = 1; + } +#endif +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + ssl->options.serverState = SERVER_FINISHED_COMPLETE; } #endif @@ -5974,12 +6199,20 @@ static int DoTls13EndOfEarlyData(WOLFSSL* ssl, const byte* input, if ((*inOutIdx - begin) != size) return BUFFER_ERROR; + if (ssl->earlyData == no_early_data) { + WOLFSSL_MSG("EndOfEarlyData recieved unexpectedly"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + ssl->earlyData = done_early_data; + /* Always encrypted. */ *inOutIdx += ssl->keys.padSz; ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY); - WOLFSSL_LEAVE("SendTls13EndOfEarlyData", ret); + WOLFSSL_LEAVE("DoTls13EndOfEarlyData", ret); WOLFSSL_END(WC_FUNC_END_OF_EARLY_DATA_DO); return ret; @@ -6076,6 +6309,7 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, if (nonceLength > 0) XMEMCPY(&ssl->session.ticketNonce.data, nonce, nonceLength); #endif + ssl->session.namedGroup = ssl->namedGroup; if ((*inOutIdx - begin) + EXTS_SZ > size) return BUFFER_ERROR; @@ -6168,7 +6402,7 @@ static int ExpectedResumptionSecret(WOLFSSL* ssl) return ret; header[FINISHED_MSG_SIZE_OFFSET] = finishedSz; #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData) { + if (ssl->earlyData != no_early_data) { static byte endOfEarlyData[] = { 0x05, 0x00, 0x00, 0x00 }; ret = HashInputRaw(ssl, endOfEarlyData, sizeof(endOfEarlyData)); if (ret != 0) @@ -6346,6 +6580,16 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) #ifndef NO_WOLFSSL_SERVER case client_hello: + #ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + WOLFSSL_MSG("ClientHello received by client"); + return OUT_OF_ORDER_E; + } + #endif + if (ssl->options.clientState >= CLIENT_HELLO_COMPLETE) { + WOLFSSL_MSG("ClientHello received out of order"); + return OUT_OF_ORDER_E; + } if (ssl->msgsReceived.got_client_hello == 2) { WOLFSSL_MSG("Too many ClientHello received"); return DUPLICATE_MSG_E; @@ -6357,27 +6601,43 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) #ifndef NO_WOLFSSL_CLIENT case server_hello: -#ifdef WOLFSSL_TLS13_DRAFT_18 + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + WOLFSSL_MSG("ServerHello received by server"); + return OUT_OF_ORDER_E; + } + #endif + #ifdef WOLFSSL_TLS13_DRAFT_18 if (ssl->msgsReceived.got_server_hello) { WOLFSSL_MSG("Duplicate ServerHello received"); return DUPLICATE_MSG_E; } ssl->msgsReceived.got_server_hello = 1; -#else + #else if (ssl->msgsReceived.got_server_hello == 2) { WOLFSSL_MSG("Duplicate ServerHello received"); return DUPLICATE_MSG_E; } ssl->msgsReceived.got_server_hello++; -#endif + #endif break; #endif #ifndef NO_WOLFSSL_CLIENT case session_ticket: + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + WOLFSSL_MSG("NewSessionTicket received by server"); + return OUT_OF_ORDER_E; + } + #endif + if (ssl->options.clientState < CLIENT_FINISHED_COMPLETE) { + WOLFSSL_MSG("NewSessionTicket received out of order"); + return OUT_OF_ORDER_E; + } if (ssl->msgsReceived.got_session_ticket) { - WOLFSSL_MSG("Duplicate SessionTicket received"); + WOLFSSL_MSG("Duplicate NewSessionTicket received"); return DUPLICATE_MSG_E; } ssl->msgsReceived.got_session_ticket = 1; @@ -6388,6 +6648,20 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) #ifndef NO_WOLFSSL_SERVER #ifdef WOLFSSL_EARLY_DATA case end_of_early_data: + #ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + WOLFSSL_MSG("EndOfEarlyData received by client"); + return OUT_OF_ORDER_E; + } + #endif + if (ssl->options.serverState < SERVER_FINISHED_COMPLETE) { + WOLFSSL_MSG("EndOfEarlyData received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->options.clientState >= CLIENT_FINISHED_COMPLETE) { + WOLFSSL_MSG("EndOfEarlyData received out of order"); + return OUT_OF_ORDER_E; + } if (ssl->msgsReceived.got_end_of_early_data == 1) { WOLFSSL_MSG("Too many EndOfEarlyData received"); return DUPLICATE_MSG_E; @@ -6398,8 +6672,19 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) #endif #endif -#ifndef NO_WOLFSSL_CLIENT +#ifdef WOLFSSL_TLS13_DRAFT_18 + #ifndef NO_WOLFSSL_CLIENT case hello_retry_request: + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + WOLFSSL_MSG("HelloRetryRequest received by server"); + return OUT_OF_ORDER_E; + } + #endif + if (ssl->options.clientState > CLIENT_FINISHED_COMPLETE) { + WOLFSSL_MSG("HelloRetryRequest received out of order"); + return OUT_OF_ORDER_E; + } if (ssl->msgsReceived.got_hello_retry_request) { WOLFSSL_MSG("Duplicate HelloRetryRequest received"); return DUPLICATE_MSG_E; @@ -6407,10 +6692,21 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) ssl->msgsReceived.got_hello_retry_request = 1; break; + #endif #endif #ifndef NO_WOLFSSL_CLIENT case encrypted_extensions: + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + WOLFSSL_MSG("EncryptedExtensions received by server"); + return OUT_OF_ORDER_E; + } + #endif + if (ssl->options.serverState != SERVER_HELLO_COMPLETE) { + WOLFSSL_MSG("EncryptedExtensions received out of order"); + return OUT_OF_ORDER_E; + } if (ssl->msgsReceived.got_encrypted_extensions) { WOLFSSL_MSG("Duplicate EncryptedExtensions received"); return DUPLICATE_MSG_E; @@ -6421,37 +6717,71 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) #endif case certificate: + #ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END && + ssl->options.serverState != + SERVER_ENCRYPTED_EXTENSIONS_COMPLETE) { + WOLFSSL_MSG("Certificate received out of order - Client"); + return OUT_OF_ORDER_E; + } + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + /* Server's authenticating with PSK must not send this. */ + if (ssl->options.side == WOLFSSL_CLIENT_END && + ssl->options.serverState == SERVER_CERT_COMPLETE && + ssl->arrays->psk_keySz != 0) { + WOLFSSL_MSG("Certificate received while using PSK"); + return SANITY_MSG_E; + } + #endif + #endif + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->options.serverState < SERVER_FINISHED_COMPLETE) { + WOLFSSL_MSG("Certificate received out of order - Server"); + return OUT_OF_ORDER_E; + } + #endif if (ssl->msgsReceived.got_certificate) { WOLFSSL_MSG("Duplicate Certificate received"); return DUPLICATE_MSG_E; } ssl->msgsReceived.got_certificate = 1; -#ifndef NO_WOLFSSL_CLIENT - if (ssl->options.side == WOLFSSL_CLIENT_END) { - if ( ssl->msgsReceived.got_server_hello == 0) { - WOLFSSL_MSG("No ServerHello before Cert"); - return OUT_OF_ORDER_E; - } - } -#endif -#ifndef NO_WOLFSSL_SERVER - if (ssl->options.side == WOLFSSL_SERVER_END) { - if ( ssl->msgsReceived.got_client_hello == 0) { - WOLFSSL_MSG("No ClientHello before Cert"); - return OUT_OF_ORDER_E; - } - } -#endif break; #ifndef NO_WOLFSSL_CLIENT case certificate_request: - #ifdef WOLFSSL_POST_HANDSHAKE_AUTH - if (ssl->msgsReceived.got_finished) - ; - else - #endif + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + WOLFSSL_MSG("CertificateRequest received by server"); + return OUT_OF_ORDER_E; + } + #endif + #ifndef WOLFSSL_POST_HANDSHAKE_AUTH + if (ssl->options.serverState != + SERVER_ENCRYPTED_EXTENSIONS_COMPLETE) { + WOLFSSL_MSG("CertificateRequest received out of order"); + return OUT_OF_ORDER_E; + } + #else + if (ssl->options.serverState != + SERVER_ENCRYPTED_EXTENSIONS_COMPLETE && + (ssl->options.serverState != SERVER_FINISHED_COMPLETE || + ssl->options.clientState != CLIENT_FINISHED_COMPLETE)) { + WOLFSSL_MSG("CertificateRequest received out of order"); + return OUT_OF_ORDER_E; + } + #endif + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + /* Server's authenticating with PSK must not send this. */ + if (ssl->options.serverState == + SERVER_ENCRYPTED_EXTENSIONS_COMPLETE && + ssl->arrays->psk_keySz != 0) { + WOLFSSL_MSG("CertificateRequset received while using PSK"); + return SANITY_MSG_E; + return SANITY_MSG_E; + } + #endif if (ssl->msgsReceived.got_certificate_request) { WOLFSSL_MSG("Duplicate CertificateRequest received"); return DUPLICATE_MSG_E; @@ -6462,24 +6792,77 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) #endif case certificate_verify: + #ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END && + ssl->options.serverState != SERVER_CERT_COMPLETE) { + WOLFSSL_MSG("No Cert before CertVerify"); + return OUT_OF_ORDER_E; + } + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + /* Server's authenticating with PSK must not send this. */ + if (ssl->options.side == WOLFSSL_CLIENT_END && + ssl->options.serverState == SERVER_CERT_COMPLETE && + ssl->arrays->psk_keySz != 0) { + WOLFSSL_MSG("CertificateVerify received while using PSK"); + return SANITY_MSG_E; + } + #endif + #endif + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + if (ssl->options.serverState < SERVER_FINISHED_COMPLETE) { + WOLFSSL_MSG("CertificateVerify received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { + WOLFSSL_MSG("CertificateVerify before ClientHello done"); + return OUT_OF_ORDER_E; + } + if (!ssl->msgsReceived.got_certificate) { + WOLFSSL_MSG("No Cert before CertificateVerify"); + return OUT_OF_ORDER_E; + } + } + #endif if (ssl->msgsReceived.got_certificate_verify) { WOLFSSL_MSG("Duplicate CertificateVerify received"); return DUPLICATE_MSG_E; } ssl->msgsReceived.got_certificate_verify = 1; - if (ssl->msgsReceived.got_certificate == 0) { - WOLFSSL_MSG("No Cert before CertVerify"); - return OUT_OF_ORDER_E; - } break; case finished: - #ifdef WOLFSSL_POST_HANDSHAKE_AUTH - if (1) { + #ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { + WOLFSSL_MSG("Finished received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->options.serverState < + SERVER_ENCRYPTED_EXTENSIONS_COMPLETE) { + WOLFSSL_MSG("Finished received out of order"); + return OUT_OF_ORDER_E; + } } - else - #endif + #endif + #ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + if (ssl->options.serverState < SERVER_FINISHED_COMPLETE) { + WOLFSSL_MSG("Finished received out of order"); + return OUT_OF_ORDER_E; + } + if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { + WOLFSSL_MSG("Finished received out of order"); + return OUT_OF_ORDER_E; + } + #ifdef WOLFSSL_EARLY_DATA + if (ssl->earlyData == process_early_data) { + return OUT_OF_ORDER_E; + } + #endif + } + #endif if (ssl->msgsReceived.got_finished) { WOLFSSL_MSG("Duplicate Finished received"); return DUPLICATE_MSG_E; @@ -6528,8 +6911,9 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, return INCOMPLETE_DATA; /* sanity check msg received */ - if ( (ret = SanityCheckTls13MsgReceived(ssl, type)) != 0) { + if ((ret = SanityCheckTls13MsgReceived(ssl, type)) != 0) { WOLFSSL_MSG("Sanity Check on handshake message type received failed"); + SendAlert(ssl, alert_fatal, unexpected_message); return ret; } @@ -6568,38 +6952,54 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, /* above checks handshake state */ switch (type) { - #ifndef NO_WOLFSSL_CLIENT -#ifdef WOLFSSL_TLS13_DRAFT_18 + /* Messages only recieved by client. */ + #ifdef WOLFSSL_TLS13_DRAFT_18 case hello_retry_request: WOLFSSL_MSG("processing hello rety request"); ret = DoTls13HelloRetryRequest(ssl, input, inOutIdx, size); break; -#endif + #endif case server_hello: WOLFSSL_MSG("processing server hello"); - ret = DoTls13ServerHello(ssl, input, inOutIdx, size); - break; - -#ifndef NO_CERTS - case certificate_request: - WOLFSSL_MSG("processing certificate request"); - ret = DoTls13CertificateRequest(ssl, input, inOutIdx, size); - break; -#endif - - case session_ticket: - WOLFSSL_MSG("processing new session ticket"); - ret = DoTls13NewSessionTicket(ssl, input, inOutIdx, size); + ret = DoTls13ServerHello(ssl, input, inOutIdx, size, &type); break; case encrypted_extensions: WOLFSSL_MSG("processing encrypted extensions"); ret = DoTls13EncryptedExtensions(ssl, input, inOutIdx, size); break; + + #ifndef NO_CERTS + case certificate_request: + WOLFSSL_MSG("processing certificate request"); + ret = DoTls13CertificateRequest(ssl, input, inOutIdx, size); + break; + #endif + + case session_ticket: + WOLFSSL_MSG("processing new session ticket"); + ret = DoTls13NewSessionTicket(ssl, input, inOutIdx, size); + break; #endif /* !NO_WOLFSSL_CLIENT */ +#ifndef NO_WOLFSSL_SERVER + /* Messages only recieved by server. */ + case client_hello: + WOLFSSL_MSG("processing client hello"); + ret = DoTls13ClientHello(ssl, input, inOutIdx, size); + break; + + #ifdef WOLFSSL_EARLY_DATA + case end_of_early_data: + WOLFSSL_MSG("processing end of early data"); + ret = DoTls13EndOfEarlyData(ssl, input, inOutIdx, size); + break; + #endif +#endif /* !NO_WOLFSSL_SERVER */ + + /* Messages recieved by both client and server. */ #ifndef NO_CERTS case certificate: WOLFSSL_MSG("processing certificate"); @@ -6614,15 +7014,6 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, break; #endif /* !NO_RSA || HAVE_ECC */ -#ifdef WOLFSSL_EARLY_DATA - #ifndef NO_WOLFSSL_SERVER - case end_of_early_data: - WOLFSSL_MSG("processing end of early data"); - ret = DoTls13EndOfEarlyData(ssl, input, inOutIdx, size); - break; - #endif -#endif - case finished: WOLFSSL_MSG("processing finished"); ret = DoTls13Finished(ssl, input, inOutIdx, size, totalSz, NO_SNIFF); @@ -6633,13 +7024,6 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, ret = DoTls13KeyUpdate(ssl, input, inOutIdx, size); break; -#ifndef NO_WOLFSSL_SERVER - case client_hello: - WOLFSSL_MSG("processing client hello"); - ret = DoTls13ClientHello(ssl, input, inOutIdx, size); - break; -#endif /* !NO_WOLFSSL_SERVER */ - default: WOLFSSL_MSG("Unknown handshake message type"); ret = UNKNOWN_HANDSHAKE_TYPE; @@ -6650,22 +7034,22 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, if (ret == 0 && ssl->error == WC_PENDING_E) ssl->error = 0; - if (ret == 0 && type != client_hello && type != session_ticket && - type != key_update && ssl->error != WC_PENDING_E) { + type != key_update) { ret = HashInput(ssl, input + inIdx, size); } if (ret == BUFFER_ERROR || ret == MISSING_HANDSHAKE_DATA) SendAlert(ssl, alert_fatal, decode_error); - - if (ret == EXT_NOT_ALLOWED || ret == PEER_KEY_ERROR || - ret == ECC_PEERKEY_ERROR || ret == BAD_KEY_SHARE_DATA || - ret == PSK_KEY_ERROR || ret == INVALID_PARAMETER) { + else if (ret == EXT_NOT_ALLOWED || ret == PEER_KEY_ERROR || + ret == ECC_PEERKEY_ERROR || ret == BAD_KEY_SHARE_DATA || + ret == PSK_KEY_ERROR || ret == INVALID_PARAMETER) { SendAlert(ssl, alert_fatal, illegal_parameter); } if (ssl->options.tls1_3) { + /* Need to hash input message before deriving secrets. */ +#ifndef NO_WOLFSSL_CLIENT if (type == server_hello && ssl->options.side == WOLFSSL_CLIENT_END) { if ((ret = DeriveEarlySecret(ssl)) != 0) return ret; @@ -6676,48 +7060,42 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, ENCRYPT_AND_DECRYPT_SIDE, 1)) != 0) { return ret; } -#ifdef WOLFSSL_EARLY_DATA + #ifdef WOLFSSL_EARLY_DATA if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) return ret; -#else + #else if ((ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE)) != 0) return ret; -#endif + #endif } -#ifdef WOLFSSL_EARLY_DATA - if (type == encrypted_extensions && - ssl->options.side == WOLFSSL_CLIENT_END) { - if (!ssl->earlyData) - { - if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) - return ret; - } - } -#endif if (type == finished && ssl->options.side == WOLFSSL_CLIENT_END) { if ((ret = DeriveMasterSecret(ssl)) != 0) return ret; -#ifdef WOLFSSL_EARLY_DATA + #ifdef WOLFSSL_EARLY_DATA if ((ret = DeriveTls13Keys(ssl, traffic_key, - ENCRYPT_AND_DECRYPT_SIDE, !ssl->earlyData)) != 0) { + ENCRYPT_AND_DECRYPT_SIDE, + ssl->earlyData == no_early_data)) != 0) { return ret; } -#else + #else if ((ret = DeriveTls13Keys(ssl, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, 1)) != 0) { return ret; } -#endif + #endif } +#endif /* NO_WOLFSSL_CLIENT */ -#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +#ifndef NO_WOLFSSL_SERVER + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) if (type == finished && ssl->options.side == WOLFSSL_SERVER_END) { ret = DeriveResumptionSecret(ssl, ssl->session.masterSecret); if (ret != 0) return ret; } -#endif + #endif +#endif /* NO_WOLFSSL_SERVER */ } #ifdef WOLFSSL_ASYNC_CRYPT @@ -6852,8 +7230,6 @@ int DoTls13HandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, */ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) { - int neededState; - WOLFSSL_ENTER("wolfSSL_connect_TLSv13()"); #ifdef HAVE_ERRNO_H @@ -6898,7 +7274,7 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) ssl->options.connectState = CLIENT_HELLO_SENT; WOLFSSL_MSG("connect state: CLIENT_HELLO_SENT"); #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData) { + if (ssl->earlyData != no_early_data) { #if !defined(WOLFSSL_TLS13_DRAFT_18) && \ defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) if ((ssl->error = SendChangeCipher(ssl)) != 0) { @@ -6914,19 +7290,13 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) FALL_THROUGH; case CLIENT_HELLO_SENT: - neededState = ssl->options.resuming ? SERVER_FINISHED_COMPLETE : - SERVER_HELLODONE_COMPLETE; /* Get the response/s from the server. */ - while (ssl->options.serverState < neededState) { + while (ssl->options.serverState < + SERVER_HELLO_RETRY_REQUEST_COMPLETE) { if ((ssl->error = ProcessReply(ssl)) < 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } - /* if resumption failed, reset needed state. */ - if (neededState == SERVER_FINISHED_COMPLETE && - !ssl->options.resuming) { - neededState = SERVER_HELLODONE_COMPLETE; - } } ssl->options.connectState = HELLO_AGAIN; @@ -6945,8 +7315,8 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) return VERSION_ERROR; } - if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) { - ssl->options.serverState = NULL_STATE; + if (ssl->options.serverState == + SERVER_HELLO_RETRY_REQUEST_COMPLETE) { #if !defined(WOLFSSL_TLS13_DRAFT_18) && \ defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) if (!ssl->options.sentChangeCipher) { @@ -6969,22 +7339,11 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) FALL_THROUGH; case HELLO_AGAIN_REPLY: - if (ssl->options.serverState == NULL_STATE || - ssl->error == WC_PENDING_E) { - neededState = ssl->options.resuming ? SERVER_FINISHED_COMPLETE : - SERVER_HELLODONE_COMPLETE; - - /* Get the response/s from the server. */ - while (ssl->options.serverState < neededState) { - if ((ssl->error = ProcessReply(ssl)) < 0) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - /* if resumption failed, reset needed state */ - else if (neededState == SERVER_FINISHED_COMPLETE) { - if (!ssl->options.resuming) - neededState = SERVER_HELLODONE_COMPLETE; - } + /* Get the response/s from the server. */ + while (ssl->options.serverState < SERVER_FINISHED_COMPLETE) { + if ((ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; } } @@ -6994,7 +7353,7 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) case FIRST_REPLY_DONE: #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData) { + if (ssl->earlyData != no_early_data) { if ((ssl->error = SendTls13EndOfEarlyData(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; @@ -7290,7 +7649,7 @@ int wolfSSL_update_keys(WOLFSSL* ssl) /* Allow post-handshake authentication in TLS v1.3 connections. * * ctx The SSL/TLS CTX object. - * returns BAD_FUNC_ARG when ctx is NULL, SIDE_ERROR when not a server and + * returns BAD_FUNC_ARG when ctx is NULL, SIDE_ERROR when not a client and * 0 on success. */ int wolfSSL_CTX_allow_post_handshake_auth(WOLFSSL_CTX* ctx) @@ -7309,7 +7668,7 @@ int wolfSSL_CTX_allow_post_handshake_auth(WOLFSSL_CTX* ctx) * * ssl The SSL/TLS object. * returns BAD_FUNC_ARG when ssl is NULL, or not using TLS v1.3, - * SIDE_ERROR when not a server and 0 on success. + * SIDE_ERROR when not a client and 0 on success. */ int wolfSSL_allow_post_handshake_auth(WOLFSSL* ssl) { @@ -7363,6 +7722,80 @@ int wolfSSL_request_certificate(WOLFSSL* ssl) } #endif /* !NO_CERTS && WOLFSSL_POST_HANDSHAKE_AUTH */ +#if !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_SERVER_GROUPS_EXT) +/* Get the preferred key exchange group. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL or not using TLS v1.3, + * SIDE_ERROR when not a client, NOT_READY_ERROR when handshake not complete + * and group number on success. + */ +int wolfSSL_preferred_group(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + if (ssl->options.side == WOLFSSL_SERVER_END) + return SIDE_ERROR; + if (ssl->options.handShakeState != HANDSHAKE_DONE) + return NOT_READY_ERROR; + + /* Return supported groups only. */ + ret = TLSX_SupportedCurve_Preferred(ssl, 1); + + return ret; +} +#endif + +/* Sets the key exchange groups in rank order on a context. + * + * ctx SSL/TLS context object. + * groups Array of groups. + * count Number of groups in array. + * returns BAD_FUNC_ARG when ctx or groups is NULL, not using TLS v1.3 or + * count is greater than WOLFSSL_MAX_GROUP_COUNT and WOLFSSL_SUCCESS on success. + */ +int wolfSSL_CTX_set_groups(WOLFSSL_CTX* ctx, int* groups, int count) +{ + int i; + + if (ctx == NULL || groups == NULL || count > WOLFSSL_MAX_GROUP_COUNT) + return BAD_FUNC_ARG; + if (!IsAtLeastTLSv1_3(ctx->method->version)) + return BAD_FUNC_ARG; + + for (i = 0; i < count; i++) + ctx->group[i] = groups[i]; + ctx->numGroups = count; + + return WOLFSSL_SUCCESS; +} + +/* Sets the key exchange groups in rank order. + * + * ssl SSL/TLS object. + * groups Array of groups. + * count Number of groups in array. + * returns BAD_FUNC_ARG when ssl or groups is NULL, not using TLS v1.3 or + * count is greater than WOLFSSL_MAX_GROUP_COUNT and WOLFSSL_SUCCESS on success. + */ +int wolfSSL_set_groups(WOLFSSL* ssl, int* groups, int count) +{ + int i; + + if (ssl == NULL || groups == NULL || count > WOLFSSL_MAX_GROUP_COUNT) + return BAD_FUNC_ARG; + if (!IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + + for (i = 0; i < count; i++) + ssl->group[i] = groups[i]; + ssl->numGroups = count; + + return WOLFSSL_SUCCESS; +} + #ifndef NO_WOLFSSL_SERVER /* The server accepting a connection from a client. * The protocol version is expecting to be TLS v1.3. @@ -7378,7 +7811,6 @@ int wolfSSL_request_certificate(WOLFSSL* ssl) int wolfSSL_accept_TLSv13(WOLFSSL* ssl) { word16 havePSK = 0; - word16 haveAnon = 0; WOLFSSL_ENTER("SSL_accept_TLSv13()"); #ifdef HAVE_ERRNO_H @@ -7390,11 +7822,6 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) #endif (void)havePSK; -#ifdef HAVE_ANON - haveAnon = ssl->options.haveAnon; -#endif - (void)haveAnon; - if (ssl->options.side != WOLFSSL_SERVER_END) { WOLFSSL_ERROR(ssl->error = SIDE_ERROR); return WOLFSSL_FATAL_ERROR; @@ -7402,7 +7829,7 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) #ifndef NO_CERTS /* allow no private key if using PK callbacks and CB is set */ - if (!havePSK && !haveAnon) { + if (!havePSK) { if (!ssl->buffers.certificate || !ssl->buffers.certificate->buffer) { @@ -7449,7 +7876,7 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) switch (ssl->options.acceptState) { case ACCEPT_BEGIN : - /* get response */ + /* get client_hello */ while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { if ((ssl->error = ProcessReply(ssl)) < 0) { WOLFSSL_ERROR(ssl->error); @@ -7463,14 +7890,16 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) case ACCEPT_CLIENT_HELLO_DONE : #ifdef WOLFSSL_TLS13_DRAFT_18 - if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) { + if (ssl->options.serverState == + SERVER_HELLO_RETRY_REQUEST_COMPLETE) { if ((ssl->error = SendTls13HelloRetryRequest(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } } #else - if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) { + if (ssl->options.serverState == + SERVER_HELLO_RETRY_REQUEST_COMPLETE) { if ((ssl->error = SendTls13ServerHello(ssl, hello_retry_request)) != 0) { WOLFSSL_ERROR(ssl->error); @@ -7490,7 +7919,8 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) FALL_THROUGH; case ACCEPT_HELLO_RETRY_REQUEST_DONE : - if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) { + if (ssl->options.serverState == + SERVER_HELLO_RETRY_REQUEST_COMPLETE) { ssl->options.clientState = NULL_STATE; while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { if ((ssl->error = ProcessReply(ssl)) < 0) { @@ -7590,7 +8020,7 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) ssl->options.acceptState = ACCEPT_FINISHED_DONE; WOLFSSL_MSG("accept state ACCEPT_FINISHED_DONE"); #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData) { + if (ssl->earlyData != no_early_data) { ssl->options.handShakeState = SERVER_FINISHED_COMPLETE; return WOLFSSL_SUCCESS; } @@ -7735,7 +8165,7 @@ int wolfSSL_write_early_data(WOLFSSL* ssl, const void* data, int sz, int* outSz) return SIDE_ERROR; if (ssl->options.handShakeState == NULL_STATE) { - ssl->earlyData = 1; + ssl->earlyData = expecting_early_data; ret = wolfSSL_connect_TLSv13(ssl); if (ret <= 0) return WOLFSSL_FATAL_ERROR; @@ -7779,7 +8209,7 @@ int wolfSSL_read_early_data(WOLFSSL* ssl, void* data, int sz, int* outSz) return SIDE_ERROR; if (ssl->options.handShakeState == NULL_STATE) { - ssl->earlyData = 1; + ssl->earlyData = expecting_early_data; ret = wolfSSL_accept_TLSv13(ssl); if (ret <= 0) return WOLFSSL_FATAL_ERROR; diff --git a/tests/api.c b/tests/api.c index 59e9393f2..a2a5bc278 100644 --- a/tests/api.c +++ b/tests/api.c @@ -18087,6 +18087,8 @@ static int test_tls13_apis(void) #ifdef WOLFSSL_EARLY_DATA int outSz; #endif + int groups[1] = { WOLFSSL_ECC_X25519 }; + int numGroups = 1; clientTls12Ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()); clientTls12Ssl = wolfSSL_new(clientTls12Ctx); @@ -18190,6 +18192,38 @@ static int test_tls13_apis(void) AssertIntEQ(wolfSSL_request_certificate(serverSsl), NOT_READY_ERROR); #endif +#ifndef WOLFSSL_NO_SERVER_GROUPS_EXT + AssertIntEQ(wolfSSL_preferred_group(NULL), BAD_FUNC_ARG); + AssertIntEQ(wolfSSL_preferred_group(serverSsl), SIDE_ERROR); + AssertIntEQ(wolfSSL_preferred_group(clientTls12Ssl), BAD_FUNC_ARG); + AssertIntEQ(wolfSSL_preferred_group(clientSsl), NOT_READY_ERROR); +#endif + + AssertIntEQ(wolfSSL_CTX_set_groups(NULL, NULL, 0), BAD_FUNC_ARG); + AssertIntEQ(wolfSSL_CTX_set_groups(clientCtx, NULL, 0), BAD_FUNC_ARG); + AssertIntEQ(wolfSSL_CTX_set_groups(NULL, groups, numGroups), BAD_FUNC_ARG); + AssertIntEQ(wolfSSL_CTX_set_groups(clientTls12Ctx, groups, numGroups), + BAD_FUNC_ARG); + AssertIntEQ(wolfSSL_CTX_set_groups(clientCtx, groups, + WOLFSSL_MAX_GROUP_COUNT + 1), + BAD_FUNC_ARG); + AssertIntEQ(wolfSSL_CTX_set_groups(clientCtx, groups, numGroups), + WOLFSSL_SUCCESS); + AssertIntEQ(wolfSSL_CTX_set_groups(serverCtx, groups, numGroups), + WOLFSSL_SUCCESS); + + AssertIntEQ(wolfSSL_set_groups(NULL, NULL, 0), BAD_FUNC_ARG); + AssertIntEQ(wolfSSL_set_groups(clientSsl, NULL, 0), BAD_FUNC_ARG); + AssertIntEQ(wolfSSL_set_groups(NULL, groups, numGroups), BAD_FUNC_ARG); + AssertIntEQ(wolfSSL_set_groups(clientTls12Ssl, groups, numGroups), + BAD_FUNC_ARG); + AssertIntEQ(wolfSSL_set_groups(clientSsl, groups, + WOLFSSL_MAX_GROUP_COUNT + 1), BAD_FUNC_ARG); + AssertIntEQ(wolfSSL_set_groups(clientSsl, groups, numGroups), + WOLFSSL_SUCCESS); + AssertIntEQ(wolfSSL_set_groups(serverSsl, groups, numGroups), + WOLFSSL_SUCCESS); + #ifdef WOLFSSL_EARLY_DATA AssertIntEQ(wolfSSL_CTX_set_max_early_data(NULL, 0), BAD_FUNC_ARG); AssertIntEQ(wolfSSL_CTX_set_max_early_data(clientCtx, 0), SIDE_ERROR); diff --git a/tests/test-tls13-ecc.conf b/tests/test-tls13-ecc.conf index e15d0878c..04f5022ee 100644 --- a/tests/test-tls13-ecc.conf +++ b/tests/test-tls13-ecc.conf @@ -1,12 +1,12 @@ -# server TLSv1.3 TLS13-CHACH20-POLY1305-SHA256 +# server TLSv1.3 TLS13-CHACHA20-POLY1305-SHA256 -v 4 --l TLS13-CHACH20-POLY1305-SHA256 +-l TLS13-CHACHA20-POLY1305-SHA256 -c ./certs/server-ecc.pem -k ./certs/ecc-key.pem -# client TLSv1.3 TLS13-CHACH20-POLY1305-SHA256 +# client TLSv1.3 TLS13-CHACHA20-POLY1305-SHA256 -v 4 --l TLS13-CHACH20-POLY1305-SHA256 +-l TLS13-CHACHA20-POLY1305-SHA256 -A ./certs/ca-ecc-cert.pem # server TLSv1.3 TLS13-AES128-GCM-SHA256 @@ -58,6 +58,7 @@ -l TLS13-AES128-GCM-SHA256 -c ./certs/server-ecc.pem -k ./certs/ecc-key.pem +-t # client TLSv1.3 TLS13-AES128-GCM-SHA256 -v 4 @@ -65,3 +66,16 @@ -A ./certs/ca-ecc-cert.pem -t +# server TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem +-Y + +# client TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 +-A ./certs/ca-ecc-cert.pem +-y + diff --git a/tests/test-tls13.conf b/tests/test-tls13.conf index 8147c20bf..532934b89 100644 --- a/tests/test-tls13.conf +++ b/tests/test-tls13.conf @@ -1,10 +1,10 @@ -# server TLSv1.3 TLS13-CHACH20-POLY1305-SHA256 +# server TLSv1.3 TLS13-CHACHA20-POLY1305-SHA256 -v 4 --l TLS13-CHACH20-POLY1305-SHA256 +-l TLS13-CHACHA20-POLY1305-SHA256 -# client TLSv1.3 TLS13-CHACH20-POLY1305-SHA256 +# client TLSv1.3 TLS13-CHACHA20-POLY1305-SHA256 -v 4 --l TLS13-CHACH20-POLY1305-SHA256 +-l TLS13-CHACHA20-POLY1305-SHA256 # server TLSv1.3 TLS13-AES128-GCM-SHA256 -v 4 diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 432365d17..eed6a3057 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1026,6 +1026,7 @@ enum Misc { TLSv1_1_MINOR = 2, /* TLSv1_1 minor version number */ TLSv1_2_MINOR = 3, /* TLSv1_2 minor version number */ TLSv1_3_MINOR = 4, /* TLSv1_3 minor version number */ +#ifndef WOLFSSL_TLS13_FINAL TLS_DRAFT_MAJOR = 0x7f, /* Draft TLS major version number */ #ifdef WOLFSSL_TLS13_DRAFT_18 TLS_DRAFT_MINOR = 0x12, /* Minor version number of TLS draft */ @@ -1034,7 +1035,8 @@ enum Misc { #elif defined(WOLFSSL_TLS13_DRAFT_23) TLS_DRAFT_MINOR = 0x17, /* Minor version number of TLS draft */ #else - TLS_DRAFT_MINOR = 0x1b, /* Minor version number of TLS draft */ + TLS_DRAFT_MINOR = 0x1c, /* Minor version number of TLS draft */ +#endif #endif OLD_HELLO_ID = 0x01, /* SSLv2 Client Hello Indicator */ INVALID_BYTE = 0xff, /* Used to initialize cipher specs values */ @@ -1380,6 +1382,7 @@ enum states { NULL_STATE = 0, SERVER_HELLOVERIFYREQUEST_COMPLETE, + SERVER_HELLO_RETRY_REQUEST_COMPLETE, SERVER_HELLO_COMPLETE, SERVER_ENCRYPTED_EXTENSIONS_COMPLETE, SERVER_CERT_COMPLETE, @@ -1387,7 +1390,6 @@ enum states { SERVER_HELLODONE_COMPLETE, SERVER_CHANGECIPHERSPEC_COMPLETE, SERVER_FINISHED_COMPLETE, - SERVER_HELLO_RETRY_REQUEST, CLIENT_HELLO_COMPLETE, CLIENT_KEYEXCHANGE_COMPLETE, @@ -1465,6 +1467,8 @@ struct WOLFSSL_METHOD { /* wolfSSL buffer type - internal uses "buffer" type */ typedef WOLFSSL_BUFFER_INFO buffer; +typedef struct Suites Suites; + /* defaults to client */ WOLFSSL_LOCAL void InitSSL_Method(WOLFSSL_METHOD*, ProtocolVersion); @@ -1474,6 +1478,8 @@ WOLFSSL_LOCAL int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size, word32 totalSz, int sniff); WOLFSSL_LOCAL int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx); /* TLS v1.3 needs these */ +WOLFSSL_LOCAL int HandleTlsResumption(WOLFSSL* ssl, int bogusID, + Suites* clSuites); WOLFSSL_LOCAL int DoClientHello(WOLFSSL* ssl, const byte* input, word32*, word32); #ifdef WOLFSSL_TLS13 @@ -1513,7 +1519,8 @@ WOLFSSL_LOCAL int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, WOLFSSL_LOCAL int DoTls13HandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 totalSz); WOLFSSL_LOCAL int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, - word32* inOutIdx, word32 helloSz); + word32* inOutIdx, word32 helloSz, + byte* extMsgType); #endif @@ -1594,7 +1601,7 @@ typedef struct { } bufferStatic; /* Cipher Suites holder */ -typedef struct Suites { +struct Suites { word16 suiteSz; /* suite length in bytes */ word16 hashSigAlgoSz; /* SigAlgo extension length in bytes */ byte suites[WOLFSSL_MAX_SUITE_SZ]; @@ -1602,7 +1609,7 @@ typedef struct Suites { byte setSuites; /* user set suites from default */ byte hashAlgo; /* selected hash algorithm */ byte sigAlgo; /* selected sig algorithm */ -} Suites; +}; WOLFSSL_LOCAL void InitSuitesHashSigAlgo(Suites* suites, int haveECDSAsig, @@ -1935,6 +1942,7 @@ typedef struct TLSX { } TLSX; WOLFSSL_LOCAL TLSX* TLSX_Find(TLSX* list, TLSX_Type type); +WOLFSSL_LOCAL void TLSX_Remove(TLSX** list, TLSX_Type type, void* heap); WOLFSSL_LOCAL void TLSX_FreeAll(TLSX* list, void* heap); WOLFSSL_LOCAL int TLSX_SupportExtensions(WOLFSSL* ssl); WOLFSSL_LOCAL int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isRequest); @@ -2100,6 +2108,9 @@ WOLFSSL_LOCAL int TLSX_UsePointFormat(TLSX** extensions, byte point, #ifndef NO_WOLFSSL_SERVER WOLFSSL_LOCAL int TLSX_ValidateSupportedCurves(WOLFSSL* ssl, byte first, byte second); +WOLFSSL_LOCAL int TLSX_SupportedCurve_CheckPriority(WOLFSSL* ssl); +WOLFSSL_LOCAL int TLSX_SupportedCurve_Preferred(WOLFSSL* ssl, + int checkSupported); #endif #endif /* HAVE_SUPPORTED_CURVES */ @@ -2420,6 +2431,10 @@ struct WOLFSSL_CTX { wc_psk_server_callback server_psk_cb; /* server callback */ char server_hint[MAX_PSK_ID_LEN + NULL_TERM_LEN]; #endif /* HAVE_SESSION_TICKET || !NO_PSK */ +#ifdef WOLFSSL_TLS13 + word16 group[WOLFSSL_MAX_GROUP_COUNT]; + byte numGroups; +#endif #ifdef WOLFSSL_EARLY_DATA word32 maxEarlyDataSz; #endif @@ -2773,9 +2788,11 @@ struct WOLFSSL_SESSION { byte sessionCtxSz; /* sessionCtx length */ byte sessionCtx[ID_LEN]; /* app specific context id */ #endif +#ifdef WOLFSSL_TLS13 + word16 namedGroup; +#endif #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) #ifdef WOLFSSL_TLS13 - byte namedGroup; word32 ticketSeen; /* Time ticket seen (ms) */ word32 ticketAdd; /* Added by client */ #ifndef WOLFSSL_TLS13_DRAFT_18 @@ -3060,8 +3077,12 @@ typedef struct Options { byte verifyDepth; /* maximum verification depth */ #endif #ifdef WOLFSSL_EARLY_DATA + word16 pskIdIndex; word32 maxEarlyDataSz; #endif +#ifdef WOLFSSL_TLS13 + byte oldMinor; /* client preferred version < TLS 1.3 */ +#endif } Options; typedef struct Arrays { @@ -3357,6 +3378,15 @@ struct CertReqCtx { }; #endif +#ifdef WOLFSSL_EARLY_DATA +typedef enum EarlyDataState { + no_early_data, + expecting_early_data, + process_early_data, + done_early_data +} EarlyDataState; +#endif + /* wolfSSL ssl type */ struct WOLFSSL { WOLFSSL_CTX* ctx; @@ -3448,6 +3478,8 @@ struct WOLFSSL { #endif #ifdef WOLFSSL_TLS13 word16 namedGroup; + word16 group[WOLFSSL_MAX_GROUP_COUNT]; + byte numGroups; #endif byte pssAlgo; #ifdef WOLFSSL_TLS13 @@ -3636,7 +3668,7 @@ struct WOLFSSL { void* jObjectRef; /* reference to WolfSSLSession in JNI wrapper */ #endif /* WOLFSSL_JNI */ #ifdef WOLFSSL_EARLY_DATA - int earlyData; + EarlyDataState earlyData; word32 earlyDataSz; #endif }; diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index e1615af7e..7ed13a191 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -396,6 +396,8 @@ enum AlertLevel { /* Maximum master key length (SECRET_LEN) */ #define WOLFSSL_MAX_MASTER_KEY_LENGTH 48 +/* Maximum number of groups that can be set */ +#define WOLFSSL_MAX_GROUP_COUNT 10 typedef WOLFSSL_METHOD* (*wolfSSL_method_func)(void* heap); WOLFSSL_API WOLFSSL_METHOD *wolfSSLv3_server_method_ex(void* heap); @@ -552,6 +554,11 @@ WOLFSSL_API int wolfSSL_CTX_allow_post_handshake_auth(WOLFSSL_CTX* ctx); WOLFSSL_API int wolfSSL_allow_post_handshake_auth(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_request_certificate(WOLFSSL* ssl); +WOLFSSL_API int wolfSSL_preferred_group(WOLFSSL* ssl); +WOLFSSL_API int wolfSSL_CTX_set_groups(WOLFSSL_CTX* ctx, int* groups, + int count); +WOLFSSL_API int wolfSSL_set_groups(WOLFSSL* ssl, int* groups, int count); + WOLFSSL_API int wolfSSL_connect_TLSv13(WOLFSSL*); WOLFSSL_API int wolfSSL_accept_TLSv13(WOLFSSL*); @@ -575,12 +582,11 @@ WOLFSSL_API void wolfSSL_set_quiet_shutdown(WOLFSSL*, int); WOLFSSL_API int wolfSSL_get_error(WOLFSSL*, int); WOLFSSL_API int wolfSSL_get_alert_history(WOLFSSL*, WOLFSSL_ALERT_HISTORY *); -WOLFSSL_API int wolfSSL_set_session(WOLFSSL* ssl,WOLFSSL_SESSION* session); -WOLFSSL_API long wolfSSL_SSL_SESSION_set_timeout(WOLFSSL_SESSION* session, long t); -WOLFSSL_API WOLFSSL_SESSION* wolfSSL_get_session(WOLFSSL* ssl); -WOLFSSL_API void wolfSSL_flush_sessions(WOLFSSL_CTX *ctx, long tm); -WOLFSSL_API int wolfSSL_SetServerID(WOLFSSL* ssl, const unsigned char*, - int, int); +WOLFSSL_API int wolfSSL_set_session(WOLFSSL*, WOLFSSL_SESSION*); +WOLFSSL_API long wolfSSL_SSL_SESSION_set_timeout(WOLFSSL_SESSION*, long); +WOLFSSL_API WOLFSSL_SESSION* wolfSSL_get_session(WOLFSSL*); +WOLFSSL_API void wolfSSL_flush_sessions(WOLFSSL_CTX*, long); +WOLFSSL_API int wolfSSL_SetServerID(WOLFSSL*, const unsigned char*, int, int); #ifdef SESSION_INDEX WOLFSSL_API int wolfSSL_GetSessionIndex(WOLFSSL* ssl);