|
|
@ -134,7 +134,7 @@ SslConfig ssl_config;
|
|
|
|
|
|
|
|
|
|
|
|
#define SSL_RECORD_MINIMUM_LENGTH 6
|
|
|
|
#define SSL_RECORD_MINIMUM_LENGTH 6
|
|
|
|
|
|
|
|
|
|
|
|
#define HAS_SPACE(n) ((uint32_t)((input) + (n) - (initial_input)) > (uint32_t)(input_len)) ? 0 : 1
|
|
|
|
#define HAS_SPACE(n) ((uint32_t)((*input) + (n) - (initial_input)) > (uint32_t)(input_len)) ? 0 : 1
|
|
|
|
|
|
|
|
|
|
|
|
static void SSLParserReset(SSLState *ssl_state)
|
|
|
|
static void SSLParserReset(SSLState *ssl_state)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -250,55 +250,103 @@ static void SSLSetTxDetectFlags(void *vtx, uint8_t dir, uint64_t flags)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int TLSDecodeHandshakeHello(SSLState *ssl_state, uint8_t *input,
|
|
|
|
static inline int TLSDecodeHSHelloVersion(SSLState *ssl_state, uint8_t **input,
|
|
|
|
uint32_t input_len)
|
|
|
|
const uint32_t input_len,
|
|
|
|
|
|
|
|
const uint8_t *initial_input)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
uint8_t *initial_input = input;
|
|
|
|
/* Skip version */
|
|
|
|
|
|
|
|
*input += SSLV3_CLIENT_HELLO_VERSION_LEN;
|
|
|
|
|
|
|
|
|
|
|
|
/* only parse the message if it is complete */
|
|
|
|
return 0;
|
|
|
|
if (input_len < ssl_state->curr_connp->message_length || input_len < 40)
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* skip version */
|
|
|
|
static inline int TLSDecodeHSHelloRandom(SSLState *ssl_state, uint8_t **input,
|
|
|
|
input += SSLV3_CLIENT_HELLO_VERSION_LEN;
|
|
|
|
const uint32_t input_len,
|
|
|
|
|
|
|
|
const uint8_t *initial_input)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
/* Skip random */
|
|
|
|
|
|
|
|
*input += SSLV3_CLIENT_HELLO_RANDOM_LEN;
|
|
|
|
|
|
|
|
|
|
|
|
/* skip random */
|
|
|
|
return 0;
|
|
|
|
input += SSLV3_CLIENT_HELLO_RANDOM_LEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!(HAS_SPACE(1)))
|
|
|
|
static inline int TLSDecodeHSHelloSessionID(SSLState *ssl_state,
|
|
|
|
goto invalid_length;
|
|
|
|
uint8_t **input,
|
|
|
|
|
|
|
|
const uint32_t input_len,
|
|
|
|
|
|
|
|
const uint8_t *initial_input)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!(HAS_SPACE(1))) {
|
|
|
|
|
|
|
|
SCLogDebug("TLS handshake invalid length");
|
|
|
|
|
|
|
|
SSLSetEvent(ssl_state,
|
|
|
|
|
|
|
|
TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t session_id_length = **input;
|
|
|
|
|
|
|
|
*input += 1;
|
|
|
|
|
|
|
|
|
|
|
|
/* skip session id */
|
|
|
|
|
|
|
|
uint8_t session_id_length = *(input++);
|
|
|
|
|
|
|
|
if (session_id_length != 0) {
|
|
|
|
if (session_id_length != 0) {
|
|
|
|
ssl_state->flags |= SSL_AL_FLAG_SSL_CLIENT_SESSION_ID;
|
|
|
|
ssl_state->flags |= SSL_AL_FLAG_SSL_CLIENT_SESSION_ID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
input += session_id_length;
|
|
|
|
*input += session_id_length;
|
|
|
|
|
|
|
|
|
|
|
|
if (!(HAS_SPACE(2)))
|
|
|
|
return 0;
|
|
|
|
goto invalid_length;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* skip cipher suites */
|
|
|
|
static inline int TLSDecodeHSHelloCipherSuites(SSLState *ssl_state,
|
|
|
|
uint16_t cipher_suites_length = input[0] << 8 | input[1];
|
|
|
|
uint8_t **input,
|
|
|
|
input += 2;
|
|
|
|
const uint32_t input_len,
|
|
|
|
|
|
|
|
const uint8_t *initial_input)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!(HAS_SPACE(2))) {
|
|
|
|
|
|
|
|
SCLogDebug("TLS handshake invalid length");
|
|
|
|
|
|
|
|
SSLSetEvent(ssl_state,
|
|
|
|
|
|
|
|
TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
input += cipher_suites_length;
|
|
|
|
uint16_t cipher_suites_length = **input << 8 | *(*input + 1);
|
|
|
|
|
|
|
|
*input += 2;
|
|
|
|
|
|
|
|
|
|
|
|
if (!(HAS_SPACE(1)))
|
|
|
|
/* Skip cipher suites */
|
|
|
|
goto invalid_length;
|
|
|
|
*input += cipher_suites_length;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline int TLSDecodeHSHelloCompressionMethods(SSLState *ssl_state,
|
|
|
|
|
|
|
|
uint8_t **input,
|
|
|
|
|
|
|
|
const uint32_t input_len,
|
|
|
|
|
|
|
|
const uint8_t *initial_input)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!(HAS_SPACE(1))) {
|
|
|
|
|
|
|
|
SCLogDebug("TLS handshake invalid length");
|
|
|
|
|
|
|
|
SSLSetEvent(ssl_state,
|
|
|
|
|
|
|
|
TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* skip compression methods */
|
|
|
|
/* Skip compression methods */
|
|
|
|
uint8_t compression_methods_length = *(input++);
|
|
|
|
uint8_t compression_methods_length = **input;
|
|
|
|
|
|
|
|
*input += 1;
|
|
|
|
|
|
|
|
|
|
|
|
input += compression_methods_length;
|
|
|
|
*input += compression_methods_length;
|
|
|
|
|
|
|
|
|
|
|
|
/* extensions are optional (RFC5246 section 7.4.1.2) */
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline int TLSDecodeHSHelloExtensions(SSLState *ssl_state,
|
|
|
|
|
|
|
|
uint8_t **input,
|
|
|
|
|
|
|
|
const uint32_t input_len,
|
|
|
|
|
|
|
|
const uint8_t *initial_input)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
/* Extensions are optional (RFC5246 section 7.4.1.2) */
|
|
|
|
if (!(HAS_SPACE(2)))
|
|
|
|
if (!(HAS_SPACE(2)))
|
|
|
|
goto end;
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t extensions_len = input[0] << 8 | input[1];
|
|
|
|
uint16_t extensions_len = **input << 8 | *(*input + 1);
|
|
|
|
input += 2;
|
|
|
|
*input += 2;
|
|
|
|
|
|
|
|
|
|
|
|
if (!(HAS_SPACE(extensions_len)))
|
|
|
|
if (!(HAS_SPACE(extensions_len)))
|
|
|
|
goto invalid_length;
|
|
|
|
goto invalid_length;
|
|
|
@ -309,20 +357,20 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state, uint8_t *input,
|
|
|
|
if (!(HAS_SPACE(2)))
|
|
|
|
if (!(HAS_SPACE(2)))
|
|
|
|
goto invalid_length;
|
|
|
|
goto invalid_length;
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t ext_type = input[0] << 8 | input[1];
|
|
|
|
uint16_t ext_type = **input << 8 | *(*input + 1);
|
|
|
|
input += 2;
|
|
|
|
*input += 2;
|
|
|
|
|
|
|
|
|
|
|
|
if (!(HAS_SPACE(2)))
|
|
|
|
if (!(HAS_SPACE(2)))
|
|
|
|
goto invalid_length;
|
|
|
|
goto invalid_length;
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t ext_len = input[0] << 8 | input[1];
|
|
|
|
uint16_t ext_len = **input << 8 | *(*input + 1);
|
|
|
|
input += 2;
|
|
|
|
*input += 2;
|
|
|
|
|
|
|
|
|
|
|
|
switch (ext_type) {
|
|
|
|
switch (ext_type) {
|
|
|
|
case SSL_EXTENSION_SNI:
|
|
|
|
case SSL_EXTENSION_SNI:
|
|
|
|
{
|
|
|
|
{
|
|
|
|
/* there must not be more than one extension of the same
|
|
|
|
/* There must not be more than one extension of the same
|
|
|
|
type (RFC5246 section 7.4.1.4) */
|
|
|
|
type (RFC5246 section 7.4.1.4). */
|
|
|
|
if (ssl_state->curr_connp->sni) {
|
|
|
|
if (ssl_state->curr_connp->sni) {
|
|
|
|
SCLogDebug("Multiple SNI extensions");
|
|
|
|
SCLogDebug("Multiple SNI extensions");
|
|
|
|
SSLSetEvent(ssl_state,
|
|
|
|
SSLSetEvent(ssl_state,
|
|
|
@ -330,16 +378,17 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state, uint8_t *input,
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* skip sni_list_length */
|
|
|
|
/* Skip sni_list_length */
|
|
|
|
input += 2;
|
|
|
|
*input += 2;
|
|
|
|
|
|
|
|
|
|
|
|
if (!(HAS_SPACE(1)))
|
|
|
|
if (!(HAS_SPACE(1)))
|
|
|
|
goto invalid_length;
|
|
|
|
goto invalid_length;
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t sni_type = *(input++);
|
|
|
|
uint8_t sni_type = **input;
|
|
|
|
|
|
|
|
*input += 1;
|
|
|
|
|
|
|
|
|
|
|
|
/* currently the only type allowed is host_name
|
|
|
|
/* Currently the only type allowed is host_name
|
|
|
|
(RFC6066 section 3) */
|
|
|
|
(RFC6066 section 3). */
|
|
|
|
if (sni_type != SSL_SNI_TYPE_HOST_NAME) {
|
|
|
|
if (sni_type != SSL_SNI_TYPE_HOST_NAME) {
|
|
|
|
SCLogDebug("Unknown SNI type");
|
|
|
|
SCLogDebug("Unknown SNI type");
|
|
|
|
SSLSetEvent(ssl_state,
|
|
|
|
SSLSetEvent(ssl_state,
|
|
|
@ -350,15 +399,15 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state, uint8_t *input,
|
|
|
|
if (!(HAS_SPACE(2)))
|
|
|
|
if (!(HAS_SPACE(2)))
|
|
|
|
goto invalid_length;
|
|
|
|
goto invalid_length;
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t sni_len = input[0] << 8 | input[1];
|
|
|
|
uint16_t sni_len = **input << 8 | *(*input + 1);
|
|
|
|
input += 2;
|
|
|
|
*input += 2;
|
|
|
|
|
|
|
|
|
|
|
|
if (!(HAS_SPACE(sni_len)))
|
|
|
|
if (!(HAS_SPACE(sni_len)))
|
|
|
|
goto invalid_length;
|
|
|
|
goto invalid_length;
|
|
|
|
|
|
|
|
|
|
|
|
/* host_name contains the fully qualified domain name,
|
|
|
|
/* host_name contains the fully qualified domain name,
|
|
|
|
and should therefore be limited by the maximum domain
|
|
|
|
and should therefore be limited by the maximum domain
|
|
|
|
name length */
|
|
|
|
name length. */
|
|
|
|
if (sni_len > 255) {
|
|
|
|
if (sni_len > 255) {
|
|
|
|
SCLogDebug("SNI length >255");
|
|
|
|
SCLogDebug("SNI length >255");
|
|
|
|
SSLSetEvent(ssl_state,
|
|
|
|
SSLSetEvent(ssl_state,
|
|
|
@ -370,17 +419,18 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state, uint8_t *input,
|
|
|
|
ssl_state->curr_connp->sni = SCMalloc(sni_strlen);
|
|
|
|
ssl_state->curr_connp->sni = SCMalloc(sni_strlen);
|
|
|
|
|
|
|
|
|
|
|
|
if (unlikely(ssl_state->curr_connp->sni == NULL))
|
|
|
|
if (unlikely(ssl_state->curr_connp->sni == NULL))
|
|
|
|
goto end;
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
|
|
memcpy(ssl_state->curr_connp->sni, input, sni_strlen - 1);
|
|
|
|
memcpy(ssl_state->curr_connp->sni, *input, sni_strlen - 1);
|
|
|
|
ssl_state->curr_connp->sni[sni_strlen-1] = 0;
|
|
|
|
ssl_state->curr_connp->sni[sni_strlen-1] = 0;
|
|
|
|
|
|
|
|
|
|
|
|
input += sni_len;
|
|
|
|
*input += sni_len;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
{
|
|
|
|
input += ext_len;
|
|
|
|
*input += ext_len;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -393,7 +443,48 @@ end:
|
|
|
|
invalid_length:
|
|
|
|
invalid_length:
|
|
|
|
SCLogDebug("TLS handshake invalid length");
|
|
|
|
SCLogDebug("TLS handshake invalid length");
|
|
|
|
SSLSetEvent(ssl_state,
|
|
|
|
SSLSetEvent(ssl_state,
|
|
|
|
TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH);
|
|
|
|
TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int TLSDecodeHandshakeHello(SSLState *ssl_state, uint8_t *input,
|
|
|
|
|
|
|
|
uint32_t input_len)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
uint8_t *initial_input = input;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Only parse the message if it is complete */
|
|
|
|
|
|
|
|
if (input_len < ssl_state->curr_connp->message_length || input_len < 40)
|
|
|
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rc = TLSDecodeHSHelloVersion(ssl_state, &input, input_len, initial_input);
|
|
|
|
|
|
|
|
if (rc != 0)
|
|
|
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rc = TLSDecodeHSHelloRandom(ssl_state, &input, input_len, initial_input);
|
|
|
|
|
|
|
|
if (rc != 0)
|
|
|
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rc = TLSDecodeHSHelloSessionID(ssl_state, &input, input_len, initial_input);
|
|
|
|
|
|
|
|
if (rc != 0)
|
|
|
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rc = TLSDecodeHSHelloCipherSuites(ssl_state, &input, input_len,
|
|
|
|
|
|
|
|
initial_input);
|
|
|
|
|
|
|
|
if (rc != 0)
|
|
|
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rc = TLSDecodeHSHelloCompressionMethods(ssl_state, &input, input_len,
|
|
|
|
|
|
|
|
initial_input);
|
|
|
|
|
|
|
|
if (rc != 0)
|
|
|
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rc = TLSDecodeHSHelloExtensions(ssl_state, &input, input_len,
|
|
|
|
|
|
|
|
initial_input);
|
|
|
|
|
|
|
|
if (rc != 0)
|
|
|
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|