Skip to content

Commit 15b8c88

Browse files
Write ECH last in HRR to promote interop
1 parent 9d938c1 commit 15b8c88

2 files changed

Lines changed: 103 additions & 59 deletions

File tree

.github/scripts/openssl-ech.sh

Lines changed: 91 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ usage() {
1515
exit 1
1616
}
1717

18+
# --------------------------------------------------------------------------
19+
# Argument parsing
20+
# --------------------------------------------------------------------------
1821
MODE=""
1922
SUITE=""
2023
PQC=""
@@ -38,24 +41,21 @@ while [ $# -gt 0 ]; do
3841
[ -z "$2" ] && { echo "ERROR: --suite requires a value"; exit 1; }
3942
SUITE="$2"
4043
shift 2
41-
echo ""
42-
echo "Using suite: $SUITE"
43-
echo ""
4444
;;
4545
--pqc)
4646
[ -z "$2" ] && { echo "ERROR: --pqc requires a value"; exit 1; }
4747
PQC="$2"
4848
shift 2
4949
;;
50+
--hrr)
51+
FORCE_HRR=1
52+
shift
53+
;;
5054
--workspace)
5155
[ -z "$2" ] && { echo "ERROR: --workspace requires a value"; exit 1; }
5256
WORKSPACE="$2"
5357
shift 2
5458
;;
55-
--hrr)
56-
FORCE_HRR=1
57-
shift
58-
;;
5959
*) echo "Unknown argument: $1"; usage ;;
6060
esac
6161
done
@@ -65,6 +65,20 @@ if [ "$FORCE_HRR" -ne 0 ] && [ -n "$PQC" ]; then
6565
exit 1
6666
fi
6767

68+
# Pick exactly one test variant. The variant decides which -groups go to
69+
# each side and any extra flags needed to drive the desired handshake.
70+
# default - both sides use secp256r1 (no HRR)
71+
# pqc - both sides use the chosen PQC group
72+
# hrr - pin one side to a group the other doesn't keyshare by
73+
# default, forcing the server to send HelloRetryRequest
74+
if [ -n "$PQC" ]; then
75+
VARIANT="pqc"
76+
elif [ "$FORCE_HRR" -ne 0 ]; then
77+
VARIANT="hrr"
78+
else
79+
VARIANT="default"
80+
fi
81+
6882
OPENSSL=${OPENSSL:-"openssl"}
6983
WOLFSSL_CLIENT=${WOLFSSL_CLIENT:-"$WORKSPACE/examples/client/client"}
7084
WOLFSSL_SERVER=${WOLFSSL_SERVER:-"$WORKSPACE/examples/server/server"}
@@ -75,30 +89,49 @@ PRIV_NAME="ech-private-name.com"
7589
PUB_NAME="ech-public-name.com"
7690
MAX_WAIT=50
7791

92+
# --------------------------------------------------------------------------
93+
# server mode -- OpenSSL is the server, wolfSSL is the client
94+
# --------------------------------------------------------------------------
7895
openssl_server(){
7996
local ech_file="$WORKSPACE/ech_config.pem"
8097
local ech_config=""
8198
local port=""
82-
local groups_arg=""
8399

84-
# restrict group based on arguments
85-
if [ "$FORCE_HRR" -eq 0 ]; then
86-
groups_arg="-groups secp256r1"
87-
if [ -n "$PQC" ]; then
88-
groups_arg="-groups ${PQC#--pqc }"
89-
fi
90-
fi
100+
# Per-variant args.
101+
# openssl_groups : -groups passed to OpenSSL s_server
102+
# openssl_suite : -suite passed to `openssl ech` for key generation
103+
# wolfssl_extra : extra flags for the wolfSSL client
104+
local openssl_groups=""
105+
local openssl_suite=""
106+
local wolfssl_extra=""
107+
108+
case "$VARIANT" in
109+
default)
110+
openssl_groups="-groups secp256r1"
111+
;;
112+
pqc)
113+
openssl_groups="-groups $PQC"
114+
wolfssl_extra="--pqc $PQC"
115+
;;
116+
hrr)
117+
# wolfSSL client keyshares X25519 by default; pin OpenSSL
118+
# server to secp384r1 so it must send HelloRetryRequest.
119+
openssl_groups="-groups secp384r1"
120+
;;
121+
esac
122+
[ -n "$SUITE" ] && openssl_suite="-suite $SUITE"
91123

92124
rm -f "$ech_file"
93125

94-
$OPENSSL ech -public_name "$PUB_NAME" -out "$ech_file" $SUITE &>> "$TMP_LOG"
126+
$OPENSSL ech -public_name "$PUB_NAME" -out "$ech_file" $openssl_suite \
127+
&>> "$TMP_LOG"
95128

96129
# parse ECH config from file
97130
ech_config=$(sed -n '/BEGIN ECHCONFIG/,/END ECHCONFIG/{/BEGIN ECHCONFIG\|END ECHCONFIG/d;p}' "$ech_file" | tr -d '\n')
98131
echo "parsed ech config: $ech_config" &>> "$TMP_LOG"
99132

