System architecture

OpenSSL 4.1.0 released: DTLS 1.3, GREASE, and what breaks when you upgrade

OpenSSL 4.1.0 adds DTLS 1.3 and GREASE and drops the CN fallback in host-name checks. What breaks, how to test it, and which version to run.

Kemo
12 min read
A steel padlock closing a heavy chain wrapped around the posts of a metal gate, with a blurred building behind.
On this page
  1. What's new in OpenSSL 4.1.0?
  2. What breaks when you upgrade to OpenSSL 4.1
  3. How DTLS 1.3 works in OpenSSL: the listener model
  4. Try DTLS 1.3 with openssl s_server and s_client
  5. A minimal DTLS 1.3 server in C with SSL_new_listener
  6. Known DTLS 1.3 issues in 4.1.0
  7. Post-quantum performance: ML-DSA and ML-KEM on 4.1.0
  8. Which OpenSSL version should you use now?
  9. Upgrade checklist for OpenSSL 4.1
  10. OpenSSL 4.1 questions
  11. Sources and further reading

OpenSSL 4.1.0 was tagged on 23 October 2026. The headline is DTLS 1.3 (RFC 9147), the UDP flavour of TLS 1.3, served through a new DTLS mode of the SSL_new_listener() API. The release also adds client-side GREASE, an IKEv2 KDF and faster post-quantum code on x86_64 and ppc64le — and it quietly changes how certificate host names are checked, which is the part most likely to break something you already run.

This article covers what is in 4.1.0, which changes can break an existing build or deployment, how to try DTLS 1.3 from the command line and from C, the four known DTLS issues the project shipped with, and which OpenSSL line you should actually be on now that 3.6 leaves support on 1 November.

