Troubleshooting SSL Handshake Failures: Why cURL Works But wget/PHP file() Fails on HTTPS Requests


2 views

Recently encountered a puzzling scenario where HTTPS requests behave differently across tools:

# Success case
curl "https://example.com"

# Failure case
wget https://example.com
# Returns: "Unable to establish SSL connection"

The same issue manifests in PHP's file() function when accessing HTTPS URLs. This behavior suddenly appeared over a weekend on a RHEL 6.4 system that previously worked fine.

Several technical factors could explain why cURL succeeds where wget fails:

  • Default SSL/TLS versions differ between implementations
  • Certificate verification handling varies
  • Underlying SSL library differences (OpenSSL vs GnuTLS)
  • Different default cipher suites

First, let's verify SSL/TLS capabilities with openssl:

openssl s_client -connect example.com:443 -showcerts

For wget, we can increase verbosity:

wget --debug https://example.com

Compare with cURL's verbose output:

curl -v https://example.com

Based on similar cases I've encountered, these are the most likely culprits:

  • SSL Protocol Version Mismatch: Older wget versions may default to SSLv3 while servers require TLS 1.2+
  • Certificate Chain Issues: Intermediate certificates might not be properly installed
  • Cipher Suite Incompatibility: Server may reject wget's default cipher suite
  • System Time Drift: Certificate validation fails if system clock is incorrect

For wget:

# Force TLS 1.2
wget --secure-protocol=TLSv1_2 https://example.com

# Or try different SSL implementations
wget --no-check-certificate --https-only --secure-protocol=auto https://example.com

For PHP file():

// Context options for SSL
$context = stream_context_create([
    'ssl' => [
        'verify_peer' => false,
        'verify_peer_name' => false,
        'allow_self_signed' => true
    ]
]);

$content = file('https://example.com', FILE_USE_INCLUDE_PATH, $context);

For system-wide resolution on RHEL 6.4:

  1. Update wget and OpenSSL packages:
  2. yum update wget openssl
  3. Adjust system-wide crypto policies:
  4. update-crypto-policies --set LEGACY
  5. Add CA certificates to the trusted store:
  6. yum install ca-certificates
    update-ca-trust force-enable
    update-ca-trust extract

If the issue persists, try compiling wget with different SSL backends:

# Recompile with OpenSSL
./configure --with-ssl=openssl
make && make install

# Or with GnuTLS
./configure --with-ssl=gnutls
make && make install

Sometimes the issue stems from network configuration:

  • Check for SSL inspection devices (firewalls, proxies)
  • Verify MTU settings aren't causing packet fragmentation
  • Test with different DNS resolvers
  • Inspect TCP connections with tcpdump
tcpdump -nn -i eth0 'port 443 and host example.com'

When executing HTTPS requests on RHEL 6.4, we're seeing inconsistent behavior between different tools:

# Success case
curl "https://example.com"

# Failure case (times out during SSL handshake)
wget https://example.com
# Output: Unable to establish SSL connection

# HTTP works fine
wget http://example.com
  • OS: Red Hat Enterprise Linux 6.4
  • Affected tools: wget, PHP's file() function
  • Working tool: cURL
  • Protocol difference: HTTPS fails, HTTP succeeds

The root cause typically relates to SSL/TLS protocol version mismatches or cipher suite differences between client and server. Here's how to investigate:

# Check cURL's SSL details
curl -v https://example.com 2>&1 | grep -i "SSL"

# Check wget's SSL handshake attempt
wget --debug https://example.com 2>&1 | grep -i "SSL"

# Alternative using openssl client
openssl s_client -connect example.com:443 -showcerts

1. Outdated SSL/TLS Protocols

RHEL 6.4 ships with older SSL libraries by default. Try forcing modern protocols:

# For wget
wget --secure-protocol=TLSv1_2 https://example.com

# For curl comparison
curl --tlsv1.2 https://example.com

2. Certificate Verification Issues

While --no-check-certificate didn't help, try specifying CA bundles:

wget --ca-certificate=/etc/pki/tls/certs/ca-bundle.crt https://example.com

3. Cipher Suite Mismatches

Some servers reject connections with weak ciphers:

# For wget (requires newer versions)
wget --ciphers="HIGH:!aNULL:!MD5" https://example.com

The PHP issue stems from the same SSL configuration. Here are options:

// Option 1: Use curl instead
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://example.com");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);

// Option 2: Update PHP stream context
$context = stream_context_create([
    'ssl' => [
        'verify_peer' => false,
        'verify_peer_name' => false,
        'ciphers' => 'HIGH:!SSLv2:!SSLv3:!TLSv1:!TLSv1.1'
    ]
]);
file('https://example.com', false, $context);
  • Update system CA certificates: yum update ca-certificates
  • Upgrade wget to a newer version that supports modern TLS
  • Consider upgrading OpenSSL libraries if possible
  • For PHP, update to a newer version with better SSL support

For deeper investigation, these commands help:

# Check installed SSL/TLS versions
openssl version

# Verify what protocols a server supports
nmap --script ssl-enum-ciphers -p 443 example.com

# Check current SSL configuration in PHP
php -i | grep -i ssl