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.