[openssl/openssl] 38a436: DTLS 1.3 Signal the listener notifier on accept qu...

"'Matt Caswell' via openssl-commits" <[email protected]>
Newsgroups gmane.comp.encryption.openssl.cvs
Message-ID <openssl/openssl/push/refs/heads/feature/dtls-1.3/[email protected]>
  Branch: refs/heads/feature/dtls-1.3
  Home:   https://github.com/openssl/openssl
  Commit: 38a43642c868aba0a1a0c11e89a3001c6569a19a
      https://github.com/openssl/openssl/commit/38a43642c868aba0a1a0c11e89a3001c6569a19a
  Author: Matt Caswell <[email protected]>
  Date:   2026-08-14 (Fri, 14 Aug 2026)

  Changed paths:
    M ssl/d1_lib.c
    M test/dtlsssllistenertest.c

  Log Message:
  -----------
  DTLS 1.3 Signal the listener notifier on accept queue push

The listener's notifier was signalled when the demux routed a datagram into a
connection's receive queue, but not when dtls_listener_drive_pending() moved
a completed connection onto the accept queue - even though the latter is
precisely the readiness event a thread waiting in SSL_poll() for
SSL_POLL_EVENT_IC is waiting for.

Usually the injection signal covers for this. Every connection reaching the
accept queue got there because a datagram was demuxed into its receive queue,
so the waiter is woken by that, ticks the listener during its own readout,
and finds the connection. The exception is the window in which the injection
and the queue push straddle a waiter registering, since signalling only
happens if there is a waiter at the time:

  1. Accept thread A polls the listener for SSL_POLL_EVENT_IC. Its readout
     ticks the listener, finds nothing, and it decides to block. It is not a
     registered waiter yet.
  2. Worker thread B polls one of its own connections, which also ticks the
     listener. The pump reads a client's final ClientHello and injects it into
     that pending connection's queue. There are no waiters, so nothing is
     signalled.
  3. A enters the blocking section. Its re-check runs without ticking, so it
     sees only the accept queue, still empty, and blocks.
  4. B's tick reaches dtls_listener_drive_pending(), which completes the
     connection against the buffered ClientHello and pushes it onto the accept
     queue.

With no signal at step 4, A sleeps on while a validated connection sits ready
to be accepted, until an unrelated datagram makes the socket readable again.
B consumed the only one in flight and the client is now waiting on the server,
so on a quiet listener that means waiting for the client to retransmit its
handshake.

Factor the signalling out of dtls_listener_packet_handler() into a helper and
call it from both places. Both call sites already hold the listener mutex,
which the helper requires.

Assisted-by: Claude Code:claude-opus-5
Reviewed-by: Ryan Hooper <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
Merge-date: Fri Aug 14 15:45:34 2026
Merged-from: https://github.com/openssl/openssl/pull/32239


  Commit: 970613fbd544526d7e289108b8884f6289d7aad2
      https://github.com/openssl/openssl/commit/970613fbd544526d7e289108b8884f6289d7aad2
  Author: Matt Caswell <[email protected]>
  Date:   2026-08-14 (Fri, 14 Aug 2026)

  Changed paths:
    M ssl/rio/poll_immediate.c
    M test/dtlsssllistenertest.c

  Log Message:
  -----------
  DTLS 1.3 Enter a blocking section when polling a DTLS listener

A DTLS listener added only the network socket to the poll set. Three things
followed from that. The notifier was not in the poll set, so a thread blocked
in SSL_poll() on the listener could not be woken by it. The thread never
called ossl_dtls_listener_enter_blocking_section(), so cur_blocking_waiters
stayed at zero - and since signalling is conditional on there being a waiter,
no other thread even attempted to signal. And there was no re-check after
registering, so readiness arising between the readout deciding nothing was
ready and the wait actually starting was lost.

