Viktor Dukhovni writes:
On Wed, Apr 29, 2020 at 06:02:13PM -0400, Sam Varshavchik wrote:
> > It emits a fatal "unexpected message" alert. Turn off the
> > client-cert request, and it works fine.
> > Name withheld to protect the guilty.
> I wouldn't necessarily blame the operator. It's almost a sure bet that
> they're using OpenSSL, and this developer's opinion is that OpenSSL is one
> of the worst, most confusing, and the most poorly documented API libraries
> in existence.
I are of course free to vent, but on this particular issue the
frustration is misdirected. The OpenSSL TLS client silently ignores
solications for client certificates when none are configured at the
client. It is up to the server to then accept or deny the handshake.
[ Rare applications that want to select certificates dynamically can
register for a callback, but then the decisions are theirs to make. ]
So after reading the following:
# When a certificate was set using the SSL_CTX_use_certificate(3) family of
# functions, it will be sent to the server. The TLS standard requires that
# only a certificate is sent, if it matches the list of acceptable CAs sent by
# the server. This constraint is violated by the default behavior of the
# OpenSSL library.
This appeared to me like a client that was configured with a certificate for
some other host, but sending it in error, here, and the server rejecting the
connection for that reason.
Problematic TLS implementation have been quite common, historically. For a
long time I was seeing frequently TLS-related misconfigurations with SMTP
servers. I lost count how many servers I saw advertising STARTTLS but
choking when taken up on their offer:
220 poorly-configured-server.example.com ESMTP
450 Not now, maybe someday.
At one point I had to carefully implement an adaptive, transient TLS
blacklist: ignore the server's STARTTLS if you have a prior record of the
server failing to negotiate a TLS connection.
> have reached the stage where it's been determined that the OpenSSL library
> is reporting an error code that its own documentation describes thusly:
> Some non-recoverable, fatal I/O error occurred. The OpenSSL error
> queue may contain more information on the error. For socket I/O
> Unix systems, consult errno for details.
> And, immediately after that, the code in question does "consult errno", and
> finds that it's zero. No error has occured, according to the operating
This is likely TLS session termination without a TLS close notify, i.e.
potentially vulnerable to truncation attacks. An empty read on EOF does
not set errno. In OpenSSL 1.1.1e there was a fix for that, to make it
an SSL_ERROR_SSL, but that turned to have too many backwards compatibility
issues, so it got rolled back in 1.1.1f.
I did not find this called out in the documentation, just a blanket
statement: check errno, here's your error. This behavior was observed not
with an active connection, but in a middle of a handshake, inside
SSL_accept. The connection failed with no other indication of what the issue
was. I'm too lazy to dig into openssl's source, but it seems that SSL_accept
uses BIO_read, where "no data was successfully read or written if the result
is 0 or -1". Then the default BIO_should_retry returns an indication
calculated as follows: the read or write failed with -1 and errno was EAGAIN
or EWOULDBLOCK. A closed socket connection (obviously) does not meet that
So, I surmised that SSL_accept was likely calling BIO_read, and if it
returns 0 or -1 BIO_should_retry gets called; and SSL_ERROR_WANT_READ if so,
otherwise it must be SSL_ERROR_SYSCALL. And in this sequence, I was getting
an SSL_ERROR_SYSCALL but errno remained unset. I could not see how this was
documented behavior, from any public documentation.
Description: PGP signature
ietf-smtp mailing list