Networking/SSL 29 September 2025 10 min read

Proxy and SSL Certificate Issues — Troubleshooting Guide

A practical troubleshooting guide for SSL certificate errors and proxy configuration issues affecting developer tools, security tools, and applications in enterprise and home environments.

ProxySSLTLSCertificateTroubleshootingMITMEnterprise

Overview

SSL certificate and proxy issues are among the most common problems developers and security professionals face — particularly when moving between home and corporate environments. This guide provides a systematic troubleshooting approach.


Categorising the Error

SSL errors fall into several categories:

1. Certificate Trust Errors

CERTIFICATE_VERIFY_FAILED
unable to get local issuer certificate
self-signed certificate in certificate chain
SSL_ERROR_BAD_CERT_DOMAIN

Cause: The certificate’s issuer (CA) is not trusted by the client.

2. Certificate Validity Errors

certificate has expired or is not yet valid
CERT_NOT_YET_VALID / CERT_DATE_INVALID

Cause: The certificate’s validity period is outside the current date/time.

3. Hostname Mismatch Errors

SSL: CERTIFICATE_VERIFY_FAILED
hostname 'api.example.com' doesn't match certificate's CN 'example.com'

Cause: The hostname doesn’t match the Subject Alternative Names (SANs) in the certificate.

407 Proxy Authentication Required
CONNECT tunnel failed with status 407
Could not resolve proxy hostname

Cause: Proxy configuration missing or proxy requires authentication.


The Diagnostic Flowchart

SSL Error Encountered


Is this a corporate environment?
   │                    │
  YES                   NO
   │                    │
   ▼                    ▼
Check if proxy     Check cert expiry
is intercepting    and hostname match
   │                    │
   ▼                    ▼
openssl s_client   openssl x509 -text
check issuer       check dates and SANs

Step-by-Step Diagnostics

Check 1: Examine the Certificate

# Check what certificate a server presents
echo | openssl s_client -connect hostname:443 2>/dev/null | openssl x509 -noout -text

# Quick summary
echo | openssl s_client -connect hostname:443 2>/dev/null | openssl x509 -noout \
  -subject -issuer -dates -extensions

# Check Subject Alternative Names
echo | openssl s_client -connect hostname:443 2>/dev/null | \
  openssl x509 -noout -text | grep -A1 "Subject Alternative"

Check 2: Verify the Chain

# Verify against system trust store
openssl s_client -connect hostname:443 -verify_return_error 2>&1 | grep -E "verify|Verify"

# Show full chain
openssl s_client -connect hostname:443 -showcerts 2>/dev/null | \
  grep -E "BEGIN CERTIFICATE|subject|issuer"

Check 3: Test from Different Contexts

# Test with curl (uses system CA)
curl -v https://hostname 2>&1 | grep -E "SSL|TLS|error|OK"

# Test with Python requests
python3 -c "import requests; print(requests.get('https://hostname').status_code)"

# Test with Node.js
node -e "const https=require('https'); https.get('https://hostname',r=>console.log(r.statusCode))"

# Test bypassing verification (DIAGNOSTIC ONLY - never in production)
curl -k https://hostname

If curl -k succeeds but curl fails, it’s a trust issue.


Common Fixes

Fix 1: Untrusted CA (Corporate Proxy)

# Find the corporate CA
echo | openssl s_client -connect api.service.com:443 2>/dev/null | \
  openssl x509 -outform PEM > /tmp/proxy-ca.pem

# Verify it's the CA (not the leaf cert)
openssl x509 -in /tmp/proxy-ca.pem -text -noout | grep -E "CA:|Basic Constraints"
# Should show: CA:TRUE

# Trust it system-wide (Ubuntu)
sudo cp /tmp/proxy-ca.pem /usr/local/share/ca-certificates/proxy-ca.crt
sudo update-ca-certificates

# Trust it system-wide (RHEL/CentOS)
sudo cp /tmp/proxy-ca.pem /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust extract

# Trust it for specific tools
export REQUESTS_CA_BUNDLE=/tmp/proxy-ca.pem     # Python requests
export NODE_EXTRA_CA_CERTS=/tmp/proxy-ca.pem    # Node.js
export SSL_CERT_FILE=/tmp/proxy-ca.pem          # curl + OpenSSL
git config --global http.sslCAInfo /tmp/proxy-ca.pem  # git

Fix 2: Expired Certificate

If you control the certificate:

# Check expiry
openssl x509 -in cert.pem -noout -dates

# Renew with Let's Encrypt
certbot renew

# Or use acme.sh
acme.sh --renew -d yourdomain.com

If you don’t control the certificate (external service):

  • Contact the service provider
  • Check for a status page or known incident

Fix 3: Hostname Mismatch

# Check what names the cert covers
echo | openssl s_client -connect hostname:443 2>/dev/null | \
  openssl x509 -noout -text | grep -A3 "Subject Alternative"

# Typical output:
# X509v3 Subject Alternative Names:
#     DNS:example.com, DNS:*.example.com, DNS:www.example.com

If the hostname doesn’t match:

  • Use a hostname that IS in the SANs
  • Request a new certificate with the correct SANs included

Fix 4: Proxy Configuration Issues

# Test proxy connectivity
curl -x http://proxy:port https://httpbin.org/ip

# Test with authentication
curl -x http://user:password@proxy:port https://httpbin.org/ip

# Check if CONNECT method works (required for HTTPS)
curl -v -x http://proxy:port https://example.com 2>&1 | grep -E "CONNECT|Establish"

# NO_PROXY - bypass for internal addresses
export NO_PROXY="localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,.internal.com"

Tool-Specific Proxy and SSL Configuration

Python (requests / pip)

# For pip
pip install package --trusted-host pypi.org --trusted-host files.pythonhosted.org
# Or:
pip install package --proxy http://proxy:port
pip config set global.proxy http://proxy:port

# For requests in code
import requests
session = requests.Session()
session.verify = '/path/to/ca-bundle.pem'
session.proxies = {'https': 'http://proxy:port'}

npm / Node.js

npm config set proxy http://proxy:port
npm config set https-proxy http://proxy:port
npm config set cafile /path/to/ca.pem

# Or per-command
npm install --proxy http://proxy:port

git

git config --global http.proxy http://proxy:port
git config --global http.sslCAInfo /path/to/ca.pem

# Disable SSL verify for a single repo (testing only!)
git config http.sslVerify false

curl (persistent)

# ~/.curlrc
proxy = http://proxy:port
cacert = /path/to/ca.pem

Docker

# Dockerfile
ENV http_proxy=http://proxy:port \
    https_proxy=http://proxy:port

# Or at build time
docker build --build-arg HTTPS_PROXY=http://proxy:port .

When to Escalate

Contact your network/security team when:

  1. Proxy auth keeps expiring — you may need certificate-based auth or an exception
  2. Specific tools or protocols are blocked — modern tools (gRPC, WebSocket, HTTP/3) may need specific proxy support
  3. SSL inspection breaks pinned apps — mobile or enterprise apps with certificate pinning need inspection bypasses
  4. Compliance requirements — some tools must not be inspected; request an exemption with justification

Security Warning

Never disable SSL verification in production code. Common antipatterns:

# DANGEROUS - never in production
requests.get(url, verify=False)
urllib3.disable_warnings()
// DANGEROUS - never in production
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

These completely disable the authentication purpose of TLS — anyone can intercept your connection. The correct fix is always to add the required CA to your trust store.