Polling the socket alone is not sufficient, though not because a wakeup can
be missed outright. poll() reports whatever is currently sitting in the
socket buffer and returns immediately if there is any, so a thread cannot
miss a datagram just by being outside poll() when it arrives. What it can
miss is a datagram another thread has already taken. With several threads
polling the one shared socket that happens constantly: an arriving datagram
wakes all of them, only one gets it, and the rest find nothing. Any of them
can be the one that takes it, because SSL_read() on a connection pumps the
demux and SSL_poll() on a connection ticks the whole listener.

  1. Accept thread A polls the listener for SSL_POLL_EVENT_IC. Its readout
     ticks the listener, finds nothing, and it decides to block.
  2. A client's final ClientHello lands on the shared socket.
  3. Worker thread B, polling one of its own connections, ticks the listener
     and is the one that takes the datagram. Its tick completes the pending
     connection and pushes it onto the accept queue. Signalling is attempted,
     but A never registered as a waiter, so nothing is signalled.
  4. A reaches its poll, watching the socket alone. B drained it, so it is
     empty. A sleeps with a validated connection sitting on the accept queue,
     and nothing can wake it until an unrelated datagram arrives or its
     deadline expires.

A's readout, back at step 1, would have found that connection had it run
after step 3 rather than before it.

Add the notifier FD to the poll set and bracket the wait with the enter/leave
blocking section calls, mirroring what the listener-based connection path
already does. As there, re-check readiness once inside the section, since it
is only from that point that a readiness event is guaranteed to make the
notifier readable, and abort blocking if the listener became ready in the
meantime. The re-check removes the dependency on that ordering; the notifier
covers anything arising after it.

Note that the signal raised when a connection is pushed onto the accept queue
is itself conditional on a registered waiter, so it does nothing for a thread
polling the listener until that thread registers here. The two changes are
complementary and neither is sufficient alone.

Assisted-by: Claude Code:claude-opus-5
Reviewed-by: Ryan Hooper <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
Merge-date: Fri Aug 14 15:45:35 2026
Merged-from: https://github.com/openssl/openssl/pull/32239


  Commit: e642b4883843393d0b24e896f32414c1216fb68e
      https://github.com/openssl/openssl/commit/e642b4883843393d0b24e896f32414c1216fb68e
  Author: Matt Caswell <[email protected]>
  Date:   2026-08-14 (Fri, 14 Aug 2026)

  Changed paths:
    M ssl/d1_lib.c
    M ssl/rio/poll_immediate.c
    M test/dtlsssllistenertest.c

  Log Message:
  -----------
  DTLS 1.3 Honour the DTLS retransmit timer in SSL_poll

When SSL_poll() decides to block it computes a wakeup deadline from the
per-object event timeout, so that timer driven work is not delayed by the
wait. This was done for QUIC objects but not for DTLS connections, whose
timeout is the handshake retransmission timer.

The consequence was that a poll with no user timeout would sleep until a
datagram arrived, straight through the point at which the connection should
have retransmitted. If the peer had itself lost the message we were waiting
for, neither side would make progress.

Fold SSL_get_event_timeout() into the deadline for DTLS connections as the
QUIC branch already does. It reports the DTLS timer already, so no new
plumbing is needed there.

Waking at the deadline is only useful if something then services the timer.
Unlike the QUIC case, where the readout ticks the reactor and that handles
timeouts, the DTLS readout only pumped the listener's demux. Nothing
retransmitted, and because an expired timer reports zero time remaining the
recomputed deadline would be "now" on every subsequent wait, turning the
sleep into a spin. Call SSL_handle_events() from the readout as well, which
is what a caller polling without SSL_POLL_FLAG_NO_HANDLE_EVENTS is asking
for, and which for a DTLS connection services that timer.

Both of those are the calls the documentation asks new code to use:
DTLSv1_get_timeout(3) and DTLSv1_handle_timeout(3) each record that
SSL_get_event_timeout(3) and SSL_handle_events(3) respectively supersede all
of their use cases. The test asserts its precondition through
SSL_get_event_timeout() for the same reason, which has the side benefit of
using the same call SSL_poll() uses to compute the deadline being tested.

