asyncnet, net: call SSL_shutdown only when connection established
This commit prevents "SSL_shutdown while in init" errors from happening. See https://github.com/openssl/openssl/issues/710#issuecomment-253897666
This commit is contained in:
parent
61f2f1f5c5
commit
82092b3bb7
4 changed files with 52 additions and 12 deletions
|
|
@ -713,7 +713,14 @@ proc close*(socket: AsyncSocket) =
|
||||||
socket.fd.AsyncFD.closeSocket()
|
socket.fd.AsyncFD.closeSocket()
|
||||||
when defineSsl:
|
when defineSsl:
|
||||||
if socket.isSsl:
|
if socket.isSsl:
|
||||||
let res = SSL_shutdown(socket.sslHandle)
|
let res =
|
||||||
|
# Don't call SSL_shutdown if the connection has not been fully
|
||||||
|
# established, see:
|
||||||
|
# https://github.com/openssl/openssl/issues/710#issuecomment-253897666
|
||||||
|
if SSL_in_init(socket.sslHandle) == 0:
|
||||||
|
SSL_shutdown(socket.sslHandle)
|
||||||
|
else:
|
||||||
|
0
|
||||||
SSL_free(socket.sslHandle)
|
SSL_free(socket.sslHandle)
|
||||||
if res == 0:
|
if res == 0:
|
||||||
discard
|
discard
|
||||||
|
|
|
||||||
|
|
@ -1007,6 +1007,10 @@ proc close*(socket: Socket) =
|
||||||
when defineSsl:
|
when defineSsl:
|
||||||
if socket.isSsl and socket.sslHandle != nil:
|
if socket.isSsl and socket.sslHandle != nil:
|
||||||
ErrClearError()
|
ErrClearError()
|
||||||
|
# Don't call SSL_shutdown if the connection has not been fully
|
||||||
|
# established, see:
|
||||||
|
# https://github.com/openssl/openssl/issues/710#issuecomment-253897666
|
||||||
|
if SSL_in_init(socket.sslHandle) == 0:
|
||||||
# As we are closing the underlying socket immediately afterwards,
|
# As we are closing the underlying socket immediately afterwards,
|
||||||
# it is valid, under the TLS standard, to perform a unidirectional
|
# it is valid, under the TLS standard, to perform a unidirectional
|
||||||
# shutdown i.e not wait for the peers "close notify" alert with a second
|
# shutdown i.e not wait for the peers "close notify" alert with a second
|
||||||
|
|
|
||||||
|
|
@ -201,6 +201,9 @@ const
|
||||||
SSL_OP_ALL* = 0x000FFFFF
|
SSL_OP_ALL* = 0x000FFFFF
|
||||||
SSL_VERIFY_NONE* = 0x00000000
|
SSL_VERIFY_NONE* = 0x00000000
|
||||||
SSL_VERIFY_PEER* = 0x00000001
|
SSL_VERIFY_PEER* = 0x00000001
|
||||||
|
SSL_ST_CONNECT* = 0x1000
|
||||||
|
SSL_ST_ACCEPT* = 0x2000
|
||||||
|
SSL_ST_INIT* = SSL_ST_CONNECT or SSL_ST_ACCEPT
|
||||||
OPENSSL_DES_DECRYPT* = 0
|
OPENSSL_DES_DECRYPT* = 0
|
||||||
OPENSSL_DES_ENCRYPT* = 1
|
OPENSSL_DES_ENCRYPT* = 1
|
||||||
X509_V_OK* = 0
|
X509_V_OK* = 0
|
||||||
|
|
@ -282,6 +285,13 @@ when compileOption("dynlibOverride", "ssl") or defined(noOpenSSLHacks):
|
||||||
# Static linking against OpenSSL < 1.1.0 is not supported
|
# Static linking against OpenSSL < 1.1.0 is not supported
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
when defined(libressl) or defined(openssl10):
|
||||||
|
proc SSL_state(ssl: SslPtr): cint {.cdecl, dynlib: DLLSSLName, importc.}
|
||||||
|
proc SSL_in_init*(ssl: SslPtr): cint {.inline.} =
|
||||||
|
SSl_state(ssl) and SSL_ST_INIT
|
||||||
|
else:
|
||||||
|
proc SSL_in_init*(ssl: SslPtr): cint {.cdecl, dynlib: DLLSSLName, importc.}
|
||||||
|
|
||||||
template OpenSSL_add_all_algorithms*() = discard
|
template OpenSSL_add_all_algorithms*() = discard
|
||||||
|
|
||||||
proc SSLv23_client_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.}
|
proc SSLv23_client_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.}
|
||||||
|
|
@ -382,6 +392,24 @@ else:
|
||||||
if theProc.isNil: 0.culong
|
if theProc.isNil: 0.culong
|
||||||
else: theProc()
|
else: theProc()
|
||||||
|
|
||||||
|
proc SSL_in_init*(ssl: SslPtr): cint =
|
||||||
|
# A compatibility wrapper for `SSL_in_init()` for OpenSSL 1.0, 1.1 and LibreSSL
|
||||||
|
const MainProc = "SSL_in_init"
|
||||||
|
let
|
||||||
|
theProc {.global.} = cast[proc(ssl: SslPtr): cint {.cdecl.}](sslSymNullable(MainProc))
|
||||||
|
# Fallback
|
||||||
|
sslState {.global.} = cast[proc(ssl: SslPtr): cint {.cdecl.}](sslSymNullable("SSL_state"))
|
||||||
|
|
||||||
|
# FIXME: This shouldn't be needed, but the compiler is complaining about
|
||||||
|
# `sslState` being GC-ed memory???
|
||||||
|
{.gcsafe.}:
|
||||||
|
if not theProc.isNil:
|
||||||
|
theProc(ssl)
|
||||||
|
elif not sslState.isNil:
|
||||||
|
sslState(ssl) and SSL_ST_INIT
|
||||||
|
else:
|
||||||
|
raiseInvalidLibrary MainProc
|
||||||
|
|
||||||
proc ERR_load_BIO_strings*(){.cdecl, dynlib: DLLUtilName, importc.}
|
proc ERR_load_BIO_strings*(){.cdecl, dynlib: DLLUtilName, importc.}
|
||||||
|
|
||||||
proc SSL_new*(context: SslCtx): SslPtr{.cdecl, dynlib: DLLSSLName, importc.}
|
proc SSL_new*(context: SslCtx): SslPtr{.cdecl, dynlib: DLLSSLName, importc.}
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,8 @@ when not defined(windows):
|
||||||
let msg = getCurrentExceptionMsg()
|
let msg = getCurrentExceptionMsg()
|
||||||
log "client: exception: " & msg
|
log "client: exception: " & msg
|
||||||
# SSL_shutdown:shutdown while in init
|
# SSL_shutdown:shutdown while in init
|
||||||
if not (msg.contains("shutdown while in init") or msg.contains("alert number 48") or
|
if not (msg.contains("alert number 48") or
|
||||||
msg.contains("routines:CONNECT_CR_CERT:certificate verify failed")):
|
msg.contains("routines:CONNECT_CR_CERT:certificate verify failed") or
|
||||||
|
msg.contains("routines:tls_process_server_certificate:certificate verify failed")):
|
||||||
echo "CVerifyPeer exception: " & msg
|
echo "CVerifyPeer exception: " & msg
|
||||||
check(false)
|
check(false)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue