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.
| Released | 23 October 2026 (release notes) |
| Type | Feature release on the 4.x line; not LTS |
| Supported until | November 2027 (downloads page) |
| Tarball | openssl-4.1.0.tar.gz, 53.2 MiB |
| New protocols | DTLS 1.3, DTLS in the SSL listener API, RFC 8701 GREASE |
| Known issues at release | Four, all in DTLS (#32878, #33242, #33277, #33278) |
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_GREASEset, a client injects reserved values into cipher suites, versions, groups, signature algorithms, key shares and extensions in itsClientHello.openssl s_client -greaseturns 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:
#!/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)" fidoneTLS 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-ecdsaandno-ecdhare gone; according to the release notes they never disabled anything. Useno-ec.- The
VC-WIN64I(Windows on Itanium) andVC-CE(Windows CE) targets are removed. - The
tsgetscript now needs the Perl moduleNet::Curl::Easyinstead of the abandonedWWW::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.
- 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
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():
| Value | Controls | Default |
|---|---|---|
SSL_VALUE_DTLS_LISTENER_MAX_PENDING_CONNS | Connections the listener holds before you accept them | 256 |
SSL_VALUE_DTLS_LISTENER_PENDING_TIMEOUT | How long a pending connection waits, in ms | 30000 |
SSL_VALUE_DTLS_LISTENER_MAX_DGRAM_SIZE | Largest datagram the listener reads, in bytes | 2000 |
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:
$ 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:
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.pemThe -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().
#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); }}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.
| Issue | What happens | Who should care |
|---|---|---|
| #32878 | After a DTLS 1.3 KeyUpdate, post-handshake records such as NewSessionTicket can drop out of the retransmission buffer and are not resent if lost | Long-lived sessions that rekey on lossy links |
| #33242 | A DTLS 1.3 server may abort with unexpected_message when a client acknowledges part of the first flight early | Servers facing other DTLS 1.3 stacks |
| #33277 | A permanent receive failure on a DTLS listener can surface as SSL_ERROR_WANT_READ | Event loops that wait forever on WANT_READ |
| #33278 | A retryable write failure from a listener connection can surface as SSL_ERROR_SYSCALL instead of SSL_ERROR_WANT_WRITE | Non-blocking servers that treat SYSCALL as fatal |
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:
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)
| RSA-2048 | ML-DSA-65 | |
|---|---|---|
| Sign | 2,110.7 ops/s | 2,719.1 ops/s |
| Verify | 33.8k ops/s | 13.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:
| Series | End of life | LTS |
|---|---|---|
| 3.5 | 8 April 2030 | Yes |
| 3.6 | 1 November 2026 | No |
| 4.0 | 14 May 2027 | No |
| 4.1 | November 2027 | No |
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_STRINGdata as a C string. - To do: Replace
no-ecdsa/no-ecdhin build scripts withno-ecif you meant it, or remove them. - To do: For DTLS 1.3: move from
DTLSv1_listen()toSSL_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
.sha256file 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
- OpenSSL 4.1.0 release on GitHub and the CHANGES.md and NEWS.md files
- ossl-guide-dtlsv13(7) and SSL_new_listener(3)
- The OpenSSL Library supports DTLS 1.3 and the 4.1 beta announcement
- 4.1.0-beta2 announcement on openssl-project
- OpenSSL downloads and support dates
- RFC 9147: DTLS 1.3 and RFC 8701: GREASE
- OpenSSL 4.1.0 shipped today. I built it and measured ML-KEM, ML-DSA, and DTLS 1.3 on dev.to
Discussion
Join the discussion
Sign in with Google, Apple or an email code to comment and reply.