Assisted-by: Claude Code:claude-opus-5
Reviewed-by: Ryan Hooper <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
Merge-date: Fri Aug 14 15:45:37 2026
Merged-from: https://github.com/openssl/openssl/pull/32239


  Commit: 7a051e9e21577a031440b578dcbd034f688e9bbc
      https://github.com/openssl/openssl/commit/7a051e9e21577a031440b578dcbd034f688e9bbc
  Author: Matt Caswell <[email protected]>
  Date:   2026-08-14 (Fri, 14 Aug 2026)

  Changed paths:
    M ssl/d1_lib.c
    M test/dtlsssllistenertest.c

  Log Message:
  -----------
  Stop the DTLS timer when the retransmit budget is exhausted

dtls1_handle_timeout() fails the connection with SSLfatal() once
dtls1_check_timeout_num() reports that DTLS1_TMO_ALERT_COUNT unanswered
retransmissions have been sent. It returns at that point without reaching
dtls1_start_timer(), so next_timeout is left holding a time in the past.

Nothing re-arms or clears it afterwards, the connection being finished, so
every later dtls1_get_timeout() computes a negative remaining time, clamps it
to zero and reports the timeout as due immediately. A caller which waits on
that timeout therefore never waits at all. The documented
DTLSv1_get_timeout() plus select() loop turns into a busy loop on any
connection which has given up retransmitting, consuming a core until the
application gives up on the connection itself.

Stop the timer instead. dtls1_stop_timer() zeroes next_timeout, which
dtls1_get_timeout() already reports as "no timer running", so callers see no
pending timeout and wait on whatever other deadline they have.

The test drives this without waiting by forcing a retransmission timeout of
1ms, which is below the 15ms floor at which dtls1_get_timeout() treats a
timer as already expired. The server therefore retransmits on every read
attempt and exhausts its budget inside SSL_accept().

Assisted-by: Claude Code:claude-opus-5
Reviewed-by: Ryan Hooper <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
Merge-date: Fri Aug 14 15:45:40 2026
Merged-from: https://github.com/openssl/openssl/pull/32239


  Commit: 4e7e2b703b64207c0207596773e6882881afd72e
      https://github.com/openssl/openssl/commit/4e7e2b703b64207c0207596773e6882881afd72e
  Author: Matt Caswell <[email protected]>
  Date:   2026-08-14 (Fri, 14 Aug 2026)

  Changed paths:
    M ssl/rio/poll_builder.c

  Log Message:
  -----------
  Wait consistently across platforms when there is nothing to poll

poll_translate_ssl_dtls_conn() adds no file descriptor to the poll set when
the connection's BIO cannot supply one, which is the case for the memory and
datagram-pair BIOs the test suite is built on. Unlike the QUIC and DTLS
listener paths it does not report that as an error, and rightly so: a DTLS
connection with no pollable BIO has no readiness to wait for, but it still
has a retransmission deadline to wake for, so a wait with nothing to watch is
meaningful.

The resulting empty descriptor set was then handed to the operating system,
where the behaviour differs. poll() treats it as a plain sleep, so this
worked on Unix. Windows' select() rejects a call with no descriptors, so
ossl_rio_poll_builder_poll() returned failure and SSL_poll() failed with it.

Sleep out the deadline explicitly rather than relying on the platform. With
no descriptors and no deadline nothing could ever provide a wakeup, so that
combination is reported as a failure instead of sleeping for ever.

This has no test of its own: on any platform whose poll() already sleeps, the
behaviour before and after is identical, so only the Windows CI builds
distinguish them.

Assisted-by: Claude Code:claude-opus-5
Reviewed-by: Ryan Hooper <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
Merge-date: Fri Aug 14 15:45:41 2026
Merged-from: https://github.com/openssl/openssl/pull/32239


  Commit: 24b4ad741357b1f77f572e81e10e726bdac0f537
      https://github.com/openssl/openssl/commit/24b4ad741357b1f77f572e81e10e726bdac0f537
  Author: Matt Caswell <[email protected]>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M ssl/d1_lib.c
    M ssl/rio/poll_immediate.c
    M ssl/ssl_local.h
    M test/dtls_multithread_test.c

  Log Message:
  -----------
  DTLS 1.3 Wait rather than spin in the blocking accept path

