asyncnet, net: clear openssl error queue before performing I/O

Per SSL_get_error(3):

  The current thread's error queue must be empty before the TLS/SSL I/O
  operation is attempted, or SSL_get_error() will not work reliably.

There has been records of not clearing the error queue causing weird SSL
errors when there shouldn't be any, see:

https://github.com/openssl/openssl/issues/11889
This commit is contained in:
Leorize 2020-06-03 15:11:10 -05:00 • committed by Andreas Rumpf
commit 6cb94b5da6
3 changed files with 9 additions and 0 deletions

View file

@ -718,6 +718,7 @@ proc close*(socket: AsyncSocket) =
# established, see: # established, see:
# https://github.com/openssl/openssl/issues/710#issuecomment-253897666 # https://github.com/openssl/openssl/issues/710#issuecomment-253897666
if SSL_in_init(socket.sslHandle) == 0: if SSL_in_init(socket.sslHandle) == 0:
ErrClearError()
SSL_shutdown(socket.sslHandle) SSL_shutdown(socket.sslHandle)
else: else:
0 0

View file

@ -752,12 +752,14 @@ when defineSsl:
# Discard result in case OpenSSL version doesn't support SNI, or we're # Discard result in case OpenSSL version doesn't support SNI, or we're
# not using TLSv1+ # not using TLSv1+
discard SSL_set_tlsext_host_name(socket.sslHandle, hostname) discard SSL_set_tlsext_host_name(socket.sslHandle, hostname)
ErrClearError()
let ret = SSL_connect(socket.sslHandle) let ret = SSL_connect(socket.sslHandle)
socketError(socket, ret) socketError(socket, ret)
when not defined(nimDisableCertificateValidation) and not defined(windows): when not defined(nimDisableCertificateValidation) and not defined(windows):
if hostname.len > 0 and not isIpAddress(hostname): if hostname.len > 0 and not isIpAddress(hostname):
socket.checkCertName(hostname) socket.checkCertName(hostname)
of handshakeAsServer: of handshakeAsServer:
ErrClearError()
let ret = SSL_accept(socket.sslHandle) let ret = SSL_accept(socket.sslHandle)
socketError(socket, ret) socketError(socket, ret)
@ -926,6 +928,7 @@ proc acceptAddr*(server: Socket, client: var owned(Socket), address: var string,
# We must wrap the client sock in a ssl context. # We must wrap the client sock in a ssl context.
server.sslContext.wrapSocket(client) server.sslContext.wrapSocket(client)
ErrClearError()
let ret = SSL_accept(client.sslHandle) let ret = SSL_accept(client.sslHandle)
socketError(client, ret, false) socketError(client, ret, false)
@ -955,6 +958,7 @@ when false: #defineSsl:
if not client.isSsl or client.sslHandle == nil: if not client.isSsl or client.sslHandle == nil:
server.sslContext.wrapSocket(client) server.sslContext.wrapSocket(client)
ErrClearError()
let ret = SSL_accept(client.sslHandle) let ret = SSL_accept(client.sslHandle)
while ret <= 0: while ret <= 0:
let err = SSL_get_error(client.sslHandle, ret) let err = SSL_get_error(client.sslHandle, ret)
@ -1135,6 +1139,7 @@ proc uniRecv(socket: Socket, buffer: pointer, size, flags: cint): int =
assert(not socket.isClosed, "Cannot `recv` on a closed socket") assert(not socket.isClosed, "Cannot `recv` on a closed socket")
when defineSsl: when defineSsl:
if socket.isSsl: if socket.isSsl:
ErrClearError()
return SSL_read(socket.sslHandle, buffer, size) return SSL_read(socket.sslHandle, buffer, size)
return recv(socket.fd, buffer, size, flags) return recv(socket.fd, buffer, size, flags)
@ -1484,6 +1489,7 @@ proc send*(socket: Socket, data: pointer, size: int): int {.
assert(not socket.isClosed, "Cannot `send` on a closed socket") assert(not socket.isClosed, "Cannot `send` on a closed socket")
when defineSsl: when defineSsl:
if socket.isSsl: if socket.isSsl:
ErrClearError()
return SSL_write(socket.sslHandle, cast[cstring](data), size) return SSL_write(socket.sslHandle, cast[cstring](data), size)
when useWinVersion or defined(macosx): when useWinVersion or defined(macosx):
@ -1768,6 +1774,7 @@ proc connect*(socket: Socket, address: string,
# not using TLSv1+ # not using TLSv1+
discard SSL_set_tlsext_host_name(socket.sslHandle, address) discard SSL_set_tlsext_host_name(socket.sslHandle, address)
ErrClearError()
let ret = SSL_connect(socket.sslHandle) let ret = SSL_connect(socket.sslHandle)
socketError(socket, ret) socketError(socket, ret)
when not defined(nimDisableCertificateValidation) and not defined(windows): when not defined(nimDisableCertificateValidation) and not defined(windows):

View file

@ -61,6 +61,7 @@ when not defined(windows):
var ssl: SslPtr = SSL_new(ctx.context) var ssl: SslPtr = SSL_new(ctx.context)
discard SSL_set_fd(ssl, client.getFd()) discard SSL_set_fd(ssl, client.getFd())
log "server: accepting connection" log "server: accepting connection"
ErrClearError()
if SSL_accept(ssl) <= 0: if SSL_accept(ssl) <= 0:
ERR_print_errors_fp(stderr) ERR_print_errors_fp(stderr)
else: else: