Rails 3 Install Error: "Invalid Value for @Cert_Chain"

Rails 3 install error: invalid value for @cert_chain

This is an issue with Rubygems version 1.7.1. Upgrading to 1.7.2 or above, or downgrading to 1.6.2, fixes this.

To upgrade (preferred):

gem update --system

To downgrade:

gem update --system 1.6.2

WARNING: builder-2.1.2 has an invalid nil value for @cert_chain

You cannot fix or get rid of this warning without submitting a patch to the gem that would fix it. I do not know what is causing it, so I cannot advise on that part.

Get certificate information after connection error

TLDR: use the callback.

All session parameters including the cert chain are available only if the connection (handshake) succeeded; this is because if the handshake did not succeed there is no way to have confidence any of the results are valid. In theory the received certs could be a special case, but a special case would be more complicated and as you may have noticed the OpenSSL API is already complicated enough people routinely screw up using it.

As you saw s_client sets a verify callback that forces acceptance of any cert chain, even an invalid one; this causes the handshake to succeed and parameters including the cert chain to be available. s_client is intended as a test tool where it doesn't matter if the data is really secure or not.

If you want to connect only to verified servers, use the default verify logic. If you want to connect to unverified servers and handle risk (possibly minimal in your case) of data being intercepted and/or tampered, use the callback. The reason it is a callback is to allow applications control.

The fact s_client uses SSL_set_connect_state to cause handshake before the first data transfer, rather than explicitly calling SSL_connect, is irrelevant and makes no difference.

ADDED: you can detect an error after using the callback -- or even without!

First to be clear, the callback we are talking about here (the 'verify' callback) is used in addition to the builtin chain verification logic. There is a different callback, with a very similar name, the 'cert verify' callback, which you do NOT want. Quoting the man page

The actual verification procedure is performed either using the built-in verification procedure or using another application provided verification function set with SSL_CTX_set_cert_verify_callback. The following descriptions apply in the case of the built-in procedure. An application provided procedure also has access to the verify depth information and the verify_callback() function, but the way this information is used may be different.

As the (conveniently hyperlinked) SSL_[CTX_]set_cert_verify_callback man page says

[by default] the built-in verification function is used. If a verification callback callback [that's clearly a typo] is specified via SSL_CTX_set_cert_verify_callback(), the supplied callback function is called instead. [...]

Providing a complete verification procedure including certificate purpose settings etc is a complex task. The built-in procedure is quite powerful and in most cases it should be sufficient to modify its behaviour using the verify_callback function.

Where 'the verify_callback function' means the set_verify one not the set_verify_callback one. Actually this is not exact; part of the builtin logic is always used and only part of it is replaced by the cert verify callback. But you still don't want to do that, only the verify callback.

The SSL_[CTX_]set_verify[_depth] page continues to describe the builtin logic:

SSL_CTX_set_verify_depth() and SSL_set_verify_depth() set the limit up to which depth certificates in a chain are used during the verification procedure. [...]

The certificate chain is checked starting with the deepest nesting level (the root CA certificate) and worked upward to the peer's certificate. At each level signatures and issuer attributes are checked. Whenever a verification error is found, the error number is stored in x509_ctx and verify_callback is called with preverify_ok=0. [...] If no error is found for a certificate, verify_callback is called with preverify_ok=1 before advancing to the next level.

The return value of verify_callback controls the strategy of the further verification process. If verify_callback returns 0, the verification process is immediately stopped with "verification failed" state. [,,,] If verify_callback returns 1, the verification process is continued. If verify_callback always returns 1, the TLS/SSL handshake will not be terminated with respect to verification failures and the connection will be established. The calling process can however retrieve the error code of the last verification error using SSL_get_verify_result or by maintaining its own error storage managed by verify_callback.

If no verify_callback is specified, the default callback will be used. Its return value is identical to preverify_ok, so that any verification failure will lead to a termination of the TLS/SSL handshake with an alert message, if SSL_VERIFY_PEER is set.

So a callback has the option to force acceptance after the builtin logic has found an error (call with 0, return 1) or force failure even if the builtin logic considers the cert chain okay (call with 1, return 0) but if it doesn't the builtin logic controls.
The special callback used by s_client (and by s_server when client authentication is used, but that is relatively rare) prints the subject name of each cert with the status (labelled 'verify return') from the builtin logic, but always returns 1 thereby forcing the (rest of the verification and) connection to continue regardless of any error found.

Notice in the second paragraph "Whenever a verification error is found, the error number is stored in x509_ctx and [then] verify_callback is called with preverify_ok=0" and in the third paragraph "The calling process can however retrieve the error code of the last verification error using SSL_get_verify_result" -- this is true even if the callback forced ok=1.

But in checking the references for this I found an even better solution I had missed right on that page: if you just default (or set) mode SSL_VERIFY_NONE (emphasis and clarifications added):

Client mode: if not using an anonymous cipher (by default disabled), the server will send a certificate which will be checked [by the builtin logic, even though NONE would make you think it isn't checked]. The result of the certificate verification process can be checked after the TLS/SSL handshake [is completed] using the SSL_get_verify_result function. The handshake will be continued regardless of the verification result.

This is effectively the same as a callback that forces ok=1 and does what you want.

How to solve certificate verify failed on Windows?

Actually the best way I found to solve this in windows for Ruby itself, not just one gem, is to do the following:

  1. Download https://curl.haxx.se/ca/cacert.pem into c:\railsinstaller\cacert.pem. Make sure you save it as a .pem file, rather than a text file.
  2. Go to your Computer -> Advanced Settings -> Environment Variables
  3. Create a new System Variable:

    Variable: SSL_CERT_FILE
    Value: C:\RailsInstaller\cacert.pem

  4. Close all your command prompts, including your Rails server command prompt, etc.

  5. Start a new ruby irb prompt, and try the following:

    $irb>require 'open-uri'
    $irb>open('https://www.gmail.com')

It should all work now just fine.

Openssl error 20 at 0 depth lookup:unable to get local issuer certificate

From the Openssl documentation:
https://www.openssl.org/docs/manmaster/man1/verify.html

-CApath directory

A directory of trusted certificates. The certificates should have
names of the form: hash.0 or have symbolic links to them of this form
("hash" is the hashed certificate subject name: see the -hash option
of the x509 utility). Under Unix the c_rehash script will
automatically create symbolic links to a directory of certificates.

So if I'm right, then the -CApath option should point a directory with the hashed list of certificates or have a symbolic link to them.
You could get some kind of list via e.g. with the use of -hash option of the openssl x509 command.

I hope, it helps.



Related Topics



Leave a reply



Submit