SSL_accept_connection() looped calling ossl_dtls_tick() with nothing in
between, so it only avoided spinning if the application supplied a
blocking network BIO and each tick slept inside BIO_recvmmsg().

A listener cannot require that. It demultiplexes one socket to many
connections and ossl_dgram_demux_pump() holds the demux lock across the
receive, so a thread blocked in accept stalls reads on every established
connection until a datagram for any peer arrives. QUIC takes the
opposite approach, keeping the socket non-blocking and waiting for
readiness instead.

Do the same: set the listener's network BIO non-blocking and wait
between ticks via ossl_dtls_block_until_ready(), which reuses
SSL_poll()'s blocking machinery. It reads nothing out, so the caller
re-tests its own condition and waits again if the wakeup was not for it.

Assisted-by: Claude Code:claude-opus-5
Reviewed-by: Ryan Hooper <[email protected]>
Reviewed-by: Jakub Zelenka <[email protected]>
Merge-date: Mon Aug 17 08:29:51 2026
Merged-from: https://github.com/openssl/openssl/pull/32324


  Commit: 216dca27039a0facc31bdcbc9bdb6c98e62ea650
      https://github.com/openssl/openssl/commit/216dca27039a0facc31bdcbc9bdb6c98e62ea650
  Author: Matt Caswell <[email protected]>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M test/dtlsssllistenertest.c

  Log Message:
  -----------
  DTLS 1.3 Name the accept flag in the no-BIO test comments

Both tests describe themselves in terms of "blocking mode" and
"non-blocking behaviour", when what they actually vary is the
SSL_ACCEPT_CONNECTION_NO_BLOCK flag. That reads as though they concern a
mode on the object, which invites confusion with
SSL_set_blocking_mode(). Name the flag, and say what each case is really
asserting.

Comment only, no functional change.

Assisted-by: Claude Code:claude-opus-5
Reviewed-by: Ryan Hooper <[email protected]>
Reviewed-by: Jakub Zelenka <[email protected]>
Merge-date: Mon Aug 17 08:29:53 2026
Merged-from: https://github.com/openssl/openssl/pull/32324


  Commit: e4c9b87c9871f9f1a6dbac7c0a37483ebd103604
      https://github.com/openssl/openssl/commit/e4c9b87c9871f9f1a6dbac7c0a37483ebd103604
  Author: Matt Caswell <[email protected]>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M doc/man3/SSL_new_listener.pod
    M doc/man3/SSL_set_bio.pod
    M doc/man3/SSL_set_blocking_mode.pod
    M ssl/d1_lib.c
    M ssl/ssl_lib.c
    M ssl/ssl_local.h
    M test/dtlsssllistenertest.c

  Log Message:
  -----------
  DTLS 1.3 Support SSL_set_blocking_mode() on a DTLS listener

A DTLS listener cannot take its blocking behaviour from its network BIO
the way an ordinary DTLS object does. It demultiplexes one socket to
many connections, so a read for one of them must not be allowed to
block and stall the others, and the connections it hands out have no BIO
of their own to configure - they read from a queue the listener fills.
Blocking was therefore unavailable to them, SSL_set_blocking_mode()
being QUIC only.

Extend it to a DTLS listener and to the connections created from one,
with the same semantics QUIC has. Blocking is the default, a connection
follows its listener unless given a setting of its own, and asking for
blocking fails where it cannot be delivered, which for a listener means
a network BIO with no poll descriptor to wait on.
SSL_accept_connection() waits only where the caller did not pass
SSL_ACCEPT_CONNECTION_NO_BLOCK and the listener is in blocking mode,
matching what QUIC does with the same flag.

Only the accept path acts on the mode so far; reads and writes follow.

