diff --git a/configure.ac b/configure.ac index dd0052133..87eb28026 100644 --- a/configure.ac +++ b/configure.ac @@ -140,6 +140,7 @@ then enable_shared=yes enable_static=yes enable_dtls=yes + enable_tls13=yes enable_openssh=yes enable_opensslextra=yes enable_savesession=yes @@ -233,6 +234,21 @@ then fi +# TLS v1.3 +AC_ARG_ENABLE([tls13], + [ --enable-tls13 Enable wolfSSL TLS v1.3 (default: disabled)], + [ ENABLED_TLS13=$enableval ], + [ ENABLED_TLS13=no ] + ) +if test "$ENABLED_TLS13" = "yes" +then + AM_CFLAGS="-DWOLFSSL_TLS13 -DHAVE_TLS_EXTENSIONS -DHAVE_FFDHE_2048 $AM_CFLAGS" +fi + +# check if TLS v1.3 was enabled for conditionally running tls13.test script +AM_CONDITIONAL([BUILD_TLS13], [test "x$ENABLED_TLS13" = "xyes"]) + + AC_ARG_ENABLE([rng], [AS_HELP_STRING([--enable-rng Enable compiling and using RNG (default: enabled)])], [ ENABLED_RNG=$enableval ], @@ -845,6 +861,10 @@ if test "x$ENABLED_NGINX" = "xyes" then ENABLED_SESSIONCERTS=yes fi +if test "$ENABLED_TLS13" = "yes" && test "$ENABLED_PSK" = "yes" +then + ENABLED_SESSIONCERTS=yes +fi if test "$ENABLED_SESSIONCERTS" = "yes" then @@ -930,6 +950,10 @@ AC_ARG_ENABLE([hkdf], [ ENABLED_HKDF=$enableval ], [ ENABLED_HKDF=no ] ) +if test "$ENABLED_TLS13" = "yes" +then + ENABLED_HKDF="yes" +fi if test "$ENABLED_HKDF" = "yes" then AM_CFLAGS="$AM_CFLAGS -DHAVE_HKDF" @@ -3620,6 +3644,7 @@ echo " * DTLS: $ENABLED_DTLS" echo " * SCTP: $ENABLED_SCTP" echo " * Old TLS Versions: $ENABLED_OLD_TLS" echo " * SSL version 3.0: $ENABLED_SSLV3" +echo " * TLS v1.3: $ENABLED_TLS13" echo " * OCSP: $ENABLED_OCSP" echo " * OCSP Stapling: $ENABLED_CERTIFICATE_STATUS_REQUEST" echo " * OCSP Stapling v2: $ENABLED_CERTIFICATE_STATUS_REQUEST_V2" diff --git a/examples/client/client.c b/examples/client/client.c index 1af2c22b3..4ba666d70 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -165,6 +165,11 @@ static int ClientBenchmarkConnections(WOLFSSL_CTX* ctx, char* host, word16 port, #ifndef NO_SESSION_CACHE WOLFSSL_SESSION* benchSession = NULL; #endif +#ifdef WOLFSSL_TLS13 + byte* reply[80]; + char msg[] = "hello wolfssl!"; +#endif + (void)resumeSession; while (loops--) { @@ -179,6 +184,7 @@ static int ClientBenchmarkConnections(WOLFSSL_CTX* ctx, char* host, word16 port, if (ssl == NULL) err_sys("unable to get SSL object"); + tcp_connect(&sockfd, host, port, dtlsUDP, dtlsSCTP, ssl); #ifndef NO_SESSION_CACHE @@ -206,6 +212,16 @@ static int ClientBenchmarkConnections(WOLFSSL_CTX* ctx, char* host, word16 port, err_sys("SSL_connect failed"); } + #ifdef WOLFSSL_TLS13 + if (resumeSession) { + if (wolfSSL_write(ssl, msg, sizeof(msg)-1) <= 0) + err_sys("SSL_write failed"); + + if (wolfSSL_read(ssl, reply, sizeof(reply)-1) <= 0) + err_sys("SSL_read failed"); + } + #endif + wolfSSL_shutdown(ssl); #ifndef NO_SESSION_CACHE if (i == (times-1) && resumeSession) { @@ -242,6 +258,7 @@ static int ClientBenchmarkThroughput(WOLFSSL_CTX* ctx, char* host, word16 port, ssl = wolfSSL_new(ctx); if (ssl == NULL) err_sys("unable to get SSL object"); + tcp_connect(&sockfd, host, port, dtlsUDP, dtlsSCTP, ssl); if (wolfSSL_set_fd(ssl, sockfd) != SSL_SUCCESS) { err_sys("error in setting fd"); @@ -598,6 +615,18 @@ static void Usage(void) #endif #ifdef HAVE_WNR printf("-q Whitewood config file, default %s\n", wnrConfig); +#endif + printf("-H Force use of the default cipher suite list\n"); +#ifdef WOLFSSL_TLS13 + printf("-t Use HelloRetryRequest to choose group for KE\n"); + printf("-K Key Exchange for PSK not using (EC)DHE\n"); + printf("-I Update keys and IVs before sending data\n"); +#ifndef NO_DH + printf("-y Key Share with FFDHE named groups only\n"); +#endif +#ifdef HAVE_ECC + printf("-Y Key Share with ECC named groups only\n"); +#endif #endif } @@ -690,6 +719,12 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #ifdef HAVE_EXTENDED_MASTER byte disableExtMasterSecret = 0; #endif +#ifdef WOLFSSL_TLS13 + int helloRetry = 0; + int onlyKeyShare = 0; + int noPskDheKe = 0; +#endif + int updateKeysIVs = 0; #ifdef HAVE_OCSP int useOcsp = 0; @@ -727,14 +762,15 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) (void)minDhKeyBits; (void)alpnList; (void)alpn_opt; + (void)updateKeysIVs; StackTrap(); #ifndef WOLFSSL_VXWORKS - /* Not used: j, t, y, I, J, K, Q, Y */ + /* Not used: j, J, Q */ while ((ch = mygetopt(argc, argv, "?" - "ab:c:defgh:ik:l:mnop:q:rsuv:wxz" - "A:B:CDE:F:GHL:M:NO:PRS:TUVW:XZ:")) != -1) { + "ab:c:defgh:ik:l:mnop:q:rstuv:wxyz" + "A:B:CDE:F:GHIKL:M:NO:PRS:TUVW:XYZ:")) != -1) { switch (ch) { case '?' : Usage(); @@ -827,7 +863,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) case 'v' : version = atoi(myoptarg); - if (version < 0 || version > 3) { + if (version < 0 || version > 4) { Usage(); exit(MY_EX_USAGE); } @@ -1004,6 +1040,35 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #endif break; + case 't' : + #ifdef WOLFSSL_TLS13 + helloRetry = 1; + #endif + break; + + case 'K' : + #ifdef WOLFSSL_TLS13 + noPskDheKe = 1; + #endif + break; + + case 'I' : + #ifdef WOLFSSL_TLS13 + updateKeysIVs = 1; + #endif + + case 'y' : + #if defined(WOLFSSL_TLS13) && !defined(NO_DH) + onlyKeyShare = 1; + #endif + break; + + case 'Y' : + #if defined(WOLFSSL_TLS13) && defined(HAVE_ECC) + onlyKeyShare = 2; + #endif + break; + default: Usage(); exit(MY_EX_USAGE); @@ -1127,6 +1192,11 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) case 3: method = wolfTLSv1_2_client_method(); break; + #ifdef WOLFSSL_TLS13 + case 4: + method = wolfTLSv1_3_client_method(); + break; + #endif #endif #ifdef WOLFSSL_DTLS @@ -1402,6 +1472,11 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) } #endif + #ifdef WOLFSSL_TLS13 + if (noPskDheKe) + wolfSSL_CTX_no_dhe_psk(ctx); + #endif + ssl = wolfSSL_new(ctx); if (ssl == NULL) { wolfSSL_CTX_free(ctx); @@ -1412,45 +1487,29 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) wolfSSL_KeepArrays(ssl); #endif - #if 0 /* all enabled and supported ECC curves will be added automatically */ - #ifdef HAVE_SUPPORTED_CURVES /* add curves to supported curves extension */ - if (wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP256R1) - != SSL_SUCCESS) { - wolfSSL_free(ssl); - wolfSSL_CTX_free(ctx); - err_sys("unable to set curve secp256r1"); + #ifdef WOLFSSL_TLS13 + if (!helloRetry) { + if (onlyKeyShare == 0 || onlyKeyShare == 1) { + #ifdef HAVE_FFDHE_2048 + if (wolfSSL_UseKeyShare(ssl, WOLFSSL_FFDHE_2048) != SSL_SUCCESS) { + err_sys("unable to use DH 2048-bit parameters"); + } + #endif } - if (wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP384R1) - != SSL_SUCCESS) { - wolfSSL_free(ssl); - wolfSSL_CTX_free(ctx); - err_sys("unable to set curve secp384r1"); + if (onlyKeyShare == 0 || onlyKeyShare == 2) { + if (wolfSSL_UseKeyShare(ssl, WOLFSSL_ECC_SECP256R1) + != SSL_SUCCESS) { + err_sys("unable to use curve secp256r1"); + } + if (wolfSSL_UseKeyShare(ssl, WOLFSSL_ECC_SECP384R1) + != SSL_SUCCESS) { + err_sys("unable to use curve secp384r1"); + } } - if (wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP521R1) - != SSL_SUCCESS) { - wolfSSL_free(ssl); - wolfSSL_CTX_free(ctx); - err_sys("unable to set curve secp521r1"); - } - if (wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP224R1) - != SSL_SUCCESS) { - wolfSSL_free(ssl); - wolfSSL_CTX_free(ctx); - err_sys("unable to set curve secp224r1"); - } - if (wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP192R1) - != SSL_SUCCESS) { - wolfSSL_free(ssl); - wolfSSL_CTX_free(ctx); - err_sys("unable to set curve secp192r1"); - } - if (wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP160R1) - != SSL_SUCCESS) { - wolfSSL_free(ssl); - wolfSSL_CTX_free(ctx); - err_sys("unable to set curve secp160r1"); - } - #endif + } + else { + wolfSSL_NoKeyShares(ssl); + } #endif #ifdef HAVE_SESSION_TICKET @@ -1715,6 +1774,11 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #endif #endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ +#ifdef WOLFSSL_TLS13 + if (updateKeysIVs) + wolfSSL_update_keys(ssl); +#endif + do { err = 0; /* reset error */ ret = wolfSSL_write(ssl, msg, msgSz); @@ -1849,45 +1913,21 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) wolfSSL_set_SessionTicket_cb(sslResume, sessionTicketCB, (void*)"resumed session"); #endif - #if 0 /* all enabled and supported ECC curves will be added automatically */ - #ifdef HAVE_SUPPORTED_CURVES /* add curves to supported curves extension */ - if (wolfSSL_UseSupportedCurve(sslResume, WOLFSSL_ECC_SECP256R1) - != SSL_SUCCESS) { - wolfSSL_free(sslResume); - wolfSSL_CTX_free(ctx); - err_sys("unable to set curve secp256r1"); + + #ifdef WOLFSSL_TLS13 + #ifdef HAVE_FFDHE_2048 + if (wolfSSL_UseKeyShare(sslResume, WOLFSSL_FFDHE_2048) != SSL_SUCCESS) { + err_sys("unable to use DH 2048-bit parameters"); } - if (wolfSSL_UseSupportedCurve(sslResume, WOLFSSL_ECC_SECP384R1) - != SSL_SUCCESS) { - wolfSSL_free(sslResume); - wolfSSL_CTX_free(ctx); - err_sys("unable to set curve secp384r1"); + #endif + if (wolfSSL_UseKeyShare(sslResume, + WOLFSSL_ECC_SECP256R1) != SSL_SUCCESS) { + err_sys("unable to use curve secp256r1"); } - if (wolfSSL_UseSupportedCurve(sslResume, WOLFSSL_ECC_SECP521R1) - != SSL_SUCCESS) { - wolfSSL_free(sslResume); - wolfSSL_CTX_free(ctx); - err_sys("unable to set curve secp521r1"); + if (wolfSSL_UseKeyShare(sslResume, + WOLFSSL_ECC_SECP384R1) != SSL_SUCCESS) { + err_sys("unable to use curve secp384r1"); } - if (wolfSSL_UseSupportedCurve(sslResume, WOLFSSL_ECC_SECP224R1) - != SSL_SUCCESS) { - wolfSSL_free(sslResume); - wolfSSL_CTX_free(ctx); - err_sys("unable to set curve secp224r1"); - } - if (wolfSSL_UseSupportedCurve(sslResume, WOLFSSL_ECC_SECP192R1) - != SSL_SUCCESS) { - wolfSSL_free(sslResume); - wolfSSL_CTX_free(ctx); - err_sys("unable to set curve secp192r1"); - } - if (wolfSSL_UseSupportedCurve(sslResume, WOLFSSL_ECC_SECP160R1) - != SSL_SUCCESS) { - wolfSSL_free(sslResume); - wolfSSL_CTX_free(ctx); - err_sys("unable to set curve secp160r1"); - } - #endif #endif #ifndef WOLFSSL_CALLBACKS diff --git a/examples/server/server.c b/examples/server/server.c index 38dcd7136..205c07e0c 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -304,7 +304,11 @@ static void Usage(void) #endif printf("-g Return basic HTML web page\n"); printf("-C The number of connections to accept, default: 1\n"); - printf("-U Force use of the default cipher suite list\n"); + printf("-H Force use of the default cipher suite list\n"); +#ifdef WOLFSSL_TLS13 + printf("-K Key Exchange for PSK not using (EC)DHE\n"); + printf("-U Update keys and IVs before sending\n"); +#endif } THREAD_RETURN CYASSL_THREAD server_test(void* args) @@ -386,6 +390,10 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) const char* wnrConfigFile = wnrConfig; #endif char buffer[CYASSL_MAX_ERROR_SZ]; +#ifdef WOLFSSL_TLS13 + int noPskDheKe = 0; +#endif + int updateKeysIVs = 0; #ifdef WOLFSSL_STATIC_MEMORY #if (defined(HAVE_ECC) && !defined(ALT_ECC_SIZE)) \ @@ -421,6 +429,7 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) (void)alpn_opt; (void)crlFlags; (void)readySignal; + (void)updateKeysIVs; #ifdef CYASSL_TIRTOS fdOpenSession(Task_self()); @@ -429,10 +438,10 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) #ifdef WOLFSSL_VXWORKS useAnyAddr = 1; #else - /* Not Used: h, m, t, x, y, z, F, J, K, M, Q, T, U, V, W, X, Y */ + /* Not Used: h, m, t, x, y, z, F, J, M, Q, T, V, W, X, Y */ while ((ch = mygetopt(argc, argv, "?" "abc:defgijk:l:nop:q:rsuv:w" - "A:B:C:D:E:GHIL:NO:PR:S:YZ:")) != -1) { + "A:B:C:D:E:GHIKL:NO:PR:S:UYZ:")) != -1) { switch (ch) { case '?' : Usage(); @@ -500,7 +509,7 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) case 'v' : version = atoi(myoptarg); - if (version < 0 || version > 3) { + if (version < 0 || version > 4) { Usage(); exit(MY_EX_USAGE); } @@ -634,6 +643,18 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) useWebServerMsg = 1; break; + case 'K' : + #ifdef WOLFSSL_TLS13 + noPskDheKe = 1; + #endif + break; + + case 'U' : + #ifdef WOLFSSL_TLS13 + updateKeysIVs = 1; + #endif + break; + default: Usage(); exit(MY_EX_USAGE); @@ -696,6 +717,12 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) break; #endif +#ifdef WOLFSSL_TLS13 + case 4: + method = wolfTLSv1_3_server_method_ex; + break; +#endif + #ifdef CYASSL_DTLS #ifndef NO_OLD_TLS case -1: @@ -914,6 +941,11 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) wolfSSL_CTX_UseAsync(ctx, devId); #endif /* WOLFSSL_ASYNC_CRYPT */ +#ifdef WOLFSSL_TLS13 + if (noPskDheKe) + wolfSSL_CTX_no_dhe_psk(ctx); +#endif + while (1) { /* allow resume option */ if (resumeCount > 1) { @@ -1174,6 +1206,11 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) printf("Client message: %s\n", input); } +#ifdef WOLFSSL_TLS13 + if (updateKeysIVs) + wolfSSL_update_keys(ssl); +#endif + /* Write data */ if (!useWebServerMsg) { write_msg = msg; diff --git a/scripts/include.am b/scripts/include.am index 0a49b14af..442d758f7 100644 --- a/scripts/include.am +++ b/scripts/include.am @@ -62,6 +62,10 @@ dist_noinst_SCRIPTS+= scripts/openssl.test endif endif +if BUILD_TLS13 +dist_noinst_SCRIPTS+= scripts/tls13.test +endif + EXTRA_DIST += scripts/testsuite.pcap \ scripts/ping.test diff --git a/scripts/tls13.test b/scripts/tls13.test new file mode 100755 index 000000000..ba8287bf5 --- /dev/null +++ b/scripts/tls13.test @@ -0,0 +1,312 @@ +#!/bin/sh + +# tls13.test +# copyright wolfSSL 2016 + +# getting unique port is modeled after resume.test script +# need a unique port since may run the same time as testsuite +# use server port zero hack to get one +port=0 +no_pid=-1 +server_pid=$no_pid +counter=0 +# let's use absolute path to a local dir (make distcheck may be in sub dir) +# also let's add some randomness by adding pid in case multiple 'make check's +# per source tree +ready_file=`pwd`/wolfssl_psk_ready$$ + +echo "ready file $ready_file" + +create_port() { + while [ ! -s $ready_file -a "$counter" -lt 20 ]; do + echo -e "waiting for ready file..." + sleep 0.1 + counter=$((counter+ 1)) + done + + if test -e $ready_file; then + echo -e "found ready file, starting client..." + + # get created port 0 ephemeral port + port=`cat $ready_file` + else + echo -e "NO ready file ending test..." + do_cleanup + fi +} + +remove_ready_file() { + if test -e $ready_file; then + echo -e "removing existing ready file" + rm $ready_file + fi +} + +do_cleanup() { + echo "in cleanup" + + if [ $server_pid != $no_pid ] + then + echo "killing server" + kill -9 $server_pid + fi + remove_ready_file +} + +do_trap() { + echo "got trap" + do_cleanup + exit -1 +} + +trap do_trap INT TERM + +[ ! -x ./examples/client/client ] && echo -e "\n\nClient doesn't exist" && exit 1 + +# Usual TLS v1.3 server / TLS v1.3 client. +echo -e "\n\nTLS v1.3 server with TLS v1.3 client" +port=0 +./examples/server/server -v 4 -R $ready_file -p $port & +server_pid=$! +create_port +./examples/client/client -v 4 -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nTLS v1.3 not enabled" + do_cleanup + exit 1 +fi +echo "" + +# Use HelloRetryRequest with TLS v1.3 server / TLS v1.3 client. +echo -e "\n\nTLS v1.3 HelloRetryRequest" +port=0 +./examples/server/server -v 4 -R $ready_file -p $port & +server_pid=$! +create_port +./examples/client/client -v 4 -H -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nTLS v1.3 HelloRetryRequest not working" + do_cleanup + exit 1 +fi +echo "" + +# Resumption TLS v1.3 server / TLS v1.3 client. +echo -e "\n\nTLS v1.3 resumption" +port=0 +./examples/server/server -v 4 -r -R $ready_file -p $port & +server_pid=$! +create_port +./examples/client/client -v 4 -r -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nTLS v1.3 resumption not working" + do_cleanup + exit 1 +fi +echo "" + +# Usual TLS v1.3 server / TLS v1.3 client and ECC certificates. +echo -e "\n\nTLS v1.3 server with TLS v1.3 client - ECC certificates" +port=0 +./examples/server/server -v 4 -A certs/client-ecc-cert.pem -c certs/server-ecc.pem -k certs/ecc-key.pem -R $ready_file -p $port & +server_pid=$! +create_port +./examples/client/client -v 4 -A certs/server-ecc.pem -c certs/client-ecc-cert.pem -k certs/ecc-client-key.pem -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nTLS v1.3 ECC certificates not working" + do_cleanup + exit 1 +fi +echo "" + +# Usual TLS v1.3 server / TLS v1.3 client and DH Key. +echo -e "\n\nTLS v1.3 server with TLS v1.3 client - DH Key Exchange" +port=0 +./examples/server/server -v 4 -R $ready_file -p $port & +server_pid=$! +create_port +./examples/client/client -v 4 -y -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nTLS v1.3 DH Key Exchange not working" + do_cleanup + exit 1 +fi +echo "" + +# Usual TLS v1.3 server / TLS v1.3 client and ECC Key. +echo -e "\n\nTLS v1.3 server with TLS v1.3 client - ECC Key Exchange" +port=0 +./examples/server/server -v 4 -R $ready_file -p $port & +server_pid=$! +create_port +./examples/client/client -v 4 -Y -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nTLS v1.3 ECDH Key Exchange not working" + do_cleanup + exit 1 +fi +echo "" + +# TLS 1.3 cipher suites server / client. +echo -e "\n\nOnly TLS v1.3 cipher suites" +port=0 +./examples/server/server -v 4 -R $ready_file -p $port -l TLS13-AES128-GCM-SHA256:TLS13-AES256-GCM-SHA384:TLS13-CHACH20-POLY1305-SHA256:TLS13-AES128-CCM-SHA256:TLS13-AES128-CCM-8-SHA256 & +server_pid=$! +create_port +./examples/client/client -v 4 -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nIssue with TLS v1.3 cipher suites - only TLS v1.3" + do_cleanup + exit 1 +fi +echo "" + +# TLS 1.3 cipher suites server / client. +echo -e "\n\nOnly TLS v1.3 cipher suite - AES128-GCM SHA-256" +port=0 +./examples/server/server -v 4 -R $ready_file -p $port -l TLS13-AES128-GCM-SHA256 & +server_pid=$! +create_port +./examples/client/client -v 4 -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nIssue with TLS v1.3 cipher suites - AES128-GCM SHA-256" + do_cleanup + exit 1 +fi +echo "" + +# TLS 1.3 cipher suites server / client. +echo -e "\n\nOnly TLS v1.3 cipher suite - AES256-GCM SHA-384" +port=0 +./examples/server/server -v 4 -R $ready_file -p $port -l TLS13-AES256-GCM-SHA384 & +server_pid=$! +create_port +./examples/client/client -v 4 -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nIssue with TLS v1.3 cipher suites - AES256-GCM SHA-384" + do_cleanup + exit 1 +fi +echo "" + +# TLS 1.3 cipher suites server / client. +echo -e "\n\nOnly TLS v1.3 cipher suite - CHACHA20-POLY1305 SHA-256" +port=0 +./examples/server/server -v 4 -R $ready_file -p $port -l TLS13-CHACH20-POLY1305-SHA256 & +server_pid=$! +create_port +./examples/client/client -v 4 -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nIssue with TLS v1.3 cipher suites - CHACHA20-POLY1305 SHA-256" + do_cleanup + exit 1 +fi +echo "" + +./examples/client/client -v 4 -e 2>&1 | grep -- '-CCM' +if [ $? -eq 0 ]; then + # TLS 1.3 cipher suites server / client. + echo -e "\n\nOnly TLS v1.3 cipher suite - AES128-CCM SHA-256" + port=0 + ./examples/server/server -v 4 -R $ready_file -p $port -l TLS13-AES128-CCM-SHA256 & + server_pid=$! + create_port + ./examples/client/client -v 4 -p $port + RESULT=$? + remove_ready_file + if [ $RESULT -ne 0 ]; then + echo -e "\n\nIssue with TLS v1.3 cipher suites - AES128-CCM SHA-256" + do_cleanup + exit 1 + fi + echo "" + + # TLS 1.3 cipher suites server / client. + echo -e "\n\nOnly TLS v1.3 cipher suite - AES128-CCM-8 SHA-256" + port=0 + ./examples/server/server -v 4 -R $ready_file -p $port -l TLS13-AES128-CCM-8-SHA256 & + server_pid=$! + create_port + ./examples/client/client -v 4 -p $port + RESULT=$? + remove_ready_file + if [ $RESULT -ne 0 ]; then + echo -e "\n\nIssue with TLS v1.3 cipher suites - AES128-CCM-8 SHA-256" + do_cleanup + exit 1 + fi + echo "" +fi + +# TLS 1.3 server / TLS 1.2 client. +echo -e "\n\nTLS v1.3 server downgrading to TLS v1.2" +port=0 +./examples/server/server -v 4 -R $ready_file -p $port & +server_pid=$! +create_port +./examples/client/client -v 3 -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nIssue with TLS v1.3 server downgrading to TLS v1.2" + do_cleanup + exit 1 +fi +echo "" + +# TLS 1.2 server / TLS 1.3 client. +echo -e "\n\nTLS v1.3 client downgrading to TLS v1.2" +port=0 +./examples/server/server -v 3 -R $ready_file -p $port & +server_pid=$! +create_port +./examples/client/client -v 4 -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nIssue with TLS v1.3 client downgrading to TLS v1.2" + do_cleanup + exit 1 +fi +echo "" + +# TLS 1.3 server / TLS 1.3 client send KeyUpdate before sending app data. +echo -e "\n\nTLS v1.3 KeyUpdate" +port=0 +./examples/server/server -v 4 -U -R $ready_file -p $port & +server_pid=$! +create_port +./examples/client/client -v 4 -I -p $port +RESULT=$? +remove_ready_file +if [ $RESULT -ne 0 ]; then + echo -e "\n\nIssue with TLS v1.3 KeyUpdate" + do_cleanup + exit 1 +fi +echo "" + +echo -e "\nALL Tests Passed" + +exit 0 + diff --git a/src/include.am b/src/include.am index 031e9645c..b8dd4951d 100644 --- a/src/include.am +++ b/src/include.am @@ -262,7 +262,8 @@ src_libwolfssl_la_SOURCES += \ src/io.c \ src/keys.c \ src/ssl.c \ - src/tls.c + src/tls.c \ + src/tls13.c if BUILD_OCSP src_libwolfssl_la_SOURCES += src/ocsp.c diff --git a/src/internal.c b/src/internal.c index e220d8843..1d45461c0 100755 --- a/src/internal.c +++ b/src/internal.c @@ -85,7 +85,6 @@ WOLFSSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS #ifndef NO_WOLFSSL_CLIENT static int DoHelloVerifyRequest(WOLFSSL* ssl, const byte* input, word32*, word32); - static int DoServerHello(WOLFSSL* ssl, const byte* input, word32*, word32); static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, word32*, word32); #ifndef NO_CERTS @@ -100,14 +99,10 @@ WOLFSSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS #ifndef NO_WOLFSSL_SERVER - static int DoClientHello(WOLFSSL* ssl, const byte* input, word32*, word32); static int DoClientKeyExchange(WOLFSSL* ssl, byte* input, word32*, word32); #if !defined(NO_RSA) || defined(HAVE_ECC) static int DoCertificateVerify(WOLFSSL* ssl, byte*, word32*, word32); #endif - #if defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined (WOLFSSL_HAPROXY) - static int SNI_Callback(WOLFSSL* ssl); - #endif #ifdef WOLFSSL_DTLS static int SendHelloVerifyRequest(WOLFSSL*, const byte*, byte); #endif /* WOLFSSL_DTLS */ @@ -148,16 +143,6 @@ enum cipherState { CIPHER_STATE_END, }; -/* sub-states for send/do key share (key exchange) */ -enum asyncState { - TLS_ASYNC_BEGIN = 0, - TLS_ASYNC_BUILD, - TLS_ASYNC_DO, - TLS_ASYNC_VERIFY, - TLS_ASYNC_FINALIZE, - TLS_ASYNC_END -}; - #ifndef NO_OLD_TLS static int SSL_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, @@ -165,10 +150,6 @@ static int SSL_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, #endif -#ifndef NO_CERTS -static int BuildCertHashes(WOLFSSL* ssl, Hashes* hashes); -#endif - #ifdef HAVE_QSH int QSH_Init(WOLFSSL* ssl); #endif @@ -193,6 +174,11 @@ int IsAtLeastTLSv1_2(const WOLFSSL* ssl) return 0; } +int IsAtLeastTLSv1_3(const ProtocolVersion pv) +{ + return (pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_3_MINOR); +} + static INLINE int IsEncryptionOn(WOLFSSL* ssl, int isSend) { @@ -883,9 +869,15 @@ static int dtls_export_new(WOLFSSL* ssl, byte* exp, word32 len, byte ver) #ifdef HAVE_SESSION_TICKET exp[idx++] = options->createTicket; exp[idx++] = options->useTicket; +#ifdef WOLFSSL_TLS13 + exp[idx++] = options->noTicketTls13; +#endif #else exp[idx++] = 0; exp[idx++] = 0; +#ifdef WOLFSSL_TLS13 + exp[idx++] = 0; +#endif #endif exp[idx++] = options->processReply; exp[idx++] = options->cipherSuite0; @@ -1002,11 +994,17 @@ static int dtls_export_load(WOLFSSL* ssl, byte* exp, word32 len, byte ver) idx++; #endif #ifdef HAVE_SESSION_TICKET - options->createTicket = exp[idx++]; /* Server to create new Ticket */ - options->useTicket = exp[idx++]; /* Use Ticket not session cache */ + options->createTicket = exp[idx++]; /* Server to create new Ticket */ + options->useTicket = exp[idx++]; /* Use Ticket not session cache */ +#ifdef WOLFSSL_TLS13 + options->noTicketTls13 = exp[idx++]; /* Server won't create new Ticket */ +#endif #else idx++; idx++; +#ifdef WOLFSSL_TLS13 + idx++; +#endif #endif options->processReply = exp[idx++]; options->cipherSuite0 = exp[idx++]; @@ -1757,6 +1755,9 @@ void InitSuites(Suites* suites, ProtocolVersion pv, word16 haveRSA, word16 idx = 0; int tls = pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_MINOR; int tls1_2 = pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_2_MINOR; +#ifdef WOLFSSL_TLS13 + int tls1_3 = IsAtLeastTLSv1_3(pv); +#endif int dtls = 0; int haveRSAsig = 1; @@ -1840,6 +1841,43 @@ void InitSuites(Suites* suites, ProtocolVersion pv, word16 haveRSA, } #endif +#ifdef WOLFSSL_TLS13 +#ifdef BUILD_TLS_AES_128_GCM_SHA256 + if (tls1_3) { + suites->suites[idx++] = TLS13_BYTE; + suites->suites[idx++] = TLS_AES_128_GCM_SHA256; + } +#endif + +#ifdef BUILD_TLS_AES_256_GCM_SHA384 + if (tls1_3) { + suites->suites[idx++] = TLS13_BYTE; + suites->suites[idx++] = TLS_AES_256_GCM_SHA384; + } +#endif + +#ifdef BUILD_TLS_CHACHA20_POLY1305_SHA256 + if (tls1_3) { + suites->suites[idx++] = TLS13_BYTE; + suites->suites[idx++] = TLS_CHACHA20_POLY1305_SHA256; + } +#endif + +#ifdef BUILD_TLS_AES_128_CCM_SHA256 + if (tls1_3) { + suites->suites[idx++] = TLS13_BYTE; + suites->suites[idx++] = TLS_AES_128_CCM_SHA256; + } +#endif + +#ifdef BUILD_TLS_AES_128_CCM_8_SHA256 + if (tls1_3) { + suites->suites[idx++] = TLS13_BYTE; + suites->suites[idx++] = TLS_AES_128_CCM_8_SHA256; + } +#endif +#endif /* WOLFSSL_TLS13 */ + #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 if (tls1_2 && haveECC) { suites->suites[idx++] = ECC_BYTE; @@ -3165,12 +3203,10 @@ int DhAgree(WOLFSSL* ssl, DhKey* dhKey, return ret; } - #endif /* !NO_DH */ #endif /* !NO_CERTS || !NO_PSK */ - /* This function inherits a WOLFSSL_CTX's fields into an SSL object. It is used during initialization and to switch an ssl's CTX with wolfSSL_Set_SSL_CTX. Requires ssl->suites alloc and ssl-arrays with PSK @@ -3296,6 +3332,9 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) /* ctx still owns certificate, certChain, key, dh, and cm */ ssl->buffers.certificate = ctx->certificate; ssl->buffers.certChain = ctx->certChain; +#ifdef WOLFSSL_TLS13 + ssl->buffers.certChainCnt = ctx->certChainCnt; +#endif ssl->buffers.key = ctx->privateKey; #endif @@ -3356,7 +3395,7 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) return SSL_SUCCESS; } -static int InitHashes(WOLFSSL* ssl) +int InitHandshakeHashes(WOLFSSL* ssl) { int ret; @@ -3399,7 +3438,7 @@ static int InitHashes(WOLFSSL* ssl) return ret; } -static void FreeHashes(WOLFSSL* ssl) +void FreeHandshakeHashes(WOLFSSL* ssl) { if (ssl->hsHashes) { #ifndef NO_OLD_TLS @@ -3596,6 +3635,13 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) #endif ssl->options.useClientOrder = ctx->useClientOrder; +#ifdef WOLFSSL_TLS13 +#ifdef HAVE_SESSION_TICKET + ssl->options.noTicketTls13 = ctx->noTicketTls13; +#endif + ssl->options.noPskDheKe = ctx->noPskDheKe; +#endif + #ifdef HAVE_TLS_EXTENSIONS #ifdef HAVE_MAX_FRAGMENT ssl->max_fragment = MAX_RECORD_SIZE; @@ -3689,7 +3735,7 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) } /* hsHashes */ - ret = InitHashes(ssl); + ret = InitHandshakeHashes(ssl); if (ret != 0) return ret; @@ -3840,7 +3886,7 @@ int AllocKey(WOLFSSL* ssl, int type, void** pKey) return ret; } -static void FreeKeyExchange(WOLFSSL* ssl) +void FreeKeyExchange(WOLFSSL* ssl) { /* Cleanup signature buffer */ if (ssl->buffers.sig.buffer) { @@ -3890,7 +3936,7 @@ void SSL_ResourceFree(WOLFSSL* ssl) XFREE(ssl->rng, ssl->heap, DYNAMIC_TYPE_RNG); } XFREE(ssl->suites, ssl->heap, DYNAMIC_TYPE_SUITES); - FreeHashes(ssl); + FreeHandshakeHashes(ssl); XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN); /* clear keys struct after session */ @@ -4052,7 +4098,7 @@ void FreeHandshakeResources(WOLFSSL* ssl) ssl->suites = NULL; /* hsHashes */ - FreeHashes(ssl); + FreeHandshakeHashes(ssl); /* RNG */ if (ssl->specs.cipher_type == stream || ssl->options.tls1_1 == 0) { @@ -4898,7 +4944,7 @@ ProtocolVersion MakeDTLSv1_2(void) #ifndef NO_CERTS -static int HashOutputRaw(WOLFSSL* ssl, const byte* output, int sz) +int HashOutputRaw(WOLFSSL* ssl, const byte* output, int sz) { int ret = 0; @@ -4942,7 +4988,7 @@ static int HashOutputRaw(WOLFSSL* ssl, const byte* output, int sz) /* add output to md5 and sha handshake hashes, exclude record header */ -static int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz) +int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz) { int ret = 0; const byte* adj; @@ -4992,7 +5038,7 @@ static int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz) /* add input to md5 and sha handshake hashes, include handshake header */ -static int HashInput(WOLFSSL* ssl, const byte* input, int sz) +int HashInput(WOLFSSL* ssl, const byte* input, int sz) { int ret = 0; const byte* adj; @@ -5052,7 +5098,12 @@ static void AddRecordHeader(byte* output, word32 length, byte type, WOLFSSL* ssl } rl->type = type; rl->pvMajor = ssl->version.major; /* type and version same in each */ - rl->pvMinor = ssl->version.minor; +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + rl->pvMinor = TLSv1_MINOR; + else +#endif + rl->pvMinor = ssl->version.minor; #ifdef WOLFSSL_ALTERNATIVE_DOWNGRADE if (ssl->options.side == WOLFSSL_CLIENT_END @@ -5262,6 +5313,11 @@ int SendBuffered(WOLFSSL* ssl) return SOCKET_ERROR_E; } + if (ssl->buffers.outputBuffer.idx == 0) { + WOLFSSL_MSG("Data to send"); + WOLFSSL_BUFFER(ssl->buffers.outputBuffer.buffer, + ssl->buffers.outputBuffer.length); + } while (ssl->buffers.outputBuffer.length > 0) { int sent = ssl->ctx->CBIOSend(ssl, (char*)ssl->buffers.outputBuffer.buffer + @@ -5536,7 +5592,14 @@ static int GetRecordHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif /* OPENSSL_EXTRA */ /* catch version mismatch */ - if (rh->pvMajor != ssl->version.major || rh->pvMinor != ssl->version.minor){ +#ifndef WOLFSSL_TLS13 + if (rh->pvMajor != ssl->version.major || rh->pvMinor != ssl->version.minor) +#else + if (rh->pvMajor != ssl->version.major || + (rh->pvMinor != ssl->version.minor && + (!IsAtLeastTLSv1_3(ssl->version) || rh->pvMinor != TLSv1_MINOR))) +#endif + { if (ssl->options.side == WOLFSSL_SERVER_END && ssl->options.acceptState < ACCEPT_FIRST_REPLY_DONE) @@ -6126,7 +6189,29 @@ static int BuildFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender) return 0; } /* switch */ } /* if */ - if (first != ECC_BYTE && first != CHACHA_BYTE) { /* normal suites */ + + /* Distinct TLS v1.3 cipher suites with cipher and digest only. */ + if (first == TLS13_BYTE) { + + switch (second) { +#ifdef WOLFSSL_TLS13 + case TLS_AES_128_GCM_SHA256: + case TLS_AES_256_GCM_SHA384: + case TLS_CHACHA20_POLY1305_SHA256: + case TLS_AES_128_CCM_SHA256: + case TLS_AES_128_CCM_8_SHA256: + break; +#endif + + default: + WOLFSSL_MSG("Unsupported cipher suite, CipherRequires " + "TLS v1.3"); + return 0; + } + } + + if (first != ECC_BYTE && first != CHACHA_BYTE && + first != TLS13_BYTE) { /* normal suites */ switch (second) { #ifndef NO_RSA @@ -6345,7 +6430,7 @@ static int BuildFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender) *.z.com matches y.z.com but not x.y.z.com return 1 on success */ -static int MatchDomainName(const char* pattern, int len, const char* str) +int MatchDomainName(const char* pattern, int len, const char* str) { char p, s; @@ -6391,7 +6476,7 @@ static int MatchDomainName(const char* pattern, int len, const char* str) /* try to find an altName match to domain, return 1 on success */ -static int CheckAltNames(DecodedCert* dCert, char* domain) +int CheckAltNames(DecodedCert* dCert, char* domain) { int match = 0; DNS_entry* altName = NULL; @@ -8201,7 +8286,6 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) WOLFSSL_MSG("Finished received before ChangeCipher"); return NO_CHANGE_CIPHER_E; } - break; case change_cipher_hs: @@ -8277,6 +8361,13 @@ static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, WOLFSSL_ENTER("DoHandShakeMsgType"); +#ifdef WOLFSSL_TLS13 + if (type == hello_retry_request) { + return DoTls13HandShakeMsgType(ssl, input, inOutIdx, type, size, + totalSz); + } +#endif + /* make sure can read the message */ if (*inOutIdx + size > totalSz) return INCOMPLETE_DATA; @@ -8551,7 +8642,6 @@ static int DoHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, return ret; } - #ifdef WOLFSSL_DTLS static INLINE int DtlsCheckWindow(WOLFSSL* ssl) @@ -9667,6 +9757,20 @@ static INLINE int Decrypt(WOLFSSL* ssl, byte* plain, const byte* input, return ret; } +/* Check conditions for a cipher to have an explicit IV. + * + * ssl The SSL/TLS object. + * returns 1 if the cipher in use has an explicit IV and 0 otherwise. + */ +static INLINE int CipherHasExpIV(WOLFSSL *ssl) +{ +#ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return 0; +#endif + return (ssl->specs.cipher_type == aead) && + (ssl->specs.bulk_cipher_algorithm != wolfssl_chacha); +} /* check cipher text size for sanity */ static int SanityCheckCipherText(WOLFSSL* ssl, word32 encryptSz) @@ -9694,8 +9798,8 @@ static int SanityCheckCipherText(WOLFSSL* ssl, word32 encryptSz) } else if (ssl->specs.cipher_type == aead) { minLength = ssl->specs.aead_mac_size; /* authTag size */ - if (ssl->specs.bulk_cipher_algorithm != wolfssl_chacha) - minLength += AESGCM_EXP_IV_SZ; /* explicit IV */ + if (CipherHasExpIV(ssl)) + minLength += AESGCM_EXP_IV_SZ; /* explicit IV */ } if (encryptSz < minLength) { @@ -9985,7 +10089,7 @@ int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx) ivExtra = ssl->specs.block_size; } else if (ssl->specs.cipher_type == aead) { - if (ssl->specs.bulk_cipher_algorithm != wolfssl_chacha) + if (CipherHasExpIV(ssl)) ivExtra = AESGCM_EXP_IV_SZ; } @@ -10059,6 +10163,14 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type, WOLFSSL_MSG("\tclose notify"); ssl->options.closeNotify = 1; } +#ifdef WOLFSSL_TLS13 + if (*type == decode_error) { + WOLFSSL_MSG(" decode error"); + } + if (*type == illegal_parameter) { + WOLFSSL_MSG(" illegal parameter"); + } +#endif WOLFSSL_ERROR(*type); if (IsEncryptionOn(ssl, 0)) { if (*inOutIdx + ssl->keys.padSz > totalSz) @@ -10131,6 +10243,12 @@ static int GetInputData(WOLFSSL *ssl, word32 size) } while (ssl->buffers.inputBuffer.length < size); + if (ssl->buffers.inputBuffer.idx == 0) { + WOLFSSL_MSG("Data received"); + WOLFSSL_BUFFER(ssl->buffers.inputBuffer.buffer, + ssl->buffers.inputBuffer.length); + } + return 0; } @@ -10381,6 +10499,8 @@ int ProcessReply(WOLFSSL* ssl) case decryptMessage: if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0) { + bufferStatic* in = &ssl->buffers.inputBuffer; + ret = SanityCheckCipherText(ssl, ssl->curSize); if (ret < 0) return ret; @@ -10388,21 +10508,31 @@ int ProcessReply(WOLFSSL* ssl) if (atomicUser) { #ifdef ATOMIC_USER ret = ssl->ctx->DecryptVerifyCb(ssl, - ssl->buffers.inputBuffer.buffer + - ssl->buffers.inputBuffer.idx, - ssl->buffers.inputBuffer.buffer + - ssl->buffers.inputBuffer.idx, + in->buffer + in->idx, + in->buffer + in->idx, ssl->curSize, ssl->curRL.type, 1, &ssl->keys.padSz, ssl->DecryptVerifyCtx); #endif /* ATOMIC_USER */ } else { - ret = Decrypt(ssl, ssl->buffers.inputBuffer.buffer + - ssl->buffers.inputBuffer.idx, - ssl->buffers.inputBuffer.buffer + - ssl->buffers.inputBuffer.idx, - ssl->curSize); + if (!ssl->options.tls1_3) { + ret = Decrypt(ssl, + in->buffer + in->idx, + in->buffer + in->idx, + ssl->curSize); + } + else { + #ifdef WOLFSSL_TLS13 + ret = DecryptTls13(ssl, + in->buffer + in->idx, + in->buffer + in->idx, + ssl->curSize); + #else + ret = DECRYPT_ERROR; + #endif /* WOLFSSL_TLS13 */ + } } + #ifdef WOLFSSL_ASYNC_CRYPT if (ret == WC_PENDING_E) return ret; @@ -10413,8 +10543,7 @@ int ProcessReply(WOLFSSL* ssl) if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) ssl->buffers.inputBuffer.idx += ssl->specs.block_size; /* go past TLSv1.1 IV */ - if (ssl->specs.cipher_type == aead && - ssl->specs.bulk_cipher_algorithm != wolfssl_chacha) + if (CipherHasExpIV(ssl)) ssl->buffers.inputBuffer.idx += AESGCM_EXP_IV_SZ; } else { @@ -10429,6 +10558,7 @@ int ProcessReply(WOLFSSL* ssl) ssl->buffers.inputBuffer.length; } #endif /* WOLFSSL_DTLS */ + return DECRYPT_ERROR; } } @@ -10457,6 +10587,14 @@ int ProcessReply(WOLFSSL* ssl) ssl->keys.encryptSz = ssl->curSize; ssl->keys.decryptedCur = 1; +#ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) { + /* Get the real content type from the end of the data. */ + ssl->keys.padSz++; + ssl->curRL.type = ssl->buffers.inputBuffer.buffer[ + ssl->buffers.inputBuffer.length - ssl->keys.padSz]; + } +#endif } ssl->options.processReply = runProcessingOneMessage; @@ -10475,19 +10613,29 @@ int ProcessReply(WOLFSSL* ssl) switch (ssl->curRL.type) { case handshake : /* debugging in DoHandShakeMsg */ - if (!ssl->options.dtls) { + if (ssl->options.dtls) { +#ifdef WOLFSSL_DTLS + ret = DoDtlsHandShakeMsg(ssl, + ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, + ssl->buffers.inputBuffer.length); +#endif + } + else if (!IsAtLeastTLSv1_3(ssl->version)) { ret = DoHandShakeMsg(ssl, ssl->buffers.inputBuffer.buffer, &ssl->buffers.inputBuffer.idx, ssl->buffers.inputBuffer.length); } else { - #ifdef WOLFSSL_DTLS - ret = DoDtlsHandShakeMsg(ssl, +#ifdef WOLFSSL_TLS13 + ret = DoTls13HandShakeMsg(ssl, ssl->buffers.inputBuffer.buffer, &ssl->buffers.inputBuffer.idx, ssl->buffers.inputBuffer.length); - #endif +#else + ret = BUFFER_ERROR; +#endif } if (ret != 0) return ret; @@ -10589,6 +10737,12 @@ int ProcessReply(WOLFSSL* ssl) ssl->options.dtlsHsRetain = 0; } #endif + #ifdef WOLFSSL_TLS13 + if (ssl->keys.keyUpdateRespond) { + WOLFSSL_MSG("No KeyUpdate from peer seen"); + return SANITY_MSG_E; + } + #endif if ((ret = DoApplicationData(ssl, ssl->buffers.inputBuffer.buffer, &ssl->buffers.inputBuffer.idx)) @@ -10937,7 +11091,7 @@ static int BuildSHA_CertVerify(WOLFSSL* ssl, byte* digest) } #endif /* !NO_SHA && (!NO_OLD_TLS || WOLFSSL_ALLOW_TLS_SHA1) */ -static int BuildCertHashes(WOLFSSL* ssl, Hashes* hashes) +int BuildCertHashes(WOLFSSL* ssl, Hashes* hashes) { int ret = 0; @@ -11031,7 +11185,20 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, WOLFSSL_ENTER("BuildMessage"); - if (ssl == NULL || output == NULL) { + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + +#ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) { + return BuildTls13Message(ssl, output, outSz, input, inSz, type, + hashOutput, sizeOnly); + } +#endif + + /* catch mistaken sizeOnly parameter */ + if (sizeOnly && (output || input) ) { + WOLFSSL_MSG("BuildMessage with sizeOnly doesn't need input or output"); return BAD_FUNC_ARG; } @@ -12237,13 +12404,23 @@ int SendData(WOLFSSL* ssl, const void* data, int sz) sendBuffer = comp; } #endif - sendSz = BuildMessage(ssl, out, outputSz, sendBuffer, buffSz, - application_data, 0, 0, 1); + if (!ssl->options.tls1_3) { + sendSz = BuildMessage(ssl, out, outputSz, sendBuffer, buffSz, + application_data, 0, 0, 1); + } + else { +#ifdef WOLFSSL_TLS13 + sendSz = BuildTls13Message(ssl, out, outputSz, sendBuffer, buffSz, + application_data, 0, 0); +#else + sendSz = BUFFER_ERROR; +#endif + } if (sendSz < 0) { - #ifdef WOLFSSL_ASYNC_CRYPT +#ifdef WOLFSSL_ASYNC_CRYPT if (sendSz == WC_PENDING_E) ssl->error = sendSz; - #endif +#endif return BUILD_MSG_ERROR; } @@ -12841,6 +13018,27 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case WRITE_DUP_WRITE_E: return "Write dup read side can't write error"; + case INVALID_CERT_CTX_E: + return "Certificate context does not match request or not empty"; + + case BAD_KEY_SHARE_DATA: + return "The Key Share data contains group that was in Client Hello"; + + case MISSING_HANDSHAKE_DATA: + return "The handshake message is missing required data"; + + case BAD_BINDER: + return "Binder value does not match value server calculated"; + + case EXT_NOT_ALLOWED: + return "Extension type not allowed in handshake message type"; + + case INVALID_PARAMETER: + return "The security parameter is invalid"; + + case KEY_SHARE_ERROR: + return "Key share extension did not contain a valid named group"; + default : return "unknown error number"; } @@ -13296,6 +13494,27 @@ static const char* const cipher_names[] = #ifdef BUILD_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA "EDH-RSA-DES-CBC3-SHA", #endif + +#ifdef BUILD_TLS_AES_128_GCM_SHA256 + "TLS13-AES128-GCM-SHA256", +#endif + +#ifdef BUILD_TLS_AES_256_GCM_SHA384 + "TLS13-AES256-GCM-SHA384", +#endif + +#ifdef BUILD_TLS_CHACHA20_POLY1305_SHA256 + "TLS13-CHACH20-POLY1305-SHA256", +#endif + +#ifdef BUILD_TLS_AES_128_CCM_SHA256 + "TLS13-AES128-CCM-SHA256", +#endif + +#ifdef BUILD_TLS_AES_128_CCM_8_SHA256 + "TLS13-AES128-CCM-8-SHA256", +#endif + }; @@ -13742,6 +13961,27 @@ static int cipher_name_idx[] = #ifdef BUILD_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, #endif + +#ifdef BUILD_TLS_AES_128_GCM_SHA256 + TLS_AES_128_GCM_SHA256, +#endif + +#ifdef BUILD_TLS_AES_256_GCM_SHA384 + TLS_AES_256_GCM_SHA384, +#endif + +#ifdef BUILD_TLS_CHACHA20_POLY1305_SHA256 + TLS_CHACHA20_POLY1305_SHA256, +#endif + +#ifdef BUILD_TLS_AES_128_CCM_SHA256 + TLS_AES_128_CCM_SHA256, +#endif + +#ifdef BUILD_TLS_AES_128_CCM_8_SHA256 + TLS_AES_128_CCM_8_SHA256, +#endif + }; @@ -14018,8 +14258,38 @@ const char* wolfSSL_get_cipher_name_from_suite(const unsigned char cipherSuite, } /* ECC and AES CCM/GCM */ #endif /* HAVE_ECC || HAVE_AESCCM*/ + if (cipherSuite0 == TLS13_BYTE) { + /* TLS v1.3 suites */ + switch (cipherSuite) { +#ifdef WOLFSSL_TLS13 + #ifdef HAVE_AESGCM + case TLS_AES_128_GCM_SHA256 : + return "TLS_AES_128_GCM_SHA256"; + case TLS_AES_256_GCM_SHA384 : + return "TLS_AES_256_GCM_SHA384"; + #endif + + #ifdef HAVE_CHACHA + case TLS_CHACHA20_POLY1305_SHA256 : + return "TLS_CHACHA20_POLY1305_SHA256"; + #endif + + #ifdef HAVE_AESCCM + case TLS_AES_128_CCM_SHA256 : + return "TLS_AES_128_CCM_SHA256"; + case TLS_AES_128_CCM_8_SHA256 : + return "TLS_AES_256_CCM_8_SHA256"; + #endif +#endif + + default: + return "NONE"; + } + } + if (cipherSuite0 != ECC_BYTE && - cipherSuite0 != CHACHA_BYTE) { + cipherSuite0 != CHACHA_BYTE && + cipherSuite0 != TLS13_BYTE) { /* normal suites */ switch (cipherSuite) { @@ -14270,6 +14540,7 @@ int SetCipherList(WOLFSSL_CTX* ctx, Suites* suites, const char* list) suites->suites[idx++] = (XSTRSTR(name, "CHACHA")) ? CHACHA_BYTE : (XSTRSTR(name, "QSH")) ? QSH_BYTE + : (XSTRSTR(name, "TLS13")) ? TLS13_BYTE : (XSTRSTR(name, "EC")) ? ECC_BYTE : (XSTRSTR(name, "CCM")) ? ECC_BYTE : 0x00; /* normal */ @@ -14277,7 +14548,11 @@ int SetCipherList(WOLFSSL_CTX* ctx, Suites* suites, const char* list) /* The suites are either ECDSA, RSA, PSK, or Anon. The RSA * suites don't necessarily have RSA in the name. */ - if ((haveECDSAsig == 0) && XSTRSTR(name, "ECDSA")) + if (XSTRSTR(name, "TLS13")) { + haveRSAsig = 1; + haveECDSAsig = 1; + } + else if ((haveECDSAsig == 0) && XSTRSTR(name, "ECDSA")) haveECDSAsig = 1; else if (XSTRSTR(name, "ADH")) haveAnon = 1; @@ -14303,8 +14578,7 @@ int SetCipherList(WOLFSSL_CTX* ctx, Suites* suites, const char* list) } #if !defined(NO_WOLFSSL_SERVER) || !defined(NO_CERTS) -static void PickHashSigAlgo(WOLFSSL* ssl, - const byte* hashSigAlgo, word32 hashSigAlgoSz) +void PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo, word32 hashSigAlgoSz) { word32 i; @@ -14347,6 +14621,9 @@ static void PickHashSigAlgo(WOLFSSL* ssl, } #endif } + else if (ssl->specs.sig_algo == 0) { + ssl->suites->hashAlgo = ssl->specs.mac_algorithm; + } } } #endif /* !defined(NO_WOLFSSL_SERVER) || !defined(NO_CERTS) */ @@ -14511,6 +14788,12 @@ static void PickHashSigAlgo(WOLFSSL* ssl, int ret; word16 extSz = 0; + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + return SendTls13ClientHello(ssl); +#endif + if (ssl->suites == NULL) { WOLFSSL_MSG("Bad suites pointer in SendClientHello"); return SUITES_ERROR; @@ -14792,36 +15075,34 @@ static void PickHashSigAlgo(WOLFSSL* ssl, return ret; } - static int DoServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, - word32 helloSz) + /* Check the version in the received message is valid and set protocol + * version to use. + * + * ssl The SSL/TLS object. + * pv The protocol version from the packet. + * returns 0 on success, otherwise failure. + */ + int CheckVersion(WOLFSSL *ssl, ProtocolVersion pv) { - byte cs0; /* cipher suite bytes 0, 1 */ - byte cs1; - ProtocolVersion pv; - byte compression; - word32 i = *inOutIdx; - word32 begin = i; - -#ifdef WOLFSSL_CALLBACKS - if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo); - if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo); +#ifdef WOLFSSL_TLS13 + /* TODO: [TLS13] Remove this. + * Translate the draft TLS v1.3 version to final version. + */ + if (pv.major == TLS_DRAFT_MAJOR) { + pv.major = SSLv3_MAJOR; + pv.minor = TLSv1_3_MINOR; + } #endif - /* protocol version, random and session id length check */ - if (OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz) - return BUFFER_ERROR; - - /* protocol version */ - XMEMCPY(&pv, input + i, OPAQUE16_LEN); - i += OPAQUE16_LEN; - + /* Check for upgrade attack. */ if (pv.minor > ssl->version.minor) { WOLFSSL_MSG("Server using higher version, fatal error"); return VERSION_ERROR; } - else if (pv.minor < ssl->version.minor) { + if (pv.minor < ssl->version.minor) { WOLFSSL_MSG("server using lower version"); + /* Check for downgrade attack. */ if (!ssl->options.downgrade) { WOLFSSL_MSG("\tno downgrade allowed, fatal error"); return VERSION_ERROR; @@ -14840,6 +15121,7 @@ static void PickHashSigAlgo(WOLFSSL* ssl, } #endif + /* Checks made - OK to downgrade. */ if (pv.minor == SSLv3_MINOR) { /* turn off tls */ WOLFSSL_MSG("\tdowngrading to SSLv3"); @@ -14857,8 +15139,48 @@ static void PickHashSigAlgo(WOLFSSL* ssl, WOLFSSL_MSG("\tdowngrading to TLSv1.1"); ssl->version.minor = TLSv1_1_MINOR; } + else if (pv.minor == TLSv1_2_MINOR) { + WOLFSSL_MSG(" downgrading to TLSv1.2"); + ssl->version.minor = TLSv1_2_MINOR; + } } + return 0; + } + + int DoServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 helloSz) + { + byte cs0; /* cipher suite bytes 0, 1 */ + byte cs1; + ProtocolVersion pv; + byte compression; + word32 i = *inOutIdx; + word32 begin = i; + int ret; + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo); +#endif + + /* protocol version, random and session id length check */ + if (OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + + /* protocol version */ + XMEMCPY(&pv, input + i, OPAQUE16_LEN); + i += OPAQUE16_LEN; + + ret = CheckVersion(ssl, pv); + if (ret != 0) + return ret; + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(pv)) + return DoTls13ServerHello(ssl, input, inOutIdx, helloSz); +#endif + /* random */ XMEMCPY(ssl->arrays->serverRandom, input + i, RAN_LEN); i += RAN_LEN; @@ -14919,7 +15241,6 @@ static void PickHashSigAlgo(WOLFSSL* ssl, #ifdef HAVE_TLS_EXTENSIONS if ( (i - begin) < helloSz) { if (TLSX_SupportExtensions(ssl)) { - int ret = 0; word16 totalExtSz; if ((i - begin) + OPAQUE16_LEN > helloSz) @@ -15012,7 +15333,7 @@ static void PickHashSigAlgo(WOLFSSL* ssl, #ifdef HAVE_SECRET_CALLBACK if (ssl->sessionSecretCb != NULL) { - int secretSz = SECRET_LEN, ret; + int secretSz = SECRET_LEN; ret = ssl->sessionSecretCb(ssl, ssl->session.masterSecret, &secretSz, ssl->sessionSecretCtx); if (ret != 0 || secretSz != SECRET_LEN) @@ -15023,7 +15344,7 @@ static void PickHashSigAlgo(WOLFSSL* ssl, if (ssl->options.resuming) { if (DSH_CheckSessionId(ssl)) { if (SetCipherSpecs(ssl) == 0) { - int ret = -1; + ret = -1; XMEMCPY(ssl->arrays->masterSecret, ssl->session.masterSecret, SECRET_LEN); @@ -17404,6 +17725,106 @@ exit_scke: #ifndef NO_CERTS +/* Decode the private key - RSA or ECC - and creates a key object. + * The signature type is set as well. + * The maximum length of a signature is returned. + * + * ssl The SSL/TLS object. + * length The length of a signature. + * returns 0 on success, otherwise failure. + */ +int DecodePrivateKey(WOLFSSL *ssl, word16* length) +{ + int ret; + int keySz; + word32 idx; + + /* make sure private key exists */ + if (ssl->buffers.key == NULL || ssl->buffers.key->buffer == NULL) { + WOLFSSL_MSG("Private key missing!"); + ERROR_OUT(NO_PRIVATE_KEY, exit_dpk); + } + +#ifndef NO_RSA + ssl->hsType = DYNAMIC_TYPE_RSA; + ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); + if (ret != 0) { + goto exit_dpk; + } + + WOLFSSL_MSG("Trying RSA private key"); + + /* Set start of data to beginning of buffer. */ + idx = 0; + /* Decode the key assuming it is an RSA private key. */ + ret = wc_RsaPrivateKeyDecode(ssl->buffers.key->buffer, &idx, + (RsaKey*)ssl->hsKey, ssl->buffers.key->length); + if (ret == 0) { + WOLFSSL_MSG("Using RSA private key"); + + /* It worked so check it meeets minimum key size requirements. */ + keySz = wc_RsaEncryptSize((RsaKey*)ssl->hsKey); + if (keySz < 0) { /* check if keySz has error case */ + ERROR_OUT(keySz, exit_dpk); + } + + if (keySz < ssl->options.minRsaKeySz) { + WOLFSSL_MSG("RSA key size too small"); + ERROR_OUT(RSA_KEY_SIZE_E, exit_dpk); + } + + /* Return the maximum signature length. */ + *length = (word16)keySz; + + goto exit_dpk; + } +#endif /* !NO_RSA */ + +#ifdef HAVE_ECC +#ifndef NO_RSA + FreeKey(ssl, ssl->hsType, (void**)&ssl->hsKey); +#endif /* !NO_RSA */ + + ssl->hsType = DYNAMIC_TYPE_ECC; + ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); + if (ret != 0) { + goto exit_dpk; + } + +#ifndef NO_RSA + WOLFSSL_MSG("Trying ECC private key, RSA didn't work"); +#else + WOLFSSL_MSG("Trying ECC private key"); +#endif + + /* Set start of data to beginning of buffer. */ + idx = 0; + /* Decode the key assuming it is an ECC private key. */ + ret = wc_EccPrivateKeyDecode(ssl->buffers.key->buffer, &idx, + (ecc_key*)ssl->hsKey, + ssl->buffers.key->length); + if (ret != 0) { + WOLFSSL_MSG("Bad client cert type"); + goto exit_dpk; + } + + WOLFSSL_MSG("Using ECC private key"); + + /* Check it meets the minimum ECC key size requirements. */ + keySz = wc_ecc_size((ecc_key*)ssl->hsKey); + if (keySz < ssl->options.minEccKeySz) { + WOLFSSL_MSG("ECC key size too small"); + ERROR_OUT(ECC_KEY_SIZE_E, exit_dpk); + } + + /* Return the maximum signature length. */ + *length = wc_ecc_sig_size((ecc_key*)ssl->hsKey); +#endif + +exit_dpk: + return ret; +} + typedef struct ScvArgs { byte* output; /* not allocated */ @@ -17498,79 +17919,19 @@ int SendCertificateVerify(WOLFSSL* ssl) case TLS_ASYNC_BUILD: { - int keySz; - int typeH = 0; + int typeH; ret = BuildCertHashes(ssl, &ssl->hsHashes->certHashes); if (ret != 0) { goto exit_scv; } - /* make sure private key exists */ - if (ssl->buffers.key == NULL || ssl->buffers.key->buffer == NULL) { - WOLFSSL_MSG("Private key missing!"); - ERROR_OUT(NO_PRIVATE_KEY, exit_scv); - } - - #ifndef NO_RSA - ssl->hsType = DYNAMIC_TYPE_RSA; - ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); + /* Decode private key. */ + ret = DecodePrivateKey(ssl, (word16*)&args->length); if (ret != 0) { goto exit_scv; } - WOLFSSL_MSG("Trying RSA client cert"); - - ret = wc_RsaPrivateKeyDecode(ssl->buffers.key->buffer, &args->idx, - (RsaKey*)ssl->hsKey, ssl->buffers.key->length); - if (ret == 0) { - keySz = wc_RsaEncryptSize((RsaKey*)ssl->hsKey); - if (keySz < 0) { /* check if keySz has error case */ - ERROR_OUT(keySz, exit_scv); - } - - args->length = (word32)keySz; - if (keySz < ssl->options.minRsaKeySz) { - WOLFSSL_MSG("RSA key size too small"); - ERROR_OUT(RSA_KEY_SIZE_E, exit_scv); - } - } - else - #endif /* !NO_RSA */ - { - #ifdef HAVE_ECC - #ifndef NO_RSA - FreeKey(ssl, ssl->hsType, (void**)&ssl->hsKey); - #endif /* !NO_RSA */ - - ssl->hsType = DYNAMIC_TYPE_ECC; - ret = AllocKey(ssl, ssl->hsType, &ssl->hsKey); - if (ret != 0) { - goto exit_scv; - } - - WOLFSSL_MSG("Trying ECC client cert, RSA didn't work"); - - args->idx = 0; - ret = wc_EccPrivateKeyDecode(ssl->buffers.key->buffer, - &args->idx, (ecc_key*)ssl->hsKey, ssl->buffers.key->length); - if (ret != 0) { - WOLFSSL_MSG("Bad client cert type"); - goto exit_scv; - } - - WOLFSSL_MSG("Using ECC client cert"); - args->length = MAX_ENCODED_SIG_SZ; - - /* check minimum size of ECC key */ - keySz = wc_ecc_size((ecc_key*)ssl->hsKey); - if (keySz < ssl->options.minEccKeySz) { - WOLFSSL_MSG("ECC key size too small"); - ERROR_OUT(ECC_KEY_SIZE_E, exit_scv); - } - #endif - } - /* idx is used to track verify pointer offset to output */ args->idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; args->verify = &args->output[RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ]; @@ -17896,7 +18257,7 @@ exit_scv: #ifdef HAVE_SESSION_TICKET -int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, +static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size) { word32 begin = *inOutIdx; @@ -18001,7 +18362,7 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + ENUM_LEN; #ifdef HAVE_TLS_EXTENSIONS - length += TLSX_GetResponseSize(ssl); + length += TLSX_GetResponseSize(ssl, server_hello); #ifdef HAVE_SESSION_TICKET if (ssl->options.useTicket) { /* echo session id sz can be 0,32 or bogus len inbetween */ @@ -18010,7 +18371,8 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, WOLFSSL_MSG("Bad bogus session id len"); return BUFFER_ERROR; } - length -= (ID_LEN - sessIdSz); /* adjust ID_LEN assumption */ + if (!IsAtLeastTLSv1_3(ssl->version)) + length -= (ID_LEN - sessIdSz); /* adjust ID_LEN assumption */ echoId = 1; } #endif /* HAVE_SESSION_TICKET */ @@ -18108,7 +18470,7 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* last, extensions */ #ifdef HAVE_TLS_EXTENSIONS - TLSX_WriteResponse(ssl, output + idx); + TLSX_WriteResponse(ssl, output + idx, server_hello); #else #ifdef HAVE_EXTENDED_MASTER if (ssl->options.haveEMS) { @@ -18141,6 +18503,7 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (ret != 0) return ret; + #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo); @@ -19743,6 +20106,18 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } #endif +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + ssl->options.side == WOLFSSL_SERVER_END) { + /* Try to establish a key share. */ + int ret = TLSX_KeyShare_Establish(ssl); + if (ret == KEY_SHARE_ERROR) + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST; + else if (ret != 0) + return 0; + } +#endif + return 1; } @@ -19772,7 +20147,7 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, return MATCH_SUITE_ERROR; } - static int MatchSuite(WOLFSSL* ssl, Suites* peerSuites) + int MatchSuite(WOLFSSL* ssl, Suites* peerSuites) { int ret; word16 i, j; @@ -19887,6 +20262,10 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, WOLFSSL_MSG("\tdowngrading to TLSv1.1"); ssl->version.minor = TLSv1_1_MINOR; } + else if (pv.minor == TLSv1_2_MINOR) { + WOLFSSL_MSG(" downgrading to TLSv1.2"); + ssl->version.minor = TLSv1_2_MINOR; + } #ifndef NO_RSA haveRSA = 1; #endif @@ -20005,7 +20384,7 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif /* OLD_HELLO_ALLOWED */ - static int DoClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + int DoClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 helloSz) { byte b; @@ -20099,6 +20478,10 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, WOLFSSL_MSG("\tdowngrading to TLSv1.1"); ssl->version.minor = TLSv1_1_MINOR; } + else if (pv.minor == TLSv1_2_MINOR) { + WOLFSSL_MSG(" downgrading to TLSv1.2"); + ssl->version.minor = TLSv1_2_MINOR; + } #ifndef NO_RSA haveRSA = 1; #endif @@ -20335,8 +20718,8 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #ifdef HAVE_TLS_EXTENSIONS /* tls extensions */ - if ((ret = TLSX_Parse(ssl, (byte *) input + i, - totalExtSz, 1, &clSuites))) + if ((ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz, + client_hello, &clSuites))) return ret; #if defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) if((ret=SNI_Callback(ssl))) @@ -20870,6 +21253,10 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, byte msecret[SECRET_LEN]; /* master secret */ word32 timestamp; /* born on */ word16 haveEMS; /* have extended master secret */ +#ifdef WOLFSSL_TLS13 + word32 ageAdd; /* Obfuscation of age */ + byte namedGroup; /* Named group used */ +#endif } InternalTicket; /* fit within SESSION_TICKET_LEN */ @@ -20883,7 +21270,7 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } ExternalTicket; /* create a new session ticket, 0 on success */ - static int CreateTicket(WOLFSSL* ssl) + int CreateTicket(WOLFSSL* ssl) { InternalTicket it; ExternalTicket* et = (ExternalTicket*)ssl->session.ticket; @@ -20900,9 +21287,25 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, it.suite[0] = ssl->options.cipherSuite0; it.suite[1] = ssl->options.cipherSuite; - XMEMCPY(it.msecret, ssl->arrays->masterSecret, SECRET_LEN); - c32toa(LowResTimer(), (byte*)&it.timestamp); - it.haveEMS = ssl->options.haveEMS; + if (!ssl->options.tls1_3) { + XMEMCPY(it.msecret, ssl->arrays->masterSecret, SECRET_LEN); + c32toa(LowResTimer(), (byte*)&it.timestamp); + it.haveEMS = ssl->options.haveEMS; + } + else { +#ifdef WOLFSSL_TLS13 + /* Client adds to ticket age to obfuscate. */ + ret = wc_RNG_GenerateBlock(ssl->rng, (void*)&it.ageAdd, + sizeof(it.ageAdd)); + if (ret != 0) + return BAD_TICKET_ENCRYPT; + ssl->session.ticketAdd = it.ageAdd; + it.namedGroup = ssl->session.namedGroup; + it.timestamp = TimeNowInMilliseconds(); + /* Resumption master secret. */ + XMEMCPY(it.msecret, ssl->session.masterSecret, SECRET_LEN); +#endif + } /* build external */ XMEMCPY(et->enc_ticket, &it, sizeof(InternalTicket)); @@ -20995,10 +21398,24 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* get master secret */ if (ret == WOLFSSL_TICKET_RET_OK || ret == WOLFSSL_TICKET_RET_CREATE) { - XMEMCPY(ssl->arrays->masterSecret, it->msecret, SECRET_LEN); - /* Copy the haveExtendedMasterSecret property from the ticket to - * the saved session, so the property may be checked later. */ - ssl->session.haveEMS = it->haveEMS; + if (!IsAtLeastTLSv1_3(ssl->version)) { + XMEMCPY(ssl->arrays->masterSecret, it->msecret, SECRET_LEN); + /* Copy the haveExtendedMasterSecret property from the ticket to + * the saved session, so the property may be checked later. */ + ssl->session.haveEMS = it->haveEMS; + } + else { +#ifdef WOLFSSL_TLS13 + /* Restore information to renegotiate. */ + ssl->session.ticketSeen = it->timestamp; + ssl->session.ticketAdd = it->ageAdd; + ssl->session.cipherSuite0 = it->suite[0]; + ssl->session.cipherSuite = it->suite[1]; + /* Resumption master secret. */ + XMEMCPY(ssl->session.masterSecret, it->msecret, SECRET_LEN); + ssl->session.namedGroup = it->namedGroup; +#endif + } } return ret; @@ -22033,7 +22450,7 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #if defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) - static int SNI_Callback(WOLFSSL* ssl) + int SNI_Callback(WOLFSSL* ssl) { /* Stunnel supports a custom sni callback to switch an SSL's ctx * when SNI is received. Call it now if exists */ @@ -22048,7 +22465,7 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } return 0; } -#endif /* HAVE_STUNNEL */ +#endif /* HAVE_STUNNEL || WOLGSSL_NGINX */ #endif /* NO_WOLFSSL_SERVER */ diff --git a/src/keys.c b/src/keys.c index 176a46a6c..7971bf1cf 100644 --- a/src/keys.c +++ b/src/keys.c @@ -1053,8 +1053,109 @@ int SetCipherSpecs(WOLFSSL* ssl) return UNSUPPORTED_SUITE; } /* switch */ } /* if */ - if (ssl->options.cipherSuite0 != ECC_BYTE && - ssl->options.cipherSuite0 != CHACHA_BYTE) { /* normal suites */ + + /* TLSi v1.3 cipher suites, 0x13 */ + if (ssl->options.cipherSuite0 == TLS13_BYTE) { + switch (ssl->options.cipherSuite) { + +#ifdef WOLFSSL_TLS13 + #ifdef BUILD_TLS_AES_128_GCM_SHA256 + case TLS_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = 0; + ssl->specs.sig_algo = 0; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_NONCE_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; + #endif + + #ifdef BUILD_TLS_AES_256_GCM_SHA384 + case TLS_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = 0; + ssl->specs.sig_algo = 0; + ssl->specs.hash_size = SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_NONCE_SZ; + ssl->specs.aead_mac_size = AES_GCM_AUTH_SZ; + + break; + #endif + + #ifdef BUILD_TLS_CHACHA20_POLY1305_SHA256 + case TLS_CHACHA20_POLY1305_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_chacha; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = 0; + ssl->specs.sig_algo = 0; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CHACHA20_256_KEY_SIZE; + ssl->specs.block_size = CHACHA20_BLOCK_SIZE; + ssl->specs.iv_size = CHACHA20_IV_SIZE; + ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + ssl->options.oldPoly = 0; /* use recent padding RFC */ + + break; + #endif + + #ifdef BUILD_TLS_AES_128_CCM_SHA256 + case TLS_AES_128_CCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = 0; + ssl->specs.sig_algo = 0; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_NONCE_SZ; + ssl->specs.aead_mac_size = AES_CCM_16_AUTH_SZ; + + break; + #endif + + #ifdef BUILD_TLS_AES_128_CCM_8_SHA256 + case TLS_AES_128_CCM_8_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = 0; + ssl->specs.sig_algo = 0; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AESGCM_NONCE_SZ; + ssl->specs.aead_mac_size = AES_CCM_8_AUTH_SZ; + + break; + #endif +#endif /* WOLFSSL_TLS13 */ + } + } + + if (ssl->options.cipherSuite0 != ECC_BYTE && + ssl->options.cipherSuite0 != CHACHA_BYTE && + ssl->options.cipherSuite0 != TLS13_BYTE) { /* normal suites */ switch (ssl->options.cipherSuite) { #ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA @@ -1993,8 +2094,11 @@ int SetCipherSpecs(WOLFSSL* ssl) #ifndef NO_TLS ssl->options.tls = 1; ssl->hmac = TLS_hmac; - if (ssl->version.minor >= 2) + if (ssl->version.minor >= 2) { ssl->options.tls1_1 = 1; + if (ssl->version.minor >= 4) + ssl->options.tls1_3 = 1; + } #endif } @@ -2452,14 +2556,14 @@ static int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs, specs->key_size); if (gcmRet != 0) return gcmRet; XMEMCPY(keys->aead_enc_imp_IV, keys->client_write_IV, - AESGCM_IMP_IV_SZ); + AEAD_MAX_IMP_SZ); } if (dec) { gcmRet = wc_AesGcmSetKey(dec->aes, keys->server_write_key, specs->key_size); if (gcmRet != 0) return gcmRet; XMEMCPY(keys->aead_dec_imp_IV, keys->server_write_IV, - AESGCM_IMP_IV_SZ); + AEAD_MAX_IMP_SZ); } } else { @@ -2468,14 +2572,14 @@ static int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs, specs->key_size); if (gcmRet != 0) return gcmRet; XMEMCPY(keys->aead_enc_imp_IV, keys->server_write_IV, - AESGCM_IMP_IV_SZ); + AEAD_MAX_IMP_SZ); } if (dec) { gcmRet = wc_AesGcmSetKey(dec->aes, keys->client_write_key, specs->key_size); if (gcmRet != 0) return gcmRet; XMEMCPY(keys->aead_dec_imp_IV, keys->client_write_IV, - AESGCM_IMP_IV_SZ); + AEAD_MAX_IMP_SZ); } } if (enc) diff --git a/src/ssl.c b/src/ssl.c index 557b8416b..efe32125b 100755 --- a/src/ssl.c +++ b/src/ssl.c @@ -1600,6 +1600,17 @@ int wolfSSL_UseSupportedCurve(WOLFSSL* ssl, word16 name) case WOLFSSL_ECC_BRAINPOOLP512R1: break; +#ifdef WOLFSSL_TLS13 + case WOLFSSL_FFDHE_2048: + case WOLFSSL_FFDHE_3072: + case WOLFSSL_FFDHE_4096: + case WOLFSSL_FFDHE_6144: + case WOLFSSL_FFDHE_8192: + if (!IsAtLeastTLSv1_3(ssl->version)) + return SSL_SUCCESS; + break; +#endif + default: return BAD_FUNC_ARG; } @@ -1632,6 +1643,15 @@ int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx, word16 name) case WOLFSSL_ECC_BRAINPOOLP512R1: break; +#ifdef WOLFSSL_TLS13 + case WOLFSSL_FFDHE_2048: + case WOLFSSL_FFDHE_3072: + case WOLFSSL_FFDHE_4096: + case WOLFSSL_FFDHE_6144: + case WOLFSSL_FFDHE_8192: + break; +#endif + default: return BAD_FUNC_ARG; } @@ -1696,7 +1716,6 @@ int wolfSSL_UseSupportedQSH(WOLFSSL* ssl, word16 name) #endif /* NO_WOLFSSL_CLIENT */ #endif /* HAVE_QSH */ - /* Application-Layer Protocol Negotiation */ #ifdef HAVE_ALPN @@ -1869,33 +1888,9 @@ int wolfSSL_Rehandshake(WOLFSSL* ssl) ssl->secure_renegotiation->cache_status = SCR_CACHE_NEEDED; -#ifndef NO_OLD_TLS -#ifndef NO_MD5 - ret = wc_InitMd5_ex(&ssl->hsHashes->hashMd5, ssl->heap, ssl->devId); + ret = InitHandshakeHashes(ssl); if (ret !=0) return ret; -#endif -#ifndef NO_SHA - ret = wc_InitSha_ex(&ssl->hsHashes->hashSha, ssl->heap, ssl->devId); - if (ret !=0) - return ret; -#endif -#endif /* NO_OLD_TLS */ -#ifndef NO_SHA256 - ret = wc_InitSha256_ex(&ssl->hsHashes->hashSha256, ssl->heap, ssl->devId); - if (ret !=0) - return ret; -#endif -#ifdef WOLFSSL_SHA384 - ret = wc_InitSha384_ex(&ssl->hsHashes->hashSha384, ssl->heap, ssl->devId); - if (ret !=0) - return ret; -#endif -#ifdef WOLFSSL_SHA512 - ret = wc_InitSha512_ex(&ssl->hsHashes->hashSha512, ssl->heap, ssl->devId); - if (ret !=0) - return ret; -#endif ret = wolfSSL_negotiate(ssl); return ret; @@ -4203,6 +4198,9 @@ static int ProcessUserChain(WOLFSSL_CTX* ctx, const unsigned char* buff, { int ret = 0; void* heap = ctx ? ctx->heap : ((ssl) ? ssl->heap : NULL); +#ifdef WOLFSSL_TLS13 + int cnt = 0; +#endif /* we may have a user cert chain, try to consume */ if (type == CERT_TYPE && info->consumed < sz) { @@ -4260,6 +4258,9 @@ static int ProcessUserChain(WOLFSSL_CTX* ctx, const unsigned char* buff, } if (ret == 0) { gotOne = 1; +#ifdef WOLFSSL_TLS13 + cnt++; +#endif if ((idx + part->length) > bufferSz) { WOLFSSL_MSG(" Cert Chain bigger than buffer"); ret = BUFFER_E; @@ -4303,12 +4304,18 @@ static int ProcessUserChain(WOLFSSL_CTX* ctx, const unsigned char* buff, XMEMCPY(ssl->buffers.certChain->buffer, chainBuffer, idx); ssl->buffers.weOwnCertChain = 1; } +#ifdef WOLFSSL_TLS13 + ssl->buffers.certChainCnt = cnt; +#endif } else if (ctx) { FreeDer(&ctx->certChain); ret = AllocDer(&ctx->certChain, idx, type, heap); if (ret == 0) { XMEMCPY(ctx->certChain->buffer, chainBuffer, idx); } +#ifdef WOLFSSL_TLS13 + ctx->certChainCnt = cnt; +#endif } } @@ -8028,6 +8035,7 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, return result; } + /* please see note at top of README if you get an error from connect */ int wolfSSL_connect(WOLFSSL* ssl) { @@ -8120,47 +8128,18 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, if (ssl->options.certOnly) return SSL_SUCCESS; +#ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_connect_TLSv13(ssl); +#endif + #ifdef WOLFSSL_DTLS if (IsDtlsNotSctpMode(ssl)) { /* re-init hashes, exclude first hello and verify request */ -#ifndef NO_OLD_TLS - if ( (ssl->error = wc_InitMd5_ex(&ssl->hsHashes->hashMd5, - ssl->heap, ssl->devId)) != 0) { + if ((ssl->error = InitHandshakeHashes(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return SSL_FATAL_ERROR; } - if ( (ssl->error = wc_InitSha_ex(&ssl->hsHashes->hashSha, - ssl->heap, ssl->devId)) != 0) { - WOLFSSL_ERROR(ssl->error); - return SSL_FATAL_ERROR; - } -#endif - if (IsAtLeastTLSv1_2(ssl)) { - #ifndef NO_SHA256 - if ( (ssl->error = wc_InitSha256_ex( - &ssl->hsHashes->hashSha256, - ssl->heap, ssl->devId)) != 0) { - WOLFSSL_ERROR(ssl->error); - return SSL_FATAL_ERROR; - } - #endif - #ifdef WOLFSSL_SHA384 - if ( (ssl->error = wc_InitSha384_ex( - &ssl->hsHashes->hashSha384, - ssl->heap, ssl->devId)) != 0) { - WOLFSSL_ERROR(ssl->error); - return SSL_FATAL_ERROR; - } - #endif - #ifdef WOLFSSL_SHA512 - if ( (ssl->error = wc_InitSha512_ex( - &ssl->hsHashes->hashSha512, - ssl->heap, ssl->devId)) != 0) { - WOLFSSL_ERROR(ssl->error); - return SSL_FATAL_ERROR; - } - #endif - } if ( (ssl->error = SendClientHello(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return SSL_FATAL_ERROR; @@ -8374,10 +8353,17 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, } #endif + int wolfSSL_accept(WOLFSSL* ssl) { word16 havePSK = 0; word16 haveAnon = 0; + +#ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_accept_TLSv13(ssl); +#endif + WOLFSSL_ENTER("SSL_accept()"); #ifdef HAVE_ERRNO_H @@ -8451,14 +8437,37 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, WOLFSSL_ERROR(ssl->error); return SSL_FATAL_ERROR; } +#ifdef WOLFSSL_TLS13 ssl->options.acceptState = ACCEPT_CLIENT_HELLO_DONE; WOLFSSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE"); case ACCEPT_CLIENT_HELLO_DONE : + if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) { + if ((ssl->error = SendTls13HelloRetryRequest(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } + ssl->options.acceptState = ACCEPT_HELLO_RETRY_REQUEST_DONE; + WOLFSSL_MSG("accept state ACCEPT_HELLO_RETRY_REQUEST_DONE"); + + case ACCEPT_HELLO_RETRY_REQUEST_DONE : + if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) { + if ( (ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } +#endif ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE; WOLFSSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE"); case ACCEPT_FIRST_REPLY_DONE : +#ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) { + return wolfSSL_accept_TLSv13(ssl); + } +#endif if ( (ssl->error = SendServerHello(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return SSL_FATAL_ERROR; @@ -8974,6 +8983,24 @@ static int GetDeepCopySession(WOLFSSL* ssl, WOLFSSL_SESSION* copyFrom) } #ifdef HAVE_SESSION_TICKET +#ifdef WOLFSSL_TLS13 + if (wc_LockMutex(&session_mutex) != 0) { + XFREE(tmpBuff, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); + return BAD_MUTEX_E; + } + + copyInto->cipherSuite0 = copyFrom->cipherSuite0; + copyInto->cipherSuite = copyFrom->cipherSuite; + copyInto->namedGroup = copyFrom->namedGroup; + copyInto->ticketSeen = copyFrom->ticketSeen; + copyInto->ticketAdd = copyFrom->ticketAdd; + XMEMCPY(copyInto->masterSecret, copyFrom->masterSecret, SECRET_LEN); + + if (wc_UnLockMutex(&session_mutex) != 0) { + if (ret == SSL_SUCCESS) + ret = BAD_MUTEX_E; + } +#endif /* If doing dynamic copy, need to alloc outside lock, then inside a lock * confirm the size still matches and memcpy */ if (doDynamicCopy) { @@ -9033,7 +9060,8 @@ int SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session) if (ret == SSL_SUCCESS) { ssl->options.resuming = 1; -#ifdef SESSION_CERTS +#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ + defined(HAVE_SESSION_TICKET) && !defined(NO_PSK)) ssl->version = session->version; ssl->options.cipherSuite0 = session->cipherSuite0; ssl->options.cipherSuite = session->cipherSuite; @@ -9127,7 +9155,10 @@ int AddSession(WOLFSSL* ssl) session = &SessionCache[row].Sessions[idx]; } - XMEMCPY(session->masterSecret, ssl->arrays->masterSecret, SECRET_LEN); + if (!ssl->options.tls1_3) + XMEMCPY(session->masterSecret, ssl->arrays->masterSecret, SECRET_LEN); + else + XMEMCPY(session->masterSecret, ssl->session.masterSecret, SECRET_LEN); session->haveEMS = ssl->options.haveEMS; XMEMCPY(session->sessionID, ssl->arrays->sessionID, ID_LEN); session->sessionIDSz = ssl->arrays->sessionIDSz; @@ -9177,12 +9208,23 @@ int AddSession(WOLFSSL* ssl) session->chain.count = ssl->session.chain.count; XMEMCPY(session->chain.certs, ssl->session.chain.certs, sizeof(x509_buffer) * MAX_CHAIN_DEPTH); - + } +#endif /* SESSION_CERTS */ +#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ + defined(HAVE_SESSION_TICKET) && !defined(NO_PSK)) + if (error == 0) { session->version = ssl->version; session->cipherSuite0 = ssl->options.cipherSuite0; session->cipherSuite = ssl->options.cipherSuite; } -#endif /* SESSION_CERTS */ +#endif /* SESSION_CERTS || (WOLFSSL_TLS13 & !NO_PSK) */ +#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) + if (error == 0) { + session->namedGroup = ssl->session.namedGroup; + session->ticketSeen = ssl->session.ticketSeen; + session->ticketAdd = ssl->session.ticketAdd; + } +#endif /* WOLFSSL_TLS13 && HAVE_SESSION_TICKET */ #ifdef HAVE_EXT_CACHE if (!ssl->options.internalCacheOff) #endif @@ -14042,6 +14084,8 @@ const char* wolfSSL_get_version(WOLFSSL* ssl) return "TLSv1.1"; case TLSv1_2_MINOR : return "TLSv1.2"; + case TLSv1_3_MINOR : + return "TLSv1.3"; default: return "unknown"; } @@ -23106,6 +23150,7 @@ int wolfSSL_version(WOLFSSL* ssl) case TLSv1_MINOR : case TLSv1_1_MINOR : case TLSv1_2_MINOR : + case TLSv1_3_MINOR : return TLS1_VERSION; default: return SSL_FAILURE; diff --git a/src/tls.c b/src/tls.c index 056ca0934..00b55c18e 100755 --- a/src/tls.c +++ b/src/tls.c @@ -342,7 +342,6 @@ static int PRF(byte* digest, word32 digLen, const byte* secret, word32 secLen, return ret; } - #ifdef WOLFSSL_SHA384 #define HSHASH_SZ SHA384_DIGEST_SIZE #else @@ -455,6 +454,21 @@ ProtocolVersion MakeTLSv1_2(void) return pv; } +#ifdef WOLFSSL_TLS13 +/* The TLS v1.3 protocol version. + * + * returns the protocol version data for TLS v1.3. + */ +ProtocolVersion MakeTLSv1_3(void) +{ + ProtocolVersion pv; + pv.major = SSLv3_MAJOR; + pv.minor = TLSv1_3_MINOR; + + return pv; +} +#endif + #ifdef HAVE_EXTENDED_MASTER static const byte ext_master_label[EXT_MASTER_LABEL_SZ + 1] = @@ -654,7 +668,19 @@ static INLINE void c24to32(const word24 u24, word32* u32) *u32 = (u24[0] << 16) | (u24[1] << 8) | u24[2]; } #endif + +#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) +/* Convert opaque data to a 32-bit unsigned integer. + * + * c The opaque data holding a 32-bit integer. + * u32 The 32-bit unsigned integer. + */ +static INLINE void ato32(const byte* c, word32* u32) +{ + *u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; +} #endif +#endif /* HAVE_TLS_EXTENSIONS */ /* convert 32 bit integer to opaque */ static INLINE void c32toa(word32 u32, byte* c) @@ -884,12 +910,16 @@ static INLINE word16 TLSX_ToSemaphore(word16 type) /** Checks if a specific light (tls extension) is not set in the semaphore. */ #define IS_OFF(semaphore, light) \ - ((semaphore)[(light) / 8] ^ (byte) (0x01 << ((light) % 8))) + (!(((semaphore)[(light) / 8] & (byte) (0x01 << ((light) % 8))))) /** Turn on a specific light (tls extension) in the semaphore. */ #define TURN_ON(semaphore, light) \ ((semaphore)[(light) / 8] |= (byte) (0x01 << ((light) % 8))) +/** Turn off a specific light (tls extension) in the semaphore. */ +#define TURN_OFF(semaphore, light) \ + ((semaphore)[(light) / 8] &= (byte) ~(0x01 << ((light) % 8))) + /** Creates a new extension. */ static TLSX* TLSX_New(TLSX_Type type, void* data, void* heap) { @@ -1557,6 +1587,13 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length, switch(type) { case WOLFSSL_SNI_HOST_NAME: { int matchStat; +#ifdef WOLFSSL_TLS13 + /* Don't process the second ClientHello SNI extension if there + * was problems with the first. + */ + if (sni->status != 0) + break; +#endif byte matched = cacheOnly || ((XSTRLEN(sni->data.host_name) == size) && (XSTRNCMP(sni->data.host_name, @@ -2838,7 +2875,8 @@ static void TLSX_EllipticCurve_ValidateRequest(WOLFSSL* ssl, byte* semaphore) for (i = 0; i < ssl->suites->suiteSz; i+= 2) if (ssl->suites->suites[i] == ECC_BYTE || - ssl->suites->suites[i] == CHACHA_BYTE) + ssl->suites->suites[i] == CHACHA_BYTE || + ssl->suites->suites[i] == TLS13_BYTE) return; /* turns semaphore on to avoid sending this extension. */ @@ -2914,6 +2952,29 @@ static int TLSX_EllipticCurve_Parse(WOLFSSL* ssl, byte* input, word16 length, return 0; } +#ifdef WOLFSSL_TLS13 +/* Searches the supported groups extension for the specified named group. + * + * ssl The SSL/TLS object. + * name The group name to match. + * returns 1 when the extension has the group name and 0 otherwise. + */ +static int TLSX_SupportedGroups_Find(WOLFSSL* ssl, word16 name) +{ + TLSX* extension; + EllipticCurve* curve = NULL; + + if ((extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS)) == NULL) + return 0; + + for (curve = (EllipticCurve*)extension->data; curve; curve = curve->next) { + if (curve->name == name) + return 1; + } + return 0; +} +#endif /* WOLFSSL_TLS13 */ + int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) { TLSX* extension = (first == ECC_BYTE || first == CHACHA_BYTE) ? TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS) @@ -4194,6 +4255,1780 @@ int TLSX_UseQSHScheme(TLSX** extensions, word16 name, byte* pKey, word16 pkeySz, #endif /* HAVE_QSH */ +/******************************************************************************/ +/* Supported Versions */ +/******************************************************************************/ + +#ifdef WOLFSSL_TLS13 +/* Return the size of the SupportedVersions extension's data. + * + * data The SSL/TLS object. + * returns the length of data that will be in the extension. + */ +static word16 TLSX_SupportedVersions_GetSize(byte* data) +{ + (void)data; + + /* TLS v1.2 and TLS v1.3 */ + int cnt = 2; + +#ifndef NO_OLD_TLS + /* TLS v1 and TLS v1.1 */ + cnt += 2; +#endif + + return OPAQUE8_LEN + cnt * OPAQUE16_LEN; +} + +/* Writes the SupportedVersions extension into the buffer. + * + * data The SSL/TLS object. + * output The buffer to write the extension into. + * returns the length of data that was written. + */ +static word16 TLSX_SupportedVersions_Write(byte* data, byte* output) +{ + WOLFSSL* ssl = (WOLFSSL*)data; + ProtocolVersion pv = ssl->ctx->method->version; + int i; + /* TLS v1.2 and TLS v1.3 */ + int cnt = 2; + +#ifndef NO_OLD_TLS + /* TLS v1 and TLS v1.1 */ + cnt += 2; +#endif + + *(output++) = cnt * OPAQUE16_LEN; + for (i = 0; i < cnt; i++) { + /* TODO: [TLS13] Remove code when TLS v1.3 becomes an RFC. */ + if (pv.minor - i == TLSv1_3_MINOR) { + /* The TLS draft major number. */ + *(output++) = 0x7f; + /* Version of draft supported. */ + *(output++) = 18; + continue; + } + + *(output++) = pv.major; + *(output++) = pv.minor - i; + } + + return OPAQUE8_LEN + cnt * OPAQUE16_LEN; +} + +/* Parse the SupportedVersions extension. + * + * ssl The SSL/TLS object. + * input The buffer with the extension data. + * length The length of the extension data. + * returns 0 on success, otherwise failure. + */ +static int TLSX_SupportedVersions_Parse(WOLFSSL *ssl, byte* input, + word16 length) +{ + ProtocolVersion pv = ssl->ctx->method->version; + int i; + int ret = 0; + int len; + + /* Must contain a length and at least one version. */ + if (length < OPAQUE8_LEN + OPAQUE16_LEN || (length & 1) != 1) + return BUFFER_ERROR; + + len = *input; + + /* Protocol version array must fill rest of data. */ + if (length != OPAQUE8_LEN + len) + return BUFFER_ERROR; + + input++; + + /* Find first match. */ + for (i = 0; i < len; i += OPAQUE16_LEN) { + /* TODO: [TLS13] Remove code when TLS v1.3 becomes an RFC. */ + if (input[i] == 0x7f && input[i + OPAQUE8_LEN] == 18) { + ssl->version.minor = TLSv1_3_MINOR; + break; + } + + if (input[i] != pv.major) + continue; + +#ifndef NO_OLD_TLS + if (input[i + OPAQUE8_LEN] == TLSv1_MINOR || + input[i + OPAQUE8_LEN] == TLSv1_1_MINOR) { + ssl->version.minor = input[i + OPAQUE8_LEN]; + break; + } +#endif + if (input[i + OPAQUE8_LEN] == TLSv1_2_MINOR) { + ssl->version.minor = input[i + OPAQUE8_LEN]; + break; + } + if (input[i + OPAQUE8_LEN] == TLSv1_3_MINOR) { + ssl->version.minor = input[i + OPAQUE8_LEN]; + break; + } + } + + return ret; +} + +/* Sets a new SupportedVersions extension into the extension list. + * + * extensions The list of extensions. + * data The extensions specific data. + * heap The heap used for allocation. + * returns 0 on success, otherwise failure. + */ +static int TLSX_SetSupportedVersions(TLSX** extensions, const void* data, + void* heap) +{ + if (extensions == NULL || data == NULL) + return BAD_FUNC_ARG; + + return TLSX_Push(extensions, TLSX_SUPPORTED_VERSIONS, (void *)data, heap); +} + +#define SV_GET_SIZE TLSX_SupportedVersions_GetSize +#define SV_WRITE TLSX_SupportedVersions_Write +#define SV_PARSE TLSX_SupportedVersions_Parse + +#else + +#define SV_GET_SIZE(a) 0 +#define SV_WRITE(a, b) 0 +#define SV_PARSE(a, b, c) 0 + +#endif /* WOLFSSL_TLS13 */ + +/******************************************************************************/ +/* Key Share */ +/******************************************************************************/ + +#ifdef WOLFSSL_TLS13 +#ifndef NO_DH +/* Create a key share entry using named Diffie-Hellman parameters group. + * Generates a key pair. + * + * ssl The SSL/TLS object. + * kse The key share entry object. + * returns 0 on success, otherwise failure. + */ +static int TLSX_KeyShare_GenDhKey(WOLFSSL *ssl, KeyShareEntry* kse) +{ + int ret; + byte* keyData; + void* key = NULL; + word32 keySz; + word32 dataSz; + const DhParams* params; + DhKey dhKey; + + /* TODO: [TLS13] The key size should come from wolfcrypt. */ + /* Pick the parameters from the named group. */ + switch (kse->group) { + #ifdef HAVE_FFDHE_2048 + case WOLFSSL_FFDHE_2048: + params = wc_Dh_ffdhe2048_Get(); + keySz = 29; + break; + #endif + #ifdef HAVE_FFDHE_3072 + case WOLFSSL_FFDHE_3072: + params = wc_Dh_ffdhe3072_Get(); + keySz = 34; + break; + #endif + #ifdef HAVE_FFDHE_4096 + case WOLFSSL_FFDHE_4096: + params = wc_Dh_ffdhe4096_Get(); + keySz = 39; + break; + #endif + #ifdef HAVE_FFDHE_6144 + case WOLFSSL_FFDHE_6144: + params = wc_Dh_ffdhe6144_Get(); + keySz = 46; + break; + #endif + #ifdef HAVE_FFDHE_8192 + case WOLFSSL_FFDHE_8192: + params = wc_Dh_ffdhe8192_Get(); + keySz = 52; + break; + #endif + default: + return BAD_FUNC_ARG; + } + + ret = wc_InitDhKey_ex(&dhKey, ssl->heap, ssl->devId); + if (ret != 0) + return ret; + + /* Allocate space for the public key. */ + dataSz = params->p_len; + keyData = (byte*)XMALLOC(dataSz, ssl->heap, DYNAMIC_TYPE_TLSX); + if (keyData == NULL) { + ret = MEMORY_E; + goto end; + } + /* Allocate space for the private key. */ + key = (byte*)XMALLOC(keySz, ssl->heap, DYNAMIC_TYPE_TLSX); + if (key == NULL) { + ret = MEMORY_E; + goto end; + } + + /* Set key */ + ret = wc_DhSetKey(&dhKey, + (byte*)params->p, params->p_len, + (byte*)params->g, params->g_len); + if (ret != 0) + goto end; + + /* Generate a new key pair. */ + ret = wc_DhGenerateKeyPair(&dhKey, ssl->rng, key, &keySz, keyData, &dataSz); +#ifdef WOLFSSL_ASYNC_CRYPT + /* TODO: Make this function non-blocking */ + if (ret == WC_PENDING_E) { + ret = wc_AsyncWait(ret, &dhKey.asyncDev, WC_ASYNC_FLAG_NONE); + } +#endif + if (ret != 0) + goto end; + + if (params->p_len != dataSz) { + /* Pad the front of the key data with zeros. */ + XMEMMOVE(keyData + params->p_len - dataSz, keyData, dataSz); + XMEMSET(keyData, 0, params->p_len - dataSz); + } + + kse->ke = keyData; + kse->keLen = params->p_len; + kse->key = key; + kse->keyLen = keySz; + + WOLFSSL_MSG("Public DH Key"); + WOLFSSL_BUFFER(keyData, params->p_len); +end: + + wc_FreeDhKey(&dhKey); + + if (ret != 0) { + /* Data owned by key share entry otherwise. */ + if (keyData != NULL) + XFREE(keyData, ssl->heap, DYNAMIC_TYPE_TLSX); + if (key != NULL) + XFREE(key, ssl->heap, DYNAMIC_TYPE_TLSX); + } + + return ret; +} +#endif + +#ifndef NO_ECC +/* Create a key share entry using named elliptic curve parameters group. + * Generates a key pair. + * + * ssl The SSL/TLS object. + * kse The key share entry object. + * returns 0 on success, otherwise failure. + */ +static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse) +{ + int ret; + byte* keyData = NULL; + word32 dataSize; + word32 keySize; + ecc_key* eccKey; + word16 curveId; + + /* TODO: [TLS13] The key sizes should come from wolfcrypt. */ + /* Translate named group to a curve id. */ + switch (kse->group) { + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP256R1: + curveId = ECC_SECP256R1; + keySize = 32; + dataSize = keySize * 2 + 1; + break; + #endif /* !NO_ECC_SECP */ + #endif + #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP384R1: + curveId = ECC_SECP384R1; + keySize = 48; + dataSize = keySize * 2 + 1; + break; + #endif /* !NO_ECC_SECP */ + #endif + #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP521R1: + curveId = ECC_SECP521R1; + keySize = 66; + dataSize = keySize * 2 + 1; + break; + #endif /* !NO_ECC_SECP */ + #endif + #ifdef HAVE_CURVE25519 + case WOLFSSL_ECC_X25519: + curveId = ECC_X25519; + dataSize = keySize = 32; + break; + #endif + #ifdef HAVE_X448 + case WOLFSSL_ECC_X448: + curveId = ECC_X448; + dataSize = keySize = 56; + break; + #endif + default: + return BAD_FUNC_ARG; + } + + /* Allocate an ECC key to hold private key. */ + eccKey = (ecc_key*)XMALLOC(sizeof(ecc_key), ssl->heap, DYNAMIC_TYPE_TLSX); + if (eccKey == NULL) { + WOLFSSL_MSG("EccTempKey Memory error"); + return MEMORY_E; + } + + /* Make an ECC key. */ + ret = wc_ecc_init_ex(eccKey, ssl->heap, ssl->devId); + if (ret != 0) + goto end; + ret = wc_ecc_make_key_ex(ssl->rng, keySize, eccKey, curveId); + if (ret != 0) + goto end; + + /* Allocate space for the public key. */ + keyData = XMALLOC(dataSize, ssl->heap, DYNAMIC_TYPE_TLSX); + if (keyData == NULL) { + WOLFSSL_MSG("Key data Memory error"); + ret = MEMORY_E; + goto end; + } + + /* Export public key. */ + if (wc_ecc_export_x963(eccKey, keyData, &dataSize) != 0) { + ret = ECC_EXPORT_ERROR; + goto end; + } + + kse->ke = keyData; + kse->keLen = dataSize; + kse->key = eccKey; + + WOLFSSL_MSG("Public ECC Key"); + WOLFSSL_BUFFER(keyData, dataSize); +end: + if (ret != 0) { + /* Data owned by key share entry otherwise. */ + if (eccKey != NULL) + XFREE(eccKey, ssl->heap, DYNAMIC_TYPE_TLSX); + if (keyData != NULL) + XFREE(keyData, ssl->heap, DYNAMIC_TYPE_TLSX); + } + return ret; +} +#endif /* !NO_ECC */ + +/* Generate a secret/key using the key share entry. + * + * ssl The SSL/TLS object. + * kse The key share entry holding peer data. + */ +static int TLSX_KeyShare_GenKey(WOLFSSL *ssl, KeyShareEntry *kse) +{ + /* Named FFHE groups have a bit set to identify them. */ + if ((kse->group & NAMED_DH_MASK) == NAMED_DH_MASK) + return TLSX_KeyShare_GenDhKey(ssl, kse); + return TLSX_KeyShare_GenEccKey(ssl, kse); +} + +/* Free the key share dynamic data. + * + * list The linked list of key share entry objects. + * heap The heap used for allocation. + */ +static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap) +{ + KeyShareEntry* current; + + while ((current = list) != NULL) { + list = current->next; + XFREE(current->key, heap, DYNAMIC_TYPE_TLSX); + XFREE(current->ke, heap, DYNAMIC_TYPE_TLSX); + XFREE(current, heap, DYNAMIC_TYPE_TLSX); + } + + (void)heap; +} + +/* Get the size of the encoded key share extension. + * + * list The linked list of key share extensions. + * msgType The type of the message this extension is being written into. + * returns the number of bytes of the encoded key share extension. + */ +static word16 TLSX_KeyShare_GetSize(KeyShareEntry* list, byte msgType) +{ + int len = 0; + byte isRequest = (msgType == client_hello); + KeyShareEntry* current; + + /* The named group the server wants to use. */ + if (msgType == hello_retry_request) + return OPAQUE16_LEN; + + /* List of key exchange groups. */ + if (isRequest) + len += OPAQUE16_LEN; + while ((current = list) != NULL) { + list = current->next; + + if (!isRequest && current->key == NULL) + continue; + + len += OPAQUE16_LEN + OPAQUE16_LEN + current->keLen; + } + + return len; +} + +/* Writes the key share extension into the output buffer. + * Assumes that the the output buffer is big enough to hold data. + * + * list The linked list of key share entries. + * output The buffer to write into. + * msgType The type of the message this extension is being written into. + * returns the number of bytes written into the buffer. + */ +static word16 TLSX_KeyShare_Write(KeyShareEntry* list, byte* output, + byte msgType) +{ + word16 i = 0; + byte isRequest = (msgType == client_hello); + KeyShareEntry* current; + + if (msgType == hello_retry_request) { + c16toa(list->group, output); + return OPAQUE16_LEN; + } + + /* ClientHello has a list but ServerHello is only the chosen. */ + if (isRequest) + i += OPAQUE16_LEN; + + /* Write out all in the list. */ + while ((current = list) != NULL) { + list = current->next; + + if (!isRequest && current->key == NULL) + continue; + + c16toa(current->group, &output[i]); + i += KE_GROUP_LEN; + c16toa(current->keLen, &output[i]); + i += OPAQUE16_LEN; + XMEMCPY(&output[i], current->ke, current->keLen); + i += current->keLen; + } + /* Write the length of the list if required. */ + if (isRequest) + c16toa(i - OPAQUE16_LEN, output); + + return i; +} + +/* Process the DH key share extension on the client side. + * + * ssl The SSL/TLS object. + * keyShareEntry The key share entry object to use to calculate shared secret. + * returns 0 on success and other values indicate failure. + */ +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) { + #ifdef HAVE_FFDHE_2048 + case WOLFSSL_FFDHE_2048: + params = wc_Dh_ffdhe2048_Get(); + break; + #endif + #ifdef HAVE_FFDHE_3072 + case WOLFSSL_FFDHE_3072: + params = wc_Dh_ffdhe3072_Get(); + break; + #endif + #ifdef HAVE_FFDHE_4096 + case WOLFSSL_FFDHE_4096: + params = wc_Dh_ffdhe4096_Get(); + break; + #endif + #ifdef HAVE_FFDHE_6144 + case WOLFSSL_FFDHE_6144: + params = wc_Dh_ffdhe6144_Get(); + break; + #endif + #ifdef HAVE_FFDHE_8192 + case WOLFSSL_FFDHE_8192: + params = wc_Dh_ffdhe8192_Get(); + break; + #endif + default: + return PEER_KEY_ERROR; + } + + WOLFSSL_MSG("Peer DH Key"); + WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen); + + if (params->p_len != keyShareEntry->keLen) + return BUFFER_ERROR; + + /* 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); + if (ret != 0) { + wc_FreeDhKey(&dhKey); + return ret; + } + + /* Derive secret from private key and peer's public key. */ + ret = wc_DhAgree(&dhKey, + ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz, + keyShareEntry->key, keyShareEntry->keyLen, + keyShareEntry->ke, keyShareEntry->keLen); +#ifdef WOLFSSL_ASYNC_CRYPT + /* TODO: Make this function non-blocking */ + if (ret == WC_PENDING_E) { + ret = wc_AsyncWait(ret, &dhKey.asyncDev, WC_ASYNC_FLAG_NONE); + } +#endif + + wc_FreeDhKey(&dhKey); + + return ret; +#else + return PEER_KEY_ERROR; +#endif +} + +/* Process the ECC key share extension on the client side. + * + * ssl The SSL/TLS object. + * keyShareEntry The key share entry object to use to calculate shared secret. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_KeyShare_ProcessEcc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) +{ +#ifndef NO_ECC + int ret; + int curveId; + + if (ssl->peerEccKey != NULL) + wc_ecc_free(ssl->peerEccKey); + + ssl->peerEccKey = (ecc_key*)XMALLOC(sizeof(ecc_key), ssl->heap, + DYNAMIC_TYPE_TLSX); + if (ssl->peerEccKey == NULL) { + WOLFSSL_MSG("PeerEccKey Memory error"); + return MEMORY_ERROR; + } + ret = wc_ecc_init_ex(ssl->peerEccKey, ssl->heap, ssl->devId); + if (ret != 0) + return ret; + + /* find supported curve */ + switch (keyShareEntry->group) { + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP256R1: + curveId = ECC_SECP256R1; + break; + #endif /* !NO_ECC_SECP */ + #endif + #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP384R1: + curveId = ECC_SECP384R1; + break; + #endif /* !NO_ECC_SECP */ + #endif + #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP521R1: + curveId = ECC_SECP521R1; + break; + #endif /* !NO_ECC_SECP */ + #endif + #ifdef HAVE_CURVE25519 + case WOLFSSL_ECC_X25519: + curveId = ECC_X25519; + break; + #endif + #ifdef HAVE_X448 + case WOLFSSL_ECC_X448: + curveId = ECC_X448; + break; + #endif + default: + /* unsupported curve */ + return ECC_PEERKEY_ERROR; + } + + WOLFSSL_MSG("Peer ECC Key"); + WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen); + + /* Point is validated by import function. */ + if (wc_ecc_import_x963_ex(keyShareEntry->ke, keyShareEntry->keLen, + ssl->peerEccKey, curveId) != 0) { + return ECC_PEERKEY_ERROR; + } + + ssl->arrays->preMasterSz = sizeof(ssl->arrays->preMasterSecret); + return EccSharedSecret(ssl, keyShareEntry->key, ssl->peerEccKey, + keyShareEntry->ke, &keyShareEntry->keLen, + ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz, + ssl->options.side, + #ifdef HAVE_PK_CALLBACKS + ssl->EccSharedSecretCtx + #else + NULL + #endif + ); +#else + return PEER_KEY_ERROR; +#endif +} + +/* Process the key share extension on the client side. + * + * ssl The SSL/TLS object. + * keyShareEntry The key share entry object to use to calculate shared secret. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_KeyShare_Process(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) +{ + int ret; + +#ifdef HAVE_SESSION_TICKET + ssl->session.namedGroup = keyShareEntry->group; +#endif + /* Use Key Share Data from server. */ + if (keyShareEntry->group & NAMED_DH_MASK) + ret = TLSX_KeyShare_ProcessDh(ssl, keyShareEntry); + else + ret = TLSX_KeyShare_ProcessEcc(ssl, keyShareEntry); + + WOLFSSL_MSG("KE Secret"); + WOLFSSL_BUFFER(ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz); + + return ret; +} + +/* Parse an entry of the KeyShare extension. + * + * ssl The SSL/TLS object. + * input The extension data. + * length The length of the extension data. + * kse The new key share entry object. + * returns a positive number to indicate amount of data parsed and a negative + * number on error. + */ +static int TLSX_KeyShareEntry_Parse(WOLFSSL* ssl, byte* input, word16 length, + KeyShareEntry **kse) +{ + int ret; + word16 group; + word16 keLen; + int offset = 0; + byte* ke; + + if (length < OPAQUE16_LEN + OPAQUE16_LEN) + return BUFFER_ERROR; + /* Named group */ + ato16(&input[offset], &group); + offset += OPAQUE16_LEN; + /* Key exchange data - public key. */ + ato16(&input[offset], &keLen); + offset += OPAQUE16_LEN; + if (keLen < 1 || keLen > length - offset) + return BUFFER_ERROR; + + /* Store a copy in the key share object. */ + ke = XMALLOC(keLen, ssl->heap, DYNAMIC_TYPE_TLSX); + if (ke == NULL) + return MEMORY_E; + XMEMCPY(ke, &input[offset], keLen); + + /* Populate a key share object in the extension. */ + ret = TLSX_KeyShare_Use(ssl, group, keLen, ke, kse); + if (ret != 0) + return ret; + + /* Total length of the parsed data. */ + return offset + keLen; +} + +/* Searches the groups sent for the specified named group. + * + * ssl The SSL/TLS object. + * name The group name to match. + * returns 1 when the extension has the group name and 0 otherwise. + */ +static int TLSX_KeyShare_Find(WOLFSSL* ssl, word16 group) +{ + TLSX* extension; + KeyShareEntry* list; + + extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + if (extension == NULL) + return 0; + + list = (KeyShareEntry*)extension->data; + while (list != NULL) { + if (list->group == group) { + return 1; + } + list = list->next; + } + + return 0; +} + +/* Parse the KeyShare extension. + * Different formats in different messages. + * + * ssl The SSL/TLS object. + * input The extension data. + * length The length of the extension data. + * msgType The type of the message this extension is being parsed from. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_KeyShare_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte msgType) +{ + int ret; + KeyShareEntry *keyShareEntry; + + if (msgType == client_hello) { + int offset = 0; + word16 len; + + if (length < OPAQUE16_LEN) + return BUFFER_ERROR; + + /* ClientHello contains zero or more key share entries. */ + ato16(input, &len); + if (len != length - OPAQUE16_LEN) + return BUFFER_ERROR; + offset += OPAQUE16_LEN; + + while (offset < length) { + ret = TLSX_KeyShareEntry_Parse(ssl, &input[offset], length, + &keyShareEntry); + if (ret < 0) + return ret; + + offset += ret; + } + + ret = 0; + } + else if (msgType == server_hello) { + int len; + + /* ServerHello contains one key share entry. */ + len = TLSX_KeyShareEntry_Parse(ssl, input, length, &keyShareEntry); + if (len != length) + return BUFFER_ERROR; + + /* Not in list sent if there isn't a private key. */ + if (keyShareEntry->key == NULL) + return BAD_KEY_SHARE_DATA; + + /* Process the entry to calculate the secret. */ + ret = TLSX_KeyShare_Process(ssl, keyShareEntry); + } + else if (msgType == hello_retry_request) { + word16 group; + + 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; + + /* Try to use the server's group. */ + ret = TLSX_KeyShare_Use(ssl, group, 0, NULL, NULL); + } + else { + /* Not a message type that is allowed to have this extension. */ + return SANITY_MSG_E; + } + + return ret; +} + +/* Create a new key share entry and put it into the list. + * + * list The linked list of key share entries. + * group The named group. + * heap The memory to allocate with. + * keyShareEntry The new key share entry object. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_KeyShare_New(KeyShareEntry** list, int group, void *heap, + KeyShareEntry** keyShareEntry) +{ + KeyShareEntry* kse; + + kse = (KeyShareEntry*)XMALLOC(sizeof(KeyShareEntry), heap, + DYNAMIC_TYPE_TLSX); + if (kse == NULL) + return MEMORY_E; + + XMEMSET(kse, 0, sizeof(*kse)); + kse->group = group; + + /* Add it to the back and maintain the links. */ + while (*list != NULL) + list = &((*list)->next); + *list = kse; + *keyShareEntry = kse; + + return 0; +} + +/* Use the data to create a new key share object in the extensions. + * + * ssl The SSL/TLS object. + * group The named group. + * len The length of the public key data. + * data The public key data. + * kse The new key share entry object. + * returns 0 on success and other values indicate failure. + */ +int TLSX_KeyShare_Use(WOLFSSL* ssl, word16 group, word16 len, byte* data, + KeyShareEntry **kse) +{ + int ret = 0; + TLSX* extension; + KeyShareEntry* keyShareEntry = NULL; + + /* Find the KeyShare extension if it exists. */ + extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + if (extension == NULL) { + /* Push new KeyShare extension. */ + ret = TLSX_Push(&ssl->extensions, TLSX_KEY_SHARE, NULL, ssl->heap); + if (ret != 0) + return ret; + + extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + if (extension == NULL) + return MEMORY_E; + } + + /* Try to find the key share entry with this group. */ + keyShareEntry = (KeyShareEntry*)extension->data; + while (keyShareEntry != NULL) { + if (keyShareEntry->group == group) + break; + keyShareEntry = keyShareEntry->next; + } + + /* Create a new key share entry if not found. */ + if (keyShareEntry == NULL) { + ret = TLSX_KeyShare_New((KeyShareEntry**)&extension->data, group, + ssl->heap, &keyShareEntry); + if (ret != 0) + return ret; + } + + if (data != NULL) { + /* Keep the public key data and free when finished. */ + if (keyShareEntry->ke != NULL) + XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_TLSX); + keyShareEntry->ke = data; + keyShareEntry->keLen = len; + } + else { + /* Generate a key pair. */ + ret = TLSX_KeyShare_GenKey(ssl, keyShareEntry); + if (ret != 0) + return ret; + } + + if (kse != NULL) + *kse = keyShareEntry; + + return 0; +} + +/* Set an empty Key Share extension. + * + * ssl The SSL/TLS object. + * returns 0 on success and other values indicate failure. + */ +int TLSX_KeyShare_Empty(WOLFSSL* ssl) +{ + int ret = 0; + TLSX* extension; + + /* Find the KeyShare extension if it exists. */ + extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + if (extension == NULL) { + /* Push new KeyShare extension. */ + ret = TLSX_Push(&ssl->extensions, TLSX_KEY_SHARE, NULL, ssl->heap); + } + else if (extension->data != NULL) { + TLSX_KeyShare_FreeAll(extension->data, ssl->heap); + extension->data = NULL; + } + + return ret; +} + +/* Returns whether this group is supported. + * + * namedGroup The named group to check. + * returns 1 when supported or 0 otherwise. + */ +static int TLSX_KeyShare_IsSupported(int namedGroup) +{ + switch (namedGroup) { + #ifdef HAVE_FFDHE_2048 + case WOLFSSL_FFDHE_2048: + break; + #endif + #ifdef HAVE_FFDHE_3072 + case WOLFSSL_FFDHE_3072: + break; + #endif + #ifdef HAVE_FFDHE_4096 + case WOLFSSL_FFDHE_4096: + break; + #endif + #ifdef HAVE_FFDHE_6144 + case WOLFSSL_FFDHE_6144: + break; + #endif + #ifdef HAVE_FFDHE_8192 + case WOLFSSL_FFDHE_8192: + break; + #endif + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP256R1: + break; + #endif /* !NO_ECC_SECP */ + #endif + #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP384R1: + break; + #endif /* !NO_ECC_SECP */ + #endif + #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + case WOLFSSL_ECC_SECP521R1: + break; + #endif /* !NO_ECC_SECP */ + #endif + #ifdef HAVE_CURVE25519 + case WOLFSSL_ECC_X25519: + break; + #endif + #ifdef HAVE_X448 + case WOLFSSL_ECC_X448: + break; + #endif + default: + return 0; + } + + return 1; +} + +/* Set a key share that is supported by the client into extensions. + * + * ssl The SSL/TLS object. + * returns BAD_KEY_SHARE_DATA if no supported group has a key share, + * 0 if a supported group has a key share and other values indicate an error. + */ +static int TLSX_KeyShare_SetSupported(WOLFSSL* ssl) +{ + int ret; + TLSX* extension; + EllipticCurve* curve = NULL; + + /* Use SupportedGroup's order. */ + extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS); + if (extension != NULL) + curve = (EllipticCurve*)extension->data; + for (; curve != NULL; curve = curve->next) { + if (TLSX_KeyShare_IsSupported(curve->name) && + !TLSX_KeyShare_Find(ssl, curve->name)) { + break; + } + } + if (curve == NULL) + return BAD_KEY_SHARE_DATA; + + /* Delete the old key share data list. */ + extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + if (extension != NULL) { + TLSX_KeyShare_FreeAll(extension->data, ssl->heap); + extension->data = NULL; + } + + /* Add in the chosen group. */ + ret = TLSX_KeyShare_Use(ssl, curve->name, 0, NULL, NULL); + if (ret != 0) + return ret; + + /* Set extension to be in reponse. */ + extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + extension->resp = 1; + + return 0; +} + +/* Establish the secret based on the key shares received from the client. + * + * ssl The SSL/TLS object. + * returns 0 on success and other values indicate failure. + */ +int TLSX_KeyShare_Establish(WOLFSSL *ssl) +{ + int ret; + TLSX* extension; + KeyShareEntry* clientKSE = NULL; + KeyShareEntry* serverKSE; + KeyShareEntry* list = NULL; + byte* ke; + word16 keLen; + + /* Find the KeyShare extension if it exists. */ + extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + if (extension != NULL) + list = (KeyShareEntry*)extension->data; + + /* TODO: [TLS13] Server's preference and sending back SupportedGroups */ + /* Use client's preference. */ + for (clientKSE = list; clientKSE != NULL; clientKSE = clientKSE->next) { + /* Check consistency now - extensions in any order. */ + if (!TLSX_SupportedGroups_Find(ssl, clientKSE->group)) + return BAD_KEY_SHARE_DATA; + + /* Check if server supports group. */ + if (TLSX_KeyShare_IsSupported(clientKSE->group)) + break; + } + /* No supported group found - send HelloRetryRequest. */ + if (clientKSE == NULL) { + ret = TLSX_KeyShare_SetSupported(ssl); + /* Return KEY_SHARE_ERROR to indicate HelloRetryRequest required. */ + if (ret == 0) + return KEY_SHARE_ERROR; + return ret; + } + + list = NULL; + /* Generate a new key pair. */ + ret = TLSX_KeyShare_New(&list, clientKSE->group, ssl->heap, &serverKSE); + if (ret != 0) + return ret; + ret = TLSX_KeyShare_GenKey(ssl, serverKSE); + if (ret != 0) + return ret; + + /* Move private key to client entry. */ + if (clientKSE->key != NULL) + XFREE(clientKSE->key, heap, DYNAMIC_TYPE_TLSX); + clientKSE->key = serverKSE->key; + serverKSE->key = NULL; + clientKSE->keyLen = serverKSE->keyLen; + + /* Calculate secret. */ + ret = TLSX_KeyShare_Process(ssl, clientKSE); + if (ret != 0) + return ret; + + /* Swap public keys for sending to client. */ + ke = serverKSE->ke; + keLen = serverKSE->keLen; + serverKSE->ke = clientKSE->ke; + serverKSE->keLen = clientKSE->keLen; + clientKSE->ke = ke; + clientKSE->keLen = keLen; + + extension->resp = 1; + + /* Dispose of temporary server extension. */ + TLSX_KeyShare_FreeAll(list, ssl->heap); + + return 0; +} + +#define KS_FREE_ALL TLSX_KeyShare_FreeAll +#define KS_GET_SIZE TLSX_KeyShare_GetSize +#define KS_WRITE TLSX_KeyShare_Write +#define KS_PARSE TLSX_KeyShare_Parse + +#else + +#define KS_FREE_ALL(a, b) +#define KS_GET_SIZE(a, b) 0 +#define KS_WRITE(a, b, c) 0 +#define KS_PARSE(a, b, c, d) 0 + +#endif /* WOLFSSL_TLS13 */ + +/******************************************************************************/ +/* Pre-Shared Key */ +/******************************************************************************/ + +#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && !defined(NO_PSK) +/* Free the pre-shared key dynamic data. + * + * list The linked list of key share entry objects. + * heap The heap used for allocation. + */ +static void TLSX_PreSharedKey_FreeAll(PreSharedKey* list, void* heap) +{ + PreSharedKey* current; + + while ((current = list) != NULL) { + list = current->next; + XFREE(current->identity, heap, DYNAMIC_TYPE_TLSX); + XFREE(current, heap, DYNAMIC_TYPE_TLSX); + } + + (void)heap; +} + +/* Get the size of the encoded pre shared key extension. + * + * list The linked list of pre-shared key extensions. + * msgType The type of the message this extension is being written into. + * returns the number of bytes of the encoded pre-shared key extension or + * SANITY_MSG_E to indicate invalid message type. + */ +static word16 TLSX_PreSharedKey_GetSize(PreSharedKey* list, byte msgType) +{ + if (msgType == client_hello) { + /* Length of identities + Length of binders. */ + word16 len = OPAQUE16_LEN + OPAQUE16_LEN; + while (list != NULL) { + /* Each entry has: identity, ticket age and binder. */ + len += OPAQUE16_LEN + list->identityLen + OPAQUE32_LEN + + OPAQUE8_LEN + list->binderLen; + list = list->next; + } + return len; + } + + if (msgType == server_hello) { + return OPAQUE16_LEN; + } + + return 0; +} + +/* The number of bytes to be written for the binders. + * + * list The linked list of pre-shared key extensions. + * msgType The type of the message this extension is being written into. + * returns the number of bytes of the encoded pre-shared key extension or + * SANITY_MSG_E to indicate invalid message type. + */ +word16 TLSX_PreSharedKey_GetSizeBinders(PreSharedKey* list, byte msgType) +{ + word16 len; + + if (msgType != client_hello) + return SANITY_MSG_E; + + /* Length of all binders. */ + len = OPAQUE16_LEN; + while (list != NULL) { + len += OPAQUE8_LEN + list->binderLen; + list = list->next; + } + + return len; +} + +/* Writes the pre-shared key extension into the output buffer - binders only. + * Assumes that the the output buffer is big enough to hold data. + * + * list The linked list of key share entries. + * output The buffer to write into. + * msgType The type of the message this extension is being written into. + * returns the number of bytes written into the buffer. + */ +word16 TLSX_PreSharedKey_WriteBinders(PreSharedKey* list, byte* output, + byte msgType) +{ + PreSharedKey* current = list; + word16 idx = 0; + word16 lenIdx; + word16 len; + + if (msgType != client_hello) + return SANITY_MSG_E; + + /* Skip length of all binders. */ + lenIdx = idx; + idx += OPAQUE16_LEN; + while (current != NULL) { + /* Binder data length. */ + output[idx++] = current->binderLen; + /* Binder data. */ + XMEMCPY(output + idx, current->binder, current->binderLen); + idx += current->binderLen; + + current = current->next; + } + /* Length of the binders. */ + len = idx - lenIdx - OPAQUE16_LEN; + c16toa(len, output + lenIdx); + + return idx; +} + + +/* Writes the pre-shared key extension into the output buffer. + * Assumes that the the output buffer is big enough to hold data. + * + * list The linked list of key share entries. + * output The buffer to write into. + * msgType The type of the message this extension is being written into. + * returns the number of bytes written into the buffer. + */ +static word16 TLSX_PreSharedKey_Write(PreSharedKey* list, byte* output, + byte msgType) +{ + if (msgType == client_hello) { + PreSharedKey* current = list; + word16 idx = 0; + word16 lenIdx; + word16 len; + + /* Write identites only. Binders after HMACing over this. */ + lenIdx = idx; + idx += OPAQUE16_LEN; + while (current != NULL) { + /* Identity length */ + c16toa(current->identityLen, output + idx); + idx += OPAQUE16_LEN; + /* Identity data */ + XMEMCPY(output + idx, current->identity, current->identityLen); + idx += current->identityLen; + + /* Obfuscated ticket age. */ + c32toa(current->ticketAge, output + idx); + idx += OPAQUE32_LEN; + + current = current->next; + } + /* Length of the identites. */ + len = idx - lenIdx - OPAQUE16_LEN; + c16toa(len, output + lenIdx); + + /* Don't include binders here. + * The binders are based on the hash of all the ClientHello data up to + * and include the identities written above. + */ + idx += TLSX_PreSharedKey_GetSizeBinders(list, msgType); + + return idx; + } + + if (msgType == server_hello) { + word16 i; + + /* Find the index of the chosen identity. */ + for (i=0; list != NULL && !list->chosen; i++) + list = list->next; + if (list == NULL) + return BUILD_MSG_ERROR; + + /* The index of the identity chosen by the server from the list supplied + * by the client. + */ + c16toa(i, output); + return OPAQUE16_LEN; + } + + return 0; +} + +/* Parse the pre-shared key extension. + * Different formats in different messages. + * + * ssl The SSL/TLS object. + * input The extension data. + * length The length of the extension data. + * msgType The type of the message this extension is being parsed from. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_PreSharedKey_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte msgType) +{ + TLSX* extension; + PreSharedKey* list; + + if (msgType == client_hello) { + int ret; + word16 len; + word16 idx = 0; + + /* Length of identities and of binders. */ + if (length - idx < OPAQUE16_LEN + OPAQUE16_LEN) + return BUFFER_E; + + /* Length of identities. */ + ato16(input + idx, &len); + idx += OPAQUE16_LEN; + if (len < MIN_PSK_ID_LEN || length - idx < len) + return BUFFER_E; + + /* Create a pre-shared key object for each identity. */ + while (len > 0) { + byte* identity; + word16 identityLen; + word32 age; + + if (len < OPAQUE16_LEN) + return BUFFER_E; + + /* Length of identity. */ + ato16(input + idx, &identityLen); + idx += OPAQUE16_LEN; + if (len < OPAQUE16_LEN + identityLen + OPAQUE32_LEN) + return BUFFER_E; + /* Cache identity pointer. */ + identity = input + idx; + idx += identityLen; + /* Ticket age. */ + ato32(input + idx, &age); + idx += OPAQUE32_LEN; + + ret = TLSX_PreSharedKey_Use(ssl, identity, identityLen, age, 0, 1, + NULL); + if (ret != 0) + return ret; + + /* Done with this identity. */ + len -= OPAQUE16_LEN + identityLen + OPAQUE32_LEN; + } + + /* Find the list of identities sent to server. */ + extension = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (extension == NULL) + return PSK_KEY_ERROR; + list = (PreSharedKey*)extension->data; + + /* Length of binders. */ + ato16(input + idx, &len); + idx += OPAQUE16_LEN; + if (len < MIN_PSK_BINDERS_LEN || length - idx < len) + return BUFFER_E; + + /* Set binder for each identity. */ + while (list != NULL && len > 0) { + /* Length of binder */ + list->binderLen = input[idx++]; + if (list->binderLen < SHA256_DIGEST_SIZE || + list->binderLen > MAX_DIGEST_SIZE) + return BUFFER_E; + if (len < OPAQUE8_LEN + list->binderLen) + return BUFFER_E; + + /* Copy binder into static buffer. */ + XMEMCPY(list->binder, input + idx, list->binderLen); + idx += list->binderLen; + + /* Done with binder entry. */ + len -= OPAQUE8_LEN + list->binderLen; + + /* Next identity. */ + list = list->next; + } + if (list != NULL || len != 0) + return BUFFER_E; + + return 0; + } + + if (msgType == server_hello) { + word16 idx; + + /* Index of identity chosen by server. */ + if (length != OPAQUE16_LEN) + return BUFFER_E; + ato16(input, &idx); + + /* Find the list of identities sent to server. */ + extension = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (extension == NULL) + return PSK_KEY_ERROR; + list = (PreSharedKey*)extension->data; + + /* Mark the identity as chosen. */ + for (; list != NULL && idx > 0; idx--) + list = list->next; + if (list == NULL) + return PSK_KEY_ERROR; + list->chosen = 1; + + 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 ) { + return PSK_KEY_ERROR; + } + } + /* 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; + } + + return SANITY_MSG_E; +} + +/* Create a new pre-shared key and put it into the list. + * + * list The linked list of pre-shared key. + * identity The identity. + * len The length of the identity data. + * heap The memory to allocate with. + * preSharedKey The new pre-shared key object. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_PreSharedKey_New(PreSharedKey** list, byte* identity, + word16 len, void *heap, + PreSharedKey** preSharedKey) +{ + PreSharedKey* psk; + + psk = (PreSharedKey*)XMALLOC(sizeof(PreSharedKey), heap, DYNAMIC_TYPE_TLSX); + if (psk == NULL) + return MEMORY_E; + XMEMSET(psk, 0, sizeof(*psk)); + + /* Make a copy of the identity data. */ + psk->identity = (byte*)XMALLOC(len, heap, DYNAMIC_TYPE_TLSX); + if (psk->identity == NULL) { + XFREE(psk, heap, DYNAMIC_TYPE_TLSX); + return MEMORY_E; + } + XMEMCPY(psk->identity, identity, len); + psk->identityLen = len; + + /* Add it to the end and maintain the links. */ + while (*list != NULL) + list = &((*list)->next); + *list = psk; + *preSharedKey = psk; + + return 0; +} + +static INLINE byte GetHmacLength(int hmac) +{ + switch (hmac) { + #ifndef NO_SHA256 + case sha256_mac: + return SHA256_DIGEST_SIZE; + #endif + #ifndef NO_SHA384 + case sha384_mac: + return SHA384_DIGEST_SIZE; + #endif + #ifndef NO_SHA512 + case sha512_mac: + return SHA512_DIGEST_SIZE; + #endif + } + return 0; +} + +/* Use the data to create a new pre-shared key object in the extensions. + * + * ssl The SSL/TLS object. + * identity The identity. + * len The length of the identity data. + * age The age of the identity. + * hmac The HMAC algorithm. + * resumption The PSK is for resumption of a session. + * preSharedKey The new pre-shared key object. + * returns 0 on success and other values indicate failure. + */ +int TLSX_PreSharedKey_Use(WOLFSSL* ssl, byte* identity, word16 len, word32 age, + byte hmac, byte resumption, + PreSharedKey **preSharedKey) +{ + int ret = 0; + TLSX* extension; + PreSharedKey* psk = NULL; + + /* Find the pre-shared key extension if it exists. */ + extension = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (extension == NULL) { + /* Push new pre-shared key extension. */ + ret = TLSX_Push(&ssl->extensions, TLSX_PRE_SHARED_KEY, NULL, ssl->heap); + if (ret != 0) + return ret; + + extension = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (extension == NULL) + return MEMORY_E; + } + + /* Try to find the pre-shared key with this identity. */ + psk = (PreSharedKey*)extension->data; + while (psk != NULL) { + if ((psk->identityLen == len) && + (XMEMCMP(psk->identity, identity, len) == 0)) { + break; + } + psk = psk->next; + } + + /* Create a new pre-shared key object if not found. */ + if (psk == NULL) { + ret = TLSX_PreSharedKey_New((PreSharedKey**)&extension->data, identity, + len, ssl->heap, &psk); + if (ret != 0) + return ret; + } + + /* Update/set age and HMAC algorithm. */ + psk->ticketAge = age; + psk->hmac = hmac; + psk->resumption = resumption; + psk->binderLen = GetHmacLength(psk->hmac); + + if (preSharedKey != NULL) + *preSharedKey = psk; + + return 0; +} + +#define PSK_FREE_ALL TLSX_PreSharedKey_FreeAll +#define PSK_GET_SIZE TLSX_PreSharedKey_GetSize +#define PSK_WRITE TLSX_PreSharedKey_Write +#define PSK_PARSE TLSX_PreSharedKey_Parse + +#else + +#define PSK_FREE_ALL(a, b) +#define PSK_GET_SIZE(a, b) 0 +#define PSK_WRITE(a, b, c) 0 +#define PSK_PARSE(a, b, c, d) 0 + +#endif + +/******************************************************************************/ +/* PSK Key Exchange Modes */ +/******************************************************************************/ + +#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) +/* Get the size of the encoded PSK KE modes extension. + * Only in ClientHello. + * + * modes The PSK KE mode bit string. + * msgType The type of the message this extension is being written into. + * returns the number of bytes of the encoded key share extension. + */ +static word16 TLSX_PskKeModes_GetSize(byte modes, byte msgType) +{ + if (msgType == client_hello) { + /* Format: Len | Modes* */ + word16 len = OPAQUE8_LEN; + /* Check whether each possible mode is to be written. */ + if (modes & (1 << PSK_KE)) + len += OPAQUE8_LEN; + if (modes & (1 << PSK_DHE_KE)) + len += OPAQUE8_LEN; + return len; + } + + return SANITY_MSG_E; +} + +/* Writes the PSK KE modes extension into the output buffer. + * Assumes that the the output buffer is big enough to hold data. + * Only in ClientHello. + * + * modes The PSK KE mode bit string. + * output The buffer to write into. + * msgType The type of the message this extension is being written into. + * returns the number of bytes written into the buffer. + */ +static word16 TLSX_PskKeModes_Write(byte modes, byte* output, byte msgType) +{ + if (msgType == client_hello) { + /* Format: Len | Modes* */ + int idx = OPAQUE8_LEN; + + /* Write out each possible mode. */ + if (modes & (1 << PSK_KE)) + output[idx++] = PSK_KE; + if (modes & (1 << PSK_DHE_KE)) + output[idx++] = PSK_DHE_KE; + /* Write out length of mode list. */ + output[0] = idx - OPAQUE8_LEN; + + return idx; + } + + return SANITY_MSG_E; +} + +/* Parse the PSK KE modes extension. + * Only in ClientHello. + * + * ssl The SSL/TLS object. + * input The extension data. + * length The length of the extension data. + * msgType The type of the message this extension is being parsed from. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_PskKeModes_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte msgType) +{ + int ret; + + if (msgType == client_hello) { + /* Format: Len | Modes* */ + int idx = 0; + int len; + byte modes = 0; + + /* Ensure length byte exists. */ + if (length < OPAQUE8_LEN) + return BUFFER_E; + + /* Get length of mode list and ensure that is the only data. */ + len = input[0]; + if (length - OPAQUE8_LEN != len) + return BUFFER_E; + + idx = OPAQUE8_LEN; + /* Set a bit for each recognized modes. */ + while (len > 0) { + /* Ignore unrecognized modes. */ + if (input[idx] <= PSK_DHE_KE) + modes |= 1 << input[idx]; + idx++; + len--; + } + + ret = TLSX_PskKeModes_Use(ssl, modes); + if (ret != 0) + return ret; + + return 0; + } + + return SANITY_MSG_E; +} + +/* Use the data to create a new PSK Key Exchange Modes object in the extensions. + * + * ssl The SSL/TLS object. + * modes The PSK key exchange modes. + * returns 0 on success and other values indicate failure. + */ +int TLSX_PskKeModes_Use(WOLFSSL* ssl, byte modes) +{ + int ret = 0; + TLSX* extension; + + /* Find the PSK key exchange modes extension if it exists. */ + extension = TLSX_Find(ssl->extensions, TLSX_PSK_KEY_EXCHANGE_MODES); + if (extension == NULL) { + /* Push new PSK key exchange modes extension. */ + ret = TLSX_Push(&ssl->extensions, TLSX_PSK_KEY_EXCHANGE_MODES, NULL, + ssl->heap); + if (ret != 0) + return ret; + + extension = TLSX_Find(ssl->extensions, TLSX_PSK_KEY_EXCHANGE_MODES); + if (extension == NULL) + return MEMORY_E; + } + + extension->val = modes; + + return 0; +} + +#define PKM_GET_SIZE TLSX_PskKeModes_GetSize +#define PKM_WRITE TLSX_PskKeModes_Write +#define PKM_PARSE TLSX_PskKeModes_Parse + +#else + +#define PKM_GET_SIZE(a, b) 0 +#define PKM_WRITE(a, b, c) 0 +#define PKM_PARSE(a, b, c, d) 0 + +#endif + /******************************************************************************/ /* TLS Extensions Framework */ /******************************************************************************/ @@ -4259,6 +6094,24 @@ void TLSX_FreeAll(TLSX* list, void* heap) case TLSX_APPLICATION_LAYER_PROTOCOL: ALPN_FREE_ALL((ALPN*)extension->data, heap); break; + +#ifdef WOLFSSL_TLS13 + case TLSX_SUPPORTED_VERSIONS: + break; + + case TLSX_KEY_SHARE: + KS_FREE_ALL((KeyShareEntry*)extension->data, heap); + break; + + #ifndef NO_PSK + case TLSX_PRE_SHARED_KEY: + PSK_FREE_ALL((PreSharedKey*)extension->data, heap); + break; + + case TLSX_PSK_KEY_EXCHANGE_MODES: + break; + #endif +#endif } XFREE(extension, heap, DYNAMIC_TYPE_TLSX); @@ -4273,10 +6126,11 @@ int TLSX_SupportExtensions(WOLFSSL* ssl) { } /** Tells the buffered size of the extensions in a list. */ -static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest) +static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType) { - TLSX* extension; + TLSX* extension; word16 length = 0; + byte isRequest = (msgType == client_hello); while ((extension = list)) { list = extension->next; @@ -4342,6 +6196,25 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest) length += ALPN_GET_SIZE((ALPN*)extension->data); break; +#ifdef WOLFSSL_TLS13 + case TLSX_SUPPORTED_VERSIONS: + length += SV_GET_SIZE(extension->data); + break; + + case TLSX_KEY_SHARE: + length += KS_GET_SIZE(extension->data, msgType); + break; + + #ifndef NO_PSK + case TLSX_PRE_SHARED_KEY: + length += PSK_GET_SIZE(extension->data, msgType); + break; + + case TLSX_PSK_KEY_EXCHANGE_MODES: + length += PKM_GET_SIZE(extension->val, msgType); + break; + #endif +#endif } /* marks the extension as processed so ctx level */ @@ -4354,11 +6227,12 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest) /** Writes the extensions of a list in a buffer. */ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore, - byte isRequest) + byte msgType) { TLSX* extension; word16 offset = 0; word16 length_offset = 0; + byte isRequest = (msgType == client_hello); while ((extension = list)) { list = extension->next; @@ -4379,45 +6253,55 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore, /* extension data should be written internally. */ switch (extension->type) { case TLSX_SERVER_NAME: - if (isRequest) + if (isRequest) { + WOLFSSL_MSG("SNI extension to write"); offset += SNI_WRITE((SNI*)extension->data, output + offset); + } break; case TLSX_MAX_FRAGMENT_LENGTH: + WOLFSSL_MSG("Max Fragment Length extension to write"); offset += MFL_WRITE((byte*)extension->data, output + offset); break; case TLSX_TRUNCATED_HMAC: + WOLFSSL_MSG("Truncated HMAC extension to write"); /* always empty. */ break; case TLSX_SUPPORTED_GROUPS: + WOLFSSL_MSG("Elliptic Curves extension to write"); offset += EC_WRITE((EllipticCurve*)extension->data, output + offset); break; case TLSX_STATUS_REQUEST: + WOLFSSL_MSG("Certificate Status Request extension to write"); offset += CSR_WRITE((CertificateStatusRequest*)extension->data, output + offset, isRequest); break; case TLSX_STATUS_REQUEST_V2: + WOLFSSL_MSG("Certificate Status Request v2 extension to write"); offset += CSR2_WRITE( (CertificateStatusRequestItemV2*)extension->data, output + offset, isRequest); break; case TLSX_RENEGOTIATION_INFO: + WOLFSSL_MSG("Secure Renegotiation extension to write"); offset += SCR_WRITE((SecureRenegotiation*)extension->data, output + offset, isRequest); break; case TLSX_SESSION_TICKET: + WOLFSSL_MSG("Session Ticket extension to write"); offset += WOLF_STK_WRITE((SessionTicket*)extension->data, output + offset, isRequest); break; case TLSX_QUANTUM_SAFE_HYBRID: + WOLFSSL_MSG("Quantum-Safe-Hybrid extension to write"); if (isRequest) { offset += QSH_WRITE((QSHScheme*)extension->data, output + offset); } @@ -4426,8 +6310,33 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore, break; case TLSX_APPLICATION_LAYER_PROTOCOL: + WOLFSSL_MSG("ALPN extension to write"); offset += ALPN_WRITE((ALPN*)extension->data, output + offset); break; + +#ifdef WOLFSSL_TLS13 + case TLSX_SUPPORTED_VERSIONS: + WOLFSSL_MSG("Supported Versions extension to write"); + offset += SV_WRITE(extension->data, output + offset); + break; + + case TLSX_KEY_SHARE: + WOLFSSL_MSG("Key Share extension to write"); + offset += KS_WRITE(extension->data, output + offset, msgType); + break; + + #ifndef NO_PSK + case TLSX_PRE_SHARED_KEY: + WOLFSSL_MSG("Pre-Shared Key extension to write"); + offset += PSK_WRITE(extension->data, output + offset, msgType); + break; + + case TLSX_PSK_KEY_EXCHANGE_MODES: + WOLFSSL_MSG("PSK Key Exchange Modes extension to write"); + offset += PKM_WRITE(extension->val, output + offset, msgType); + break; + #endif +#endif } /* writes extension data length. */ @@ -4634,7 +6543,6 @@ static byte* TLSX_QSHKeyFind_Pub(QSHKey* qsh, word16* pubLen, word16 name) } #endif /* HAVE_QSH */ - int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) { int ret = 0; @@ -4728,72 +6636,86 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) #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); + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_ECC_SECP160R1, ssl->heap); if (ret != SSL_SUCCESS) return ret; #endif #ifdef HAVE_ECC_SECPR2 - ret = TLSX_UseSupportedCurve(&ssl->extensions, WOLFSSL_ECC_SECP160R2, ssl->heap); + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_ECC_SECP160R2, ssl->heap); if (ret != SSL_SUCCESS) return ret; #endif #ifdef HAVE_ECC_KOBLITZ - ret = TLSX_UseSupportedCurve(&ssl->extensions, WOLFSSL_ECC_SECP160K1, ssl->heap); + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_ECC_SECP160K1, ssl->heap); if (ret != SSL_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); + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_ECC_SECP192R1, ssl->heap); if (ret != SSL_SUCCESS) return ret; #endif #ifdef HAVE_ECC_KOBLITZ - ret = TLSX_UseSupportedCurve(&ssl->extensions, WOLFSSL_ECC_SECP192K1, ssl->heap); + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_ECC_SECP192K1, ssl->heap); if (ret != SSL_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); + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_ECC_SECP224R1, ssl->heap); if (ret != SSL_SUCCESS) return ret; #endif #ifdef HAVE_ECC_KOBLITZ - ret = TLSX_UseSupportedCurve(&ssl->extensions, WOLFSSL_ECC_SECP224K1, ssl->heap); + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_ECC_SECP224K1, ssl->heap); if (ret != SSL_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); + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_ECC_SECP256R1, ssl->heap); if (ret != SSL_SUCCESS) return ret; #endif #ifdef HAVE_ECC_KOBLITZ - ret = TLSX_UseSupportedCurve(&ssl->extensions, WOLFSSL_ECC_SECP256K1, ssl->heap); + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_ECC_SECP256K1, ssl->heap); if (ret != SSL_SUCCESS) return ret; #endif #ifdef HAVE_ECC_BRAINPOOL - ret = TLSX_UseSupportedCurve(&ssl->extensions, WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap); + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap); if (ret != SSL_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); + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_ECC_SECP384R1, ssl->heap); if (ret != SSL_SUCCESS) return ret; #endif #ifdef HAVE_ECC_BRAINPOOL - ret = TLSX_UseSupportedCurve(&ssl->extensions, WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap); + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap); if (ret != SSL_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); + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap); if (ret != SSL_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); + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_ECC_SECP521R1, ssl->heap); if (ret != SSL_SUCCESS) return ret; #endif #endif @@ -4801,6 +6723,113 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) #endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */ } /* is not server */ + #ifdef WOLFSSL_TLS13 + if (!isServer && IsAtLeastTLSv1_3(ssl->version)) { + /* Add mandatory TLS v1.3 extension: supported version */ + WOLFSSL_MSG("Adding supported versions extension"); + if ((ret = TLSX_SetSupportedVersions(&ssl->extensions, ssl, + ssl->heap)) != 0) + return ret; + + /* Add FFDHE supported groups. */ + #ifdef HAVE_FFDHE_2048 + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_FFDHE_2048, ssl->heap); + if (ret != SSL_SUCCESS) + return ret; + #endif + #ifdef HAVE_FFDHE_3072 + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_FFDHE_3072, ssl->heap); + if (ret != SSL_SUCCESS) + return ret; + #endif + #ifdef HAVE_FFDHE_4096 + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_FFDHE_4096, ssl->heap); + if (ret != SSL_SUCCESS) + return ret; + #endif + #ifdef HAVE_FFDHE_6144 + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_FFDHE_6144, ssl->heap); + if (ret != SSL_SUCCESS) + return ret; + #endif + #ifdef HAVE_FFDHE_8192 + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_FFDHE_8192, ssl->heap); + if (ret != SSL_SUCCESS) + return ret; + #endif + ret = 0; + + if (TLSX_Find(ssl->extensions, TLSX_KEY_SHARE) == NULL) { + #if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \ + !defined(NO_ECC_SECP) + ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_SECP256R1, 0, NULL, + NULL); + #elif (!defined(NO_ECC384) || defined(HAVE_ALL_CURVES)) && \ + !defined(NO_ECC_SECP) + ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_SECP384R1, 0, NULL, + NULL); + #elif (!defined(NO_ECC521) || defined(HAVE_ALL_CURVES)) && \ + !defined(NO_ECC_SECP) + ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_SECP521R1, 0, NULL, + NULL); + #elif defined(HAVE_FFDHE_2048) + ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_2048, 0, NULL, NULL); + #elif defined(HAVE_FFDHE_3072) + ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_3072, 0, NULL, NULL); + #elif defined(HAVE_FFDHE_4096) + ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_4096, 0, NULL, NULL); + #elif defined(HAVE_FFDHE_6144) + ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_6144, 0, NULL, NULL); + #elif defined(HAVE_FFDHE_8192) + ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_8192, 0, NULL, NULL); + #else + ret = KEY_SHARE_ERROR; + #endif + if (ret != 0) + return ret; + } + + #if defined(HAVE_SESSION_TICKET) && !defined(NO_PSK) + if (ssl->options.resuming) { + WOLFSSL_SESSION* sess = &ssl->session; + word32 milli; + byte modes; + + /* Determine the MAC algorithm for the cipher suite used. */ + ssl->options.cipherSuite0 = sess->cipherSuite0; + ssl->options.cipherSuite = sess->cipherSuite; + SetCipherSpecs(ssl); + milli = TimeNowInMilliseconds() - sess->ticketSeen + + sess->ticketAdd; + /* Pre-shared key is mandatory extension for resumption. */ + ret = TLSX_PreSharedKey_Use(ssl, sess->ticket, sess->ticketLen, + milli, ssl->specs.mac_algorithm, 1, + ssl->heap); + if (ret != 0) + return ret; + + /* Pre-shared key modes: mandatory extension for resumption. */ + modes = 1 << PSK_KE; + #if !defined(NO_DH) || defined(HAVE_ECC) + if (!ssl->options.noPskDheKe) + modes |= 1 << PSK_DHE_KE; + #endif + ret = TLSX_PskKeModes_Use(ssl, modes); + if (ret != 0) + return ret; + } + #endif + /* TODO: [TLS13] Add PSKs */ + } + + #endif + + (void)isServer; (void)public_key; (void)public_key_len; (void)ssl; @@ -4825,12 +6854,24 @@ word16 TLSX_GetRequestSize(WOLFSSL* ssl) EC_VALIDATE_REQUEST(ssl, semaphore); QSH_VALIDATE_REQUEST(ssl, semaphore); WOLF_STK_VALIDATE_REQUEST(ssl); +#if defined(WOLFSSL_TLS13) + if (!IsAtLeastTLSv1_3(ssl->version)) { + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); + #ifndef NO_PSK + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PSK_KEY_EXCHANGE_MODES)); + #endif + } +#endif if (ssl->extensions) - length += TLSX_GetSize(ssl->extensions, semaphore, 1); + length += TLSX_GetSize(ssl->extensions, semaphore, client_hello); - if (ssl->ctx && ssl->ctx->extensions) - length += TLSX_GetSize(ssl->ctx->extensions, semaphore, 1); + if (ssl->ctx && ssl->ctx->extensions) { + length += TLSX_GetSize(ssl->ctx->extensions, semaphore, + client_hello); + } if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) length += HELLO_EXT_SZ + HELLO_EXT_SIGALGO_SZ @@ -4861,14 +6902,26 @@ word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output) EC_VALIDATE_REQUEST(ssl, semaphore); WOLF_STK_VALIDATE_REQUEST(ssl); QSH_VALIDATE_REQUEST(ssl, semaphore); +#if defined(WOLFSSL_TLS13) + if (!IsAtLeastTLSv1_3(ssl->version)) { + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); + #ifndef NO_PSK + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PSK_KEY_EXCHANGE_MODES)); + #endif + } + #ifndef NO_PSK + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); + #endif +#endif if (ssl->extensions) - offset += TLSX_Write(ssl->extensions, output + offset, - semaphore, 1); + offset += TLSX_Write(ssl->extensions, output + offset, semaphore, + client_hello); if (ssl->ctx && ssl->ctx->extensions) offset += TLSX_Write(ssl->ctx->extensions, output + offset, - semaphore, 1); + semaphore, client_hello); if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) { int i; @@ -4899,6 +6952,16 @@ word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output) } #endif +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && ssl->options.resuming) { + #ifndef NO_PSK + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); + #endif + offset += TLSX_Write(ssl->extensions, output + offset, semaphore, + client_hello); + } +#endif + if (offset > OPAQUE16_LEN) c16toa(offset - OPAQUE16_LEN, output); /* extensions length */ } @@ -4911,11 +6974,33 @@ word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output) #ifndef NO_WOLFSSL_SERVER /** Tells the buffered size of extensions to be sent into the server hello. */ -word16 TLSX_GetResponseSize(WOLFSSL* ssl) +word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType) { word16 length = 0; byte semaphore[SEMAPHORE_SIZE] = {0}; + switch (msgType) { + case server_hello: +#ifdef WOLFSSL_TLS13 + case hello_retry_request: + if (ssl->options.tls1_3) { + XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); + #ifndef NO_PSK + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); + #endif + } + break; + case encrypted_extensions: + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); + #ifndef NO_PSK + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); + #endif +#endif + break; + } + #ifdef HAVE_QSH /* change response if not using TLS_QSH */ if (!ssl->options.haveQSH) { @@ -4926,35 +7011,58 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl) #endif #ifdef HAVE_EXTENDED_MASTER - if (ssl->options.haveEMS) + if (ssl->options.haveEMS && msgType == server_hello) length += HELLO_EXT_SZ; #endif if (TLSX_SupportExtensions(ssl)) - length += TLSX_GetSize(ssl->extensions, semaphore, 0); + length += TLSX_GetSize(ssl->extensions, semaphore, msgType); /* All the response data is set at the ssl object only, so no ctx here. */ - if (length) + if (length || (msgType != server_hello)) length += OPAQUE16_LEN; /* for total length storage. */ return length; } /** Writes the server hello extensions into a buffer. */ -word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output) +word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType) { word16 offset = 0; if (TLSX_SupportExtensions(ssl) && output) { byte semaphore[SEMAPHORE_SIZE] = {0}; + switch (msgType) { + case server_hello: +#ifdef WOLFSSL_TLS13 + case hello_retry_request: + if (ssl->options.tls1_3) { + XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); + #ifndef NO_PSK + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); + #endif + } + break; + case encrypted_extensions: + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); + #ifndef NO_PSK + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); + #endif +#endif + break; + } + offset += OPAQUE16_LEN; /* extensions length */ - offset += TLSX_Write(ssl->extensions, output + offset, semaphore, 0); + offset += TLSX_Write(ssl->extensions, output + offset, semaphore, + msgType); #ifdef HAVE_EXTENDED_MASTER - if (ssl->options.haveEMS) { + if (ssl->options.haveEMS && msgType == server_hello) { c16toa(HELLO_EXT_EXTMS, output + offset); offset += HELLO_EXT_TYPE_SZ; c16toa(0, output + offset); @@ -4962,7 +7070,7 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output) } #endif - if (offset > OPAQUE16_LEN) + if (offset > OPAQUE16_LEN || msgType == encrypted_extensions) c16toa(offset - OPAQUE16_LEN, output); /* extensions length */ } @@ -4972,11 +7080,12 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output) #endif /* NO_WOLFSSL_SERVER */ /** Parses a buffer of TLS extensions. */ -int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest, +int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, Suites *suites) { int ret = 0; word16 offset = 0; + byte isRequest = (msgType == client_hello); #ifdef HAVE_EXTENDED_MASTER byte pendingEMS = 0; #endif @@ -5004,36 +7113,75 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest, case TLSX_SERVER_NAME: WOLFSSL_MSG("SNI extension received"); +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello && + msgType != encrypted_extensions) { + return EXT_NOT_ALLOWED; + } +#endif ret = SNI_PARSE(ssl, input + offset, size, isRequest); break; case TLSX_MAX_FRAGMENT_LENGTH: WOLFSSL_MSG("Max Fragment Length extension received"); +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello && + msgType != encrypted_extensions) { + return EXT_NOT_ALLOWED; + } +#endif ret = MFL_PARSE(ssl, input + offset, size, isRequest); break; case TLSX_TRUNCATED_HMAC: WOLFSSL_MSG("Truncated HMAC extension received"); +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + return EXT_NOT_ALLOWED; +#endif ret = THM_PARSE(ssl, input + offset, size, isRequest); break; case TLSX_SUPPORTED_GROUPS: WOLFSSL_MSG("Elliptic Curves extension received"); +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello && + msgType != encrypted_extensions) { + return EXT_NOT_ALLOWED; + } +#endif ret = EC_PARSE(ssl, input + offset, size, isRequest); break; case TLSX_STATUS_REQUEST: 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; + } +#endif ret = CSR_PARSE(ssl, input + offset, size, isRequest); break; case TLSX_STATUS_REQUEST_V2: WOLFSSL_MSG("Certificate Status Request v2 extension received"); +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello && + msgType != encrypted_extensions) { + return EXT_NOT_ALLOWED; + } +#endif ret = CSR2_PARSE(ssl, input + offset, size, isRequest); break; @@ -5041,8 +7189,14 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest, case HELLO_EXT_EXTMS: WOLFSSL_MSG("Extended Master Secret extension received"); +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello) { + return EXT_NOT_ALLOWED; + } +#endif #ifndef NO_WOLFSSL_SERVER - if (isRequest) + if (isRequest && !IsAtLeastTLSv1_3(ssl->version)) ssl->options.haveEMS = 1; #endif pendingEMS = 1; @@ -5052,29 +7206,58 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest, case TLSX_RENEGOTIATION_INFO: WOLFSSL_MSG("Secure Renegotiation extension received"); +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + return EXT_NOT_ALLOWED; +#endif ret = SCR_PARSE(ssl, input + offset, size, isRequest); break; case TLSX_SESSION_TICKET: WOLFSSL_MSG("Session Ticket extension received"); +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello) { + return EXT_NOT_ALLOWED; + } +#endif ret = WOLF_STK_PARSE(ssl, input + offset, size, isRequest); break; case TLSX_QUANTUM_SAFE_HYBRID: WOLFSSL_MSG("Quantum-Safe-Hybrid extension received"); +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + return EXT_NOT_ALLOWED; +#endif ret = QSH_PARSE(ssl, input + offset, size, isRequest); break; case TLSX_APPLICATION_LAYER_PROTOCOL: WOLFSSL_MSG("ALPN extension received"); +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello && + msgType != encrypted_extensions) { + return EXT_NOT_ALLOWED; + } +#endif ret = ALPN_PARSE(ssl, input + offset, size, isRequest); break; case HELLO_EXT_SIG_ALGO: + WOLFSSL_MSG("Extended signature algorithm extension received"); + if (isRequest) { +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello) { + return EXT_NOT_ALLOWED; + } +#endif /* do not mess with offset inside the switch! */ if (IsAtLeastTLSv1_2(ssl)) { ato16(input + offset, &suites->hashSigAlgoSz); @@ -5092,6 +7275,63 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest, } break; + +#ifdef WOLFSSL_TLS13 + case TLSX_SUPPORTED_VERSIONS: + WOLFSSL_MSG("Supported Versions extension received"); + + if (!IsAtLeastTLSv1_3(ssl->version)) + break; + + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello) { + return EXT_NOT_ALLOWED; + } + ret = SV_PARSE(ssl, input + offset, size); + break; + + case TLSX_KEY_SHARE: + WOLFSSL_MSG("Key Share extension received"); + + if (!IsAtLeastTLSv1_3(ssl->version)) + break; + + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello && msgType != server_hello && + msgType != hello_retry_request) { + return EXT_NOT_ALLOWED; + } + ret = KS_PARSE(ssl, input + offset, size, msgType); + break; + + #ifndef NO_PSK + case TLSX_PRE_SHARED_KEY: + WOLFSSL_MSG("Pre-Shared Key extension received"); + + if (!IsAtLeastTLSv1_3(ssl->version)) + break; + + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello && msgType != server_hello) { + return EXT_NOT_ALLOWED; + } + ret = PSK_PARSE(ssl, input + offset, size, msgType); + break; + + case TLSX_PSK_KEY_EXCHANGE_MODES: + WOLFSSL_MSG("PSK Key Exchange Modes extension received"); + + if (!IsAtLeastTLSv1_3(ssl->version)) + break; + + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello) { + return EXT_NOT_ALLOWED; + } + ret = PKM_PARSE(ssl, input + offset, size, msgType); + break; + #endif +#endif } /* offset should be updated here! */ @@ -5171,6 +7411,35 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest, return method; } +#ifdef WOLFSSL_TLS13 + /* The TLS v1.3 client method data. + * + * returns the method data for a TLS v1.3 client. + */ + WOLFSSL_METHOD* wolfTLSv1_3_client_method(void) + { + return wolfTLSv1_3_client_method_ex(NULL); + } + + /* The TLS v1.3 client method data. + * + * heap The heap used for allocation. + * returns the method data for a TLS v1.3 client. + */ + WOLFSSL_METHOD* wolfTLSv1_3_client_method_ex(void* heap) + { + WOLFSSL_METHOD* method = (WOLFSSL_METHOD*) + XMALLOC(sizeof(WOLFSSL_METHOD), heap, + DYNAMIC_TYPE_METHOD); + (void)heap; + if (method) { + InitSSL_Method(method, MakeTLSv1_3()); + method->downgrade = 1; + } + return method; + } +#endif /* WOLFSSL_TLS13 */ + WOLFSSL_METHOD* wolfSSLv23_client_method(void) { @@ -5186,7 +7455,11 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest, (void)heap; if (method) { #if !defined(NO_SHA256) || defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512) +#ifdef WOLFSSL_TLS13 + InitSSL_Method(method, MakeTLSv1_3()); +#else InitSSL_Method(method, MakeTLSv1_2()); +#endif #else #ifndef NO_OLD_TLS InitSSL_Method(method, MakeTLSv1_1()); @@ -5263,6 +7536,34 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest, return method; } +#ifdef WOLFSSL_TLS13 + /* The TLS v1.3 server method data. + * + * returns the method data for a TLS v1.3 server. + */ + WOLFSSL_METHOD* wolfTLSv1_3_server_method(void) + { + return wolfTLSv1_3_server_method_ex(NULL); + } + + /* The TLS v1.3 server method data. + * + * heap The heap used for allocation. + * returns the method data for a TLS v1.3 server. + */ + WOLFSSL_METHOD* wolfTLSv1_3_server_method_ex(void* heap) + { + WOLFSSL_METHOD* method = + (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), + heap, DYNAMIC_TYPE_METHOD); + (void)heap; + if (method) { + InitSSL_Method(method, MakeTLSv1_3()); + method->side = WOLFSSL_SERVER_END; + } + return method; + } +#endif /* WOLFSSL_TLS13 */ WOLFSSL_METHOD* wolfSSLv23_server_method(void) { @@ -5277,7 +7578,11 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest, (void)heap; if (method) { #if !defined(NO_SHA256) || defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512) +#ifdef WOLFSSL_TLS13 + InitSSL_Method(method, MakeTLSv1_3()); +#else InitSSL_Method(method, MakeTLSv1_2()); +#endif #else #ifndef NO_OLD_TLS InitSSL_Method(method, MakeTLSv1_1()); diff --git a/src/tls13.c b/src/tls13.c new file mode 100644 index 000000000..75f6aa9af --- /dev/null +++ b/src/tls13.c @@ -0,0 +1,6057 @@ +/* tls13.c + * + * Copyright (C) 2006-2016 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + + +#ifdef HAVE_CONFIG_H + #include +#endif + +#ifdef WOLFSSL_TLS13 +#if defined(HAVE_SESSION_TICKET) +#include +#endif + +#include + +#ifndef WOLFCRYPT_ONLY + +#ifdef HAVE_ERRNO_H + #include +#endif + +#include +#include +#include +#include +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#ifdef HAVE_NTRU + #include "libntruencrypt/ntru_crypto.h" +#endif + +#if defined(DEBUG_WOLFSSL) || defined(WOLFSSL_DEBUG) || \ + defined(CHACHA_AEAD_TEST) || defined(WOLFSSL_SESSION_EXPORT_DEBUG) + #if defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX) + #if MQX_USE_IO_OLD + #include + #else + #include + #endif + #else + #include + #endif +#endif + +#ifdef __sun + #include +#endif + +#ifndef TRUE + #define TRUE 1 +#endif +#ifndef FALSE + #define FALSE 0 +#endif + +/* Set ret to error value and jump to label. + * + * err The error value to set. + * eLabel The label to jump to. + */ +#define ERROR_OUT(err, eLabel) { ret = (err); goto eLabel; } + + +#ifndef WOLFSSL_HAVE_MIN +#define WOLFSSL_HAVE_MIN +/* Return the minimum of the two values. + * + * a First value. + * b Second value. + * returns the minimum of a and b. + */ +static INLINE word32 min(word32 a, word32 b) +{ + return a > b ? b : a; +} +#endif /* WOLFSSL_HAVE_MIN */ + +/* Convert 16-bit integer to opaque data. + * + * u16 Unsigned 16-bit value. + * c The buffer to write to. + */ +static INLINE void c16toa(word16 u16, byte* c) +{ + c[0] = (u16 >> 8) & 0xff; + c[1] = u16 & 0xff; +} + +/* Convert 32-bit integer to opaque data. + * + * u32 Unsigned 32-bit value. + * c The buffer to write to. + */ +static INLINE void c32toa(word32 u32, byte* c) +{ + c[0] = (u32 >> 24) & 0xff; + c[1] = (u32 >> 16) & 0xff; + c[2] = (u32 >> 8) & 0xff; + c[3] = u32 & 0xff; +} + + +/* Convert 24-bit opaque data into a 32-bit value. + * + * u24 The opaque data holding a 24-bit integer. + * u32 Unsigned 32-bit value. + */ +static INLINE void c24to32(const word24 u24, word32* u32) +{ + *u32 = (u24[0] << 16) | (u24[1] << 8) | u24[2]; +} + + +/* Convert opaque data into a 16-bit value. + * + * c The opaque data. + * u16 Unsigned 16-bit value. + */ +static INLINE void ato16(const byte* c, word16* u16) +{ + *u16 = (word16) ((c[0] << 8) | (c[1])); +} + +#ifndef NO_WOLFSSL_CLIENT +#ifdef HAVE_SESSION_TICKET +/* Convert opaque data into a 32-bit value. + * + * c The opaque data. + * u32 Unsigned 32-bit value. + */ +static INLINE void ato32(const byte* c, word32* u32) +{ + *u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; +} +#endif +#endif + +/* Extract data using HMAC, salt and input. + * RFC 5869 - HMAC-based Extract-and-Expand Key Derivation Function (HKDF) + * + * prk The generated pseudorandom key. + * salt The salt. + * saltLen The length of the salt. + * ikm The input keying material. + * ikmLen The length of the input keying material. + * mac The type of digest to use. + * returns 0 on success, otherwise failure. + */ +static int Tls13_HKDF_Extract(byte* prk, const byte* salt, int saltLen, + byte* ikm, int ikmLen, int mac) +{ + int ret; + int hash; + int len; + + switch (mac) { + #ifndef NO_SHA256 + case sha256_mac: + hash = SHA256; + len = SHA256_DIGEST_SIZE; + break; + #endif + + #ifdef WOLFSSL_SHA384 + case sha384_mac: + hash = SHA384; + len = SHA384_DIGEST_SIZE; + break; + #endif + + #ifdef WOLFSSL_SHA512 + case sha512_mac: + hash = SHA512; + len = SHA512_DIGEST_SIZE; + break; + #endif + + default: + return BAD_FUNC_ARG; + } + + /* When length is 0 then use zeroed data of digest length. */ + if (ikmLen == 0) { + ikmLen = len; + XMEMSET(ikm, 0, len); + } + + WOLFSSL_MSG("Salt"); + WOLFSSL_BUFFER(salt, saltLen); + WOLFSSL_MSG("IKM"); + WOLFSSL_BUFFER(ikm, ikmLen); + + ret = wc_HKDF_Extract(hash, salt, saltLen, ikm, ikmLen, prk); + + WOLFSSL_MSG("PRK"); + WOLFSSL_BUFFER(prk, len); + + return ret; +} + +/* Expand data using HMAC, salt and label and info. + * TLS v1.3 defines this function. + * + * okm The generated pseudorandom key - output key material. + * prk The salt - pseudo-random key. + * prkLen The length of the salt - pseudo-random key. + * protocol The TLS protocol label. + * protocolLen The length of the TLS protocol label. + * info The information to expand. + * infoLen The length of the information. + * digest The type of digest to use. + * returns 0 on success, otherwise failure. + */ +static int HKDF_Expand_Label(byte* okm, word32 okmLen, + const byte* prk, word32 prkLen, + const byte* protocol, word32 protocolLen, + const byte* label, word32 labelLen, + const byte* info, word32 infoLen, + int digest) +{ + int ret = 0; + int idx = 0; + byte data[MAX_HKDF_LABEL_SZ]; + + /* Output length. */ + data[idx++] = okmLen >> 8; + data[idx++] = okmLen; + /* Length of protocol | label. */ + data[idx++] = protocolLen + labelLen; + /* Protocol */ + XMEMCPY(&data[idx], protocol, protocolLen); + idx += protocolLen; + /* Label */ + XMEMCPY(&data[idx], label, labelLen); + idx += labelLen; + /* Length of hash of messages */ + data[idx++] = infoLen; + /* Hash of messages */ + XMEMCPY(&data[idx], info, infoLen); + idx += infoLen; + + WOLFSSL_MSG("PRK"); + WOLFSSL_BUFFER(prk, prkLen); + WOLFSSL_MSG("Info"); + WOLFSSL_BUFFER(data, idx); + + ret = wc_HKDF_Expand(digest, prk, prkLen, data, idx, okm, okmLen); + + WOLFSSL_MSG("OKM"); + WOLFSSL_BUFFER(okm, okmLen); + + ForceZero(data, idx); + + return ret; +} + +/* Size of the TLS v1.3 label use when deriving keys. */ +#define TLS13_PROTOCOL_LABEL_SZ 9 +/* The protocol label for TLS v1.3. */ +static const byte tls13ProtocolLabel[TLS13_PROTOCOL_LABEL_SZ + 1] = "TLS 1.3, "; + +/* Derive a key from a message. + * + * ssl The SSL/TLS object. + * output The buffer to hold the derived key. + * outputLen The length of the derived key. + * secret The secret used to derive the key (HMAC secret). + * label The label used to distinguish the context. + * labelLen The length of the label. + * msg The message data to derive key from. + * msgLen The length of the message data to derive key from. + * hashAlgo The hash algorithm to use in the HMAC. + * returns 0 on success, otherwise failure. + */ +static int DeriveKeyMsg(WOLFSSL* ssl, byte* output, int outputLen, + const byte* secret, const byte* label, word32 labelLen, + byte* msg, int msgLen, int hashAlgo) +{ + byte hash[MAX_DIGEST_SIZE]; + Digest digest; + word32 hashSz = 0; + const byte* protocol; + word32 protocolLen; + int digestAlg; + + switch (hashAlgo) { +#ifndef NO_WOLFSSL_SHA256 + case sha256_mac: + wc_InitSha256(&digest.sha256); + wc_Sha256Update(&digest.sha256, msg, msgLen); + wc_Sha256Final(&digest.sha256, hash); + wc_Sha256Free(&digest.sha256); + hashSz = SHA256_DIGEST_SIZE; + digestAlg = SHA256; + break; +#endif +#ifdef WOLFSSL_SHA384 + case sha384_mac: + wc_InitSha384(&digest.sha384); + wc_Sha384Update(&digest.sha384, msg, msgLen); + wc_Sha384Final(&digest.sha384, hash); + wc_Sha384Free(&digest.sha384); + hashSz = SHA384_DIGEST_SIZE; + digestAlg = SHA384; + break; +#endif +#ifdef WOLFSSL_SHA512 + case sha512_mac: + wc_InitSha512(&digest.sha512); + wc_Sha512Update(&digest.sha512, msg, msgLen); + wc_Sha512Final(&digest.sha512, hash); + wc_Sha512Free(&digest.sha512); + hashSz = SHA512_DIGEST_SIZE; + digestAlg = SHA512; + break; +#endif + + default: + return BAD_FUNC_ARG; + } + + switch (ssl->version.minor) { + case TLSv1_3_MINOR: + protocol = tls13ProtocolLabel; + protocolLen = TLS13_PROTOCOL_LABEL_SZ; + break; + + default: + return VERSION_ERROR; + } + if (outputLen == -1) + outputLen = hashSz; + + return HKDF_Expand_Label(output, outputLen, secret, hashSz, + protocol, protocolLen, label, labelLen, + hash, hashSz, digestAlg); +} + +/* Derive a key. + * + * ssl The SSL/TLS object. + * output The buffer to hold the derived key. + * outputLen The length of the derived key. + * secret The secret used to derive the key (HMAC secret). + * label The label used to distinguish the context. + * labelLen The length of the label. + * hashAlgo The hash algorithm to use in the HMAC. + * includeMsgs Whether to include a hash of the handshake messages so far. + * returns 0 on success, otherwise failure. + */ +static int DeriveKey(WOLFSSL* ssl, byte* output, int outputLen, + const byte* secret, const byte* label, word32 labelLen, + int hashAlgo, int includeMsgs) +{ + int ret = 0; + byte hash[MAX_DIGEST_SIZE]; + word32 hashSz = 0; + word32 hashOutSz = 0; + const byte* protocol; + word32 protocolLen; + int digestAlg; + + switch (hashAlgo) { + #ifndef NO_SHA256 + case sha256_mac: + hashSz = SHA256_DIGEST_SIZE; + digestAlg = SHA256; + if (includeMsgs) + ret = wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash); + break; + #endif + + #ifdef WOLFSSL_SHA384 + case sha384_mac: + hashSz = SHA384_DIGEST_SIZE; + digestAlg = SHA384; + if (includeMsgs) + ret = wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash); + break; + #endif + + #ifdef WOLFSSL_SHA512 + case sha512_mac: + hashSz = SHA512_DIGEST_SIZE; + digestAlg = SHA512; + if (includeMsgs) + ret = wc_Sha512GetHash(&ssl->hsHashes->hashSha512, hash); + break; + #endif + + default: + ret = BAD_FUNC_ARG; + break; + } + if (ret != 0) + return ret; + + /* Only one protocol version defined at this time. */ + protocol = tls13ProtocolLabel; + protocolLen = TLS13_PROTOCOL_LABEL_SZ; + + if (outputLen == -1) + outputLen = hashSz; + if (includeMsgs) + hashOutSz = hashSz; + + return HKDF_Expand_Label(output, outputLen, secret, hashSz, + protocol, protocolLen, label, labelLen, + hash, hashOutSz, digestAlg); +} + + +#if defined(HAVE_SESSION_TICKET) && !defined(NO_PSK) +/* The length of the binder key label. */ +#define BINDER_KEY_LABEL_SZ 23 +/* The binder key label. */ +static const byte binderKeyLabel[BINDER_KEY_LABEL_SZ + 1] = + "external psk binder key"; +/* Derive the binder key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveBinderKey(WOLFSSL* ssl, byte* key) +{ + WOLFSSL_MSG("Derive Binder Key"); + return DeriveKeyMsg(ssl, key, -1, ssl->arrays->secret, + binderKeyLabel, BINDER_KEY_LABEL_SZ, + NULL, 0, ssl->specs.mac_algorithm); +} + +/* The length of the binder key resume label. */ +#define BINDER_KEY_RESUME_LABEL_SZ 25 +/* The binder key resume label. */ +static const byte binderKeyResumeLabel[BINDER_KEY_RESUME_LABEL_SZ + 1] = + "resumption psk binder key"; +/* Derive the binder resumption key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveBinderKeyResume(WOLFSSL* ssl, byte* key) +{ + WOLFSSL_MSG("Derive Binder Key - Resumption"); + return DeriveKeyMsg(ssl, key, -1, ssl->arrays->secret, + binderKeyResumeLabel, BINDER_KEY_RESUME_LABEL_SZ, + NULL, 0, ssl->specs.mac_algorithm); +} +#endif + +#ifdef TLS13_SUPPORTS_0RTT +/* The length of the early traffic label. */ +#define EARLY_TRAFFIC_LABEL_SZ 27 +/* The early traffic label. */ +static const byte earlyTrafficLabel[EARLY_TRAFFIC_LABEL_SZ + 1] = + "client early traffic secret"; +/* Derive the early traffic key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveEarlyTrafficSecret(WOLFSSL* ssl, byte* key) +{ + WOLFSSL_MSG("Derive Early Traffic Secret"); + return DeriveKey(ssl, key, -1, ssl->arrays->secret, + earlyTrafficLabel, EARLY_TRAFFIC_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +} + + #ifdef TLS13_SUPPORTS_EXPORTERS +/* The length of the early exporter label. */ +#define EARLY_EXPORTER_LABEL_SZ 28 +/* The early exporter label. */ +static const byte earlyExporterLabel[EARLY_EXPORTER_LABEL_SZ + 1] = + "early exporter master secret"; +/* Derive the early exporter key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveEarlyExporterSecret(WOLFSSL* ssl, byte* key) +{ + WOLFSSL_MSG("Derive Early Exporter Secret"); + return DeriveKey(ssl, key, -1, ssl->arrays->secret, + earlyExporterLabel, EARLY_EXPORTER_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +} + #endif +#endif + +/* The length of the client hanshake label. */ +#define CLIENT_HANDSHAKE_LABEL_SZ 31 +/* The client hanshake label. */ +static const byte clientHandshakeLabel[CLIENT_HANDSHAKE_LABEL_SZ + 1] = + "client handshake traffic secret"; +/* Derive the client handshake key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveClientHandshakeSecret(WOLFSSL* ssl, byte* key) +{ + WOLFSSL_MSG("Derive Client Handshake Secret"); + return DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret, + clientHandshakeLabel, CLIENT_HANDSHAKE_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +} + +/* The length of the server handshake label. */ +#define SERVER_HANDSHAKE_LABEL_SZ 31 +/* The server handshake label. */ +static const byte serverHandshakeLabel[SERVER_HANDSHAKE_LABEL_SZ + 1] = + "server handshake traffic secret"; +/* Derive the server handshake key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveServerHandshakeSecret(WOLFSSL* ssl, byte* key) +{ + WOLFSSL_MSG("Derive Server Handshake Secret"); + return DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret, + serverHandshakeLabel, SERVER_HANDSHAKE_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +} + +/* The length of the client application traffic label. */ +#define CLIENT_APP_LABEL_SZ 33 +/* The client application traffic label. */ +static const byte clientAppLabel[CLIENT_APP_LABEL_SZ + 1] = + "client application traffic secret"; +/* Derive the client application traffic key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveClientTrafficSecret(WOLFSSL* ssl, byte* key) +{ + WOLFSSL_MSG("Derive Client Traffic Secret"); + return DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, + clientAppLabel, CLIENT_APP_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +} + +/* The length of the server application traffic label. */ +#define SERVER_APP_LABEL_SZ 33 +/* The server application traffic label. */ +static const byte serverAppLabel[SERVER_APP_LABEL_SZ + 1] = + "server application traffic secret"; +/* Derive the server application traffic key. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveServerTrafficSecret(WOLFSSL* ssl, byte* key) +{ + WOLFSSL_MSG("Derive Server Traffic Secret"); + return DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, + serverAppLabel, SERVER_APP_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +} + +#ifdef TLS13_SUPPORTS_EXPORTERS +/* The length of the exporter master secret label. */ +#define EXPORTER_MASTER_LABEL_SZ 22 +/* The exporter master secret label. */ +static const byte exporterMasterLabel[EXPORTER_MASTER_LABEL_SZ + 1] = + "exporter master secret"; +/* Derive the exporter secret. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveExporterSecret(WOLFSSL* ssl, byte* key) +{ + WOLFSSL_MSG("Derive Exporter Secret"); + return DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, + exporterMasterLabel, EXPORTER_MASTER_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +} +#endif + +#ifndef NO_PSK +/* The length of the resumption master secret label. */ +#define RESUME_MASTER_LABEL_SZ 24 +/* The resumption master secret label. */ +static const byte resumeMasterLabel[RESUME_MASTER_LABEL_SZ + 1] = + "resumption master secret"; +/* Derive the resumption secret. + * + * ssl The SSL/TLS object. + * key The derived key. + * returns 0 on success, otherwise failure. + */ +static int DeriveResumptionSecret(WOLFSSL* ssl, byte* key) +{ + WOLFSSL_MSG("Derive Resumption Secret"); + return DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, + resumeMasterLabel, RESUME_MASTER_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +} +#endif + +/* Length of the finished label. */ +#define FINISHED_LABEL_SZ 8 +/* Finished label for generating finished key. */ +static const byte finishedLabel[FINISHED_LABEL_SZ+1] = "finished"; +/* Derive the finished secret. + * + * ssl The SSL/TLS object. + * key The key to use with the HMAC. + * secret The derived secret. + * returns 0 on success, otherwise failure. + */ +static int DeriveFinishedSecret(WOLFSSL* ssl, byte* key, byte* secret) +{ + WOLFSSL_MSG("Derive Finished Secret"); + return DeriveKey(ssl, secret, -1, key, finishedLabel, FINISHED_LABEL_SZ, + ssl->specs.mac_algorithm, 0); +} + +/* The length of the application traffic label. */ +#define APP_TRAFFIC_LABEL_SZ 26 +/* The application traffic label. */ +static const byte appTrafficLabel[APP_TRAFFIC_LABEL_SZ + 1] = + "application traffic secret"; +/* Update the traffic secret. + * + * ssl The SSL/TLS object. + * secret The previous secret and derived secret. + * returns 0 on success, otherwise failure. + */ +static int DeriveTrafficSecret(WOLFSSL* ssl, byte* secret) +{ + WOLFSSL_MSG("Derive New Application Traffic Secret"); + return DeriveKeyMsg(ssl, secret, -1, secret, + appTrafficLabel, APP_TRAFFIC_LABEL_SZ, + NULL, 0, ssl->specs.mac_algorithm); +} + +/* Derive the early secret using HKDF Extract. + * + * ssl The SSL/TLS object. + */ +static int DeriveEarlySecret(WOLFSSL* ssl) +{ + WOLFSSL_MSG("Derive Early Secret"); +#ifndef NO_PSK + return Tls13_HKDF_Extract(ssl->arrays->secret, NULL, 0, + ssl->arrays->psk_key, ssl->arrays->psk_keySz, + ssl->specs.mac_algorithm); +#else + return Tls13_HKDF_Extract(ssl->arrays->secret, NULL, 0, + ssl->arrays->masterSecret, 0, ssl->specs.mac_algorithm); +#endif +} + +/* Derive the handshake secret using HKDF Extract. + * + * ssl The SSL/TLS object. + */ +static int DeriveHandshakeSecret(WOLFSSL* ssl) +{ + WOLFSSL_MSG("Derive Handshake Secret"); + return Tls13_HKDF_Extract(ssl->arrays->preMasterSecret, + ssl->arrays->secret, ssl->specs.hash_size, + ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz, + ssl->specs.mac_algorithm); +} + +/* Derive the master secret using HKDF Extract. + * + * ssl The SSL/TLS object. + */ +static int DeriveMasterSecret(WOLFSSL* ssl) +{ + WOLFSSL_MSG("Derive Master Secret"); + return Tls13_HKDF_Extract(ssl->arrays->masterSecret, + ssl->arrays->preMasterSecret, ssl->specs.hash_size, + ssl->arrays->masterSecret, 0, ssl->specs.mac_algorithm); +} + +/* Calculate the HMAC of message data to this point. + * + * ssl The SSL/TLS object. + * key The HMAC key. + * hash The hash result - verify data. + * returns length of verify data generated. + */ +static int BuildTls13HandshakeHmac(WOLFSSL* ssl, byte* key, byte* hash) +{ + Hmac verifyHmac; + int hashType = SHA256; + int hashSz = SHA256_DIGEST_SIZE; + + /* Get the hash of the previous handshake messages. */ + switch (ssl->specs.mac_algorithm) { + #ifndef NO_SHA256 + case sha256_mac: + hashType = SHA256; + hashSz = SHA256_DIGEST_SIZE; + wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash); + break; + #endif /* !NO_SHA256 */ + #ifdef WOLFSSL_SHA384 + case sha384_mac: + hashType = SHA384; + hashSz = SHA384_DIGEST_SIZE; + wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash); + break; + #endif /* WOLFSSL_SHA384 */ + #ifdef WOLFSSL_SHA512 + case sha512_mac: + hashType = SHA512; + hashSz = SHA512_DIGEST_SIZE; + wc_Sha512GetHash(&ssl->hsHashes->hashSha512, hash); + break; + #endif /* WOLFSSL_SHA512 */ + } + + /* Calculate the verify data. */ + wc_HmacSetKey(&verifyHmac, hashType, key, ssl->specs.hash_size); + wc_HmacUpdate(&verifyHmac, hash, hashSz); + wc_HmacFinal(&verifyHmac, hash); + + return hashSz; +} + +/* The length of the label to use when deriving keys. */ +#define WRITE_KEY_LABEL_SZ 3 +/* The length of the label to use when deriving IVs. */ +#define WRITE_IV_LABEL_SZ 2 +/* The label to use when deriving keys. */ +static const byte writeKeyLabel[WRITE_KEY_LABEL_SZ+1] = "key"; +/* The label to use when deriving IVs. */ +static const byte writeIVLabel[WRITE_IV_LABEL_SZ+1] = "iv"; + +/* Derive the keys and IVs for TLS v1.3. + * + * ssl The SSL/TLS object. + * sercret handshake_key when deriving keys and IVs for encrypting handshake + * messages. + * traffic_key when deriving first keys and IVs for encrypting + * traffic messages. + * update_traffic_key when deriving next keys and IVs for encrypting + * traffic messages. + * side ENCRYPT_SIDE_ONLY when only encryption secret needs to be derived. + * DECRYPT_SIDE_ONLY when only decryption secret needs to be derived. + * ENCRYPT_AND_DECRYPT_SIDE when both secret needs to be derived. + * returns 0 on success, otherwise failure. + */ +static int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side) +{ + int ret; + int i = 0; +#ifdef WOLFSSL_SMALL_STACK + byte* key_data; +#else + byte key_data[MAX_PRF_DIG]; +#endif + int deriveClient = 0; + int deriveServer = 0; + +#ifdef WOLFSSL_SMALL_STACK + key_data = (byte*)XMALLOC(MAX_PRF_DIG, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (key_data == NULL) + return MEMORY_E; +#endif + + if (side == ENCRYPT_AND_DECRYPT_SIDE) { + deriveClient = 1; + deriveServer = 1; + } + else { + deriveClient = (ssl->options.side != WOLFSSL_CLIENT_END) ^ + (side == ENCRYPT_SIDE_ONLY); + deriveServer = !deriveClient; + } + + /* Derive the appropriate secret to use in the HKDF. */ + switch (secret) { + case handshake_key: + if (deriveClient) { + ret = DeriveClientHandshakeSecret(ssl, + ssl->arrays->clientSecret); + if (ret != 0) + goto end; + } + if (deriveServer) { + ret = DeriveServerHandshakeSecret(ssl, + ssl->arrays->serverSecret); + if (ret != 0) + goto end; + } + break; + + case traffic_key: + if (deriveClient) { + ret = DeriveClientTrafficSecret(ssl, ssl->arrays->clientSecret); + if (ret != 0) + goto end; + } + if (deriveServer) { + ret = DeriveServerTrafficSecret(ssl, ssl->arrays->serverSecret); + if (ret != 0) + goto end; + } + break; + + case update_traffic_key: + if (deriveClient) { + ret = DeriveTrafficSecret(ssl, ssl->arrays->clientSecret); + if (ret != 0) + goto end; + } + if (deriveServer) { + ret = DeriveTrafficSecret(ssl, ssl->arrays->serverSecret); + if (ret != 0) + goto end; + } + break; + } + + /* Key data = client key | server key | client IV | server IV */ + + /* Derive the client key. */ + WOLFSSL_MSG("Derive Client Key"); + ret = DeriveKey(ssl, &key_data[i], ssl->specs.key_size, + ssl->arrays->clientSecret, writeKeyLabel, + WRITE_KEY_LABEL_SZ, ssl->specs.mac_algorithm, 0); + if (ret != 0) + goto end; + i += ssl->specs.key_size; + + /* Derive the server key. */ + WOLFSSL_MSG("Derive Server Key"); + ret = DeriveKey(ssl, &key_data[i], ssl->specs.key_size, + ssl->arrays->serverSecret, writeKeyLabel, + WRITE_KEY_LABEL_SZ, ssl->specs.mac_algorithm, 0); + if (ret != 0) + goto end; + i += ssl->specs.key_size; + + /* Derive the client IV. */ + WOLFSSL_MSG("Derive Client IV"); + ret = DeriveKey(ssl, &key_data[i], ssl->specs.iv_size, + ssl->arrays->clientSecret, writeIVLabel, WRITE_IV_LABEL_SZ, + ssl->specs.mac_algorithm, 0); + if (ret != 0) + goto end; + i += ssl->specs.iv_size; + + /* Derive the server IV. */ + WOLFSSL_MSG("Derive Server IV"); + ret = DeriveKey(ssl, &key_data[i], ssl->specs.iv_size, + ssl->arrays->serverSecret, writeIVLabel, WRITE_IV_LABEL_SZ, + ssl->specs.mac_algorithm, 0); + if (ret != 0) + goto end; + + /* Store keys and IVs but don't activate them. */ + ret = StoreKeys(ssl, key_data); + +end: +#ifdef WOLFSSL_SMALL_STACK + XFREE(serverData, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(key_data, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + +#if defined(HAVE_SESSION_TICKET) +#if defined(USER_TICKS) +#if 0 + word32 TimeNowInMilliseconds(void) + { + /* + write your own clock tick function if don't want gettimeofday() + needs millisecond accuracy but doesn't have to correlated to EPOCH + */ + } +#endif + +#elif defined(TIME_OVERRIDES) + #ifndef HAVE_TIME_T_TYPE + typedef long time_t; + #endif + extern time_t XTIME(time_t * timer); + + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32) XTIME(0) * 1000; + } +#elif defined(USE_WINDOWS_API) + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + static int init = 0; + static LARGE_INTEGER freq; + LARGE_INTEGER count; + + if (!init) { + QueryPerformanceFrequency(&freq); + init = 1; + } + + QueryPerformanceCounter(&count); + + return (word32)(count.QuadPart / (freq.QuadPart / 1000)); + } + +#elif defined(HAVE_RTP_SYS) + #include "rtptime.h" + + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32)rtp_get_system_sec() * 1000; + } +#elif defined(MICRIUM) + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + NET_SECURE_OS_TICK clk = 0; + + #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) + clk = NetSecure_OS_TimeGet(); + #endif + return (word32)clk * 1000; + } +#elif defined(MICROCHIP_TCPIP_V5) + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32) (TickGet() / (TICKS_PER_SECOND / 1000)); + } +#elif defined(MICROCHIP_TCPIP) + #if defined(MICROCHIP_MPLAB_HARMONY) + #include + + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32) (SYS_TMR_TickCountGet() / + (SYS_TMR_TickCounterFrequencyGet() / 1000)); + } + #else + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32) (SYS_TICK_Get() / (SYS_TICK_TicksPerSecondGet() / 1000)); + } + + #endif + +#elif defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX) + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + TIME_STRUCT mqxTime; + + _time_get_elapsed(&mqxTime); + + return (word32) mqxTime.SECONDS * 1000; + } +#elif defined(FREESCALE_FREE_RTOS) || defined(FREESCALE_KSDK_FREERTOS) + #include "include/task.h" + + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (unsigned int)(((float)xTaskGetTickCount()) / + (configTICK_RATE_HZ / 1000)); + } +#elif defined(FREESCALE_KSDK_BM) + #include "lwip/sys.h" /* lwIP */ + + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return sys_now(); + } +#elif defined(WOLFSSL_TIRTOS) + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32) Seconds_get() * 1000; + } +#elif defined(WOLFSSL_UTASKER) + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + return (word32)(uTaskerSystemTick / (TICK_RESOLUTION / 1000)); + } +#else + /* The time in milliseconds. + * Used for tickets to represent difference between when first seen and when + * sending. + * + * returns the time in milliseconds as a 32-bit value. + */ + word32 TimeNowInMilliseconds(void) + { + struct timeval now; + + if (gettimeofday(&now, 0) < 0) + return GETTIME_ERROR; + /* Convert to milliseconds number. */ + return (word32)(now.tv_sec * 1000 + now.tv_usec / 1000); + } +#endif +#endif /* HAVE_SESSION_TICKET */ + + +#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_SESSION_TICKET) && \ + !defined(NO_PSK)) +/* Add input to all handshake hashes. + * + * ssl The SSL/TLS object. + * input The data to hash. + * sz The size of the data to hash. + * returns 0 on success, otherwise failure. + */ +static int HashInputRaw(WOLFSSL* ssl, const byte* input, int sz) +{ + int ret = 0; + +#ifndef NO_OLD_TLS +#ifndef NO_SHA + wc_ShaUpdate(&ssl->hsHashes->hashSha, input, sz); +#endif +#ifndef NO_MD5 + wc_Md5Update(&ssl->hsHashes->hashMd5, input, sz); +#endif +#endif + +#ifndef NO_SHA256 + ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, input, sz); + if (ret != 0) + return ret; +#endif +#ifdef WOLFSSL_SHA384 + ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, input, sz); + if (ret != 0) + return ret; +#endif +#ifdef WOLFSSL_SHA512 + ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, input, sz); + if (ret != 0) + return ret; +#endif + + return ret; +} +#endif + +/* Extract the handshake header information. + * + * ssl The SSL/TLS object. + * input The buffer holding the message data. + * inOutIdx On entry, the index into the buffer of the handshake data. + * On exit, the start of the hanshake data. + * type Type of handshake message. + * size The length of the handshake message data. + * totalSz The total size of data in the buffer. + * returns BUFFER_E if there is not enough input data and 0 on success. + */ +static int GetHandshakeHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + byte *type, word32 *size, word32 totalSz) +{ + const byte *ptr = input + *inOutIdx; + (void)ssl; + + *inOutIdx += HANDSHAKE_HEADER_SZ; + if (*inOutIdx > totalSz) + return BUFFER_E; + + *type = ptr[0]; + c24to32(&ptr[1], size); + + return 0; +} + +/* Add record layer header to message. + * + * output The buffer to write the record layer header into. + * length The length of the record data. + * type The type of record message. + * ssl The SSL/TLS object. + */ +static void AddTls13RecordHeader(byte* output, word32 length, byte type, + WOLFSSL* ssl) +{ + RecordLayerHeader* rl; + + rl = (RecordLayerHeader*)output; + rl->type = type; + rl->pvMajor = ssl->version.major; + rl->pvMinor = TLSv1_MINOR; + c16toa((word16)length, rl->length); +} + +/* Add handshake header to message. + * + * output The buffer to write the hanshake header into. + * length The length of the handshake data. + * fragOffset The offset of the fragment data. (DTLS) + * fragLength The length of the fragment data. (DTLS) + * type The type of handshake message. + * ssl The SSL/TLS object. (DTLS) + */ +static void AddTls13HandShakeHeader(byte* output, word32 length, + word32 fragOffset, word32 fragLength, + byte type, WOLFSSL* ssl) +{ + HandShakeHeader* hs; + (void)fragOffset; + (void)fragLength; + (void)ssl; + + /* handshake header */ + hs = (HandShakeHeader*)output; + hs->type = type; + c32to24(length, hs->length); +} + + +/* Add both record layer and handshake header to message. + * + * output The buffer to write the headers into. + * length The length of the handshake data. + * type The type of record layer message. + * ssl The SSL/TLS object. (DTLS) + */ +static void AddTls13Headers(byte* output, word32 length, byte type, WOLFSSL* ssl) +{ + word32 lengthAdj = HANDSHAKE_HEADER_SZ; + word32 outputAdj = RECORD_HEADER_SZ; + + AddTls13RecordHeader(output, length + lengthAdj, handshake, ssl); + AddTls13HandShakeHeader(output + outputAdj, length, 0, length, type, ssl); +} + + +#ifndef NO_CERTS +/* Add both record layer and fragement handshake header to message. + * + * output The buffer to write the headers into. + * fragOffset The offset of the fragment data. (DTLS) + * fragLength The length of the fragment data. (DTLS) + * length The length of the handshake data. + * type The type of record layer message. + * ssl The SSL/TLS object. (DTLS) + */ +static void AddTls13FragHeaders(byte* output, word32 fragSz, word32 fragOffset, + word32 length, byte type, WOLFSSL* ssl) +{ + word32 lengthAdj = HANDSHAKE_HEADER_SZ; + word32 outputAdj = RECORD_HEADER_SZ; + (void)fragSz; + + AddTls13RecordHeader(output, fragSz + lengthAdj, handshake, ssl); + AddTls13HandShakeHeader(output + outputAdj, length, fragOffset, fragSz, + type, ssl); +} +#endif /* NO_CERTS */ + +/* Write the sequence number into the buffer. + * No DTLS v1.3 support. + * + * ssl The SSL/TLS object. + * verifyOrder Which set of sequence numbers to use. + * out The buffer to write into. + */ +static INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out) +{ + word32 seq[2] = {0, 0}; + + if (verifyOrder) { + seq[0] = ssl->keys.peer_sequence_number_hi; + seq[1] = ssl->keys.peer_sequence_number_lo++; + /* handle rollover */ + if (seq[1] > ssl->keys.peer_sequence_number_lo) + ssl->keys.peer_sequence_number_hi++; + } + else { + seq[0] = ssl->keys.sequence_number_hi; + seq[1] = ssl->keys.sequence_number_lo++; + /* handle rollover */ + if (seq[1] > ssl->keys.sequence_number_lo) + ssl->keys.sequence_number_hi++; + } + + c32toa(seq[0], out); + c32toa(seq[1], out + OPAQUE32_LEN); +} + +/* Build the nonce for TLS v1.3 encryption and decryption. + * + * ssl The SSL/TLS object. + * nonce The nonce data to use when encrypting or decrypting. + * iv The derived IV. + * order The side on which the message is to be or was sent. + */ +static INLINE void BuildTls13Nonce(WOLFSSL* ssl, byte *nonce, const byte* iv, + int order) +{ + int i; + + /* The nonce is the IV with the sequence XORed into the last bytes. */ + WriteSEQ(ssl, order, nonce + AEAD_NONCE_SZ - SEQ_SZ); + for (i = 0; i < AEAD_NONCE_SZ - SEQ_SZ; i++) + nonce[i] = iv[i]; + for (; i < AEAD_NONCE_SZ; i++) + nonce[i] ^= iv[i]; +} + +/* Encrypt with ChaCha20 and create authenication tag with Poly1305. + * + * ssl The SSL/TLS object. + * output The buffer to write encrypted data and authentication tag into. + * May be the same pointer as input. + * input The data to encrypt. + * sz The number of bytes to encrypt. + * nonce The nonce to use with ChaCha20. + * tag The authentication tag buffer. + * returns 0 on success, otherwise failure. + */ +static int ChaCha20Poly1305_Encrypt(WOLFSSL* ssl, byte* output, + const byte* input, word16 sz, byte* nonce, + byte* tag) +{ + int ret = 0; + byte poly[CHACHA20_256_KEY_SIZE]; + + /* Poly1305 key is 256 bits of zero encrypted with ChaCha20. */ + XMEMSET(poly, 0, sizeof(poly)); + + /* Set the nonce for ChaCha and get Poly1305 key. */ + ret = wc_Chacha_SetIV(ssl->encrypt.chacha, nonce, 0); + if (ret != 0) + return ret; + /* Create Poly1305 key using ChaCha20 keystream. */ + ret = wc_Chacha_Process(ssl->encrypt.chacha, poly, poly, sizeof(poly)); + if (ret != 0) + return ret; + /* Encrypt the plain text. */ + ret = wc_Chacha_Process(ssl->encrypt.chacha, output, input, sz); + if (ret != 0) { + ForceZero(poly, sizeof(poly)); + return ret; + } + + /* Set key for Poly1305. */ + ret = wc_Poly1305SetKey(ssl->auth.poly1305, poly, sizeof(poly)); + ForceZero(poly, sizeof(poly)); /* done with poly1305 key, clear it */ + if (ret != 0) + return ret; + /* Add authentication code of encrypted data to end. */ + ret = wc_Poly1305_MAC(ssl->auth.poly1305, NULL, 0, output, sz, tag, + POLY1305_AUTH_SZ); + + return ret; +} + +/* Encrypt data for TLS v1.3. + * + * ssl The SSL/TLS object. + * output The buffer to write encrypted data and authentication tag into. + * May be the same pointer as input. + * input The data to encrypt. + * sz The number of bytes to encrypt. + * returns 0 on success, otherwise failure. + */ +static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input, + word16 sz) +{ + int ret = 0; + word16 dataSz = sz - ssl->specs.aead_mac_size; + word16 macSz = ssl->specs.aead_mac_size; + byte nonce[AEAD_NONCE_SZ]; + + (void)output; + (void)input; + (void)sz; + (void)dataSz; + (void)macSz; + + + WOLFSSL_MSG("Data to encrypt"); + WOLFSSL_BUFFER(input, dataSz); + + BuildTls13Nonce(ssl, nonce, ssl->keys.aead_enc_imp_IV, CUR_ORDER); + + switch (ssl->specs.bulk_cipher_algorithm) { + #ifdef BUILD_AESGCM + case wolfssl_aes_gcm: + ret = wc_AesGcmEncrypt(ssl->encrypt.aes, output, input, dataSz, + nonce, AESGCM_NONCE_SZ, output + dataSz, macSz, NULL, 0); + break; + #endif + + #ifdef HAVE_AESCCM + case wolfssl_aes_ccm: + ret = wc_AesCcmEncrypt(ssl->encrypt.aes, output, input, dataSz, + nonce, AESCCM_NONCE_SZ, output + dataSz, macSz, NULL, 0); + break; + #endif + + #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) + case wolfssl_chacha: + ret = ChaCha20Poly1305_Encrypt(ssl, output, input, dataSz, nonce, + output + dataSz); + break; + #endif + + default: + WOLFSSL_MSG("wolfSSL Encrypt programming error"); + return ENCRYPT_ERROR; + } + + ForceZero(nonce, AEAD_NONCE_SZ); + + WOLFSSL_MSG("Encrypted data"); + WOLFSSL_BUFFER(output, dataSz); + WOLFSSL_MSG("Authentication Tag"); + WOLFSSL_BUFFER(output + dataSz, macSz); + + return ret; +} + +/* Decrypt with ChaCha20 and check authenication tag with Poly1305. + * + * ssl The SSL/TLS object. + * output The buffer to write decrypted data into. + * May be the same pointer as input. + * input The data to decrypt. + * sz The number of bytes to decrypt. + * nonce The nonce to use with ChaCha20. + * tagIn The authentication tag data from packet. + * returns 0 on success, otherwise failure. + */ +static int ChaCha20Poly1305_Decrypt(WOLFSSL *ssl, byte* output, + const byte* input, word16 sz, byte* nonce, + const byte* tagIn) +{ + int ret; + byte tag[POLY1305_AUTH_SZ]; + byte poly[CHACHA20_256_KEY_SIZE]; /* generated key for mac */ + + /* Poly1305 key is 256 bits of zero encrypted with ChaCha20. */ + XMEMSET(poly, 0, sizeof(poly)); + + /* Set nonce and get Poly1305 key. */ + ret = wc_Chacha_SetIV(ssl->decrypt.chacha, nonce, 0); + if (ret != 0) + return ret; + /* Use ChaCha20 keystream to get Poly1305 key for tag. */ + ret = wc_Chacha_Process(ssl->decrypt.chacha, poly, poly, sizeof(poly)); + if (ret != 0) + return ret; + + /* Set key for Poly1305. */ + ret = wc_Poly1305SetKey(ssl->auth.poly1305, poly, sizeof(poly)); + ForceZero(poly, sizeof(poly)); /* done with poly1305 key, clear it */ + if (ret != 0) + return ret; + /* Generate authentication tag for encrypted data. */ + if ((ret = wc_Poly1305_MAC(ssl->auth.poly1305, NULL, 0, (byte*)input, sz, + tag, sizeof(tag))) != 0) { + return ret; + } + + /* Check tag sent along with packet. */ + if (ConstantCompare(tagIn, tag, POLY1305_AUTH_SZ) != 0) { + WOLFSSL_MSG("MAC did not match"); + return VERIFY_MAC_ERROR; + } + + /* If the tag was good decrypt message. */ + ret = wc_Chacha_Process(ssl->decrypt.chacha, output, input, sz); + + return ret; +} + +/* Decrypt data for TLS v1.3. + * + * ssl The SSL/TLS object. + * output The buffer to write decrypted data into. + * May be the same pointer as input. + * input The data to encrypt and authentication tag. + * sz The length of the encrypted data plus authentication tag. + * returns 0 on success, otherwise failure. + */ +int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input, word16 sz) +{ + int ret = 0; + word16 dataSz = sz - ssl->specs.aead_mac_size; + word16 macSz = ssl->specs.aead_mac_size; + byte nonce[AEAD_NONCE_SZ]; + + (void)output; + (void)input; + (void)sz; + (void)dataSz; + (void)macSz; + + WOLFSSL_MSG("Data to decrypt"); + WOLFSSL_BUFFER(input, dataSz); + WOLFSSL_MSG("Authentication tag"); + WOLFSSL_BUFFER(input + dataSz, macSz); + + BuildTls13Nonce(ssl, nonce, ssl->keys.aead_dec_imp_IV, PEER_ORDER); + + switch (ssl->specs.bulk_cipher_algorithm) { + #ifdef BUILD_AESGCM + case wolfssl_aes_gcm: + ret = wc_AesGcmDecrypt(ssl->decrypt.aes, output, input, dataSz, + nonce, AESGCM_NONCE_SZ, input + dataSz, macSz, NULL, 0); + break; + #endif + + #ifdef HAVE_AESCCM + case wolfssl_aes_ccm: + ret = wc_AesCcmDecrypt(ssl->decrypt.aes, output, input, dataSz, + nonce, AESCCM_NONCE_SZ, input + dataSz, macSz, NULL, 0); + break; + #endif + + #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) + case wolfssl_chacha: + ret = ChaCha20Poly1305_Decrypt(ssl, output, input, dataSz, nonce, + input + dataSz); + break; + #endif + + default: + WOLFSSL_MSG("wolfSSL Decrypt programming error"); + return DECRYPT_ERROR; + } + + ForceZero(nonce, AEAD_NONCE_SZ); + if (ret < 0 && !ssl->options.dtls) { + SendAlert(ssl, alert_fatal, bad_record_mac); + ret = VERIFY_MAC_ERROR; + } + + WOLFSSL_MSG("Decrypted data"); + WOLFSSL_BUFFER(output, dataSz); + + return ret; +} + +/* Build SSL Message, encrypted. + * TLS v1.3 encryption is AEAD only. + * + * ssl The SSL/TLS object. + * output The buffer to write record message to. + * outSz Size of the buffer being written into. + * input The record data to encrypt (excluding record header). + * inSz The size of the record data. + * type The recorder header content type. + * hashOutput Whether to hash the unencrypted record data. + * sizeOnly Only want the size of the record message. + * returns the size of the encrypted record message or negative value on error. + */ +int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input, + int inSz, int type, int hashOutput, int sizeOnly) +{ + word32 sz = RECORD_HEADER_SZ + inSz; + word32 idx = RECORD_HEADER_SZ; + word32 headerSz = RECORD_HEADER_SZ; + word16 size; + int ret = 0; + int atomicUser = 0; + + if (ssl == NULL) + return BAD_FUNC_ARG; + if (!sizeOnly && (output == NULL || input == NULL)) + return BAD_FUNC_ARG; + /* catch mistaken sizeOnly parameter */ + if (sizeOnly && (output || input)) { + WOLFSSL_MSG("BuildMessage with sizeOnly doesn't need input or output"); + return BAD_FUNC_ARG; + } + + /* Record layer content type at the end of record data. */ + sz++; + /* Authentication data at the end. */ + sz += ssl->specs.aead_mac_size; + + if (sizeOnly) + return sz; + + if (sz > (word32)outSz) { + WOLFSSL_MSG("Oops, want to write past output buffer size"); + return BUFFER_E; + } + + /* Record data length. */ + size = (word16)(sz - headerSz); + /* Write/update the record header with the new size. + * Always have the content type as application data for encrypted + * messages in TLS v1.3. + */ + AddTls13RecordHeader(output, size, application_data, ssl); + + /* TLS v1.3 can do in place encryption. */ + if (input != output + idx) + XMEMCPY(output + idx, input, inSz); + idx += inSz; + + if (hashOutput) { + ret = HashOutput(ssl, output, headerSz + inSz, 0); + if (ret != 0) + return ret; + } + + /* The real record content type goes at the end of the data. */ + output[idx++] = type; + +#ifdef ATOMIC_USER + if (ssl->ctx->MacEncryptCb) + atomicUser = 1; +#endif + + if (atomicUser) { /* User Record Layer Callback handling */ +#ifdef ATOMIC_USER + byte* mac = output + idx; + output += headerSz; + + if ((ret = ssl->ctx->MacEncryptCb(ssl, mac, output, inSz, type, 0, + output, output, size, ssl->MacEncryptCtx)) != 0) { + return ret; + } +#endif + } + else { + output += headerSz; + if ((ret = EncryptTls13(ssl, output, output, size)) != 0) + return ret; + } + + return sz; +} + +#ifndef NO_WOLFSSL_CLIENT +#if defined(HAVE_SESSION_TICKET) && !defined(NO_PSK) +/* Get the size of the message hash. + * + * ssl The SSL/TLS object. + * returns the length of the hash. + */ +static int GetMsgHashSize(WOLFSSL *ssl) +{ + switch (ssl->specs.mac_algorithm) { + #ifndef NO_SHA256 + case sha256_mac: + return SHA256_DIGEST_SIZE; + #endif /* !NO_SHA256 */ + #ifdef WOLFSSL_SHA384 + case sha384_mac: + return SHA384_DIGEST_SIZE; + #endif /* WOLFSSL_SHA384 */ + #ifdef WOLFSSL_SHA512 + case sha512_mac: + return SHA512_DIGEST_SIZE; + #endif /* WOLFSSL_SHA512 */ + } + return 0; +} + +/* Derive and write the binders into the ClientHello in space left when + * writing the Pre-Shared Key extension. + * + * ssl The SSL/TLS object. + * output The buffer containing the ClientHello. + * idx The index at the end of the completed ClientHello. + * returns 0 on success and otherwise failure. + */ +static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) +{ + int ret; + TLSX* ext; + PreSharedKey* current; + byte binderKey[MAX_DIGEST_SIZE]; + word16 len; + + ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (ext == NULL) + return SANITY_MSG_E; + + /* Get the size of the binders to determine where to write binders. */ + idx -= TLSX_PreSharedKey_GetSizeBinders(ext->data, client_hello); + + /* Hash truncated ClientHello - up to binders. */ + ret = HashOutput(ssl, output, idx, 0); + if (ret != 0) + return ret; + + current = ext->data; + /* Calculate the binder for each identity based on previous handshake data. + */ + while (current != NULL) { + if (current->resumption) { + /* Set the HMAC to use based on the one for the session (set into + * the extension data at the start of this function based on the + * cipher suite in the session information. + */ + ssl->specs.mac_algorithm = current->hmac; + + /* Resumption PSK is master secret. */ + ssl->arrays->psk_keySz = GetMsgHashSize(ssl); + XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret, + ssl->arrays->psk_keySz); + /* Derive the early secret using the PSK. */ + DeriveEarlySecret(ssl); + /* Derive the binder key to use to with HMAC. */ + DeriveBinderKeyResume(ssl, binderKey); + } + else { + /* TODO: [TLS13] Support non-ticket PSK. */ + /* Get the pre-shared key. */ + ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, + (char *)current->identity, ssl->arrays->client_identity, + MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); + /* Derive the early secret using the PSK. */ + DeriveEarlySecret(ssl); + /* Derive the binder key to use to with HMAC. */ + DeriveBinderKey(ssl, binderKey); + } + + /* Derive the Finished message secret. */ + DeriveFinishedSecret(ssl, binderKey, ssl->keys.client_write_MAC_secret); + /* Build the HMAC of the handshake message data = binder. */ + current->binderLen = BuildTls13HandshakeHmac(ssl, + ssl->keys.client_write_MAC_secret, current->binder); + + current = current->next; + } + + /* Data entered into extension, now write to message. */ + len = TLSX_PreSharedKey_WriteBinders(ext->data, output + idx, client_hello); + + /* Hash binders to complete the hash of the ClientHello. */ + return HashOutputRaw(ssl, output + idx, len); +} +#endif + +/* Send a ClientHello message to the server. + * Include the information required to start a handshake with servers using + * protocol versions less than TLS v1.3. + * Only a client will send this message. + * + * ssl The SSL/TLS object. + * returns 0 on success and otherwise failure. + */ +int SendTls13ClientHello(WOLFSSL* ssl) +{ + byte* output; + word32 length; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + int ret; + +#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && !defined(NO_PSK) + if (ssl->options.resuming && + (ssl->session.version.major != ssl->version.major || + ssl->session.version.minor != ssl->version.minor)) { + ssl->version.major = ssl->session.version.major; + ssl->version.minor = ssl->session.version.minor; + return SendClientHello(ssl); + } +#endif + + if (ssl->suites == NULL) { + WOLFSSL_MSG("Bad suites pointer in SendTls13ClientHello"); + return SUITES_ERROR; + } + + /* Version | Random | Session Id | Cipher Suites | Compression | Ext */ + length = VERSION_SZ + RAN_LEN + ENUM_LEN + ssl->suites->suiteSz + + SUITE_LEN + COMP_LEN + ENUM_LEN; + + /* Auto populate extensions supported unless user defined. */ + if ((ret = TLSX_PopulateExtensions(ssl, 0)) != 0) + return ret; +#ifdef HAVE_QSH + if (QSH_Init(ssl) != 0) + return MEMORY_E; +#endif + /* Include length of TLS extensions. */ + length += TLSX_GetRequestSize(ssl); + + /* Total message size. */ + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* Get position in output buffer to write new message to. */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Put the record and handshake headers on. */ + AddTls13Headers(output, length, client_hello, ssl); + + /* Protocol version. */ + output[idx++] = ssl->version.major; + output[idx++] = ssl->version.minor; + ssl->chVersion = ssl->version; + + /* Client Random */ + if (ssl->options.connectState == CONNECT_BEGIN) { + ret = wc_RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN); + if (ret != 0) + return ret; + + /* Store random for possible second ClientHello. */ + XMEMCPY(ssl->arrays->clientRandom, output + idx, RAN_LEN); + } + else + XMEMCPY(output + idx, ssl->arrays->clientRandom, RAN_LEN); + idx += RAN_LEN; + + /* TLS v1.3 does not use session id - 0 length. */ + output[idx++] = 0; + + /* Cipher suites */ + c16toa(ssl->suites->suiteSz, output + idx); + idx += OPAQUE16_LEN; + XMEMCPY(output + idx, &ssl->suites->suites, ssl->suites->suiteSz); + idx += ssl->suites->suiteSz; + + /* Compression not supported in TLS v1.3. */ + output[idx++] = COMP_LEN; + output[idx++] = NO_COMPRESSION; + + /* Write out extensions for a request. */ + idx += TLSX_WriteRequest(ssl, output + idx); + +#if defined(HAVE_SESSION_TICKET) && !defined(NO_PSK) + /* Resumption has a specific set of extensions and binder is calculated + * for each identity. + */ + if (ssl->options.resuming) + ret = WritePSKBinders(ssl, output, idx); + else +#endif + ret = HashOutput(ssl, output, idx, 0); + if (ret != 0) + return ret; + + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("ClientHello", &ssl->timeoutInfo, output, sendSz, + ssl->heap); +#endif + + ssl->buffers.outputBuffer.length += sendSz; + + return SendBuffered(ssl); +} + +/* Parse and handle a HelloRetryRequest message. + * Only a client will receive this message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of + * HelloRetryRequest. + * On exit, the index of byte after the HelloRetryRequest message. + * totalSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13HelloRetryRequest(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, word32 totalSz) +{ + int ret; + word32 begin = *inOutIdx; + word32 i = begin; + word16 totalExtSz; + ProtocolVersion pv; + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("HelloRetryRequest", &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("HelloRetryRequest", &ssl->timeoutInfo); +#endif + + /* Version info and length field of extension data. */ + if (totalSz < i - begin + OPAQUE16_LEN + OPAQUE16_LEN) + return BUFFER_ERROR; + + /* Protocol version. */ + XMEMCPY(&pv, input + i, OPAQUE16_LEN); + i += OPAQUE16_LEN; + ret = CheckVersion(ssl, pv); + if (ret != 0) + return ret; + + /* Length of extension data. */ + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + if (totalExtSz == 0) { + WOLFSSL_MSG("HelloRetryRequest must contain extensions"); + return MISSING_HANDSHAKE_DATA; + } + + /* Extension data. */ + if (i - begin + totalExtSz > totalSz) + return BUFFER_ERROR; + if ((ret = TLSX_Parse(ssl, (byte *)(input + i), totalExtSz, + hello_retry_request, NULL))) + return ret; + /* The KeyShare extension parsing fails when not valid. */ + + /* Move index to byte after message. */ + *inOutIdx = i + totalExtSz; + + ssl->options.tls1_3 = 1; + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST; + + return 0; +} + +/* Handle the ServerHello message from the server. + * Only a client will receive this message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of ServerHello. + * On exit, the index of byte after the ServerHello message. + * helloSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 helloSz) +{ + ProtocolVersion pv; + word32 i = *inOutIdx; + word32 begin = i; + int ret; + word16 totalExtSz; + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo); +#endif + + /* Protocol version length check. */ + if (OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + + /* Protocol version */ + XMEMCPY(&pv, input + i, OPAQUE16_LEN); + i += OPAQUE16_LEN; + ret = CheckVersion(ssl, pv); + if (ret != 0) + return ret; + if (!IsAtLeastTLSv1_3(pv) && pv.major != TLS_DRAFT_MAJOR) { + ssl->version = pv; + return DoServerHello(ssl, input, inOutIdx, helloSz); + } + + /* Random, cipher suite and extensions length check. */ + if ((i - begin) + RAN_LEN + OPAQUE16_LEN + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + + /* Server random - keep for debugging. */ + XMEMCPY(ssl->arrays->serverRandom, input + i, RAN_LEN); + i += RAN_LEN; + /* TODO: [TLS13] Check last 8 bytes. */ + + /* Set the cipher suite from the message. */ + ssl->options.cipherSuite0 = input[i++]; + ssl->options.cipherSuite = input[i++]; + + /* Get extension length and length check. */ + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + if ((i - begin) + totalExtSz > helloSz) + return BUFFER_ERROR; + + /* Parse and handle extensions. */ + ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz, server_hello, NULL); + if (ret != 0) + return ret; + + i += totalExtSz; + *inOutIdx = i; + + ssl->options.serverState = SERVER_HELLO_COMPLETE; + +#ifdef HAVE_SECRET_CALLBACK + if (ssl->sessionSecretCb != NULL) { + int secretSz = SECRET_LEN, ret; + ret = ssl->sessionSecretCb(ssl, ssl->session.masterSecret, + &secretSz, ssl->sessionSecretCtx); + if (ret != 0 || secretSz != SECRET_LEN) + return SESSION_SECRET_CB_E; + } +#endif /* HAVE_SECRET_CALLBACK */ + + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; + +#ifndef NO_PSK + if (ssl->options.resuming) { + PreSharedKey *psk = NULL; + TLSX* ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (ext != NULL) + psk = (PreSharedKey*)ext->data; + while (psk != NULL && !psk->chosen) + psk = psk->next; + if (psk == NULL) { + ssl->options.resuming = 0; + ssl->arrays->psk_keySz = ssl->specs.hash_size; + XMEMSET(ssl->arrays->psk_key, 0, ssl->arrays->psk_keySz); + } + } +#endif + + ssl->keys.encryptionOn = 1; + + return ret; +} + +/* Parse and handle an EncryptedExtensions message. + * Only a client will receive this message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of + * EncryptedExtensions. + * On exit, the index of byte after the EncryptedExtensions + * message. + * totalSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13EncryptedExtensions(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, word32 totalSz) +{ + int ret; + word32 begin = *inOutIdx; + word32 i = begin; + word16 totalExtSz; + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("EncryptedExtensions", + &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("EncryptedExtensions", &ssl->timeoutInfo); +#endif + + /* Length field of extension data. */ + if (totalSz < i - begin + OPAQUE16_LEN) + return BUFFER_ERROR; + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + + /* Extension data. */ + if (i - begin + totalExtSz > totalSz) + return BUFFER_ERROR; + if ((ret = TLSX_Parse(ssl, (byte *)(input + i), totalExtSz, + encrypted_extensions, NULL))) + return ret; + + /* Move index to byte after message. */ + *inOutIdx = i + totalExtSz; + + /* Always encrypted. */ + *inOutIdx += ssl->keys.padSz; + + return 0; +} + +/* Handle a TLS v1.3 CertificateRequest message. + * This message is always encrypted. + * Only a client will receive this message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of CertificateRequest. + * On exit, the index of byte after the CertificateRequest message. + * size The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, word32 size) +{ + word16 len; + word32 begin = *inOutIdx; + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("CertificateRequest", + &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("CertificateRequest", &ssl->timeoutInfo); + #endif + + if ((*inOutIdx - begin) + OPAQUE8_LEN > size) + return BUFFER_ERROR; + + /* Length of the request context. */ + len = input[(*inOutIdx)++]; + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + if (ssl->options.connectState < FINISHED_DONE && len > 0) + return BUFFER_ERROR; + + /* Request context parsed here. */ + /* TODO: [TLS13] Request context for post-handshake auth. + * Store the value and return it in Certificate message. + * Must be unique in the scope of the connection. + */ + *inOutIdx += len; + + /* Signature and hash algorithms. */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + ato16(input + *inOutIdx, &len); + *inOutIdx += OPAQUE16_LEN; + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + PickHashSigAlgo(ssl, input + *inOutIdx, len); + *inOutIdx += len; + + /* Length of certificate authority data. */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + ato16(input + *inOutIdx, &len); + *inOutIdx += OPAQUE16_LEN; + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + + /* Certificate authorities. */ + while (len) { + word16 dnSz; + + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &dnSz); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + dnSz > size) + return BUFFER_ERROR; + + *inOutIdx += dnSz; + len -= OPAQUE16_LEN + dnSz; + } + + /* TODO: [TLS13] Add extension handling. */ + /* Certificate extensions */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + ato16(input + *inOutIdx, &len); + *inOutIdx += OPAQUE16_LEN; + if ((*inOutIdx - begin) + len > size) + return BUFFER_ERROR; + /* Skip over extensions for now. */ + *inOutIdx += len; + + ssl->options.sendVerify = SEND_CERT; + + /* This message is always encrypted so add encryption padding. */ + *inOutIdx += ssl->keys.padSz; + + return 0; +} + +#endif /* !NO_WOLFSSL_CLIENT */ + +#ifndef NO_WOLFSSL_SERVER +#if defined(HAVE_SESSION_TICKET) && !defined(NO_PSK) +/* 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. + * + * ssl The SSL/TLS object. + * input The ClientHello message. + * helloSz The size of the ClientHello message (including binders if present). + * usingPSK Indicates handshake is using Pre-Shared Keys. + * returns 0 on success and otherwise failure. + */ +static int DoPreSharedKeys(WOLFSSL *ssl, const byte* input, word32 helloSz, + int* usingPSK) +{ + int ret; + TLSX* ext; + word16 bindersLen; + PreSharedKey* current; + byte binderKey[MAX_DIGEST_SIZE]; + byte binder[MAX_DIGEST_SIZE]; + word16 binderLen; + word16 modes; + + ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (ext == NULL) + return 0; + + /* Extensions pushed on stack/list and PSK must be last. */ + if (ssl->extensions != ext) + return PSK_KEY_ERROR; + + /* Assume we are going to resume with a pre-shared key. */ + ssl->options.resuming = 1; + + /* Find the pre-shared key extension and calculate hash of truncated + * ClientHello for binders. + */ + bindersLen = TLSX_PreSharedKey_GetSizeBinders(ext->data, client_hello); + + /* Hash data up to binders for deriving binders in PSK extension. */ + ret = HashInput(ssl, input, helloSz - bindersLen); + if (ret != 0) + return ret; + + /* Look through all client's pre-shared keys for a match. */ + current = (PreSharedKey*)ext->data; + while (current != NULL) { + /* TODO: [TLS13] Support non-ticket PSK. */ + /* Decode the identity. */ + ret = DoClientTicket(ssl, current->identity, current->identityLen); + if (ret != WOLFSSL_TICKET_RET_OK) + continue; + + if (current->resumption) { + /* Check the ticket isn't too old or new. */ + int diff = TimeNowInMilliseconds() - ssl->session.ticketSeen; + diff -= current->ticketAge - ssl->session.ticketAdd; + /* TODO: [TLS13] What should the value be? Configurable? */ + if (diff < -1000 || diff > 1000) { + /* Invalid difference, fallback to full handshake. */ + ssl->options.resuming = 0; + break; + } + + /* Use the same cipher suite as before and set up for use. */ + ssl->options.cipherSuite0 = ssl->session.cipherSuite0; + ssl->options.cipherSuite = ssl->session.cipherSuite; + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; + + /* Resumption PSK is resumption master secret. */ + ssl->arrays->psk_keySz = ssl->specs.hash_size; + XMEMCPY(ssl->arrays->psk_key, ssl->session.masterSecret, + ssl->specs.hash_size); + /* Derive the early secret using the PSK. */ + DeriveEarlySecret(ssl); + /* Derive the binder key to use to with HMAC. */ + DeriveBinderKeyResume(ssl, binderKey); + } + else { + /* PSK age is always zero. */ + if (current->ticketAge != ssl->session.ticketAdd) + return PSK_KEY_ERROR; + + /* Get the pre-shared key. */ + ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, + (char*)current->identity, ssl->arrays->client_identity, + MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); + /* Derive the early secret using the PSK. */ + DeriveEarlySecret(ssl); + /* Derive the binder key to use to with HMAC. */ + DeriveBinderKey(ssl, binderKey); + } + + /* Derive the Finished message secret. */ + DeriveFinishedSecret(ssl, binderKey, ssl->keys.client_write_MAC_secret); + /* Derive the binder and compare with the one in the extension. */ + binderLen = BuildTls13HandshakeHmac(ssl, + ssl->keys.client_write_MAC_secret, binder); + if (binderLen != current->binderLen || + XMEMCMP(binder, current->binder, binderLen) != 0) { + return BAD_BINDER; + } + + /* This PSK works, no need to try any more. */ + current->chosen = 1; + ext->resp = 1; + break; + } + + /* Hash the rest of the ClientHello. */ + ret = HashInputRaw(ssl, input + helloSz - bindersLen, bindersLen); + if (ret != 0) + return ret; + + /* Get the PSK key exchange modes the client wants to negotiate. */ + ext = TLSX_Find(ssl->extensions, TLSX_PSK_KEY_EXCHANGE_MODES); + if (ext == NULL) + return MISSING_HANDSHAKE_DATA; + modes = ext->val; + + ext = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + /* Use (EC)DHE for forward-security if possible. */ + if (ext != NULL && (modes & (1 << PSK_DHE_KE)) != 0 && + !ssl->options.noPskDheKe) { + /* Only use named group used in last session. */ + ssl->namedGroup = ssl->session.namedGroup; + + /* Try to establish a new secret. */ + ret = TLSX_KeyShare_Establish(ssl); + if (ret == KEY_SHARE_ERROR) + return PSK_KEY_ERROR; + else if (ret > 0) + ret = 0; + + /* Send new public key to client. */ + ext->resp = 1; + } + else if ((modes & (1 << PSK_KE)) != 0) { + /* Don't send a key share extension back. */ + if (ext != NULL) + ext->resp = 0; + } + else + return PSK_KEY_ERROR; + + *usingPSK = 1; + + return ret; +} +#endif + +/* Handle a ClientHello handshake message. + * If the protocol version in the message is not TLS v1.3 or higher, use + * DoClientHello() + * Only a server will receive this message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of ClientHello. + * On exit, the index of byte after the ClientHello message and + * padding. + * helloSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 helloSz) +{ + int ret; + byte b; + ProtocolVersion pv; + Suites clSuites; + word32 i = *inOutIdx; + word32 begin = i; + word16 totalExtSz; + int usingPSK = 0; + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("ClientHello", &ssl->timeoutInfo); +#endif + + /* protocol version, random and session id length check */ + if ((i - begin) + OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + + /* Protocol version */ + XMEMCPY(&pv, input + i, OPAQUE16_LEN); + ssl->chVersion = pv; /* store */ + i += OPAQUE16_LEN; + + if ((ssl->version.major == SSLv3_MAJOR && + ssl->version.minor < TLSv1_3_MINOR) || ssl->options.dtls) { + return DoClientHello(ssl, input, inOutIdx, helloSz); + } + + /* Client random */ + XMEMCPY(ssl->arrays->clientRandom, input + i, RAN_LEN); + i += RAN_LEN; + + WOLFSSL_MSG("client random"); + WOLFSSL_BUFFER(ssl->arrays->clientRandom, RAN_LEN); + + + /* Session id - empty in TLS v1.3 */ + b = input[i++]; + if (b != 0) { + WOLFSSL_MSG("Client sent session id - not supported"); + return BUFFER_ERROR; + } + + /* Cipher suites */ + if ((i - begin) + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + ato16(&input[i], &clSuites.suiteSz); + i += OPAQUE16_LEN; + /* suites and compression length check */ + if ((i - begin) + clSuites.suiteSz + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + if (clSuites.suiteSz > WOLFSSL_MAX_SUITE_SZ) + return BUFFER_ERROR; + XMEMCPY(clSuites.suites, input + i, clSuites.suiteSz); + i += clSuites.suiteSz; + clSuites.hashSigAlgoSz = 0; + + /* Compression */ + b = input[i++]; + if ((i - begin) + b > helloSz) + return BUFFER_ERROR; + if (b != COMP_LEN) { + WOLFSSL_MSG("Must be one compression type in list"); + return INVALID_PARAMETER; + } + b = input[i++]; + if (b != NO_COMPRESSION) { + WOLFSSL_MSG("Must be no compression type in list"); + 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; + +#ifdef HAVE_QSH + QSH_Init(ssl); +#endif + + /* 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, + &clSuites))) { + return ret; + } + +#ifdef HAVE_STUNNEL + if ((ret = SNI_Callback(ssl)) != 0) + return ret; +#endif /*HAVE_STUNNEL*/ + + if (TLSX_Find(ssl->extensions, TLSX_SUPPORTED_VERSIONS) == NULL) + ssl->version.minor = pv.minor; + +#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; +#endif + + if (!usingPSK) { + ret = MatchSuite(ssl, &clSuites); + if (ret < 0) { + WOLFSSL_MSG("Unsupported cipher suite, ClientHello"); + return ret; + } + +#ifndef NO_PSK + if (ssl->options.resuming) { + ssl->options.resuming = 0; + XMEMSET(ssl->arrays->psk_key, 0, ssl->specs.hash_size); + /* May or may not have done any hashing. */ + ret = InitHandshakeHashes(ssl); + if (ret != 0) + return ret; + } +#endif + + ret = HashInput(ssl, input + begin, helloSz); + if (ret != 0) + return ret; + } + + i += totalExtSz; + *inOutIdx = i; + + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + + return 0; +} + +/* Send the HelloRetryRequest message to indicate the negotiated protocol + * version and security parameters the server is willing to use. + * Only a server will send this message. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +int SendTls13HelloRetryRequest(WOLFSSL *ssl) +{ + int ret; + byte* output; + word32 length; + word32 len; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + + /* Get the length of the extensions that will be written. */ + len = TLSX_GetResponseSize(ssl, hello_retry_request); + /* There must be extensions sent to indicate what client needs to do. */ + if (len == 0) + return MISSING_HANDSHAKE_DATA; + + /* Protocol version + Extensions */ + length = OPAQUE16_LEN + len; + sendSz = idx + length; + + /* Check buffers are big enough and grow if needed. */ + ret = CheckAvailableSize(ssl, sendSz); + if (ret != 0) + return ret; + + /* Get position in output buffer to write new message to. */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + /* Add record and hanshake headers. */ + AddTls13Headers(output, length, hello_retry_request, ssl); + + /* TODO: [TLS13] Replace existing code with code in comment. + * Use the TLS v1.3 draft version for now. + * + * Change to: + * output[idx++] = ssl->version.major; + * output[idx++] = ssl->version.minor; + */ + /* The negotiated protocol version. */ + output[idx++] = TLS_DRAFT_MAJOR; + output[idx++] = TLS_DRAFT_MINOR; + + /* Add TLS extensions. */ + TLSX_WriteResponse(ssl, output + idx, hello_retry_request); + idx += len; + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("HelloRetryRequest", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("HelloRetryRequest", &ssl->timeoutInfo, output, sendSz, + ssl->heap); +#endif + + ret = HashOutput(ssl, output, idx, 0); + if (ret != 0) + return ret; + + ssl->buffers.outputBuffer.length += sendSz; + + if (ssl->options.groupMessages) + return 0; + else + return SendBuffered(ssl); +} + +/* Send TLS v1.3 ServerHello message to client. + * Only a server will send this message. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +int SendTls13ServerHello(WOLFSSL* ssl) +{ + byte* output; + word32 length; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + int ret; + + /* Protocol version, server random, cipher suite and extensions. */ + length = VERSION_SZ + RAN_LEN + SUITE_LEN + + TLSX_GetResponseSize(ssl, server_hello); + sendSz = idx + length; + + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* Get position in output buffer to write new message to. */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Put the record and handshake headers on. */ + AddTls13Headers(output, length, server_hello, ssl); + + /* Protocol version. */ + output[idx++] = ssl->version.major; + output[idx++] = ssl->version.minor; + + /* TODO: [TLS13] Last 8 bytes have special meaning. */ + /* Generate server random. */ + ret = wc_RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN); + if (ret != 0) + return ret; + /* Store in SSL for debugging. */ + XMEMCPY(ssl->arrays->serverRandom, output + idx, RAN_LEN); + idx += RAN_LEN; + + WOLFSSL_MSG("Server random"); + WOLFSSL_BUFFER(ssl->arrays->serverRandom, RAN_LEN); + + + /* Chosen cipher suite */ + output[idx++] = ssl->options.cipherSuite0; + output[idx++] = ssl->options.cipherSuite; + + /* Extensions */ + TLSX_WriteResponse(ssl, output + idx, server_hello); + + ssl->buffers.outputBuffer.length += sendSz; + + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) + return ret; + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ServerHello", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("ServerHello", &ssl->timeoutInfo, output, sendSz, + ssl->heap); + #endif + + ssl->options.serverState = SERVER_HELLO_COMPLETE; + + if (ssl->options.groupMessages) + return 0; + else + return SendBuffered(ssl); +} + +/* Send the rest of the extensions encrypted under the handshake key. + * This message is always encrypted in TLS v1.3. + * Only a server will send this message. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +int SendTls13EncryptedExtensions(WOLFSSL *ssl) +{ + int ret; + byte* output; + word32 length; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + + ssl->keys.encryptionOn = 1; + + /* Derive early secret for handshake secret. */ + if ((ret = DeriveEarlySecret(ssl)) != 0) + return ret; + /* Derive the handshake secret now that we are at first message to be + * encrypted under the keys. + */ + if ((ret = DeriveHandshakeSecret(ssl)) != 0) + return ret; + if ((ret = DeriveTls13Keys(ssl, handshake_key, + ENCRYPT_AND_DECRYPT_SIDE)) != 0) + return ret; + + /* Setup encrypt/decrypt keys for following messages. */ + if ((ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE)) != 0) + return ret; + + length = TLSX_GetResponseSize(ssl, encrypted_extensions); + sendSz = idx + length; + /* Encryption always on. */ + sendSz += MAX_MSG_EXTRA; + + /* Check buffers are big enough and grow if needed. */ + ret = CheckAvailableSize(ssl, sendSz); + if (ret != 0) + return ret; + + /* Get position in output buffer to write new message to. */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Put the record and handshake headers on. */ + AddTls13Headers(output, length, encrypted_extensions, ssl); + + TLSX_WriteResponse(ssl, output + idx, encrypted_extensions); + idx += length; + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("EncryptedExtensions", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("EncryptedExtensions", &ssl->timeoutInfo, output, + sendSz, ssl->heap); +#endif + + /* This handshake message is always encrypted. */ + sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ, + idx - RECORD_HEADER_SZ, handshake, 1, 0); + if (sendSz < 0) + return sendSz; + + ssl->buffers.outputBuffer.length += sendSz; + + ssl->options.serverState = SERVER_ENCRYPTED_EXTENSIONS_COMPLETE; + + if (ssl->options.groupMessages) + return 0; + else + return SendBuffered(ssl); +} + +#ifndef NO_CERTS +/* Send the TLS v1.3 CertificateRequest message. + * This message is always encrypted in TLS v1.3. + * Only a server will send this message. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +int SendTls13CertificateRequest(WOLFSSL* ssl) +{ + byte *output; + int ret; + int sendSz; + int reqCtxLen = 0; + word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + int reqSz = OPAQUE8_LEN + reqCtxLen + REQ_HEADER_SZ + REQ_HEADER_SZ; + + reqSz += LENGTH_SZ + ssl->suites->hashSigAlgoSz; + + if (ssl->options.usingPSK_cipher || ssl->options.usingAnon_cipher) + return 0; /* not needed */ + + sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + reqSz; + /* Always encrypted and make room for padding. */ + sendSz += MAX_MSG_EXTRA; + + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* Get position in output buffer to write new message to. */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Put the record and handshake headers on. */ + AddTls13Headers(output, reqSz, certificate_request, ssl); + + /* Certificate request context. */ + /* TODO: [TLS13] Request context for post-handshake auth. + * Must be unique in the scope of the connection. + */ + output[i++] = reqCtxLen; + + /* supported hash/sig */ + c16toa(ssl->suites->hashSigAlgoSz, &output[i]); + i += LENGTH_SZ; + + XMEMCPY(&output[i], ssl->suites->hashSigAlgo, ssl->suites->hashSigAlgoSz); + i += ssl->suites->hashSigAlgoSz; + + /* Certificate authorities not supported yet - empty buffer. */ + c16toa(0, &output[i]); + i += REQ_HEADER_SZ; + + /* Certificate extensions. */ + /* TODO: [TLS13] Add extension handling. */ + c16toa(0, &output[i]); /* auth's */ + i += REQ_HEADER_SZ; + + /* Always encrypted. */ + sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ, + i - RECORD_HEADER_SZ, handshake, 1, 0); + if (sendSz < 0) + return sendSz; + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("CertificateRequest", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("CertificateRequest", &ssl->timeoutInfo, output, + sendSz, ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + if (!ssl->options.groupMessages) + return SendBuffered(ssl); + return 0; +} +#endif /* NO_CERTS */ +#endif /* NO_WOLFSSL_SERVER */ + +#ifndef NO_CERTS +#if !defined(NO_RSA) || defined(HAVE_ECC) +/* Encode the signature algorithm into buffer. + * + * hashalgo The hash algorithm. + * hsType The signature type. + * output The buffer to encode into. + */ +static INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output) +{ + switch (hsType) { +#ifdef HAVE_ECC + case DYNAMIC_TYPE_ECC: + output[0] = hashAlgo; + output[1] = ecc_dsa_sa_algo; + break; +#endif +#ifndef NO_RSA + case DYNAMIC_TYPE_RSA: + output[0] = hashAlgo; + output[1] = rsa_sa_algo; + break; +#endif + /* PSS signatures: 0x080[4-6] */ + /* ED25519: 0x0807 */ + /* ED448: 0x0808 */ + } +} + +/* Decode the signature algorithm. + * + * input The encoded signature algorithm. + * hashalgo The hash algorithm. + * hsType The signature type. + */ +static INLINE void DecodeSigAlg(byte* input, byte* hashAlgo, byte* hsType) +{ + switch (input[0]) { + /* PSS signatures: 0x080[4-6] */ + /* ED25519: 0x0807 */ + /* ED448: 0x0808 */ + default: + *hashAlgo = input[0]; + *hsType = input[1]; + break; + } +} + +/* Get the hash of the messages so far. + * + * ssl The SSL/TLS object. + * hash The buffer to write the hash to. + * returns the length of the hash. + */ +static INLINE int GetMsgHash(WOLFSSL *ssl, byte* hash) +{ + switch (ssl->specs.mac_algorithm) { + #ifndef NO_SHA256 + case sha256_mac: + wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash); + return SHA256_DIGEST_SIZE; + #endif /* !NO_SHA256 */ + #ifdef WOLFSSL_SHA384 + case sha384_mac: + wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash); + return SHA384_DIGEST_SIZE; + #endif /* WOLFSSL_SHA384 */ + #ifdef WOLFSSL_SHA512 + case sha512_mac: + wc_Sha512GetHash(&ssl->hsHashes->hashSha512, hash); + return SHA512_DIGEST_SIZE; + #endif /* WOLFSSL_SHA512 */ + } + return 0; +} + +/* The length of the certificate verification label - client and server. */ +#define CERT_VFY_LABEL_SZ 34 +/* The server certificate verification label. */ +static const byte serverCertVfyLabel[CERT_VFY_LABEL_SZ] = + "TLS 1.3, server CertificateVerify"; +/* The client certificate verification label. */ +static const byte clientCertVfyLabel[CERT_VFY_LABEL_SZ] = + "TLS 1.3, client CertificateVerify"; + +/* The number of prefix bytes for signature data. */ +#define SIGNING_DATA_PREFIX_SZ 64 +/* The prefix byte in the signature data. */ +#define SIGNING_DATA_PREFIX_BYTE 0x20 +/* Maximum length of the signature data. */ +#define MAX_SIG_DATA_SZ (SIGNING_DATA_PREFIX_SZ + \ + CERT_VFY_LABEL_SZ + \ + MAX_DIGEST_SIZE) + +/* Create the signature data for TLS v1.3 certificate verification. + * + * ssl The SSL/TLS object. + * sigData The signature data. + * sigDataSz The length of the signature data. + * check Indicates this is a check not create. + */ +static void CreateSigData(WOLFSSL* ssl, byte* sigData, word16* sigDataSz, + int check) +{ + word16 idx; + int side = ssl->options.side; + + /* Signature Data = Prefix | Label | Handshake Hash */ + XMEMSET(sigData, SIGNING_DATA_PREFIX_BYTE, SIGNING_DATA_PREFIX_SZ); + idx = SIGNING_DATA_PREFIX_SZ; + + #ifndef NO_WOLFSSL_SERVER + if ((side == WOLFSSL_SERVER_END && check) || + (side == WOLFSSL_CLIENT_END && !check)) { + XMEMCPY(&sigData[idx], clientCertVfyLabel, CERT_VFY_LABEL_SZ); + } + #endif + #ifndef NO_WOLFSSL_CLIENT + if ((side == WOLFSSL_CLIENT_END && check) || + (side == WOLFSSL_SERVER_END && !check)) { + XMEMCPY(&sigData[idx], serverCertVfyLabel, CERT_VFY_LABEL_SZ); + } + #endif + idx += CERT_VFY_LABEL_SZ; + + *sigDataSz = idx + GetMsgHash(ssl, &sigData[idx]); +} + +#ifndef NO_RSA +/* Encode the PKCS #1.5 RSA signature. + * + * sig The buffer to place the encoded signature into. + * sigData The data to be signed. + * sigDataSz The size of the data to be signed. + * hashAlgo The hash algorithm to use when signing. + * returns the length of the encoded signature or negative on error. + */ +static int CreateRSAEncodedSig(byte* sig, byte* sigData, int sigDataSz, + int hashAlgo) +{ + Digest digest; + int hashSz = 0; + int hashOid = 0; + + /* Digest the signature data. */ + switch (hashAlgo) { +#ifndef NO_WOLFSSL_SHA256 + case sha256_mac: + wc_InitSha256(&digest.sha256); + wc_Sha256Update(&digest.sha256, sigData, sigDataSz); + wc_Sha256Final(&digest.sha256, sigData); + wc_Sha256Free(&digest.sha256); + hashSz = SHA256_DIGEST_SIZE; + hashOid = SHA256h; + break; +#endif +#ifdef WOLFSSL_SHA384 + case sha384_mac: + wc_InitSha384(&digest.sha384); + wc_Sha384Update(&digest.sha384, sigData, sigDataSz); + wc_Sha384Final(&digest.sha384, sigData); + wc_Sha384Free(&digest.sha384); + hashSz = SHA384_DIGEST_SIZE; + hashOid = SHA384h; + break; +#endif +#ifdef WOLFSSL_SHA512 + case sha512_mac: + wc_InitSha512(&digest.sha512); + wc_Sha512Update(&digest.sha512, sigData, sigDataSz); + wc_Sha512Final(&digest.sha512, sigData); + wc_Sha512Free(&digest.sha512); + hashSz = SHA512_DIGEST_SIZE; + hashOid = SHA512h; + break; +#endif + } + + /* Encode the signature data as per PKCS #1.5 */ + return wc_EncodeSignature(sig, sigData, hashSz, hashOid); +} + +/* Check that the decrypted signature matches the encoded signature + * based on the digest of the signature data. + * + * ssl The SSL/TLS object. + * hashAlgo The hash algorithm used to generate signature. + * decSig The decrypted signature. + * decSigSz The size of the decrypted signature. + * returns 0 on success, otherwise failure. + */ +static int CheckRSASignature(WOLFSSL* ssl, int hashAlgo, byte* decSig, + word32 decSigSz) +{ + int ret = 0; + byte sigData[MAX_SIG_DATA_SZ]; + word16 sigDataSz; +#ifdef WOLFSSL_SMALL_STACK + byte* encodedSig = NULL; +#else + byte encodedSig[MAX_ENCODED_SIG_SZ]; +#endif + word32 sigSz; + +#ifdef WOLFSSL_SMALL_STACK + encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (encodedSig == NULL) { + ret = MEMORY_E; + goto end; + } +#endif + + CreateSigData(ssl, sigData, &sigDataSz, 1); + sigSz = CreateRSAEncodedSig(encodedSig, sigData, sigDataSz, hashAlgo); + /* Check the encoded and decrypted signature data match. */ + if (decSigSz != sigSz || decSig == NULL || + XMEMCMP(decSig, encodedSig, sigSz) != 0) { + ret = VERIFY_CERT_ERROR; + } + +#ifdef WOLFSSL_SMALL_STACK +end: + if (encodedSig != NULL) + XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} +#endif /* !NO_RSA */ +#endif /* !NO_RSA || HAVE_ECC */ + +/* Get the next certificate from the list for writing into the TLS v1.3 + * Certificate message. + * + * data The certificate list. + * length The length of the certificate data in the list. + * idx The index of the next certificate. + * returns the length of the certificate data. 0 indicates no more certificates + * in the list. + */ +static word32 NextCert(byte* data, word32 length, word32* idx) +{ + word32 len; + + /* Is index at end of list. */ + if (*idx == length) + return 0; + + /* Length of the current ASN.1 encoded certificate. */ + c24to32(data + *idx, &len); + /* Include the length field. */ + len += 3; + + /* Move index to next certificate and return the current certificate's + * length. + */ + *idx += len; + return len; +} + +/* Add certificate data and empty extension to output up to the fragment size. + * + * cert The certificate data to write out. + * len The length of the certificate data. + * idx The start of the certificate data to write out. + * fragSz The maximum size of this fragment. + * output The buffer to write to. + * returns the number of bytes written. + */ +static word32 AddCertExt(byte* cert, word32 len, word32 idx, word32 fragSz, + byte* output) +{ + word32 i = 0; + word32 copySz = min(len - idx, fragSz); + + if (idx < len) { + XMEMCPY(output, cert + idx, copySz); + i = copySz; + } + + if (copySz + OPAQUE16_LEN <= fragSz) { + /* Empty extension */ + output[i++] = 0; + output[i++] = 0; + } + + return i; +} + +/* Send the certificate for this end and any CAs that help with validation. + * This message is always encrypted in TLS v1.3. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +int SendTls13Certificate(WOLFSSL* ssl) +{ + int ret = 0; + word32 certSz, certChainSz, headerSz, listSz, payloadSz; + word32 length, maxFragment; + word32 len = 0; + word32 idx = 0; + word32 offset = OPAQUE16_LEN; + byte* p = NULL; + + + /* TODO: [TLS13] Request context for post-handshake auth. + * Taken from request if post-handshake. + */ + + if (ssl->options.sendVerify == SEND_BLANK_CERT) { + certSz = 0; + certChainSz = 0; + headerSz = CERT_HEADER_SZ; + length = CERT_HEADER_SZ; + listSz = 0; + } + else { + if (!ssl->buffers.certificate) { + WOLFSSL_MSG("Send Cert missing certificate buffer"); + return BUFFER_ERROR; + } + /* Certificate Data */ + certSz = ssl->buffers.certificate->length; + /* Cert Req Ctx Len | Cert List Len | Cert Data Len */ + headerSz = OPAQUE8_LEN + CERT_HEADER_SZ + CERT_HEADER_SZ; + /* Length of message data with one certificate and empty extensions. */ + length = headerSz + certSz + OPAQUE16_LEN; + /* Length of list data with one certificate and empty extensions. */ + listSz = CERT_HEADER_SZ + certSz + OPAQUE16_LEN; + + /* Send rest of chain if sending cert (chain has leading size/s). */ + if (certSz > 0 && ssl->buffers.certChainCnt > 0) { + /* The pointer to the current spot in the cert chain buffer. */ + p = ssl->buffers.certChain->buffer; + /* Chain length including extensions. */ + certChainSz = ssl->buffers.certChain->length + + OPAQUE16_LEN * ssl->buffers.certChainCnt; + length += certChainSz; + listSz += certChainSz; + } + else + certChainSz = 0; + } + + payloadSz = length; + + if (ssl->fragOffset != 0) + length -= (ssl->fragOffset + headerSz); + + maxFragment = MAX_RECORD_SIZE; + + #ifdef HAVE_MAX_FRAGMENT + if (ssl->max_fragment != 0 && maxFragment >= ssl->max_fragment) + maxFragment = ssl->max_fragment; + #endif /* HAVE_MAX_FRAGMENT */ + + while (length > 0 && ret == 0) { + byte* output = NULL; + word32 fragSz = 0; + word32 i = RECORD_HEADER_SZ; + int sendSz = RECORD_HEADER_SZ; + + if (ssl->fragOffset == 0) { + if (headerSz + certSz + OPAQUE16_LEN + certChainSz <= + maxFragment - HANDSHAKE_HEADER_SZ) { + + fragSz = headerSz + certSz + OPAQUE16_LEN + certChainSz; + } + else { + fragSz = maxFragment - HANDSHAKE_HEADER_SZ; + } + sendSz += fragSz + HANDSHAKE_HEADER_SZ; + i += HANDSHAKE_HEADER_SZ; + } + else { + fragSz = min(length, maxFragment); + sendSz += fragSz; + } + + sendSz += MAX_MSG_EXTRA; + + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* Get position in output buffer to write new message to. */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + if (ssl->fragOffset == 0) { + AddTls13FragHeaders(output, fragSz, 0, payloadSz, certificate, ssl); + + /* Request context. */ + output[i++] = 0; + length -= 1; + fragSz -= 1; + /* Certificate list length. */ + c32to24(listSz, output + i); + i += CERT_HEADER_SZ; + length -= CERT_HEADER_SZ; + fragSz -= CERT_HEADER_SZ; + /* Leaf certificate data length. */ + if (certSz > 0) { + c32to24(certSz, output + i); + i += CERT_HEADER_SZ; + length -= CERT_HEADER_SZ; + fragSz -= CERT_HEADER_SZ; + } + } + else + AddTls13RecordHeader(output, fragSz, handshake, ssl); + + /* TODO: [TLS13] Test with fragments and multiple CA certs */ + if (certSz > 0 && ssl->fragOffset < certSz + OPAQUE16_LEN) { + /* Put in the leaf certificate and empty extension. */ + word32 copySz = AddCertExt(ssl->buffers.certificate->buffer, certSz, + ssl->fragOffset, fragSz, output + i); + + i += copySz; + ssl->fragOffset += copySz; + length -= copySz; + fragSz -= copySz; + } + if (certChainSz > 0 && fragSz > 0) { + /* Put in the CA certificates with empty extensions. */ + while (fragSz > 0) { + word32 l; + + if (offset == len + OPAQUE16_LEN) { + /* Find next CA certificate to write out. */ + offset = 0; + len = NextCert(ssl->buffers.certChain->buffer, + ssl->buffers.certChain->length, &idx); + if (len == 0) + break; + } + + /* Write out certificate and empty extension. */ + l = AddCertExt(p, len, offset, fragSz, output + i); + i += l; + ssl->fragOffset += l; + length -= l; + fragSz -= l; + offset += l; + } + } + + if ((int)i - RECORD_HEADER_SZ < 0) { + WOLFSSL_MSG("Send Cert bad inputSz"); + return BUFFER_E; + } + + /* This message is always encrypted. */ + sendSz = BuildTls13Message(ssl, output, sendSz, + output + RECORD_HEADER_SZ, + i - RECORD_HEADER_SZ, handshake, 1, 0); + if (sendSz < 0) + return sendSz; + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("Certificate", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("Certificate", &ssl->timeoutInfo, output, sendSz, + ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + } + + if (ret != WANT_WRITE) { + /* Clean up the fragment offset. */ + ssl->fragOffset = 0; + if (ssl->options.side == WOLFSSL_SERVER_END) + ssl->options.serverState = SERVER_CERT_COMPLETE; + } + + return ret; +} + +typedef struct Scv13Args { + byte* output; /* not allocated */ +#ifndef NO_RSA + byte* verifySig; +#endif + byte* verify; /* not allocated */ + byte* input; + word32 idx; + word32 extraSz; + word32 sigSz; + int sendSz; + int length; + int inputSz; + + byte sigData[MAX_SIG_DATA_SZ]; + word16 sigDataSz; + + word16 keySz; +} Scv13Args; + +static void FreeScv13Args(WOLFSSL* ssl, void* pArgs) +{ + Scv13Args* args = (Scv13Args*)pArgs; + + (void)ssl; + +#ifndef NO_RSA + if (args->verifySig) { + XFREE(args->verifySig, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + args->verifySig = NULL; + } +#endif + if (args->input) { + XFREE(args->input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + args->input = NULL; + } +} + +/* Send the TLS v1.3 CertificateVerify message. + * A hash of all the message so far is used. + * The signed data is: + * 0x20 * 64 | context string | 0x00 | hash of messages + * This message is always encrypted in TLS v1.3. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +int SendTls13CertificateVerify(WOLFSSL* ssl) +{ + int ret = 0; +#ifdef WOLFSSL_ASYNC_CRYPT + Scv13Args* args = (Scv13Args*)ssl->async.args; + typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1]; + (void)sizeof(args_test); +#else + Scv13Args args[1]; +#endif + + WOLFSSL_ENTER("SendTls13CertificateVerify"); + +#ifdef WOLFSSL_ASYNC_CRYPT + ret = wolfSSL_AsyncPop(ssl, &ssl->options.asyncState); + if (ret != WC_NOT_PENDING_E) { + /* Check for error */ + if (ret < 0) + goto exit_scv; + } + else +#endif + { + /* Reset state */ + ret = 0; + ssl->options.asyncState = TLS_ASYNC_BEGIN; + XMEMSET(args, 0, sizeof(Scv13Args)); + #ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = FreeScv13Args; + #endif + } + + switch(ssl->options.asyncState) + { + case TLS_ASYNC_BEGIN: + { + if (ssl->options.sendVerify == SEND_BLANK_CERT) { + return 0; /* sent blank cert, can't verify */ + } + + args->sendSz = MAX_CERT_VERIFY_SZ; + /* Always encrypted. */ + args->sendSz += MAX_MSG_EXTRA; + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, args->sendSz)) != 0) { + goto exit_scv; + } + + /* get output buffer */ + args->output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_BUILD; + } /* case TLS_ASYNC_BEGIN */ + + case TLS_ASYNC_BUILD: + { + /* idx is used to track verify pointer offset to output */ + args->idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + args->verify = &args->output[RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ]; + + ret = DecodePrivateKey(ssl, &args->keySz); + if (ret != 0) + goto exit_scv; + + /* Add signature algorithm. */ + EncodeSigAlg(ssl->suites->hashAlgo, ssl->hsType, args->verify); + + /* Create the data to be signed. */ + CreateSigData(ssl, args->sigData, &args->sigDataSz, 0); + + #ifndef NO_RSA + if (ssl->hsType == DYNAMIC_TYPE_RSA) { + args->sigSz = ENCRYPT_LEN; + + /* build encoded signature buffer */ + ssl->buffers.sig.length = MAX_ENCODED_SIG_SZ; + ssl->buffers.sig.buffer = (byte*)XMALLOC(ssl->buffers.sig.length, + ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (ssl->buffers.sig.buffer == NULL) + return MEMORY_E; + + /* Digest the signature data and encode. Used in verify too. */ + ssl->buffers.sig.length = CreateRSAEncodedSig( + ssl->buffers.sig.buffer, args->sigData, args->sigDataSz, + ssl->suites->hashAlgo); + if (ret != 0) + goto exit_scv; + } + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + if (ssl->hsType == DYNAMIC_TYPE_ECC) + ssl->buffers.sig.length = args->sendSz - args->idx - + HASH_SIG_SIZE - VERIFY_HEADER; + #endif /* HAVE_ECC */ + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_DO; + } /* case TLS_ASYNC_BUILD */ + + case TLS_ASYNC_DO: + { + #ifdef HAVE_ECC + if (ssl->hsType == DYNAMIC_TYPE_ECC) { + ret = EccSign(ssl, args->sigData, args->sigDataSz, + args->verify + HASH_SIG_SIZE + VERIFY_HEADER, + &ssl->buffers.sig.length, (ecc_key*)ssl->hsKey, + #if defined(HAVE_PK_CALLBACKS) + ssl->buffers.key->buffer, ssl->buffers.key->length, + ssl->EccSignCtx + #else + NULL, 0, NULL + #endif + ); + } + #endif /* HAVE_ECC */ + #ifndef NO_RSA + if (ssl->hsType == DYNAMIC_TYPE_RSA) { + /* restore verify pointer */ + args->verify = &args->output[args->idx]; + + ret = RsaSign(ssl, ssl->buffers.sig.buffer, ssl->buffers.sig.length, + args->verify + HASH_SIG_SIZE + VERIFY_HEADER, &args->sigSz, + (RsaKey*)ssl->hsKey, + ssl->buffers.key->buffer, ssl->buffers.key->length, + #ifdef HAVE_PK_CALLBACKS + ssl->RsaSignCtx + #else + NULL + #endif + ); + args->keySz = ssl->buffers.sig.length; + } + #endif /* !NO_RSA */ + + /* Check for error */ + if (ret != 0) { + goto exit_scv; + } + + /* Add signature length. */ + c16toa(args->keySz, args->verify + HASH_SIG_SIZE); + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_VERIFY; + } /* case TLS_ASYNC_DO */ + + case TLS_ASYNC_VERIFY: + { + /* restore verify pointer */ + args->verify = &args->output[args->idx]; + + #ifndef NO_RSA + if (ssl->hsType == DYNAMIC_TYPE_RSA) { + if (args->verifySig == NULL) { + args->verifySig = (byte*)XMALLOC(args->sigSz, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (args->verifySig == NULL) { + ERROR_OUT(MEMORY_E, exit_scv); + } + XMEMCPY(args->verifySig, args->verify + HASH_SIG_SIZE + VERIFY_HEADER, + args->sigSz); + } + + /* check for signature faults */ + ret = VerifyRsaSign(ssl, args->verifySig, args->sigSz, + ssl->buffers.sig.buffer, ssl->buffers.sig.length, (RsaKey*)ssl->hsKey); + } + #endif /* !NO_RSA */ + + /* Check for error */ + if (ret != 0) { + goto exit_scv; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_FINALIZE; + } /* case TLS_ASYNC_VERIFY */ + + case TLS_ASYNC_FINALIZE: + { + /* Put the record and handshake headers on. */ + AddTls13Headers(args->output, args->keySz + HASH_SIG_SIZE + VERIFY_HEADER, + certificate_verify, ssl); + + args->sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + args->keySz + + HASH_SIG_SIZE + VERIFY_HEADER; + + /* This message is always encrypted. */ + args->sendSz = BuildTls13Message(ssl, args->output, + MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA, + args->output + RECORD_HEADER_SZ, + args->sendSz - RECORD_HEADER_SZ, handshake, + 1, 0); + if (args->sendSz < 0) { + ret = args->sendSz; + goto exit_scv; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_END; + } /* case TLS_ASYNC_FINALIZE */ + + case TLS_ASYNC_END: + { + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("CertificateVerify", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("CertificateVerify", &ssl->timeoutInfo, + args->output, args->sendSz, ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += args->sendSz; + + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + break; + } + default: + ret = INPUT_CASE_ERROR; + } /* switch(ssl->options.asyncState) */ + +exit_scv: + + WOLFSSL_LEAVE("SendTls13CertificateVerify", ret); + +#ifdef WOLFSSL_ASYNC_CRYPT + /* Handle async operation */ + if (ret == WC_PENDING_E) { + return ret; + } +#endif /* WOLFSSL_ASYNC_CRYPT */ + + /* Final cleanup */ + FreeScv13Args(ssl, args); + FreeKeyExchange(ssl); + + return ret; +} + +int ProcessPeerCerts(WOLFSSL* ssl, buffer *certs, buffer *exts, int totalCerts) +{ + int ret = 0; + int anyError = 0; + int count; +#ifdef WOLFSSL_SMALL_STACK + char* domain = NULL; + DecodedCert* dCert = NULL; + WOLFSSL_X509_STORE_CTX* store = NULL; +#else + char domain[ASN_NAME_MAX]; + DecodedCert dCert[1]; + WOLFSSL_X509_STORE_CTX store[1]; +#endif + +#ifdef WOLFSSL_TRUST_PEER_CERT + byte haveTrustPeer = 0; /* was cert verified by loaded trusted peer cert */ +#endif + + /* TODO: [TLS13] Handle certificate extensions */ + (void)exts; + + count = totalCerts; + +#ifdef WOLFSSL_SMALL_STACK + dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (dCert == NULL) + return MEMORY_E; +#endif + +#ifdef WOLFSSL_TRUST_PEER_CERT + /* if using trusted peer certs check before verify chain and CA test */ + if (count > 0) { + TrustedPeerCert* tp = NULL; + + InitDecodedCert(dCert, certs[0].buffer, certs[0].length, ssl->heap); + ret = ParseCertRelative(dCert, CERT_TYPE, 0, ssl->ctx->cm); + #ifndef NO_SKID + if (dCert->extAuthKeyIdSet) { + tp = GetTrustedPeer(ssl->ctx->cm, dCert->extSubjKeyId, + WC_MATCH_SKID); + } + else { /* if the cert has no SKID try to match by name */ + tp = GetTrustedPeer(ssl->ctx->cm, dCert->subjectHash, + WC_MATCH_NAME); + } + #else /* NO_SKID */ + tp = GetTrustedPeer(ssl->ctx->cm, dCert->subjectHash, + WC_MATCH_NAME); + #endif /* NO SKID */ + WOLFSSL_MSG("Checking for trusted peer cert"); + + if (tp == NULL) { + /* no trusted peer cert */ + WOLFSSL_MSG("No matching trusted peer cert. Checking CAs"); + FreeDecodedCert(dCert); + } else if (MatchTrustedPeer(tp, dCert)){ + WOLFSSL_MSG("Found matching trusted peer cert"); + haveTrustPeer = 1; + } else { + WOLFSSL_MSG("Trusted peer cert did not match!"); + FreeDecodedCert(dCert); + } + } + if (!haveTrustPeer) { /* do not verify chain if trusted peer cert found */ +#endif /* WOLFSSL_TRUST_PEER_CERT */ + + /* verify up to peer's first */ + while (count > 1) { + buffer myCert = certs[count - 1]; + byte* subjectHash; + + InitDecodedCert(dCert, myCert.buffer, myCert.length, ssl->heap); + ret = ParseCertRelative(dCert, CERT_TYPE, !ssl->options.verifyNone, + ssl->ctx->cm); + #ifndef NO_SKID + subjectHash = dCert->extSubjKeyId; + #else + subjectHash = dCert->subjectHash; + #endif + + /* Check key sizes for certs. Is redundent check since ProcessBuffer + also performs this check. */ + if (!ssl->options.verifyNone) { + switch (dCert->keyOID) { + #ifndef NO_RSA + case RSAk: + if (ssl->options.minRsaKeySz < 0 || + dCert->pubKeySize < (word16)ssl->options.minRsaKeySz) { + WOLFSSL_MSG("RSA key size in cert chain error"); + ret = RSA_KEY_SIZE_E; + } + break; + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + case ECDSAk: + if (ssl->options.minEccKeySz < 0 || + dCert->pubKeySize < (word16)ssl->options.minEccKeySz) { + WOLFSSL_MSG("ECC key size in cert chain error"); + ret = ECC_KEY_SIZE_E; + } + break; + #endif /* HAVE_ECC */ + + default: + WOLFSSL_MSG("Key size not checked"); + break; /* key not being checked for size if not in switch */ + } + } + + if (ret == 0 && dCert->isCA == 0) { + WOLFSSL_MSG("Chain cert is not a CA, not adding as one"); + } + else if (ret == 0 && ssl->options.verifyNone) { + WOLFSSL_MSG("Chain cert not verified by option, not adding as CA"); + } + else if (ret == 0 && !AlreadySigner(ssl->ctx->cm, subjectHash)) { + DerBuffer* add = NULL; + ret = AllocDer(&add, myCert.length, CA_TYPE, ssl->heap); + if (ret < 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif + return ret; + } + + WOLFSSL_MSG("Adding CA from chain"); + + XMEMCPY(add->buffer, myCert.buffer, myCert.length); + + /* already verified above */ + ret = AddCA(ssl->ctx->cm, &add, WOLFSSL_CHAIN_CA, 0); + if (ret == 1) ret = 0; /* SSL_SUCCESS for external */ + } + else if (ret != 0) { + WOLFSSL_MSG("Failed to verify CA from chain"); + #ifdef OPENSSL_EXTRA + ssl->peerVerifyRet = X509_V_ERR_INVALID_CA; + #endif + } + else { + WOLFSSL_MSG("Verified CA from chain and already had it"); + } + +#if defined(HAVE_OCSP) || defined(HAVE_CRL) + if (ret == 0) { + int doCrlLookup = 1; + +#ifdef HAVE_OCSP + #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 + if (ssl->status_request_v2) + ret = TLSX_CSR2_InitRequests(ssl->extensions, dCert, 0, + ssl->heap); + else /* skips OCSP and force CRL check */ + #endif + if (ssl->ctx->cm->ocspEnabled && ssl->ctx->cm->ocspCheckAll) { + WOLFSSL_MSG("Doing Non Leaf OCSP check"); + ret = CheckCertOCSP(ssl->ctx->cm->ocsp, dCert, NULL); + doCrlLookup = (ret == OCSP_CERT_UNKNOWN); + if (ret != 0) { + doCrlLookup = 0; + WOLFSSL_MSG("\tOCSP Lookup not ok"); + } + } +#endif /* HAVE_OCSP */ + +#ifdef HAVE_CRL + if (ret == 0 && doCrlLookup && ssl->ctx->cm->crlEnabled + && ssl->ctx->cm->crlCheckAll) { + WOLFSSL_MSG("Doing Non Leaf CRL check"); + ret = CheckCertCRL(ssl->ctx->cm->crl, dCert); + + if (ret != 0) { + WOLFSSL_MSG("\tCRL check not ok"); + } + } +#else + (void)doCrlLookup; +#endif /* HAVE_CRL */ + } +#endif /* HAVE_OCSP || HAVE_CRL */ + + if (ret != 0 && anyError == 0) + anyError = ret; /* save error from last time */ + + FreeDecodedCert(dCert); + count--; + } + +#ifdef WOLFSSL_TRUST_PEER_CERT + } /* end of if (haveTrustPeer) -- a check for if already verified */ +#endif + + /* peer's, may not have one if blank client cert sent by TLSv1.2 */ + if (count) { + buffer myCert = certs[0]; + int fatal = 0; + + WOLFSSL_MSG("Verifying Peer's cert"); + +#ifdef WOLFSSL_TRUST_PEER_CERT + if (!haveTrustPeer) { /* do not parse again if previously verified */ +#endif + InitDecodedCert(dCert, myCert.buffer, myCert.length, ssl->heap); + ret = ParseCertRelative(dCert, CERT_TYPE, !ssl->options.verifyNone, + ssl->ctx->cm); +#ifdef WOLFSSL_TRUST_PEER_CERT + } +#endif + + if (ret == 0) { + WOLFSSL_MSG("Verified Peer's cert"); + #ifdef OPENSSL_EXTRA + ssl->peerVerifyRet = X509_V_OK; + #endif + fatal = 0; + } + else if (ret == ASN_PARSE_E) { + WOLFSSL_MSG("Got Peer cert ASN PARSE ERROR, fatal"); + fatal = 1; + } + else { + WOLFSSL_MSG("Failed to verify Peer's cert"); + #ifdef OPENSSL_EXTRA + ssl->peerVerifyRet = X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE; + #endif + if (ssl->verifyCallback) { + WOLFSSL_MSG("\tCallback override available, will continue"); + fatal = 0; + } + else { + WOLFSSL_MSG("\tNo callback override available, fatal"); + fatal = 1; + } + } + +#ifdef HAVE_SECURE_RENEGOTIATION + if (fatal == 0 && ssl->secure_renegotiation + && ssl->secure_renegotiation->enabled) { + + if (IsEncryptionOn(ssl, 0)) { + /* compare against previous time */ + if (XMEMCMP(dCert->subjectHash, + ssl->secure_renegotiation->subject_hash, + SHA_DIGEST_SIZE) != 0) { + WOLFSSL_MSG("Peer sent different cert during scr, fatal"); + fatal = 1; + ret = SCR_DIFFERENT_CERT_E; + } + } + + /* cache peer's hash */ + if (fatal == 0) { + XMEMCPY(ssl->secure_renegotiation->subject_hash, + dCert->subjectHash, SHA_DIGEST_SIZE); + } + } +#endif + +#if defined(HAVE_OCSP) || defined(HAVE_CRL) + if (fatal == 0) { + int doLookup = 1; + + if (ssl->options.side == WOLFSSL_CLIENT_END) { +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST + if (ssl->status_request) { + fatal = TLSX_CSR_InitRequest(ssl->extensions, dCert, + ssl->heap); + doLookup = 0; + } +#endif +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 + if (ssl->status_request_v2) { + fatal = TLSX_CSR2_InitRequests(ssl->extensions, dCert, 1, + ssl->heap); + doLookup = 0; + } +#endif + } + +#ifdef HAVE_OCSP + if (doLookup && ssl->ctx->cm->ocspEnabled) { + WOLFSSL_MSG("Doing Leaf OCSP check"); + ret = CheckCertOCSP(ssl->ctx->cm->ocsp, dCert, NULL); + doLookup = (ret == OCSP_CERT_UNKNOWN); + if (ret != 0) { + WOLFSSL_MSG("\tOCSP Lookup not ok"); + fatal = 0; + #ifdef OPENSSL_EXTRA + ssl->peerVerifyRet = X509_V_ERR_CERT_REJECTED; + #endif + } + } +#endif /* HAVE_OCSP */ + +#ifdef HAVE_CRL + if (doLookup && ssl->ctx->cm->crlEnabled) { + WOLFSSL_MSG("Doing Leaf CRL check"); + ret = CheckCertCRL(ssl->ctx->cm->crl, dCert); + if (ret != 0) { + WOLFSSL_MSG("\tCRL check not ok"); + fatal = 0; + #ifdef OPENSSL_EXTRA + ssl->peerVerifyRet = X509_V_ERR_CERT_REJECTED; + #endif + } + } +#endif /* HAVE_CRL */ + (void)doLookup; + } +#endif /* HAVE_OCSP || HAVE_CRL */ + +#ifdef KEEP_PEER_CERT + { + /* set X509 format for peer cert even if fatal */ + int copyRet = CopyDecodedToX509(&ssl->peerCert, dCert); + if (copyRet == MEMORY_E) + fatal = 1; + } +#endif + +#ifndef IGNORE_KEY_EXTENSIONS + if (dCert->extKeyUsageSet) { + if ((ssl->specs.kea == rsa_kea) && + (ssl->options.side == WOLFSSL_CLIENT_END) && + (dCert->extKeyUsage & KEYUSE_KEY_ENCIPHER) == 0) { + ret = KEYUSE_ENCIPHER_E; + } + if ((ssl->specs.sig_algo == rsa_sa_algo || + (ssl->specs.sig_algo == ecc_dsa_sa_algo && + !ssl->specs.static_ecdh)) && + (dCert->extKeyUsage & KEYUSE_DIGITAL_SIG) == 0) { + WOLFSSL_MSG("KeyUse Digital Sig not set"); + ret = KEYUSE_SIGNATURE_E; + } + } + + if (dCert->extExtKeyUsageSet) { + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if ((dCert->extExtKeyUsage & + (EXTKEYUSE_ANY | EXTKEYUSE_SERVER_AUTH)) == 0) { + WOLFSSL_MSG("ExtKeyUse Server Auth not set"); + ret = EXTKEYUSE_AUTH_E; + } + } + else { + if ((dCert->extExtKeyUsage & + (EXTKEYUSE_ANY | EXTKEYUSE_CLIENT_AUTH)) == 0) { + WOLFSSL_MSG("ExtKeyUse Client Auth not set"); + ret = EXTKEYUSE_AUTH_E; + } + } + } +#endif /* IGNORE_KEY_EXTENSIONS */ + + if (fatal) { + FreeDecodedCert(dCert); + #ifdef WOLFSSL_SMALL_STACK + XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif + ssl->error = ret; + #ifdef OPENSSL_EXTRA + ssl->peerVerifyRet = X509_V_ERR_CERT_REJECTED; + #endif + return ret; + } + ssl->options.havePeerCert = 1; + +#ifdef WOLFSSL_SMALL_STACK + domain = (char*)XMALLOC(ASN_NAME_MAX, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (domain == NULL) { + FreeDecodedCert(dCert); + XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + /* store for callback use */ + if (dCert->subjectCNLen < ASN_NAME_MAX) { + XMEMCPY(domain, dCert->subjectCN, dCert->subjectCNLen); + domain[dCert->subjectCNLen] = '\0'; + } + else + domain[0] = '\0'; + + if (!ssl->options.verifyNone && ssl->buffers.domainName.buffer) { + if (MatchDomainName(dCert->subjectCN, dCert->subjectCNLen, + (char*)ssl->buffers.domainName.buffer) == 0) { + WOLFSSL_MSG("DomainName match on common name failed"); + if (CheckAltNames(dCert, + (char*)ssl->buffers.domainName.buffer) == 0 ) { + WOLFSSL_MSG("DomainName match on alt names failed too"); + ret = DOMAIN_NAME_MISMATCH; /* try to get peer key still */ + } + } + } + + /* decode peer key */ + switch (dCert->keyOID) { + #ifndef NO_RSA + case RSAk: + { + word32 idx = 0; + int keyRet = 0; + + if (ssl->peerRsaKey == NULL) { + ssl->peerRsaKey = (RsaKey*)XMALLOC(sizeof(RsaKey), + ssl->heap, DYNAMIC_TYPE_RSA); + if (ssl->peerRsaKey == NULL) { + WOLFSSL_MSG("PeerRsaKey Memory error"); + keyRet = MEMORY_E; + } else { + keyRet = wc_InitRsaKey_ex(ssl->peerRsaKey, + ssl->heap, ssl->devId); + } + } else if (ssl->peerRsaKeyPresent) { + /* don't leak on reuse */ + wc_FreeRsaKey(ssl->peerRsaKey); + ssl->peerRsaKeyPresent = 0; + keyRet = wc_InitRsaKey_ex(ssl->peerRsaKey, ssl->heap, ssl->devId); + } + + if (keyRet != 0 || wc_RsaPublicKeyDecode(dCert->publicKey, + &idx, ssl->peerRsaKey, dCert->pubKeySize) != 0) { + ret = PEER_KEY_ERROR; + } + else { + ssl->peerRsaKeyPresent = 1; + #ifdef HAVE_PK_CALLBACKS + #ifndef NO_RSA + ssl->buffers.peerRsaKey.buffer = + (byte*)XMALLOC(dCert->pubKeySize, + ssl->heap, DYNAMIC_TYPE_RSA); + if (ssl->buffers.peerRsaKey.buffer == NULL) + ret = MEMORY_ERROR; + else { + XMEMCPY(ssl->buffers.peerRsaKey.buffer, + dCert->publicKey, dCert->pubKeySize); + ssl->buffers.peerRsaKey.length = + dCert->pubKeySize; + } + #endif /* NO_RSA */ + #endif /*HAVE_PK_CALLBACKS */ + } + + /* check size of peer RSA key */ + if (ret == 0 && ssl->peerRsaKeyPresent && + !ssl->options.verifyNone && + wc_RsaEncryptSize(ssl->peerRsaKey) + < ssl->options.minRsaKeySz) { + ret = RSA_KEY_SIZE_E; + WOLFSSL_MSG("Peer RSA key is too small"); + } + + } + break; + #endif /* NO_RSA */ + #ifdef HAVE_NTRU + case NTRUk: + { + if (dCert->pubKeySize > sizeof(ssl->peerNtruKey)) { + ret = PEER_KEY_ERROR; + } + else { + XMEMCPY(ssl->peerNtruKey, dCert->publicKey, + dCert->pubKeySize); + ssl->peerNtruKeyLen = (word16)dCert->pubKeySize; + ssl->peerNtruKeyPresent = 1; + } + } + break; + #endif /* HAVE_NTRU */ + #ifdef HAVE_ECC + case ECDSAk: + { + int curveId; + if (ssl->peerEccDsaKey == NULL) { + /* alloc/init on demand */ + ssl->peerEccDsaKey = (ecc_key*)XMALLOC(sizeof(ecc_key), + ssl->heap, DYNAMIC_TYPE_ECC); + if (ssl->peerEccDsaKey == NULL) { + WOLFSSL_MSG("PeerEccDsaKey Memory error"); + return MEMORY_E; + } + wc_ecc_init_ex(ssl->peerEccDsaKey, ssl->heap, + ssl->devId); + } else if (ssl->peerEccDsaKeyPresent) { + /* don't leak on reuse */ + wc_ecc_free(ssl->peerEccDsaKey); + ssl->peerEccDsaKeyPresent = 0; + wc_ecc_init_ex(ssl->peerEccDsaKey, ssl->heap, + ssl->devId); + } + + curveId = wc_ecc_get_oid(dCert->keyOID, NULL, NULL); + if (wc_ecc_import_x963_ex(dCert->publicKey, + dCert->pubKeySize, ssl->peerEccDsaKey, curveId) != 0) { + ret = PEER_KEY_ERROR; + } + else { + ssl->peerEccDsaKeyPresent = 1; + #ifdef HAVE_PK_CALLBACKS + #ifdef HAVE_ECC + ssl->buffers.peerEccDsaKey.buffer = + (byte*)XMALLOC(dCert->pubKeySize, + ssl->heap, DYNAMIC_TYPE_ECC); + if (ssl->buffers.peerEccDsaKey.buffer == NULL) + ret = MEMORY_ERROR; + else { + XMEMCPY(ssl->buffers.peerEccDsaKey.buffer, + dCert->publicKey, dCert->pubKeySize); + ssl->buffers.peerEccDsaKey.length = + dCert->pubKeySize; + } + #endif /* HAVE_ECC */ + #endif /*HAVE_PK_CALLBACKS */ + } + + /* check size of peer ECC key */ + if (ret == 0 && ssl->peerEccDsaKeyPresent && + !ssl->options.verifyNone && + wc_ecc_size(ssl->peerEccDsaKey) + < ssl->options.minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Peer ECC key is too small"); + } + + } + break; + #endif /* HAVE_ECC */ + default: + break; + } + + FreeDecodedCert(dCert); + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + store = (WOLFSSL_X509_STORE_CTX*)XMALLOC(sizeof(WOLFSSL_X509_STORE_CTX), + NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (store == NULL) { + XFREE(domain, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + XMEMSET(store, 0, sizeof(WOLFSSL_X509_STORE_CTX)); + + if (anyError != 0 && ret == 0) + ret = anyError; + + if (ret != 0) { + if (!ssl->options.verifyNone) { + int why = bad_certificate; + + if (ret == ASN_AFTER_DATE_E || ret == ASN_BEFORE_DATE_E) + why = certificate_expired; + if (ssl->verifyCallback) { + int ok; + + store->error = ret; + store->error_depth = totalCerts; + store->discardSessionCerts = 0; + store->domain = domain; + store->userCtx = ssl->verifyCbCtx; + store->certs = certs; + store->totalCerts = totalCerts; +#ifdef KEEP_PEER_CERT + store->current_cert = &ssl->peerCert; +#else + store->current_cert = NULL; +#endif +#if defined(HAVE_EX_DATA) || defined(HAVE_FORTRESS) + store->ex_data = ssl; +#endif + ok = ssl->verifyCallback(0, store); + if (ok) { + WOLFSSL_MSG("Verify callback overriding error!"); + ret = 0; + } + #ifdef SESSION_CERTS + if (store->discardSessionCerts) { + WOLFSSL_MSG("Verify callback requested discard sess certs"); + ssl->session.chain.count = 0; + } + #endif + } + if (ret != 0) { + SendAlert(ssl, alert_fatal, why); /* try to send */ + ssl->options.isClosed = 1; + } + } + ssl->error = ret; + } +#ifdef WOLFSSL_ALWAYS_VERIFY_CB + else { + if (ssl->verifyCallback) { + int ok; + + store->error = ret; +#ifdef WOLFSSL_WPAS + store->error_depth = 0; +#else + store->error_depth = totalCerts; +#endif + store->discardSessionCerts = 0; + store->domain = domain; + store->userCtx = ssl->verifyCbCtx; + store->certs = certs; + store->totalCerts = totalCerts; +#ifdef KEEP_PEER_CERT + store->current_cert = &ssl->peerCert; +#endif + store->ex_data = ssl; + + ok = ssl->verifyCallback(1, store); + if (!ok) { + WOLFSSL_MSG("Verify callback overriding valid certificate!"); + ret = -1; + SendAlert(ssl, alert_fatal, bad_certificate); + ssl->options.isClosed = 1; + } + #ifdef SESSION_CERTS + if (store->discardSessionCerts) { + WOLFSSL_MSG("Verify callback requested discard sess certs"); + ssl->session.chain.count = 0; + } + #endif + } + } +#endif + + if (ssl->options.verifyNone && + (ret == CRL_MISSING || ret == CRL_CERT_REVOKED)) { + WOLFSSL_MSG("Ignoring CRL problem based on verify setting"); + ret = ssl->error = 0; + } + + if (ret == 0 && ssl->options.side == WOLFSSL_CLIENT_END) + ssl->options.serverState = SERVER_CERT_COMPLETE; + +#ifdef WOLFSSL_SMALL_STACK + XFREE(store, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(domain, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + +/* Parse and handle a TLS v1.3 Certificate message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of Certificate. + * On exit, the index of byte after the Certificate message. + * totalSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13Certificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, + word32 totalSz) +{ + int ret; + word32 listSz; + word32 begin = *inOutIdx; + int totalCerts = 0; /* number of certs in certs buffer */ + buffer certs[MAX_CHAIN_DEPTH]; + buffer exts[MAX_CHAIN_DEPTH]; + byte ctxSz; + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("Certificate", &ssl->timeoutInfo); + #endif + + /* Certificate Request Context */ + if ((*inOutIdx - begin) + OPAQUE8_LEN > totalSz) + return BUFFER_ERROR; + ctxSz = *(input + *inOutIdx); + (*inOutIdx)++; + if ((*inOutIdx - begin) + ctxSz > totalSz) + return BUFFER_ERROR; +#ifndef NO_WOLFSSL_CLIENT + /* Must be empty when received from server. */ + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (ctxSz != 0) { + return INVALID_CERT_CTX_E; + } + } +#endif +#ifndef NO_WOLFSSL_SERVER + /* Must contain value sent in request when received from client. */ + if (ssl->options.side == WOLFSSL_SERVER_END) { + if (ssl->clientCertCtx.length != ctxSz || + XMEMCMP(ssl->clientCertCtx.buffer, input + *inOutIdx, ctxSz) != 0) { + return INVALID_CERT_CTX_E; + } + } +#endif + *inOutIdx += ctxSz; + + /* Certificate List */ + if ((*inOutIdx - begin) + OPAQUE24_LEN > totalSz) + return BUFFER_ERROR; + c24to32(input + *inOutIdx, &listSz); + *inOutIdx += OPAQUE24_LEN; + if (listSz > MAX_RECORD_SIZE) + return BUFFER_E; + if ((*inOutIdx - begin) + listSz != totalSz) + return BUFFER_ERROR; + + WOLFSSL_MSG("Loading peer's cert chain"); + /* Put the indeces into the buffer of the certificates and extensions into + * list so they can be verified top down as they were sent bottom up. + */ + while (listSz) { + word32 certSz; + word16 extSz; + + if (totalCerts >= MAX_CHAIN_DEPTH) + return MAX_CHAIN_ERROR; + + /* Certificate Data */ + if ((*inOutIdx - begin) + OPAQUE24_LEN > totalSz) + return BUFFER_ERROR; + c24to32(input + *inOutIdx, &certSz); + *inOutIdx += OPAQUE24_LEN; + if ((*inOutIdx - begin) + certSz > totalSz) + return BUFFER_ERROR; + /* Store certificate data info for later processing. */ + certs[totalCerts].length = certSz; + certs[totalCerts].buffer = input + *inOutIdx; + +#ifdef SESSION_CERTS + if (ssl->session.chain.count < MAX_CHAIN_DEPTH && + certSz < MAX_X509_SIZE) { + ssl->session.chain.certs[ssl->session.chain.count].length = certSz; + XMEMCPY(ssl->session.chain.certs[ssl->session.chain.count].buffer, + input + *inOutIdx, certSz); + ssl->session.chain.count++; + } else { + WOLFSSL_MSG("Couldn't store chain cert for session"); + } +#endif + + *inOutIdx += certSz; + listSz -= certSz + CERT_HEADER_SZ; + + /* Extensions */ + if ((*inOutIdx - begin) + OPAQUE16_LEN > totalSz) + return BUFFER_ERROR; + ato16(input + *inOutIdx, &extSz); + *inOutIdx += OPAQUE16_LEN; + if ((*inOutIdx - begin) + extSz > totalSz) + return BUFFER_ERROR; + /* Store extension data info for later processing. */ + exts[totalCerts].length = extSz; + exts[totalCerts].buffer = input + *inOutIdx; + *inOutIdx += extSz; + listSz -= extSz + OPAQUE16_LEN; + + totalCerts++; + WOLFSSL_MSG(" Put another cert into chain"); + } + + ret = ProcessPeerCerts(ssl, certs, exts, totalCerts); + if (ret != 0) + return ret; + + /* Always encrypted. */ + *inOutIdx += ssl->keys.padSz; + + return 0; +} + +#if !defined(NO_RSA) || defined(HAVE_ECC) +/* Parse and handle a TLS v1.3 CertificateVerify message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of + * CertificateVerify. + * On exit, the index of byte after the CertificateVerify message. + * totalSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, + word32* inOutIdx, word32 totalSz) +{ + int ret = 0; + byte* output = NULL; + word32 sendSz = 0; + word16 sz = 0; + byte hashAlgo = sha_mac; + byte sigAlgo = anonymous_sa_algo; + word32 idx = *inOutIdx, begin = *inOutIdx; + buffer* sig = &ssl->buffers.sig; + + WOLFSSL_ENTER("DoTls13CertificateVerify"); + + (void)output; + (void)sendSz; + + #ifdef WOLFSSL_ASYNC_CRYPT + ret = wolfAsync_EventPop(&ssl->event, WOLF_EVENT_TYPE_ASYNC_ANY); + if (ret != WC_NOT_PENDING_E) { + WOLF_EVENT_TYPE eType = ssl->event.type; + + /* Clear event */ + XMEMSET(&ssl->event, 0, sizeof(ssl->event)); + + /* Check for error */ + if (ret < 0) { + goto exit_dcv; + } + else { + /* Restore variables needed for async */ + output = ssl->async.output; + sendSz = ssl->async.sendSz; + idx = ssl->async.idx; + sz = ssl->async.length; + sigAlgo = ssl->async.sigAlgo; + hashAlgo = ssl->async.hashAlgo; + + /* Advance key share state if not wolfCrypt */ + if (eType == WOLF_EVENT_TYPE_ASYNC_WOLFSSL) { + ssl->options.asyncState++; + } + } + } + else + #endif + { + /* Reset state */ + ret = 0; + ssl->options.asyncState = TLS_ASYNC_BEGIN; + } + + switch(ssl->options.asyncState) + { + case TLS_ASYNC_BEGIN: + { + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("CertificateVerify", + &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("CertificateVerify", + &ssl->timeoutInfo); + #endif + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_BUILD; + } /* case TLS_ASYNC_BEGIN */ + + case TLS_ASYNC_BUILD: + { + /* Signature algorithm. */ + if ((idx - begin) + ENUM_LEN + ENUM_LEN > totalSz) { + ERROR_OUT(BUFFER_ERROR, exit_dcv); + } + DecodeSigAlg(input + idx, &hashAlgo, &sigAlgo); + idx += OPAQUE16_LEN; + /* TODO: [TLS13] was it in SignatureAlgorithms extension? */ + + /* Signature length. */ + if ((idx - begin) + OPAQUE16_LEN > totalSz) { + ERROR_OUT(BUFFER_ERROR, exit_dcv); + } + ato16(input + idx, &sz); + idx += OPAQUE16_LEN; + + /* Signature data. */ + if ((idx - begin) + sz > totalSz || sz > ENCRYPT_LEN) { + ERROR_OUT(BUFFER_ERROR, exit_dcv); + } + + /* Check for public key of required type. */ + if (sigAlgo == ecc_dsa_sa_algo && !ssl->peerEccDsaKeyPresent) { + WOLFSSL_MSG("Oops, peer sent ECC key but not in verify"); + } + if (sigAlgo == rsa_sa_algo && + (ssl->peerRsaKey == NULL || !ssl->peerRsaKeyPresent)) { + WOLFSSL_MSG("Oops, peer sent RSA key but not in verify"); + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_DO; + } /* case TLS_ASYNC_BUILD */ + + case TLS_ASYNC_DO: + { + sig->buffer = XMALLOC(sz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (sig->buffer == NULL) + ERROR_OUT(MEMORY_E, exit_dcv); + sig->length = sz; + XMEMCPY(sig->buffer, input + idx, sz); + + #ifndef NO_RSA + if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent) { + WOLFSSL_MSG("Doing RSA peer cert verify"); + + ret = RsaVerify(ssl, sig->buffer, sig->length, &output, + ssl->peerRsaKey, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.peerRsaKey.buffer, + ssl->buffers.peerRsaKey.length, + ssl->RsaVerifyCtx + #else + NULL, 0, NULL + #endif + ); + if (ret >= 0) { + sendSz = ret; + ret = 0; + } + } + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + if (ssl->peerEccDsaKeyPresent) { + byte sigData[MAX_SIG_DATA_SZ]; + word16 sigDataSz; + + WOLFSSL_MSG("Doing ECC peer cert verify"); + + CreateSigData(ssl, sigData, &sigDataSz, 1); + + ret = EccVerify(ssl, input + idx, sz, sigData, sigDataSz, + ssl->peerEccDsaKey, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.peerEccDsaKey.buffer, + ssl->buffers.peerEccDsaKey.length, + ssl->EccVerifyCtx + #else + NULL, 0, NULL + #endif + ); + } + #endif /* HAVE_ECC */ + + /* Check for error */ + if (ret != 0) { + goto exit_dcv; + } + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_VERIFY; + } /* case TLS_ASYNC_DO */ + + case TLS_ASYNC_VERIFY: + { + #ifndef NO_RSA + if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) { + ret = CheckRSASignature(ssl, hashAlgo, output, sendSz); + if (ret != 0) + goto exit_dcv; + } + #endif /* !NO_RSA */ + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_FINALIZE; + } /* case TLS_ASYNC_VERIFY */ + + case TLS_ASYNC_FINALIZE: + { + ssl->options.havePeerVerify = 1; + + /* Set final index */ + idx += sz; + *inOutIdx = idx; + + /* Encryption is always on: add padding */ + *inOutIdx += ssl->keys.padSz; + + /* Advance state and proceed */ + ssl->options.asyncState = TLS_ASYNC_END; + } /* case TLS_ASYNC_FINALIZE */ + + case TLS_ASYNC_END: + { + break; + } + default: + ret = INPUT_CASE_ERROR; + } /* switch(ssl->options.asyncState) */ + +exit_dcv: + + WOLFSSL_LEAVE("DoTls13CertificateVerify", ret); + + /* Handle cleanup for stack variables here */ + + + #ifdef WOLFSSL_ASYNC_CRYPT + /* Handle WC_PENDING_E */ + if (ret == WC_PENDING_E) { + /* Store variables needed for async */ + XMEMSET(&ssl->async, 0, sizeof(ssl->async)); + ssl->async.output = output; + ssl->async.sendSz = sendSz; + ssl->async.idx = idx; + ssl->async.length = sz; + ssl->async.sigAlgo = sigAlgo; + ssl->async.hashAlgo = hashAlgo; + + /* Mark message as not recevied so it can process again */ + ssl->msgsReceived.got_certificate_verify = 0; + + /* Push event to queue */ + ret = wolfAsync_EventQueuePush(&ssl->ctx->event_queue, &ssl->event); + if (ret == 0) { + return WC_PENDING_E; + } + } + #endif /* WOLFSSL_ASYNC_CRYPT */ + + /* Final cleanup */ + FreeKeyExchange(ssl); + + return ret; +} +#endif /* !NO_RSA || HAVE_ECC */ + +/* Parse and handle a TLS v1.3 Finished message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of Finished. + * On exit, the index of byte after the Finished message and padding. + * size Length of message data. + * totalSz Length of remaining data in the message buffer. + * sniff Indicates whether we are sniffing packets. + * returns 0 on success and otherwise failure. + */ +static int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 size, word32 totalSz, int sniff) +{ + int ret; + word32 finishedSz = 0; + byte* secret; + byte mac[MAX_DIGEST_SIZE]; + + /* check against totalSz */ + if (*inOutIdx + size + ssl->keys.padSz > totalSz) + return BUFFER_E; + + if (ssl->options.side == WOLFSSL_CLIENT_END) { + /* All the handshake messages have been received to calculate + * client and server finished keys. + */ + ret = DeriveFinishedSecret(ssl, ssl->arrays->clientSecret, + ssl->keys.client_write_MAC_secret); + if (ret != 0) + return ret; + + ret = DeriveFinishedSecret(ssl, ssl->arrays->serverSecret, + ssl->keys.server_write_MAC_secret); + if (ret != 0) + return ret; + + secret = ssl->keys.server_write_MAC_secret; + } + else + secret = ssl->keys.client_write_MAC_secret; + finishedSz = BuildTls13HandshakeHmac(ssl, secret, mac); + if (size != finishedSz) + return BUFFER_ERROR; + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo); + #endif + + if (sniff == NO_SNIFF) { + /* Actually check verify data. */ + if (XMEMCMP(input + *inOutIdx, mac, size) != 0){ + WOLFSSL_MSG("Verify finished error on hashes"); + return VERIFY_FINISHED_ERROR; + } + } + + /* Force input exhaustion at ProcessReply by consuming padSz. */ + *inOutIdx += size + ssl->keys.padSz; + + if (ssl->options.side == WOLFSSL_SERVER_END) { + /* Setup keys for application data messages from client. */ + if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) + return ret; + } + +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_CLIENT_END) { + ssl->options.serverState = SERVER_FINISHED_COMPLETE; + if (!ssl->options.resuming) { + ssl->options.handShakeState = HANDSHAKE_DONE; + ssl->options.handShakeDone = 1; + } + } +#endif +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_SERVER_END) { + ssl->options.clientState = CLIENT_FINISHED_COMPLETE; + ssl->options.handShakeState = HANDSHAKE_DONE; + ssl->options.handShakeDone = 1; + } +#endif + + return 0; +} +#endif /* NO_CERTS */ + +/* Send the TLS v1.3 Finished message. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +int SendTls13Finished(WOLFSSL* ssl) +{ + int sendSz; + int finishedSz = ssl->specs.hash_size; + byte* input; + byte* output; + int ret; + int headerSz = HANDSHAKE_HEADER_SZ; + int outputSz; + byte* secret; + + outputSz = MAX_DIGEST_SIZE + DTLS_HANDSHAKE_HEADER_SZ + MAX_MSG_EXTRA; + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, outputSz)) != 0) + return ret; + + /* get output buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + input = output + RECORD_HEADER_SZ; + + AddTls13HandShakeHeader(input, finishedSz, 0, finishedSz, finished, ssl); + + /* make finished hashes */ + if (ssl->options.side == WOLFSSL_CLIENT_END) + secret = ssl->keys.client_write_MAC_secret; + else { + /* All the handshake messages have been done to calculate client and + * server finished keys. + */ + ret = DeriveFinishedSecret(ssl, ssl->arrays->clientSecret, + ssl->keys.client_write_MAC_secret); + if (ret != 0) + return ret; + + ret = DeriveFinishedSecret(ssl, ssl->arrays->serverSecret, + ssl->keys.server_write_MAC_secret); + if (ret != 0) + return ret; + + secret = ssl->keys.server_write_MAC_secret; + } + BuildTls13HandshakeHmac(ssl, secret, &input[headerSz]); + + /* This message is always encrypted. */ + sendSz = BuildTls13Message(ssl, output, outputSz, input, + headerSz + finishedSz, handshake, 1, 0); + if (sendSz < 0) + return BUILD_MSG_ERROR; + + if (!ssl->options.resuming) { +#ifndef NO_SESSION_CACHE + AddSession(ssl); /* just try */ +#endif + } + else { + if (ssl->options.side == WOLFSSL_CLIENT_END) { + ssl->options.handShakeState = HANDSHAKE_DONE; + ssl->options.handShakeDone = 1; + } + } + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("Finished", &ssl->timeoutInfo, output, sendSz, + ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + + ret = SendBuffered(ssl); + if (ret != 0) + return ret; + + if (ssl->options.side == WOLFSSL_SERVER_END) { + /* Can send application data now. */ + if ((ret = DeriveMasterSecret(ssl)) != 0) + return ret; + if ((ret = DeriveTls13Keys(ssl, traffic_key, + ENCRYPT_AND_DECRYPT_SIDE)) != 0) + return ret; + if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) + return ret; + } + + if (ssl->options.side == WOLFSSL_CLIENT_END) { + /* Setup keys for application data messages. */ + if ((ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE)) != 0) + return ret; + +#ifndef NO_PSK + ret = DeriveResumptionSecret(ssl, ssl->session.masterSecret); +#endif + } + + return ret; +} + +/* Send the TLS v1.3 KeyUpdate message. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +static int SendTls13KeyUpdate(WOLFSSL* ssl) +{ + int sendSz; + byte* input; + byte* output; + int ret; + int headerSz = HANDSHAKE_HEADER_SZ; + int outputSz; + word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + outputSz = OPAQUE8_LEN + MAX_MSG_EXTRA; + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, outputSz)) != 0) + return ret; + + /* get output buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + input = output + RECORD_HEADER_SZ; + + AddTls13Headers(output, OPAQUE8_LEN, key_update, ssl); + + /* If: + * 1. I haven't sent a KeyUpdate requesting a response and + * 2. This isn't responding to peer KeyUpdate requiring a response then, + * I want a response. + */ + ssl->keys.updateResponseReq = output[i++] = + !ssl->keys.updateResponseReq && !ssl->keys.keyUpdateRespond; + /* Sent response, no longer need to respond. */ + ssl->keys.keyUpdateRespond = 0; + + /* This message is always encrypted. */ + sendSz = BuildTls13Message(ssl, output, outputSz, input, + headerSz + OPAQUE8_LEN, handshake, 0, 0); + if (sendSz < 0) + return BUILD_MSG_ERROR; + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("KeyUpdate", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("KeyUpdate", &ssl->timeoutInfo, output, sendSz, + ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + + ret = SendBuffered(ssl); + if (ret != 0 && ret != WANT_WRITE) + return ret; + + /* Future traffic uses new encryption keys. */ + if ((ret = DeriveTls13Keys(ssl, update_traffic_key, ENCRYPT_SIDE_ONLY)) + != 0) + return ret; + if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) + return ret; + + return ret; +} + +/* Parse and handle a TLS v1.3 KeyUpdate message. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of Finished. + * On exit, the index of byte after the Finished message and padding. + * totalSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13KeyUpdate(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 totalSz) +{ + int ret; + word32 i = *inOutIdx; + + /* check against totalSz */ + if (OPAQUE8_LEN != totalSz) + return BUFFER_E; + + switch (input[i]) { + case update_not_requested: + /* This message in response to any oustanding request. */ + ssl->keys.keyUpdateRespond = 0; + ssl->keys.updateResponseReq = 0; + break; + case update_requested: + /* New key update requiring a response. */ + ssl->keys.keyUpdateRespond = 1; + break; + default: + return INVALID_PARAMETER; + break; + } + + /* Move index to byte after message. */ + *inOutIdx += totalSz; + /* Always encrypted. */ + *inOutIdx += ssl->keys.padSz; + + /* Future traffic uses new decryption keys. */ + if ((ret = DeriveTls13Keys(ssl, update_traffic_key, DECRYPT_SIDE_ONLY)) != 0) + return ret; + if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) + return ret; + + if (ssl->keys.keyUpdateRespond) + return SendTls13KeyUpdate(ssl); + return 0; +} + +#ifndef NO_WOLFSSL_CLIENT +/* Handle a New Session Ticket handshake message. + * Message contains the information required to perform resumption. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the message buffer of Finished. + * On exit, the index of byte after the Finished message and padding. + * size The length of the current handshake message. + * retuns 0 on success, otherwise failure. + */ +static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, word32 size) +{ +#ifdef HAVE_SESSION_TICKET + word32 begin = *inOutIdx; + word32 lifetime; + word32 ageAdd; + word16 length; + + /* Lifetime hint. */ + if ((*inOutIdx - begin) + SESSION_HINT_SZ > size) + return BUFFER_ERROR; + ato32(input + *inOutIdx, &lifetime); + *inOutIdx += SESSION_HINT_SZ; + if (lifetime > MAX_LIFETIME) + return SERVER_HINT_ERROR; + + /* Age add. */ + if ((*inOutIdx - begin) + SESSION_ADD_SZ > size) + return BUFFER_ERROR; + ato32(input + *inOutIdx, &ageAdd); + *inOutIdx += SESSION_ADD_SZ; + + /* Ticket length. */ + if ((*inOutIdx - begin) + LENGTH_SZ > size) + return BUFFER_ERROR; + ato16(input + *inOutIdx, &length); + *inOutIdx += LENGTH_SZ; + if ((*inOutIdx - begin) + length > size) + return BUFFER_ERROR; + + /* Free old dynamic ticket if we already had one. */ + if (ssl->session.isDynamic) { + XFREE(ssl->session.ticket, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); + /* Reset back to static by default. */ + ssl->session.ticket = NULL; + ssl->session.isDynamic = 0; + ssl->session.ticket = ssl->session.staticTicket; + } + /* Use dynamic ticket if required.*/ + if (length > sizeof(ssl->session.staticTicket)) { + ssl->session.ticket = (byte*)XMALLOC(length, ssl->heap, + DYNAMIC_TYPE_SESSION_TICK); + if (ssl->session.ticket == NULL) + return MEMORY_E; + ssl->session.isDynamic = 1; + } + + /* Copy in ticket data (server identity). */ + XMEMCPY(ssl->session.ticket, input + *inOutIdx, length); + *inOutIdx += length; + ssl->timeout = lifetime; + ssl->session.ticketLen = length; + ssl->session.timeout = lifetime; + ssl->session.ticketAdd = ageAdd; + ssl->session.ticketSeen = TimeNowInMilliseconds(); + if (ssl->session_ticket_cb != NULL) { + ssl->session_ticket_cb(ssl, ssl->session.ticket, + ssl->session.ticketLen, + ssl->session_ticket_ctx); + } + ssl->options.haveSessionId = 1; + XMEMCPY(ssl->arrays->sessionID, ssl->session.ticket + length - ID_LEN, + ID_LEN); + ssl->session.cipherSuite0 = ssl->options.cipherSuite0; + ssl->session.cipherSuite = ssl->options.cipherSuite; + #ifndef NO_SESSION_CACHE + AddSession(ssl); + #endif + + /* No extension support - skip over extensions. */ + if ((*inOutIdx - begin) + EXTS_SZ > size) + return BUFFER_ERROR; + ato16(input + *inOutIdx, &length); + *inOutIdx += EXTS_SZ; + if ((*inOutIdx - begin) + length != size) + return BUFFER_ERROR; + *inOutIdx += length; + + /* Always encrypted. */ + *inOutIdx += ssl->keys.padSz; + + ssl->expect_session_ticket = 0; +#else + (void)ssl; + (void)input; + *inOutIdx += size + ssl->keys.padSz; +#endif /* HAVE_SESSION_TICKET */ + + return 0; +} +#endif /* NO_WOLFSSL_CLIENT */ + +#ifndef NO_WOLFSSL_SERVER + #ifdef HAVE_SESSION_TICKET +/* Send New Session Ticket handshake message. + * Message contains the information required to perform resumption. + * + * ssl The SSL/TLS object. + * retuns 0 on success, otherwise failure. + */ +int SendTls13NewSessionTicket(WOLFSSL* ssl) +{ + byte* output; + int ret; + int sendSz; + word32 length; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + if (!ssl->options.noTicketTls13) { + ret = CreateTicket(ssl); + if (ret != 0) return ret; + } + + /* Lifetime | Age Add | Ticket | Extensions */ + length = SESSION_HINT_SZ + SESSION_ADD_SZ + LENGTH_SZ + + ssl->session.ticketLen + EXTS_SZ; + sendSz = idx + length + MAX_MSG_EXTRA; + + /* Check buffers are big enough and grow if needed. */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* Get position in output buffer to write new message to. */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* Put the record and handshake headers on. */ + AddTls13Headers(output, length, session_ticket, ssl); + + /* Lifetime hint */ + c32toa(ssl->ctx->ticketHint, output + idx); + idx += SESSION_HINT_SZ; + /* Age add - obfuscator */ + c32toa(ssl->session.ticketAdd, output + idx); + idx += SESSION_ADD_SZ; + + /* length */ + c16toa(ssl->session.ticketLen, output + idx); + idx += LENGTH_SZ; + /* ticket */ + XMEMCPY(output + idx, ssl->session.ticket, ssl->session.ticketLen); + idx += ssl->session.ticketLen; + + /* No extension support - empty extensions. */ + c16toa(0, output + idx); + idx += EXTS_SZ; + + ssl->options.haveSessionId = 1; + + #ifndef NO_SESSION_CACHE + AddSession(ssl); + #endif + + /* This message is always encrypted. */ + sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ, + idx - RECORD_HEADER_SZ, handshake, 0, 0); + if (sendSz < 0) + return sendSz; + + ssl->buffers.outputBuffer.length += sendSz; + + return SendBuffered(ssl); +} + #endif /* HAVE_SESSION_TICKET */ +#endif /* NO_WOLFSSL_SERVER */ + +/* Make sure no duplicates, no fast forward, or other problems + * + * ssl The SSL/TLS object. + * type Type of handshake message received. + * returns 0 on success, otherwise failure. + */ +static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) +{ + /* verify not a duplicate, mark received, check state */ + switch (type) { + +#ifndef NO_WOLFSSL_SERVER + case client_hello: + if (ssl->msgsReceived.got_client_hello == 2) { + WOLFSSL_MSG("Too many ClientHello received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_client_hello++; + + break; +#endif + +#ifndef NO_WOLFSSL_CLIENT + case server_hello: + if (ssl->msgsReceived.got_server_hello) { + WOLFSSL_MSG("Duplicate ServerHello received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_server_hello = 1; + + break; +#endif + +#ifndef NO_WOLFSSL_CLIENT + case session_ticket: + if (ssl->msgsReceived.got_session_ticket) { + WOLFSSL_MSG("Duplicate SessionTicket received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_session_ticket = 1; + + break; +#endif + +#ifndef NO_WOLFSSL_CLIENT + case hello_retry_request: + if (ssl->msgsReceived.got_hello_retry_request) { + WOLFSSL_MSG("Duplicate HelloRetryRequest received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_hello_retry_request = 1; + + break; +#endif + +#ifndef NO_WOLFSSL_CLIENT + case encrypted_extensions: + if (ssl->msgsReceived.got_encrypted_extensions) { + WOLFSSL_MSG("Duplicate EncryptedExtensions received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_encrypted_extensions = 1; + + break; +#endif + + case certificate: + 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: + if (ssl->msgsReceived.got_certificate_request) { + WOLFSSL_MSG("Duplicate CertificateRequest received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_certificate_request = 1; + + break; +#endif + + case certificate_verify: + 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: + if (ssl->msgsReceived.got_finished) { + WOLFSSL_MSG("Duplicate Finished received"); + return DUPLICATE_MSG_E; + } + ssl->msgsReceived.got_finished = 1; + + break; + + case key_update: + if (!ssl->msgsReceived.got_finished) { + WOLFSSL_MSG("No KeyUpdate before Finished"); + return OUT_OF_ORDER_E; + } + break; + + default: + WOLFSSL_MSG("Unknown message type"); + return SANITY_MSG_E; + } + + return 0; +} + +/* Handle a type of handshake message that has been received. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the buffer of the current message. + * On exit, the index into the buffer of the next message. + * size The length of the current handshake message. + * totalSz Length of remaining data in the message buffer. + * returns 0 on success and otherwise failure. + */ +int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, + byte type, word32 size, word32 totalSz) +{ + int ret = 0; + (void)totalSz; + word32 inIdx = *inOutIdx; + + WOLFSSL_ENTER("DoTls13HandShakeMsgType"); + + /* make sure can read the message */ + if (*inOutIdx + size > totalSz) + return INCOMPLETE_DATA; + + /* sanity check msg received */ + if ( (ret = SanityCheckTls13MsgReceived(ssl, type)) != 0) { + WOLFSSL_MSG("Sanity Check on handshake message type received failed"); + return ret; + } + +#ifdef WOLFSSL_CALLBACKS + /* add name later, add on record and handshake header part back on */ + if (ssl->toInfoOn) { + int add = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + AddPacketInfo(0, &ssl->timeoutInfo, input + *inOutIdx - add, + size + add, ssl->heap); + AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo); + } +#endif + + if (ssl->options.handShakeState == HANDSHAKE_DONE && + type != session_ticket && type != certificate_request && + type != key_update) { + WOLFSSL_MSG("HandShake message after handshake complete"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + if (ssl->options.side == WOLFSSL_CLIENT_END && !ssl->options.dtls && + ssl->options.serverState == NULL_STATE && + type != server_hello && type != hello_retry_request) { + WOLFSSL_MSG("First server message not server hello"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->options.dtls && + type == server_hello_done && + ssl->options.serverState < SERVER_HELLO_COMPLETE) { + WOLFSSL_MSG("Server hello done received before server hello in DTLS"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->options.clientState == NULL_STATE && type != client_hello) { + WOLFSSL_MSG("First client message not client hello"); + SendAlert(ssl, alert_fatal, unexpected_message); + return OUT_OF_ORDER_E; + } + + /* above checks handshake state */ + switch (type) { + +#ifndef NO_WOLFSSL_CLIENT + case hello_retry_request: + WOLFSSL_MSG("processing hello rety request"); + ret = DoTls13HelloRetryRequest(ssl, input, inOutIdx, size); + break; + + 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); + break; + + case encrypted_extensions: + WOLFSSL_MSG("processing encrypted extensions"); + ret = DoTls13EncryptedExtensions(ssl, input, inOutIdx, size); + break; +#endif /* !NO_WOLFSSL_CLIENT */ + +#ifndef NO_CERTS + case certificate: + WOLFSSL_MSG("processing certificate"); + ret = DoTls13Certificate(ssl, input, inOutIdx, size); + break; +#endif + +#if !defined(NO_RSA) || defined(HAVE_ECC) + case certificate_verify: + WOLFSSL_MSG("processing certificate verify"); + ret = DoTls13CertificateVerify(ssl, input, inOutIdx, size); + break; +#endif /* !NO_RSA || HAVE_ECC */ + + case finished: + WOLFSSL_MSG("processing finished"); + ret = DoTls13Finished(ssl, input, inOutIdx, size, totalSz, NO_SNIFF); + break; + + case key_update: + WOLFSSL_MSG("processing finished"); + 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; + break; + } + + if (ret == 0 && type != client_hello && type != session_ticket && + type != key_update && ssl->error != WC_PENDING_E) { + 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) { + SendAlert(ssl, alert_fatal, illegal_parameter); + } + + if (ssl->options.tls1_3) { + if (type == server_hello && ssl->options.side == WOLFSSL_CLIENT_END) { + if ((ret = DeriveEarlySecret(ssl)) != 0) + return ret; + if ((ret = DeriveHandshakeSecret(ssl)) != 0) + return ret; + if ((ret = DeriveTls13Keys(ssl, handshake_key, + ENCRYPT_AND_DECRYPT_SIDE)) != 0) + return ret; + + /* setup decrypt keys for following messages */ + if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) + return ret; + if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) + return ret; + } + + if (type == finished && ssl->options.side == WOLFSSL_CLIENT_END) { + if ((ret = DeriveMasterSecret(ssl)) != 0) + return ret; + if ((ret = DeriveTls13Keys(ssl, traffic_key, + ENCRYPT_AND_DECRYPT_SIDE)) != 0) + return ret; + } + +#ifndef NO_PSK + if (type == finished && ssl->options.side == WOLFSSL_SERVER_END) + DeriveResumptionSecret(ssl, ssl->session.masterSecret); +#endif + } + + /* if async, offset index so this msg will be processed again */ + if (ret == WC_PENDING_E) { + *inOutIdx -= HANDSHAKE_HEADER_SZ; + } + + WOLFSSL_LEAVE("DoTls13HandShakeMsgType()", ret); + return ret; +} + + +/* Handle a handshake message that has been received. + * + * ssl The SSL/TLS object. + * input The message buffer. + * inOutIdx On entry, the index into the buffer of the current message. + * On exit, the index into the buffer of the next message. + * totalSz Length of remaining data in the message buffer. + * returns 0 on success and otherwise failure. + */ +int DoTls13HandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, + word32 totalSz) +{ + int ret = 0; + word32 inputLength; + + WOLFSSL_ENTER("DoTls13HandShakeMsg()"); + + if (ssl->arrays == NULL) { + byte type; + word32 size; + + if (GetHandshakeHeader(ssl,input,inOutIdx,&type, &size, totalSz) != 0) + return PARSE_ERROR; + + return DoTls13HandShakeMsgType(ssl, input, inOutIdx, type, size, + totalSz); + } + + inputLength = ssl->buffers.inputBuffer.length - *inOutIdx; + + /* If there is a pending fragmented handshake message, + * pending message size will be non-zero. */ + if (ssl->arrays->pendingMsgSz == 0) { + byte type; + word32 size; + + if (GetHandshakeHeader(ssl,input, inOutIdx, &type, &size, totalSz) != 0) + return PARSE_ERROR; + + /* Cap the maximum size of a handshake message to something reasonable. + * By default is the maximum size of a certificate message assuming + * nine 2048-bit RSA certificates in the chain. */ + if (size > MAX_HANDSHAKE_SZ) { + WOLFSSL_MSG("Handshake message too large"); + return HANDSHAKE_SIZE_ERROR; + } + + /* size is the size of the certificate message payload */ + if (inputLength - HANDSHAKE_HEADER_SZ < size) { + ssl->arrays->pendingMsgType = type; + ssl->arrays->pendingMsgSz = size + HANDSHAKE_HEADER_SZ; + ssl->arrays->pendingMsg = (byte*)XMALLOC(size + HANDSHAKE_HEADER_SZ, + ssl->heap, + DYNAMIC_TYPE_ARRAYS); + if (ssl->arrays->pendingMsg == NULL) + return MEMORY_E; + XMEMCPY(ssl->arrays->pendingMsg, + input + *inOutIdx - HANDSHAKE_HEADER_SZ, + inputLength); + ssl->arrays->pendingMsgOffset = inputLength; + *inOutIdx += inputLength - HANDSHAKE_HEADER_SZ; + return 0; + } + + ret = DoTls13HandShakeMsgType(ssl, input, inOutIdx, type, size, + totalSz); + } + else { + if (inputLength + ssl->arrays->pendingMsgOffset > + ssl->arrays->pendingMsgSz) { + return BUFFER_ERROR; + } + + XMEMCPY(ssl->arrays->pendingMsg + ssl->arrays->pendingMsgOffset, + input + *inOutIdx, inputLength); + ssl->arrays->pendingMsgOffset += inputLength; + *inOutIdx += inputLength; + + if (ssl->arrays->pendingMsgOffset == ssl->arrays->pendingMsgSz) + { + word32 idx = 0; + ret = DoTls13HandShakeMsgType(ssl, + ssl->arrays->pendingMsg + HANDSHAKE_HEADER_SZ, + &idx, ssl->arrays->pendingMsgType, + ssl->arrays->pendingMsgSz - HANDSHAKE_HEADER_SZ, + ssl->arrays->pendingMsgSz); + XFREE(ssl->arrays->pendingMsg, ssl->heap, DYNAMIC_TYPE_ARRAYS); + ssl->arrays->pendingMsg = NULL; + ssl->arrays->pendingMsgSz = 0; + } + } + + WOLFSSL_LEAVE("DoTls13HandShakeMsg()", ret); + return ret; +} + +/* The client connecting to the server. + * The protocol version is expecting to be TLS v1.3. + * If the server downgrades, and older versions of the protocol are compiled + * in, the client will fallback to wolfSSL_connect(). + * Please see note at top of README if you get an error from connect. + * + * ssl The SSL/TLS object. + * returns SSL_SUCCESS on successful handshake, SSL_FATAL_ERROR when + * unrecoverable error occurs and 0 otherwise. + * For more error information use wolfSSL_get_error(). + */ +int wolfSSL_connect_TLSv13(WOLFSSL* ssl) +{ + int neededState; + + WOLFSSL_ENTER("wolfSSL_connect_TLSv13()"); + + #ifdef HAVE_ERRNO_H + errno = 0; + #endif + + if (ssl->options.side != WOLFSSL_CLIENT_END) { + WOLFSSL_ERROR(ssl->error = SIDE_ERROR); + return SSL_FATAL_ERROR; + } + + if (ssl->buffers.outputBuffer.length > 0) { + if ((ssl->error = SendBuffered(ssl)) == 0) { + /* fragOffset is non-zero when sending fragments. On the last + * fragment, fragOffset is zero again, and the state can be + * advanced. */ + if (ssl->fragOffset == 0) { + ssl->options.connectState++; + WOLFSSL_MSG("connect state: " + "Advanced from last buffered fragment send"); + } + else { + WOLFSSL_MSG("connect state: " + "Not advanced, more fragments to send"); + } + } + else { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } + + switch (ssl->options.connectState) { + + case CONNECT_BEGIN: + /* Always send client hello first. */ + if ((ssl->error = SendTls13ClientHello(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + + ssl->options.connectState = CLIENT_HELLO_SENT; + WOLFSSL_MSG("connect state: CLIENT_HELLO_SENT"); + + 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) { + if ((ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_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; + WOLFSSL_MSG("connect state: HELLO_AGAIN"); + case HELLO_AGAIN: + if (ssl->options.certOnly) + return SSL_SUCCESS; + + if (!ssl->options.tls1_3) + return wolfSSL_connect(ssl); + + if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) { + ssl->options.serverState = NULL_STATE; + /* Try again with different security parameters. */ + if ((ssl->error = SendTls13ClientHello(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } + + ssl->options.connectState = HELLO_AGAIN_REPLY; + WOLFSSL_MSG("connect state: HELLO_AGAIN_REPLY"); + + case HELLO_AGAIN_REPLY: + if (ssl->options.serverState == NULL_STATE) { + 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 SSL_FATAL_ERROR; + } + /* if resumption failed, reset needed state */ + else if (neededState == SERVER_FINISHED_COMPLETE) { + if (!ssl->options.resuming) + neededState = SERVER_HELLODONE_COMPLETE; + } + } + } + + ssl->options.connectState = FIRST_REPLY_DONE; + WOLFSSL_MSG("connect state: FIRST_REPLY_DONE"); + + case FIRST_REPLY_DONE: + #ifndef NO_CERTS + if (!ssl->options.resuming && ssl->options.sendVerify) { + ssl->error = SendTls13Certificate(ssl); + if (ssl->error != 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: certificate"); + } + #endif + + ssl->options.connectState = FIRST_REPLY_FIRST; + WOLFSSL_MSG("connect state: FIRST_REPLY_FIRST"); + + case FIRST_REPLY_FIRST: + #ifndef NO_CERTS + if (!ssl->options.resuming && ssl->options.sendVerify) { + ssl->error = SendTls13CertificateVerify(ssl); + if (ssl->error != 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: certificate verify"); + } + #endif + + ssl->options.connectState = FIRST_REPLY_SECOND; + WOLFSSL_MSG("connect state: FIRST_REPLY_SECOND"); + + case FIRST_REPLY_SECOND: + if ((ssl->error = SendTls13Finished(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: finished"); + + ssl->options.connectState = FINISHED_DONE; + WOLFSSL_MSG("connect state: FINISHED_DONE"); + + case FINISHED_DONE: +#ifndef NO_HANDSHAKE_DONE_CB + if (ssl->hsDoneCb != NULL) { + int cbret = ssl->hsDoneCb(ssl, ssl->hsDoneCtx); + if (cbret < 0) { + ssl->error = cbret; + WOLFSSL_MSG("HandShake Done Cb don't continue error"); + return SSL_FATAL_ERROR; + } + } +#endif /* NO_HANDSHAKE_DONE_CB */ + + WOLFSSL_LEAVE("SSL_connect()", SSL_SUCCESS); + return SSL_SUCCESS; + + default: + WOLFSSL_MSG("Unknown connect state ERROR"); + return SSL_FATAL_ERROR; /* unknown connect state */ + } +} + +/* Create a key share entry from group. + * Generates a key pair. + * + * ssl The SSL/TLS object. + * group The named group. + * returns 0 on success, otherwise failure. + */ +int wolfSSL_UseKeyShare(WOLFSSL* ssl, word16 group) +{ + int ret = BAD_FUNC_ARG; + + if (ssl == NULL) + return BAD_FUNC_ARG; + + ret = TLSX_KeyShare_Use(ssl, group, 0, NULL, NULL); + if (ret != 0) + return ret; + + return SSL_SUCCESS; +} + +/* Send no key share entries - use HelloRetryRequest to negotiate shared group. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +int wolfSSL_NoKeyShares(WOLFSSL* ssl) +{ + int ret = BAD_FUNC_ARG; + + if (ssl == NULL) + return BAD_FUNC_ARG; + + ret = TLSX_KeyShare_Empty(ssl); + if (ret != 0) + return ret; + + return SSL_SUCCESS; +} + +/* Do not send a ticket after TLS v1.3 handshake for resumption. + * + * ctx The SSL/TLS CTX object. + * returns BAD_FUNC_ARG when ctx is NULL and 0 on success. + */ +int wolfSSL_CTX_no_ticket_TLSv13(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + +#ifdef HAVE_SESSION_TICKET + ctx->noTicketTls13 = 1; +#endif + + return 0; +} + +/* Do not send a ticket after TLS v1.3 handshake for resumption. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL, not using TLS v1.3, or called on + * a client and 0 on success. + */ +int wolfSSL_no_ticket_TLSv13(WOLFSSL* ssl) +{ + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version) || + ssl->options.side == WOLFSSL_CLIENT_END) + return BAD_FUNC_ARG; + +#ifdef HAVE_SESSION_TICKET + ssl->options.noTicketTls13 = 1; +#endif + + return 0; +} + +/* Disallow (EC)DHE key exchange when using pre-shared keys. + * + * ctx The SSL/TLS CTX object. + * returns BAD_FUNC_ARG when ctx is NULL and 0 on success. + */ +int wolfSSL_CTX_no_dhe_psk(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + ctx->noPskDheKe = 1; + + return 0; +} + +/* Disallow (EC)DHE key exchange when using pre-shared keys. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL, or not using TLS v1.3 and 0 on + * success. + */ +int wolfSSL_no_dhe_psk(WOLFSSL* ssl) +{ + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + + ssl->options.noPskDheKe = 1; + + return 0; +} + +/* Update the keys for encryption and decryption. + * If using non-blocking I/O and SSL_ERROR_WANT_WRITE is returned then + * calling wolfSSL_write() will have the message sent when ready. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL, or not using TLS v1.3, + * SSL_ERROR_WANT_WRITE when non-blocking I/O is not ready to write, + * SSL_SUCCESS on success and otherwise failure. + */ +int wolfSSL_update_keys(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + + ret = SendTls13KeyUpdate(ssl); + if (ret == WANT_WRITE) + ret = SSL_ERROR_WANT_WRITE; + else if (ret == 0) + ret = SSL_SUCCESS; + return ret; +} + +/* The server accepting a connection from a client. + * The protocol version is expecting to be TLS v1.3. + * If the client downgrades, and older versions of the protocol are compiled + * in, the server will fallback to wolfSSL_accept(). + * Please see note at top of README if you get an error from accept. + * + * ssl The SSL/TLS object. + * returns SSL_SUCCESS on successful handshake, SSL_FATAL_ERROR when + * unrecoverable error occurs and 0 otherwise. + * For more error information use wolfSSL_get_error(). + */ +int wolfSSL_accept_TLSv13(WOLFSSL* ssl) +{ + word16 havePSK = 0; + word16 haveAnon = 0; + WOLFSSL_ENTER("SSL_accept_TLSv13()"); + +#ifdef HAVE_ERRNO_H + errno = 0; +#endif + +#ifndef NO_PSK + havePSK = ssl->options.havePSK; +#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 SSL_FATAL_ERROR; + } + +#ifndef NO_CERTS + /* in case used set_accept_state after init */ + if (!havePSK && !haveAnon && + (!ssl->buffers.certificate || + !ssl->buffers.certificate->buffer || + !ssl->buffers.key || + !ssl->buffers.key->buffer)) { + WOLFSSL_MSG("accept error: don't have server cert and key"); + ssl->error = NO_PRIVATE_KEY; + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } +#endif +#ifdef WOLFSSL_DTLS + if (ssl->version.major == DTLS_MAJOR) { + ssl->options.dtls = 1; + ssl->options.tls = 1; + ssl->options.tls1_1 = 1; + } +#endif + + if (ssl->buffers.outputBuffer.length > 0) { + if ((ssl->error = SendBuffered(ssl)) == 0) { + /* fragOffset is non-zero when sending fragments. On the last + * fragment, fragOffset is zero again, and the state can be + * advanced. */ + if (ssl->fragOffset == 0) { + ssl->options.acceptState++; + WOLFSSL_MSG("accept state: " + "Advanced from last buffered fragment send"); + } + else { + WOLFSSL_MSG("accept state: " + "Not advanced, more fragments to send"); + } + } + else { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } + + switch (ssl->options.acceptState) { + + case ACCEPT_BEGIN : + /* get response */ + while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) + if ((ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + + ssl->options.acceptState = ACCEPT_CLIENT_HELLO_DONE; + WOLFSSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE"); + + case ACCEPT_CLIENT_HELLO_DONE : + if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) { + if ((ssl->error = SendTls13HelloRetryRequest(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } + ssl->options.acceptState = ACCEPT_HELLO_RETRY_REQUEST_DONE; + WOLFSSL_MSG("accept state ACCEPT_HELLO_RETRY_REQUEST_DONE"); + + case ACCEPT_HELLO_RETRY_REQUEST_DONE : + if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) { + if ( (ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } + ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE; + WOLFSSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE"); + + case ACCEPT_FIRST_REPLY_DONE : + if ((ssl->error = SendTls13ServerHello(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + ssl->options.acceptState = SERVER_HELLO_SENT; + WOLFSSL_MSG("accept state SERVER_HELLO_SENT"); + + case SERVER_HELLO_SENT : + if ((ssl->error = SendTls13EncryptedExtensions(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + ssl->options.acceptState = SERVER_EXTENSIONS_SENT; + WOLFSSL_MSG("accept state SERVER_EXTENSIONS_SENT"); + case SERVER_EXTENSIONS_SENT : +#ifndef NO_CERTS + if (!ssl->options.resuming) + if (ssl->options.verifyPeer) + ssl->error = SendTls13CertificateRequest(ssl); + if (ssl->error != 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } +#endif + ssl->options.acceptState = CERT_REQ_SENT; + WOLFSSL_MSG("accept state CERT_REQ_SENT"); + + case CERT_REQ_SENT : + ssl->options.acceptState = KEY_EXCHANGE_SENT; +#ifndef NO_CERTS + if (!ssl->options.resuming) { + if ((ssl->error = SendTls13Certificate(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } +#endif + ssl->options.acceptState = CERT_SENT; + WOLFSSL_MSG("accept state CERT_SENT"); + + case CERT_SENT : +#ifndef NO_CERTS + if (!ssl->options.resuming) { + if ((ssl->error = SendTls13CertificateVerify(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } +#endif + ssl->options.acceptState = CERT_STATUS_SENT; + WOLFSSL_MSG("accept state CERT_STATUS_SENT"); + + case CERT_VERIFY_SENT : + if ((ssl->error = SendTls13Finished(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + + ssl->options.acceptState = ACCEPT_FINISHED_DONE; + WOLFSSL_MSG("accept state ACCEPT_FINISHED_DONE"); + + case ACCEPT_FINISHED_DONE : +#ifdef HAVE_SESSION_TICKET + /* TODO: [TLS13] Section 4.5.1 Note. */ + if (!ssl->options.resuming && !ssl->options.verifyPeer && + !ssl->options.noTicketTls13 && ssl->ctx->ticketEncCb != NULL) { + if ((ssl->error = SendTls13NewSessionTicket(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } +#endif /* HAVE_SESSION_TICKET */ + ssl->options.acceptState = TICKET_SENT; + WOLFSSL_MSG("accept state TICKET_SENT"); + + case TICKET_SENT: + while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE) + if ( (ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + + ssl->options.acceptState = ACCEPT_SECOND_REPLY_DONE; + WOLFSSL_MSG("accept state ACCEPT_SECOND_REPLY_DONE"); + case ACCEPT_SECOND_REPLY_DONE : +#ifdef HAVE_SESSION_TICKET + if (!ssl->options.resuming && ssl->options.verifyPeer && + !ssl->options.noTicketTls13 && ssl->ctx->ticketEncCb != NULL) { + if ((ssl->error = SendTls13NewSessionTicket(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } +#endif /* HAVE_SESSION_TICKET */ + ssl->options.acceptState = ACCEPT_THIRD_REPLY_DONE; + WOLFSSL_MSG("accept state ACCEPT_THIRD_REPLY_DONE"); + + case ACCEPT_THIRD_REPLY_DONE: +#ifndef NO_HANDSHAKE_DONE_CB + if (ssl->hsDoneCb) { + int cbret = ssl->hsDoneCb(ssl, ssl->hsDoneCtx); + if (cbret < 0) { + ssl->error = cbret; + WOLFSSL_MSG("HandShake Done Cb don't continue error"); + return SSL_FATAL_ERROR; + } + } +#endif /* NO_HANDSHAKE_DONE_CB */ + +#ifdef WOLFSSL_SESSION_EXPORT + if (ssl->dtls_export) { + if ((ssl->error = wolfSSL_send_session(ssl)) != 0) { + WOLFSSL_MSG("Export DTLS session error"); + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } +#endif + + WOLFSSL_LEAVE("SSL_accept()", SSL_SUCCESS); + return SSL_SUCCESS; + + default : + WOLFSSL_MSG("Unknown accept state ERROR"); + return SSL_FATAL_ERROR; + } +} + + +#undef ERROR_OUT + +#endif /* WOLFCRYPT_ONLY */ + +#endif /* WOLFSSL_TLS13 */ diff --git a/tests/include.am b/tests/include.am index 8368b49ce..934454417 100644 --- a/tests/include.am +++ b/tests/include.am @@ -20,6 +20,7 @@ tests_unit_test_DEPENDENCIES = src/libwolfssl.la endif EXTRA_DIST += tests/unit.h EXTRA_DIST += tests/test.conf \ + tests/test-tls13.conf \ tests/test-qsh.conf \ tests/test-psk-no-id.conf \ tests/test-dtls.conf \ diff --git a/tests/suites.c b/tests/suites.c index 443573cc3..289c5ef46 100644 --- a/tests/suites.c +++ b/tests/suites.c @@ -564,6 +564,16 @@ int SuiteTest(void) /* any extra cases will need another argument */ args.argc = 2; +#ifdef WOLFSSL_TLS13 + /* add TLSv13 extra suites */ + strcpy(argv0[1], "tests/test-tls13.conf"); + printf("starting TLSv13 extra cipher suite tests\n"); + test_harness(&args); + if (args.return_code != 0) { + printf("error from script %d\n", args.return_code); + exit(EXIT_FAILURE); + } +#endif #ifdef WOLFSSL_DTLS /* add dtls extra suites */ strcpy(argv0[1], "tests/test-dtls.conf"); diff --git a/tests/test-tls13.conf b/tests/test-tls13.conf new file mode 100644 index 000000000..cf1e9f7f9 --- /dev/null +++ b/tests/test-tls13.conf @@ -0,0 +1,95 @@ +# server TLSv1.3 TLS13-CHACH20-POLY1305-SHA256 +-v 4 +-l TLS13-CHACH20-POLY1305-SHA256 + +# client TLSv1.3 TLS13-CHACH20-POLY1305-SHA256 +-v 4 +-l TLS13-CHACH20-POLY1305-SHA256 + +# server TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 + +# client TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 + +# server TLSv1.3 TLS13-AES256-GCM-SHA384 +-v 4 +-l TLS13-AES256-GCM-SHA384 + +# client TLSv1.3 TLS13-AES256-GCM-SHA384 +-v 4 +-l TLS13-AES256-GCM-SHA384 + +# server TLSv1.3 TLS13-AES128-CCM-SHA256 +-v 4 +-l TLS13-AES128-CCM-SHA256 + +# client TLSv1.3 TLS13-AES128-CCM-SHA256 +-v 4 +-l TLS13-AES128-CCM-SHA256 + +# server TLSv1.3 TLS13-AES128-CCM-8-SHA256 +-v 4 +-l TLS13-AES128-CCM-8-SHA256 + +# client TLSv1.3 TLS13-AES128-CCM-8-SHA256 +-v 4 +-l TLS13-AES128-CCM-8-SHA256 + +# server TLSv1.3 TLS13-CHACH20-POLY1305-SHA256 +-v 4 +-l TLS13-CHACH20-POLY1305-SHA256 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.3 TLS13-CHACH20-POLY1305-SHA256 +-v 4 +-l TLS13-CHACH20-POLY1305-SHA256 +-A ./certs/server-ecc.pem + +# server TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 +-A ./certs/server-ecc.pem + +# server TLSv1.3 TLS13-AES256-GCM-SHA384 +-v 4 +-l TLS13-AES256-GCM-SHA384 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.3 TLS13-AES256-GCM-SHA384 +-v 4 +-l TLS13-AES256-GCM-SHA384 +-A ./certs/server-ecc.pem + +# server TLSv1.3 TLS13-AES128-CCM-SHA256 +-v 4 +-l TLS13-AES128-CCM-SHA256 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.3 TLS13-AES128-CCM-SHA256 +-v 4 +-l TLS13-AES128-CCM-SHA256 +-A ./certs/server-ecc.pem + +# server TLSv1.3 TLS13-AES128-CCM-8-SHA256 +-v 4 +-l TLS13-AES128-CCM-8-SHA256 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.3 TLS13-AES128-CCM-8-SHA256 +-v 4 +-l TLS13-AES128-CCM-8-SHA256 +-A ./certs/server-ecc.pem + diff --git a/wolfcrypt/src/dh.c b/wolfcrypt/src/dh.c index f67e404d6..f6e2caf21 100755 --- a/wolfcrypt/src/dh.c +++ b/wolfcrypt/src/dh.c @@ -48,6 +48,448 @@ /* user's own math lib */ #endif +#ifdef HAVE_FFDHE_2048 +static const byte dh_ffdhe2048_p[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, + 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, + 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, + 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, + 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, + 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, + 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, + 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, + 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, + 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, + 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, + 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, + 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, + 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, + 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, + 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, + 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, + 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, + 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, + 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, + 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, + 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, + 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, + 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, + 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, + 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, + 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, + 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, + 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, + 0x88, 0x6B, 0x42, 0x38, 0x61, 0x28, 0x5C, 0x97, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; +static const byte dh_ffdhe2048_g[] = { 0x02 }; + +const DhParams* wc_Dh_ffdhe2048_Get(void) +{ + static const DhParams ffdhe2048 = { + dh_ffdhe2048_p, sizeof(dh_ffdhe2048_p), + dh_ffdhe2048_g, sizeof(dh_ffdhe2048_g) + }; + return &ffdhe2048; +} +#endif + +#ifdef HAVE_FFDHE_3072 +static const byte dh_ffdhe3072_p[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, + 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, + 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, + 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, + 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, + 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, + 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, + 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, + 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, + 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, + 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, + 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, + 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, + 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, + 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, + 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, + 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, + 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, + 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, + 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, + 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, + 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, + 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, + 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, + 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, + 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, + 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, + 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, + 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, + 0x88, 0x6B, 0x42, 0x38, 0x61, 0x1F, 0xCF, 0xDC, + 0xDE, 0x35, 0x5B, 0x3B, 0x65, 0x19, 0x03, 0x5B, + 0xBC, 0x34, 0xF4, 0xDE, 0xF9, 0x9C, 0x02, 0x38, + 0x61, 0xB4, 0x6F, 0xC9, 0xD6, 0xE6, 0xC9, 0x07, + 0x7A, 0xD9, 0x1D, 0x26, 0x91, 0xF7, 0xF7, 0xEE, + 0x59, 0x8C, 0xB0, 0xFA, 0xC1, 0x86, 0xD9, 0x1C, + 0xAE, 0xFE, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, + 0xB4, 0x13, 0x0C, 0x93, 0xBC, 0x43, 0x79, 0x44, + 0xF4, 0xFD, 0x44, 0x52, 0xE2, 0xD7, 0x4D, 0xD3, + 0x64, 0xF2, 0xE2, 0x1E, 0x71, 0xF5, 0x4B, 0xFF, + 0x5C, 0xAE, 0x82, 0xAB, 0x9C, 0x9D, 0xF6, 0x9E, + 0xE8, 0x6D, 0x2B, 0xC5, 0x22, 0x36, 0x3A, 0x0D, + 0xAB, 0xC5, 0x21, 0x97, 0x9B, 0x0D, 0xEA, 0xDA, + 0x1D, 0xBF, 0x9A, 0x42, 0xD5, 0xC4, 0x48, 0x4E, + 0x0A, 0xBC, 0xD0, 0x6B, 0xFA, 0x53, 0xDD, 0xEF, + 0x3C, 0x1B, 0x20, 0xEE, 0x3F, 0xD5, 0x9D, 0x7C, + 0x25, 0xE4, 0x1D, 0x2B, 0x66, 0xC6, 0x2E, 0x37, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; +static const byte dh_ffdhe3072_g[] = { 0x02 }; + +const DhParams* wc_Dh_ffdhe3072_Get(void) +{ + static const DhParams ffdhe3072 = { + dh_ffdhe3072_p, sizeof(dh_ffdhe3072_p), + dh_ffdhe3072_g, sizeof(dh_ffdhe3072_g) + }; + return &ffdhe3072; +} +#endif + +#ifdef HAVE_FFDHE_4096 +static const byte dh_ffdhe4096_p[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, + 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, + 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, + 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, + 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, + 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, + 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, + 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, + 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, + 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, + 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, + 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, + 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, + 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, + 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, + 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, + 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, + 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, + 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, + 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, + 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, + 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, + 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, + 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, + 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, + 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, + 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, + 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, + 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, + 0x88, 0x6B, 0x42, 0x38, 0x61, 0x1F, 0xCF, 0xDC, + 0xDE, 0x35, 0x5B, 0x3B, 0x65, 0x19, 0x03, 0x5B, + 0xBC, 0x34, 0xF4, 0xDE, 0xF9, 0x9C, 0x02, 0x38, + 0x61, 0xB4, 0x6F, 0xC9, 0xD6, 0xE6, 0xC9, 0x07, + 0x7A, 0xD9, 0x1D, 0x26, 0x91, 0xF7, 0xF7, 0xEE, + 0x59, 0x8C, 0xB0, 0xFA, 0xC1, 0x86, 0xD9, 0x1C, + 0xAE, 0xFE, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, + 0xB4, 0x13, 0x0C, 0x93, 0xBC, 0x43, 0x79, 0x44, + 0xF4, 0xFD, 0x44, 0x52, 0xE2, 0xD7, 0x4D, 0xD3, + 0x64, 0xF2, 0xE2, 0x1E, 0x71, 0xF5, 0x4B, 0xFF, + 0x5C, 0xAE, 0x82, 0xAB, 0x9C, 0x9D, 0xF6, 0x9E, + 0xE8, 0x6D, 0x2B, 0xC5, 0x22, 0x36, 0x3A, 0x0D, + 0xAB, 0xC5, 0x21, 0x97, 0x9B, 0x0D, 0xEA, 0xDA, + 0x1D, 0xBF, 0x9A, 0x42, 0xD5, 0xC4, 0x48, 0x4E, + 0x0A, 0xBC, 0xD0, 0x6B, 0xFA, 0x53, 0xDD, 0xEF, + 0x3C, 0x1B, 0x20, 0xEE, 0x3F, 0xD5, 0x9D, 0x7C, + 0x25, 0xE4, 0x1D, 0x2B, 0x66, 0x9E, 0x1E, 0xF1, + 0x6E, 0x6F, 0x52, 0xC3, 0x16, 0x4D, 0xF4, 0xFB, + 0x79, 0x30, 0xE9, 0xE4, 0xE5, 0x88, 0x57, 0xB6, + 0xAC, 0x7D, 0x5F, 0x42, 0xD6, 0x9F, 0x6D, 0x18, + 0x77, 0x63, 0xCF, 0x1D, 0x55, 0x03, 0x40, 0x04, + 0x87, 0xF5, 0x5B, 0xA5, 0x7E, 0x31, 0xCC, 0x7A, + 0x71, 0x35, 0xC8, 0x86, 0xEF, 0xB4, 0x31, 0x8A, + 0xED, 0x6A, 0x1E, 0x01, 0x2D, 0x9E, 0x68, 0x32, + 0xA9, 0x07, 0x60, 0x0A, 0x91, 0x81, 0x30, 0xC4, + 0x6D, 0xC7, 0x78, 0xF9, 0x71, 0xAD, 0x00, 0x38, + 0x09, 0x29, 0x99, 0xA3, 0x33, 0xCB, 0x8B, 0x7A, + 0x1A, 0x1D, 0xB9, 0x3D, 0x71, 0x40, 0x00, 0x3C, + 0x2A, 0x4E, 0xCE, 0xA9, 0xF9, 0x8D, 0x0A, 0xCC, + 0x0A, 0x82, 0x91, 0xCD, 0xCE, 0xC9, 0x7D, 0xCF, + 0x8E, 0xC9, 0xB5, 0x5A, 0x7F, 0x88, 0xA4, 0x6B, + 0x4D, 0xB5, 0xA8, 0x51, 0xF4, 0x41, 0x82, 0xE1, + 0xC6, 0x8A, 0x00, 0x7E, 0x5E, 0x65, 0x5F, 0x6A, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; +static const byte dh_ffdhe4096_g[] = { 0x02 }; + +const DhParams* wc_Dh_ffdhe4096_Get(void) +{ + static const DhParams ffdhe4096 = { + dh_ffdhe4096_p, sizeof(dh_ffdhe4096_p), + dh_ffdhe4096_g, sizeof(dh_ffdhe4096_g) + }; + return &ffdhe4096; +} +#endif + +#ifdef HAVE_FFDHE_6144 +static const byte dh_ffdhe6144_p[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, + 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, + 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, + 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, + 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, + 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, + 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, + 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, + 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, + 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, + 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, + 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, + 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, + 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, + 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, + 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, + 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, + 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, + 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, + 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, + 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, + 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, + 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, + 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, + 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, + 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, + 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, + 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, + 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, + 0x88, 0x6B, 0x42, 0x38, 0x61, 0x1F, 0xCF, 0xDC, + 0xDE, 0x35, 0x5B, 0x3B, 0x65, 0x19, 0x03, 0x5B, + 0xBC, 0x34, 0xF4, 0xDE, 0xF9, 0x9C, 0x02, 0x38, + 0x61, 0xB4, 0x6F, 0xC9, 0xD6, 0xE6, 0xC9, 0x07, + 0x7A, 0xD9, 0x1D, 0x26, 0x91, 0xF7, 0xF7, 0xEE, + 0x59, 0x8C, 0xB0, 0xFA, 0xC1, 0x86, 0xD9, 0x1C, + 0xAE, 0xFE, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, + 0xB4, 0x13, 0x0C, 0x93, 0xBC, 0x43, 0x79, 0x44, + 0xF4, 0xFD, 0x44, 0x52, 0xE2, 0xD7, 0x4D, 0xD3, + 0x64, 0xF2, 0xE2, 0x1E, 0x71, 0xF5, 0x4B, 0xFF, + 0x5C, 0xAE, 0x82, 0xAB, 0x9C, 0x9D, 0xF6, 0x9E, + 0xE8, 0x6D, 0x2B, 0xC5, 0x22, 0x36, 0x3A, 0x0D, + 0xAB, 0xC5, 0x21, 0x97, 0x9B, 0x0D, 0xEA, 0xDA, + 0x1D, 0xBF, 0x9A, 0x42, 0xD5, 0xC4, 0x48, 0x4E, + 0x0A, 0xBC, 0xD0, 0x6B, 0xFA, 0x53, 0xDD, 0xEF, + 0x3C, 0x1B, 0x20, 0xEE, 0x3F, 0xD5, 0x9D, 0x7C, + 0x25, 0xE4, 0x1D, 0x2B, 0x66, 0x9E, 0x1E, 0xF1, + 0x6E, 0x6F, 0x52, 0xC3, 0x16, 0x4D, 0xF4, 0xFB, + 0x79, 0x30, 0xE9, 0xE4, 0xE5, 0x88, 0x57, 0xB6, + 0xAC, 0x7D, 0x5F, 0x42, 0xD6, 0x9F, 0x6D, 0x18, + 0x77, 0x63, 0xCF, 0x1D, 0x55, 0x03, 0x40, 0x04, + 0x87, 0xF5, 0x5B, 0xA5, 0x7E, 0x31, 0xCC, 0x7A, + 0x71, 0x35, 0xC8, 0x86, 0xEF, 0xB4, 0x31, 0x8A, + 0xED, 0x6A, 0x1E, 0x01, 0x2D, 0x9E, 0x68, 0x32, + 0xA9, 0x07, 0x60, 0x0A, 0x91, 0x81, 0x30, 0xC4, + 0x6D, 0xC7, 0x78, 0xF9, 0x71, 0xAD, 0x00, 0x38, + 0x09, 0x29, 0x99, 0xA3, 0x33, 0xCB, 0x8B, 0x7A, + 0x1A, 0x1D, 0xB9, 0x3D, 0x71, 0x40, 0x00, 0x3C, + 0x2A, 0x4E, 0xCE, 0xA9, 0xF9, 0x8D, 0x0A, 0xCC, + 0x0A, 0x82, 0x91, 0xCD, 0xCE, 0xC9, 0x7D, 0xCF, + 0x8E, 0xC9, 0xB5, 0x5A, 0x7F, 0x88, 0xA4, 0x6B, + 0x4D, 0xB5, 0xA8, 0x51, 0xF4, 0x41, 0x82, 0xE1, + 0xC6, 0x8A, 0x00, 0x7E, 0x5E, 0x0D, 0xD9, 0x02, + 0x0B, 0xFD, 0x64, 0xB6, 0x45, 0x03, 0x6C, 0x7A, + 0x4E, 0x67, 0x7D, 0x2C, 0x38, 0x53, 0x2A, 0x3A, + 0x23, 0xBA, 0x44, 0x42, 0xCA, 0xF5, 0x3E, 0xA6, + 0x3B, 0xB4, 0x54, 0x32, 0x9B, 0x76, 0x24, 0xC8, + 0x91, 0x7B, 0xDD, 0x64, 0xB1, 0xC0, 0xFD, 0x4C, + 0xB3, 0x8E, 0x8C, 0x33, 0x4C, 0x70, 0x1C, 0x3A, + 0xCD, 0xAD, 0x06, 0x57, 0xFC, 0xCF, 0xEC, 0x71, + 0x9B, 0x1F, 0x5C, 0x3E, 0x4E, 0x46, 0x04, 0x1F, + 0x38, 0x81, 0x47, 0xFB, 0x4C, 0xFD, 0xB4, 0x77, + 0xA5, 0x24, 0x71, 0xF7, 0xA9, 0xA9, 0x69, 0x10, + 0xB8, 0x55, 0x32, 0x2E, 0xDB, 0x63, 0x40, 0xD8, + 0xA0, 0x0E, 0xF0, 0x92, 0x35, 0x05, 0x11, 0xE3, + 0x0A, 0xBE, 0xC1, 0xFF, 0xF9, 0xE3, 0xA2, 0x6E, + 0x7F, 0xB2, 0x9F, 0x8C, 0x18, 0x30, 0x23, 0xC3, + 0x58, 0x7E, 0x38, 0xDA, 0x00, 0x77, 0xD9, 0xB4, + 0x76, 0x3E, 0x4E, 0x4B, 0x94, 0xB2, 0xBB, 0xC1, + 0x94, 0xC6, 0x65, 0x1E, 0x77, 0xCA, 0xF9, 0x92, + 0xEE, 0xAA, 0xC0, 0x23, 0x2A, 0x28, 0x1B, 0xF6, + 0xB3, 0xA7, 0x39, 0xC1, 0x22, 0x61, 0x16, 0x82, + 0x0A, 0xE8, 0xDB, 0x58, 0x47, 0xA6, 0x7C, 0xBE, + 0xF9, 0xC9, 0x09, 0x1B, 0x46, 0x2D, 0x53, 0x8C, + 0xD7, 0x2B, 0x03, 0x74, 0x6A, 0xE7, 0x7F, 0x5E, + 0x62, 0x29, 0x2C, 0x31, 0x15, 0x62, 0xA8, 0x46, + 0x50, 0x5D, 0xC8, 0x2D, 0xB8, 0x54, 0x33, 0x8A, + 0xE4, 0x9F, 0x52, 0x35, 0xC9, 0x5B, 0x91, 0x17, + 0x8C, 0xCF, 0x2D, 0xD5, 0xCA, 0xCE, 0xF4, 0x03, + 0xEC, 0x9D, 0x18, 0x10, 0xC6, 0x27, 0x2B, 0x04, + 0x5B, 0x3B, 0x71, 0xF9, 0xDC, 0x6B, 0x80, 0xD6, + 0x3F, 0xDD, 0x4A, 0x8E, 0x9A, 0xDB, 0x1E, 0x69, + 0x62, 0xA6, 0x95, 0x26, 0xD4, 0x31, 0x61, 0xC1, + 0xA4, 0x1D, 0x57, 0x0D, 0x79, 0x38, 0xDA, 0xD4, + 0xA4, 0x0E, 0x32, 0x9C, 0xD0, 0xE4, 0x0E, 0x65, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; +static const byte dh_ffdhe6144_g[] = { 0x02 }; + +const DhParams* wc_Dh_ffdhe6144_Get(void) +{ + static const DhParams ffdhe6144 = { + dh_ffdhe6144_p, sizeof(dh_ffdhe6144_p), + dh_ffdhe6144_g, sizeof(dh_ffdhe6144_g) + }; + return &ffdhe6144; +} +#endif + +#ifdef HAVE_FFDHE_8192 +static const byte dh_ffdhe8192_p[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, + 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, + 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, + 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, + 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, + 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, + 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, + 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, + 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, + 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, + 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, + 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, + 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, + 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, + 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, + 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, + 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, + 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, + 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, + 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, + 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, + 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, + 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, + 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, + 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, + 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, + 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, + 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, + 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, + 0x88, 0x6B, 0x42, 0x38, 0x61, 0x1F, 0xCF, 0xDC, + 0xDE, 0x35, 0x5B, 0x3B, 0x65, 0x19, 0x03, 0x5B, + 0xBC, 0x34, 0xF4, 0xDE, 0xF9, 0x9C, 0x02, 0x38, + 0x61, 0xB4, 0x6F, 0xC9, 0xD6, 0xE6, 0xC9, 0x07, + 0x7A, 0xD9, 0x1D, 0x26, 0x91, 0xF7, 0xF7, 0xEE, + 0x59, 0x8C, 0xB0, 0xFA, 0xC1, 0x86, 0xD9, 0x1C, + 0xAE, 0xFE, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, + 0xB4, 0x13, 0x0C, 0x93, 0xBC, 0x43, 0x79, 0x44, + 0xF4, 0xFD, 0x44, 0x52, 0xE2, 0xD7, 0x4D, 0xD3, + 0x64, 0xF2, 0xE2, 0x1E, 0x71, 0xF5, 0x4B, 0xFF, + 0x5C, 0xAE, 0x82, 0xAB, 0x9C, 0x9D, 0xF6, 0x9E, + 0xE8, 0x6D, 0x2B, 0xC5, 0x22, 0x36, 0x3A, 0x0D, + 0xAB, 0xC5, 0x21, 0x97, 0x9B, 0x0D, 0xEA, 0xDA, + 0x1D, 0xBF, 0x9A, 0x42, 0xD5, 0xC4, 0x48, 0x4E, + 0x0A, 0xBC, 0xD0, 0x6B, 0xFA, 0x53, 0xDD, 0xEF, + 0x3C, 0x1B, 0x20, 0xEE, 0x3F, 0xD5, 0x9D, 0x7C, + 0x25, 0xE4, 0x1D, 0x2B, 0x66, 0x9E, 0x1E, 0xF1, + 0x6E, 0x6F, 0x52, 0xC3, 0x16, 0x4D, 0xF4, 0xFB, + 0x79, 0x30, 0xE9, 0xE4, 0xE5, 0x88, 0x57, 0xB6, + 0xAC, 0x7D, 0x5F, 0x42, 0xD6, 0x9F, 0x6D, 0x18, + 0x77, 0x63, 0xCF, 0x1D, 0x55, 0x03, 0x40, 0x04, + 0x87, 0xF5, 0x5B, 0xA5, 0x7E, 0x31, 0xCC, 0x7A, + 0x71, 0x35, 0xC8, 0x86, 0xEF, 0xB4, 0x31, 0x8A, + 0xED, 0x6A, 0x1E, 0x01, 0x2D, 0x9E, 0x68, 0x32, + 0xA9, 0x07, 0x60, 0x0A, 0x91, 0x81, 0x30, 0xC4, + 0x6D, 0xC7, 0x78, 0xF9, 0x71, 0xAD, 0x00, 0x38, + 0x09, 0x29, 0x99, 0xA3, 0x33, 0xCB, 0x8B, 0x7A, + 0x1A, 0x1D, 0xB9, 0x3D, 0x71, 0x40, 0x00, 0x3C, + 0x2A, 0x4E, 0xCE, 0xA9, 0xF9, 0x8D, 0x0A, 0xCC, + 0x0A, 0x82, 0x91, 0xCD, 0xCE, 0xC9, 0x7D, 0xCF, + 0x8E, 0xC9, 0xB5, 0x5A, 0x7F, 0x88, 0xA4, 0x6B, + 0x4D, 0xB5, 0xA8, 0x51, 0xF4, 0x41, 0x82, 0xE1, + 0xC6, 0x8A, 0x00, 0x7E, 0x5E, 0x0D, 0xD9, 0x02, + 0x0B, 0xFD, 0x64, 0xB6, 0x45, 0x03, 0x6C, 0x7A, + 0x4E, 0x67, 0x7D, 0x2C, 0x38, 0x53, 0x2A, 0x3A, + 0x23, 0xBA, 0x44, 0x42, 0xCA, 0xF5, 0x3E, 0xA6, + 0x3B, 0xB4, 0x54, 0x32, 0x9B, 0x76, 0x24, 0xC8, + 0x91, 0x7B, 0xDD, 0x64, 0xB1, 0xC0, 0xFD, 0x4C, + 0xB3, 0x8E, 0x8C, 0x33, 0x4C, 0x70, 0x1C, 0x3A, + 0xCD, 0xAD, 0x06, 0x57, 0xFC, 0xCF, 0xEC, 0x71, + 0x9B, 0x1F, 0x5C, 0x3E, 0x4E, 0x46, 0x04, 0x1F, + 0x38, 0x81, 0x47, 0xFB, 0x4C, 0xFD, 0xB4, 0x77, + 0xA5, 0x24, 0x71, 0xF7, 0xA9, 0xA9, 0x69, 0x10, + 0xB8, 0x55, 0x32, 0x2E, 0xDB, 0x63, 0x40, 0xD8, + 0xA0, 0x0E, 0xF0, 0x92, 0x35, 0x05, 0x11, 0xE3, + 0x0A, 0xBE, 0xC1, 0xFF, 0xF9, 0xE3, 0xA2, 0x6E, + 0x7F, 0xB2, 0x9F, 0x8C, 0x18, 0x30, 0x23, 0xC3, + 0x58, 0x7E, 0x38, 0xDA, 0x00, 0x77, 0xD9, 0xB4, + 0x76, 0x3E, 0x4E, 0x4B, 0x94, 0xB2, 0xBB, 0xC1, + 0x94, 0xC6, 0x65, 0x1E, 0x77, 0xCA, 0xF9, 0x92, + 0xEE, 0xAA, 0xC0, 0x23, 0x2A, 0x28, 0x1B, 0xF6, + 0xB3, 0xA7, 0x39, 0xC1, 0x22, 0x61, 0x16, 0x82, + 0x0A, 0xE8, 0xDB, 0x58, 0x47, 0xA6, 0x7C, 0xBE, + 0xF9, 0xC9, 0x09, 0x1B, 0x46, 0x2D, 0x53, 0x8C, + 0xD7, 0x2B, 0x03, 0x74, 0x6A, 0xE7, 0x7F, 0x5E, + 0x62, 0x29, 0x2C, 0x31, 0x15, 0x62, 0xA8, 0x46, + 0x50, 0x5D, 0xC8, 0x2D, 0xB8, 0x54, 0x33, 0x8A, + 0xE4, 0x9F, 0x52, 0x35, 0xC9, 0x5B, 0x91, 0x17, + 0x8C, 0xCF, 0x2D, 0xD5, 0xCA, 0xCE, 0xF4, 0x03, + 0xEC, 0x9D, 0x18, 0x10, 0xC6, 0x27, 0x2B, 0x04, + 0x5B, 0x3B, 0x71, 0xF9, 0xDC, 0x6B, 0x80, 0xD6, + 0x3F, 0xDD, 0x4A, 0x8E, 0x9A, 0xDB, 0x1E, 0x69, + 0x62, 0xA6, 0x95, 0x26, 0xD4, 0x31, 0x61, 0xC1, + 0xA4, 0x1D, 0x57, 0x0D, 0x79, 0x38, 0xDA, 0xD4, + 0xA4, 0x0E, 0x32, 0x9C, 0xCF, 0xF4, 0x6A, 0xAA, + 0x36, 0xAD, 0x00, 0x4C, 0xF6, 0x00, 0xC8, 0x38, + 0x1E, 0x42, 0x5A, 0x31, 0xD9, 0x51, 0xAE, 0x64, + 0xFD, 0xB2, 0x3F, 0xCE, 0xC9, 0x50, 0x9D, 0x43, + 0x68, 0x7F, 0xEB, 0x69, 0xED, 0xD1, 0xCC, 0x5E, + 0x0B, 0x8C, 0xC3, 0xBD, 0xF6, 0x4B, 0x10, 0xEF, + 0x86, 0xB6, 0x31, 0x42, 0xA3, 0xAB, 0x88, 0x29, + 0x55, 0x5B, 0x2F, 0x74, 0x7C, 0x93, 0x26, 0x65, + 0xCB, 0x2C, 0x0F, 0x1C, 0xC0, 0x1B, 0xD7, 0x02, + 0x29, 0x38, 0x88, 0x39, 0xD2, 0xAF, 0x05, 0xE4, + 0x54, 0x50, 0x4A, 0xC7, 0x8B, 0x75, 0x82, 0x82, + 0x28, 0x46, 0xC0, 0xBA, 0x35, 0xC3, 0x5F, 0x5C, + 0x59, 0x16, 0x0C, 0xC0, 0x46, 0xFD, 0x82, 0x51, + 0x54, 0x1F, 0xC6, 0x8C, 0x9C, 0x86, 0xB0, 0x22, + 0xBB, 0x70, 0x99, 0x87, 0x6A, 0x46, 0x0E, 0x74, + 0x51, 0xA8, 0xA9, 0x31, 0x09, 0x70, 0x3F, 0xEE, + 0x1C, 0x21, 0x7E, 0x6C, 0x38, 0x26, 0xE5, 0x2C, + 0x51, 0xAA, 0x69, 0x1E, 0x0E, 0x42, 0x3C, 0xFC, + 0x99, 0xE9, 0xE3, 0x16, 0x50, 0xC1, 0x21, 0x7B, + 0x62, 0x48, 0x16, 0xCD, 0xAD, 0x9A, 0x95, 0xF9, + 0xD5, 0xB8, 0x01, 0x94, 0x88, 0xD9, 0xC0, 0xA0, + 0xA1, 0xFE, 0x30, 0x75, 0xA5, 0x77, 0xE2, 0x31, + 0x83, 0xF8, 0x1D, 0x4A, 0x3F, 0x2F, 0xA4, 0x57, + 0x1E, 0xFC, 0x8C, 0xE0, 0xBA, 0x8A, 0x4F, 0xE8, + 0xB6, 0x85, 0x5D, 0xFE, 0x72, 0xB0, 0xA6, 0x6E, + 0xDE, 0xD2, 0xFB, 0xAB, 0xFB, 0xE5, 0x8A, 0x30, + 0xFA, 0xFA, 0xBE, 0x1C, 0x5D, 0x71, 0xA8, 0x7E, + 0x2F, 0x74, 0x1E, 0xF8, 0xC1, 0xFE, 0x86, 0xFE, + 0xA6, 0xBB, 0xFD, 0xE5, 0x30, 0x67, 0x7F, 0x0D, + 0x97, 0xD1, 0x1D, 0x49, 0xF7, 0xA8, 0x44, 0x3D, + 0x08, 0x22, 0xE5, 0x06, 0xA9, 0xF4, 0x61, 0x4E, + 0x01, 0x1E, 0x2A, 0x94, 0x83, 0x8F, 0xF8, 0x8C, + 0xD6, 0x8C, 0x8B, 0xB7, 0xC5, 0xC6, 0x42, 0x4C, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; +static const byte dh_ffdhe8192_g[] = { 0x02 }; + +const DhParams* wc_Dh_ffdhe8192_Get(void) +{ + static const DhParams ffdhe8192 = { + dh_ffdhe8192_p, sizeof(dh_ffdhe8192_p), + dh_ffdhe8192_g, sizeof(dh_ffdhe8192_g) + }; + return &ffdhe8192; +} +#endif int wc_InitDhKey_ex(DhKey* key, void* heap, int devId) { diff --git a/wolfcrypt/src/hmac.c b/wolfcrypt/src/hmac.c index c595465da..2498a8add 100755 --- a/wolfcrypt/src/hmac.c +++ b/wolfcrypt/src/hmac.c @@ -788,40 +788,25 @@ int wolfSSL_GetHmacMaxSize(void) } #ifdef HAVE_HKDF - /* HMAC-KDF with hash type, optional salt and info, return 0 on success */ - int wc_HKDF(int type, const byte* inKey, word32 inKeySz, - const byte* salt, word32 saltSz, - const byte* info, word32 infoSz, - byte* out, word32 outSz) + /* HMAC-KDF-Extract. + * RFC 5869 - HMAC-based Extract-and-Expand Key Derivation Function (HKDF). + * + * type The hash algorithm type. + * salt The optional salt value. + * saltSz The size of the salt. + * inKey The input keying material. + * inKeySz The size of the input keying material. + * out The pseudorandom key with the length that of the hash. + * returns 0 on success, otherwise failure. + */ + int wc_HKDF_Extract(int type, const byte* salt, word32 saltSz, + const byte* inKey, word32 inKeySz, byte* out) { + byte tmp[MAX_DIGEST_SIZE]; /* localSalt helper */ Hmac myHmac; - #ifdef WOLFSSL_SMALL_STACK - byte* tmp; - byte* prk; - #else - byte tmp[MAX_DIGEST_SIZE]; /* localSalt helper and T */ - byte prk[MAX_DIGEST_SIZE]; - #endif + int ret; const byte* localSalt; /* either points to user input or tmp */ int hashSz = wc_HmacSizeByType(type); - word32 outIdx = 0; - byte n = 0x1; - int ret; - - if (hashSz < 0) - return BAD_FUNC_ARG; - - #ifdef WOLFSSL_SMALL_STACK - tmp = (byte*)XMALLOC(MAX_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (tmp == NULL) - return MEMORY_E; - - prk = (byte*)XMALLOC(MAX_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (prk == NULL) { - XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_E; - } - #endif localSalt = salt; if (localSalt == NULL) { @@ -834,45 +819,94 @@ int wolfSSL_GetHmacMaxSize(void) if (ret == 0) ret = wc_HmacUpdate(&myHmac, inKey, inKeySz); if (ret == 0) - ret = wc_HmacFinal(&myHmac, prk); - - if (ret == 0) { - while (outIdx < outSz) { - int tmpSz = (n == 1) ? 0 : hashSz; - word32 left = outSz - outIdx; - - ret = wc_HmacSetKey(&myHmac, type, prk, hashSz); - if (ret != 0) - break; - ret = wc_HmacUpdate(&myHmac, tmp, tmpSz); - if (ret != 0) - break; - ret = wc_HmacUpdate(&myHmac, info, infoSz); - if (ret != 0) - break; - ret = wc_HmacUpdate(&myHmac, &n, 1); - if (ret != 0) - break; - ret = wc_HmacFinal(&myHmac, tmp); - if (ret != 0) - break; - - left = min(left, (word32)hashSz); - XMEMCPY(out+outIdx, tmp, left); - - outIdx += hashSz; - n++; - } - } - - #ifdef WOLFSSL_SMALL_STACK - XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(prk, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif + ret = wc_HmacFinal(&myHmac, out); return ret; } + /* HMAC-KDF-Expand. + * RFC 5869 - HMAC-based Extract-and-Expand Key Derivation Function (HKDF). + * + * type The hash algorithm type. + * inKey The input key. + * inKeySz The size of the input key. + * info The application specific information. + * infoSz The size of the application specific information. + * out The output keying material. + * returns 0 on success, otherwise failure. + */ + int wc_HKDF_Expand(int type, const byte* inKey, word32 inKeySz, + const byte* info, word32 infoSz, byte* out, word32 outSz) + { + byte tmp[MAX_DIGEST_SIZE]; + Hmac myHmac; + int ret = 0; + word32 outIdx = 0; + word32 hashSz = wc_HmacSizeByType(type); + byte n = 0x1; + + while (outIdx < outSz) { + int tmpSz = (n == 1) ? 0 : hashSz; + word32 left = outSz - outIdx; + + ret = wc_HmacSetKey(&myHmac, type, inKey, inKeySz); + if (ret != 0) + break; + ret = wc_HmacUpdate(&myHmac, tmp, tmpSz); + if (ret != 0) + break; + ret = wc_HmacUpdate(&myHmac, info, infoSz); + if (ret != 0) + break; + ret = wc_HmacUpdate(&myHmac, &n, 1); + if (ret != 0) + break; + ret = wc_HmacFinal(&myHmac, tmp); + if (ret != 0) + break; + + left = min(left, hashSz); + XMEMCPY(out+outIdx, tmp, left); + + outIdx += hashSz; + n++; + } + + return ret; + } + + /* HMAC-KDF. + * RFC 5869 - HMAC-based Extract-and-Expand Key Derivation Function (HKDF). + * + * type The hash algorithm type. + * inKey The input keying material. + * inKeySz The size of the input keying material. + * salt The optional salt value. + * saltSz The size of the salt. + * info The application specific information. + * infoSz The size of the application specific information. + * out The output keying material. + * returns 0 on success, otherwise failure. + */ + int wc_HKDF(int type, const byte* inKey, word32 inKeySz, + const byte* salt, word32 saltSz, + const byte* info, word32 infoSz, + byte* out, word32 outSz) + { + byte prk[MAX_DIGEST_SIZE]; + int hashSz = wc_HmacSizeByType(type); + int ret; + + if (hashSz < 0) + return BAD_FUNC_ARG; + + ret = wc_HKDF_Extract(type, salt, saltSz, inKey, inKeySz, prk); + if (ret != 0) + return ret; + + return wc_HKDF_Expand(type, prk, hashSz, info, infoSz, out, outSz); + } + #endif /* HAVE_HKDF */ #endif /* HAVE_FIPS */ diff --git a/wolfcrypt/src/logging.c b/wolfcrypt/src/logging.c index 047f3a0dd..1a7b6ff39 100644 --- a/wolfcrypt/src/logging.c +++ b/wolfcrypt/src/logging.c @@ -161,7 +161,7 @@ void WOLFSSL_MSG(const char* msg) } -void WOLFSSL_BUFFER(byte* buffer, word32 length) +void WOLFSSL_BUFFER(const byte* buffer, word32 length) { #define LINE_LEN 16 diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 941c379c5..c797c7f55 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -155,12 +155,19 @@ enum wolfSSL_ErrorCodes { HTTP_TIMEOUT = -417, /* HTTP timeout for OCSP or CRL req */ WRITE_DUP_READ_E = -418, /* Write dup write side can't read */ WRITE_DUP_WRITE_E = -419, /* Write dup read side can't write */ + INVALID_CERT_CTX_E = -420, /* TLS cert ctx not matching */ + BAD_KEY_SHARE_DATA = -421, /* Key Share data invalid */ + MISSING_HANDSHAKE_DATA = -422, /* Handshake message missing data */ + BAD_BINDER = -423, /* Binder does not match */ + EXT_NOT_ALLOWED = -424, /* Extension not allowed in msg */ + INVALID_PARAMETER = -425, /* Security parameter invalid */ /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ /* begin negotiation parameter errors */ UNSUPPORTED_SUITE = -500, /* unsupported cipher suite */ MATCH_SUITE_ERROR = -501, /* can't match cipher suite */ - COMPRESSION_ERROR = -502 /* compression mismatch */ + COMPRESSION_ERROR = -502, /* compression mismatch */ + KEY_SHARE_ERROR = -503 /* key share mismatch */ /* end negotiation parameter errors only 10 for now */ /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 19a065a43..fa0d0bf43 100755 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -627,6 +627,29 @@ typedef byte word24[3]; #endif #endif +#if defined(WOLFSSL_TLS13) + #ifdef HAVE_AESGCM + #ifndef NO_SHA256 + #define BUILD_TLS_AES_128_GCM_SHA256 + #endif + #ifdef WOLFSSL_SHA384 + #define BUILD_TLS_AES_256_GCM_SHA384 + #endif + #endif + + #ifdef HAVE_CHACHA + #ifndef NO_SHA256 + #define BUILD_TLS_CHACHA20_POLY1305_SHA256 + #endif + #endif + + #ifdef HAVE_AESCCM + #ifndef NO_SHA256 + #define BUILD_TLS_AES_128_CCM_SHA256 + #define BUILD_TLS_AES_128_CCM_8_SHA256 + #endif + #endif +#endif #if defined(BUILD_SSL_RSA_WITH_RC4_128_SHA) || \ defined(BUILD_SSL_RSA_WITH_RC4_128_MD5) @@ -853,6 +876,13 @@ enum { TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 = 0x14, TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 = 0x15, + /* TLS v1.3 cipher suites */ + TLS_AES_128_GCM_SHA256 = 0x01, + TLS_AES_256_GCM_SHA384 = 0x02, + TLS_CHACHA20_POLY1305_SHA256 = 0x03, + TLS_AES_128_CCM_SHA256 = 0x04, + TLS_AES_128_CCM_8_SHA256 = 0x05, + /* Renegotiation Indication Extension Special Suite */ TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0xff }; @@ -876,6 +906,7 @@ enum Misc { ECC_BYTE = 0xC0, /* ECC first cipher suite byte */ QSH_BYTE = 0xD0, /* Quantum-safe Handshake cipher suite */ CHACHA_BYTE = 0xCC, /* ChaCha first cipher suite */ + TLS13_BYTE = 0x13, /* TLS v.13 first byte of cipher suite */ SEND_CERT = 1, SEND_BLANK_CERT = 2, @@ -888,6 +919,9 @@ enum Misc { TLSv1_MINOR = 1, /* TLSv1 minor version number */ 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 */ + TLS_DRAFT_MAJOR = 0x7f, /* Draft TLS major version number */ + TLS_DRAFT_MINOR = 0x12, /* Minor version number of TLS draft */ OLD_HELLO_ID = 0x01, /* SSLv2 Client Hello Indicator */ INVALID_BYTE = 0xff, /* Used to initialize cipher specs values */ NO_COMPRESSION = 0, @@ -927,9 +961,13 @@ enum Misc { SEQ_SZ = 8, /* 64 bit sequence number */ ALERT_SIZE = 2, /* level + description */ VERIFY_HEADER = 2, /* always use 2 bytes */ + EXTS_SZ = 2, /* always use 2 bytes */ EXT_ID_SZ = 2, /* always use 2 bytes */ MAX_DH_SIZE = 513, /* 4096 bit plus possible leading 0 */ + NAMED_DH_MASK = 0x100, /* Named group mask for DH parameters */ SESSION_HINT_SZ = 4, /* session timeout hint */ + SESSION_ADD_SZ = 4, /* session age add */ + MAX_LIFETIME = 604800, /* maximum ticket lifetime */ RAN_LEN = 32, /* random length */ SEED_LEN = RAN_LEN * 2, /* tls prf seed length */ @@ -946,6 +984,7 @@ enum Misc { OPAQUE64_LEN = 8, /* 8 bytes */ COMP_LEN = 1, /* compression length */ CURVE_LEN = 2, /* ecc named curve length */ + KE_GROUP_LEN = 2, /* key exchange group length */ SERVER_ID_LEN = 20, /* server session id length */ HANDSHAKE_HEADER_SZ = 4, /* type + length(3) */ @@ -986,6 +1025,11 @@ enum Misc { MAX_PRF_HALF = 256, /* Maximum half secret len */ MAX_PRF_LABSEED = 128, /* Maximum label + seed len */ MAX_PRF_DIG = 224, /* Maximum digest len */ + PROTOCOL_LABEL_SZ = 9, /* Length of the protocol label */ + MAX_LABEL_SZ = 34, /* Maximum length of a label */ + MAX_HKDF_LABEL_SZ = OPAQUE16_LEN + + OPAQUE8_LEN + PROTOCOL_LABEL_SZ + MAX_LABEL_SZ + + OPAQUE8_LEN + MAX_DIGEST_SIZE, MAX_REQUEST_SZ = 256, /* Maximum cert req len (no auth yet */ SESSION_FLUSH_COUNT = 256, /* Flush session cache unless user turns off */ @@ -1004,6 +1048,7 @@ enum Misc { AEAD_VMIN_OFFSET = 10, /* Auth Data: Minor Version */ AEAD_LEN_OFFSET = 11, /* Auth Data: Length */ AEAD_AUTH_DATA_SZ = 13, /* Size of the data to authenticate */ + AEAD_NONCE_SZ = 12, AESGCM_IMP_IV_SZ = 4, /* Size of GCM/CCM AEAD implicit IV */ AESGCM_EXP_IV_SZ = 8, /* Size of GCM/CCM AEAD explicit IV */ AESGCM_NONCE_SZ = AESGCM_EXP_IV_SZ + AESGCM_IMP_IV_SZ, @@ -1017,6 +1062,7 @@ enum Misc { AES_GCM_AUTH_SZ = 16, /* AES-GCM Auth Tag length */ AES_CCM_16_AUTH_SZ = 16, /* AES-CCM-16 Auth Tag length */ AES_CCM_8_AUTH_SZ = 8, /* AES-CCM-8 Auth Tag Length */ + AESCCM_NONCE_SZ = 12, CAMELLIA_128_KEY_SIZE = 16, /* for 128 bit */ CAMELLIA_192_KEY_SIZE = 24, /* for 192 bit */ @@ -1057,6 +1103,8 @@ enum Misc { MAX_PSK_ID_LEN = 128, /* max psk identity/hint supported */ NULL_TERM_LEN = 1, /* length of null '\0' termination character */ MAX_PSK_KEY_LEN = 64, /* max psk key supported */ + MIN_PSK_ID_LEN = 6, /* min length of identities */ + MIN_PSK_BINDERS_LEN= 33, /* min length of binders */ MAX_WOLFSSL_FILE_SIZE = 1024 * 1024 * 4, /* 4 mb file size alloc limit */ @@ -1087,11 +1135,7 @@ enum Misc { /* Set max implicit IV size for AEAD cipher suites */ -#ifdef HAVE_CHACHA - #define AEAD_MAX_IMP_SZ 12 -#else - #define AEAD_MAX_IMP_SZ 4 -#endif +#define AEAD_MAX_IMP_SZ 12 /* Set max explicit IV size for AEAD cipher suites */ #define AEAD_MAX_EXP_SZ 8 @@ -1200,10 +1244,12 @@ enum states { SERVER_HELLOVERIFYREQUEST_COMPLETE, SERVER_HELLO_COMPLETE, + SERVER_ENCRYPTED_EXTENSIONS_COMPLETE, SERVER_CERT_COMPLETE, SERVER_KEYEXCHANGE_COMPLETE, SERVER_HELLODONE_COMPLETE, SERVER_FINISHED_COMPLETE, + SERVER_HELLO_RETRY_REQUEST, CLIENT_HELLO_COMPLETE, CLIENT_KEYEXCHANGE_COMPLETE, @@ -1230,6 +1276,7 @@ WOLFSSL_LOCAL ProtocolVersion MakeSSLv3(void); WOLFSSL_LOCAL ProtocolVersion MakeTLSv1(void); WOLFSSL_LOCAL ProtocolVersion MakeTLSv1_1(void); WOLFSSL_LOCAL ProtocolVersion MakeTLSv1_2(void); +WOLFSSL_LOCAL ProtocolVersion MakeTLSv1_3(void); #ifdef WOLFSSL_DTLS WOLFSSL_LOCAL ProtocolVersion MakeDTLSv1(void); @@ -1291,6 +1338,9 @@ struct WOLFSSL_METHOD { byte downgrade; /* whether to downgrade version, default no */ }; +/* wolfSSL buffer type - internal uses "buffer" type */ +typedef WOLFSSL_BUFFER_INFO buffer; + /* defaults to client */ WOLFSSL_LOCAL void InitSSL_Method(WOLFSSL_METHOD*, ProtocolVersion); @@ -1299,10 +1349,39 @@ WOLFSSL_LOCAL void InitSSL_Method(WOLFSSL_METHOD*, ProtocolVersion); 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); - - -/* wolfSSL buffer type - internal uses "buffer" type */ -typedef WOLFSSL_BUFFER_INFO buffer; +/* TLS v1.3 needs these */ +WOLFSSL_LOCAL int DoClientHello(WOLFSSL* ssl, const byte* input, word32*, + word32); +WOLFSSL_LOCAL int DoServerHello(WOLFSSL* ssl, const byte* input, word32*, + word32); +WOLFSSL_LOCAL int CheckVersion(WOLFSSL *ssl, ProtocolVersion pv); +WOLFSSL_LOCAL void PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo, + word32 hashSigAlgoSz); +WOLFSSL_LOCAL int DecodePrivateKey(WOLFSSL *ssl, word16* length); +WOLFSSL_LOCAL void FreeKeyExchange(WOLFSSL* ssl); +WOLFSSL_LOCAL int ProcessPeerCerts(WOLFSSL* ssl, buffer *certs, buffer *exts, + int totalCerts); +WOLFSSL_LOCAL int MatchDomainName(const char* pattern, int len, const char* str); +WOLFSSL_LOCAL int CheckAltNames(DecodedCert* dCert, char* domain); +WOLFSSL_LOCAL int CreateTicket(WOLFSSL* ssl); +WOLFSSL_LOCAL int HashOutputRaw(WOLFSSL* ssl, const byte* output, int sz); +WOLFSSL_LOCAL int HashOutput(WOLFSSL* ssl, const byte* output, int sz, + int ivSz); +WOLFSSL_LOCAL int HashInput(WOLFSSL* ssl, const byte* input, int sz); +#if defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || defined (WOLFSSL_HAPROXY) +WOLFSSL_LOCAL int SNI_Callback(WOLFSSL* ssl); +#endif +#ifdef WOLFSSL_TLS13 +WOLFSSL_LOCAL int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input, + word16 sz); +WOLFSSL_LOCAL int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, + word32* inOutIdx, byte type, + word32 size, word32 totalSz); +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); +#endif #ifndef NO_CERTS /* wolfSSL DER buffer */ @@ -1404,11 +1483,10 @@ typedef struct Suites { } Suites; -WOLFSSL_LOCAL -void InitSuites(Suites*, ProtocolVersion, word16, word16, word16, word16, - word16, word16, word16, int); -WOLFSSL_LOCAL -int SetCipherList(WOLFSSL_CTX*, Suites*, const char* list); +WOLFSSL_LOCAL void InitSuites(Suites*, ProtocolVersion, word16, word16, word16, word16, + word16, word16, word16, int); +WOLFSSL_LOCAL int MatchSuite(WOLFSSL* ssl, Suites* peerSuites); +WOLFSSL_LOCAL int SetCipherList(WOLFSSL_CTX*, Suites*, const char* list); #ifndef PSK_TYPES_DEFINED typedef unsigned int (*wc_psk_client_callback)(WOLFSSL*, const char*, char*, @@ -1651,6 +1729,10 @@ typedef struct Keys { word32 padSz; /* how much to advance after decrypt part */ byte encryptionOn; /* true after change cipher spec */ byte decryptedCur; /* only decrypt current record once */ +#ifdef WOLFSSL_TLS13 + byte updateResponseReq:1; /* KeyUpdate response from peer required. */ + byte keyUpdateRespond:1; /* KeyUpdate is to be responded to. */ +#endif } Keys; @@ -1668,12 +1750,23 @@ typedef enum { TLSX_STATUS_REQUEST_V2 = 0x0011, /* a.k.a. OCSP stapling v2 */ TLSX_QUANTUM_SAFE_HYBRID = 0x0018, /* a.k.a. QSH */ TLSX_SESSION_TICKET = 0x0023, +#ifdef WOLFSSL_TLS13 + TLSX_KEY_SHARE = 0x0028, + #ifndef NO_PSK + TLSX_PRE_SHARED_KEY = 0x0029, + #endif + TLSX_SUPPORTED_VERSIONS = 0x002b, + #ifndef NO_PSK + TLSX_PSK_KEY_EXCHANGE_MODES = 0x002d, + #endif +#endif TLSX_RENEGOTIATION_INFO = 0xff01 } TLSX_Type; typedef struct TLSX { TLSX_Type type; /* Extension Type */ void* data; /* Extension Data */ + word32 val; /* Extension Value */ byte resp; /* IsResponse Flag */ struct TLSX* next; /* List Behavior */ } TLSX; @@ -1689,12 +1782,13 @@ WOLFSSL_LOCAL word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output); #endif #ifndef NO_WOLFSSL_SERVER -WOLFSSL_LOCAL word16 TLSX_GetResponseSize(WOLFSSL* ssl); -WOLFSSL_LOCAL word16 TLSX_WriteResponse(WOLFSSL* ssl, byte* output); +WOLFSSL_LOCAL word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType); +WOLFSSL_LOCAL word16 TLSX_WriteResponse(WOLFSSL* ssl, byte* output, + byte msgType); #endif -WOLFSSL_LOCAL int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, - byte isRequest, Suites *suites); +WOLFSSL_LOCAL int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte msgType, Suites *suites); #elif defined(HAVE_SNI) \ || defined(HAVE_MAX_FRAGMENT) \ @@ -1870,6 +1964,10 @@ WOLFSSL_LOCAL int TLSX_AddEmptyRenegotiationInfo(TLSX** extensions, void* heap); typedef struct SessionTicket { word32 lifetime; +#ifdef WOLFSSL_TLS13 + word64 seen; + word32 ageAdd; +#endif byte* data; word16 size; } SessionTicket; @@ -1924,6 +2022,69 @@ WOLFSSL_LOCAL int TLSX_ValidateQSHScheme(TLSX** extensions, word16 name); #endif /* HAVE_QSH */ +#ifdef WOLFSSL_TLS13 +/* Key Share - TLS v1.3 Specification */ + +/* The KeyShare extension information - entry in a linked list. */ +typedef struct KeyShareEntry { + word16 group; /* NamedGroup */ + byte* ke; /* Key exchange data */ + word32 keLen; /* Key exchange data length */ + void* key; /* Private key */ + word32 keyLen; /* Private key length */ + struct KeyShareEntry* next; /* List pointer */ +} KeyShareEntry; + +WOLFSSL_LOCAL int TLSX_KeyShare_Use(WOLFSSL* ssl, word16 group, word16 len, + byte* data, KeyShareEntry **kse); +WOLFSSL_LOCAL int TLSX_KeyShare_Empty(WOLFSSL* ssl); +WOLFSSL_LOCAL int TLSX_KeyShare_Establish(WOLFSSL* ssl); + +#ifndef NO_PSK +/* The PreSharedKey extension information - entry in a linked list. */ +typedef struct PreSharedKey { + word16 identityLen; /* Length of identity */ + byte* identity; /* PSK identity */ + word32 ticketAge; /* Age of the ticket */ + byte binderLen; /* Length of HMAC */ + byte binder[MAX_DIGEST_SIZE]; /* HMAC of hanshake */ + byte hmac; /* HMAC algorithm */ + byte resumption:1; /* Resumption PSK */ + byte chosen:1; /* Server's choice */ + struct PreSharedKey* next; /* List pointer */ +} PreSharedKey; + +WOLFSSL_LOCAL word16 TLSX_PreSharedKey_WriteBinders(PreSharedKey* list, + byte* output, byte msgType); +WOLFSSL_LOCAL word16 TLSX_PreSharedKey_GetSizeBinders(PreSharedKey* list, + byte msgType); +WOLFSSL_LOCAL int TLSX_PreSharedKey_Use(WOLFSSL* ssl, byte* identity, + word16 len, word32 age, byte hmac, + byte resumption, + PreSharedKey **preSharedKey); + +enum PskKeyExchangeMode { + PSK_KE, + PSK_DHE_KE +}; + +WOLFSSL_LOCAL int TLSX_PskKeModes_Use(WOLFSSL* ssl, byte modes); +#endif /* NO_PSK */ + +/* The types of keys to derive for. */ +enum DeriveKeyType { + handshake_key, + traffic_key, + update_traffic_key +}; + +/* The key update request values for KeyUpdate message. */ +enum KeyUpdateRequest { + update_not_requested, + update_requested +}; +#endif /* WOLFSSL_TLS13 */ + /* wolfSSL context type */ struct WOLFSSL_CTX { @@ -1948,6 +2109,9 @@ struct WOLFSSL_CTX { #if defined(WOLFSSL_NGINX) || defined (WOLFSSL_HAPROXY) STACK_OF(WOLFSSL_X509)* x509Chain; #endif +#ifdef WOLFSSL_TLS13 + int certChainCnt; +#endif DerBuffer* privateKey; WOLFSSL_CERT_MANAGER* cm; /* our cert manager, ctx owns SSL will use */ #endif @@ -1979,6 +2143,10 @@ struct WOLFSSL_CTX { byte minDowngrade; /* minimum downgrade version */ byte haveEMS; /* have extended master secret extension */ byte useClientOrder; /* Use client's cipher preference order */ +#ifdef WOLFSSL_TLS13 + byte noTicketTls13; /* Server won't create new Ticket */ + byte noPskDheKe; /* Don't use (EC)DHE with PSK */ +#endif #if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS) byte dtlsSctp; /* DTLS-over-SCTP mode */ word16 dtlsMtuSz; /* DTLS MTU size */ @@ -2105,6 +2273,7 @@ int DeriveTlsKeys(WOLFSSL* ssl); WOLFSSL_LOCAL int ProcessOldClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 inSz, word16 sz); + #ifndef NO_CERTS WOLFSSL_LOCAL int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify); @@ -2275,6 +2444,21 @@ typedef struct Hashes { #endif } Hashes; +WOLFSSL_LOCAL int BuildCertHashes(WOLFSSL* ssl, Hashes* hashes); + +#ifdef WOLFSSL_TLS13 +typedef union Digest { +#ifndef NO_WOLFSSL_SHA256 + Sha256 sha256; +#endif +#ifdef WOLFSSL_SHA384 + Sha384 sha384; +#endif +#ifdef WOLFSSL_SHA512 + Sha512 sha512; +#endif +} Digest; +#endif /* Static x509 buffer */ typedef struct x509_buffer { @@ -2300,6 +2484,9 @@ struct WOLFSSL_SESSION { word16 haveEMS; /* ext master secret flag */ #ifdef SESSION_CERTS WOLFSSL_X509_CHAIN chain; /* peer cert chain, static */ +#endif +#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ + defined(HAVE_SESSION_TICKET)) ProtocolVersion version; /* which version was used */ byte cipherSuite0; /* first byte, normally 0 */ byte cipherSuite; /* 2nd byte, actual suite */ @@ -2309,6 +2496,11 @@ struct WOLFSSL_SESSION { byte serverID[SERVER_ID_LEN]; /* for easier client lookup */ #endif #ifdef HAVE_SESSION_TICKET + #ifdef WOLFSSL_TLS13 + byte namedGroup; + word32 ticketSeen; /* Time ticket seen (ms) */ + word32 ticketAdd; /* Added by client */ + #endif byte* ticket; word16 ticketLen; byte staticTicket[SESSION_TICKET_LEN]; @@ -2354,9 +2546,12 @@ enum ConnectState { enum AcceptState { ACCEPT_BEGIN = 0, ACCEPT_CLIENT_HELLO_DONE, + ACCEPT_HELLO_RETRY_REQUEST_DONE, ACCEPT_FIRST_REPLY_DONE, SERVER_HELLO_SENT, + SERVER_EXTENSIONS_SENT, CERT_SENT, + CERT_VERIFY_SENT, CERT_STATUS_SENT, KEY_EXCHANGE_SENT, CERT_REQ_SENT, @@ -2396,6 +2591,9 @@ typedef struct Buffers { DerBuffer* key; /* WOLFSSL_CTX owns, unless we own */ DerBuffer* certChain; /* WOLFSSL_CTX owns, unless we own */ /* chain after self, in DER, with leading size for each cert */ +#ifdef WOLFSSL_TLS13 + int certChainCnt; +#endif #endif #ifdef WOLFSSL_DTLS WOLFSSL_DTLS_CTX dtlsCtx; /* DTLS connection context */ @@ -2413,6 +2611,16 @@ typedef struct Buffers { #endif /* HAVE_PK_CALLBACKS */ } Buffers; +/* sub-states for send/do key share (key exchange) */ +enum asyncState { + TLS_ASYNC_BEGIN = 0, + TLS_ASYNC_BUILD, + TLS_ASYNC_DO, + TLS_ASYNC_VERIFY, + TLS_ASYNC_FINALIZE, + TLS_ASYNC_END +}; + typedef struct Options { #ifndef NO_PSK wc_psk_client_callback client_psk_cb; @@ -2440,6 +2648,7 @@ typedef struct Options { word16 haveSessionId:1; /* server may not send */ word16 tls:1; /* using TLS ? */ word16 tls1_1:1; /* using TLSv1.1+ ? */ + word16 tls1_3:1; /* using TLSv1.3+ ? */ word16 dtls:1; /* using datagrams ? */ word16 connReset:1; /* has the peer reset */ word16 isClosed:1; /* if we consider conn closed */ @@ -2457,6 +2666,7 @@ typedef struct Options { word16 havePeerVerify:1; /* and peer's cert verify */ word16 usingPSK_cipher:1; /* are using psk as cipher */ word16 usingAnon_cipher:1; /* are we using an anon cipher */ + word16 noPskDheKe:1; /* Don't use (EC)DHE with PSK */ word16 sendAlertState:1; /* nonblocking resume */ word16 partialWrite:1; /* only one msg per write call */ word16 quietShutdown:1; /* don't send close notify */ @@ -2476,6 +2686,9 @@ typedef struct Options { word16 createTicket:1; /* Server to create new Ticket */ word16 useTicket:1; /* Use Ticket not session cache */ word16 rejectTicket:1; /* Callback rejected ticket */ +#ifdef WOLFSSL_TLS13 + word16 noTicketTls13:1; /* Server won't create new Ticket */ +#endif #endif #ifdef WOLFSSL_DTLS word16 dtlsHsRetain:1; /* DTLS retaining HS data */ @@ -2532,6 +2745,11 @@ typedef struct Arrays { byte serverRandom[RAN_LEN]; byte sessionID[ID_LEN]; byte sessionIDSz; +#ifdef WOLFSSL_TLS13 + byte clientSecret[SECRET_LEN]; + byte serverSecret[SECRET_LEN]; + byte secret[SECRET_LEN]; +#endif byte masterSecret[SECRET_LEN]; #ifdef WOLFSSL_DTLS byte cookie[MAX_COOKIE_LEN]; @@ -2715,10 +2933,12 @@ typedef struct DtlsMsg { /* Handshake messages received from peer (plus change cipher */ typedef struct MsgsReceived { word16 got_hello_request:1; - word16 got_client_hello:1; + word16 got_client_hello:2; word16 got_server_hello:1; word16 got_hello_verify_request:1; word16 got_session_ticket:1; + word16 got_hello_retry_request:1; + word16 got_encrypted_extensions:1; word16 got_certificate:1; word16 got_certificate_status:1; word16 got_server_key_exchange:1; @@ -2727,6 +2947,7 @@ typedef struct MsgsReceived { word16 got_certificate_verify:1; word16 got_client_key_exchange:1; word16 got_finished:1; + word16 got_key_update:1; word16 got_change_cipher:1; } MsgsReceived; @@ -2859,6 +3080,9 @@ struct WOLFSSL { byte maxRequest; byte user_set_QSHSchemes; #endif +#ifdef WOLFSSL_TLS13 + word16 namedGroup; +#endif #ifdef HAVE_NTRU word16 peerNtruKeyLen; byte peerNtruKey[MAX_NTRU_PUB_KEY_SZ]; @@ -2906,6 +3130,9 @@ struct WOLFSSL { CallbackFuzzer fuzzerCb; /* for testing with using fuzzer */ void* fuzzerCtx; /* user defined pointer */ #endif +#ifdef WOLFSSL_TLS13 + buffer clientCertCtx; /* Certificate context in request */ +#endif #ifdef KEEP_PEER_CERT WOLFSSL_X509 peerCert; /* X509 peer cert */ #endif @@ -3095,6 +3322,8 @@ enum HandShakeType { server_hello = 2, hello_verify_request = 3, /* DTLS addition */ session_ticket = 4, + hello_retry_request = 6, + encrypted_extensions = 8, certificate = 11, server_key_exchange = 12, certificate_request = 13, @@ -3103,6 +3332,7 @@ enum HandShakeType { client_key_exchange = 16, finished = 20, certificate_status = 22, + key_update = 24, change_cipher_hs = 55, /* simulate unique handshake type for sanity checks. record layer change_cipher conflicts with handshake finished */ @@ -3122,13 +3352,27 @@ WOLFSSL_LOCAL int SendChangeCipher(WOLFSSL*); WOLFSSL_LOCAL int SendTicket(WOLFSSL*); WOLFSSL_LOCAL int DoClientTicket(WOLFSSL*, const byte*, word32); WOLFSSL_LOCAL int SendData(WOLFSSL*, const void*, int); +#ifdef WOLFSSL_TLS13 +WOLFSSL_LOCAL int SendTls13HelloRetryRequest(WOLFSSL*); +WOLFSSL_LOCAL int SendTls13EncryptedExtensions(WOLFSSL*); +#endif WOLFSSL_LOCAL int SendCertificate(WOLFSSL*); +#ifdef WOLFSSL_TLS13 +WOLFSSL_LOCAL int SendTls13Certificate(WOLFSSL*); +#endif WOLFSSL_LOCAL int SendCertificateRequest(WOLFSSL*); +#ifdef WOLFSSL_TLS13 +WOLFSSL_LOCAL int SendTls13CertificateRequest(WOLFSSL*); +#endif WOLFSSL_LOCAL int SendCertificateStatus(WOLFSSL*); WOLFSSL_LOCAL int SendServerKeyExchange(WOLFSSL*); WOLFSSL_LOCAL int SendBuffered(WOLFSSL*); WOLFSSL_LOCAL int ReceiveData(WOLFSSL*, byte*, int, int); WOLFSSL_LOCAL int SendFinished(WOLFSSL*); +#ifdef WOLFSSL_TLS13 +WOLFSSL_LOCAL int SendTls13Finished(WOLFSSL*); +WOLFSSL_LOCAL int SendTls13NewSessionTicket(WOLFSSL*); +#endif WOLFSSL_LOCAL int SendAlert(WOLFSSL*, int, int); WOLFSSL_LOCAL int ProcessReply(WOLFSSL*); @@ -3141,6 +3385,7 @@ WOLFSSL_LOCAL int StoreKeys(WOLFSSL* ssl, const byte* keyData); WOLFSSL_LOCAL int IsTLS(const WOLFSSL* ssl); WOLFSSL_LOCAL int IsAtLeastTLSv1_2(const WOLFSSL* ssl); +WOLFSSL_LOCAL int IsAtLeastTLSv1_3(const ProtocolVersion pv); WOLFSSL_LOCAL void FreeHandshakeResources(WOLFSSL* ssl); WOLFSSL_LOCAL void ShrinkInputBuffer(WOLFSSL* ssl, int forcedFree); @@ -3208,12 +3453,20 @@ WOLFSSL_LOCAL int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength); #ifndef NO_WOLFSSL_CLIENT WOLFSSL_LOCAL int SendClientHello(WOLFSSL*); + #ifdef WOLFSSL_TLS13 + WOLFSSL_LOCAL int SendTls13ClientHello(WOLFSSL*); + #endif WOLFSSL_LOCAL int SendClientKeyExchange(WOLFSSL*); WOLFSSL_LOCAL int SendCertificateVerify(WOLFSSL*); #endif /* NO_WOLFSSL_CLIENT */ + WOLFSSL_LOCAL int SendTls13CertificateVerify(WOLFSSL*); + #ifndef NO_WOLFSSL_SERVER WOLFSSL_LOCAL int SendServerHello(WOLFSSL*); + #ifdef WOLFSSL_TLS13 + WOLFSSL_LOCAL int SendTls13ServerHello(WOLFSSL*); + #endif WOLFSSL_LOCAL int SendServerHelloDone(WOLFSSL*); #endif /* NO_WOLFSSL_SERVER */ @@ -3240,7 +3493,9 @@ WOLFSSL_LOCAL int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength); #endif /* NO_TLS */ - +#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) + WOLFSSL_LOCAL word32 TimeNowInMilliseconds(void); +#endif WOLFSSL_LOCAL word32 LowResTimer(void); #ifndef NO_CERTS @@ -3284,10 +3539,18 @@ WOLFSSL_LOCAL int SetKeysSide(WOLFSSL*, enum encrypt_side); WOLFSSL_LOCAL int EccMakeKey(WOLFSSL* ssl, ecc_key* key, ecc_key* peer); #endif +WOLFSSL_LOCAL int InitHandshakeHashes(WOLFSSL* ssl); +WOLFSSL_LOCAL void FreeHandshakeHashes(WOLFSSL* ssl); + WOLFSSL_LOCAL int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, int inSz, int type, int hashOutput, int sizeOnly, int asyncOkay); +#ifdef WOLFSSL_TLS13 +int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input, + int inSz, int type, int hashOutput, int sizeOnly); +#endif + WOLFSSL_LOCAL int AllocKey(WOLFSSL* ssl, int type, void** pKey); WOLFSSL_LOCAL void FreeKey(WOLFSSL* ssl, int type, void** pKey); diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index d254a3df7..db7d25dab 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -270,6 +270,10 @@ WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_1_server_method_ex(void* heap); WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_1_client_method_ex(void* heap); WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_2_server_method_ex(void* heap); WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_2_client_method_ex(void* heap); +#ifdef WOLFSSL_TLS13 + WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_3_server_method_ex(void* heap); + WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_3_client_method_ex(void* heap); +#endif WOLFSSL_API WOLFSSL_METHOD *wolfSSLv23_server_method_ex(void* heap); WOLFSSL_API WOLFSSL_METHOD *wolfSSLv23_client_method_ex(void* heap); @@ -288,6 +292,10 @@ WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_1_server_method(void); WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_1_client_method(void); WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_2_server_method(void); WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_2_client_method(void); +#ifdef WOLFSSL_TLS13 + WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_3_server_method(void); + WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_3_client_method(void); +#endif #ifdef WOLFSSL_DTLS WOLFSSL_API WOLFSSL_METHOD *wolfDTLSv1_client_method(void); @@ -382,12 +390,23 @@ WOLFSSL_API const char* wolfSSL_get_curve_name(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_get_fd(const WOLFSSL*); WOLFSSL_API void wolfSSL_set_using_nonblock(WOLFSSL*, int); WOLFSSL_API int wolfSSL_get_using_nonblock(WOLFSSL*); -WOLFSSL_API int wolfSSL_connect(WOLFSSL*); /* please see note at top of README - if you get an error from connect */ +/* please see note at top of README if you get an error from connect */ +WOLFSSL_API int wolfSSL_connect(WOLFSSL*); +#ifdef WOLFSSL_TLS13 +WOLFSSL_API int wolfSSL_connect_TLSv13(WOLFSSL*); +#endif WOLFSSL_API int wolfSSL_write(WOLFSSL*, const void*, int); WOLFSSL_API int wolfSSL_read(WOLFSSL*, void*, int); WOLFSSL_API int wolfSSL_peek(WOLFSSL*, void*, int); WOLFSSL_API int wolfSSL_accept(WOLFSSL*); +#ifdef WOLFSSL_TLS13 +WOLFSSL_API int wolfSSL_CTX_no_ticket_TLSv13(WOLFSSL_CTX* ctx); +WOLFSSL_API int wolfSSL_no_ticket_TLSv13(WOLFSSL* ssl); +WOLFSSL_API int wolfSSL_CTX_no_dhe_psk(WOLFSSL_CTX* ctx); +WOLFSSL_API int wolfSSL_no_dhe_psk(WOLFSSL* ssl); +WOLFSSL_API int wolfSSL_update_keys(WOLFSSL* ssl); +WOLFSSL_API int wolfSSL_accept_TLSv13(WOLFSSL*); +#endif WOLFSSL_API void wolfSSL_CTX_free(WOLFSSL_CTX*); WOLFSSL_API void wolfSSL_free(WOLFSSL*); WOLFSSL_API int wolfSSL_shutdown(WOLFSSL*); @@ -1784,7 +1803,7 @@ WOLFSSL_API int wolfSSL_CTX_UseOCSPStaplingV2(WOLFSSL_CTX* ctx, #endif #endif -/* Elliptic Curves */ +/* Named Groups */ enum { #if 0 /* Not Supported */ WOLFSSL_ECC_SECT163K1 = 1, @@ -1816,6 +1835,19 @@ enum { WOLFSSL_ECC_BRAINPOOLP256R1 = 26, WOLFSSL_ECC_BRAINPOOLP384R1 = 27, WOLFSSL_ECC_BRAINPOOLP512R1 = 28, +#ifdef WOLFSSL_TLS13 + /* Not implemented. */ + WOLFSSL_ECC_X25519 = 29, + /* Not implemented. */ + WOLFSSL_ECC_X448 = 30, + + /* Not implemented. */ + WOLFSSL_FFDHE_2048 = 256, + WOLFSSL_FFDHE_3072 = 257, + WOLFSSL_FFDHE_4096 = 258, + WOLFSSL_FFDHE_6144 = 259, + WOLFSSL_FFDHE_8192 = 260, +#endif }; #ifdef HAVE_SUPPORTED_CURVES @@ -1828,6 +1860,11 @@ WOLFSSL_API int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx, #endif #endif +#ifdef WOLFSSL_TLS13 +WOLFSSL_API int wolfSSL_UseKeyShare(WOLFSSL* ssl, unsigned short group); +WOLFSSL_API int wolfSSL_NoKeyShares(WOLFSSL* ssl); +#endif + /* Secure Renegotiation */ #ifdef HAVE_SECURE_RENEGOTIATION diff --git a/wolfssl/wolfcrypt/dh.h b/wolfssl/wolfcrypt/dh.h index be40c5c11..e4753e42c 100644 --- a/wolfssl/wolfcrypt/dh.h +++ b/wolfssl/wolfcrypt/dh.h @@ -37,6 +37,12 @@ #ifdef WOLFSSL_ASYNC_CRYPT #include #endif +typedef struct DhParams { + const byte* p; + word32 p_len; + const byte* g; + word32 g_len; +} DhParams; /* Diffie-Hellman Key */ typedef struct DhKey { @@ -48,6 +54,22 @@ typedef struct DhKey { } DhKey; +#ifdef HAVE_FFDHE_2048 +WOLFSSL_API const DhParams* wc_Dh_ffdhe2048_Get(void); +#endif +#ifdef HAVE_FFDHE_3072 +WOLFSSL_API const DhParams* wc_Dh_ffdhe3072_Get(void); +#endif +#ifdef HAVE_FFDHE_4096 +WOLFSSL_API const DhParams* wc_Dh_ffdhe4096_Get(void); +#endif +#ifdef HAVE_FFDHE_6144 +WOLFSSL_API const DhParams* wc_Dh_ffdhe6144_Get(void); +#endif +#ifdef HAVE_FFDHE_8192 +WOLFSSL_API const DhParams* wc_Dh_ffdhe8192_Get(void); +#endif + WOLFSSL_API int wc_InitDhKey(DhKey* key); WOLFSSL_API int wc_InitDhKey_ex(DhKey* key, void* heap, int devId); WOLFSSL_API void wc_FreeDhKey(DhKey* key); diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index 24e78359d..df29e7168 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -150,6 +150,14 @@ typedef enum ecc_curve_id { ECC_BRAINPOOLP320R1, ECC_BRAINPOOLP384R1, ECC_BRAINPOOLP512R1, + + /* Twisted Edwards Curves */ +#ifdef HAVE_CURVE25519 + ECC_X25519, +#endif +#ifdef HAVE_X448 + ECC_X448, +#endif } ecc_curve_id; #ifdef HAVE_OID_ENCODING diff --git a/wolfssl/wolfcrypt/hmac.h b/wolfssl/wolfcrypt/hmac.h index bf7154a64..9501b84b6 100644 --- a/wolfssl/wolfcrypt/hmac.h +++ b/wolfssl/wolfcrypt/hmac.h @@ -180,10 +180,18 @@ WOLFSSL_API void wc_HmacFree(Hmac*); WOLFSSL_API int wolfSSL_GetHmacMaxSize(void); #ifdef HAVE_HKDF - WOLFSSL_API int wc_HKDF(int type, const byte* inKey, word32 inKeySz, - const byte* salt, word32 saltSz, - const byte* info, word32 infoSz, - byte* out, word32 outSz); + +WOLFSSL_API int wc_HKDF_Extract(int type, const byte* salt, word32 saltSz, + const byte* inKey, word32 inKeySz, byte* out); +WOLFSSL_API int wc_HKDF_Expand(int type, const byte* inKey, word32 inKeySz, + const byte* info, word32 infoSz, + byte* out, word32 outSz); + +WOLFSSL_API int wc_HKDF(int type, const byte* inKey, word32 inKeySz, + const byte* salt, word32 saltSz, + const byte* info, word32 infoSz, + byte* out, word32 outSz); + #endif /* HAVE_HKDF */ #ifdef __cplusplus diff --git a/wolfssl/wolfcrypt/logging.h b/wolfssl/wolfcrypt/logging.h index 93bcee33e..4b3f4f72f 100755 --- a/wolfssl/wolfcrypt/logging.h +++ b/wolfssl/wolfcrypt/logging.h @@ -79,7 +79,7 @@ WOLFSSL_API int wolfSSL_SetLoggingCb(wolfSSL_Logging_cb log_function); WOLFSSL_MSG(WOLFSSL_LOG_CAT(wolfSSL Stub, m, not implemented)) void WOLFSSL_MSG(const char* msg); - void WOLFSSL_BUFFER(byte* buffer, word32 length); + void WOLFSSL_BUFFER(const byte* buffer, word32 length); #else /* DEBUG_WOLFSSL */