diff options
author | Kazuki Yamaguchi <k@rhe.jp> | 2017-01-20 23:12:10 +0900 |
---|---|---|
committer | Kazuki Yamaguchi <k@rhe.jp> | 2017-01-24 13:28:48 +0900 |
commit | 654e024beec5a4f6deb05c8c7994544aabd1e825 (patch) | |
tree | dc5986694fa444c8eba205f71e6a798bdabac13d /ext/openssl/ossl_ssl.c | |
parent | 54db4a4abd22ee2ee204f473143c4ad23d894bc4 (diff) | |
download | ruby-openssl-654e024beec5a4f6deb05c8c7994544aabd1e825.tar.gz |
ssl: show reason of 'certificate verify error' in exception messagetopic/ssl-certificate-verify-error-desc
The 'certificate verify error' is one of the most common errors that can
be raised by OpenSSL::SSL::SSLSocket#connect. The certificate
verification may fail due to many different issues such as misconfigured
trusted certificate store or inaccurate system clock.
Unfortunately, since the detail is not put to the queue and is only
accessible through OpenSSL::SSL::SSLSocket#verify_result, it is
sometimes hard to figure out the real reason. Let's include a human
readable reason message in the exception message. Like this:
require "socket"
require "openssl"
ctx = OpenSSL::SSL::SSLContext.new
ctx.set_params(cert_store: OpenSSL::X509::Store.new)
ssl = OpenSSL::SSL::SSLSocket.new(Socket.tcp("www.ruby-lang.org", 443), ctx)
ssl.connect
#=>
-:7:in `connect': SSL_connect returned=1 errno=0 state=error: certificate verify failed (unable to get local issuer certificate) (OpenSSL::SSL::SSLError)
from -:7:in `<main>'
Diffstat (limited to 'ext/openssl/ossl_ssl.c')
-rw-r--r-- | ext/openssl/ossl_ssl.c | 20 |
1 files changed, 20 insertions, 0 deletions
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index eef7dbec..fae4c66a 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -1525,6 +1525,9 @@ ossl_start_ssl(VALUE self, int (*func)(), const char *funcname, VALUE opts) int ret, ret2; VALUE cb_state; int nonblock = opts != Qfalse; +#if defined(SSL_R_CERTIFICATE_VERIFY_FAILED) + unsigned long err; +#endif rb_ivar_set(self, ID_callback_state, Qnil); @@ -1558,6 +1561,23 @@ ossl_start_ssl(VALUE self, int (*func)(), const char *funcname, VALUE opts) case SSL_ERROR_SYSCALL: if (errno) rb_sys_fail(funcname); ossl_raise(eSSLError, "%s SYSCALL returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl)); +#if defined(SSL_R_CERTIFICATE_VERIFY_FAILED) + case SSL_ERROR_SSL: + err = ERR_peek_last_error(); + if (ERR_GET_LIB(err) == ERR_LIB_SSL && + ERR_GET_REASON(err) == SSL_R_CERTIFICATE_VERIFY_FAILED) { + const char *err_msg = ERR_reason_error_string(err), + *verify_msg = X509_verify_cert_error_string(SSL_get_verify_result(ssl)); + if (!err_msg) + err_msg = "(null)"; + if (!verify_msg) + verify_msg = "(null)"; + ossl_clear_error(); /* let ossl_raise() not append message */ + ossl_raise(eSSLError, "%s returned=%d errno=%d state=%s: %s (%s)", + funcname, ret2, errno, SSL_state_string_long(ssl), + err_msg, verify_msg); + } +#endif default: ossl_raise(eSSLError, "%s returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl)); } |