Note that this does not extend to a DTLS object which did not come from
a listener. Such an object has its own BIO and already offers both modes
through it, so unlike QUIC - where the socket is always nonblocking and
nothing works without emulation - there is nothing missing to provide.

While documenting the above, correct the existing description of which
QUIC objects these functions apply to. It said connection objects only,
but they have always been accepted for QUIC stream and listener objects
too.

Assisted-by: Claude Code:claude-opus-5
Reviewed-by: Ryan Hooper <[email protected]>
Reviewed-by: Jakub Zelenka <[email protected]>
Merge-date: Mon Aug 17 08:29:54 2026
Merged-from: https://github.com/openssl/openssl/pull/32324


  Commit: ed945b20d762b18bc35c6759fc73b17d623c1e70
      https://github.com/openssl/openssl/commit/ed945b20d762b18bc35c6759fc73b17d623c1e70
  Author: Matt Caswell <[email protected]>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M ssl/d1_lib.c
    M ssl/ssl_lib.c
    M ssl/ssl_local.h
    M test/dtlsssllistenertest.c

  Log Message:
  -----------
  DTLS 1.3 Keep listener driven connections out of blocking mode

A DTLS listener drives the handshakes of connections which have not been
accepted yet from inside its own tick: dtls_listener_drive_pending()
calls SSL_accept() on each of them. Those connections inherit the
listener's blocking mode, so once a listener connection is able to block
waiting for a datagram, that SSL_accept() can block too - and it must
not, because the listener is the only thing which will ever deliver the
datagram it is waiting for. Nothing else runs while the tick is inside
that call, so the wait cannot end.

Add force_nonblocking to DTLS1_STATE, set around the SSL_accept() that
dtls_listener_drive_pending() performs, and consulted by
ossl_dtls_desires_blocking(). Ownership of a connection passes to the
application when SSL_accept_connection() returns it, and by then the
flag is clear, so an application which asked for blocking still gets it.

The flag has to survive SSL_clear(), which memsets d1. SSL_clear() can
run inside the very SSL_accept() the listener is driving:
drive_single_connection() sets TLS1_FLAGS_STATELESS to suppress it, but
only where cookie validation is enabled. Losing the flag there is not
merely a missed optimisation - the connection blocks inside the tick,
poll_translate_ssl_dtls_conn() ticks the listener again from another
thread, drive_pending re-enters and collects the same connection twice,
and registering it a second time trips the old == NULL assertion in the
connection lookup. In a release build that appears later as a
use-after-free rather than as anything to do with blocking mode.

Nothing blocks in a read yet, so this commit changes no behaviour on its
own. It lands first so that the commit which adds blocking reads cannot
deadlock at any point in the series.

Assisted-by: Claude Code:claude-opus-5
Reviewed-by: Ryan Hooper <[email protected]>
Reviewed-by: Jakub Zelenka <[email protected]>
Merge-date: Mon Aug 17 08:29:56 2026
Merged-from: https://github.com/openssl/openssl/pull/32324


  Commit: cf159be310698fea23cdbf5ae4660e27c4ccea27
      https://github.com/openssl/openssl/commit/cf159be310698fea23cdbf5ae4660e27c4ccea27
  Author: Matt Caswell <[email protected]>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M ssl/d1_lib.c
    M ssl/record/rec_layer_s3.c
    M ssl/ssl_local.h
    M test/dtls_multithread_test.c
    M test/dtlsssllistenertest.c

  Log Message:
  -----------
  DTLS 1.3 Support blocking reads on listener connections

A connection created by a DTLS listener has no BIO of its own. The
listener owns the socket and demultiplexes datagrams into a per
connection queue, so there is nothing for a read to block in, and every
read on an empty queue reported WANT_READ however the connection was
configured. SSL_set_blocking_mode() therefore had no effect on reads.

Wait in the record layer instead, where a blocking BIO would have. When
rlayer_dtls_get_urxe_packet() finds the queue empty and the connection is
in blocking mode, ossl_dtls_conn_wait_for_datagram() waits for one to
arrive. The state machine above is untouched, so SSL_read(), SSL_peek(),
SSL_do_handshake() and SSL_accept() all become blocking together, which
is what an application moving from a plain DTLS object expects.

