Problem
A legacy application only negotiates TLS 1.0, while the servers enforce TLS 1.2+. Downgrading servers isn’t acceptable.
Approach
Create a local stunnel bridge:
- Inbound (server mode):
127.0.0.1:443
— accepts TLS 1.0 for the legacy client, bound to loopback only. - Outbound (client mode):
endpoint.example.com:443
— enforces TLS 1.2 and verifies the upstream certificate chain.
This isolates TLS 1.0 to the same host and keeps the network path modern.
stunnel configuration
Use a stunnel build linked with OpenSSL 1.1.1 for TLS 1.0 support. OpenSSL 3.x builds typically disable TLSv1/TLSv1.1 and will log
no protocols available
.
; Inbound: local listener (TLS 1.0), loopback only
[in-tls10]
accept = 127.0.0.1:443
connect = 127.0.0.1:4443
; key + cert (PEM)
cert = localhost.pem
sslVersionMin = TLSv1
sslVersionMax = TLSv1
; Optional for very old clients:
; ciphers = ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:AES256-SHA:AES128-SHA
TIMEOUTclose = 0
; Outbound: TLS 1.2 to real endpoint verification
[out-tls12]
client = yes
accept = 127.0.0.1:4443
connect = endpoint.example.com:443
sslVersionMin = TLSv1.2
sslVersionMax = TLSv1.2
verifyChain = yes
CAfile = ca-bundle.pem
checkHost = endpoint.example.com
Keep TLS 1.0 strictly on 127.0.0.1. Never bind it to a real interface.
Converting a PFX for stunnel (OpenSSL)
:: Extract leaf cert and unencrypted key
openssl pkcs12 -in localhost.pfx -clcerts -nokeys -out localhost.cert.pem
openssl pkcs12 -in localhost.pfx -nocerts -nodes -out localhost.key.pem
:: Combine for stunnel listener
copy /b localhost.key.pem+localhost.cert.pem localhost.pem
:: Extract CA chain for upstream verification
openssl pkcs12 -in server.pfx -nokeys -cacerts -out ca-bundle.pem
Prefer generating a separate cert/key for the local listener; use the PFX primarily to build CAfile for upstream verification.
Check inbound TLS1.0
openssl s_client -tls1 -connect 127.0.0.1:636 -servername localhost
If your Windows TLS 1.0 client is disabled (Schannel policy), a PowerShell TLS1.0 handshake will fail even when stunnel accepts TLS1.0. Use openssl s_client -tls1 for the inbound test.
Troubleshooting notes
stunnel log: fatal: protocol version / no protocols available → Your stunnel build doesn’t support TLS 1.0. Install a build with OpenSSL 1.1.1 for the inbound section, or run inbound on a small Linux VM with OpenSSL 1.1.1.
Chain/host validation errors upstream → Ensure CAfile contains the correct chain and checkHost matches a SAN/CN on the LDAP cert.
Schannel events 36871/36887 → Often signal policy/cipher/protocol mismatch. Validate with the diagnostics script and stunnel logs.
Security posture
- Keep the TLS1.0 listener loopback-only.
- Verify upstream with CA chain + hostname.
Outcome
Legacy app keeps working against a TLS 1.2–only endpoint, without weakening server-side security. The bridge is transparent to the app (https://127.0.0.1) and fully verified upstream.