diff --git a/src/openssl.cr b/src/openssl.cr index 802c9a05e7d3..4185518d3982 100644 --- a/src/openssl.cr +++ b/src/openssl.cr @@ -88,10 +88,19 @@ module OpenSSL message = "Raised erroneously" when .syscall? @code, message = fetch_error_details - if @code == 0 + {% if LibSSL.has_constant?(:SSL_R_UNEXPECTED_EOF_WHILE_READING) %} + if @code == 0 + # FIXME: this isn't a per the OpenSSL documentation for how to + # detect EOF, but this fixes the EOF detection spec... + message = "Unexpected EOF while reading" + @underlying_eof = true + else + cause = RuntimeError.from_errno(func || "OpenSSL") + end + {% else %} case return_code when 0 - message = "Unexpected EOF" + message = "Unexpected EOF while reading" @underlying_eof = true when -1 cause = RuntimeError.from_errno(func || "OpenSSL") @@ -99,9 +108,15 @@ module OpenSSL else message = "Unknown error" end - end + {% end %} when .ssl? - @code, message = fetch_error_details + code, message = fetch_error_details + @code = code + {% if LibSSL.has_constant?(:SSL_R_UNEXPECTED_EOF_WHILE_READING) %} + if get_reason(code) == LibSSL::SSL_R_UNEXPECTED_EOF_WHILE_READING + @underlying_eof = true + end + {% end %} else message = @error.to_s end diff --git a/src/openssl/error.cr b/src/openssl/error.cr index e902ad9bef42..ff12c33812ab 100644 --- a/src/openssl/error.cr +++ b/src/openssl/error.cr @@ -21,5 +21,17 @@ module OpenSSL message = String.new(LibCrypto.err_error_string(code, nil)) unless code == 0 {code, message || "Unknown or no error"} end + + protected def get_reason(code) + {% if LibCrypto.has_constant?(:ERR_REASON_MASK) %} + if (code & LibCrypto::ERR_SYSTEM_FLAG) != 0 + (code & LibCrypto::ERR_SYSTEM_MASK).to_i + else + (code & LibCrypto::ERR_REASON_MASK).to_i + end + {% else %} + (code & 0xFFF).to_i + {% end %} + end end end diff --git a/src/openssl/lib_crypto.cr b/src/openssl/lib_crypto.cr index caca9c11c520..87d9c25014a4 100644 --- a/src/openssl/lib_crypto.cr +++ b/src/openssl/lib_crypto.cr @@ -268,6 +268,12 @@ lib LibCrypto fun err_get_error = ERR_get_error : ULong fun err_error_string = ERR_error_string(e : ULong, buf : Char*) : Char* + {% if compare_versions(OPENSSL_VERSION, "3.0.0") >= 0 %} + ERR_SYSTEM_FLAG = Int32::MAX.to_u32 + 1 + ERR_SYSTEM_MASK = Int32::MAX.to_u32 + ERR_REASON_MASK = 0x7FFFFF + {% end %} + struct MD5Context a : UInt b : UInt diff --git a/src/openssl/lib_ssl.cr b/src/openssl/lib_ssl.cr index 27faf9bbe185..54932332c68b 100644 --- a/src/openssl/lib_ssl.cr +++ b/src/openssl/lib_ssl.cr @@ -284,6 +284,11 @@ lib LibSSL fun ssl_ctx_set_security_level = SSL_CTX_set_security_level(ctx : SSLContext, level : Int) : Void fun ssl_ctx_get_security_level = SSL_CTX_get_security_level(ctx : SSLContext) : Int {% end %} + + # SSL reason codes + {% if compare_versions(OPENSSL_VERSION, "3.0.0") >= 0 %} + SSL_R_UNEXPECTED_EOF_WHILE_READING = 294 + {% end %} end {% unless compare_versions(LibSSL::OPENSSL_VERSION, "1.1.0") >= 0 %}