Add ability to resend last flight

This commit is contained in:
Manuel Pégourié-Gonnard 2014-09-23 09:42:16 +02:00 committed by Paul Bakker
parent 992e13665d
commit abf16240dd

View file

@ -2297,7 +2297,7 @@ int ssl_write_record( ssl_context *ssl )
#if defined(POLARSSL_SSL_PROTO_DTLS) #if defined(POLARSSL_SSL_PROTO_DTLS)
if( ssl->transport == SSL_TRANSPORT_DATAGRAM && if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
ssl->handshake != NULL && ssl->handshake != NULL &&
ssl->handshake->retransmit_state == SSL_RETRANS_PREPARING && ssl->handshake->retransmit_state != SSL_RETRANS_SENDING &&
( ssl->out_msgtype == SSL_MSG_CHANGE_CIPHER_SPEC || ( ssl->out_msgtype == SSL_MSG_CHANGE_CIPHER_SPEC ||
ssl->out_msgtype == SSL_MSG_HANDSHAKE ) ) ssl->out_msgtype == SSL_MSG_HANDSHAKE ) )
{ {
@ -2873,6 +2873,8 @@ static int ssl_prepare_record_content( ssl_context *ssl )
return( 0 ); return( 0 );
} }
static void ssl_handshake_wrapup_free_hs_transform( ssl_context *ssl );
/* /*
* Read a record. * Read a record.
* *
@ -2985,6 +2987,46 @@ read_record_header:
} }
} }
/*
* When we sent the last flight of the handshake, we MUST respond to a
* retransmit of the peer's previous flight with a retransmit. (In
* practice, only the Finished message will make it, other messages
* including CCS use the old transform so they're dropped as invalid.)
*
* If the record we received is not a handshake message, however, it
* means the peer received our last flight so we can clean up
* handshake info.
*
* This check needs to be done before prepare_handshake() due to an edge
* case: if the client immediately requests renegotiation, this
* finishes the current handshake first, avoiding the new ClientHello
* being mistaken for an ancient message in the current handshake.
*/
#if defined(POLARSSL_SSL_PROTO_DTLS)
if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
ssl->handshake != NULL &&
ssl->handshake->retransmit_state == SSL_RETRANS_FINISHED )
{
if( ssl->in_msgtype == SSL_MSG_HANDSHAKE &&
ssl->in_msg[0] == SSL_HS_FINISHED )
{
SSL_DEBUG_MSG( 2, ( "received retransmit of last flight" ) );
if( ( ret = ssl_resend( ssl ) ) != 0 )
{
SSL_DEBUG_RET( 1, "ssl_resend", ret );
return( ret );
}
return( POLARSSL_ERR_NET_WANT_READ );
}
else
{
ssl_handshake_wrapup_free_hs_transform( ssl );
}
}
#endif
/* /*
* Handle particular types of records * Handle particular types of records
*/ */
@ -3859,11 +3901,9 @@ static void ssl_calc_finished_tls_sha384(
#endif /* POLARSSL_SHA512_C */ #endif /* POLARSSL_SHA512_C */
#endif /* POLARSSL_SSL_PROTO_TLS1_2 */ #endif /* POLARSSL_SSL_PROTO_TLS1_2 */
void ssl_handshake_wrapup( ssl_context *ssl ) static void ssl_handshake_wrapup_free_hs_transform( ssl_context *ssl )
{ {
int resume = ssl->handshake->resume; SSL_DEBUG_MSG( 3, ( "=> handshake wrapup: final free" ) );
SSL_DEBUG_MSG( 3, ( "=> handshake wrapup" ) );
/* /*
* Free our handshake params * Free our handshake params
@ -3872,14 +3912,8 @@ void ssl_handshake_wrapup( ssl_context *ssl )
polarssl_free( ssl->handshake ); polarssl_free( ssl->handshake );
ssl->handshake = NULL; ssl->handshake = NULL;
if( ssl->renegotiation == SSL_RENEGOTIATION )
{
ssl->renegotiation = SSL_RENEGOTIATION_DONE;
ssl->renego_records_seen = 0;
}
/* /*
* Switch in our now active transform context * Free the previous transform and swith in the current one
*/ */
if( ssl->transform ) if( ssl->transform )
{ {
@ -3889,6 +3923,24 @@ void ssl_handshake_wrapup( ssl_context *ssl )
ssl->transform = ssl->transform_negotiate; ssl->transform = ssl->transform_negotiate;
ssl->transform_negotiate = NULL; ssl->transform_negotiate = NULL;
SSL_DEBUG_MSG( 3, ( "<= handshake wrapup: final free" ) );
}
void ssl_handshake_wrapup( ssl_context *ssl )
{
int resume = ssl->handshake->resume;
SSL_DEBUG_MSG( 3, ( "=> handshake wrapup" ) );
if( ssl->renegotiation == SSL_RENEGOTIATION )
{
ssl->renegotiation = SSL_RENEGOTIATION_DONE;
ssl->renego_records_seen = 0;
}
/*
* Free the previous session and switch in the current one
*/
if( ssl->session ) if( ssl->session )
{ {
ssl_session_free( ssl->session ); ssl_session_free( ssl->session );
@ -3908,6 +3960,18 @@ void ssl_handshake_wrapup( ssl_context *ssl )
SSL_DEBUG_MSG( 1, ( "cache did not store session" ) ); SSL_DEBUG_MSG( 1, ( "cache did not store session" ) );
} }
#if defined(POLARSSL_SSL_PROTO_DTLS)
if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
ssl->handshake->flight != NULL )
{
/* Keep last flight around in case we need to resend it:
* we need the handshake and transform structures for that */
SSL_DEBUG_MSG( 3, ( "skip freeing handshake and transform" ) );
}
else
#endif
ssl_handshake_wrapup_free_hs_transform( ssl );
ssl->state++; ssl->state++;
SSL_DEBUG_MSG( 3, ( "<= handshake wrapup" ) ); SSL_DEBUG_MSG( 3, ( "<= handshake wrapup" ) );
@ -5313,6 +5377,19 @@ int ssl_read( ssl_context *ssl, unsigned char *buf, size_t len )
SSL_DEBUG_MSG( 2, ( "=> read" ) ); SSL_DEBUG_MSG( 2, ( "=> read" ) );
#if defined(POLARSSL_SSL_PROTO_DTLS)
if( ssl->transport == SSL_TRANSPORT_DATAGRAM &&
ssl->handshake != NULL &&
ssl->handshake->retransmit_state == SSL_RETRANS_SENDING )
{
if( ( ret = ssl_flush_output( ssl ) ) != 0 )
return( ret );
if( ( ret = ssl_resend( ssl ) ) != 0 )
return( ret );
}
#endif
if( ssl->state != SSL_HANDSHAKE_OVER ) if( ssl->state != SSL_HANDSHAKE_OVER )
{ {
ret = ssl_handshake( ssl ); ret = ssl_handshake( ssl );