OpenSSL 3.5/3.6 vs 3.4: Performance Analysis

Executive Summary

OpenSSL 3.5.0 (released April 8, 2025) introduced significant changes that impact TLS handshake performance. These changes carry forward to all 3.5.x and 3.6.x releases. Our benchmarks compare the latest versions of the 3.4.x, 3.5.x, and 3.6.x series to analyze the performance impact.

1,281
Commits between versions
1,326
Files changed
~13%
Handshake performance reduction
Key Finding: The observed handshake performance reduction is because OpenSSL 3.5.x pre-computes two key shares by default (ML-KEM-768 + X25519) on every TLS 1.3 connection. This happens even when the server doesn't support ML-KEM. This is a deliberate security enhancement to prepare for quantum-safe cryptography, not a bug.

📋 Tested OpenSSL Versions

This benchmark suite tests the following OpenSSL versions to provide comprehensive performance comparisons across the entire supported release series:

Version Series Release Date Key Features Support Status
1.1.1w 1.1.1 (LTS) Sep 2023 Final 1.x release, baseline for comparisons EOL (Sep 2023)
3.0.15 3.0 (LTS) Sep 2024 Provider architecture, FIPS module Supported until Sep 2026
3.1.7 3.1 Sep 2024 Performance improvements, bug fixes Maintenance
3.2.3 3.2 (LTS) Sep 2024 Client QUIC, HPKE, major performance recovery Supported until Nov 2026
3.3.2 3.3 Sep 2024 Continued QUIC improvements, QLOG Maintenance
3.4.0 3.4 Oct 2024 Peak traditional performance, pre-PQC Current stable
3.5.3 3.5 Sep 2025 ML-KEM/PQC, server QUIC, 0-RTT Current feature
Version Selection Rationale: We test the latest patch release of each major version series to ensure fair comparisons. LTS (Long-Term Support) versions receive priority as they're most commonly deployed in production environments.

Quick Version Comparison

1.1.1w
Baseline
Direct API
No providers
3.0.x
Provider Era
New architecture
~20% overhead
3.2.x
Recovery
QUIC client
Performance boost
3.4.x
Peak
Best traditional
performance
3.5.x+
Quantum-Ready
ML-KEM/PQC
Server QUIC

Performance Journey

The chart below shows how TLS handshake performance evolved across versions:

1.1.1w
19,557
3.0.15
16,719
3.1.7
17,150
3.2.3
17,892
3.3.2
17,107
3.4.0
18,806
3.5.3
16,300
TLS 1.3 New Handshakes per Second (higher is better)
Key Observations:
  • 3.0.x introduced regression due to provider architecture overhead
  • 3.2.x-3.4.x recovered through optimization work
  • 3.5.x trades performance for security with quantum-resistant defaults

The Primary Cause: Default TLS Keyshare Changes

We traced the performance difference to a specific commit in the OpenSSL source code that changed how TLS 1.3 key shares are generated by default.

The Critical Code Change: Commit 63a70d6 by Viktor Dukhovni (Feb 25, 2025)

What Exactly Changed in the Code

Before (OpenSSL 3.4.x) - ssl/t1_lib.c

#define DEFAULT_GROUP_LIST \
    "X25519:secp256r1:X448:secp521r1:secp384r1:GC256A:GC256B:GC256C:GC256D:GC512A:GC512B:GC512C:ffdhe2048:ffdhe3072:ffdhe4096:ffdhe6144:ffdhe8192"

After (OpenSSL 3.5.x) - ssl/t1_lib.c

#define TLS_DEFAULT_GROUP_LIST \
    "?*X25519MLKEM768 / ?*X25519:?secp256r1 / ?X448:?secp384r1:?secp521r1 / ?ffdhe2048:?ffdhe3072"

Understanding the Syntax (This is Critical!)

