@@ -1474,7 +1474,6 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security,
14741474 return 0 ;
14751475}
14761476
1477-
14781477static int
14791478dtls_send_handshake_msg_hash (dtls_context_t * ctx ,
14801479 dtls_peer_t * peer ,
@@ -3636,7 +3635,8 @@ dtls_free_reassemble_buffer(dtls_handshake_parameters_t *handshake_params){
36363635}
36373636
36383637static int
3639- dtls_init_reassemble_buffer (dtls_handshake_parameters_t * handshake_params , size_t packet_length ){
3638+ dtls_init_reassemble_buffer (dtls_handshake_parameters_t * handshake_params ,
3639+ size_t hs_size ){
36403640 /* Allocate buffer for full packet */
36413641 void * ret ;
36423642 ret = malloc (sizeof (dtls_hs_reassemble_t ));
@@ -3645,14 +3645,14 @@ dtls_init_reassemble_buffer(dtls_handshake_parameters_t *handshake_params, size_
36453645 } else {
36463646 handshake_params -> reassemble_buf = (dtls_hs_reassemble_t * )ret ;
36473647 }
3648- ret = malloc (packet_length + sizeof ( dtls_handshake_header_t ) );
3648+ ret = malloc (hs_size + DTLS_HS_LENGTH );
36493649 if (ret == NULL ){
36503650 free (handshake_params -> reassemble_buf );
36513651 return 0 ;
36523652 } else {
36533653 handshake_params -> reassemble_buf -> data = (uint8 * )ret ;
36543654 }
3655- handshake_params -> reassemble_buf -> packet_length = packet_length ;
3655+ handshake_params -> reassemble_buf -> data_length = hs_size + DTLS_HS_LENGTH ;
36563656 handshake_params -> reassemble_buf -> last_offset = 0 ;
36573657 return 1 ;
36583658}
@@ -3664,60 +3664,89 @@ handle_handshake(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session,
36643664{
36653665 dtls_handshake_header_t * hs_header ;
36663666 int res ;
3667+ size_t hs_size ;
3668+ size_t fragment_length ;
3669+ size_t fragment_offset ;
36673670
36683671 if (data_length < DTLS_HS_LENGTH ) {
36693672 dtls_warn ("handshake message too short\n" );
36703673 return dtls_alert_fatal_create (DTLS_ALERT_DECODE_ERROR );
36713674 }
36723675 hs_header = DTLS_HANDSHAKE_HEADER (data );
36733676
3674- size_t packet_length = dtls_uint24_to_int (hs_header -> length );
3675- size_t fragment_length = dtls_uint24_to_int (hs_header -> fragment_length );
3676- size_t fragment_offset = dtls_uint24_to_int (hs_header -> fragment_offset );
3677+ hs_size = dtls_uint24_to_int (hs_header -> length );
3678+ fragment_length = dtls_uint24_to_int (hs_header -> fragment_length );
3679+ fragment_offset = dtls_uint24_to_int (hs_header -> fragment_offset );
36773680
3678- if (packet_length > fragment_length ){
3679- dtls_debug ("received fragmented handshake packet: length %zu, fragment length %zu.\n" ,
3680- packet_length , fragment_length );
3681- /* If (reassembled) packet is larger than our buffer, drop with error */
3682- if (packet_length > DTLS_MAX_BUF ){
3683- dtls_warn ("reassembled packet (%zu) would be larger than buffer (%i)\n" , packet_length , DTLS_MAX_BUF );
3684- return dtls_alert_fatal_create (DTLS_ALERT_RECORD_OVERFLOW ); // TODO: Is this the correct alert?
3681+ if (fragment_offset + fragment_length > hs_size ) {
3682+ /* Fragment extension larger than handshake */
3683+ dtls_warn ("fragment_offset (%zu) + fragment_length (%zu) >"
3684+ " handshake length (%zu)\n" , fragment_offset ,
3685+ fragment_length , hs_size );
3686+ return dtls_alert_fatal_create (DTLS_ALERT_RECORD_OVERFLOW ); // TODO: Is this the correct alert?
3687+ }
3688+ else if (hs_size > fragment_length ) {
3689+
3690+ /* Handle fragmented packet */
3691+
3692+ if (!peer || !peer -> handshake_params ) {
3693+ /* This is the initial ClientHello - can't handle fragmented */
3694+ dtls_alert ("Cannot handle initial fragmented ClientHello\n" );
3695+ return dtls_alert_fatal_create (DTLS_ALERT_HANDSHAKE_FAILURE );
36853696 }
3686- if ((fragment_offset + fragment_length ) > packet_length ){
3687- dtls_warn ("fragment_offset (%zu) + fragment_length (%zu) > packet length (%zu)\n" ,
3688- fragment_offset , fragment_length , packet_length );
3689- return dtls_alert_fatal_create (DTLS_ALERT_RECORD_OVERFLOW ); // TODO: Is this the correct alert?
3697+ dtls_debug ("received fragmented handshake packet: handshake length %zu,"
3698+ " fragment length %zu.\n" , hs_size , fragment_length );
3699+
3700+ if (DTLS_HS_LENGTH + hs_size > DTLS_MAX_BUF ) {
3701+ /* Reassembled handshake is larger than our buffer, drop with error */
3702+ dtls_warn ("reassembled packet (%zu) would be larger than buffer (%i)\n" ,
3703+ DTLS_HS_LENGTH + hs_size , DTLS_MAX_BUF );
3704+ return dtls_alert_fatal_create (DTLS_ALERT_RECORD_OVERFLOW ); // TODO: Is this the correct alert?
36903705 }
3691- /* Handle fragmented packet */
36923706
3693- /* First fragment */
3694- if ( fragment_offset == 0 && packet_length <= DTLS_MAX_BUF ){
3707+ if ( fragment_offset == 0 ) {
3708+ /* First fragment */
36953709 dtls_debug ("received first packet of fragmented.\n" );
36963710 dtls_free_reassemble_buffer (peer -> handshake_params );
36973711
36983712 /* Allocate buffer for full packet */
3699- if (!dtls_init_reassemble_buffer (peer -> handshake_params , packet_length )) {
3700- return dtls_alert_fatal_create (DTLS_ALERT_RECORD_OVERFLOW ); // TODO: Is this the correct alert?
3713+ if (!dtls_init_reassemble_buffer (peer -> handshake_params , hs_size )) {
3714+ return dtls_alert_fatal_create (DTLS_ALERT_RECORD_OVERFLOW ); // TODO: Is this the correct alert?
37013715 }
3716+ /* Save handshake at the start */
3717+ memcpy (peer -> handshake_params -> reassemble_buf -> data , data ,
3718+ DTLS_HS_LENGTH );
37023719 } else {
3703- /* Not first fragment, skip over handshake header */
3704- data += sizeof (dtls_handshake_header_t );
3720+ /* Subsequent fragment */
3721+ if (memcmp (peer -> handshake_params -> reassemble_buf -> data , data ,
3722+ offsetof(dtls_handshake_header_t , fragment_offset )) != 0 ) {
3723+ /* Not a continuation fragment - msg_type+length+message_seq mismatch */
3724+ dtls_warn ("fragment does not match fragment #0\n" );
3725+ return dtls_alert_fatal_create (DTLS_ALERT_HANDSHAKE_FAILURE ); // TODO: Is this the correct alert?
3726+ }
3727+ if (peer -> handshake_params -> reassemble_buf -> last_offset !=
3728+ fragment_offset ) {
3729+ dtls_warn ("Received fragment out of order\n" );
3730+ return dtls_alert_fatal_create (DTLS_ALERT_HANDSHAKE_FAILURE ); // TODO: Is this the correct alert?
3731+ }
37053732 }
37063733
3707- /* Check if we have fragment buffer, (possibly earlier fragments) and offset is consecutive */
3708- if (peer -> handshake_params -> reassemble_buf == NULL ||
3709- peer -> handshake_params -> reassemble_buf -> last_offset != fragment_offset ){
3710- dtls_warn ("Received fragment out of order\n" );
3711- return dtls_alert_fatal_create (DTLS_ALERT_HANDSHAKE_FAILURE ); // TODO: Is this the correct alert?
3734+ if (fragment_length > data_length - DTLS_HS_LENGTH ) {
3735+ dtls_warn ("insufficient data provided for fragment\n" );
3736+ return dtls_alert_fatal_create (DTLS_ALERT_RECORD_OVERFLOW ); // TODO: Is this the correct alert?
37123737 }
3738+
37133739 /* Looks good: copy fragment in buffer */
3714- dtls_debug ("copying fragment to buffer: offset (%zu), length (%zu).\n" , fragment_offset ,
3715- fragment_length );
3716- memcpy (peer -> handshake_params -> reassemble_buf -> data + fragment_offset + (fragment_offset != 0 ? sizeof (dtls_handshake_header_t ) : 0 ),
3717- data , (size_t )fragment_length + (fragment_offset == 0 ? sizeof (dtls_handshake_header_t ) : 0 ));
3740+ dtls_debug ("copying fragment to buffer: offset (%zu), length (%zu),"
3741+ " handshake length (%zu).\n" , fragment_offset , fragment_length ,
3742+ hs_size );
3743+
3744+ memcpy (peer -> handshake_params -> reassemble_buf -> data +
3745+ DTLS_HS_LENGTH + fragment_offset ,
3746+ data + DTLS_HS_LENGTH , fragment_length );
37183747 peer -> handshake_params -> reassemble_buf -> last_offset = fragment_offset + fragment_length ;
37193748
3720- if (peer -> handshake_params -> reassemble_buf -> last_offset < packet_length ){
3749+ if (peer -> handshake_params -> reassemble_buf -> last_offset < hs_size ){
37213750 dtls_debug ("waiting for next fragment\n" );
37223751 return DTLS_HS_FRAGMENTED ;
37233752 }
@@ -3726,16 +3755,18 @@ handle_handshake(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session,
37263755 dtls_debug ("last hs fragment received.\n" );
37273756 /* Last fragment received, packet reassembled */
37283757 data = peer -> handshake_params -> reassemble_buf -> data ;
3729- /* packet_length is handshake payload size, data_length is record length (including header) */
3730- data_length = peer -> handshake_params -> reassemble_buf -> packet_length + DTLS_HS_LENGTH ;
3758+ data_length = peer -> handshake_params -> reassemble_buf -> data_length ;
37313759
3732- /* Rewrite header as if this package was received unfragmented. Needed for the hs_hash, see rfc6347#section-4.2.6 */
3760+ /*
3761+ * Rewrite header as if this package was received unfragmented.
3762+ * Needed for the hs_hash, see rfc6347#section-4.2.6
3763+ */
37333764 hs_header = DTLS_HANDSHAKE_HEADER (data );
3734- dtls_int_to_uint24 (hs_header -> fragment_offset , 0 ); //Should already be this way
3735- dtls_int_to_uint24 (hs_header -> length , peer -> handshake_params -> reassemble_buf -> packet_length );
3736- dtls_int_to_uint24 (hs_header -> fragment_length , peer -> handshake_params -> reassemble_buf -> packet_length );
3765+ dtls_int_to_uint24 (hs_header -> fragment_length , hs_size );
37373766
3738- dtls_debug_dump ("reassembled fragment header" , (const unsigned char * )hs_header , sizeof (dtls_handshake_header_t ));
3767+ dtls_debug_dump ("reassembled fragment header" ,
3768+ (const unsigned char * )hs_header ,
3769+ sizeof (dtls_handshake_header_t ));
37393770 }
37403771
37413772 dtls_debug ("received handshake packet of type: %s (%i)\n" ,
0 commit comments