|
|
|
|
@ -262,9 +262,7 @@ static inline int SafeMemcpy(void *dst, size_t dst_offset, size_t dst_size,
|
|
|
|
|
#define SSLParserHSReset(connp) \
|
|
|
|
|
do { \
|
|
|
|
|
(connp)->handshake_type = 0; \
|
|
|
|
|
(connp)->hs_bytes_processed = 0; \
|
|
|
|
|
(connp)->message_length = 0; \
|
|
|
|
|
(connp)->message_start = 0; \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
#define SSLParserReset(state) \
|
|
|
|
|
@ -1390,17 +1388,9 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
ssl_state->curr_connp->hs_bytes_processed = 0;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
|
HaveEntireRecord(const SSLStateConnp *curr_connp, const uint32_t input_len)
|
|
|
|
|
{
|
|
|
|
|
return (curr_connp->bytes_processed + input_len) >=
|
|
|
|
|
(curr_connp->record_length + SSLV3_RECORD_HDR_LEN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_VALIDATION
|
|
|
|
|
static inline bool
|
|
|
|
|
RecordAlreadyProcessed(const SSLStateConnp *curr_connp)
|
|
|
|
|
@ -1424,10 +1414,33 @@ static inline int SSLv3ParseHandshakeTypeCertificate(SSLState *ssl_state,
|
|
|
|
|
SSLParserHSReset(ssl_state->curr_connp);
|
|
|
|
|
/* fall through to still consume the cert bytes */
|
|
|
|
|
}
|
|
|
|
|
ssl_state->curr_connp->bytes_processed += input_len;
|
|
|
|
|
return input_len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int SupportedHandshakeType(const uint8_t type)
|
|
|
|
|
{
|
|
|
|
|
switch (type) {
|
|
|
|
|
case SSLV3_HS_CLIENT_HELLO:
|
|
|
|
|
case SSLV3_HS_SERVER_HELLO:
|
|
|
|
|
case SSLV3_HS_SERVER_KEY_EXCHANGE:
|
|
|
|
|
case SSLV3_HS_CLIENT_KEY_EXCHANGE:
|
|
|
|
|
case SSLV3_HS_CERTIFICATE:
|
|
|
|
|
case SSLV3_HS_HELLO_REQUEST:
|
|
|
|
|
case SSLV3_HS_CERTIFICATE_REQUEST:
|
|
|
|
|
case SSLV3_HS_CERTIFICATE_VERIFY:
|
|
|
|
|
case SSLV3_HS_FINISHED:
|
|
|
|
|
case SSLV3_HS_CERTIFICATE_URL:
|
|
|
|
|
case SSLV3_HS_CERTIFICATE_STATUS:
|
|
|
|
|
case SSLV3_HS_NEW_SESSION_TICKET:
|
|
|
|
|
return true;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \retval parsed number of consumed bytes
|
|
|
|
|
* \retval < 0 error
|
|
|
|
|
@ -1447,28 +1460,17 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, const uint8_t *input,
|
|
|
|
|
case SSLV3_HS_CLIENT_HELLO:
|
|
|
|
|
ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_HELLO;
|
|
|
|
|
|
|
|
|
|
/* Only parse the message if it is complete */
|
|
|
|
|
if (input_len >= ssl_state->curr_connp->message_length &&
|
|
|
|
|
input_len >= 40) {
|
|
|
|
|
rc = TLSDecodeHandshakeHello(ssl_state, input, input_len);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = TLSDecodeHandshakeHello(ssl_state, input, input_len);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SSLV3_HS_SERVER_HELLO:
|
|
|
|
|
ssl_state->current_flags = SSL_AL_FLAG_STATE_SERVER_HELLO;
|
|
|
|
|
|
|
|
|
|
/* Only parse the message if it is complete */
|
|
|
|
|
if (input_len >= ssl_state->curr_connp->message_length &&
|
|
|
|
|
input_len >= 40) {
|
|
|
|
|
rc = TLSDecodeHandshakeHello(ssl_state, input,
|
|
|
|
|
ssl_state->curr_connp->message_length);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = TLSDecodeHandshakeHello(ssl_state, input, ssl_state->curr_connp->message_length);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SSLV3_HS_SERVER_KEY_EXCHANGE:
|
|
|
|
|
@ -1486,9 +1488,11 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, const uint8_t *input,
|
|
|
|
|
"direction!");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = SSLv3ParseHandshakeTypeCertificate(ssl_state,
|
|
|
|
|
initial_input, input_len);
|
|
|
|
|
return rc;
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SSLV3_HS_HELLO_REQUEST:
|
|
|
|
|
@ -1508,29 +1512,10 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, const uint8_t *input,
|
|
|
|
|
|
|
|
|
|
ssl_state->flags |= ssl_state->current_flags;
|
|
|
|
|
|
|
|
|
|
SCLogDebug("message: start %u length %u", ssl_state->curr_connp->message_start, ssl_state->curr_connp->message_length);
|
|
|
|
|
SCLogDebug("message: length %u", ssl_state->curr_connp->message_length);
|
|
|
|
|
SCLogDebug("input_len %u ssl_state->curr_connp->bytes_processed %u", input_len, ssl_state->curr_connp->bytes_processed);
|
|
|
|
|
|
|
|
|
|
uint32_t write_len = 0;
|
|
|
|
|
if (ssl_state->curr_connp->message_start + ssl_state->curr_connp->message_length <
|
|
|
|
|
ssl_state->curr_connp->bytes_processed + input_len) {
|
|
|
|
|
SCLogDebug("msg done");
|
|
|
|
|
|
|
|
|
|
// Safety check against integer underflow
|
|
|
|
|
DEBUG_VALIDATE_BUG_ON(
|
|
|
|
|
ssl_state->curr_connp->message_start + ssl_state->curr_connp->message_length <
|
|
|
|
|
ssl_state->curr_connp->bytes_processed);
|
|
|
|
|
write_len = (ssl_state->curr_connp->message_start + ssl_state->curr_connp->message_length) -
|
|
|
|
|
ssl_state->curr_connp->bytes_processed;
|
|
|
|
|
DEBUG_VALIDATE_BUG_ON(write_len > input_len);
|
|
|
|
|
ssl_state->curr_connp->bytes_processed += write_len;
|
|
|
|
|
SSLParserHSReset(ssl_state->curr_connp);
|
|
|
|
|
SCLogDebug("write_len %u", write_len);
|
|
|
|
|
return write_len;
|
|
|
|
|
} else {
|
|
|
|
|
ssl_state->curr_connp->bytes_processed += input_len;
|
|
|
|
|
return input_len;
|
|
|
|
|
}
|
|
|
|
|
return input_len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int SSLv3ParseHandshakeProtocol(SSLState *ssl_state, const uint8_t *input,
|
|
|
|
|
@ -1540,74 +1525,161 @@ static int SSLv3ParseHandshakeProtocol(SSLState *ssl_state, const uint8_t *input
|
|
|
|
|
|
|
|
|
|
if (input_len == 0 || ssl_state->curr_connp->bytes_processed ==
|
|
|
|
|
(ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) {
|
|
|
|
|
return 0;
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (input_len) {
|
|
|
|
|
SCLogDebug("bytes_processed %u", ssl_state->curr_connp->bytes_processed);
|
|
|
|
|
SCLogDebug("ssl_state->curr_connp->hs_bytes_processed %u input %p input_len %u",
|
|
|
|
|
ssl_state->curr_connp->hs_bytes_processed, input, input_len);
|
|
|
|
|
SCLogDebug("input_len %u", input_len);
|
|
|
|
|
|
|
|
|
|
if (ssl_state->curr_connp->hs_buffer != NULL) {
|
|
|
|
|
SCLogDebug("partial handshake record in place");
|
|
|
|
|
const uint32_t need = ssl_state->curr_connp->hs_buffer_message_size -
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_offset;
|
|
|
|
|
const uint32_t add = MIN(need, input_len);
|
|
|
|
|
|
|
|
|
|
/* grow buffer to next multiple of 4k that fits all data we have */
|
|
|
|
|
if (ssl_state->curr_connp->hs_buffer_offset + add >
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_size) {
|
|
|
|
|
const uint32_t avail = ssl_state->curr_connp->hs_buffer_offset + add;
|
|
|
|
|
const uint32_t new_size = avail + (4096 - (avail % 4096));
|
|
|
|
|
SCLogDebug("new_size %u, avail %u", new_size, avail);
|
|
|
|
|
void *ptr = SCRealloc(ssl_state->curr_connp->hs_buffer, new_size);
|
|
|
|
|
if (ptr == NULL)
|
|
|
|
|
return -1;
|
|
|
|
|
ssl_state->curr_connp->hs_buffer = ptr;
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_size = new_size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (ssl_state->curr_connp->hs_bytes_processed) {
|
|
|
|
|
case 0:
|
|
|
|
|
ssl_state->curr_connp->handshake_type = *(input++);
|
|
|
|
|
SCLogDebug("handshake_type %u", ssl_state->curr_connp->handshake_type);
|
|
|
|
|
ssl_state->curr_connp->bytes_processed++;
|
|
|
|
|
ssl_state->curr_connp->hs_bytes_processed++;
|
|
|
|
|
if (--input_len == 0 ||
|
|
|
|
|
ssl_state->curr_connp->bytes_processed ==
|
|
|
|
|
(ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) {
|
|
|
|
|
return (input - initial_input);
|
|
|
|
|
}
|
|
|
|
|
SCLogDebug("ssl_state->curr_connp->hs_buffer_offset %u "
|
|
|
|
|
"ssl_state->curr_connp->hs_buffer_size %u",
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_offset, ssl_state->curr_connp->hs_buffer_size);
|
|
|
|
|
SCLogDebug("to add %u total %u", add, ssl_state->curr_connp->hs_buffer_offset + add);
|
|
|
|
|
|
|
|
|
|
/* fall through */
|
|
|
|
|
case 1:
|
|
|
|
|
ssl_state->curr_connp->message_length = *(input++) << 16;
|
|
|
|
|
ssl_state->curr_connp->bytes_processed++;
|
|
|
|
|
ssl_state->curr_connp->hs_bytes_processed++;
|
|
|
|
|
if (--input_len == 0 ||
|
|
|
|
|
ssl_state->curr_connp->bytes_processed ==
|
|
|
|
|
(ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) {
|
|
|
|
|
return (input - initial_input);
|
|
|
|
|
}
|
|
|
|
|
if (SafeMemcpy(ssl_state->curr_connp->hs_buffer,
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_offset,
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_size, input, 0, add, add) != 0) {
|
|
|
|
|
SCLogDebug("copy failed");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_offset += add;
|
|
|
|
|
|
|
|
|
|
/* fall through */
|
|
|
|
|
case 2:
|
|
|
|
|
ssl_state->curr_connp->message_length |= *(input++) << 8;
|
|
|
|
|
ssl_state->curr_connp->bytes_processed++;
|
|
|
|
|
ssl_state->curr_connp->hs_bytes_processed++;
|
|
|
|
|
if (--input_len == 0 ||
|
|
|
|
|
ssl_state->curr_connp->bytes_processed ==
|
|
|
|
|
(ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) {
|
|
|
|
|
return (input - initial_input);
|
|
|
|
|
if (ssl_state->curr_connp->hs_buffer_message_size <=
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_offset + input_len) {
|
|
|
|
|
|
|
|
|
|
ssl_state->curr_connp->handshake_type =
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_message_type;
|
|
|
|
|
ssl_state->curr_connp->message_length =
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_message_size;
|
|
|
|
|
|
|
|
|
|
SCLogDebug("got all data now: handshake_type %u message_length %u",
|
|
|
|
|
ssl_state->curr_connp->handshake_type,
|
|
|
|
|
ssl_state->curr_connp->message_length);
|
|
|
|
|
|
|
|
|
|
int retval = SSLv3ParseHandshakeType(ssl_state, ssl_state->curr_connp->hs_buffer,
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_offset, direction);
|
|
|
|
|
if (retval < 0) {
|
|
|
|
|
SSLParserHSReset(ssl_state->curr_connp);
|
|
|
|
|
return (retval);
|
|
|
|
|
}
|
|
|
|
|
SCLogDebug("retval %d", retval);
|
|
|
|
|
|
|
|
|
|
/* data processed, reset buffer */
|
|
|
|
|
SCFree(ssl_state->curr_connp->hs_buffer);
|
|
|
|
|
ssl_state->curr_connp->hs_buffer = NULL;
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_size = 0;
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_message_size = 0;
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_message_type = 0;
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_offset = 0;
|
|
|
|
|
} else {
|
|
|
|
|
SCLogDebug("partial data");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* fall through */
|
|
|
|
|
case 3:
|
|
|
|
|
ssl_state->curr_connp->message_length |= *(input++);
|
|
|
|
|
SCLogDebug("message len %u", ssl_state->curr_connp->message_length);
|
|
|
|
|
ssl_state->curr_connp->bytes_processed++;
|
|
|
|
|
ssl_state->curr_connp->hs_bytes_processed++;
|
|
|
|
|
--input_len;
|
|
|
|
|
ssl_state->curr_connp->message_start = ssl_state->curr_connp->bytes_processed;
|
|
|
|
|
input += add;
|
|
|
|
|
input_len -= add;
|
|
|
|
|
SCLogDebug("input_len %u", input_len);
|
|
|
|
|
SSLParserHSReset(ssl_state->curr_connp);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* fall through */
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
SCLogDebug("message len %u input %p input_len %u", ssl_state->curr_connp->message_length,
|
|
|
|
|
input, input_len);
|
|
|
|
|
|
|
|
|
|
int retval = SSLv3ParseHandshakeType(ssl_state, input, input_len, direction);
|
|
|
|
|
if (retval < 0 || retval > (int)input_len) {
|
|
|
|
|
DEBUG_VALIDATE_BUG_ON(retval > (int)input_len);
|
|
|
|
|
return (retval);
|
|
|
|
|
ssl_state->curr_connp->handshake_type = input[0];
|
|
|
|
|
ssl_state->curr_connp->message_length = input[1] << 16 | input[2] << 8 | input[3];
|
|
|
|
|
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
|
|
|
|
|
* handling on things we don't support. */
|
|
|
|
|
const bool supported_type = SupportedHandshakeType(ssl_state->curr_connp->handshake_type);
|
|
|
|
|
SCLogDebug("supported_type %s handshake_type %u/%02x", supported_type ? "true" : "false",
|
|
|
|
|
ssl_state->curr_connp->handshake_type, ssl_state->curr_connp->handshake_type);
|
|
|
|
|
if (!supported_type) {
|
|
|
|
|
uint32_t avail_record_len = MIN(input_len, record_len);
|
|
|
|
|
input += avail_record_len;
|
|
|
|
|
input_len -= avail_record_len;
|
|
|
|
|
|
|
|
|
|
SSLParserHSReset(ssl_state->curr_connp);
|
|
|
|
|
SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HANDSHAKE_MESSAGE);
|
|
|
|
|
SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
SCLogDebug("retval %d input_len %u", retval, input_len);
|
|
|
|
|
input += retval;
|
|
|
|
|
input_len -= retval;
|
|
|
|
|
|
|
|
|
|
SSLParserHSReset(ssl_state->curr_connp);
|
|
|
|
|
}
|
|
|
|
|
/* if the message lenght exceeds our input_len, we have a tls fragment. */
|
|
|
|
|
if (record_len > input_len) {
|
|
|
|
|
const uint32_t avail = input_len;
|
|
|
|
|
const uint32_t size = avail + (4096 - (avail % 4096));
|
|
|
|
|
SCLogDebug("initial buffer size %u, based on input %u", size, avail);
|
|
|
|
|
ssl_state->curr_connp->hs_buffer = SCCalloc(1, size);
|
|
|
|
|
if (ssl_state->curr_connp->hs_buffer == NULL) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_size = size;
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_message_size = record_len;
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_message_type = ssl_state->curr_connp->handshake_type;
|
|
|
|
|
|
|
|
|
|
if (input_len > 0) {
|
|
|
|
|
if (SafeMemcpy(ssl_state->curr_connp->hs_buffer, 0,
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_size, input, 0, input_len,
|
|
|
|
|
input_len) != 0) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_offset = input_len;
|
|
|
|
|
}
|
|
|
|
|
SCLogDebug("opened record buffer %p size %u offset %u type %u msg_size %u",
|
|
|
|
|
ssl_state->curr_connp->hs_buffer, ssl_state->curr_connp->hs_buffer_size,
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_offset,
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_message_type,
|
|
|
|
|
ssl_state->curr_connp->hs_buffer_message_size);
|
|
|
|
|
input += input_len;
|
|
|
|
|
SSLParserHSReset(ssl_state->curr_connp);
|
|
|
|
|
return (input - initial_input);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
/* full record, parse it now */
|
|
|
|
|
int retval = SSLv3ParseHandshakeType(
|
|
|
|
|
ssl_state, input, ssl_state->curr_connp->message_length, direction);
|
|
|
|
|
if (retval < 0 || retval > (int)input_len) {
|
|
|
|
|
DEBUG_VALIDATE_BUG_ON(retval > (int)input_len);
|
|
|
|
|
return (retval);
|
|
|
|
|
}
|
|
|
|
|
SCLogDebug("retval %d input_len %u", retval, input_len);
|
|
|
|
|
input += retval;
|
|
|
|
|
input_len -= retval;
|
|
|
|
|
|
|
|
|
|
SSLParserHSReset(ssl_state->curr_connp);
|
|
|
|
|
}
|
|
|
|
|
SCLogDebug("input_len left %u", input_len);
|
|
|
|
|
}
|
|
|
|
|
return (input - initial_input);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -1934,9 +2006,6 @@ static struct SSLDecoderResult SSLv2Decode(uint8_t direction, SSLState *ssl_stat
|
|
|
|
|
SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER);
|
|
|
|
|
return SSL_DECODER_ERROR(-1);
|
|
|
|
|
}
|
|
|
|
|
// TODO review
|
|
|
|
|
// BUG_ON(ssl_state->curr_connp->record_lengths_length + 1 !=
|
|
|
|
|
// ssl_state->curr_connp->bytes_processed);
|
|
|
|
|
|
|
|
|
|
AppLayerFrameNewByPointer(ssl_state->f, &stream_slice, input,
|
|
|
|
|
ssl_state->curr_connp->record_lengths_length + ssl_state->curr_connp->record_length,
|
|
|
|
|
@ -2119,7 +2188,7 @@ static struct SSLDecoderResult SSLv3Decode(uint8_t direction, SSLState *ssl_stat
|
|
|
|
|
ssl_state->curr_connp->record_length + retval, direction, TLS_FRAME_PDU);
|
|
|
|
|
AppLayerFrameNewByPointer(
|
|
|
|
|
ssl_state->f, &stream_slice, input, SSLV3_RECORD_HDR_LEN, direction, TLS_FRAME_HDR);
|
|
|
|
|
parsed += retval;
|
|
|
|
|
parsed = retval;
|
|
|
|
|
record_len = MIN(input_len - parsed, ssl_state->curr_connp->record_length);
|
|
|
|
|
SCLogDebug("record_len %u (input_len %u, parsed %u, ssl_state->curr_connp->record_length %u)",
|
|
|
|
|
record_len, input_len, parsed, ssl_state->curr_connp->record_length);
|
|
|
|
|
@ -2132,6 +2201,7 @@ static struct SSLDecoderResult SSLv3Decode(uint8_t direction, SSLState *ssl_stat
|
|
|
|
|
SCLogDebug("record length %u processed %u got %u",
|
|
|
|
|
ssl_state->curr_connp->record_length, ssl_state->curr_connp->bytes_processed, record_len);
|
|
|
|
|
|
|
|
|
|
/* if we don't have the full record, we return incomplete */
|
|
|
|
|
if (ssl_state->curr_connp->record_length > input_len - parsed) {
|
|
|
|
|
/* no need to use incomplete api buffering for application
|
|
|
|
|
* records that we'll not use anyway. */
|
|
|
|
|
@ -2159,7 +2229,6 @@ static struct SSLDecoderResult SSLv3Decode(uint8_t direction, SSLState *ssl_stat
|
|
|
|
|
ssl_state->curr_connp->record_length, direction, TLS_FRAME_DATA);
|
|
|
|
|
|
|
|
|
|
switch (ssl_state->curr_connp->content_type) {
|
|
|
|
|
|
|
|
|
|
/* we don't need any data from these types */
|
|
|
|
|
case SSLV3_CHANGE_CIPHER_SPEC:
|
|
|
|
|
ssl_state->flags |= SSL_AL_FLAG_CHANGE_CIPHER_SPEC;
|
|
|
|
|
@ -2169,7 +2238,6 @@ static struct SSLDecoderResult SSLv3Decode(uint8_t direction, SSLState *ssl_stat
|
|
|
|
|
} else {
|
|
|
|
|
ssl_state->flags |= SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SSLV3_ALERT_PROTOCOL:
|
|
|
|
|
@ -2207,7 +2275,6 @@ static struct SSLDecoderResult SSLv3Decode(uint8_t direction, SSLState *ssl_stat
|
|
|
|
|
AppLayerParserStateSetFlag(pstate,
|
|
|
|
|
APP_LAYER_PARSER_BYPASS_READY);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SSLV3_HANDSHAKE_PROTOCOL: {
|
|
|
|
|
@ -2221,7 +2288,6 @@ static struct SSLDecoderResult SSLv3Decode(uint8_t direction, SSLState *ssl_stat
|
|
|
|
|
/* do nothing */
|
|
|
|
|
} else {
|
|
|
|
|
// if we started parsing this, we must stop
|
|
|
|
|
ssl_state->curr_connp->hs_bytes_processed = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -2235,6 +2301,7 @@ static struct SSLDecoderResult SSLv3Decode(uint8_t direction, SSLState *ssl_stat
|
|
|
|
|
|
|
|
|
|
int retval = SSLv3ParseHandshakeProtocol(ssl_state, input + parsed,
|
|
|
|
|
record_len, direction);
|
|
|
|
|
SCLogDebug("retval %d", retval);
|
|
|
|
|
if (retval < 0 || retval > (int)record_len) {
|
|
|
|
|
DEBUG_VALIDATE_BUG_ON(retval > (int)record_len);
|
|
|
|
|
SSLSetEvent(ssl_state,
|
|
|
|
|
@ -2244,27 +2311,8 @@ static struct SSLDecoderResult SSLv3Decode(uint8_t direction, SSLState *ssl_stat
|
|
|
|
|
SCLogDebug("SSLv3ParseHandshakeProtocol returned %d", retval);
|
|
|
|
|
return SSL_DECODER_ERROR(-1);
|
|
|
|
|
}
|
|
|
|
|
SCLogDebug("retval %d", retval);
|
|
|
|
|
|
|
|
|
|
parsed += retval;
|
|
|
|
|
record_len -= retval;
|
|
|
|
|
(void)record_len; /* for scan-build */
|
|
|
|
|
|
|
|
|
|
SCLogDebug("bytes_processed %u (record+hdr %u)", ssl_state->curr_connp->bytes_processed,
|
|
|
|
|
(ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN));
|
|
|
|
|
ValidateRecordState(ssl_state->curr_connp);
|
|
|
|
|
|
|
|
|
|
if (ssl_state->curr_connp->bytes_processed >=
|
|
|
|
|
ssl_state->curr_connp->record_length +
|
|
|
|
|
SSLV3_RECORD_HDR_LEN) {
|
|
|
|
|
SCLogDebug("record ready");
|
|
|
|
|
SSLParserReset(ssl_state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCLogDebug("trigger RAW! (post HS)");
|
|
|
|
|
AppLayerParserTriggerRawStreamReassembly(ssl_state->f,
|
|
|
|
|
direction == 0 ? STREAM_TOSERVER : STREAM_TOCLIENT);
|
|
|
|
|
return SSL_DECODER_OK(parsed);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SSLV3_HEARTBEAT_PROTOCOL: {
|
|
|
|
|
AppLayerFrameNewByPointer(ssl_state->f, &stream_slice, input + parsed,
|
|
|
|
|
@ -2285,35 +2333,21 @@ static struct SSLDecoderResult SSLv3Decode(uint8_t direction, SSLState *ssl_stat
|
|
|
|
|
return SSL_DECODER_ERROR(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (HaveEntireRecord(ssl_state->curr_connp, record_len)) {
|
|
|
|
|
DEBUG_VALIDATE_BUG_ON(((ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) <
|
|
|
|
|
ssl_state->curr_connp->bytes_processed));
|
|
|
|
|
|
|
|
|
|
if ((ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) <
|
|
|
|
|
ssl_state->curr_connp->bytes_processed) {
|
|
|
|
|
/* defensive checks. Something is wrong. */
|
|
|
|
|
SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD);
|
|
|
|
|
SCLogDebug("defensive checks. Something is wrong.");
|
|
|
|
|
return SSL_DECODER_ERROR(-1);
|
|
|
|
|
}
|
|
|
|
|
parsed += record_len;
|
|
|
|
|
ssl_state->curr_connp->bytes_processed += record_len;
|
|
|
|
|
|
|
|
|
|
if (ssl_state->curr_connp->bytes_processed >=
|
|
|
|
|
ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) {
|
|
|
|
|
SCLogDebug("record complete, trigger RAW");
|
|
|
|
|
AppLayerParserTriggerRawStreamReassembly(ssl_state->f,
|
|
|
|
|
direction == 0 ? STREAM_TOSERVER : STREAM_TOCLIENT);
|
|
|
|
|
|
|
|
|
|
/* looks like we have another record */
|
|
|
|
|
uint32_t diff = ssl_state->curr_connp->record_length +
|
|
|
|
|
SSLV3_RECORD_HDR_LEN - ssl_state->curr_connp->bytes_processed;
|
|
|
|
|
parsed += diff;
|
|
|
|
|
AppLayerParserTriggerRawStreamReassembly(
|
|
|
|
|
ssl_state->f, direction == 0 ? STREAM_TOSERVER : STREAM_TOCLIENT);
|
|
|
|
|
SSLParserReset(ssl_state);
|
|
|
|
|
ValidateRecordState(ssl_state->curr_connp);
|
|
|
|
|
return SSL_DECODER_OK(parsed);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
/* we still don't have the entire record for the one we are
|
|
|
|
|
currently parsing */
|
|
|
|
|
} else {
|
|
|
|
|
parsed += record_len;
|
|
|
|
|
ssl_state->curr_connp->bytes_processed += record_len;
|
|
|
|
|
ValidateRecordState(ssl_state->curr_connp);
|
|
|
|
|
return SSL_DECODER_OK(parsed);
|
|
|
|
|
}
|
|
|
|
|
@ -2393,8 +2427,8 @@ static AppLayerResult SSLDecode(Flow *f, uint8_t direction, void *alstate,
|
|
|
|
|
SCLogDebug("SSL/TLS version reset");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
SCLogDebug("record %u: bytes_processed %u, version %02X", counter,
|
|
|
|
|
ssl_state->curr_connp->bytes_processed, ssl_state->curr_connp->version);
|
|
|
|
|
SCLogDebug("record %u: bytes_processed %u, version %02X, input_len %u", counter,
|
|
|
|
|
ssl_state->curr_connp->bytes_processed, ssl_state->curr_connp->version, input_len);
|
|
|
|
|
|
|
|
|
|
if (ssl_state->curr_connp->version == SSL_VERSION_2) {
|
|
|
|
|
if (ssl_state->curr_connp->bytes_processed == 0) {
|
|
|
|
|
@ -2526,6 +2560,8 @@ static void SSLStateFree(void *p)
|
|
|
|
|
SCFree(ssl_state->client_connp.sni);
|
|
|
|
|
if (ssl_state->client_connp.session_id)
|
|
|
|
|
SCFree(ssl_state->client_connp.session_id);
|
|
|
|
|
if (ssl_state->client_connp.hs_buffer)
|
|
|
|
|
SCFree(ssl_state->client_connp.hs_buffer);
|
|
|
|
|
|
|
|
|
|
if (ssl_state->server_connp.cert0_subject)
|
|
|
|
|
rs_cstring_free(ssl_state->server_connp.cert0_subject);
|
|
|
|
|
@ -2548,6 +2584,8 @@ static void SSLStateFree(void *p)
|
|
|
|
|
Ja3BufferFree(&ssl_state->server_connp.ja3_str);
|
|
|
|
|
if (ssl_state->server_connp.ja3_hash)
|
|
|
|
|
SCFree(ssl_state->server_connp.ja3_hash);
|
|
|
|
|
if (ssl_state->server_connp.hs_buffer)
|
|
|
|
|
SCFree(ssl_state->server_connp.hs_buffer);
|
|
|
|
|
|
|
|
|
|
AppLayerDecoderEventsFreeEvents(&ssl_state->tx_data.events);
|
|
|
|
|
|
|
|
|
|
@ -5096,7 +5134,6 @@ static int SSLParserTest25(void)
|
|
|
|
|
FAIL_IF_NULL(ssl_state);
|
|
|
|
|
|
|
|
|
|
FAIL_IF(ssl_state->client_connp.bytes_processed != 0);
|
|
|
|
|
FAIL_IF(ssl_state->client_connp.hs_bytes_processed != 0);
|
|
|
|
|
|
|
|
|
|
r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT,
|
|
|
|
|
server_hello_certificate_done,
|
|
|
|
|
@ -5104,7 +5141,6 @@ static int SSLParserTest25(void)
|
|
|
|
|
FAIL_IF(r != 0);
|
|
|
|
|
|
|
|
|
|
FAIL_IF(ssl_state->client_connp.bytes_processed != 0);
|
|
|
|
|
FAIL_IF(ssl_state->client_connp.hs_bytes_processed != 0);
|
|
|
|
|
|
|
|
|
|
r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER,
|
|
|
|
|
client_key_exchange_cipher_enc_hs,
|
|
|
|
|
|