Support multiple records in one datagram

This commit is contained in:
Manuel Pégourié-Gonnard 2014-07-10 17:54:52 +02:00 committed by Paul Bakker
parent 798f15a500
commit b2f3be8757
3 changed files with 62 additions and 6 deletions

View file

@ -770,6 +770,10 @@ struct _ssl_context
int in_msgtype; /*!< record header: message type */ int in_msgtype; /*!< record header: message type */
size_t in_msglen; /*!< record header: message length */ size_t in_msglen; /*!< record header: message length */
size_t in_left; /*!< amount of data read so far */ size_t in_left; /*!< amount of data read so far */
#if defined(POLARSSL_SSL_PROTO_DTLS)
size_t next_record_offset; /*!< offset of the next record in datagram,
or 0 if none */
#endif
size_t in_hslen; /*!< current handshake message length */ size_t in_hslen; /*!< current handshake message length */
int nb_zero; /*!< # of 0-length encrypted messages */ int nb_zero; /*!< # of 0-length encrypted messages */

View file

@ -1697,6 +1697,7 @@ have_ciphersuite:
ssl->transform_negotiate->ciphersuite_info = ciphersuite_info; ssl->transform_negotiate->ciphersuite_info = ciphersuite_info;
ssl_optimize_checksum( ssl, ssl->transform_negotiate->ciphersuite_info ); ssl_optimize_checksum( ssl, ssl->transform_negotiate->ciphersuite_info );
/* ClientHello can't be bundled with another record in same datagram */
ssl->in_left = 0; ssl->in_left = 0;
ssl->state++; ssl->state++;

View file

@ -1821,14 +1821,19 @@ static int ssl_decompress_buf( ssl_context *ssl )
#endif /* POLARSSL_ZLIB_SUPPORT */ #endif /* POLARSSL_ZLIB_SUPPORT */
/* /*
* Fill the input message buffer * Fill the input message buffer by appending data to it.
* The amount of data already fetched is in ssl->in_left.
* *
* If we return 0, is it guaranteed that (at least) nb_want bytes are * If we return 0, is it guaranteed that (at least) nb_want bytes are
* available (from this read and/or a previous one). Otherwise, an error code * available (from this read and/or a previous one). Otherwise, an error code
* is returned (possibly EOF or WANT_READ). * is returned (possibly EOF or WANT_READ).
* *
* Set ssl->in_left to 0 before calling to start a new record. Apart from * With stream transport (TLS) on success ssl->in_left == nb_want, but
* this, ssl->in_left is an internal variable and should never be read. * with datagram transport (DTLS) on success ssl->in_left >= nb_want,
* since we always read a whole datagram at once.
*
* For DTLS, It is up to the caller to set ssl->next_record_offset when
* they're done reading a record.
*/ */
int ssl_fetch_input( ssl_context *ssl, size_t nb_want ) int ssl_fetch_input( ssl_context *ssl, size_t nb_want )
{ {
@ -1846,13 +1851,43 @@ int ssl_fetch_input( ssl_context *ssl, size_t nb_want )
#if defined(POLARSSL_SSL_PROTO_DTLS) #if defined(POLARSSL_SSL_PROTO_DTLS)
if( ssl->transport == SSL_TRANSPORT_DATAGRAM ) if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
{ {
/*
* The point is, we need to always read a full datagram at once, so we
* sometimes read more then requested, and handle the additional data.
* It could be the rest of the current record (while fetching the
* header) and/or some other records in the same datagram.
*/
/*
* Move to the next record in the already read datagram if applicable
*/
if( ssl->next_record_offset != 0 )
{
if( ssl->in_left < ssl->next_record_offset )
{
SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( POLARSSL_ERR_SSL_INTERNAL_ERROR );
}
ssl->in_left -= ssl->next_record_offset;
if( ssl->in_left != 0 )
{
SSL_DEBUG_MSG( 2, ( "next record in same datagram, offset: %d",
ssl->next_record_offset ) );
memmove( ssl->in_hdr,
ssl->in_hdr + ssl->next_record_offset,
ssl->in_left );
}
ssl->next_record_offset = 0;
}
SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d", SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d",
ssl->in_left, nb_want ) ); ssl->in_left, nb_want ) );
/* /*
* With UDP, we must always read a full datagram. * Done if we already have enough data.
* Just remember how much we read and avoid reading again if we
* already have enough data.
*/ */
if( nb_want <= ssl->in_left) if( nb_want <= ssl->in_left)
return( 0 ); return( 0 );
@ -1884,6 +1919,9 @@ int ssl_fetch_input( ssl_context *ssl, size_t nb_want )
else else
#endif #endif
{ {
SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d",
ssl->in_left, nb_want ) );
while( ssl->in_left < nb_want ) while( ssl->in_left < nb_want )
{ {
len = nb_want - ssl->in_left; len = nb_want - ssl->in_left;
@ -2251,6 +2289,12 @@ int ssl_read_record( ssl_context *ssl )
return( ret ); return( ret );
} }
#if defined(POLARSSL_SSL_PROTO_DTLS)
/* Done reading this record, get ready for the next one */
if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
ssl->next_record_offset = ssl->in_msglen + ssl_hdr_len( ssl );
#endif
SSL_DEBUG_BUF( 4, "input record from network", SSL_DEBUG_BUF( 4, "input record from network",
ssl->in_hdr, ssl_hdr_len( ssl ) + ssl->in_msglen ); ssl->in_hdr, ssl_hdr_len( ssl ) + ssl->in_msglen );
@ -2358,6 +2402,10 @@ int ssl_read_record( ssl_context *ssl )
} }
} }
/* With DTLS there might be other records in the same datagram */
#if defined(POLARSSL_SSL_PROTO_DTLS)
if( ssl->transport != SSL_TRANSPORT_DATAGRAM )
#endif
ssl->in_left = 0; ssl->in_left = 0;
SSL_DEBUG_MSG( 2, ( "<= read record" ) ); SSL_DEBUG_MSG( 2, ( "<= read record" ) );
@ -3597,6 +3645,9 @@ int ssl_session_reset( ssl_context *ssl )
ssl->in_msgtype = 0; ssl->in_msgtype = 0;
ssl->in_msglen = 0; ssl->in_msglen = 0;
ssl->in_left = 0; ssl->in_left = 0;
#if defined(POLARSSL_SSL_PROTO_DTLS)
ssl->next_record_offset = 0;
#endif
ssl->in_hslen = 0; ssl->in_hslen = 0;
ssl->nb_zero = 0; ssl->nb_zero = 0;