From 12bdacdca5d19988f3ffe60714f518ec7324b35a Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Sat, 1 Jul 2023 21:53:38 +0900 Subject: [PATCH] [ruby/openssl] Include "additional data" message in OpenSSL errors Error entries in the OpenSSL error queue may contain additional contextual information associated with the error, which can be helpful when debugging. This "additional data" is currently only printed to stderr when OpenSSL.debug is enabled. Let's include this in the exception messages raised with ossl_raise(), too. $ ruby -Ilib -ropenssl -e'OpenSSL.debug=true; OpenSSL::SSL::SSLContext.new.ecdh_curves="P-256:not-a-curve"' -e:1: warning: error on stack: error:0A080106:SSL routines:gid_cb:passed invalid argument (group 'not-a-curve' cannot be set) -e:1:in `ecdh_curves=': passed invalid argument (group 'not-a-curve' cannot be set) (OpenSSL::SSL::SSLError) from -e:1:in `
' https://github.com/ruby/openssl/commit/1c5bbdd68e --- ext/openssl/ossl.c | 29 +++++++++++++++++------------ test/openssl/test_ossl.rb | 12 ++++++++++++ 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c index b1ba48c869..0bd2fa497e 100644 --- a/ext/openssl/ossl.c +++ b/ext/openssl/ossl.c @@ -272,23 +272,28 @@ VALUE ossl_make_error(VALUE exc, VALUE str) { unsigned long e; + const char *data; + int flags; - e = ERR_peek_last_error(); + if (NIL_P(str)) + str = rb_str_new(NULL, 0); + +#ifdef HAVE_ERR_GET_ERROR_ALL + e = ERR_peek_last_error_all(NULL, NULL, NULL, &data, &flags); +#else + e = ERR_peek_last_error_line_data(NULL, NULL, &data, &flags); +#endif if (e) { - const char *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); - } - else { - if (RSTRING_LEN(str)) rb_str_cat2(str, ": "); - rb_str_cat2(str, msg ? msg : "(null)"); - } - ossl_clear_error(); + if (RSTRING_LEN(str)) rb_str_cat_cstr(str, ": "); + rb_str_cat_cstr(str, msg ? msg : "(null)"); + if (flags & ERR_TXT_STRING && data) + rb_str_catf(str, " (%s)", data); + ossl_clear_error(); } - if (NIL_P(str)) str = rb_str_new(0, 0); - return rb_exc_new3(exc, str); + return rb_exc_new_str(exc, str); } void diff --git a/test/openssl/test_ossl.rb b/test/openssl/test_ossl.rb index e1d86bd40b..5759c75b81 100644 --- a/test/openssl/test_ossl.rb +++ b/test/openssl/test_ossl.rb @@ -60,6 +60,18 @@ class OpenSSL::OSSL < OpenSSL::SSLTestCase assert_operator(a_b_time, :<, a_c_time * 10, "fixed_length_secure_compare timing test failed") assert_operator(a_c_time, :<, a_b_time * 10, "fixed_length_secure_compare timing test failed") end + + def test_error_data + # X509V3_EXT_nconf_nid() called from OpenSSL::X509::ExtensionFactory#create_ext is a function + # that uses ERR_raise_data() to append additional information about the error. + # + # The generated message should look like: + # "subjectAltName = IP:not.a.valid.ip.address: bad ip address (value=not.a.valid.ip.address)" + ef = OpenSSL::X509::ExtensionFactory.new + assert_raise_with_message(OpenSSL::X509::ExtensionError, /\(value=not.a.valid.ip.address\)/) { + ef.create_ext("subjectAltName", "IP:not.a.valid.ip.address") + } + end end end