DEV Community

Cover image for OpenSSL 4.1.0 shipped today. I built it and measured ML-KEM, ML-DSA, and DTLS 1.3.
frank chu
frank chu

Posted on

OpenSSL 4.1.0 shipped today. I built it and measured ML-KEM, ML-DSA, and DTLS 1.3.

OpenSSL 4.1.0 was released today, October 23. The headline is DTLS 1.3 (RFC 9147) — the UDP sibling of TLS finally catching up to the 1.3 baseline — plus RFC 8701 GREASE, DTLS support in the SSL listener API, an IKEv2 KDF, and a round of speedups for the post-quantum algorithms: optimized ML-DSA and ML-KEM NTT operations, AVX-512 SHAKE x4 for ML-DSA on x86_64, and AVX-512/VAES AES-CBC decryption.

Release notes are claims. I downloaded the source, built it, and ran the parts I could measure on this machine: a 2 vCPU AMD EPYC 9D25 (AVX-512 present), gcc -O3, static build (no-shared no-tests). The system OpenSSL here is 3.0.13, which makes the before/after easy to see.

First, a build note that cost me twenty minutes: the tarball is 54 MB, but a default build does not fit in a 512 MB /tmp tmpfs — the linker died with No space left on device while linking a test binary. Build on a real disk, and no-tests is your friend if all you want is the openssl binary.

DTLS 1.3 negotiates — and 3.0 can't even parse the flag

On the 4.1.0 build, a loopback handshake between s_server -dtls1_3 and s_client -dtls1_3 with a fresh self-signed EC certificate:

Protocol: DTLSv1.3
Verify return code: 0 (ok)
Enter fullscreen mode Exit fullscreen mode

That is the whole demo, and it's the point: DTLS users (VPNs, WebRTC-ish stacks, IoT) have been stuck at a 1.2-era protocol while TLS moved on. The release notes are honest that the new code has rough edges — four known DTLS issues ship in 4.1.0, including #32878, where receiving a DTLS 1.3 KeyUpdate drops other outstanding post-handshake records from the retransmission buffer (a lost NewSessionTicket may never be retransmitted), and #33242, where a server may abort with unexpected_message if a client ACKs part of the first flight early. A fix for the first is already in progress. Read that list before you deploy, not after.

The post-quantum numbers

The system 3.0.13 knows zero post-quantum algorithms:

$ openssl list -public-key-algorithms | grep -ciE 'ML-|SLH'
0
Enter fullscreen mode Exit fullscreen mode

4.1.0 ships ML-KEM-512/768/1024, ML-DSA-44/65/87, the SLH-DSA family, and hybrid TLS groups (X25519MLKEM768, SecP256r1MLKEM768, and friends) in the default provider. Here is openssl speed, 2–3 second runs, single-threaded:

                               keygen    encaps    decaps  keygens/s  encaps/s  decaps/s
ML-KEM-512                0.000039s  0.000026s  0.000040s    25447.9   38700.0   25275.9
ML-KEM-768                0.000061s  0.000033s  0.000052s    16345.9   29921.6   19203.1
ML-KEM-1024               0.000092s  0.000046s  0.000067s    10817.7   21531.2   14865.0

                               keygen     signs    verify  keygens/s    sign/s  verify/s
ML-DSA-44                 0.000060s  0.000213s  0.000046s    16662.1    4701.3   21700.7
ML-DSA-65                 0.000135s  0.000368s  0.000074s     7423.6    2719.1   13598.3
ML-DSA-87                 0.000137s  0.000412s  0.000118s     7292.3    2427.1    8452.8
rsa2048                   0.076486s  0.000474s  0.000030s       13.1    2110.7   33781.9
rsa4096                   0.616000s  0.002879s  0.000107s        1.6     347.3    9387.5
Enter fullscreen mode Exit fullscreen mode

Two things stand out. First, ML-KEM-768 key generation is roughly 1,200x faster than RSA-2048 key generation (16,346/s vs 13.1/s) — RSA keygen was always the slow part, but seeing it next to a lattice KEM makes the gap look absurd. Second, ML-DSA-65 signs faster than RSA-2048 (2,719/s vs 2,111/s) but verifies at only 40% of RSA's verify rate (13,598/s vs 33,782/s). If your workload is verify-heavy — say, a server validating a lot of client signatures, or anything checking signed artifacts at scale — that asymmetry is the number to plan around, not the headline "post-quantum is fast."

The cost is bytes, not cycles

What PQC actually charges you is size. Measured on keys I generated with the 4.1.0 binary:

ML-KEM-768 private key (PEM)   3439 bytes    public key (PEM)   1686 bytes
ML-DSA-65  private key (PEM)   5604 bytes    public key (PEM)   2726 bytes
ML-DSA-65  signature on a 10-byte message: 3309 bytes
RSA-2048   private key (PEM)   1700 bytes    public key (PEM)    451 bytes
Enter fullscreen mode Exit fullscreen mode

An ML-DSA-65 signature is 3,309 bytes — about 13x an RSA-2048 signature — and the public key that travels in a certificate is 6x larger. Every handshake, every certificate chain, every signed token gets heavier. The CPU got cheaper and the wire got more expensive; that's the actual trade of the PQC migration, and 4.1 doesn't change it. It just makes the CPU side fast enough that the bytes are now the bottleneck worth arguing about.

Smaller print worth knowing

  • The no-ecdsa and no-ecdh configure options are gone — the release notes admit they never really disabled the implementations. Use no-ec.
  • The tsget utility switched from the abandoned WWW::Curl::Easy Perl module to Net::Curl::Easy. If you script timestamping, install the new dependency before upgrading, not after your cron job fails.
  • Windows CE and Windows-on-Itanium build targets were dropped.

My take: 4.1 is worth building this week if you ship anything DTLS or if you're starting a PQC migration — the hybrid groups and the ML-DSA/ML-KEM performance are real, and I verified both on commodity hardware in an afternoon. It's also a feature release whose own notes list four known issues in its headline feature. Test the handshake paths you actually use, especially around KeyUpdate and packet loss. The code is fast; the edges are documented; both of those are reasons to start now and deploy carefully.

Sources: OpenSSL 4.1.0 release notes (github.com/openssl/openssl, tag openssl-4.1.0, October 23, 2026) and the OpenSSL Library's DTLS 1.3 announcement. All builds, handshakes, benchmarks, and key sizes are my own runs against a self-built OpenSSL 4.1.0 (no-shared no-tests, -O3) on a 2 vCPU AMD EPYC 9D25 VM; openssl speed numbers are short 2–3 s runs and will vary by hardware.

Top comments (1)

Collapse
 
vardum profile image
Vardum (formerly VEIL) •

Thanks for actually running the numbers. The size point is the one that bites in practice: an X25519MLKEM768 key share is about 1.2 KB, which can push the ClientHello past a single packet. Over DTLS 1.3 that means a fragmented first flight that's more exposed to loss, so I'd be curious to see handshake success rates on a lossy link with hybrid vs classical groups.