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
pull/16497/head
Shivani Bhardwaj 3 weeks ago committed by Victor Julien
parent f87b8e64a5
commit bea218e7b1

@ -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);

@ -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;
/**

Loading…
Cancel
Save