The wait loops, because the socket is shared: a wakeup may be for a
datagram belonging to a different connection, in which case our queue is
still empty and there is nothing to return. It also handles events after
each wakeup, since while a thread is in here nothing else services the
connection, and the retransmission timer has to keep running - the poll
translation folds the event timeout into the deadline so the wait ends in
time for it.

Existing tests drive both ends of a connection from a single thread,
which cannot work if the server side blocks, so create_dtls_listener() in
dtlsssllistenertest.c now turns blocking mode off for its callers, with
create_dtls_listener_unconfigured() for the one test which has to observe
the default. test_dtls_multithread opts out for the same reason.

The new test_dtls_blocking_read has the client stay silent for a while
after its handshake, so the server thread is already parked in
SSL_read_ex() when the write finally comes. Its second iteration
handshakes in non-blocking mode and switches to blocking only for the
read, which pins the read path on its own: in the first iteration the
handshake is what fails without this change, and the read is never
reached.

Assisted-by: Claude Code:claude-opus-5
Reviewed-by: Ryan Hooper <[email protected]>
Reviewed-by: Jakub Zelenka <[email protected]>
Merge-date: Mon Aug 17 08:29:57 2026
Merged-from: https://github.com/openssl/openssl/pull/32324


  Commit: 11226cd1c2943ae4e586c3b97375529954fcfe3c
      https://github.com/openssl/openssl/commit/11226cd1c2943ae4e586c3b97375529954fcfe3c
  Author: Matt Caswell <[email protected]>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M doc/man3/SSL_set_blocking_mode.pod
    M ssl/d1_lib.c
    M ssl/record/methods/recmethod_local.h
    M ssl/record/methods/tls_common.c
    M ssl/record/rec_layer_s3.c
    M ssl/record/record.h
    M ssl/rio/poll_immediate.c
    M ssl/ssl_local.h
    M test/dtlsssllistenertest.c

  Log Message:
  -----------
  DTLS 1.3 Support blocking writes on listener connections

A listener connection writes through the listener's socket, which is
shared with every other connection and is always non-blocking. When a
send cannot be completed the DTLS record layer discards the datagram and
reports that the write should be retried - a fair default for an
unreliable transport, but not what an application which asked for
blocking writes expects, since it gets neither the data sent nor a call
which waited.

Add an rlayer callback, OSSL_FUNC_RLAYER_BLOCK_FOR_WRITE, which the
record layer calls instead of reporting a retry. For a listener
connection in blocking mode it waits for the socket to become writable
and returns 1, and tls_retry_write_records() goes round its loop again to
repeat the same send: nothing has been consumed at that point, so the
retry is a genuine second attempt rather than a resend.

Only the BIO_sendmmsg() branch is hooked. That is the one listener
connections take, because their peer address is set, and the BIO_write()
branch below it belongs to connections which have a BIO of their own to
block in. A NULL callback leaves both paths exactly as they were, so TLS
and standalone DTLS are untouched.

The wait itself is one wait per call, not a loop: the caller retries the
send and comes back here if it still cannot proceed, so a wakeup which
turns out not to have left room in the socket buffer costs another
attempt rather than a lost datagram.

A loopback socket's send buffer does not fill, so the test supplies the
transient failure with a filter BIO in front of the listener's write BIO
which rejects one send with a non-fatal error. Its ctrl forwards
everything to the socket underneath, the poll descriptors included, since
those are what the wait itself needs. The client is then read to confirm
the datagram really was sent rather than merely reported as sent.

Assisted-by: Claude Code:claude-opus-5
Reviewed-by: Ryan Hooper <[email protected]>
Reviewed-by: Jakub Zelenka <[email protected]>
Merge-date: Mon Aug 17 08:29:59 2026
Merged-from: https://github.com/openssl/openssl/pull/32324


  Commit: 2000b5d086725fd9d5ac425eec7560f87a3a7a89
      https://github.com/openssl/openssl/commit/2000b5d086725fd9d5ac425eec7560f87a3a7a89
  Author: Mounir IDRASSI <[email protected]>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M ssl/statem/statem_dtls.c
    M test/recipes/70-test_tls13messages.t

  Log Message:
  -----------
  Reject HelloRequest in TLS and DTLS 1.3

