mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 11:20:55 +02:00
testing + bug fixes for TLS ECH
This commit is contained in:
@@ -0,0 +1,312 @@
|
||||
name: OpenSSL ECH Interop Test
|
||||
|
||||
# START OF COMMON SECTION
|
||||
on:
|
||||
push:
|
||||
branches: [ 'master', 'main', 'release/**' ]
|
||||
pull_request:
|
||||
branches: [ '*' ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
# END OF COMMON SECTION
|
||||
|
||||
jobs:
|
||||
build_wolfssl:
|
||||
name: Build wolfSSL
|
||||
if: github.repository_owner == 'wolfssl'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 4
|
||||
steps:
|
||||
- name: Build wolfSSL
|
||||
uses: wolfSSL/actions-build-autotools-project@v1
|
||||
with:
|
||||
path: wolfssl
|
||||
configure: --enable-ech CFLAGS='-DUSE_FLAT_TEST_H'
|
||||
install: true
|
||||
|
||||
- name: tar build-dir
|
||||
run: |
|
||||
# need server.h and client.h which are not installed normally
|
||||
cp "$GITHUB_WORKSPACE/wolfssl/examples/server/server.h" \
|
||||
build-dir/share/doc/wolfssl/example/server.h
|
||||
cp "$GITHUB_WORKSPACE/wolfssl/examples/client/client.h" \
|
||||
build-dir/share/doc/wolfssl/example/client.h
|
||||
|
||||
# need certs so 'wolfSSL error: wolf root not found' does not show up
|
||||
cp -r "$GITHUB_WORKSPACE/wolfssl/certs" build-dir/certs
|
||||
tar -zcf build-dir.tgz build-dir
|
||||
|
||||
- name: Upload built wolfSSL
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: wolf-install-openssl-ech
|
||||
path: build-dir.tgz
|
||||
retention-days: 5
|
||||
|
||||
build_openssl_ech:
|
||||
name: Build OpenSSL (feature/ech)
|
||||
if: github.repository_owner == 'wolfssl'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Checkout OpenSSL feature/ech branch
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: openssl/openssl
|
||||
ref: feature/ech
|
||||
path: openssl
|
||||
|
||||
- name: Build OpenSSL
|
||||
working-directory: openssl
|
||||
run: |
|
||||
./Configure --prefix=$GITHUB_WORKSPACE/openssl-install \
|
||||
--openssldir=$GITHUB_WORKSPACE/openssl-install/ssl \
|
||||
enable-ech no-docs
|
||||
make -j$(nproc)
|
||||
make install_sw
|
||||
|
||||
- name: tar openssl-install
|
||||
run: tar -zcf openssl-install.tgz openssl-install
|
||||
|
||||
- name: Upload built OpenSSL
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: openssl-ech-install
|
||||
path: openssl-install.tgz
|
||||
retention-days: 5
|
||||
|
||||
ech_server_interop_test:
|
||||
name: ECH Server Interop Test
|
||||
if: github.repository_owner == 'wolfssl'
|
||||
needs: [build_wolfssl, build_openssl_ech]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Download wolfSSL build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: wolf-install-openssl-ech
|
||||
|
||||
- name: Download OpenSSL build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: openssl-ech-install
|
||||
|
||||
- name: Extract builds
|
||||
run: |
|
||||
tar -xzf build-dir.tgz
|
||||
tar -xzf openssl-install.tgz
|
||||
|
||||
- name: Build wolfssl server example
|
||||
run: |
|
||||
export WOLFSSL_INSTALL_DIR="$GITHUB_WORKSPACE/build-dir"
|
||||
export WOLFSSL_BIN_DIR="$WOLFSSL_INSTALL_DIR/bin"
|
||||
export CFLAGS="-Wall -I$WOLFSSL_INSTALL_DIR/include"
|
||||
export LIBS="-L$WOLFSSL_INSTALL_DIR/lib -lm -lwolfssl"
|
||||
export LD_LIBRARY_PATH="$WOLFSSL_INSTALL_DIR/lib/:$LD_LIBRARY_PATH"
|
||||
|
||||
gcc -o "$WOLFSSL_BIN_DIR/server" \
|
||||
"$WOLFSSL_INSTALL_DIR/share/doc/wolfssl/example/server.c" \
|
||||
$CFLAGS $LIBS -I"$WOLFSSL_INSTALL_DIR/share/doc/wolfssl/example"
|
||||
|
||||
- name: ECH interop - wolfSSL server, OpenSSL client
|
||||
run: |
|
||||
set -e
|
||||
|
||||
export LD_LIBRARY_PATH="$GITHUB_WORKSPACE/openssl-install/lib64:$GITHUB_WORKSPACE/openssl-install/lib:$GITHUB_WORKSPACE/build-dir/lib:$LD_LIBRARY_PATH"
|
||||
|
||||
OPENSSL=$GITHUB_WORKSPACE/openssl-install/bin/openssl
|
||||
WOLFSSL_SERVER=$GITHUB_WORKSPACE/build-dir/bin/server
|
||||
|
||||
CERT_DIR="$GITHUB_WORKSPACE/build-dir/certs"
|
||||
READY_FILE="$GITHUB_WORKSPACE/wolfssl_tls13_ready$$"
|
||||
LOG_FILE="$GITHUB_WORKSPACE/log_file.log"
|
||||
PRIV_NAME="ech-private-name.com"
|
||||
PUB_NAME="ech-public-name.com"
|
||||
ECH_CONFIG=""
|
||||
PORT=0
|
||||
|
||||
rm -f "$READY_FILE"
|
||||
|
||||
# need to cd into build-dir so the certs/ dir is available for server
|
||||
cd build-dir
|
||||
|
||||
$OPENSSL version | tee "$LOG_FILE"
|
||||
|
||||
# start server with ephemeral port + ready file
|
||||
# also set server to be line buffered so the log can be grepped
|
||||
stdbuf -oL $WOLFSSL_SERVER \
|
||||
-v 4 \
|
||||
-R "$READY_FILE" \
|
||||
-p "$PORT" \
|
||||
-S "$PRIV_NAME" \
|
||||
--ech "$PUB_NAME" \
|
||||
&>> "$LOG_FILE" &
|
||||
|
||||
# wait for server to be ready, then get port
|
||||
counter=0
|
||||
while [ ! -s "$READY_FILE" ]; do
|
||||
sleep 0.1
|
||||
counter=$((counter + 1))
|
||||
if [ "$counter" -gt 50 ]; then
|
||||
echo "ERROR: no ready file" &>> "$LOG_FILE"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
PORT="$(cat "$READY_FILE")"
|
||||
echo "parsed port: $PORT" &>> "$LOG_FILE"
|
||||
|
||||
# get ECH config from server
|
||||
counter=0
|
||||
while [ -z "$ECH_CONFIG" ]; do
|
||||
ECH_CONFIG=$(grep -m1 "ECH config (base64): " "$LOG_FILE" \
|
||||
2>/dev/null | sed 's/ECH config (base64): //g')
|
||||
sleep 0.1
|
||||
counter=$((counter + 1))
|
||||
if [ "$counter" -gt 50 ]; then
|
||||
echo "ERROR: no ECH configs" &>> "$LOG_FILE"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
echo "parsed ech config: $ECH_CONFIG" &>> "$LOG_FILE"
|
||||
|
||||
# Test with OpenSSL s_client using ECH
|
||||
echo "wolfssl" | $OPENSSL s_client \
|
||||
-tls1_3 \
|
||||
-connect "localhost:$PORT" \
|
||||
-cert "$CERT_DIR/client-cert.pem" \
|
||||
-key "$CERT_DIR/client-key.pem" \
|
||||
-CAfile "$CERT_DIR/ca-cert.pem" \
|
||||
-servername "$PRIV_NAME" \
|
||||
-ech_config_list "$ECH_CONFIG" \
|
||||
&>> "$LOG_FILE"
|
||||
|
||||
grep "ECH: success: 1" "$LOG_FILE"
|
||||
|
||||
# cleanup
|
||||
rm -f "$READY_FILE"
|
||||
rm -f "$LOG_FILE"
|
||||
|
||||
- name: Print debug info on failure
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
if [ -s "$GITHUB_WORKSPACE/log_file.log" ]; then
|
||||
cat "$GITHUB_WORKSPACE/log_file.log"
|
||||
else
|
||||
echo "No log file"
|
||||
fi
|
||||
|
||||
ech_client_interop_test:
|
||||
name: ECH Client Interop Test
|
||||
if: github.repository_owner == 'wolfssl'
|
||||
needs: [build_wolfssl, build_openssl_ech]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Download wolfSSL build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: wolf-install-openssl-ech
|
||||
|
||||
- name: Download OpenSSL build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: openssl-ech-install
|
||||
|
||||
- name: Extract builds
|
||||
run: |
|
||||
tar -xzf build-dir.tgz
|
||||
tar -xzf openssl-install.tgz
|
||||
|
||||
- name: Build wolfssl client example
|
||||
run: |
|
||||
export WOLFSSL_INSTALL_DIR="$GITHUB_WORKSPACE/build-dir"
|
||||
export WOLFSSL_BIN_DIR="$WOLFSSL_INSTALL_DIR/bin"
|
||||
export CFLAGS="-Wall -I$WOLFSSL_INSTALL_DIR/include"
|
||||
export LIBS="-L$WOLFSSL_INSTALL_DIR/lib -lm -lwolfssl"
|
||||
export LD_LIBRARY_PATH="$WOLFSSL_INSTALL_DIR/lib/:$LD_LIBRARY_PATH"
|
||||
|
||||
gcc -o "$WOLFSSL_BIN_DIR/client" \
|
||||
"$WOLFSSL_INSTALL_DIR/share/doc/wolfssl/example/client.c" \
|
||||
$CFLAGS $LIBS -I"$WOLFSSL_INSTALL_DIR/share/doc/wolfssl/example"
|
||||
|
||||
- name: ECH interop - wolfSSL client, OpenSSL server
|
||||
run: |
|
||||
set -e
|
||||
|
||||
export LD_LIBRARY_PATH="$GITHUB_WORKSPACE/openssl-install/lib64:$GITHUB_WORKSPACE/openssl-install/lib:$GITHUB_WORKSPACE/build-dir/lib:$LD_LIBRARY_PATH"
|
||||
|
||||
OPENSSL=$GITHUB_WORKSPACE/openssl-install/bin/openssl
|
||||
WOLFSSL_CLIENT=$GITHUB_WORKSPACE/build-dir/bin/client
|
||||
|
||||
CERT_DIR="$GITHUB_WORKSPACE/build-dir/certs"
|
||||
LOG_FILE="$GITHUB_WORKSPACE/log_file.log"
|
||||
ECH_FILE="$GITHUB_WORKSPACE/ech_config.pem"
|
||||
PRIV_NAME="ech-private-name.com"
|
||||
PUB_NAME="ech-public-name.com"
|
||||
PORT=""
|
||||
ECH_CONFIG=""
|
||||
|
||||
rm -f "$ECH_FILE"
|
||||
|
||||
# need to cd into build-dir so the certs/ dir is available for client
|
||||
cd build-dir
|
||||
|
||||
$OPENSSL version | tee "$LOG_FILE"
|
||||
|
||||
$OPENSSL ech -public_name "$PUB_NAME" -out "$ECH_FILE" &>> "$LOG_FILE"
|
||||
|
||||
# parse ECH config from file
|
||||
ECH_CONFIG=$(sed -n '/BEGIN ECHCONFIG/,/END ECHCONFIG/{/BEGIN ECHCONFIG\|END ECHCONFIG/d;p}' "$ECH_FILE" | tr -d '\n')
|
||||
echo "parsed ech config: $ECH_CONFIG" &>> "$LOG_FILE"
|
||||
|
||||
# start OpenSSL ECH server with ephemeral port and make sure it is
|
||||
# line-buffered
|
||||
stdbuf -oL $OPENSSL s_server \
|
||||
-tls1_3 \
|
||||
-cert "$CERT_DIR/server-cert.pem" \
|
||||
-key "$CERT_DIR/server-key.pem" \
|
||||
-cert2 "$CERT_DIR/server-cert.pem" \
|
||||
-key2 "$CERT_DIR/server-key.pem" \
|
||||
-ech_key "$ECH_FILE" \
|
||||
-servername "$PRIV_NAME" \
|
||||
-accept 0 \
|
||||
-naccept 1 \
|
||||
&>> "$LOG_FILE" <<< "wolfssl!" &
|
||||
|
||||
# wait for server port to be ready and capture it
|
||||
counter=0
|
||||
while [ -z "$PORT" ]; do
|
||||
PORT=$(grep -m1 "ACCEPT" "$LOG_FILE" | sed 's/.*:\([0-9]*\)$/\1/')
|
||||
sleep 0.1
|
||||
counter=$((counter + 1))
|
||||
if [ "$counter" -gt 50 ]; then
|
||||
echo "ERROR: server port not found" &>> "$LOG_FILE"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
echo "parsed port: $PORT" &>> "$LOG_FILE"
|
||||
|
||||
# test with wolfssl client
|
||||
$WOLFSSL_CLIENT -v 4 \
|
||||
-p "$PORT" \
|
||||
-S "$PRIV_NAME" \
|
||||
--ech "$ECH_CONFIG" \
|
||||
&>> "$LOG_FILE"
|
||||
|
||||
grep "ech_success=1" "$LOG_FILE"
|
||||
|
||||
# cleanup
|
||||
rm -f "$LOG_FILE"
|
||||
rm -f "$ECH_FILE"
|
||||
|
||||
- name: Print debug info on failure
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
if [ -s "$GITHUB_WORKSPACE/log_file.log" ]; then
|
||||
cat "$GITHUB_WORKSPACE/log_file.log"
|
||||
else
|
||||
echo "No log file"
|
||||
fi
|
||||
@@ -52,10 +52,14 @@ static const char *wolfsentry_config_path = NULL;
|
||||
#endif
|
||||
|
||||
#include <wolfssl/test.h>
|
||||
|
||||
#include <examples/client/client.h>
|
||||
#include <wolfssl/error-ssl.h>
|
||||
|
||||
#ifdef USE_FLAT_TEST_H
|
||||
#include "client.h"
|
||||
#else
|
||||
#include "examples/client/client.h"
|
||||
#endif
|
||||
|
||||
#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS)
|
||||
|
||||
|
||||
@@ -1171,7 +1175,7 @@ static int ClientWriteRead(WOLFSSL* ssl, const char* msg, int msgSz,
|
||||
/* 4. add the same message into Japanese section */
|
||||
/* (will be translated later) */
|
||||
/* 5. add printf() into suitable position of Usage() */
|
||||
static const char* client_usage_msg[][79] = {
|
||||
static const char* client_usage_msg[][80] = {
|
||||
/* English */
|
||||
{
|
||||
" NOTE: All files relative to wolfSSL home dir\n", /* 0 */
|
||||
@@ -1425,10 +1429,15 @@ static const char* client_usage_msg[][79] = {
|
||||
#endif
|
||||
#ifdef HAVE_ECC_BRAINPOOL
|
||||
"--bpKs Use Brainpool ECC group for key share\n", /* 77 */
|
||||
#endif
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
"--ech <base64> Use Encrypted Client Hello with base64 encoded "
|
||||
"ECH configs\n",
|
||||
/* 78 */
|
||||
#endif
|
||||
"\n"
|
||||
"For simpler wolfSSL TLS client examples, visit\n"
|
||||
"https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 78 */
|
||||
"https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 79 */
|
||||
NULL,
|
||||
},
|
||||
#ifndef NO_MULTIBYTE_PRINT
|
||||
@@ -1931,6 +1940,9 @@ static void Usage(void)
|
||||
#endif
|
||||
#ifdef HAVE_ECC_BRAINPOOL
|
||||
printf("%s", msg[++msgid]); /* --bpKs */
|
||||
#endif
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
printf("%s", msg[++msgid]); /* --ech */
|
||||
#endif
|
||||
printf("%s", msg[++msgid]); /* --files-are-der */
|
||||
printf("%s", msg[++msgid]); /* Documentation Hint */
|
||||
@@ -2119,6 +2131,9 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
|
||||
#endif /* WOLFSSL_SYS_CRYPTO_POLICY */
|
||||
#ifdef HAVE_ECC_BRAINPOOL
|
||||
{ "bpKs", 0, 270 },
|
||||
#endif
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
{ "ech", 1, 271 },
|
||||
#endif
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
@@ -2187,6 +2202,9 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
|
||||
#ifdef HAVE_SNI
|
||||
char* sniHostName = NULL;
|
||||
#endif
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
char* echConfigs64 = NULL;
|
||||
#endif
|
||||
#ifdef HAVE_TRUSTED_CA
|
||||
int trustedCaKeyId = 0;
|
||||
#endif
|
||||
@@ -3013,6 +3031,11 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
case 271:
|
||||
echConfigs64 = myoptarg;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
Usage();
|
||||
@@ -3878,6 +3901,16 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
|
||||
err_sys("unable to get SSL object");
|
||||
}
|
||||
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
if (echConfigs64 != NULL) {
|
||||
if (wolfSSL_SetEchConfigsBase64(ssl, echConfigs64,
|
||||
(word32)XSTRLEN(echConfigs64)) != WOLFSSL_SUCCESS) {
|
||||
wolfSSL_CTX_free(ctx); ctx = NULL;
|
||||
err_sys("SetEchConfigsBase64 failed");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_DUAL_ALG_CERTS
|
||||
if (!wolfSSL_UseCKS(ssl, cks_order, sizeof(cks_order))) {
|
||||
wolfSSL_CTX_free(ctx); ctx = NULL;
|
||||
|
||||
@@ -48,6 +48,10 @@
|
||||
#include <wolfssl/wolfcrypt/ecc.h> /* wc_ecc_fp_free */
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
#include <wolfssl/wolfcrypt/coding.h>
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_WOLFSENTRY_HOOKS
|
||||
#include <wolfsentry/wolfsentry.h>
|
||||
#if !defined(NO_FILESYSTEM) && !defined(WOLFSENTRY_NO_JSON)
|
||||
@@ -73,7 +77,11 @@ static const char *wolfsentry_config_path = NULL;
|
||||
#include <wolfssl/test.h>
|
||||
#include <wolfssl/error-ssl.h>
|
||||
|
||||
#include "examples/server/server.h"
|
||||
#ifdef USE_FLAT_TEST_H
|
||||
#include "server.h"
|
||||
#else
|
||||
#include "examples/server/server.h"
|
||||
#endif
|
||||
|
||||
#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS)
|
||||
|
||||
@@ -911,7 +919,7 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519,
|
||||
/* 4. add the same message into Japanese section */
|
||||
/* (will be translated later) */
|
||||
/* 5. add printf() into suitable position of Usage() */
|
||||
static const char* server_usage_msg[][66] = {
|
||||
static const char* server_usage_msg[][69] = {
|
||||
/* English */
|
||||
{
|
||||
" NOTE: All files relative to wolfSSL home dir\n", /* 0 */
|
||||
@@ -1107,11 +1115,16 @@ static const char* server_usage_msg[][66] = {
|
||||
#endif
|
||||
#ifdef WOLFSSL_SYS_CRYPTO_POLICY
|
||||
"--crypto-policy <path to crypto policy file>\n", /* 66 */
|
||||
#endif
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
"--ech <name> Generate Encrypted Client Hello config with "
|
||||
"public name <name>\n",
|
||||
/* 67 */
|
||||
#endif
|
||||
"\n"
|
||||
"For simpler wolfSSL TLS server examples, visit\n"
|
||||
"https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n",
|
||||
/* 67 */
|
||||
/* 68 */
|
||||
NULL,
|
||||
},
|
||||
#ifndef NO_MULTIBYTE_PRINT
|
||||
@@ -1486,6 +1499,9 @@ static void Usage(void)
|
||||
#endif
|
||||
#ifdef WOLFSSL_DUAL_ALG_CERTS
|
||||
printf("%s", msg[++msgId]); /* --altPrivKey */
|
||||
#endif
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
printf("%s", msg[++msgId]); /* --ech */
|
||||
#endif
|
||||
printf("%s", msg[++msgId]); /* Examples repo link */
|
||||
}
|
||||
@@ -1609,6 +1625,9 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args)
|
||||
#if defined(WOLFSSL_SYS_CRYPTO_POLICY)
|
||||
{ "crypto-policy", 1, 268 },
|
||||
#endif /* WOLFSSL_SYS_CRYPTO_POLICY */
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
{ "ech", 1, 269 },
|
||||
#endif
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
#endif
|
||||
@@ -1685,6 +1704,9 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args)
|
||||
#ifdef HAVE_SNI
|
||||
char* sniHostName = NULL;
|
||||
#endif
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
char* echPublicName = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TRUSTED_CA
|
||||
int trustedCaKeyId = 0;
|
||||
@@ -2513,6 +2535,11 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args)
|
||||
policy = myoptarg;
|
||||
#endif /* WOLFSSL_SYS_CRYPTO_POLICY */
|
||||
break;
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
case 269:
|
||||
echPublicName = myoptarg;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case -1:
|
||||
default:
|
||||
@@ -3073,6 +3100,32 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args)
|
||||
err_sys_ex(runWithErrors, "UseSNI failed");
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ECH
|
||||
if (echPublicName != NULL) {
|
||||
byte echConfig[512];
|
||||
word32 echConfigLen = sizeof(echConfig);
|
||||
char echConfigBase64[512];
|
||||
word32 echConfigBase64Len = sizeof(echConfigBase64);
|
||||
|
||||
if (wolfSSL_CTX_GenerateEchConfig(ctx, echPublicName, 0, 0, 0)
|
||||
!= WOLFSSL_SUCCESS) {
|
||||
err_sys_ex(runWithErrors, "GenerateEchConfig failed");
|
||||
}
|
||||
if (wolfSSL_CTX_GetEchConfigs(ctx, echConfig, &echConfigLen)
|
||||
!= WOLFSSL_SUCCESS) {
|
||||
err_sys_ex(runWithErrors, "GetEchConfigs failed");
|
||||
}
|
||||
if (Base64_Encode_NoNl(echConfig, echConfigLen, (byte*)echConfigBase64,
|
||||
&echConfigBase64Len) != 0) {
|
||||
err_sys_ex(runWithErrors, "Base64_Encode_NoNl failed");
|
||||
}
|
||||
else {
|
||||
echConfigBase64[echConfigBase64Len] = '\0';
|
||||
printf("ECH config (base64): %s\n", echConfigBase64);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_WINDOWS_API
|
||||
if (port == 0) {
|
||||
/* Generate random port for testing */
|
||||
|
||||
+1
-2
@@ -8634,10 +8634,9 @@ void wolfSSL_ResourceFree(WOLFSSL* ssl)
|
||||
ForceZero(&ssl->serverSecret, sizeof(ssl->serverSecret));
|
||||
|
||||
#if defined(HAVE_ECH)
|
||||
if (ssl->options.useEch == 1) {
|
||||
if (ssl->echConfigs != NULL) {
|
||||
FreeEchConfigs(ssl->echConfigs, ssl->heap);
|
||||
ssl->echConfigs = NULL;
|
||||
ssl->options.useEch = 0;
|
||||
}
|
||||
#endif /* HAVE_ECH */
|
||||
#endif /* WOLFSSL_TLS13 */
|
||||
|
||||
+13
-16
@@ -36,7 +36,6 @@ int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName,
|
||||
int ret = 0;
|
||||
word16 encLen = DHKEM_X25519_ENC_LEN;
|
||||
WOLFSSL_EchConfig* newConfig;
|
||||
WOLFSSL_EchConfig* parentConfig;
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
Hpke* hpke = NULL;
|
||||
WC_RNG* rng;
|
||||
@@ -67,7 +66,9 @@ int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName,
|
||||
else
|
||||
XMEMSET(newConfig, 0, sizeof(WOLFSSL_EchConfig));
|
||||
|
||||
/* set random config id */
|
||||
/* set random configId */
|
||||
/* TODO: if an equal configId is found should the old config be removed from
|
||||
* the LL? Prevents growth beyond 255+ items */
|
||||
if (ret == 0)
|
||||
ret = wc_RNG_GenerateByte(rng, &newConfig->configId);
|
||||
|
||||
@@ -147,17 +148,14 @@ int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName,
|
||||
}
|
||||
}
|
||||
else {
|
||||
parentConfig = ctx->echConfigs;
|
||||
|
||||
if (parentConfig == NULL) {
|
||||
/* insert new configs at beginning of LL as preference should be given
|
||||
* to the most recently generated configs */
|
||||
if (ctx->echConfigs == NULL) {
|
||||
ctx->echConfigs = newConfig;
|
||||
}
|
||||
else {
|
||||
while (parentConfig->next != NULL) {
|
||||
parentConfig = parentConfig->next;
|
||||
}
|
||||
|
||||
parentConfig->next = newConfig;
|
||||
newConfig->next = ctx->echConfigs;
|
||||
ctx->echConfigs = newConfig;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,7 +248,7 @@ void wolfSSL_CTX_SetEchEnable(WOLFSSL_CTX* ctx, byte enable)
|
||||
|
||||
/* set the ech config from base64 for our client ssl object, base64 is the
|
||||
* format ech configs are sent using dns records */
|
||||
int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, char* echConfigs64,
|
||||
int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, const char* echConfigs64,
|
||||
word32 echConfigs64Len)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -261,7 +259,7 @@ int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, char* echConfigs64,
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
/* already have ech configs */
|
||||
if (ssl->options.useEch == 1) {
|
||||
if (ssl->echConfigs != NULL) {
|
||||
return WOLFSSL_FATAL_ERROR;
|
||||
}
|
||||
|
||||
@@ -274,7 +272,7 @@ int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, char* echConfigs64,
|
||||
decodedConfigs[decodedLen - 1] = 0;
|
||||
|
||||
/* decode the echConfigs */
|
||||
ret = Base64_Decode((byte*)echConfigs64, echConfigs64Len,
|
||||
ret = Base64_Decode((const byte*)echConfigs64, echConfigs64Len,
|
||||
decodedConfigs, &decodedLen);
|
||||
|
||||
if (ret != 0) {
|
||||
@@ -300,7 +298,7 @@ int wolfSSL_SetEchConfigs(WOLFSSL* ssl, const byte* echConfigs,
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
/* already have ech configs */
|
||||
if (ssl->options.useEch == 1) {
|
||||
if (ssl->echConfigs != NULL) {
|
||||
return WOLFSSL_FATAL_ERROR;
|
||||
}
|
||||
|
||||
@@ -309,7 +307,6 @@ int wolfSSL_SetEchConfigs(WOLFSSL* ssl, const byte* echConfigs,
|
||||
|
||||
/* if we found valid configs */
|
||||
if (ret == 0) {
|
||||
ssl->options.useEch = 1;
|
||||
return WOLFSSL_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -472,7 +469,7 @@ int wolfSSL_GetEchConfigs(WOLFSSL* ssl, byte* output, word32* outputLen)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
/* if we don't have ech configs */
|
||||
if (ssl->options.useEch != 1) {
|
||||
if (ssl->echConfigs == NULL) {
|
||||
return WOLFSSL_FATAL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@@ -2257,9 +2257,10 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, const byte* input, word16 length,
|
||||
byte type;
|
||||
byte matched;
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
TLSX* echX = NULL;
|
||||
WOLFSSL_ECH* ech = NULL;
|
||||
WOLFSSL_EchConfig* workingConfig;
|
||||
TLSX* echX;
|
||||
word16 privateNameLen;
|
||||
#endif
|
||||
#endif /* !NO_WOLFSSL_SERVER */
|
||||
TLSX *extension = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME);
|
||||
@@ -2291,7 +2292,22 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, const byte* input, word16 length,
|
||||
}
|
||||
|
||||
#ifndef NO_WOLFSSL_SERVER
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
if (!ssl->options.disableECH) {
|
||||
echX = TLSX_Find(ssl->extensions, TLSX_ECH);
|
||||
if (echX != NULL) {
|
||||
ech = (WOLFSSL_ECH*)(echX->data);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
if ((!extension || !extension->data) ||
|
||||
(ech != NULL && ech->sniState == ECH_INNER_SNI &&
|
||||
ech->privateName == NULL)) {
|
||||
#else
|
||||
if (!extension || !extension->data) {
|
||||
#endif
|
||||
/* This will keep SNI even though TLSX_UseSNI has not been called.
|
||||
* Enable it so that the received sni is available to functions
|
||||
* that use a custom callback when SNI is received.
|
||||
@@ -2339,24 +2355,52 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, const byte* input, word16 length,
|
||||
if (!cacheOnly && !(sni = TLSX_SNI_Find((SNI*)extension->data, type)))
|
||||
return 0; /* not using this type of SNI. */
|
||||
|
||||
#ifdef WOLFSSL_TLS13
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
if (ech != NULL && ech->sniState == ECH_INNER_SNI){
|
||||
/* SNI status is carried over from processing the outer hello so it is
|
||||
* necessary to clear it before processing the inner hello */
|
||||
ech->sniState = ECH_INNER_SNI_ATTEMPT;
|
||||
if (sni != NULL){
|
||||
sni->status = WOLFSSL_SNI_NO_MATCH;
|
||||
}
|
||||
}
|
||||
else if (ech != NULL && ech->sniState == ECH_OUTER_SNI &&
|
||||
ech->privateName == NULL && sni != NULL){
|
||||
/* save the private SNI before it is overwritten by the public SNI */
|
||||
privateNameLen = (word16)XSTRLEN(sni->data.host_name) + 1;
|
||||
ech->privateName = (char*)XMALLOC(privateNameLen, ssl->heap,
|
||||
DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (ech->privateName == NULL)
|
||||
return MEMORY_E;
|
||||
XMEMCPY((char*)ech->privateName, sni->data.host_name,
|
||||
privateNameLen);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_TLS13)
|
||||
/* Don't process the second ClientHello SNI extension if there
|
||||
* was problems with the first.
|
||||
*/
|
||||
if (!cacheOnly && sni->status != 0)
|
||||
if (!cacheOnly && sni->status != WOLFSSL_SNI_NO_MATCH)
|
||||
return 0;
|
||||
#endif
|
||||
matched = cacheOnly || (XSTRLEN(sni->data.host_name) == size &&
|
||||
XSTRNCMP(sni->data.host_name, (const char*)input + offset, size) == 0);
|
||||
|
||||
#if defined(HAVE_ECH)
|
||||
if (ech != NULL && ech->sniState == ECH_INNER_SNI_ATTEMPT) {
|
||||
matched = cacheOnly || (XSTRLEN(ech->privateName) == size &&
|
||||
XSTRNCMP(ech->privateName, (const char*)input + offset, size) == 0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
matched = cacheOnly || (XSTRLEN(sni->data.host_name) == size &&
|
||||
XSTRNCMP(sni->data.host_name, (const char*)input + offset,
|
||||
size) == 0);
|
||||
}
|
||||
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
echX = TLSX_Find(ssl->extensions, TLSX_ECH);
|
||||
if (echX != NULL)
|
||||
ech = (WOLFSSL_ECH*)(echX->data);
|
||||
|
||||
if (!matched && ech != NULL) {
|
||||
if (!matched && ech != NULL && ech->sniState == ECH_OUTER_SNI) {
|
||||
workingConfig = ech->echConfig;
|
||||
|
||||
while (workingConfig != NULL) {
|
||||
matched = XSTRLEN(workingConfig->publicName) == size &&
|
||||
XSTRNCMP(workingConfig->publicName,
|
||||
@@ -2374,6 +2418,7 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, const byte* input, word16 length,
|
||||
int matchStat;
|
||||
int r = TLSX_UseSNI(&ssl->extensions, type, input + offset, size,
|
||||
ssl->heap);
|
||||
|
||||
if (r != WOLFSSL_SUCCESS)
|
||||
return r; /* throws error. */
|
||||
|
||||
@@ -13922,13 +13967,12 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
|
||||
word16 len;
|
||||
|
||||
WOLFSSL_MSG("TLSX_ECH_Parse");
|
||||
|
||||
if (size == 0)
|
||||
return BAD_FUNC_ARG;
|
||||
if (ssl->options.disableECH) {
|
||||
WOLFSSL_MSG("TLSX_ECH_Parse: ECH disabled. Ignoring.");
|
||||
return 0;
|
||||
}
|
||||
if (size == 0)
|
||||
return BAD_FUNC_ARG;
|
||||
/* retry configs */
|
||||
if (msgType == encrypted_extensions) {
|
||||
ret = wolfSSL_SetEchConfigs(ssl, readBuf, size);
|
||||
@@ -13937,7 +13981,8 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
|
||||
ret = 0;
|
||||
}
|
||||
/* HRR with special confirmation */
|
||||
else if (msgType == hello_retry_request && ssl->options.useEch) {
|
||||
else if (msgType == hello_retry_request && ssl->echConfigs != NULL &&
|
||||
!ssl->options.disableECH) {
|
||||
/* length must be 8 */
|
||||
if (size != ECH_ACCEPT_CONFIRMATION_SZ)
|
||||
return BAD_FUNC_ARG;
|
||||
@@ -14055,6 +14100,7 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
|
||||
if (ret == 0) {
|
||||
i = 0;
|
||||
/* decrement until before the padding */
|
||||
/* TODO: verify padding is 0, abort with illegal_parameter */
|
||||
while (ech->innerClientHello[ech->innerClientHelloLen +
|
||||
HANDSHAKE_HEADER_SZ - i - 1] != ECH_TYPE_INNER) {
|
||||
i++;
|
||||
@@ -14090,6 +14136,8 @@ static void TLSX_ECH_Free(WOLFSSL_ECH* ech, void* heap)
|
||||
XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (ech->hpkeContext != NULL)
|
||||
XFREE(ech->hpkeContext, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (ech->privateName != NULL)
|
||||
XFREE((char*)ech->privateName, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
|
||||
XFREE(ech, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
(void)heap;
|
||||
@@ -15868,7 +15916,7 @@ int TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, word32* pLength)
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_ECH)
|
||||
if (ssl->options.useEch == 1 && !ssl->options.disableECH
|
||||
if (ssl->echConfigs != NULL && !ssl->options.disableECH
|
||||
&& msgType == client_hello) {
|
||||
ret = TLSX_GetSizeWithEch(ssl, semaphore, msgType, &length);
|
||||
if (ret != 0)
|
||||
@@ -16053,7 +16101,7 @@ int TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType, word32* pOffset)
|
||||
#endif
|
||||
#endif
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
if (ssl->options.useEch == 1 && !ssl->options.disableECH
|
||||
if (ssl->echConfigs != NULL && !ssl->options.disableECH
|
||||
&& msgType == client_hello) {
|
||||
ret = TLSX_WriteWithEch(ssl, output, semaphore,
|
||||
msgType, &offset);
|
||||
@@ -17332,7 +17380,8 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
|
||||
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
/* If client used ECH, server HRR must include ECH confirmation */
|
||||
if (ret == 0 && msgType == hello_retry_request && ssl->options.useEch == 1) {
|
||||
if (ret == 0 && msgType == hello_retry_request && ssl->echConfigs != NULL &&
|
||||
!ssl->options.disableECH) {
|
||||
TLSX* echX = TLSX_Find(ssl->extensions, TLSX_ECH);
|
||||
if (echX == NULL || ((WOLFSSL_ECH*)echX->data)->confBuf == NULL) {
|
||||
WOLFSSL_MSG("ECH used but HRR missing ECH confirmation");
|
||||
|
||||
+28
-11
@@ -4720,7 +4720,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
|
||||
|
||||
/* find length of outer and inner */
|
||||
#if defined(HAVE_ECH)
|
||||
if (ssl->options.useEch == 1 && !ssl->options.disableECH) {
|
||||
if (ssl->echConfigs != NULL && !ssl->options.disableECH) {
|
||||
TLSX* echX = TLSX_Find(ssl->extensions, TLSX_ECH);
|
||||
if (echX == NULL)
|
||||
return WOLFSSL_FATAL_ERROR;
|
||||
@@ -4874,7 +4874,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
|
||||
|
||||
#if defined(HAVE_ECH)
|
||||
/* write inner then outer */
|
||||
if (ssl->options.useEch == 1 && !ssl->options.disableECH &&
|
||||
if (ssl->echConfigs != NULL && !ssl->options.disableECH &&
|
||||
(ssl->options.echAccepted || args->ech->innerCount == 0)) {
|
||||
/* set the type to inner */
|
||||
args->ech->type = ECH_TYPE_INNER;
|
||||
@@ -4939,7 +4939,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
|
||||
|
||||
#if defined(HAVE_ECH)
|
||||
/* encrypt and pack the ech innerClientHello */
|
||||
if (ssl->options.useEch == 1 && !ssl->options.disableECH &&
|
||||
if (ssl->echConfigs != NULL && !ssl->options.disableECH &&
|
||||
(ssl->options.echAccepted || args->ech->innerCount == 0)) {
|
||||
ret = TLSX_FinalizeEch(args->ech,
|
||||
args->output + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ,
|
||||
@@ -4970,7 +4970,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
|
||||
{
|
||||
#if defined(HAVE_ECH)
|
||||
/* compute the inner hash */
|
||||
if (ssl->options.useEch == 1 && !ssl->options.disableECH &&
|
||||
if (ssl->echConfigs != NULL && !ssl->options.disableECH &&
|
||||
(ssl->options.echAccepted || args->ech->innerCount == 0)) {
|
||||
ret = EchHashHelloInner(ssl, args->ech);
|
||||
}
|
||||
@@ -5664,7 +5664,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
|
||||
#if defined(HAVE_ECH)
|
||||
/* check for acceptConfirmation, must be done after hashes restart */
|
||||
if (ssl->options.useEch == 1) {
|
||||
if (ssl->echConfigs != NULL && !ssl->options.disableECH) {
|
||||
args->echX = TLSX_Find(ssl->extensions, TLSX_ECH);
|
||||
/* account for hrr extension instead of server random */
|
||||
if (args->extMsgType == hello_retry_request) {
|
||||
@@ -7165,9 +7165,19 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
}
|
||||
|
||||
#if defined(HAVE_ECH)
|
||||
/* jump to the end to clean things up */
|
||||
if (echX != NULL && ((WOLFSSL_ECH*)echX->data)->state == ECH_WRITE_NONE)
|
||||
goto exit_dch;
|
||||
if (echX != NULL && ((WOLFSSL_ECH*)echX->data)->state == ECH_WRITE_NONE) {
|
||||
if (((WOLFSSL_ECH*)echX->data)->innerClientHello != NULL) {
|
||||
/* Client sent real ECH and inner hello was decrypted, jump to
|
||||
* exit so the caller can re-invoke with the inner hello */
|
||||
goto exit_dch;
|
||||
}
|
||||
else {
|
||||
/* Server has ECH but client did not send ECH. Clear the
|
||||
* response flag so the empty ECH extension is not written
|
||||
* in EncryptedExtensions. */
|
||||
echX->resp = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SNI
|
||||
@@ -7244,7 +7254,8 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
#if defined(HAVE_ECH)
|
||||
/* hash clientHelloInner to hsHashesEch */
|
||||
if (echX != NULL && ssl->ctx->echConfigs != NULL &&
|
||||
!ssl->options.disableECH) {
|
||||
!ssl->options.disableECH &&
|
||||
((WOLFSSL_ECH*)echX->data)->innerClientHello != NULL) {
|
||||
ret = EchHashHelloInner(ssl, (WOLFSSL_ECH*)echX->data);
|
||||
if (ret != 0)
|
||||
goto exit_dch;
|
||||
@@ -7503,7 +7514,8 @@ exit_dch:
|
||||
|
||||
#if defined(HAVE_ECH)
|
||||
if (ret == 0 && echX != NULL &&
|
||||
((WOLFSSL_ECH*)echX->data)->state == ECH_WRITE_NONE) {
|
||||
((WOLFSSL_ECH*)echX->data)->state == ECH_WRITE_NONE &&
|
||||
((WOLFSSL_ECH*)echX->data)->innerClientHello != NULL) {
|
||||
|
||||
/* add the header to the inner hello */
|
||||
AddTls13HandShakeHeader(((WOLFSSL_ECH*)echX->data)->innerClientHello,
|
||||
@@ -13072,16 +13084,21 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
echX = TLSX_Find(ssl->extensions, TLSX_ECH);
|
||||
|
||||
if (echX != NULL &&
|
||||
((WOLFSSL_ECH*)echX->data)->state == ECH_WRITE_NONE) {
|
||||
((WOLFSSL_ECH*)echX->data)->state == ECH_WRITE_NONE &&
|
||||
((WOLFSSL_ECH*)echX->data)->innerClientHello != NULL) {
|
||||
byte copyRandom = ((WOLFSSL_ECH*)echX->data)->innerCount == 0;
|
||||
/* reset the inOutIdx to the outer start */
|
||||
*inOutIdx = echInOutIdx;
|
||||
/* call again with the inner hello */
|
||||
if (ret == 0) {
|
||||
((WOLFSSL_ECH*)echX->data)->sniState = ECH_INNER_SNI;
|
||||
|
||||
ret = DoTls13ClientHello(ssl,
|
||||
((WOLFSSL_ECH*)echX->data)->innerClientHello,
|
||||
&echInOutIdx,
|
||||
((WOLFSSL_ECH*)echX->data)->innerClientHelloLen);
|
||||
|
||||
((WOLFSSL_ECH*)echX->data)->sniState = ECH_SNI_DONE;
|
||||
}
|
||||
/* if the inner ech parsed successfully we have successfully
|
||||
* handled the hello and can skip the whole message */
|
||||
|
||||
+708
-62
@@ -13790,6 +13790,7 @@ static int test_wolfSSL_CTX_add_client_CA(void)
|
||||
defined(HAVE_IO_TESTS_DEPENDENCIES)
|
||||
static THREAD_RETURN WOLFSSL_THREAD server_task_ech(void* args)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
callback_functions* callbacks = ((func_args*)args)->callbacks;
|
||||
WOLFSSL_CTX* ctx = callbacks->ctx;
|
||||
WOLFSSL* ssl = NULL;
|
||||
@@ -13814,15 +13815,17 @@ static THREAD_RETURN WOLFSSL_THREAD server_task_ech(void* args)
|
||||
|
||||
AssertIntEQ(WOLFSSL_SUCCESS,
|
||||
wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
|
||||
WOLFSSL_FILETYPE_PEM));
|
||||
WOLFSSL_FILETYPE_PEM));
|
||||
|
||||
if (callbacks->ctx_ready)
|
||||
callbacks->ctx_ready(ctx);
|
||||
|
||||
ssl = wolfSSL_new(ctx);
|
||||
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
||||
|
||||
/* set the sni for the server */
|
||||
wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, privateName, privateNameLen);
|
||||
AssertIntEQ(WOLFSSL_SUCCESS,
|
||||
wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, privateName,
|
||||
privateNameLen));
|
||||
|
||||
tcp_accept(&sfd, &cfd, (func_args*)args, port, 0, 0, 0, 0, 1, NULL, NULL);
|
||||
CloseSocket(sfd);
|
||||
@@ -13841,12 +13844,13 @@ static THREAD_RETURN WOLFSSL_THREAD server_task_ech(void* args)
|
||||
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
char buff[WOLFSSL_MAX_ERROR_SZ];
|
||||
fprintf(stderr, "error = %d, %s\n", err, wolfSSL_ERR_error_string(err, buff));
|
||||
fprintf(stderr, "error = %d, %s\n", err, wolfSSL_ERR_error_string(err,
|
||||
buff));
|
||||
}
|
||||
else {
|
||||
if (0 < (idx = wolfSSL_read(ssl, input, sizeof(input)-1))) {
|
||||
input[idx] = 0;
|
||||
fprintf(stderr, "Client message: %s\n", input);
|
||||
fprintf(stderr, "Client message: %s\n", input);
|
||||
}
|
||||
|
||||
AssertIntEQ(privateNameLen, wolfSSL_write(ssl, privateName,
|
||||
@@ -14058,20 +14062,27 @@ static int test_wolfSSL_Tls13_Key_Logging_test(void)
|
||||
#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK && WOLFSSL_TLS13 */
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) && \
|
||||
defined(HAVE_IO_TESTS_DEPENDENCIES)
|
||||
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
#if defined(HAVE_IO_TESTS_DEPENDENCIES)
|
||||
static int test_wolfSSL_Tls13_ECH_params(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_WOLFSSL_CLIENT)
|
||||
word32 outputLen = 0;
|
||||
byte testBuf[72];
|
||||
WOLFSSL_CTX *ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
|
||||
WOLFSSL *ssl = wolfSSL_new(ctx);
|
||||
byte testBuf[256];
|
||||
/* base64 ech configs from cloudflare-ech.com */
|
||||
const char* b64Configs =
|
||||
"AEX+DQBBFAAgACBuAoQI8+liEVYQbXKBDeVgTmF2rfXuKO2knhwrN7jgTgAEAAEAAQASY2xvdWRmbGFyZS1lY2guY29tAAA=";
|
||||
word32 outputLen = sizeof(testBuf);
|
||||
word16 tmpLen;
|
||||
WOLFSSL_CTX* ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
|
||||
WOLFSSL* ssl = wolfSSL_new(ctx);
|
||||
|
||||
ExpectNotNull(ctx);
|
||||
ExpectNotNull(ssl);
|
||||
|
||||
/* CTX NULL errors */
|
||||
|
||||
/* invalid ctx */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GenerateEchConfig(NULL,
|
||||
"ech-public-name.com", 0, 0, 0));
|
||||
@@ -14080,57 +14091,142 @@ static int test_wolfSSL_Tls13_ECH_params(void)
|
||||
0, 0));
|
||||
/* invalid algorithms */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GenerateEchConfig(ctx,
|
||||
"ech-public-name.com", 1000, 1000, 1000));
|
||||
"ech-public-name.com", 1000, 0, 0));
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GenerateEchConfig(ctx,
|
||||
"ech-public-name.com", 0, 1000, 0));
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GenerateEchConfig(ctx,
|
||||
"ech-public-name.com", 0, 0, 1000));
|
||||
|
||||
/* invalid ctx */
|
||||
/* invalid base64 configs: NULL ctx, NULL configs, 0 length */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigsBase64(NULL,
|
||||
(char*)testBuf, sizeof(testBuf)));
|
||||
/* invalid base64 configs */
|
||||
b64Configs, (word32)XSTRLEN(b64Configs)));
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigsBase64(ctx,
|
||||
NULL, sizeof(testBuf)));
|
||||
/* invalid length */
|
||||
NULL, (word32)XSTRLEN(b64Configs)));
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigsBase64(ctx,
|
||||
(char*)testBuf, 0));
|
||||
b64Configs, 0));
|
||||
|
||||
/* invalid ctx */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigs(NULL,
|
||||
testBuf, sizeof(testBuf)));
|
||||
/* invalid configs */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigs(ctx,
|
||||
NULL, sizeof(testBuf)));
|
||||
/* invalid length */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigs(ctx,
|
||||
testBuf, 0));
|
||||
|
||||
/* invalid ctx */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GetEchConfigs(NULL, NULL,
|
||||
&outputLen));
|
||||
/* invalid output len */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GetEchConfigs(ctx, NULL, NULL));
|
||||
|
||||
/* invalid ssl */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigsBase64(NULL,
|
||||
(char*)testBuf, sizeof(testBuf)));
|
||||
/* invalid configs64 */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigsBase64(ssl, NULL,
|
||||
/* invalid configs: NULL ctx, NULL configs, 0 length */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigs(NULL, testBuf,
|
||||
sizeof(testBuf)));
|
||||
/* invalid size */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigsBase64(ssl,
|
||||
(char*)testBuf, 0));
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigs(ctx, NULL,
|
||||
sizeof(testBuf)));
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigs(ctx, testBuf, 0));
|
||||
|
||||
/* invalid ssl */
|
||||
/* SSL NULL errors */
|
||||
|
||||
/* invalid base64 configs: NULL ssl, NULL configs, 0 length */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigsBase64(NULL, b64Configs,
|
||||
(word32)XSTRLEN(b64Configs)));
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigsBase64(ssl, NULL,
|
||||
(word32)XSTRLEN(b64Configs)));
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigsBase64(ssl, b64Configs,
|
||||
0));
|
||||
|
||||
/* invalid configs: NULL ssl, NULL configs, 0 length */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(NULL, testBuf,
|
||||
sizeof(testBuf)));
|
||||
/* invalid configs */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(ssl, NULL,
|
||||
sizeof(testBuf)));
|
||||
/* invalid size */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(ssl, testBuf, 0));
|
||||
|
||||
/* invalid ssl */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_GetEchConfigs(NULL, NULL, &outputLen));
|
||||
/* invalid size */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_GetEchConfigs(ssl, NULL, NULL));
|
||||
/* stateful errors */
|
||||
|
||||
/* actually generate configs */
|
||||
ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_GenerateEchConfig(ctx,
|
||||
"ech-public-name.com", 0, 0, 0));
|
||||
|
||||
/* bad get: NULL ctx, NULL output len, short output len */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GetEchConfigs(NULL, testBuf,
|
||||
&outputLen));
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GetEchConfigs(ctx, testBuf, NULL));
|
||||
outputLen = 5;
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GetEchConfigs(ctx, testBuf,
|
||||
&outputLen));
|
||||
|
||||
/* should be able to retrieve length with NULL buffer... */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_GetEchConfigs(ctx, NULL,
|
||||
&outputLen));
|
||||
ExpectIntGE(sizeof(testBuf), outputLen);
|
||||
|
||||
/* and the get should work with this length */
|
||||
ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_GetEchConfigs(ctx, testBuf,
|
||||
&outputLen));
|
||||
|
||||
/* reject config with invalid total length */
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ato16(testBuf, &tmpLen);
|
||||
testBuf[0] = 0xFF;
|
||||
testBuf[1] = 0xFF;
|
||||
}
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigs(ctx, testBuf,
|
||||
outputLen));
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(ssl, testBuf,
|
||||
outputLen));
|
||||
if (EXPECT_SUCCESS()) {
|
||||
c16toa(tmpLen, testBuf);
|
||||
}
|
||||
|
||||
/* reject config with invalid version */
|
||||
if (EXPECT_SUCCESS()) {
|
||||
testBuf[2] ^= 0x01;
|
||||
}
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigs(ctx, testBuf,
|
||||
outputLen));
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(ssl, testBuf,
|
||||
outputLen));
|
||||
if (EXPECT_SUCCESS()) {
|
||||
testBuf[2] ^= 0x01;
|
||||
}
|
||||
|
||||
/* reject config with bad length */
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ato16(testBuf + 4, &tmpLen);
|
||||
testBuf[4] = 0xFF;
|
||||
testBuf[5] = 0xFF;
|
||||
}
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigs(ctx, testBuf,
|
||||
outputLen));
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(ssl, testBuf,
|
||||
outputLen));
|
||||
if (EXPECT_SUCCESS()) {
|
||||
c16toa(tmpLen, testBuf + 4);
|
||||
}
|
||||
|
||||
/* set valid configs */
|
||||
ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigs(ctx, testBuf,
|
||||
outputLen));
|
||||
ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(ssl, testBuf,
|
||||
outputLen));
|
||||
|
||||
/* NULL ssl, NULL buffer, NULL output len */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_GetEchConfigs(NULL, testBuf,
|
||||
&outputLen));
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_GetEchConfigs(ssl, NULL, &outputLen));
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_GetEchConfigs(ssl, testBuf, NULL));
|
||||
|
||||
/* reject setting configs when ssl already has them */
|
||||
ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigs(ssl, testBuf,
|
||||
outputLen));
|
||||
|
||||
/* unable to get configs from ssl with no configs (because of disable) */
|
||||
wolfSSL_SetEchEnable(ssl, 0);
|
||||
outputLen = sizeof(testBuf);
|
||||
ExpectIntNE(WOLFSSL_SUCCESS,
|
||||
wolfSSL_GetEchConfigs(ssl, testBuf, &outputLen));
|
||||
|
||||
/* base64 tests */
|
||||
|
||||
/* set base64 configs */
|
||||
ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_SetEchConfigsBase64(ctx,
|
||||
b64Configs, (word32)XSTRLEN(b64Configs)));
|
||||
ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_SetEchConfigsBase64(ssl,
|
||||
b64Configs, (word32)XSTRLEN(b64Configs)));
|
||||
|
||||
/* disable and check ctx has no configs as well */
|
||||
wolfSSL_CTX_SetEchEnable(ctx, 0);
|
||||
outputLen = sizeof(testBuf);
|
||||
ExpectIntNE(WOLFSSL_SUCCESS,
|
||||
wolfSSL_CTX_GetEchConfigs(ctx, testBuf, &outputLen));
|
||||
|
||||
wolfSSL_free(ssl);
|
||||
wolfSSL_CTX_free(ctx);
|
||||
@@ -14139,7 +14235,8 @@ static int test_wolfSSL_Tls13_ECH_params(void)
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
static int test_wolfSSL_Tls13_ECH_ex(int hrr)
|
||||
static int test_wolfSSL_ECH_conn_ex(method_provider serverMeth,
|
||||
method_provider clientMeth, int hrr)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
tcp_ready ready;
|
||||
@@ -14166,11 +14263,10 @@ static int test_wolfSSL_Tls13_ECH_ex(int hrr)
|
||||
XMEMSET(&server_args, 0, sizeof(func_args));
|
||||
XMEMSET(&server_cbf, 0, sizeof(callback_functions));
|
||||
XMEMSET(&client_cbf, 0, sizeof(callback_functions));
|
||||
server_cbf.method = wolfTLSv1_3_server_method; /* TLS1.3 */
|
||||
server_cbf.method = serverMeth;
|
||||
|
||||
/* create the server context here so we can get the ech config */
|
||||
ExpectNotNull(server_cbf.ctx =
|
||||
wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
|
||||
ExpectNotNull(server_cbf.ctx = wolfSSL_CTX_new(serverMeth()));
|
||||
|
||||
/* generate ech config */
|
||||
ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_GenerateEchConfig(server_cbf.ctx,
|
||||
@@ -14188,10 +14284,10 @@ static int test_wolfSSL_Tls13_ECH_ex(int hrr)
|
||||
start_thread(server_task_ech, &server_args, &serverThread);
|
||||
wait_tcp_ready(&server_args);
|
||||
|
||||
/* run as a TLS1.3 client */
|
||||
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
|
||||
/* set the client TLS version and run */
|
||||
ExpectNotNull(ctx = wolfSSL_CTX_new(clientMeth()));
|
||||
ExpectIntEQ(WOLFSSL_SUCCESS,
|
||||
wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0));
|
||||
wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0));
|
||||
ExpectIntEQ(WOLFSSL_SUCCESS,
|
||||
wolfSSL_CTX_use_certificate_file(ctx, cliCertFile, SSL_FILETYPE_PEM));
|
||||
ExpectIntEQ(WOLFSSL_SUCCESS,
|
||||
@@ -14221,8 +14317,8 @@ static int test_wolfSSL_Tls13_ECH_ex(int hrr)
|
||||
ExpectIntEQ(wolfSSL_write(ssl, privateName, privateNameLen),
|
||||
privateNameLen);
|
||||
ExpectIntGT((replyLen = wolfSSL_read(ssl, reply, sizeof(reply))), 0);
|
||||
/* add th null terminator for string compare */
|
||||
reply[replyLen] = 0;
|
||||
/* add the null terminator for string compare */
|
||||
reply[replyLen] = '\0';
|
||||
/* check that the server replied with the private name */
|
||||
ExpectStrEQ(privateName, reply);
|
||||
wolfSSL_free(ssl);
|
||||
@@ -14239,13 +14335,553 @@ static int test_wolfSSL_Tls13_ECH_ex(int hrr)
|
||||
|
||||
static int test_wolfSSL_Tls13_ECH(void)
|
||||
{
|
||||
return test_wolfSSL_Tls13_ECH_ex(0);
|
||||
return test_wolfSSL_ECH_conn_ex(wolfTLSv1_3_server_method,
|
||||
wolfTLSv1_3_client_method, 0);
|
||||
}
|
||||
|
||||
static int test_wolfSSL_Tls13_ECH_HRR(void)
|
||||
{
|
||||
return test_wolfSSL_Tls13_ECH_ex(1);
|
||||
return test_wolfSSL_ECH_conn_ex(wolfTLSv1_3_server_method,
|
||||
wolfTLSv1_3_client_method, 1);
|
||||
}
|
||||
|
||||
static int test_wolfSSL_SubTls13_ECH(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
|
||||
#ifndef WOLFSSL_NO_TLS12
|
||||
ExpectIntNE(test_wolfSSL_ECH_conn_ex(wolfTLSv1_3_server_method,
|
||||
wolfTLSv1_2_client_method, 0), WOLFSSL_SUCCESS);
|
||||
ExpectIntNE(test_wolfSSL_ECH_conn_ex(wolfTLSv1_2_server_method,
|
||||
wolfTLSv1_3_client_method, 0), WOLFSSL_SUCCESS);
|
||||
ExpectIntNE(test_wolfSSL_ECH_conn_ex(wolfSSLv23_server_method,
|
||||
wolfTLSv1_2_client_method, 0), WOLFSSL_SUCCESS);
|
||||
#endif
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
#endif /* HAVE_IO_TESTS_DEPENDENCIES */
|
||||
|
||||
#ifdef HAVE_SSL_MEMIO_TESTS_DEPENDENCIES
|
||||
|
||||
/* Static storage for passing ECH config between server and client callbacks */
|
||||
static byte echCbTestConfigs[512];
|
||||
static word32 echCbTestConfigsLen;
|
||||
static const char* echCbTestPublicName = "ech-public-name.com";
|
||||
static const char* echCbTestPrivateName = "ech-private-name.com";
|
||||
|
||||
/* the arg is whether the client has ech enabled or not */
|
||||
static int test_ech_server_sni_callback(WOLFSSL* ssl, int* ad, void* arg)
|
||||
{
|
||||
const char* name;
|
||||
|
||||
if (!wolfSSL_SNI_GetRequest(ssl, WOLFSSL_SNI_HOST_NAME, (void**)&name)) {
|
||||
*ad = WOLFSSL_AD_UNRECOGNIZED_NAME;
|
||||
return fatal_return;
|
||||
}
|
||||
|
||||
/* reached by *_disable_conn test: expect name to be the public SNI when
|
||||
* client has ECH enabled, otherwise it should be the private SNI */
|
||||
if (arg != NULL && *(int*)arg == 1 &&
|
||||
XSTRCMP(name, echCbTestPublicName) == 0) {
|
||||
return 0;
|
||||
}
|
||||
else if (XSTRCMP(name, echCbTestPrivateName) == 0) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
*ad = WOLFSSL_AD_UNRECOGNIZED_NAME;
|
||||
return fatal_return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Server ctx_ready callback: generate ECH config */
|
||||
static int test_ech_server_ctx_ready(WOLFSSL_CTX* ctx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wolfSSL_CTX_GenerateEchConfig(ctx, echCbTestPublicName, 0, 0, 0);
|
||||
if (ret != WOLFSSL_SUCCESS)
|
||||
return TEST_FAIL;
|
||||
|
||||
echCbTestConfigsLen = sizeof(echCbTestConfigs);
|
||||
ret = wolfSSL_CTX_GetEchConfigs(ctx, echCbTestConfigs,
|
||||
&echCbTestConfigsLen);
|
||||
if (ret != WOLFSSL_SUCCESS)
|
||||
return TEST_FAIL;
|
||||
|
||||
return TEST_SUCCESS;
|
||||
}
|
||||
|
||||
/* Server ssl_ready callback: set SNI */
|
||||
static int test_ech_server_ssl_ready(WOLFSSL* ssl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, echCbTestPrivateName,
|
||||
(word16)XSTRLEN(echCbTestPrivateName));
|
||||
if (ret != WOLFSSL_SUCCESS)
|
||||
return TEST_FAIL;
|
||||
|
||||
return TEST_SUCCESS;
|
||||
}
|
||||
|
||||
/* Client ssl_ready callback: set ECH configs and SNI */
|
||||
static int test_ech_client_ssl_ready(WOLFSSL* ssl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wolfSSL_SetEchConfigs(ssl, echCbTestConfigs, echCbTestConfigsLen);
|
||||
if (ret != WOLFSSL_SUCCESS)
|
||||
return TEST_FAIL;
|
||||
|
||||
ret = wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, echCbTestPrivateName,
|
||||
(word16)XSTRLEN(echCbTestPrivateName));
|
||||
if (ret != WOLFSSL_SUCCESS)
|
||||
return TEST_FAIL;
|
||||
|
||||
return TEST_SUCCESS;
|
||||
}
|
||||
|
||||
/* Test ECH when no private SNI is set */
|
||||
static int test_wolfSSL_Tls13_ECH_no_private_name(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
struct test_ssl_memio_ctx test_ctx;
|
||||
|
||||
/* client sends private SNI, server does not have one set */
|
||||
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
|
||||
test_ctx.s_cb.method = wolfTLSv1_3_server_method;
|
||||
test_ctx.c_cb.method = wolfTLSv1_3_client_method;
|
||||
|
||||
test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
|
||||
test_ctx.c_cb.ssl_ready = test_ech_client_ssl_ready;
|
||||
|
||||
ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);
|
||||
|
||||
ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 1);
|
||||
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
/* client does not send private SNI, server has one set */
|
||||
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
|
||||
test_ctx.s_cb.method = wolfTLSv1_3_server_method;
|
||||
test_ctx.c_cb.method = wolfTLSv1_3_client_method;
|
||||
|
||||
test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
|
||||
test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;
|
||||
|
||||
ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);
|
||||
|
||||
ExpectIntEQ(wolfSSL_SetEchConfigs(test_ctx.c_ssl, echCbTestConfigs,
|
||||
echCbTestConfigsLen), WOLFSSL_SUCCESS);
|
||||
|
||||
ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
/* client does not send private SNI, server does not have one set */
|
||||
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
|
||||
test_ctx.s_cb.method = wolfTLSv1_3_server_method;
|
||||
test_ctx.c_cb.method = wolfTLSv1_3_client_method;
|
||||
|
||||
test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
|
||||
|
||||
ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);
|
||||
|
||||
ExpectIntEQ(wolfSSL_SetEchConfigs(test_ctx.c_ssl, echCbTestConfigs,
|
||||
echCbTestConfigsLen), WOLFSSL_SUCCESS);
|
||||
|
||||
ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* Test ECH rejection when configs don't match */
|
||||
static int test_wolfSSL_Tls13_ECH_bad_configs_ex(int hrr, int sniCb)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
struct test_ssl_memio_ctx test_ctx;
|
||||
WOLFSSL_CTX* tempCtx = NULL;
|
||||
const char* badPrivateName = "ech-bad-private-name.com";
|
||||
byte badPublicConfig[128];
|
||||
word32 badPublicConfigLen = sizeof(badPublicConfig);
|
||||
|
||||
/* verify with bad public SNI / config */
|
||||
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
|
||||
test_ctx.s_cb.method = wolfTLSv1_3_server_method;
|
||||
test_ctx.c_cb.method = wolfTLSv1_3_client_method;
|
||||
|
||||
/* server generates its own ECH config */
|
||||
test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
|
||||
test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;
|
||||
|
||||
ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);
|
||||
|
||||
/* generate throwaway ECH config for client to use */
|
||||
ExpectNotNull(tempCtx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
|
||||
ExpectIntEQ(wolfSSL_CTX_GenerateEchConfig(tempCtx, echCbTestPublicName,
|
||||
0, 0, 0), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_CTX_GetEchConfigs(tempCtx, badPublicConfig,
|
||||
&badPublicConfigLen), WOLFSSL_SUCCESS);
|
||||
wolfSSL_CTX_free(tempCtx);
|
||||
tempCtx = NULL;
|
||||
|
||||
/* set bad public config on client */
|
||||
ExpectIntEQ(wolfSSL_SetEchConfigs(test_ctx.c_ssl, badPublicConfig,
|
||||
badPublicConfigLen), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_UseSNI(test_ctx.c_ssl, WOLFSSL_SNI_HOST_NAME,
|
||||
echCbTestPrivateName, (word16)XSTRLEN(echCbTestPrivateName)),
|
||||
WOLFSSL_SUCCESS);
|
||||
|
||||
if (hrr) {
|
||||
ExpectIntEQ(wolfSSL_NoKeyShares(test_ctx.c_ssl), WOLFSSL_SUCCESS);
|
||||
}
|
||||
if (sniCb) {
|
||||
wolfSSL_CTX_set_servername_callback(test_ctx.s_ctx,
|
||||
test_ech_server_sni_callback);
|
||||
}
|
||||
|
||||
ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
|
||||
/* verify with bad private SNI */
|
||||
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
|
||||
test_ctx.s_cb.method = wolfTLSv1_3_server_method;
|
||||
test_ctx.c_cb.method = wolfTLSv1_3_client_method;
|
||||
|
||||
test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
|
||||
test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;
|
||||
|
||||
ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);
|
||||
|
||||
/* set bad private SNI on client */
|
||||
ExpectIntEQ(wolfSSL_SetEchConfigs(test_ctx.c_ssl, echCbTestConfigs,
|
||||
echCbTestConfigsLen), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_UseSNI(test_ctx.c_ssl, WOLFSSL_SNI_HOST_NAME,
|
||||
badPrivateName, (word16)XSTRLEN(badPrivateName)), WOLFSSL_SUCCESS);
|
||||
|
||||
if (hrr) {
|
||||
ExpectIntEQ(wolfSSL_NoKeyShares(test_ctx.c_ssl), WOLFSSL_SUCCESS);
|
||||
}
|
||||
if (sniCb) {
|
||||
wolfSSL_CTX_set_servername_callback(test_ctx.s_ctx,
|
||||
test_ech_server_sni_callback);
|
||||
}
|
||||
|
||||
ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
static int test_wolfSSL_Tls13_ECH_bad_configs(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
|
||||
ExpectIntEQ(test_wolfSSL_Tls13_ECH_bad_configs_ex(0, 0), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(test_wolfSSL_Tls13_ECH_bad_configs_ex(0, 1), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(test_wolfSSL_Tls13_ECH_bad_configs_ex(1, 0), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(test_wolfSSL_Tls13_ECH_bad_configs_ex(1, 1), WOLFSSL_SUCCESS);
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* Test that client info can be successfully decoded from one of multiple server
|
||||
* ECH configs
|
||||
* In this case the server is expected to try it's first config, fail, then try
|
||||
* its second config and succeed */
|
||||
static int test_wolfSSL_Tls13_ECH_new_config(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
test_ssl_memio_ctx test_ctx;
|
||||
byte altConfig[512];
|
||||
word32 altConfigLen = sizeof(altConfig);
|
||||
byte combinedConfigs[512];
|
||||
word32 combinedConfigsLen = sizeof(combinedConfigs);
|
||||
word16 firstConfigLen;
|
||||
word16 secondConfigOffset;
|
||||
word16 secondConfigLen;
|
||||
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
|
||||
test_ctx.s_cb.method = wolfTLSv1_3_server_method;
|
||||
test_ctx.c_cb.method = wolfTLSv1_3_client_method;
|
||||
|
||||
/* server generates its own ECH config */
|
||||
test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
|
||||
test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;
|
||||
|
||||
ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);
|
||||
|
||||
/* generate a second ECH config for the server */
|
||||
ExpectIntEQ(wolfSSL_CTX_GenerateEchConfig(test_ctx.s_ctx,
|
||||
echCbTestPrivateName, 0, 0, 0), WOLFSSL_SUCCESS);
|
||||
ExpectNotNull(test_ctx.s_ctx->echConfigs->next);
|
||||
|
||||
/* capture the second ECH config in the list for the client to use */
|
||||
ExpectIntEQ(wolfSSL_CTX_GetEchConfigs(test_ctx.s_ctx, combinedConfigs,
|
||||
&combinedConfigsLen), WOLFSSL_SUCCESS);
|
||||
|
||||
/* ECHConfigList: [2 byte list len] [ECHConfig]...
|
||||
* ECHConfig: [2 byte version] [2 byte config len] [config data] */
|
||||
ExpectIntGE(combinedConfigsLen, OPAQUE16_LEN * 3);
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ato16(combinedConfigs + OPAQUE16_LEN + OPAQUE16_LEN, &firstConfigLen);
|
||||
secondConfigOffset = OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN +
|
||||
firstConfigLen;
|
||||
ExpectIntGE(combinedConfigsLen,
|
||||
secondConfigOffset + OPAQUE16_LEN + OPAQUE16_LEN);
|
||||
}
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ato16(combinedConfigs + secondConfigOffset + OPAQUE16_LEN,
|
||||
&secondConfigLen);
|
||||
secondConfigLen += OPAQUE16_LEN + OPAQUE16_LEN;
|
||||
ExpectIntGE(combinedConfigsLen, secondConfigOffset + secondConfigLen);
|
||||
}
|
||||
if (EXPECT_SUCCESS()) {
|
||||
/* build the ECHConfigList */
|
||||
c16toa(secondConfigLen, altConfig);
|
||||
ExpectIntLE(OPAQUE16_LEN + secondConfigLen, (word16)sizeof(altConfig));
|
||||
if (EXPECT_SUCCESS()) {
|
||||
XMEMCPY(altConfig + OPAQUE16_LEN,
|
||||
combinedConfigs + secondConfigOffset, secondConfigLen);
|
||||
altConfigLen = OPAQUE16_LEN + secondConfigLen;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set client configs - server should try both and succeed with second
|
||||
* Or seek the correct one immediately through the configId */
|
||||
ExpectIntEQ(wolfSSL_SetEchConfigs(test_ctx.c_ssl, altConfig, altConfigLen),
|
||||
WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_UseSNI(test_ctx.c_ssl, WOLFSSL_SNI_HOST_NAME,
|
||||
echCbTestPrivateName, (word16)XSTRLEN(echCbTestPrivateName)),
|
||||
WOLFSSL_SUCCESS);
|
||||
|
||||
ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 1);
|
||||
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* Test GREASE ECH:
|
||||
* 1. client sends GREASE ECH extension but server has no ECH configs so it
|
||||
* ignores it, handshake succeeds normally, no ECH configs received
|
||||
* 2. client sends GREASE ECH extensions and server has ECH configs, handshake
|
||||
* succeeds and client receives ECH configs */
|
||||
static int test_wolfSSL_Tls13_ECH_GREASE(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
test_ssl_memio_ctx test_ctx;
|
||||
byte greaseConfigs[512];
|
||||
word32 greaseConfigsLen = sizeof(greaseConfigs);
|
||||
|
||||
/* GREASE when server has no ECH configs */
|
||||
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
|
||||
test_ctx.s_cb.method = wolfTLSv1_3_server_method;
|
||||
test_ctx.c_cb.method = wolfTLSv1_3_client_method;
|
||||
|
||||
ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);
|
||||
|
||||
ExpectIntEQ(wolfSSL_UseSNI(test_ctx.c_ssl, WOLFSSL_SNI_HOST_NAME,
|
||||
echCbTestPrivateName, (word16)XSTRLEN(echCbTestPrivateName)),
|
||||
WOLFSSL_SUCCESS);
|
||||
|
||||
/* verify ECH is enabled on the client and server */
|
||||
ExpectIntEQ(test_ctx.s_ssl->options.disableECH, 0);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.disableECH, 0);
|
||||
/* verify no ECH configs are set */
|
||||
ExpectNull(test_ctx.s_ctx->echConfigs);
|
||||
ExpectNull(test_ctx.c_ctx->echConfigs);
|
||||
|
||||
/* handshake should succeed - server ignores the GREASE ECH extension */
|
||||
ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
|
||||
/* ECH should NOT be accepted since this was GREASE */
|
||||
ExpectIntEQ(test_ctx.s_ssl->options.echAccepted, 0);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
ExpectIntNE(wolfSSL_GetEchConfigs(test_ctx.c_ssl, greaseConfigs,
|
||||
&greaseConfigsLen), WOLFSSL_SUCCESS);
|
||||
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
/* GREASE when server has ECH configs */
|
||||
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
|
||||
test_ctx.s_cb.method = wolfTLSv1_3_server_method;
|
||||
test_ctx.c_cb.method = wolfTLSv1_3_client_method;
|
||||
|
||||
/* generate ECH configs */
|
||||
test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
|
||||
test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;
|
||||
|
||||
ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);
|
||||
|
||||
ExpectIntEQ(wolfSSL_UseSNI(test_ctx.c_ssl, WOLFSSL_SNI_HOST_NAME,
|
||||
echCbTestPrivateName, (word16)XSTRLEN(echCbTestPrivateName)),
|
||||
WOLFSSL_SUCCESS);
|
||||
|
||||
/* verify ECH is enabled on the client and server */
|
||||
ExpectIntEQ(test_ctx.s_ssl->options.disableECH, 0);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.disableECH, 0);
|
||||
/* verify ECH configs are set on server */
|
||||
ExpectNotNull(test_ctx.s_ctx->echConfigs);
|
||||
ExpectNull(test_ctx.c_ctx->echConfigs);
|
||||
|
||||
/* handshake should succeed - server responds to the GREASE ECH extension */
|
||||
ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
|
||||
/* ECH should NOT be accepted since this was GREASE
|
||||
* However, configs will be present this time */
|
||||
ExpectIntEQ(test_ctx.s_ssl->options.echAccepted, 0);
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
ExpectIntEQ(wolfSSL_GetEchConfigs(test_ctx.c_ssl, greaseConfigs,
|
||||
&greaseConfigsLen), WOLFSSL_SUCCESS);
|
||||
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
static int test_wolfSSL_Tls13_ECH_disable_conn_ex(int enableServer,
|
||||
int enableClient)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
test_ssl_memio_ctx test_ctx;
|
||||
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
|
||||
test_ctx.s_cb.method = wolfTLSv1_3_server_method;
|
||||
test_ctx.c_cb.method = wolfTLSv1_3_client_method;
|
||||
|
||||
/* both server and client will be setup to use ECH */
|
||||
test_ctx.s_cb.ctx_ready = test_ech_server_ctx_ready;
|
||||
test_ctx.s_cb.ssl_ready = test_ech_server_ssl_ready;
|
||||
test_ctx.c_cb.ssl_ready = test_ech_client_ssl_ready;
|
||||
|
||||
ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);
|
||||
|
||||
/* this callback will ensure that the correct SNI is being held */
|
||||
wolfSSL_CTX_set_servername_callback(test_ctx.s_ctx,
|
||||
test_ech_server_sni_callback);
|
||||
ExpectIntEQ(wolfSSL_CTX_set_servername_arg(test_ctx.s_ctx, &enableClient),
|
||||
WOLFSSL_SUCCESS);
|
||||
|
||||
/* disable ECH on the appropriate side(s) */
|
||||
wolfSSL_SetEchEnable(test_ctx.s_ssl, enableServer);
|
||||
wolfSSL_SetEchEnable(test_ctx.c_ssl, enableClient);
|
||||
|
||||
if (!enableClient) {
|
||||
/* client ECH disabled: no ECH extension sent, handshake succeeds
|
||||
* normally but ECH is not accepted */
|
||||
ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL),
|
||||
TEST_SUCCESS);
|
||||
}
|
||||
else if (!enableServer) {
|
||||
/* client sends ECH but server can't process it: server has no ECH
|
||||
* keys so it processes the outer ClientHello, client detects ECH
|
||||
* rejection and aborts the handshake */
|
||||
ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL),
|
||||
TEST_SUCCESS);
|
||||
}
|
||||
ExpectIntEQ(test_ctx.c_ssl->options.echAccepted, 0);
|
||||
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* setup a server and client with ECH then disable on one, the other, or both.
|
||||
* Verifies that disabling ECH prevents ECH from being used and that the
|
||||
* public/private SNI's are verified correctly */
|
||||
static int test_wolfSSL_Tls13_ECH_disable_conn(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
|
||||
ExpectIntEQ(test_wolfSSL_Tls13_ECH_disable_conn_ex(0, 1), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_wolfSSL_Tls13_ECH_disable_conn_ex(1, 0), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_wolfSSL_Tls13_ECH_disable_conn_ex(0, 0), TEST_SUCCESS);
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
#endif /* HAVE_SSL_MEMIO_TESTS_DEPENDENCIES */
|
||||
|
||||
/* verify that ECH can be enabled/disabled without issue */
|
||||
static int test_wolfSSL_Tls13_ECH_enable_disable(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_WOLFSSL_CLIENT)
|
||||
WOLFSSL_CTX* ctx = NULL;
|
||||
WOLFSSL* ssl = NULL;
|
||||
byte echConfigs[128];
|
||||
word32 echConfigsLen = sizeof(echConfigs);
|
||||
|
||||
/* NULL ctx, NULL ssl should not crash */
|
||||
wolfSSL_SetEchEnable(ssl, 0);
|
||||
wolfSSL_CTX_SetEchEnable(ctx, 0);
|
||||
|
||||
/* test CTX level enable/disable */
|
||||
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
|
||||
|
||||
ExpectIntEQ(wolfSSL_CTX_GenerateEchConfig(ctx, "public.com", 0, 0, 0),
|
||||
WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_CTX_GetEchConfigs(ctx, echConfigs, &echConfigsLen),
|
||||
WOLFSSL_SUCCESS);
|
||||
|
||||
/* disable ECH at CTX level */
|
||||
wolfSSL_CTX_SetEchEnable(ctx, 0);
|
||||
ExpectIntEQ(ctx->disableECH, 1);
|
||||
ExpectNull(ctx->echConfigs);
|
||||
|
||||
wolfSSL_CTX_SetEchEnable(ctx, 1);
|
||||
ExpectIntEQ(ctx->disableECH, 0);
|
||||
|
||||
/* test SSL level enable/disable */
|
||||
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
||||
|
||||
ExpectIntEQ(wolfSSL_SetEchConfigs(ssl, echConfigs, echConfigsLen),
|
||||
WOLFSSL_SUCCESS);
|
||||
|
||||
/* disable ECH at SSL level */
|
||||
wolfSSL_SetEchEnable(ssl, 0);
|
||||
ExpectIntEQ(ssl->options.disableECH, 1);
|
||||
ExpectNull(ssl->echConfigs);
|
||||
|
||||
wolfSSL_SetEchEnable(ssl, 1);
|
||||
ExpectIntEQ(ssl->options.disableECH, 0);
|
||||
|
||||
wolfSSL_free(ssl);
|
||||
wolfSSL_CTX_free(ctx);
|
||||
#endif /* !NO_WOLFSSL_CLIENT */
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
#endif /* HAVE_ECH && WOLFSSL_TLS13 */
|
||||
|
||||
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && \
|
||||
@@ -33498,13 +34134,23 @@ TEST_CASE testCases[] = {
|
||||
TEST_DECL(test_wolfSSL_SCR_check_enabled),
|
||||
TEST_DECL(test_tls_ext_duplicate),
|
||||
TEST_DECL(test_tls_bad_legacy_version),
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) && \
|
||||
defined(HAVE_IO_TESTS_DEPENDENCIES)
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
#if defined(HAVE_IO_TESTS_DEPENDENCIES)
|
||||
TEST_DECL(test_wolfSSL_Tls13_ECH_params),
|
||||
/* Uses Assert in handshake callback. */
|
||||
TEST_DECL(test_wolfSSL_Tls13_ECH),
|
||||
TEST_DECL(test_wolfSSL_Tls13_ECH_HRR),
|
||||
TEST_DECL(test_wolfSSL_SubTls13_ECH),
|
||||
#endif
|
||||
#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
|
||||
TEST_DECL(test_wolfSSL_Tls13_ECH_no_private_name),
|
||||
TEST_DECL(test_wolfSSL_Tls13_ECH_bad_configs),
|
||||
TEST_DECL(test_wolfSSL_Tls13_ECH_new_config),
|
||||
TEST_DECL(test_wolfSSL_Tls13_ECH_GREASE),
|
||||
TEST_DECL(test_wolfSSL_Tls13_ECH_disable_conn),
|
||||
#endif
|
||||
TEST_DECL(test_wolfSSL_Tls13_ECH_enable_disable),
|
||||
#endif /* WOLFSSL_TLS13 && HAVE_ECH */
|
||||
|
||||
TEST_DECL(test_wolfSSL_X509_TLS_version_test_1),
|
||||
TEST_DECL(test_wolfSSL_X509_TLS_version_test_2),
|
||||
|
||||
+9
-1
@@ -3100,6 +3100,13 @@ typedef enum {
|
||||
ECH_PARSED_INTERNAL,
|
||||
} EchState;
|
||||
|
||||
typedef enum {
|
||||
ECH_OUTER_SNI,
|
||||
ECH_INNER_SNI,
|
||||
ECH_INNER_SNI_ATTEMPT,
|
||||
ECH_SNI_DONE,
|
||||
} EchStateSNI;
|
||||
|
||||
typedef struct EchCipherSuite {
|
||||
word16 kdfId;
|
||||
word16 aeadId;
|
||||
@@ -3122,6 +3129,7 @@ typedef struct WOLFSSL_ECH {
|
||||
Hpke* hpke;
|
||||
HpkeBaseContext* hpkeContext;
|
||||
const byte* aad;
|
||||
const char* privateName;
|
||||
void* ephemeralKey;
|
||||
WOLFSSL_EchConfig* echConfig;
|
||||
byte* innerClientHello;
|
||||
@@ -3134,6 +3142,7 @@ typedef struct WOLFSSL_ECH {
|
||||
word16 kemId;
|
||||
word16 encLen;
|
||||
EchState state;
|
||||
EchStateSNI sniState;
|
||||
byte type;
|
||||
byte configId;
|
||||
byte enc[HPKE_Npk_MAX];
|
||||
@@ -5156,7 +5165,6 @@ struct Options {
|
||||
word16 useDtlsCID:1;
|
||||
#endif /* WOLFSSL_DTLS_CID */
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
|
||||
word16 useEch:1;
|
||||
word16 echAccepted:1;
|
||||
byte disableECH:1; /* Did the user disable ech */
|
||||
#endif
|
||||
|
||||
+2
-2
@@ -1230,8 +1230,8 @@ WOLFSSL_API int wolfSSL_CTX_GetEchConfigs(WOLFSSL_CTX* ctx, byte* output,
|
||||
|
||||
WOLFSSL_API void wolfSSL_CTX_SetEchEnable(WOLFSSL_CTX* ctx, byte enable);
|
||||
|
||||
WOLFSSL_API int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, char* echConfigs64,
|
||||
word32 echConfigs64Len);
|
||||
WOLFSSL_API int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl,
|
||||
const char* echConfigs64, word32 echConfigs64Len);
|
||||
|
||||
WOLFSSL_API int wolfSSL_SetEchConfigs(WOLFSSL* ssl, const byte* echConfigs,
|
||||
word32 echConfigsLen);
|
||||
|
||||
Reference in New Issue
Block a user