Notes / Domino 14.5.1 – Testing TLS 1.3 and Post-Quantum Cryptography with HttpGetRequest
Recently I received the first questions about protecting against attacks based on quantum computing, often referred to as Post-Quantum Cryptography (PQC).
It’s interesting to see this topic appearing in real customer discussions. Thinking ahead about cryptography is certainly important. However, the ecosystem is still evolving and very little software currently supports the new algorithms.
With Notes/Domino 14.5.1 EA2, there is now early groundwork for PQC support.
But what does this actually mean? And how can we test it?
What Domino 14.5.1 introduces
From the What's New in Notes/Domino 14.5.1 EA2 – Security section:
The OpenSSL library has been updated to version 3.5.4 in Domino 14.5.1 EAP2. This is a Long Term Support (LTS) version of the library that has been submitted to the CMVP for FIPS 140-3 verification.
The cryptographic layer underlying Notes and Domino now leverages OpenSSL 3.5 to support multiple algorithms relevant to protect against attacks based on quantum computing, such as ML-DSA, ML-KEM, SHAKE-128, and SHAKE-256.
As this field is rapidly evolving and the IETF standards are still being written, there is no end-user PQC functionality currently available for use in 14.5.1.
What this actually means
Notes/Domino 14.5.1 ships with OpenSSL 3.5.4.
OpenSSL 3.5 is the first mainstream OpenSSL version that includes initial support for PQC algorithms, including:
- ML-DSA (signature algorithm)
- ML-KEM (key encapsulation)
- SHAKE-128
- SHAKE-256
Both OpenSSL and libcurl (it uses OpenSSL) are statically linked into Notes/Domino, which means Domino can use these algorithms wherever the OpenSSL backend is used.
One example is the LotusScript HttpGetRequest class.
Other components inside Notes/Domino still rely on the classical SSL/NTI stack, which currently does not support TLS 1.3.
Where libcurl is used, TLS 1.3 and PQC-related algorithms become available.
The ecosystem challenge
Most Linux distributions ship much older OpenSSL versions.
OpenSSL 3.5.x is still very new, so both ends of the connection must support it.
Requirements for PQC testing:
| Component | Requirement |
| Server | OpenSSL ≥ 3.5 |
| Client | OpenSSL ≥ 3.5 |
| Go applications | Go ≥ 1.26 (Go does not use OpenSSL) |
Testing PQC support
To experiment with PQC without upgrading an existing server environment, OpenSSL provides a very useful tool:
openssl s_server
This command allows running a simple TLS test server.
When used with the -www option, it returns a basic HTML page showing TLS handshake information.
Running a test server
The example below restricts the server to the PQC hybrid group X25519MLKEM768.
If a client supports PQC hybrid TLS, the connection will succeed.
Using a container for a modern OpenSSL version
A simple way to obtain a recent OpenSSL build is using a Kali Linux container, which ships with very recent packages.
openssl_s_server.sh
apt update
apt install -y openssl
HOSTNAME=$(hostname)
echo
echo HostName: "$HOSTNAME"
echo
if [ ! -e /local/server.key ] || [ ! -e /local/server.crt ]; then
openssl req -x509 -new -newkey ec \
-pkeyopt ec_paramgen_curve:P-256 \
-pkeyopt ec_param_enc:named_curve \
-nodes \
-keyout /local/server.key \
-out /local/server.crt \
-days 365 \
-subj "/CN=$HOSTNAME" \
-addext "subjectAltName=DNS:$HOSTNAME,DNS:localhost,IP:127.0.0.1"
fi
openssl s_server \
-accept 8443 \
-cert /local/server.crt \
-key /local/server.key \
-groups X25519MLKEM768 \
-www \
-state
run.sh
HOSTNAME=$(hostname -f)
docker run --rm -it \
--name openssl \
--hostname "$HOSTNAME" \
-p 443:8443 \
-v .:/local \
kalilinux/kali-rolling \
bash -c /local/openssl_s_server.sh
Test results
A Notes 14.5 FP1 client cannot connect to this server.
However, the same request using Notes 14.5.1 EA2 works.
The TLS negotiation output includes:
Supported groups: X25519MLKEM768:x25519:secp256r1:x448:secp384r1
Shared groups: X25519MLKEM768
Meaning the connection successfully negotiated the PQC hybrid group.
The TLS session shows but the imported part is the group/CurveID
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
Java comparison
Java currently does not support PQC in TLS.
Even Java 21 does not implement:
- ML-DSA
- ML-KEM
- PQ hybrid TLS groups
Conclusion
Notes&Domino 14.5.1 ships with a very current OpenSSL version, helping the platform stay ahead of the cryptographic curve — quite literally.
However:
- Domino HTTP still requires a reverse proxy for TLS 1.3 and PQC support
- Most production environments already use reverse proxies or load balancers
At the moment, few environments have an immediate need for PQC-safe operations, but it is useful to start experimenting with the technology.
Testing external servers
To test a server you can use:
openssl s_client -connect www.example.com:443
Make sure you are running OpenSSL 3.5 or newer, otherwise PQC groups will not be available.
Logs from OpenSSL s_server
s_server -accept 8443 -cert /local/server.crt -key /local/server.key -cert_chain /local/chain.pem -groups X25519MLKEM768 -www -state
This TLS version forbids renegotiation.
Ciphers supported in s_server binary
TLSv1.3 :TLS_AES_256_GCM_SHA384 TLSv1.3 :TLS_CHACHA20_POLY1305_SHA256
TLSv1.3 :TLS_AES_128_GCM_SHA256 TLSv1.2 :ECDHE-ECDSA-AES256-GCM-SHA384
TLSv1.2 :ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 :DHE-DSS-AES256-GCM-SHA384
TLSv1.2 :DHE-RSA-AES256-GCM-SHA384 TLSv1.2 :ECDHE-ECDSA-CHACHA20-POLY1305
TLSv1.2 :ECDHE-RSA-CHACHA20-POLY1305 TLSv1.2 :DHE-RSA-CHACHA20-POLY1305
TLSv1.2 :ECDHE-ECDSA-AES256-CCM TLSv1.2 :DHE-RSA-AES256-CCM
TLSv1.2 :ECDHE-ECDSA-ARIA256-GCM-SHA384 TLSv1.2 :ECDHE-ARIA256-GCM-SHA384
TLSv1.2 :DHE-DSS-ARIA256-GCM-SHA384 TLSv1.2 :DHE-RSA-ARIA256-GCM-SHA384
TLSv1.2 :ADH-AES256-GCM-SHA384 TLSv1.2 :ECDHE-ECDSA-AES128-GCM-SHA256
TLSv1.2 :ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 :DHE-DSS-AES128-GCM-SHA256
TLSv1.2 :DHE-RSA-AES128-GCM-SHA256 TLSv1.2 :ECDHE-ECDSA-AES128-CCM
TLSv1.2 :DHE-RSA-AES128-CCM TLSv1.2 :ECDHE-ECDSA-ARIA128-GCM-SHA256
TLSv1.2 :ECDHE-ARIA128-GCM-SHA256 TLSv1.2 :DHE-DSS-ARIA128-GCM-SHA256
TLSv1.2 :DHE-RSA-ARIA128-GCM-SHA256 TLSv1.2 :ADH-AES128-GCM-SHA256
TLSv1.2 :ECDHE-ECDSA-AES256-CCM8 TLSv1.2 :ECDHE-ECDSA-AES128-CCM8
TLSv1.2 :DHE-RSA-AES256-CCM8 TLSv1.2 :DHE-RSA-AES128-CCM8
TLSv1.2 :ECDHE-ECDSA-AES256-SHA384 TLSv1.2 :ECDHE-RSA-AES256-SHA384
TLSv1.2 :DHE-RSA-AES256-SHA256 TLSv1.2 :DHE-DSS-AES256-SHA256
TLSv1.2 :ECDHE-ECDSA-CAMELLIA256-SHA384 TLSv1.2 :ECDHE-RSA-CAMELLIA256-SHA384
TLSv1.2 :DHE-RSA-CAMELLIA256-SHA256 TLSv1.2 :DHE-DSS-CAMELLIA256-SHA256
TLSv1.2 :ADH-AES256-SHA256 TLSv1.2 :ADH-CAMELLIA256-SHA256
TLSv1.2 :ECDHE-ECDSA-AES128-SHA256 TLSv1.2 :ECDHE-RSA-AES128-SHA256
TLSv1.2 :DHE-RSA-AES128-SHA256 TLSv1.2 :DHE-DSS-AES128-SHA256
TLSv1.2 :ECDHE-ECDSA-CAMELLIA128-SHA256 TLSv1.2 :ECDHE-RSA-CAMELLIA128-SHA256
TLSv1.2 :DHE-RSA-CAMELLIA128-SHA256 TLSv1.2 :DHE-DSS-CAMELLIA128-SHA256
TLSv1.2 :ADH-AES128-SHA256 TLSv1.2 :ADH-CAMELLIA128-SHA256
TLSv1.0 :ECDHE-ECDSA-AES256-SHA TLSv1.0 :ECDHE-RSA-AES256-SHA
SSLv3 :DHE-RSA-AES256-SHA SSLv3 :DHE-DSS-AES256-SHA
SSLv3 :DHE-RSA-CAMELLIA256-SHA SSLv3 :DHE-DSS-CAMELLIA256-SHA
TLSv1.0 :AECDH-AES256-SHA SSLv3 :ADH-AES256-SHA
SSLv3 :ADH-CAMELLIA256-SHA TLSv1.0 :ECDHE-ECDSA-AES128-SHA
TLSv1.0 :ECDHE-RSA-AES128-SHA SSLv3 :DHE-RSA-AES128-SHA
SSLv3 :DHE-DSS-AES128-SHA SSLv3 :DHE-RSA-SEED-SHA
SSLv3 :DHE-DSS-SEED-SHA SSLv3 :DHE-RSA-CAMELLIA128-SHA
SSLv3 :DHE-DSS-CAMELLIA128-SHA TLSv1.0 :AECDH-AES128-SHA
SSLv3 :ADH-AES128-SHA SSLv3 :ADH-SEED-SHA
SSLv3 :ADH-CAMELLIA128-SHA TLSv1.2 :RSA-PSK-AES256-GCM-SHA384
TLSv1.2 :DHE-PSK-AES256-GCM-SHA384 TLSv1.2 :RSA-PSK-CHACHA20-POLY1305
TLSv1.2 :DHE-PSK-CHACHA20-POLY1305 TLSv1.2 :ECDHE-PSK-CHACHA20-POLY1305
TLSv1.2 :DHE-PSK-AES256-CCM TLSv1.2 :RSA-PSK-ARIA256-GCM-SHA384
TLSv1.2 :DHE-PSK-ARIA256-GCM-SHA384 TLSv1.2 :AES256-GCM-SHA384
TLSv1.2 :AES256-CCM TLSv1.2 :ARIA256-GCM-SHA384
TLSv1.2 :PSK-AES256-GCM-SHA384 TLSv1.2 :PSK-CHACHA20-POLY1305
TLSv1.2 :PSK-AES256-CCM TLSv1.2 :PSK-ARIA256-GCM-SHA384
TLSv1.2 :RSA-PSK-AES128-GCM-SHA256 TLSv1.2 :DHE-PSK-AES128-GCM-SHA256
TLSv1.2 :DHE-PSK-AES128-CCM TLSv1.2 :RSA-PSK-ARIA128-GCM-SHA256
TLSv1.2 :DHE-PSK-ARIA128-GCM-SHA256 TLSv1.2 :AES128-GCM-SHA256
TLSv1.2 :AES128-CCM TLSv1.2 :ARIA128-GCM-SHA256
TLSv1.2 :PSK-AES128-GCM-SHA256 TLSv1.2 :PSK-AES128-CCM
TLSv1.2 :PSK-ARIA128-GCM-SHA256 TLSv1.2 :DHE-PSK-AES256-CCM8
TLSv1.2 :DHE-PSK-AES128-CCM8 TLSv1.2 :AES256-CCM8
TLSv1.2 :AES128-CCM8 TLSv1.2 :PSK-AES256-CCM8
TLSv1.2 :PSK-AES128-CCM8 TLSv1.2 :AES256-SHA256
TLSv1.2 :CAMELLIA256-SHA256 TLSv1.2 :AES128-SHA256
TLSv1.2 :CAMELLIA128-SHA256 TLSv1.0 :ECDHE-PSK-AES256-CBC-SHA384
TLSv1.0 :ECDHE-PSK-AES256-CBC-SHA SSLv3 :SRP-DSS-AES-256-CBC-SHA
SSLv3 :SRP-RSA-AES-256-CBC-SHA SSLv3 :SRP-AES-256-CBC-SHA
TLSv1.0 :RSA-PSK-AES256-CBC-SHA384 TLSv1.0 :DHE-PSK-AES256-CBC-SHA384
SSLv3 :RSA-PSK-AES256-CBC-SHA SSLv3 :DHE-PSK-AES256-CBC-SHA
TLSv1.0 :ECDHE-PSK-CAMELLIA256-SHA384 TLSv1.0 :RSA-PSK-CAMELLIA256-SHA384
TLSv1.0 :DHE-PSK-CAMELLIA256-SHA384 SSLv3 :AES256-SHA
SSLv3 :CAMELLIA256-SHA TLSv1.0 :PSK-AES256-CBC-SHA384
SSLv3 :PSK-AES256-CBC-SHA TLSv1.0 :PSK-CAMELLIA256-SHA384
TLSv1.0 :ECDHE-PSK-AES128-CBC-SHA256 TLSv1.0 :ECDHE-PSK-AES128-CBC-SHA
SSLv3 :SRP-DSS-AES-128-CBC-SHA SSLv3 :SRP-RSA-AES-128-CBC-SHA
SSLv3 :SRP-AES-128-CBC-SHA TLSv1.0 :RSA-PSK-AES128-CBC-SHA256
TLSv1.0 :DHE-PSK-AES128-CBC-SHA256 SSLv3 :RSA-PSK-AES128-CBC-SHA
SSLv3 :DHE-PSK-AES128-CBC-SHA TLSv1.0 :ECDHE-PSK-CAMELLIA128-SHA256
TLSv1.0 :RSA-PSK-CAMELLIA128-SHA256 TLSv1.0 :DHE-PSK-CAMELLIA128-SHA256
SSLv3 :AES128-SHA SSLv3 :SEED-SHA
SSLv3 :CAMELLIA128-SHA TLSv1.0 :PSK-AES128-CBC-SHA256
SSLv3 :PSK-AES128-CBC-SHA TLSv1.0 :PSK-CAMELLIA128-SHA256
---
Ciphers common between both SSL end points:
TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256
ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-GCM-SHA384
ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-CHACHA20-POLY1305
ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-GCM-SHA256
ECDHE-ECDSA-AES256-SHA384 ECDHE-RSA-AES256-SHA384 DHE-RSA-AES256-SHA256
ECDHE-ECDSA-AES128-SHA256 ECDHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA256
ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES256-SHA
ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES128-SHA DHE-RSA-AES128-SHA
AES256-GCM-SHA384 AES128-GCM-SHA256 AES256-SHA256
AES128-SHA256 AES256-SHA AES128-SHA
Signature Algorithms: id-ml-dsa-65:id-ml-dsa-87:id-ml-dsa-44:ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:ed25519:ed448:ecdsa_brainpoolP256r1_sha256:ecdsa_brainpoolP384r1_sha384:ecdsa_brainpoolP512r1_sha512:rsa_pss_pss_sha256:rsa_pss_pss_sha384:rsa_pss_pss_sha512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA224:RSA+SHA224:DSA+SHA224:DSA+SHA256:DSA+SHA384:DSA+SHA512
Shared Signature Algorithms: id-ml-dsa-65:id-ml-dsa-87:id-ml-dsa-44:ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:ed25519:ed448:ecdsa_brainpoolP256r1_sha256:ecdsa_brainpoolP384r1_sha384:ecdsa_brainpoolP512r1_sha512:rsa_pss_pss_sha256:rsa_pss_pss_sha384:rsa_pss_pss_sha512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA224:RSA+SHA224
Supported groups: X25519MLKEM768:x25519:secp256r1:x448:secp384r1:secp521r1:ffdhe2048:ffdhe3072
Shared groups: X25519MLKEM768
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
SSL-Session:
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
Session-ID: AA0FD5EF7D084515DB148EB6AEF8061905A90BAD3E87DE157B5859212135E283
Session-ID-ctx: 01000000
Resumption PSK: 75BAD9484C7D6F0CF176130FC6CEE498A8CF3F12C154080D1547F9B4ED12C4A72596345B3AC6D82EA2C2233C3C929558
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1772999818
Timeout : 7200 (sec)
Verify return code: 0 (ok)
Extended master secret: no
Max Early Data: 0
---
0 items in the session cache
0 client connects (SSL_connect())
0 client renegotiates (SSL_connect())
0 client connects that finished
29 server accepts (SSL_accept())
0 server renegotiates (SSL_accept())
20 server accepts that finished
2 session cache hits
0 session cache misses
0 session cache timeouts
0 callback cache hits
0 cache full overflows (128 allowed)
---
no client certificate available
- Comments [0]