TLS and DTLS 1.3 reserve handshake message type 0, but legacy
client-side HelloRequest skip paths could consume such messages before
the state machines rejected them.

Keep the skip paths only for connections that cannot use TLS or DTLS
1.3. Add TLSProxy coverage for TLS and DTLS 1.3 rejection, and for the
preserved TLS and DTLS 1.2 legacy behavior. The DTLS test insertion
also adjusts record sequencing so the injected HelloRequest is a valid
standalone server record.

Reviewed-by: Andrew Dinh <[email protected]>
Reviewed-by: Matt Caswell <[email protected]>
Merge-date: Mon Aug 17 08:32:42 2026
Merged-from: https://github.com/openssl/openssl/pull/31637


  Commit: a80f6540b6ee90446f80eb9bd9df4a34397ae3ee
      https://github.com/openssl/openssl/commit/a80f6540b6ee90446f80eb9bd9df4a34397ae3ee
  Author: Ryan Hooper <[email protected]>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M ssl/build.info
    A ssl/d1_transcript.c
    M ssl/s3_enc.c
    M ssl/ssl_local.h
    M ssl/tls13_enc.c
    M test/build.info
    M test/tls13secretstest.c

  Log Message:
  -----------
  Fix DTLS 1.3 early data transcript hash stripping

When the client installs early write keys, negotiated_version is not
yet set to DTLS1_3_VERSION, so the RFC 9147 §5.2 stripping of
msg_seq, fragment_offset, and fragment_length was skipped in
tls13_change_cipher_state. Fix by conditioning on
SSL_CONNECTION_IS_DTLS() alone.

Fixes: openssl/project#2043
Reviewed-by: Frederik Wedel-Heinen <[email protected]>
Reviewed-by: Matt Caswell <[email protected]>
Merge-date: Mon Aug 17 08:34:23 2026
Merged-from: https://github.com/openssl/openssl/pull/32276


  Commit: f5a16d6908fd4843c9e99563f6c8607c786ef5a6
      https://github.com/openssl/openssl/commit/f5a16d6908fd4843c9e99563f6c8607c786ef5a6
  Author: Matt Caswell <[email protected]>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M test/dtls_multithread_test.c

  Log Message:
  -----------
  Skip the common test options in dtls_multithread_test

setup_tests() read its two positional arguments without first calling
test_skip_common_options(), so the option cursor was never advanced from
the test's point of view and test_get_argument(0) returned the option
itself. Passing -test or -iter therefore left the certificate path set to
the literal string "-test", and the run failed on that:

    error:80000002:system library:file_ctrl:No such file or directory:
        ...:calling fopen(-test, r)

The option was not being ignored: the framework parses it in
process_shared_options() and the selected sub-test really does run. Only
the positional arguments were shifted, which is what made the failure
look unrelated to the option.

Also declare the usage string, so -help describes the two arguments the
test needs rather than showing none.

Assisted-by: Claude Code:claude-opus-5
Reviewed-by: Ryan Hooper <[email protected]>
Reviewed-by: Jakub Zelenka <[email protected]>
Merge-date: Mon Aug 17 08:36:26 2026
Merged-from: https://github.com/openssl/openssl/pull/32331


Compare: https://github.com/openssl/openssl/compare/66d51f8f9c7b...f5a16d6908fd

To unsubscribe from these emails, change your notification settings at https://github.com/openssl/openssl/settings/notifications

-- 
You received this message because you are subscribed to the Google Groups "openssl-commits" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion visit https://groups.google.com/a/openssl.org/d/msgid/openssl-commits/openssl/openssl/push/refs/heads/feature/dtls-1.3/66d51f-f5a16d%40github.com.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.