From 54db4a4abd22ee2ee204f473143c4ad23d894bc4 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Fri, 20 Jan 2017 21:23:46 +0900 Subject: Make exceptions with the same format regardless of OpenSSL.debug As the current behavior is useless. If OpenSSL.debug is set to true, errors put to the error queue will be printed to stderr anyway. --- ext/openssl/ossl.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'ext/openssl') diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c index eb71b643..e4725f09 100644 --- a/ext/openssl/ossl.c +++ b/ext/openssl/ossl.c @@ -260,18 +260,15 @@ static VALUE ossl_make_error(VALUE exc, const char *fmt, va_list args) { VALUE str = Qnil; - const char *msg; - long e; + unsigned long e; - e = ERR_peek_last_error(); if (fmt) { str = rb_vsprintf(fmt, args); } + e = ERR_peek_last_error(); if (e) { - if (dOSSL == Qtrue) /* FULL INFO */ - msg = ERR_error_string(e, NULL); - else - msg = ERR_reason_error_string(e); + const char *msg = ERR_reason_error_string(e); + if (NIL_P(str)) { if (msg) str = rb_str_new_cstr(msg); } @@ -279,8 +276,8 @@ ossl_make_error(VALUE exc, const char *fmt, va_list args) if (RSTRING_LEN(str)) rb_str_cat2(str, ": "); rb_str_cat2(str, msg ? msg : "(null)"); } + ossl_clear_error(); } - ossl_clear_error(); if (NIL_P(str)) str = rb_str_new(0, 0); return rb_exc_new3(exc, str); -- cgit v1.2.3 From 654e024beec5a4f6deb05c8c7994544aabd1e825 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Fri, 20 Jan 2017 23:12:10 +0900 Subject: ssl: show reason of 'certificate verify error' in exception message 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 `
' --- ext/openssl/ossl_ssl.c | 20 ++++++++++++++++++++ test/test_ssl.rb | 24 ++++++++++++++++++++++++ 2 files changed, 44 insertions(+) (limited to 'ext/openssl') 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)); } diff --git a/test/test_ssl.rb b/test/test_ssl.rb index 8d74f25f..2b6d9291 100644 --- a/test/test_ssl.rb +++ b/test/test_ssl.rb @@ -749,6 +749,30 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end end + def test_connect_certificate_verify_failed_exception_message + start_server(ignore_listener_error: true) { |server, port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.set_params + assert_raise_with_message(OpenSSL::SSL::SSLError, /self signed/) { + server_connect(port, ctx) + } + } + + ctx_proc = proc { |ctx| + ctx.cert = issue_cert(@svr, @svr_key, 30, [], @ca_cert, @ca_key, + not_before: Time.now-100, not_after: Time.now-10) + } + start_server(ignore_listener_error: true, ctx_proc: ctx_proc) { |server, port| + store = OpenSSL::X509::Store.new + store.add_cert(@ca_cert) + ctx = OpenSSL::SSL::SSLContext.new + ctx.set_params(cert_store: store) + assert_raise_with_message(OpenSSL::SSL::SSLError, /expired/) { + server_connect(port, ctx) + } + } + end + def test_multibyte_read_write #German a umlaut auml = [%w{ C3 A4 }.join('')].pack('H*') -- cgit v1.2.3