6

I'm new to using OpenSSL and currently using it in Windows trying to troubleshoot for the party connecting to our server.

openssl s_client -connect servername:443

CONNECTED(00000134)
depth=0 CN = servername
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = servername
verify error:num=21:unable to verify the first certificate
verify return:1
[other details follow...]

After a few search I realize that I need to specify the path for the trusted root ca.

-CApath directory The directory to use for server certificate verification. This directory must be in "hash format", see verify for more information. These are also used when building the client certificate chain.

-CApath /etc/ssl/certs/

The only problem I have is that most online example are using unix based systems so the examples are usually like the one just above. I'm not too familiar with unix so I assume if my CA are in

C:\OpenSSL-Win64\bin\cas

then the ca path parameter goes like this one below. The CA are in .cer / .crt format.

-CApath /c/OpenSSL-Win64/bin/cas

However, I still get the same result so I'm not so sure if I understand this correctly.

MichaelChan
  • 225
  • 1
  • 3
  • 8
  • When on Windows I use [Cygwin](http://cygwin.com) to get a Unix-like environment. It's quick to install and doesn't need admin (I think). (And preferably then I also use [testssl.sh](http://testssl.sh) instead of bare openssl s_client.) Is that an option for you? – StackzOfZtuff May 13 '16 at 04:39
  • I'll try that out. I'm trying to emulate the client as closely but can try out couple of things – MichaelChan May 13 '16 at 06:02
  • I got this sorted. Turns out the errors above are more like warning and the reason I was getting an error was application related. But it would still be good to know how to specify the CA using just openssl so I'll just leave this open. – MichaelChan May 18 '16 at 02:15
  • To simulate TLS client for troubleshooting, note that in the 21st century increasingly many TLS servers use Server Name Inidication (SNI) to control which cert to use (and sometimes whether to succeed at all), and OpenSSL `s_client` **through release 1.1.0** doesn't send SNI by default, whereas nearly all real, non-ancient clients do; you need to **specify `-servername $name`** where $name normally is the same as the $host you connect to. OpenSSL 1.1.1 (released 2 years after this Q) does default SNI to the `-connect` (or `-host`) value. – dave_thompson_085 Jul 23 '19 at 01:32

3 Answers3

8

#Use someone else's PEM bundle.

You can not use the Windows certificate store directly with OpenSSL. Instead OpenSSL expects its CAs in one of two ways:

  1. Many files: In a special folder structure. One file per certificate with regular names like Verisign-CA.pem. (This is so that humans can understand the cert store.) And then a symlink to each such file. And the symlinks have weird names like 01c34cfa... and so on. They are named for a hash value of the certificate file. (This is so that OpenSSL can understand the cert store. More info: man page for openssl verify.) If you want to add a cert, you just drop the file in the directory and run a script that creates the symlink for you.

You can specify the path to that folder with the CApath command line argument (Case sensitive: Large CA, small path.):

    -CApath arg   - PEM format directory of CA's
  1. Single file: All CA certificates lumped together in a PEM bundle.

You can specify the path to that file with the CAfile command line argument (Case sensitive: Large CA, small file.):

    -CAfile arg   - PEM format file of CA's

And one easy way to get such a PEM bundle is to download it from the testssl.sh site: https://github.com/drwetter/testssl.sh/blob/3.1dev/etc/Microsoft.pem

And this will then work with a Windows installation of OpenSSL:

    c:\> openssl s_client -connect google.com:443 -CAfile "c:\Microsoft.pem"  

...

    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
    ---
DylanSp
  • 134
  • 7
StackzOfZtuff
  • 17,783
  • 1
  • 50
  • 86
  • I didn't accept this answer before because I myself didn't understand it yet. From what I understand now is as long as you can convert the existing crt / pfx files into openSSL format PEM then it will work. – MichaelChan Mar 27 '17 at 01:48
  • 2
    that Microsoft.pem link is dead – bigbadmouse Oct 29 '19 at 12:26
2

This site has a list of various sites that provide PEM bundles, and refers to this git hub project, which provides copies of all the main OS PEM bundles in single file format which can be used by OpenSSL on windows.

One can extract the microsoft_windows.pem from provided tar file and use it like so

echo | openssl.exe s_client -CAfile microsoft_windows.pem -servername URL -connect HOST:PORT 2>nul
peterh
  • 2,938
  • 6
  • 25
  • 31
simo
  • 21
  • 1
1

That error is because openssl.exe wants you to tell it where to get root CA certs. In *nix it's easy since those are files, but in Windows those are stored as registry entries.

You can download them from the internet, or if you run Certificate Manager you can grab them from your own computer. Win+R > certmgr opens the program, and then Certificates - Local Computer > Trusted Root Certification Authorities > Certificates opens the list. From there select the appropriate Certificate Authority (as an example, if you're authenticating against LetsEncrypt / Certbot, the CA in 2021 is "ISRG Root X1"). Right Click > All Tasks > Export brings up the Export Wizard, and "Base-64 encoded X.509" will get you a pem file you can save out.

If you only need to check against a single CA, you're now basically done. Run openssl.exe with the option -CAfile x:/path/to/your/new/file.cer and you as long as your file is the correct Root CA you shouldn't get that error.

But what you asked about was -CApath which allows you to have multiple CA files and it will check against whichever is appropriate. Using this method on Windows has one extra step. The documentation for s_client says the directory you point to must be in "hash format" and to check the documentation for verify which says files must be named in the format "hash.0" as described in the documentation for x509 which gives us our answer: the directory pointed to by -CApath can't just have files with any old names, they must be named based on their encrypted "Certificate Subject Names" which you can get from openssl.exe x509

As an example, if you'd exported a .cer file of the ISRG Root X1 cert to C:\certs\lets.cer, you could either run the command

openssl.exe s_client -CAfile C:\certs\lets.cer -connect servername:443

Or if you wanted to create a directory of certificates, you'd first run

openssl.exe x509 -subject_hash -in C:\certs\lets.cer

Which gives you the hash 4042bcee (and a printout of the certificate)

So you'd rename the .cer file to C:\certs\4042bcee.0 (or make a copy, or a symlink etc)

And then you can run openssl.exe s_client -connect servername:443 -CApath C:\certs\

Also, if you don't want to specify the -CApath every time, you can check the default path with openssl.exe version -a which on my Win10 system is

OPENSSLDIR: "C:\Program Files\Common Files\SSL"

and put the specially-named files into a subfolder \certs of that, so in my case on Win10 C:\Program Files\Common Files\SSL\certs