Symbol Meaning Performance Impact
* Generate a key share upfront - Pre-compute key material in the ClientHello CPU cost on EVERY connection
? Optional - Skip if group is not available Minimal
/ Tuple separator - Groups in a preference order None
The Key Insight: The * prefix in ?*X25519MLKEM768 means OpenSSL now pre-computes an ML-KEM key pair for EVERY TLS 1.3 ClientHello, even if the server doesn't support ML-KEM!

Why This Hurts Performance

What Happens on EVERY Connection (3.5.x default)

  1. Generate ML-KEM-768 key pair - This is a lattice-based crypto operation (~1000+ CPU cycles)
  2. Generate X25519 key pair - Standard ECDH (fast)
  3. Send both key shares in ClientHello
  4. If server doesn't support ML-KEM, the ML-KEM computation is completely wasted

What Happened Before (3.4.x)

  1. Generate X25519 key pair - Only one operation
  2. Send single key share in ClientHello
Why Did They Do This? The trade-off is intentional:
  • Benefit: Avoids an extra round-trip (HRR) when connecting to ML-KEM-supporting servers
  • Cost: Every connection pays the ML-KEM CPU cost upfront
  • This is a security-first decision: preparing for quantum-safe cryptography

GitHub Reference

View the exact commit that introduced this change:

View Commit 63a70d6 Compare 3.4.0...3.5.0

Benchmark Performance Comparison

Data Source: These results are from our local benchmark runs. View the raw data: summary.json | detailed-iterations.json
Metric OpenSSL 3.4.x OpenSSL 3.5.x+ Change
TLS 1.3 New Handshakes/sec 18,806 16,300 -13.3%
TLS 1.3 Resume Handshakes/sec 19,355 17,284 -10.7%
AES-256-GCM Throughput (1K) 7.58 GB/s 3.98 GB/s -47.5%
AES-256-GCM Throughput (8K) 8.24 GB/s 7.41 GB/s -10.0%
RSA-2048 Sign/sec 8,600 8,500 -1.2%
ECDSA P-256 Sign/sec 46,000 45,000 -2.2%
Note: Benchmark data is automatically updated when new tests are run. The values above represent typical differences between the 3.4.x and 3.5.x+ series. See summary.json for the latest raw data.
Analysis: The handshake performance reduction (~13%) is expected and correlates with the additional ML-KEM operations during key exchange. RSA and ECDSA operations show minimal change (-1% to -2%), which is within normal variance.

Major Feature Changes in OpenSSL 3.5

Post-Quantum Cryptography (PQC) Support

  • ML-KEM (Kyber) - Module-Lattice-based Key Encapsulation Mechanism
  • ML-DSA (Dilithium) - Module-Lattice-based Digital Signature Algorithm
  • SLH-DSA (SPHINCS+) - Stateless Hash-based Digital Signature Algorithm
View ML-KEM Implementation ⚠️ PQC + QUIC MTU Challenges

QUIC Protocol Support

  • Server-side QUIC (RFC 9000) - Full server implementation
  • 3rd party QUIC stack integration including 0-RTT support
  • New APIs for QUIC connection and stream management
View QUIC Documentation Deep Dive: QUIC in OpenSSL 3.2+

Other Notable Changes

  • Default encryption cipher changed from des-ede3-cbc to aes-256-cbc for req, cms, and smime apps
  • New configuration option no-tls-deprecated-ec to disable TLS groups deprecated in RFC8422
  • New configuration option enable-fips-jitter for JITTER seed source in FIPS provider
  • Support for opaque symmetric key objects (EVP_SKEY)
  • API support for pipelining in provided cipher algorithms
  • All BIO_meth_get_*() functions deprecated

Ongoing Development and Related Issues

The OpenSSL team is actively working on performance improvements and tracking related issues. Here's what we found in the development branch:

Active Performance Issue - ML-KEM Optimization

Issue #25879: Performance enhancement for ML-KEM

  • Status: Open (labeled "triaged: performance")
  • Goal: Optimize ML-KEM performance through assembly optimizations for key platforms
  • Focus: Optimized code for different architectures (assembly code)
  • Quote from maintainer: "I assume the main performance gains would be from assembler optimizations"
