asyncnet, net: don't attempt SSL_shutdown if a fatal error occurred (#15066)

* asyncnet, net: don't attempt SSL_shutdown if a fatal error occurred

Per TLS standard and SSL_shutdown(3ssl). This should prevent errors
coming from a close() after a bad event (ie. the other end of the pipe
is closed before shutdown can be negotiated).

Ref #9867

* tssl: try sending until an error occur

* tssl: cleanup

* tssl: actually run the test

I forgot to make the test run :P

* tssl: run the test on ARC, maybe then it'll be happy

* tssl: turns off ARC, switch tlsEmulation on for freebsd

* tssl: document why tlsEmulation is employed

* net: move SafeDisconn handling logic to socketError
This commit is contained in:
alaviss 2020-07-29 22:35:02 +00:00 • committed by GitHub
commit 20315637aa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 120 additions and 34 deletions

View file

@ -123,6 +123,7 @@ type
sslContext: SslContext
bioIn: BIO
bioOut: BIO
sslNoShutdown: bool
domain: Domain
sockType: SockType
protocol: Protocol
@ -200,9 +201,10 @@ proc newAsyncSocket*(domain, sockType, protocol: cint,
Protocol(protocol), buffered, inheritable)
when defineSsl:
proc getSslError(handle: SslPtr, err: cint): cint =
proc getSslError(socket: AsyncSocket, err: cint): cint =
assert socket.isSsl
assert err < 0
var ret = SSL_get_error(handle, err.cint)
var ret = SSL_get_error(socket.sslHandle, err.cint)
case ret
of SSL_ERROR_ZERO_RETURN:
raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
@ -213,6 +215,7 @@ when defineSsl:
of SSL_ERROR_WANT_X509_LOOKUP:
raiseSSLError("Function for x509 lookup has been called.")
of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
socket.sslNoShutdown = true
raiseSSLError()
else: raiseSSLError("Unknown Error")
@ -265,7 +268,7 @@ when defineSsl:
# If the operation failed, try to see if SSL has some data to read
# or write.
if opResult < 0:
let err = getSslError(socket.sslHandle, opResult.cint)
let err = getSslError(socket, opResult.cint)
let fut = appeaseSsl(socket, flags, err.cint)
yield fut
if not fut.read():
@ -718,7 +721,7 @@ proc close*(socket: AsyncSocket) =
# 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:
if not socket.sslNoShutdown and SSL_in_init(socket.sslHandle) == 0:
ErrClearError()
SSL_shutdown(socket.sslHandle)
else:
@ -747,6 +750,8 @@ when defineSsl:
socket.bioOut = bioNew(bioSMem())
sslSetBio(socket.sslHandle, socket.bioIn, socket.bioOut)
socket.sslNoShutdown = true
proc wrapConnectedSocket*(ctx: SslContext, socket: AsyncSocket,
handshake: SslHandshakeType,
hostname: string = "") =