curl openssl can't verify IIS 7 self-signed cert even when added to curl-ca-bundle.crt curl openssl can't verify IIS 7 self-signed cert even when added to curl-ca-bundle.crt curl curl

curl openssl can't verify IIS 7 self-signed cert even when added to curl-ca-bundle.crt


I also ran into this (and I'm very surprised more people haven't.) when I couldn't get a NodeJS HTTP(s) client to connect to an IIS instance with a self-signed-certificate on it (one created through IIS manager) Just got the dreaded' unable to verify the first certificate error!

It seems that this is because the certificates that IISManager creates for this purpose specify some 'Key Usage' extensions; 'Key Encipherment' and 'Data Encipherment'.

It turns out that when openssl encounters a certificate that specifies 'Key Usage' but fails to specify the 'certSign' usage then the openssl code will discount that certificate as a possible CA certificate even if it has been correctly provided to the openssl code (meaning it is unable to verify the certificate against said absent CA!).

(See the logic here https://github.com/openssl/openssl/blob/6f0ac0e2f27d9240516edb9a23b7863e7ad02898/crypto/x509v3/v3_purp.c#L503 )

The solution is as the one already above, which is to create your own certificates with the correct key usages (or no key usage extensions!)

I also thought I should include an alternative way of creating the Self Signed certificate that openssl clients would be happy with if you're in windows land.

First download the powershell script from here

In a powershell console (Administrative) execute the following commands from within a folder that contains the downloaded scripts

New-SelfsignedCertificateEx -StoreLocation "LocalMachine" -KeyUsage "DigitalSignature,KeyEncipherment,KeyCertSign" -Subject "CN=<HOST_NAME_TO_USE>" -FriendlyName "<HOST_NAME_TO_USE>" -SignatureAlgorithm sha256 -SubjectAlternativeName "<HOST_NAME_TO_USE>","anotherhost.org","someotherdomain.com"

Once you've executed the above command your LocalMachine\Personal Certificates store will contain a self-signed certificate that can be used by IIS for its SSL communications. (Please note you may also need to copy this certificate into one of the Trusted Root stores as well to guarantee that the certificate is trusted on that machine)


I solved this by using openssl to create a self-signed CA cert, then created a server cert request (also in OpenSSL, for some reason openssl does not like to sign requests generated by IIS), signed it with the former CA cert, then exported to PKCS12. Then imported into IIS. Once the CA cert is added to curl-ca-bundle.crt, it will verify the chain correctly:

Generate a CA:

openssl req -new -x509 -days 3650 -extensions v3_ca \-keyout cakey.pem -out cacert.pem -config /etc/ssl/openssl.cnf \-newkey rsa:2048

Generate a server key and signing request:

openssl req -new -nodes -out server-csr.pem -keyout server-key.pem -newkey rsa:2048

Sign the request with the CA:

openssl ca -config /etc/ssl/openssl.cnf -cert cacert.pem -keyfile cakey.pem \-out server-cert.pem -in server-csr.pem

Export the server cert to PKCS#12:

openssl pkcs12 -export -out server-key-cert.pfx \-inkey server-key.pem -in server-cert.pem -certfile cacert.pem

Import server-key-cert.pfx into IIS. (Re)bind the site binding's SSL binding to the cert.

Append cacert.pem to clients' curl-ca-bundle.crt. openssl s_client -showcerts -CAfile curl-ca-bundle.crt -connect server:443 has depth 0 and 1 and will verify return.

Notes: Make sure that keyUsage = nonRepudiation, digitalSignature, keyEncipherment is enabled under section [usr_cert] in openssl.cnf else requests won't contain those keyUsage and IIS will complain on binding.