diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c index 0ffb817fb..365d80c42 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 e1d86bd40..888ec71f6 100644 --- a/test/openssl/test_ossl.rb +++ b/test/openssl/test_ossl.rb @@ -60,6 +60,18 @@ def test_memcmp_timing 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 + # SSL_CTX_set1_curves_list() is a function that puts additional context to + # the error queue using ERR_raise_data(). Ensure that the text is + # automatically included in the exception message. + return unless defined?(OpenSSL::SSL) + ctx = OpenSSL::SSL::SSLContext.new + # OpenSSL 3.1: "passed invalid argument (group 'not-a-curve' cannot be set)" + assert_raise_with_message(OpenSSL::SSL::SSLError, /passed invalid argument \(.*not-a-curve.*\)/) { + ctx.ecdh_curves = "P-256:not-a-curve" + } + end end end