Why can't Ruby verify SSL certificate?

This is my first time trying to use the XMLRPC :: Client library to interact with the remote API, and I keep getting this error:

warning: peer certificate won't be verified in this SSL session 

Searching around I found a lot of people who got this error. Usually this is with self-signed certificates, and they just want him to leave, so they do something dirty, like a monkey, like XMLRPC :: Client opens his http session.

At first, I assumed that it was just a client, not worrying about whether the certificate was valid or not, so I continued searching and came across this stone.It simply forces me to check all SSL certificates and gives a hard error if it doesn’t work either. That was exactly what I wanted. I turned it on, ran the code again, and now I get the following:

 OpenSSL:SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed 

Sure! The certificate is bad! But I double check to make sure openssl is embedded in s_client like this:

 openssl s_client -connect sub.example.com:443 

and what will I get:

 CONNECTED(00000003) --- Certificate chain <snip> Verify return code: 0 (ok) 

So now we come to my question. OpenSSL (command line version) says the certificate is good. OpenSSL (Ruby library) disagrees. All of my web browsers say the certificate is good.

A few additional details that may be helpful. The certificate is a wildcard, but valid for the domain. The openssl s_client parameter was executed on the same machine seconds as the Ruby code. This is Ruby 1.8.7 p357, which is installed with RVM.

Does Ruby use anything other than the CA package provided by the host operating system? Is there any way to tell Ruby to use a specific CA kit or system kit?

+49
ruby api certificate openssl
Feb 08 '12 at 18:56
source share
2 answers

If you are only interested in how to make Ruby behave just like OpenSSL s_client or your browser, you can skip to the very last section, I will talk about small print in the next.

By default, OpenSSL::X509::Store , used to connect, does not use trusted certificates at all. Based on your knowledge of the application domain, you usually write an instance of X509::Store with a trusted certificate (s) that are relevant to your application. There are several options for this:

  • Store # add_file accepts PEM / DER encoded certificate path
  • Store # add_cert accepts an X509 :: Certificate
  • Store # add_path accepts a directory path where trusted certificates can be found

Browser Approach

This is different from approach browsers, Java (cacerts), or Windows with their own internal trust store. There, the software is pre-equipped with a set of trusted certificates, which is considered "good", according to the software vendor. This is usually a good idea, but if you really look into these sets, you will soon notice that there are too many certificates. A person cannot really say whether to trust all these certificates blindly or not.

Ruby Approach

The requirements of your typical Ruby application, on the other hand, are very different from the requirements of your browser. The browser should be able to allow you to go to any “legitimate” website that comes with a TLS certificate and is served via https. But in a typical Ruby application, you only have to deal with a few services using TLS, or otherwise require certificate verification.

And there is the advantage of the Ruby approach - although it requires more manual work, you will end up with a manual solution that accurately trusts the certificates it should trust in your specific application context. This is tiring, but the security is much higher because you expose much less to the attack surface. Take the latest developments: if you have never had to include DigiNotar or any other compromised root in your trust set, then there are no violations that could affect you.

However, as you already noticed, the disadvantage of this is that by default, if you do not actively add trusted certificates, the OpenSSL extension will not be able to verify any peer certificate at all. For everything to be in order, you need to configure the configuration manually.

This inconvenience has led to many dubious measures to get around it, and the worst thing is to globally set OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE . Please, do not do that. We even joked about adding code that allows your application to crash randomly if we encounter this hack :)

If manually configuring trust seems too complicated, I now propose a lightweight alternative that makes the OpenSSL extension behave just like OpenSSL CLI commands like s_client .

Why s_client can verify the certificate

OpenSSL takes a similar approach for browsers and Windows. A typical installation will place a set of trusted certificates on your hard drive (something like /etc/ssl/certs/ca-bundle.crt ), and this will serve as a standard set of trusted certificates. What is where s_client looks like, when you need to verify peer certificates and why your experiment succeeded.

Casting Ruby as s_client

If you still want the same comfort when checking certificates with Ruby, you can say that it uses the OpenSSL trusted certificate package if it is available on your system by calling OpenSSL::X509::Store#set_default_paths . Further information can be found here . To use this with XMLRPC::Client , just make sure set_default_paths is called in the X509::Store that it uses.

+100
Feb 11 '12 at 6:00
source share

If you have a ca-certificate file, just do the following:

 http.ca_file = <YOUR CA-CERT FILE PATH> http.verify_mode = OpenSSL::SSL::VERIFY_PEER http.verify_depth = 5 
0
Jan 07 '15 at 11:43 on
source share



All Articles