@@ -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,94 @@ 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_length + DTLS_HS_LENGTH != data_length ) {
3682+ dtls_warn ("Fragment size does not match packet size\n" );
3683+ return dtls_alert_fatal_create (DTLS_ALERT_HANDSHAKE_FAILURE );
3684+ }
3685+
3686+ if (fragment_offset + fragment_length > hs_size ) {
3687+ /* Fragment extension larger than handshake */
3688+ dtls_warn ("fragment_offset (%zu) + fragment_length (%zu) >"
3689+ " handshake length (%zu)\n" , fragment_offset ,
3690+ fragment_length , hs_size );
3691+ return dtls_alert_fatal_create (DTLS_ALERT_RECORD_OVERFLOW ); // TODO: Is this the correct alert?
3692+ }
3693+ else if (hs_size > fragment_length ) {
3694+
3695+ /* Handle fragmented packet */
3696+
3697+ if (!peer || !peer -> handshake_params ) {
3698+ /* This is the initial ClientHello - can't handle fragmented */
3699+ dtls_alert ("Cannot handle initial fragmented ClientHello\n" );
3700+ return dtls_alert_fatal_create (DTLS_ALERT_HANDSHAKE_FAILURE );
36853701 }
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?
3702+ dtls_debug ("received fragmented handshake packet: handshake length %zu,"
3703+ " fragment length %zu.\n" , hs_size , fragment_length );
3704+
3705+ if (DTLS_HS_LENGTH + hs_size > DTLS_MAX_BUF ) {
3706+ /* Reassembled handshake is larger than our buffer, drop with error */
3707+ dtls_warn ("reassembled packet (%zu) would be larger than buffer (%i)\n" ,
3708+ DTLS_HS_LENGTH + hs_size , DTLS_MAX_BUF );
3709+ return dtls_alert_fatal_create (DTLS_ALERT_RECORD_OVERFLOW ); // TODO: Is this the correct alert?
36903710 }
3691- /* Handle fragmented packet */
36923711
3693- /* First fragment */
3694- if ( fragment_offset == 0 && packet_length <= DTLS_MAX_BUF ){
3712+ if ( fragment_offset == 0 ) {
3713+ /* First fragment */
36953714 dtls_debug ("received first packet of fragmented.\n" );
36963715 dtls_free_reassemble_buffer (peer -> handshake_params );
36973716
36983717 /* 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?
3718+ if (!dtls_init_reassemble_buffer (peer -> handshake_params , hs_size )) {
3719+ return dtls_alert_fatal_create (DTLS_ALERT_RECORD_OVERFLOW ); // TODO: Is this the correct alert?
37013720 }
3721+ /* Save handshake at the start */
3722+ memcpy (peer -> handshake_params -> reassemble_buf -> data , data ,
3723+ DTLS_HS_LENGTH );
37023724 } else {
3703- /* Not first fragment, skip over handshake header */
3704- data += sizeof (dtls_handshake_header_t );
3725+ /* Subsequent fragment */
3726+ if (memcmp (peer -> handshake_params -> reassemble_buf -> data , data ,
3727+ offsetof(dtls_handshake_header_t , fragment_offset )) != 0 ) {
3728+ /* Not a continuation fragment - msg_type+length+message_seq mismatch */
3729+ dtls_warn ("fragment does not match fragment #0\n" );
3730+ return dtls_alert_fatal_create (DTLS_ALERT_HANDSHAKE_FAILURE ); // TODO: Is this the correct alert?
3731+ }
3732+ if (peer -> handshake_params -> reassemble_buf -> last_offset !=
3733+ fragment_offset ) {
3734+ dtls_warn ("Received fragment out of order\n" );
3735+ return dtls_alert_fatal_create (DTLS_ALERT_HANDSHAKE_FAILURE ); // TODO: Is this the correct alert?
3736+ }
37053737 }
37063738
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?
3739+ if (fragment_length > data_length - DTLS_HS_LENGTH ) {
3740+ dtls_warn ("insufficient data provided for fragment\n" );
3741+ return dtls_alert_fatal_create (DTLS_ALERT_RECORD_OVERFLOW ); // TODO: Is this the correct alert?
37123742 }
3743+
37133744 /* 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 ));
3745+ dtls_debug ("copying fragment to buffer: offset (%zu), length (%zu),"
3746+ " handshake length (%zu).\n" , fragment_offset , fragment_length ,
3747+ hs_size );
3748+
3749+ memcpy (peer -> handshake_params -> reassemble_buf -> data +
3750+ DTLS_HS_LENGTH + fragment_offset ,
3751+ data + DTLS_HS_LENGTH , fragment_length );
37183752 peer -> handshake_params -> reassemble_buf -> last_offset = fragment_offset + fragment_length ;
37193753
3720- if (peer -> handshake_params -> reassemble_buf -> last_offset < packet_length ){
3754+ if (peer -> handshake_params -> reassemble_buf -> last_offset < hs_size ){
37213755 dtls_debug ("waiting for next fragment\n" );
37223756 return DTLS_HS_FRAGMENTED ;
37233757 }
@@ -3726,16 +3760,18 @@ handle_handshake(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session,
37263760 dtls_debug ("last hs fragment received.\n" );
37273761 /* Last fragment received, packet reassembled */
37283762 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 ;
3763+ data_length = peer -> handshake_params -> reassemble_buf -> data_length ;
37313764
3732- /* Rewrite header as if this package was received unfragmented. Needed for the hs_hash, see rfc6347#section-4.2.6 */
3765+ /*
3766+ * Rewrite header as if this package was received unfragmented.
3767+ * Needed for the hs_hash, see rfc6347#section-4.2.6
3768+ */
37333769 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 );
3770+ dtls_int_to_uint24 (hs_header -> fragment_length , hs_size );
37373771
3738- dtls_debug_dump ("reassembled fragment header" , (const unsigned char * )hs_header , sizeof (dtls_handshake_header_t ));
3772+ dtls_debug_dump ("reassembled fragment header" ,
3773+ (const unsigned char * )hs_header ,
3774+ sizeof (dtls_handshake_header_t ));
37393775 }
37403776
37413777 dtls_debug ("received handshake packet of type: %s (%i)\n" ,
0 commit comments