On 01/09/2021 16:36, Zeke Evans wrote:
Is there any way to check the status of client authentication sent in a
TLS 1.3 handshake after SSL_connect returns? With TLS 1.2 SSL_connect
seems to always capture the status and return an error code if it failed
but not TLS 1.3. I haven’t been able to find a good way to do this
after SSL_connect returns. I have to handle blocking and non-blocking
sockets so calling SSL_read or SSL_peek isn’t an option since those
could block. If client authentication happened to fail then calling
those methods would work because they will return an error but if it
didn’t fail then they could block.
At a protocol level the handshake looks like this:
Client Server
Key ^ ClientHello
Exch | + key_share*
| + signature_algorithms*
| + psk_key_exchange_modes*
v + pre_shared_key* -------->
ServerHello ^ Key
+ key_share* | Exch
+ pre_shared_key* v
{EncryptedExtensions} ^ Server
{CertificateRequest*} v Params
{Certificate*} ^
{CertificateVerify*} | Auth
{Finished} v
<-------- [Application Data*]
^ {Certificate*}
Auth | {CertificateVerify*}
v {Finished} -------->
[Application Data] <-------> [Application Data]
The handshake has completed from the perspective of one of the endpoints
once it has both sent and received a "Finished" message.
From the above you can see that the client receives the server's
"Finished" message before it sends its "Certificate"/"CertificateVerify"
and "Finished" messages back to the server. At this point "SSL_connect"
returns and the client is ready to start receiving application data.
From the server's perspective it is still handshaking when it receives
the client's certificate (because it didn't receive the client's
"Finished" message yet). So the server when send an alert at this point
if the certificate is not acceptable and SSL_accept() will return with a
failure.
The client does not know what it will receive back from the server. It
could either be application data (in the case of an accepted
certificate) or an alert (in the case of a reject certificate). The only
way it can find out is to attempt to read data from the connection and
see what it gets back. The API to do this is SSL_read()/SSL_peek().
So, to answer your question, there is no way to check the status of
client authentication without calling SSL_read()/SSL_peek(). It
necessarily requires an attempt to read data from the socket in order to
find that status out due to the way the protocol is designed.
On 01/09/2021 16:51, Benjamin Kaduk via openssl-users wrote:
> Note that the server is allowed to ignore a client cert that it
doesn't like, proceeding with the connection as if the client was
unauthenticated. If you need a specific signal that the server believes
the client successfully authenticated, that has to be at the application
layer.
This is true, but ultimately the client still needs to attempt to read
data from the socket to figure out what the server did.
> Did you try a zero-length SSL_read()? My recollection is that that
gets far enough into the library to see if there are pending alert
messages to process.
Again, there will only be alerts to process (related to a client
certificate failure) if the client has attempted to read application data.
Matt