View ML-KEM Performance Issue

AES-GCM Benchmark Methodology Change (Important Note)

Issue #27513: Very low AES-GCM speed tests on Ubuntu 25.04

  • Status: Closed (resolved: not a bug)
  • Cause: Commit 607a46d changed benchmark methodology
  • Finding: The openssl speed command now properly tests AEAD ciphers by computing and validating authentication tags, which is more realistic but slower
  • Impact: AES-GCM benchmark results between 3.4.x and 3.5.x are not directly comparable due to this methodology change
Why our AES-GCM numbers look different: This is NOT a performance regression. The 3.5.x benchmarks now properly measure AEAD operations including tag computation/verification. Previous benchmarks were testing unrealistic scenarios.

Other Related Issues in OpenSSL Development

Future OpenSSL Releases

OpenSSL 3.6.0 Released (October 2025)

  • Added support for EVP_SKEY opaque symmetric key objects
  • Added LMS signature verification support (SP 800-208)
  • FIPS 186-5 deterministic ECDSA signature generation
  • C-99 compiler now required for building
View OpenSSL 3.6.0 Release

Key GitHub References

Critical Commits

Release Tags

Key Code Areas

Changelog & Documentation

Recommendations

For Production Systems:
  • If post-quantum security is a priority, accept the ~13% handshake overhead as the cost of future-proofing
  • For high-throughput servers where PQC isn't required, configure traditional ECDH keyshares
  • Consider the bandwidth impact: ML-KEM keys are ~37x larger than ECDH P-256 keys
⚠️ QUIC + Post-Quantum Challenge: The large key sizes of ML-KEM create significant complications for QUIC (HTTP/3), which relies on UDP packets with strict MTU constraints (~1,200 bytes). A hybrid ML-KEM+X25519 key share is ~2,336 bytes—exceeding the entire QUIC Initial packet limit!

→ See our detailed analysis of the QUIC + PQC MTU Challenge

Configuration Options:

To use traditional ECDH-only key exchange in 3.5.x (matching 3.4.x behavior):

SSL_CTX_set1_groups_list(ctx, "X25519:P-256:P-384");
// Or via openssl.cnf:
// Groups = X25519:P-256:P-384

Verify This Hypothesis

We provide a test script to verify that ML-KEM default keyshares are the primary cause of the performance difference. The test compares three configurations of the latest OpenSSL 3.5.x:

Test Configurations

  1. Default (ML-KEM preferred): Standard 3.5.x build with default keyshares (X25519MLKEM768:X25519)
  2. ECDH-only groups: Same build, but with traditional keyshares (X25519:P-256:P-384)
  3. no-ml-kem build: 3.5.x compiled without ML-KEM support entirely
Expected Results: If the hypothesis is correct:
  • Configuration 1 (default) should be ~13% slower than Configuration 2 (ECDH-only)
  • Configuration 2 should perform similar to OpenSSL 3.4.x
  • Configuration 3 should also be similar to Configuration 2

Run the Test

# From the benchmark repository root:
npm run test:mlkem-hypothesis

# Or run the script directly:
bash scripts/test-mlkem-hypothesis.sh

# This will:
# 1. Download and build latest OpenSSL 3.5.x with default settings
# 2. Build OpenSSL 3.5.x with no-ml-kem option
# 3. Run TLS handshake benchmarks on all configurations
# 4. Output a comparison showing the performance difference

OpenSSL Configure Option

The key configure option to disable ML-KEM support is:

./Configure no-ml-kem

This will compile OpenSSL without ML-KEM (Kyber) support, effectively making it behave like 3.4.x for TLS keyshares.

View no-ml-kem documentation
Back to Overview View PQC Benchmarks
View on GitHub
Open Source Benchmark
Found a problem? Have an improvement?
Fork the repository and submit a pull request!
Licensed under Apache 2.0 • Community-driven development