Why can't cURL properly verify a certificate on Windows?
When I try to use Curl on windows, to retrieve an https
url, I get the dreaded "connection error (60)."
The exact error message is:
curl: (60) SSL certificate problem, verify that the CA cert is OK. Details:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
More details here: http://curl.haxx.se/docs/sslcerts.html
How to resolve this?
Solution 1:
I don't know why but I did not find this information all in one place.
Download the SSL-aware version of Curl, or build the SSL-aware version yourself.
From http://curl.haxx.se/docs/caextract.html , Download the cacert.pem file.
Place the curl.exe and the .pem file in the same directory.
Rename the
cacert.pem
file tocurl-ca-bundle.crt
Re-run curl.exe !
EDIT:
There are other ways to solve the problem. this particular way relies on a cacert produced by the maker of Curl. That may not be what you want, and in particular, it may not work for cases where you have a less-than-well-known certifying authority (such as an authority known only to your corporation) for the certificate used by the SSL site. In that case, you will want to generate your own curl-ca-bundle.crt
file. You can use certreq.exe and openssl.exe to export such a cert from the IE/Windows store, and then convert-to-pem-format, respectively.
Solution 2:
I have created a PowerShell script that is capable of writing the ca-cert.crt
file based on the CA certificates that are installed in your Windows certification store (CurrentUser or LocalMachine). Run the script like this:
CreateCaCert.ps1 -StoreLocation CurrentUser | Out-File -Encoding utf8 curl-ca-cert.crt
This will create the curl-ca-cert.crt
file that should be stored in the same directory as curl.exe
and you should be able to validate the same sites as you can in your Windows applications (note that this file can also be consumed by git
).
The "official" script can be found on GitHub, but the initial version is listed here for reference:
[CmdletBinding()]
Param(
[ValidateSet(
[System.Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser,
[System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine)]
[string]
$StoreLocation = [System.Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser
)
$maxLineLength = 77
# Open the store
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store ([System.Security.Cryptography.X509Certificates.StoreName]::Root, $StoreLocation)
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadOnly);
# Write header
Write-Output "# Root certificates ($StoreLocation) generated at $(Get-Date)"
# Write all certificates
Foreach ($certificate in $store.Certificates)
{
# Start with an empty line
Write-Output ""
# Convert the certificate to a BASE64 encoded string
$certString = [Convert]::ToBase64String($certificate.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert));
# Write the actual certificate
Write-Output "# Friendly name: $($certificate.FriendlyName)"
Write-Output "# Issuer: $($certificate.Issuer)"
Write-Output "# Expiration: $($certificate.GetExpirationDateString())"
Write-Output "# Serial: $($certificate.SerialNumber)"
Write-Output "# Thumbprint: $($certificate.Thumbprint)"
Write-Output "-----BEGIN CERTIFICATE-----"
For ($i = 0; $i -lt $certString.Length; $i += $maxLineLength)
{
Write-Output $certString.Substring($i, [Math]::Min($maxLineLength, $certString.Length - $i))
}
Write-Output "-----END CERTIFICATE-----"
}
Solution 3:
Actually we had the same problem with Typheous/Ruby. The Solution was downloading the cacert.pem and save it to C:\Windows\System32 (or whereever your Windows is). After that we set a global environment variable like discribed here where the "Variable Name" must be CURL_CA_BUNDLE
and the "Variable Value" the path to the file %SystemRoot%\System32\cacert.pem
.
When starting a new CMD Session you can now just use Typheous/Libcurl thing to authenticate SSL Connections. I've successfully tried this with Windows 8.1.