From bea218e7b1dd8ffb09f250e62c096c6b3da749b4 Mon Sep 17 00:00:00 2001 From: Shivani Bhardwaj Date: Thu, 8 Oct 2026 11:15:36 +0530 Subject: [PATCH] ssl: handle fragmented handshake header So far the SSL parser returned an error if there were less than 4 bytes available for the handshake header. This meant that a fragmented handshake header could result in the SSL parser erroring out and thus disabling any further inspection for the protocol. The parser follows a multi-record parsing scheme which means that the fragment of the header may exist in the next record. Use internal buffering to assess and process the records just like the handshake buffer. Ticket: 9167 --- src/app-layer-ssl.c | 37 +++++++++++++++++++++++-------------- src/app-layer-ssl.h | 2 ++ 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 287be4a051..9f2f54af1b 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -1921,20 +1921,36 @@ static int SSLv3ParseHandshakeProtocol(SSLState *ssl_state, const uint8_t *input SCLogDebug("bytes_processed %u", ssl_state->curr_connp->bytes_processed); SCLogDebug("input %p input_len %u", input, input_len); - if (input_len < 4) { - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); - SCReturnInt(-1); + const uint8_t *hs_hdr = input; + if (input_len < 4 || ssl_state->curr_connp->hs_hdr_len > 0) { + DEBUG_VALIDATE_BUG_ON(ssl_state->curr_connp->hs_hdr_len >= 4); + uint32_t add = MIN(input_len, (uint32_t)(4 - ssl_state->curr_connp->hs_hdr_len)); + if (SafeMemcpy(ssl_state->curr_connp->hs_hdr, ssl_state->curr_connp->hs_hdr_len, 4, + input, 0, input_len, add) != 0) { + return -1; + } + ssl_state->curr_connp->hs_hdr_len += add; + input += add; + input_len -= add; + if (ssl_state->curr_connp->hs_hdr_len < 4) { + /* partial header received, not enough input len, return */ + SSLParserHSReset(ssl_state->curr_connp); + return (int)(input - initial_input); + } + hs_hdr = ssl_state->curr_connp->hs_hdr; + ssl_state->curr_connp->hs_hdr_len = 0; + } else { + input += 4; + input_len -= 4; } - ssl_state->curr_connp->handshake_type = input[0]; - ssl_state->curr_connp->message_length = input[1] << 16 | input[2] << 8 | input[3]; + ssl_state->curr_connp->handshake_type = hs_hdr[0]; + ssl_state->curr_connp->message_length = hs_hdr[1] << 16 | hs_hdr[2] << 8 | hs_hdr[3]; /* the fragments of this message all belong to its phase */ SSLv3HandshakePhaseEnter(ssl_state, ssl_state->curr_connp->handshake_type); SCLogDebug("handshake_type %u message len %u input %p input_len %u", ssl_state->curr_connp->handshake_type, ssl_state->curr_connp->message_length, input, input_len); - input += 4; - input_len -= 4; const uint32_t record_len = ssl_state->curr_connp->message_length; /* see if we support this type. We check here to not use the fragment @@ -2754,13 +2770,6 @@ static struct SSLDecoderResult SSLv3Decode(uint8_t direction, SSLState *ssl_stat } } - if (ssl_state->curr_connp->record_length < 4) { - SSLParserReset(ssl_state); - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); - SCLogDebug("record len < 4 => %u", ssl_state->curr_connp->record_length); - return SSL_DECODER_ERROR(-1); - } - int retval = SSLv3ParseHandshakeProtocol(ssl_state, input + parsed, record_len, direction); SCLogDebug("retval %d", retval); diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index b8da3c6173..76f5fa83ea 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -253,6 +253,8 @@ typedef struct SSLStateConnp_ { uint32_t hs_buffer_message_size; uint32_t hs_buffer_size; /**< allocation size */ uint32_t hs_buffer_offset; /**< write offset */ + uint8_t hs_hdr[4]; /**< handshake header */ + uint8_t hs_hdr_len; /**< handshake header length */ } SSLStateConnp; /**