[ssl_sni_parser] debugging, fix parser bug (wrong shift)

personal/stbuehler/wip
Stefan Bühler 9 years ago
parent 85fc9dbb6d
commit b9fadd3db3
  1. 6
      src/modules/gnutls_filter.c
  2. 56
      src/modules/ssl_sni_parser.h

@ -238,7 +238,11 @@ static void do_handle_error(liGnuTLSFilter *f, const char *gnutlsfunc, int r, gb
if (gnutls_error_is_fatal(r)) {
_ERROR(f->srv, f->wrk, f->log_context, "%s (%s): %s", gnutlsfunc,
gnutls_strerror_name(r), gnutls_strerror(r));
f_close_with_alert(f, r);
if (f->initial_handshaked_finished) {
f_close_with_alert(f, r);
} else {
f_abort_gnutls(f);
}
} else {
_ERROR(f->srv, f->wrk, f->log_context, "%s non fatal (%s): %s", gnutlsfunc,
gnutls_strerror_name(r), gnutls_strerror(r));

@ -126,10 +126,17 @@ INLINE void li_ssn_sni_stream_cb(liStream *stream, liStreamEvent event) {
}
}
#define SNI_PARSER_DEBUG 0
#if SNI_PARSER_DEBUG
# define PARSER_FAIL(...) do { fprintf(stderr, "ssl_sni_parse fail: " __VA_ARGS__); goto fail; } while (0)
#else
# define PARSER_FAIL(...) do { goto fail; } while (0)
#endif
INLINE liSSLSniParserResult li_ssl_sni_parse(liSSLSniParser *context, GString *server_name) {
guint8 *p = NULL, *global_pe = NULL;
if (context->finished) goto fail;
if (context->finished) return LI_SSL_SNI_NOT_FOUND;
li_chunk_parser_prepare(&context->ctx);
@ -148,7 +155,7 @@ INLINE liSSLSniParserResult li_ssl_sni_parse(liSSLSniParser *context, GString *s
li_chunk_parser_done(&context->ctx, 1);
context->record_type = *p++;
++context->record_state;
if (22 != context->record_type) goto fail; /* abort if not handshake */
if (22 != context->record_type) PARSER_FAIL("not a handshake record: %i\n", context->record_type);
continue;
case 1:
li_chunk_parser_done(&context->ctx, 1);
@ -169,7 +176,7 @@ INLINE liSSLSniParserResult li_ssl_sni_parse(liSSLSniParser *context, GString *s
li_chunk_parser_done(&context->ctx, 1);
context->record_remaining_length += (*p++);
context->record_state = 0;
if (context->record_remaining_length > ((1u << 14) + 2048u)) goto fail;
if (context->record_remaining_length > ((1u << 14) + 2048u)) PARSER_FAIL("record too long\n");
continue;
}
@ -190,7 +197,7 @@ INLINE liSSLSniParserResult li_ssl_sni_parse(liSSLSniParser *context, GString *s
if (context->handshake_remaining_length > 0) break;
context->handshake_type = *p++;
++context->handshake_state;
if (1 != context->handshake_type) goto fail; /* abort if not client_hello */
if (1 != context->handshake_type) PARSER_FAIL("handshake isn't client_hello\n");
continue;
case 1:
context->handshake_remaining_length = (*p++) << 16;
@ -212,10 +219,18 @@ INLINE liSSLSniParserResult li_ssl_sni_parse(liSSLSniParser *context, GString *s
guint take = MIN(context->handshake_remaining_length, (guint) (record_pe - p));
context->handshake_remaining_length -= take;
client_hello_pe = p + take;
if (0 == context->handshake_remaining_length) context->finished = TRUE; /* after this there is no point searching */
if (0 == context->handshake_remaining_length) {
context->finished = TRUE; /* after this there is no point searching */
#if SNI_PARSER_DEBUG
fprintf(stderr, "ssl_sni_parse: have complete client_hello\n");
#endif
}
}
while (p < client_hello_pe) {
#if SNI_PARSER_DEBUG
fprintf(stderr, "ssl_sni_parse client_hello: state %i, remaining: %i\n", context->client_hello_state, context->client_hello_remaining);
#endif
switch (context->client_hello_state) {
case 2: /* skip random */
case 4: /* skip session id */
@ -245,28 +260,32 @@ INLINE liSSLSniParserResult li_ssl_sni_parse(liSSLSniParser *context, GString *s
++context->client_hello_state;
continue;
case 5: /* cipher length upper byte */
context->client_hello_remaining = (*p++) << 16;
context->client_hello_remaining = (*p++) << 8;
++context->client_hello_state;
continue;
case 6: /* cipher length lower byte */
context->client_hello_remaining += (*p++);
++context->client_hello_state;
if (0 != context->client_hello_remaining % 2) goto fail;
if (0 != context->client_hello_remaining % 2) PARSER_FAIL("client_hello cipher length is odd\n");
continue;
case 8: /* compression methods length */
context->client_hello_remaining = (*p++);
++context->client_hello_state;
continue;
case 10: /* extensions length upper byte */
context->client_hello_remaining = (*p++) << 16;
context->client_hello_remaining = (*p++) << 8;
++context->client_hello_state;
continue;
case 11: /* extensions length lower byte */
context->client_hello_remaining += (*p++);
++context->client_hello_state;
#if SNI_PARSER_DEBUG
fprintf(stderr, "ssl_sni_parse client_hello: extensions length %i, can read %i\n", context->client_hello_remaining, (guint) (client_hello_pe - p));
#endif
/* extensions fill the record exactly if present */
if (context->handshake_remaining_length + (guint) (client_hello_pe - p) != context->client_hello_remaining) goto fail;
if (context->handshake_remaining_length + (guint) (client_hello_pe - p) != context->client_hello_remaining)
PARSER_FAIL("client_hello extensions don't fill the handshake\n");
context->extension_state = 0;
continue;
case 12: /* extensions data */
@ -278,7 +297,6 @@ INLINE liSSLSniParserResult li_ssl_sni_parse(liSSLSniParser *context, GString *s
guint take = MIN(context->client_hello_remaining, (guint) (client_hello_pe - p));
context->client_hello_remaining -= take;
assert(client_hello_pe == p + take);
if (0 == context->client_hello_remaining) context->finished = TRUE; /* after this there is no point searching */
}
while (p < client_hello_pe) {
@ -302,6 +320,9 @@ INLINE liSSLSniParserResult li_ssl_sni_parse(liSSLSniParser *context, GString *s
++context->extension_state;
continue;
case 4:
#if SNI_PARSER_DEBUG
fprintf(stderr, "ssl_sni_parse: extension type %i\n", context->extension_type);
#endif
if (0 == context->extension_type) break; /* parse this one: SNI */
{
/* ignore extension */
@ -317,7 +338,6 @@ INLINE liSSLSniParserResult li_ssl_sni_parse(liSSLSniParser *context, GString *s
guint take = MIN(context->extension_remaining, (guint) (client_hello_pe - p));
context->extension_remaining -= take;
extension_pe = p + take;
if (0 == context->extension_remaining) context->finished = TRUE; /* after this there is no point searching */
}
while (p < extension_pe) {
@ -330,7 +350,6 @@ INLINE liSSLSniParserResult li_ssl_sni_parse(liSSLSniParser *context, GString *s
continue;
case 2: /* type of first entry */
context->sni_type = (*p++);
if (0 != context->sni_type) goto fail; /* no spec how to parse unknown entries, can't skip them as we don't know their length */
++context->sni_state;
continue;
case 3:
@ -342,19 +361,23 @@ INLINE liSSLSniParserResult li_ssl_sni_parse(liSSLSniParser *context, GString *s
++context->sni_state;
continue;
case 5:
{
if (0 == context->sni_type) {
guint take = MIN(context->sni_hostname_remaining, (guint) (extension_pe - p));
g_string_append_len(server_name, (gchar*) p, take);
context->sni_hostname_remaining -= take;
p += take;
if (0 == context->sni_hostname_remaining) goto found_sni;
} else {
guint take = MIN(context->sni_hostname_remaining, (guint) (extension_pe - p));
context->sni_hostname_remaining -= take;
p += take;
}
}
}
} /* while (p >= client_hello_pe) -- extension subloop */
} /* while (p >= client_hello_pe) */
if (0 == context->handshake_remaining_length) goto fail; /* client_hello ended, no sni found */
if (0 == context->handshake_remaining_length) PARSER_FAIL("client_hello ended, no sni found\n");
} /* while (p >= record_pe) */
}
@ -373,8 +396,13 @@ found_sni:
return LI_SSL_SNI_FOUND;
fail:
#if SNI_PARSER_DEBUG
if (context->finished) fprintf(stderr, "ssl_sni_parse fail: sni not found in client_hello\n");
#endif
context->finished = TRUE;
return LI_SSL_SNI_NOT_FOUND;
}
#undef SNI_PARSER_DEBUG
#undef PARSER_FAIL
#endif

Loading…
Cancel
Save