From ffa67be698080c2d2504285237fdd1f2aec8e089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Fri, 19 Sep 2014 11:18:57 +0200 Subject: [PATCH] Infrastructure for buffering & resending flights --- include/polarssl/ssl.h | 29 +++++++++ library/ssl_tls.c | 134 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+) diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h index 42b3473a6..1a7722c9d 100644 --- a/include/polarssl/ssl.h +++ b/include/polarssl/ssl.h @@ -243,6 +243,14 @@ #define SSL_SESSION_TICKETS_DISABLED 0 #define SSL_SESSION_TICKETS_ENABLED 1 +/* + * DTLS retransmission states, see RFC 6347 4.2.4 + */ +#define SSL_RETRANS_PREPARING 0 +#define SSL_RETRANS_SENDING 1 +#define SSL_RETRANS_WAITING 2 +#define SSL_RETRANS_FINISHED 3 + /** * \name SECTION: Module settings * @@ -511,6 +519,9 @@ typedef struct _ssl_ticket_keys ssl_ticket_keys; #if defined(POLARSSL_X509_CRT_PARSE_C) typedef struct _ssl_key_cert ssl_key_cert; #endif +#if defined(POLARSSL_SSL_PROTO_DTLS) +typedef struct _ssl_flight_item ssl_flight_item; +#endif /* * This structure is used for storing current session data. @@ -622,11 +633,17 @@ struct _ssl_handshake_params #if defined(POLARSSL_SSL_PROTO_DTLS) unsigned int out_msg_seq; /*!< Outgoing handshake sequence number */ unsigned int in_msg_seq; /*!< Incoming handshake sequence number */ + unsigned char *verify_cookie; /*!< Cli: HelloVerifyRequest cookie Srv: unused */ unsigned char verify_cookie_len; /*!< Cli: cookie length Srv: flag for sending a cookie */ + unsigned char *hs_msg; /*!< Reassembled handshake message */ + + unsigned char retransmit_state; /*!< Retransmission state */ + ssl_flight_item *flight; /*!< Current outgoing flight */ + ssl_flight_item *cur_msg; /*!< Current message in flight */ #endif /* @@ -695,6 +712,18 @@ struct _ssl_key_cert }; #endif /* POLARSSL_X509_CRT_PARSE_C */ +#if defined(POLARSSL_SSL_PROTO_DTLS) +/* + * List of handshake messages kept around for resending + */ +struct _ssl_flight_item +{ + unsigned char *p; /*!< message, including handshake headers */ + size_t len; /*!< length of hs_msg */ + ssl_flight_item *next; /*!< next handshake message(s) */ +}; +#endif /* POLARSSL_SSL_PROTO_DTLS */ + struct _ssl_context { /* diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 8ab2ee3b1..423bc0bd1 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -2013,9 +2013,117 @@ int ssl_flush_output( ssl_context *ssl ) return( 0 ); } +#if defined(POLARSSL_SSL_PROTO_DTLS) +/* + * Append current handshake message to current outgoing flight + */ +static int ssl_flight_append( ssl_context *ssl ) +{ + ssl_flight_item *msg; + + /* Allocate space for current message */ + if( ( msg = polarssl_malloc( sizeof( ssl_flight_item ) ) ) == NULL ) + { + SSL_DEBUG_MSG( 1, ( "malloc %d bytes failed", + sizeof( ssl_flight_item ) ) ); + return( POLARSSL_ERR_SSL_MALLOC_FAILED ); + } + + if( ( msg->p = polarssl_malloc( ssl->out_msglen ) ) == NULL ) + { + SSL_DEBUG_MSG( 1, ( "malloc %d bytes failed", ssl->out_msglen ) ); + return( POLARSSL_ERR_SSL_MALLOC_FAILED ); + } + + /* Copy current handshake message with headers */ + memcpy( msg->p, ssl->out_msg, ssl->out_msglen ); + msg->len = ssl->out_msglen; + msg->next = NULL; + + /* Append to the current flight */ + if( ssl->handshake->flight == NULL ) + { + ssl->handshake->flight = msg; + ssl->handshake->cur_msg = msg; + } + else + { + ssl_flight_item *cur = ssl->handshake->flight; + while( cur->next != NULL ) + cur = cur->next; + cur->next = msg; + } + + return( 0 ); +} + +/* + * Free the current flight of handshake messages + */ +static void ssl_flight_free( ssl_flight_item *flight ) +{ + ssl_flight_item *cur = flight; + ssl_flight_item *next; + + while( cur != NULL ) + { + next = cur->next; + + polarssl_free( cur->p ); + polarssl_free( cur ); + + cur = next; + } +} + +/* + * Send current flight of messages. + * + * Need to remember the current message in case flush_output returns + * WANT_WRITE, causing us to exit this function and come back later. + */ +static int ssl_send_current_flight( ssl_context *ssl ) +{ + ssl->handshake->retransmit_state = SSL_RETRANS_SENDING; + + SSL_DEBUG_MSG( 2, ( "=> ssl_send_current_flight" ) ); + + while( ssl->handshake->cur_msg != NULL ) + { + int ret; + ssl_flight_item *cur = ssl->handshake->cur_msg; + + ssl->out_msglen = cur->len; + memcpy( ssl->out_msg, cur->p, ssl->out_msglen ); + ssl->out_msgtype = SSL_MSG_HANDSHAKE; + + ssl->handshake->cur_msg = cur->next; + + SSL_DEBUG_BUF( 3, "resent handshake message header", ssl->out_msg, 12 ); + + if( ( ret = ssl_write_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_write_record", ret ); + return( ret ); + } + } + + ssl->handshake->retransmit_state = SSL_RETRANS_WAITING; + + SSL_DEBUG_MSG( 2, ( "<= ssl_send_current_flight" ) ); + + return( 0 ); +} +#endif /* POLARSSL_SSL_PROTO_DTLS */ + /* * Record layer functions */ + +/* + * Write current record. + * Uses ssl->out_msgtype, ssl->out_msglen and bytes at ssl->out_msg. + */ int ssl_write_record( ssl_context *ssl ) { int ret, done = 0; @@ -2023,6 +2131,15 @@ int ssl_write_record( ssl_context *ssl ) SSL_DEBUG_MSG( 2, ( "=> write record" ) ); +#if defined(POLARSSL_SSL_PROTO_DTLS) + if( ssl->transport == SSL_TRANSPORT_DATAGRAM && + ssl->handshake != NULL && + ssl->handshake->retransmit_state == SSL_RETRANS_SENDING ) + { + ; /* Skip special handshake treatment when resending */ + } + else +#endif if( ssl->out_msgtype == SSL_MSG_HANDSHAKE ) { ssl->out_msg[1] = (unsigned char)( ( len - 4 ) >> 16 ); @@ -2067,6 +2184,22 @@ int ssl_write_record( ssl_context *ssl ) ssl->handshake->update_checksum( ssl, ssl->out_msg, len ); } + /* Save handshake and CCS messages for resending */ +#if defined(POLARSSL_SSL_PROTO_DTLS) + if( ssl->transport == SSL_TRANSPORT_DATAGRAM && + ssl->handshake != NULL && + ssl->handshake->retransmit_state == SSL_RETRANS_PREPARING && + ( ssl->out_msgtype == SSL_MSG_CHANGE_CIPHER_SPEC || + ssl->out_msgtype == SSL_MSG_HANDSHAKE ) ) + { + if( ( ret = ssl_flight_append( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_flight_append", ret ); + return( ret ); + } + } +#endif + #if defined(POLARSSL_ZLIB_SUPPORT) if( ssl->transform_out != NULL && ssl->session_out->compression == SSL_COMPRESS_DEFLATE ) @@ -5372,6 +5505,7 @@ void ssl_handshake_free( ssl_handshake_params *handshake ) #if defined(POLARSSL_SSL_PROTO_DTLS) polarssl_free( handshake->verify_cookie ); polarssl_free( handshake->hs_msg ); + ssl_flight_free( handshake->flight ); #endif polarssl_zeroize( handshake, sizeof( ssl_handshake_params ) );