Corporate Proxy SSL Fix
Corporate networks use SSL inspection (MITM proxies) that break certificate verification in WSL, git, curl, and other tools. This guide covers identification and resolution.
Understanding SSL Inspection
What Happens
-
Your HTTPS request goes to corporate proxy (Cisco Umbrella, Zscaler, etc.)
-
Proxy decrypts your traffic, inspects it, re-encrypts with its own certificate
-
Windows trusts the proxy CA (pushed via GPO)
-
WSL/Linux tools don’t have the proxy CA → SSL verification fails
Identifying SSL Inspection
# From WSL - check who issued the certificate
curl -vI https://github.com 2>&1 | grep -E "(issuer|subject)"
# If you see corporate names instead of real CA, you're being inspected:
# BAD: issuer: O=Cisco; CN=Cisco Umbrella Secondary SubCA
# GOOD: issuer: C=US, O=DigiCert Inc, CN=DigiCert
# From PowerShell - check certificate chain
$url = "https://github.com"
$request = [System.Net.WebRequest]::Create($url)
$request.GetResponse() | Out-Null
$cert = $request.ServicePoint.Certificate
$cert.Issuer
Common Corporate Proxies
| Vendor | Subject Pattern | Notes |
|---|---|---|
Cisco Umbrella |
|
Cloud-based DNS/proxy |
Zscaler |
|
Cloud security gateway |
Palo Alto |
|
NGFW SSL decryption |
Fortinet/FortiGate |
|
UTM SSL inspection |
Blue Coat / Symantec |
|
Legacy proxy appliances |
McAfee Web Gateway |
|
Web gateway proxy |
Fix: Export and Import CA
Step 1: Find the Proxy CA in Windows
# Search for common proxy CA patterns
$proxyPatterns = "Umbrella|Zscaler|Palo Alto|Fortinet|BlueCoat|McAfee|Corporate|Proxy"
Get-ChildItem Cert:\LocalMachine\Root | Where-Object \{
$_.Subject -match $proxyPatterns -or $_.Issuer -match $proxyPatterns
} | Format-Table Subject, Issuer, NotAfter
# If nothing found, list all and look manually
Get-ChildItem Cert:\LocalMachine\Root | Sort-Object Subject | Format-Table Subject
Step 2: Export to PEM
# Replace "Umbrella" with your proxy CA name
$caName = "Umbrella"
$outputPath = "C:\temp\corporate-ca.crt"
$cert = Get-ChildItem Cert:\LocalMachine\Root | Where-Object \{ $_.Subject -match $caName }
if ($cert) \{
$pem = "-----BEGIN CERTIFICATE-----`n" +
[Convert]::ToBase64String($cert.RawData, 'InsertLineBreaks') +
"`n-----END CERTIFICATE-----"
[System.IO.File]::WriteAllText($outputPath, $pem)
Write-Host "Exported to $outputPath"
Get-Content $outputPath | Select-Object -First 3
} else \{
Write-Host "Certificate not found for pattern: $caName" -ForegroundColor Red
}
One-Liner Scripts
PowerShell: Export Cisco Umbrella CA
$cert = Get-ChildItem Cert:\LocalMachine\Root | Where-Object \{ $_.Subject -match "Umbrella" }; [System.IO.File]::WriteAllText("C:\temp\corp-ca.crt", "-----BEGIN CERTIFICATE-----`n" + [Convert]::ToBase64String($cert.RawData, 'InsertLineBreaks') + "`n-----END CERTIFICATE-----")
Bash (Arch): Import and Update
sudo cp /mnt/c/temp/corp-ca.crt /etc/ca-certificates/trust-source/anchors/ && sudo update-ca-trust
Combined (Copy-Paste Ready)
Run in PowerShell first:
$cert = Get-ChildItem Cert:\LocalMachine\Root | ? \{ $_.Subject -match "Umbrella" }
[IO.File]::WriteAllText("C:\temp\corp-ca.crt", "-----BEGIN CERTIFICATE-----`n$([Convert]::ToBase64String($cert.RawData, 'InsertLineBreaks'))`n-----END CERTIFICATE-----")
Then in WSL (Arch):
sudo cp /mnt/c/temp/corp-ca.crt /etc/ca-certificates/trust-source/anchors/ && sudo update-ca-trust && curl -sI https://github.com | head -1
Application-Specific Fixes
Git
# Check if git uses custom CA bundle
git config --global --get http.sslCAInfo
# Option 1: Unset to use system trust store
git config --global --unset http.sslCAInfo
# Option 2: Append corporate CA to git's bundle
cat /mnt/c/temp/corp-ca.crt >> $(git config --global --get http.sslCAInfo)
# Option 3: Point git to system bundle
git config --global http.sslCAInfo /etc/ssl/certs/ca-certificates.crt
Node.js / npm
# Set system CA bundle
export NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt
# Or add to .bashrc/.zshrc
echo 'export NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt' >> ~/.zshrc
Troubleshooting
Certificate Not Found in Windows Store
# Check intermediate CA store too
Get-ChildItem Cert:\LocalMachine\CA | Where-Object \{ $_.Subject -match "Umbrella|Zscaler|Proxy" }
# Check user store
Get-ChildItem Cert:\CurrentUser\Root | Where-Object \{ $_.Subject -match "Umbrella|Zscaler|Proxy" }
# List ALL certificates to find it
Get-ChildItem Cert:\LocalMachine\Root | Select-Object Subject | Sort-Object Subject | Out-GridView
Still Failing After Import
# Verify certificate was added
ls -la /etc/ca-certificates/trust-source/anchors/
# Check if trust store was updated
trust list | grep -i umbrella
# Force rebuild of CA bundle
sudo update-ca-trust force-enable
sudo update-ca-trust extract
Multiple Proxy CAs
Some environments have multiple proxy CAs (root + intermediate). Export all of them:
# Find all related certs
$certs = Get-ChildItem Cert:\LocalMachine\Root, Cert:\LocalMachine\CA |
Where-Object \{ $_.Subject -match "Umbrella" -or $_.Issuer -match "Umbrella" }
# Export all to single bundle
$bundle = ""
foreach ($cert in $certs) \{
$bundle += "-----BEGIN CERTIFICATE-----`n"
$bundle += [Convert]::ToBase64String($cert.RawData, 'InsertLineBreaks')
$bundle += "`n-----END CERTIFICATE-----`n`n"
}
[System.IO.File]::WriteAllText("C:\temp\corp-ca-bundle.crt", $bundle)
Write-Host "Exported $($certs.Count) certificates"
Emergency Workaround
| Only use as temporary measure while proper fix is implemented. |
# Disable SSL verification for specific host (INSECURE)
git config --global http.https://git.sr.ht.sslVerify false
# Disable for all (VERY INSECURE - DO NOT USE IN PRODUCTION)
# git config --global http.sslVerify false # DON'T DO THIS
Automation Script
Save this as fix-corporate-ssl.ps1:
#Requires -RunAsAdministrator
param(
[string]$CAPattern = "Umbrella|Zscaler",
[string]$OutputPath = "C:\temp\corporate-ca.crt"
)
$cert = Get-ChildItem Cert:\LocalMachine\Root | Where-Object \{ $_.Subject -match $CAPattern } | Select-Object -First 1
if (-not $cert) \{
Write-Error "No certificate found matching: $CAPattern"
Write-Host "Available certificates:"
Get-ChildItem Cert:\LocalMachine\Root | Select-Object Subject | Sort-Object Subject
exit 1
}
$pem = "-----BEGIN CERTIFICATE-----`n" +
[Convert]::ToBase64String($cert.RawData, 'InsertLineBreaks') +
"`n-----END CERTIFICATE-----"
New-Item -ItemType Directory -Path (Split-Path $OutputPath) -Force | Out-Null
[System.IO.File]::WriteAllText($OutputPath, $pem)
Write-Host "SUCCESS: Exported '$($cert.Subject)' to $OutputPath" -ForegroundColor Green
Write-Host ""
Write-Host "Next steps (run in WSL):" -ForegroundColor Yellow
Write-Host " sudo cp /mnt/c/temp/corporate-ca.crt /etc/ca-certificates/trust-source/anchors/"
Write-Host " sudo update-ca-trust"
Related
-
WSL Trust Store Integration - Full WSL integration guide
-
Certificate Management - PowerShell certificate operations