Released23 October 2026 (release notes)
TypeFeature release on the 4.x line; not LTS
Supported untilNovember 2027 (downloads page)
Tarballopenssl-4.1.0.tar.gz, 53.2 MiB
New protocolsDTLS 1.3, DTLS in the SSL listener API, RFC 8701 GREASE
Known issues at releaseFour, all in DTLS (#32878, #33242, #33277, #33278)
OpenSSL 4.1.0 at a glance, from the release page and the downloads page on 24 October 2026

What's new in OpenSSL 4.1.0?

OpenSSL 4.1.0 is a feature release whose main addition is DTLS 1.3, with GREASE, an IKEv2 KDF and platform optimisations alongside. The NEWS file lists five new features and five potentially incompatible changes; the longer CHANGES file has the behaviour changes that NEWS leaves out.

  • DTLS 1.3 (RFC 9147), documented in the new ossl-guide-dtlsv13(7) manual page. Work by Frederik Wedel-Heinen and Ryan Hooper, per the OpenSSL blog.
  • DTLS in the SSL listener API. SSL_new_listener() — introduced for QUIC — can now create a DTLS listener that demultiplexes datagrams into per-peer connections and validates addresses by default.
  • GREASE (RFC 8701). With SSL_OP_GREASE set, a client injects reserved values into cipher suites, versions, groups, signature algorithms, key shares and extensions in its ClientHello. openssl s_client -grease turns it on from the command line.
  • IKEv2 KDF as EVP_KDF-IKEV2KDF, and initial support for the Elbrus2000 (e2k) architecture.
  • Speed-ups: ML-DSA and ML-KEM NTT on ppc64le, AVX2 ML-DSA NTT and AVX-512 SHAKE x4 on x86_64, and AVX-512/VAES AES-CBC decryption, which CHANGES puts at 3.5x to 3.8x faster for inputs of 1024 bytes or more.
  • Ed25519 and Ed448 certificates in DTLS 1.2, previously TLS-only.

The release was meant to ship earlier. The beta 2 announcement on 9 October says two potential security issues in the new DTLS 1.3 code (#33172 and #33173) were reported that day, and the project "did not want to release 4.1.0 with known security issues in the new implementation", so it shipped a second beta instead.

What breaks when you upgrade to OpenSSL 4.1

Most 4.0 applications will rebuild unchanged, but four changes in the CHANGES file alter behaviour at run time rather than at compile time, so a green build proves little. The host-name change is the one to test first.

Host-name checks no longer fall back to the certificate's common name

Until now, when a certificate had no subject alternative name (SAN) of the type being checked, OpenSSL matched the subject commonName for host names, or emailAddress for e-mail checks. From 4.1 the subject DN is consulted only when X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT is set. DNS name constraints are likewise applied to the leaf's common name only under that flag.

What breaks: anything that still relies on a CN-only certificate — old internal CAs, appliance certificates, hand-rolled test certificates made with -subj /CN=host and no subjectAltName. Verification that passed on 4.0 now fails with a host-name mismatch. Browsers stopped trusting CN-only certificates years ago, so public certificates are fine; private PKI is where to look. This shell loop lists the files that have no SAN at all:

find-cn-only-certs.shShell
#!/bin/sh# Print every PEM certificate under a directory that has no subjectAltName.# Needs the openssl CLI from 3.0 onwards (for x509 -ext).dir="${1:-/etc/ssl/private-ca}"find "$dir" -name '*.pem' -o -name '*.crt' | while read -r f; do  if ! openssl x509 -in "$f" -noout -ext subjectAltName 2>/dev/null | grep -q 'DNS:\|IP Address:\|email:'; then    printf 'no SAN: %s  (%s)\n' "$f" "$(openssl x509 -in "$f" -noout -subject)"  fidone
Re-issue anything it prints with a subjectAltName, or set X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT as a stop-gap.

TLS 1.3 clients offer PSKs and 0-RTT only when usable

A client now offers a resumption ticket or external PSK only if an offered cipher suite shares its handshake digest, and attempts 0-RTT only when the ticket's exact cipher suite and ALPN are offered and it has not aged out. An ALPN mismatch now silently drops to a 1-RTT handshake instead of failing with SSL_R_INCONSISTENT_EARLY_DATA_ALPN. If you had code or tests that expected that error, they will now see a successful but slower handshake.

FIPS indicators must be explicit, and ASN1_STRING loses its spare NUL

In the FIPS provider, every algorithm advertised with fips=yes must expose a fips-indicator returning 1; a missing indicator is no longer treated as approved. Separately, the new ASN1_STRING_set1_data() and ASN1_STRING_set1_string() setters do not append a terminating NUL, and ASN1_STRING_set() and ASN1_STRING_length() are deprecated. Code that passes ASN1_STRING_get0_data() to strlen(), %s or strdup() was always wrong; under AddressSanitizer, MemorySanitizer or Valgrind it is now reported as an error.

Build options and targets that were removed

  • no-ecdsa and no-ecdh are gone; according to the release notes they never disabled anything. Use no-ec.
  • The VC-WIN64I (Windows on Itanium) and VC-CE (Windows CE) targets are removed.
  • The tsget script now needs the Perl module Net::Curl::Easy instead of the abandoned WWW::Curl::Easy.

How DTLS 1.3 works in OpenSSL: the listener model

A DTLS 1.3 server in OpenSSL 4.1 uses one listener object on one UDP socket, and accepts a separate SSL object per peer — the same shape QUIC servers already use. The old DTLSv1_listen() only handles DTLS 1.0 and 1.2 with HelloVerifyRequest; the DTLS 1.3 guide says to use SSL_new_listener() for 1.3.

One process, one socketDTLS clientUDP datagramsUDP socketBIO_new_dgramListenerSSL_new_listener()Address validationHRR cookie (1.3) · HVR (1.2)Pending peersmax 256 · 30 sPer-peer SSLSSL_accept_connection()Your handlerSSL_read / SSL_writenew peercookie OK
  • DTLS client → UDP socket
  • UDP socket → Listener
  • Listener → Address validation: new peer
  • Address validation → Pending peers: cookie OK
  • Pending peers → Per-peer SSL
  • Per-peer SSL → Your handler
One UDP socket, one listener, one SSL object per validated peer. Address validation is on by default.

Address validation is what stops a DTLS server being used as a reflection amplifier: the server replies to a new peer with a cookie and does no expensive work until the peer echoes it. SSL_LISTENER_FLAG_NO_VALIDATE turns that off, which the guide says is faster but unsafe on untrusted networks. Three tunables bound the listener's memory, read and written with SSL_set_value_uint():

ValueControlsDefault
SSL_VALUE_DTLS_LISTENER_MAX_PENDING_CONNSConnections the listener holds before you accept them256
SSL_VALUE_DTLS_LISTENER_PENDING_TIMEOUTHow long a pending connection waits, in ms30000
SSL_VALUE_DTLS_LISTENER_MAX_DGRAM_SIZELargest datagram the listener reads, in bytes2000
DTLS listener tunables in OpenSSL 4.1 and their defaults, from ossl-guide-dtlsv13(7)

The listener is blocking by default even though its BIO is non-blocking: it waits for socket readiness itself. Accepted connections inherit the mode. Set it once, before use, with SSL_set_blocking_mode(), or pass SSL_ACCEPT_CONNECTION_NO_BLOCK for a single non-blocking accept.

Try DTLS 1.3 with openssl s_server and s_client

The quickest test is the CLI: both s_server and s_client in 4.1.0 have a -dtls1_3 option ("Just talk DTLSv1.3"). First get the source and check it against the published checksum. This session is real; the machine's own OpenSSL was 3.0.13, which has no DTLS 1.3:

Ubuntu 24.04.5, 24 October 2026Shell
$ curl -sSL -o openssl-4.1.0.tar.gz https://github.com/openssl/openssl/releases/download/openssl-4.1.0/openssl-4.1.0.tar.gz$ curl -sSL https://github.com/openssl/openssl/releases/download/openssl-4.1.0/openssl-4.1.0.tar.gz.sha25650c17baf54cb008f6ce42d50deb4b28050a1aad711636cabd4b241c7e90cc2fd *openssl-4.1.0.tar.gz$ sha256sum openssl-4.1.0.tar.gz50c17baf54cb008f6ce42d50deb4b28050a1aad711636cabd4b241c7e90cc2fd  openssl-4.1.0.tar.gz$ openssl versionOpenSSL 3.0.13 30 Jan 2024 (Library: OpenSSL 3.0.13 30 Jan 2024)

Build it into its own prefix so it cannot shadow the system library, then run a loopback handshake with a throwaway certificate. Note the certificate carries a SAN, for the reason in the section above:

build-and-test-dtls13.shShell
tar xzf openssl-4.1.0.tar.gz && cd openssl-4.1.0./Configure --prefix="$HOME/openssl-4.1" --libdir=libmake -j"$(nproc)" && make install_swexport PATH="$HOME/openssl-4.1/bin:$PATH" LD_LIBRARY_PATH="$HOME/openssl-4.1/lib" openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes \  -keyout key.pem -out cert.pem -days 7 \  -subj /CN=localhost -addext subjectAltName=DNS:localhost # terminal 1openssl s_server -dtls1_3 -accept 4433 -cert cert.pem -key key.pem# terminal 2openssl s_client -dtls1_3 -connect localhost:4433 -verify_hostname localhost -CAfile cert.pem

The -dtls1_3 options come from apps/s_server.c and apps/s_client.c in the 4.1.0 tarball. A build-and-measure write-up on dev.to ran the same kind of loopback test and got Protocol: DTLSv1.3 and Verify return code: 0 (ok); it also hit one practical snag — the build ran out of space in a 512 MB /tmp tmpfs — so build on a real disk.

A minimal DTLS 1.3 server in C with SSL_new_listener

In code, DTLS 1.3 is the usual DTLS_server_method() context pinned to DTLS1_3_VERSION, plus the listener. The function below is trimmed from demos/dtlslistenerecho/main.c in the 4.1.0 source, switched to blocking mode for brevity; fd is a UDP socket already bound with BIO_listen().

dtls13_server.cText
#include <stdio.h>#include <openssl/ssl.h>#include <openssl/err.h> int serve_dtls13(int fd){    SSL_CTX *ctx = SSL_CTX_new(DTLS_server_method());    SSL_CTX_set_min_proto_version(ctx, DTLS1_3_VERSION);    SSL_CTX_set_max_proto_version(ctx, DTLS1_3_VERSION);    SSL_CTX_use_certificate_chain_file(ctx, "cert.pem");    SSL_CTX_use_PrivateKey_file(ctx, "key.pem", SSL_FILETYPE_PEM);     BIO *bio = BIO_new_dgram(fd, BIO_NOCLOSE);    SSL *listener = SSL_new_listener(ctx, 0);   /* address validation on */    BIO_up_ref(bio);                            /* one ref each for rbio and wbio */    SSL_set0_rbio(listener, bio);    SSL_set0_wbio(listener, bio);     /* Hold at most 64 unaccepted peers instead of the default 256. */    SSL_set_generic_value_uint(listener,        SSL_VALUE_DTLS_LISTENER_MAX_PENDING_CONNS, 64);     if (SSL_listen(listener) != 1) {        ERR_print_errors_fp(stderr);        return 0;    }    for (;;) {        SSL *conn = SSL_accept_connection(listener, 0); /* blocks */        if (conn == NULL) { ERR_print_errors_fp(stderr); continue; }        if (SSL_accept(conn) <= 0) { SSL_free(conn); continue; }         char buf[1500];        int n = SSL_read(conn, buf, sizeof(buf));        if (n > 0)            SSL_write(conn, buf, n);                /* echo */        SSL_shutdown(conn);        SSL_free(conn);    }}
Trimmed from the OpenSSL 4.1.0 demo; error handling shortened, not compiled for this article. The full demo adds SSL_poll(), threads and a retransmit timer.

SSL_set_generic_value_uint() is the header's convenience macro for SSL_set_value_uint(ssl, SSL_VALUE_CLASS_GENERIC, id, v). Serving one peer at a time like this is fine for a test; a real server needs the demo's SSL_poll() loop or a thread per connection.

Known DTLS 1.3 issues in 4.1.0

OpenSSL shipped 4.1.0 with four documented DTLS bugs. None is a security issue, but two can hang or kill handshakes, so test loss and retransmission before you put DTLS 1.3 in front of users.

IssueWhat happensWho should care
#32878After a DTLS 1.3 KeyUpdate, post-handshake records such as NewSessionTicket can drop out of the retransmission buffer and are not resent if lostLong-lived sessions that rekey on lossy links
#33242A DTLS 1.3 server may abort with unexpected_message when a client acknowledges part of the first flight earlyServers facing other DTLS 1.3 stacks
#33277A permanent receive failure on a DTLS listener can surface as SSL_ERROR_WANT_READEvent loops that wait forever on WANT_READ
#33278A retryable write failure from a listener connection can surface as SSL_ERROR_SYSCALL instead of SSL_ERROR_WANT_WRITENon-blocking servers that treat SYSCALL as fatal
Known issues listed in the OpenSSL 4.1.0 release notes, and what they mean in practice

There are also deliberate gaps, from the guide: no Connection ID support (a server ignores the client's), DTLS 1.3 over SCTP falls back to 1.2 or earlier, and TLS_AES_128_CCM_8_SHA256 is not offered for DTLS because RFC 9147 requires extra forgery protections OpenSSL does not implement. If your use case is IoT devices that change address mid-session, the missing Connection ID is the one that matters.

Post-quantum performance: ML-DSA and ML-KEM on 4.1.0

4.1.0 speeds up ML-DSA and ML-KEM rather than adding new post-quantum algorithms; those arrived in 3.5. Independent numbers are scarce on day one. The only public run found so far is a dev.to write-up on a 2-vCPU AMD EPYC VM with AVX-512, short single-threaded openssl speed runs on a 4.1.0 build (dev.to). Treat it as one data point, not a benchmark:

Signatures per second: RSA-2048 vs ML-DSA-65 on OpenSSL 4.1.0One 2-vCPU AMD EPYC VM, single thread, short runs
RSA-2048ML-DSA-65
0 ops/s10k ops/s20k ops/s30k ops/s40k ops/sSignVerify

Source: [dev.to build-and-measure write-up, 23 Oct 2026](https://dev.to/frankchu/openssl-410-shipped-today-i-built-it-and-measured-ml-kem-ml-dsa-and-dtls-13-4d24)

Signatures per second: RSA-2048 vs ML-DSA-65 on OpenSSL 4.1.0
RSA-2048ML-DSA-65
Sign2,110.7 ops/s2,719.1 ops/s
Verify33.8k ops/s13.6k ops/s

ML-DSA-65 signed slightly faster than RSA-2048 there but verified at about 40% of RSA's rate. The bigger cost is on the wire: the same run measured a 2,726-byte ML-DSA-65 public key against 451 bytes for RSA-2048, and a 3,309-byte signature. For DTLS, where a handshake flight is split across datagrams, that is more fragments and more chances to lose one — which brings you back to the retransmission issues above.

Which OpenSSL version should you use now?

For most servers the answer is still the 3.5 LTS line, supported until 8 April 2030; take 4.1 when you need DTLS 1.3 or a 4.x feature and can upgrade again within a year. The downloads page lists four supported series:

SeriesEnd of lifeLTS
3.58 April 2030Yes
3.61 November 2026No
4.014 May 2027No
4.1November 2027No
Supported OpenSSL release series and their end-of-life dates, from openssl-library.org/source on 24 October 2026

The date that needs action is the first one to expire: 3.6 goes out of support on 1 November 2026, a week after this release. If you build against 3.6, choose now between moving back to 3.5 LTS (no API breaks to absorb) or forward to 4.1 (and the 4.0 breaks listed earlier). Distribution packages follow their own schedules; the 3.0.13 in the terminal above is what Ubuntu 24.04 shipped on this machine.

Upgrade checklist for OpenSSL 4.1

  • To do: If you are on 3.6, pick 3.5 LTS or 4.x before 1 November 2026.
  • To do: Scan private PKI for certificates without a subjectAltName; re-issue them before host-name checks start failing.
  • To do: Run tests that cover TLS 1.3 resumption and 0-RTT, and drop any that expect SSL_R_INCONSISTENT_EARLY_DATA_ALPN.
  • To do: Build once with AddressSanitizer to catch code that treats ASN1_STRING data as a C string.
  • To do: Replace no-ecdsa / no-ecdh in build scripts with no-ec if you meant it, or remove them.
  • To do: For DTLS 1.3: move from DTLSv1_listen() to SSL_new_listener(), keep address validation on, set the pending-connection limit, and test with packet loss and KeyUpdate.
  • To do: Verify the tarball against its .sha256 file before building.

OpenSSL 4.1 questions

When was OpenSSL 4.1.0 released?

OpenSSL 4.1.0 was tagged on 23 October 2026, after a second beta on 9 October delayed the final release over two reported DTLS 1.3 security issues.

Does OpenSSL support DTLS 1.3?

Yes, from 4.1.0. Set the protocol range to DTLS1_3_VERSION on a DTLS context and use SSL_new_listener() on the server; DTLSv1_listen() does not support DTLS 1.3.

Is OpenSSL 4.1 an LTS release?

No. 4.1 is supported until November 2027. The current LTS line is 3.5, supported until 8 April 2030.

Why do my certificates fail host-name verification after upgrading to OpenSSL 4.1?

4.1 no longer falls back to the subject common name when a certificate has no subject alternative name. Re-issue the certificate with a subjectAltName, or set X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT as a temporary workaround.

What is GREASE in OpenSSL?

GREASE (RFC 8701) makes a TLS client send reserved, meaningless values in its ClientHello so that servers which reject unknown values are found early. In OpenSSL 4.1 it is enabled with SSL_OP_GREASE, or -grease in s_client.

Does DTLS 1.3 in OpenSSL support Connection ID?

No. The 4.1 implementation ignores a client's Connection ID and never sends one, so a peer whose IP address or port changes cannot keep its session through a Connection ID.

When does OpenSSL 3.6 reach end of life?

OpenSSL 3.6 is supported until 1 November 2026, according to the OpenSSL downloads page.

Sources and further reading

Discussion

Join the discussion

Sign in with Google, Apple or an email code to comment and reply.

One practical article a week

Follow k13 in any RSS reader. No account needed.