How to Properly Configure stunnel to Send Full SSL Certificate Chain (Including Intermediate CAs)


2 views

When encountering SSL/TLS connection failures on specific clients (particularly older systems like Mac OS X 10.6), the problem often stems from incomplete certificate chain transmission. Modern browsers can often fetch missing intermediates automatically, but legacy systems require the server to send the complete chain during the TLS handshake.

The existing setup shows two potential issues:

cert = $CODEZ/admin/production/proxy/asana.pem
CAfile = $CODEZ/admin/production/proxy/sf_bundle.crt
  1. The certificate file may not contain the intermediate certificates
  2. The CAfile parameter in stunnel serves a different purpose than chain building

For Starfield/GoDaddy certificates, your .pem file should contain:

-----BEGIN CERTIFICATE-----
(Your primary certificate)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Intermediate certificate 1)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Intermediate certificate 2)
-----END CERTIFICATE-----

Here's the corrected configuration approach:

cert = /path/to/fullchain.pem  # Contains server cert + intermediates
key = /path/to/private.key     # Separate private key file
CAfile = /etc/ssl/certs/ca-certificates.crt  # System trust store

For GoDaddy/Starfield certificates specifically:

cat asana.crt gd_bundle-g2-g1.crt > fullchain.pem
# Ensure proper order: server cert first, then intermediates

Test your configuration with OpenSSL:

openssl s_client -connect yourdomain.com:443 -showcerts

Look for multiple certificates in the output. You should see:

  1. Your server certificate
  2. Intermediate certificate(s)
  3. (Optionally) The root certificate

Additional troubleshooting considerations:

  • Ensure file permissions: chmod 600 for private key
  • Verify certificate order in chain file
  • Check for certificate expiration
  • Confirm the private key matches the certificate

Here's a complete stunnel.conf example:

foreground = yes
debug = 5
output = /var/log/stunnel.log

[https]
accept = 443
connect = 8443
cert = /etc/stunnel/fullchain.pem
key = /etc/stunnel/private.key
CAfile = /etc/ssl/certs/ca-certificates.crt
verifyChain = yes
sslVersion = all
options = NO_SSLv2
options = NO_SSLv3

When setting up SSL/TLS with stunnel, a common issue that surfaces particularly with older systems (like Mac OS X 10.6 in your case) is the incomplete transmission of intermediate CA certificates. This manifests as connection rejections despite the certificate chain being technically valid.

Before diving into configuration, let's verify if intermediate certificates are actually being sent. Here are two reliable methods:

# Method 1: Using OpenSSL
openssl s_client -connect yourdomain.com:443 -showcerts

# Method 2: Using cURL
curl -v https://yourdomain.com

The key to solving this lies in how you bundle your certificates. Here's the correct approach:

# Correct stunnel.conf configuration
cert = /path/to/your_certificate.pem
CAfile = /path/to/full_chain_bundle.crt
verifyChain = yes

[your_service]
accept = 443
connect = 8443

For Starfield/GoDaddy certificates (which use multiple intermediates), you need to create a proper chain file:

# Create proper bundle (order matters!)
cat your_domain.crt gd_bundle-g2-g1.crt > full_chain.pem

# For Starfield specifically:
cat your_domain.crt sf_bundle.crt > full_chain.pem

If issues persist, try these debugging steps:

# 1. Verify certificate chain
openssl verify -CAfile sf_bundle.crt your_domain.pem

# 2. Check stunnel logs with increased verbosity
stunnel -fd 7 -p /path/to/stunnel.pem -d 443 -r 127.0.0.1:8443 -v 5

For legacy systems that don't support SNI or modern TLS versions:

# Additional stunnel parameters for compatibility
options = NO_SSLv2
options = NO_SSLv3
sslVersion = TLSv1
ciphers = HIGH:!aNULL:!MD5

Remember that certificate chain issues often surface only on certain clients because modern browsers often cache intermediate certificates or fetch missing ones automatically.