100-
# start OpenSSL ECH server with ephemeral port and make sure it is
101-
# line-buffered
133+
# start OpenSSL ECH server with ephemeral port; line-buffer so the
134+
# log can be grepped
102135
stdbuf -oL $OPENSSL s_server \
103136
-tls1_3 \
104137
-cert "$CERT_DIR/server-cert.pem" \
@@ -107,7 +140,7 @@ openssl_server(){
107140
-key2 "$CERT_DIR/server-key.pem" \
108141
-ech_key "$ech_file" \
109142
-servername "$PRIV_NAME" \
110-
$groups_arg \
143+
$openssl_groups \
111144
-accept 0 \
112145
-naccept 1 \
113146
&>> "$TMP_LOG" <<< "wolfssl!" &
@@ -130,31 +163,61 @@ openssl_server(){
130163
-p "$port" \
131164
-S "$PRIV_NAME" \
132165
--ech "$ech_config" \
133-
$PQC \
166+
$wolfssl_extra \
134167
&>> "$TMP_LOG"
135168

136169
rm -f "$ech_file"
137170

138171
grep -q "ech_success=1" "$TMP_LOG"
139172
}
140173

174+
# --------------------------------------------------------------------------
175+
# client mode -- wolfSSL is the server, OpenSSL is the client
176+
# --------------------------------------------------------------------------
141177
openssl_client(){
142178
local ready_file="$WORKSPACE/wolfssl_tls13_ready$$"
143179
local ech_config=""
144180
local port=0
145181

182+
# Per-variant args.
183+
# openssl_groups : -groups passed to OpenSSL s_client
184+
# wolfssl_suite : --ech-suite passed to wolfSSL server for key gen
185+
# wolfssl_extra : extra flags for the wolfSSL server
186+
local openssl_groups=""
187+
local wolfssl_suite=""
188+
local wolfssl_extra=""
189+
190+
case "$VARIANT" in
191+
default)
192+
openssl_groups="-groups secp256r1"
193+
;;
194+
pqc)
195+
openssl_groups="-groups $PQC"
196+
wolfssl_extra="--pqc $PQC"
197+
;;
198+
hrr)
199+
# Pin wolfSSL server to SECP384R1 only. Have OpenSSL offer
200+
# X25519 as keyshare with P-384 in supported_groups: the
201+
# mismatched keyshare forces HelloRetryRequest, and P-384 in
202+
# supported_groups lets the client answer it.
203+
openssl_groups="-groups X25519:P-384"
204+
wolfssl_extra="--force-curve SECP384R1"
205+
;;
206+
esac
207+
[ -n "$SUITE" ] && wolfssl_suite="--ech-suite $SUITE"
208+
146209
rm -f "$ready_file"
147210

148-
# start server with ephemeral port + ready file
149-
# also set server to be line buffered so the log can be grepped
211+
# start server with ephemeral port + ready file; line-buffer so the
212+
# log can be grepped
150213
stdbuf -oL $WOLFSSL_SERVER \
151214
-v 4 \
152215
-R "$ready_file" \
153216
-p "$port" \
154217
-S "$PRIV_NAME" \
155218
--ech "$PUB_NAME" \
156-
$SUITE \
157-
$PQC \
219+
$wolfssl_suite \
220+
$wolfssl_extra \
158221
&>> "$TMP_LOG" &
159222

160223
# wait for server to be ready, then get port
@@ -185,14 +248,6 @@ openssl_client(){
185248
done
186249
echo "parsed ech config: $ech_config" &>> "$TMP_LOG"
187250

188-
# restrict group based on arguments
189-
local groups_arg="-groups secp256r1"
190-
if [ -n "$PQC" ]; then
191-
groups_arg="-groups ${PQC#--pqc }"
192-
elif [ "$FORCE_HRR" -ne 0 ]; then
193-
groups_arg=""
194-
fi
195-
196251
# test with OpenSSL s_client using ECH
197252
echo "wolfssl" | $OPENSSL s_client \
198253
-tls1_3 \
@@ -202,7 +257,7 @@ openssl_client(){
202257
-CAfile "$CERT_DIR/ca-cert.pem" \
203258
-servername "$PRIV_NAME" \
204259
-ech_config_list "$ech_config" \
205-
$groups_arg \
260+
$openssl_groups \
206261
&>> "$TMP_LOG"
207262

208263
grep -q "ECH: success: 1" "$TMP_LOG"
@@ -211,25 +266,7 @@ openssl_client(){
211266
rm -f "$TMP_LOG"
212267

213268
case "$MODE" in
214-
server)
215-
if [ -n "$SUITE" ]; then
216-
SUITE="-suite $SUITE"
217-
fi
218-
if [ -n "$PQC" ]; then
219-
PQC="--pqc $PQC"
220-
fi
221-
openssl_server
222-
;;
223-
client)
224-
if [ -n "$SUITE" ]; then
225-
SUITE="--ech-suite $SUITE"
226-
fi
227-
if [ -n "$PQC" ]; then
228-
PQC="--pqc $PQC"
229-
fi
230-
openssl_client
231-
;;
232-
*)
233-
exit 1
234-
;;
269+
server) openssl_server ;;
270+
client) openssl_client ;;
271+
*) exit 1 ;;
235272
esac

src/tls.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17064,11 +17064,6 @@ int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset
1706417064
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
1706517065
}
1706617066
#endif
17067-
#ifdef HAVE_ECH
17068-
/* send the special confirmation */
17069-
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_ECH));
17070-
#endif
17071-
/* Cookie is written below as last extension. */
1707217067
break;
1707317068
#endif
1707417069

@@ -17152,6 +17147,18 @@ int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset
1715217147
}
1715317148
#endif
1715417149

17150+
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
17151+
/* write ECH last to promote interop with other implementations */
17152+
if (msgType == hello_retry_request) {
17153+
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
17154+
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_ECH));
17155+
ret = TLSX_Write(ssl->extensions, output + offset, semaphore,
17156+
msgType, &offset);
17157+
if (ret != 0)
17158+
return ret;
17159+
}
17160+
#endif
17161+
1715517162
#ifdef HAVE_EXTENDED_MASTER
1715617163
if (ssl->options.haveEMS && msgType == server_hello &&
1715717164
!IsAtLeastTLSv1_3(ssl->version)) {

0 commit comments

Comments
 (0)