[openssl-dev] How to do reneg with client certs in 1.1.0 API

Rainer Jung rainer.jung at kippdata.de
Mon Feb 8 16:45:45 UTC 2016


Am 08.02.2016 um 13:34 schrieb Matt Caswell:
> On 08/02/16 12:11, Rainer Jung wrote:
>> I'm adding support for OpenSSL 1.1.0 to the Apache web server.
>>
>> I struggle to migrate the renegotiation code in the case wehere we want
>> the client to send a client cert. The current code works like explained in
>>
>>    http://www.linuxjournal.com/node/5487/print
>>
>> After using SSL_set_verify() it calls
>>
>>    SSL_renegotiate(ssl);
>>    SSL_do_handshake(ssl);
>>    SSL_set_state(ssl, SSL_ST_ACCEPT);
>>    SSL_do_handshake(ssl);
>>
>> for reasons given in the article.
>>
>> The new 1.1.0 API no longer allows to set the state using
>> SSL_set_state(). The old article states, that calling
>> SSL_set_accept_state() is not the right thing to do. Looking at
>> s_server.c doesn't give a hint what to do instead, because it looks like
>> it reads the client certs just raw from the socket.
>>
>> Any hint what would replace the above sequence or at least the
>> SSL_set_state(ssl, SSL_ST_ACCEPT)?
>>
>> Thanks a bunch and regards,
>
> Renegotiation isn't entirely within the control of the server. A server
> can request that a renegotiation takes place. It is up to the client
> whether it honours that request immediately; or perhaps its finishes off
> sending some application data before it gets around to honouring it; or
> perhaps it doesn't honour it at all.
>
>>    SSL_renegotiate(ssl);
>>    SSL_do_handshake(ssl);
>
> This sequence makes the server send the HelloVerifyRequest. It is then
> back in a state where it can continue to receive application data from
> the client. At some later point the client may or may not initiate a reneg.
>
>>    SSL_set_state(ssl, SSL_ST_ACCEPT);
>>    SSL_do_handshake(ssl);
>
> This is really not a good idea, and I suspect is a hack that was
> originally copied from s_server :-). Doing this will make the connection
> fail if the client sends application data next (which it is allowed to do).
>
> We don't know what we're going to get next from the client it could be
> more application data. It could be an immediate start of a new
> handshake. The correct thing for the server to do is to attempt to read
> application data. If we happen to get a handshake instead then it will
> be automatically handled.

OK, tried it and it partially works. More precisely: when the cipher is 
AES128-SHA it works, bur for ECDHE-RSA-AES128-SHA256 I run into an error 
in tls_construct_server_key_exchange() (file statem/statem_srvr.c).

The following conditions triggers the jump to err:

    1773     if (type & (SSL_kECDHE | SSL_kECDHEPSK)) {
    1774         int nid;
    1775
    1776         if (s->s3->tmp.pkey != NULL) {
    1777             SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
    1778                    ERR_R_INTERNAL_ERROR);
    1779             goto err;
    1780         }

By comparing the communication for the two ciphers I see the following flow:

write 69/69 bytes
SSLv3/TLS write hello request
- try to read app data -> I/O error, 5 bytes expected to read
read 5/5 bytes
read 576/576
Handshake: start
before SSL initialization
before SSL initialization
SSLv3/TLS read client hello
write 149/149
SSLv3/TLS write server hello
write 2021/2021
SSLv3/TLS write certificate

And here for the ECDHE case the error triggered by the above check.

In the AES case we proceed

write 1173/1173
SSLv3/TLS write certificate request
write 69/69 bytes
write 3412/3412 bytes
SSLv3/TLS write server done
error in SSLv3/TLS write server done
read 5/5 bytes
read 1952/1952
SSLv3/TLS write server done
Successful client certificate verification

Any idea how to clear s->s3->tmp.pkey so that the check doesn't trigger?

I see SSL_clear() but from its description I doubt that is should be 
used here.

Regards,

Rainer


More information about the openssl-dev mailing list