client authentication status

Matt Caswell matt at openssl.org
Wed Sep 1 16:06:43 UTC 2021



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



More information about the openssl-users mailing list