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.