Refactor and unify ClientHello parsers

Refactor and unify ssl_tls_clienthello_identify() and the earlier
ssl_tls_clienthello_parse_sni() into a single
ssl_tls_clienthello_parse() function that handles parsing ClientHello
messages for different purposes.  As a result, rename the debug knob
DEBUG_SNI_PARSER into DEBUG_CLIENTHELLO_PARSER.
pull/13/head
Daniel Roethlisberger 9 years ago
parent 6671a82aed
commit 74f62c3e5e

@ -65,8 +65,8 @@ DEBUG_CFLAGS?= -g
# Define to add SSL session cache debugging; dump all sessions in debug mode.
#FEATURES+= -DDEBUG_SESSION_CACHE
# Define to add debugging of parsing the SNI from the SSL ClientHello.
#FEATURES+= -DDEBUG_SNI_PARSER
# Define to add debugging of sslsplit's own ClientHello message parser.
#FEATURES+= -DDEBUG_CLIENTHELLO_PARSER
# Define to add thread debugging; dump thread state when choosing a thread.
#FEATURES+= -DDEBUG_THREAD

@ -1516,13 +1516,14 @@ pxy_conn_check_and_upgrade(pxy_conn_ctx_t *ctx)
{
struct evbuffer *inbuf;
struct evbuffer_iovec vec_out[1];
const unsigned char *chello;
if (OPTS_DEBUG(ctx->opts)) {
log_dbg_printf("Checking for a client hello\n");
}
/* peek the buffer */
inbuf = bufferevent_get_input(ctx->src.bev);
if(evbuffer_peek(inbuf, 1024, 0, vec_out, 1)) {
if(ssl_tls_clienthello_identify(vec_out->iov_base, &(vec_out->iov_len))) {
if (evbuffer_peek(inbuf, 1024, 0, vec_out, 1)) {
if (ssl_tls_clienthello_parse(vec_out[0].iov_base, vec_out[0].iov_len, 0, &chello, &ctx->sni) == 0) {
if (OPTS_DEBUG(ctx->opts)) {
log_dbg_printf("Found a clienthello in midstream\n");
}
@ -2208,10 +2209,12 @@ pxy_fd_readcb(MAYBE_UNUSED evutil_socket_t fd, UNUSED short what, void *arg)
pxy_conn_ctx_t *ctx = arg;
#ifndef OPENSSL_NO_TLSEXT
/* for SSL, peek clientHello and parse SNI from it */
/* for SSL, peek ClientHello and parse SNI from it */
if (ctx->spec->ssl && !ctx->passthrough /*&& ctx->ev*/) {
unsigned char buf[1024];
ssize_t n;
const unsigned char *chello;
int rv;
n = recv(fd, buf, sizeof(buf), MSG_PEEK);
if (n == -1) {
@ -2228,15 +2231,23 @@ pxy_fd_readcb(MAYBE_UNUSED evutil_socket_t fd, UNUSED short what, void *arg)
return;
}
ctx->sni = ssl_tls_clienthello_parse_sni(buf, &n);
rv = ssl_tls_clienthello_parse(buf, n, 0, &chello, &ctx->sni);
if ((rv == 1) && !chello) {
log_err_printf("Peeking did not yield a (truncated) "
"ClientHello message, "
"aborting connection\n");
evutil_closesocket(fd);
pxy_conn_ctx_free(ctx);
return;
}
if (OPTS_DEBUG(ctx->opts)) {
log_dbg_printf("SNI peek: [%s] [%s]\n",
ctx->sni ? ctx->sni : "n/a",
(!ctx->sni && (n == -1)) ?
((rv == 1) && chello) ?
"incomplete" : "complete");
}
if (!ctx->sni && (n == -1) && (ctx->sni_peek_retries++ < 50)) {
/* ssl_tls_clienthello_parse_sni indicates that we
if ((rv == 1) && chello && (ctx->sni_peek_retries++ < 50)) {
/* ssl_tls_clienthello_parse indicates that we
* should retry later when we have more data, and we
* haven't reached the maximum retry count yet.
* Reschedule this event as timeout-only event in

528
ssl.c

@ -103,9 +103,11 @@ ssl_openssl_version(void)
SSLeay_version(SSLEAY_VERSION),
SSLeay());
#ifndef OPENSSL_NO_TLSEXT
fprintf(stderr, "TLS Server Name Indication (SNI) supported\n");
fprintf(stderr, "OpenSSL has support for TLS extensions\n"
"TLS Server Name Indication (SNI) supported\n");
#else /* OPENSSL_NO_TLSEXT */
fprintf(stderr, "TLS Server Name Indication (SNI) not supported\n");
fprintf(stderr, "OpenSSL has no support for TLS extensions\n"
"TLS Server Name Indication (SNI) not supported\n");
#endif /* OPENSSL_NO_TLSEXT */
#ifdef OPENSSL_THREADS
#ifndef OPENSSL_NO_THREADID
@ -1669,25 +1671,43 @@ ssl_is_ocspreq(const unsigned char *buf, size_t sz)
return 1;
}
#ifndef OPENSSL_NO_TLSEXT
/*
* Ugly hack to manually parse the SNI TLS extension from a clientHello buf.
* This is needed because of limitations in the OpenSSL SNI API which only
* allows to read the indicated server name at the time when we have to
* provide the server certificate. It is not possible to asynchroniously
* read the indicated server name, wait for some event to happen, and then
* later to provide the server certificate to use and continue the handshake.
* Ugly hack to manually parse a clientHello message from a memory buffer.
* This is needed in order to be able to support SNI and STARTTLS.
*
* The OpenSSL SNI API only allows to read the indicated server name at the
* time when we have to provide the server certificate. OpenSSL does not
* allow to asynchroniously read the indicated server name, wait for some
* unrelated event to happen, and then later to provide the server certificate
* to use and continue the handshake. Therefore we resort to parsing the
* server name from the ClientHello manually before OpenSSL gets to work on it.
*
* For STARTTLS support in autossl mode, we need to peek into the buffer of
* received octets and decide whether we have something that resembles a
* (possibly incomplete) ClientHello message, so we can upgrade the connection
* to SSL automatically.
*
* This function takes a buffer containing (part of) a ClientHello message as
* seen on the network as input.
*
* Returns:
* 1 if buf does not contain a complete ClientHello message;
* *clienthello may point to the start of a truncated ClientHello message,
* indicating that the caller should retry later with more bytes available
* 0 if buf contains a complete ClientHello message;
* *clienthello will point to the start of the complete ClientHello message
*
* This function takes a buffer containing (part of) a clientHello message as
* seen on the network.
* If a servername pointer was supplied by the caller, and a server name
* extension was found and parsed, the server name is returned in *servername
* as a newly allocated string that must be freed by the caller. This may
* only occur for a return value of 0.
*
* If server name extension was found and parsed, returns server name buffer
* that must be free'd by the caller.
* If parsing failed for inconsistency reasons or if SNI TLS extension was
* not present in the clientHello, returns NULL.
* If not enough data was provided in buf, returns NULL and *sz is set to -1
* to indicate that a call to ssl_tls_clienthello_parse_sni() with more data
* in buf might succeed.
* If search is non-zero, then the buffer will be searched for a ClientHello
* message beginning at offsets >= 0, whereas if search is zero, only
* ClientHello messages starting at offset 0 will be considered.
*
* Note that this code currently only supports SSL 3.0 and TLS 1.0-1.2 and that
* it expects the ClientHello message to be unfragmented in a single record.
*
* References:
* RFC 2246: The TLS Protocol Version 1.0
@ -1697,155 +1717,206 @@ ssl_is_ocspreq(const unsigned char *buf, size_t sz)
* RFC 5246: The Transport Layer Security (TLS) Protocol Version 1.2
* RFC 6066: Transport Layer Security (TLS) Extensions: Extension Definitions
*/
char *
ssl_tls_clienthello_parse_sni(const unsigned char *buf, ssize_t *sz)
int
ssl_tls_clienthello_parse(const unsigned char *buf, ssize_t sz, int search,
const unsigned char **clienthello, char **servername)
{
#ifdef DEBUG_SNI_PARSER
#define DBG_printf(...) log_dbg_printf("SNI Parser: " __VA_ARGS__)
#else /* !DEBUG_SNI_PARSER */
#ifdef DEBUG_CLIENTHELLO_PARSER
#define DBG_printf(...) log_dbg_printf("ClientHello parser: " __VA_ARGS__)
/*#define DBG_printf(...) fprintf(stderr, "ClientHello parser: " __VA_ARGS__)*/
#else /* !DEBUG_CLIENTHELLO_PARSER */
#define DBG_printf(...)
#endif /* !DEBUG_SNI_PARSER */
#endif /* !DEBUG_CLIENTHELLO_PARSER */
const unsigned char *p = buf;
ssize_t n = *sz;
char *servername = NULL;
ssize_t n = sz;
char *sn = NULL;
*clienthello = NULL;
DBG_printf("parsing buffer of sz %zd\n", sz);
do {
if (*clienthello) {
/*
* Rewind after skipping an invalid ClientHello by
* restarting the search one byte after the beginning
* of the last candidate
*/
p = (*clienthello) + 1;
n = sz - (p - buf);
if (sn) {
free(sn);
sn = NULL;
}
}
DBG_printf("buffer length %zd\n", n);
if (search) {
/* Search for the beginning of a potential ClientHello */
while ((n > 0) && (*p != 22)) {
p++; n--;
}
if (n <= 0) {
/* Search completed without a match; reset
* clienthello to NULL to indicate to the
* caller that this buffer does not need to be
* retried */
DBG_printf("===> No match: rv 1, *clienthello NULL\n");
*clienthello = NULL;
return 1;
}
}
*clienthello = p;
DBG_printf("candidate at offset %td\n", p - buf);
DBG_printf("byte 0: %02x\n", *p);
/* +0 0x80 +2 0x01 SSLv2 clientHello;
* +0 0x22 +1 0x03 SSLv3/TLSv1.x clientHello */
if (*p != 22) { /* record type: handshake protocol */
/* this can only happen if search is 0 */
DBG_printf("===> No match: rv 1, *clienthello NULL\n");
*clienthello = NULL;
return 1;
}
p++; n--;
if (n < 1) {
*sz = -1;
goto out;
}
DBG_printf("byte 0: %02x\n", *p);
/* first byte 0x80, third byte 0x01 is SSLv2 clientHello;
* first byte 0x22, second byte 0x03 is SSLv3/TLSv1.x clientHello */
if (*p != 22) /* record type: handshake protocol */
goto out;
p++; n--;
if (n < 2) {
*sz = -1;
goto out;
}
DBG_printf("version: %02x %02x\n", p[0], p[1]);
if (p[0] != 3)
goto out;
p += 2; n -= 2;
if (n < 2) {
*sz = -1;
goto out;
}
DBG_printf("length: %02x %02x\n", p[0], p[1]);
#ifdef DEBUG_SNI_PARSER
ssize_t recordlen = p[1] + (p[0] << 8);
DBG_printf("recordlen=%zd\n", recordlen);
#endif /* DEBUG_SNI_PARSER */
p += 2; n -= 2;
if (n < 1) {
*sz = -1;
goto out;
}
DBG_printf("message type: %i\n", *p);
if (*p != 1) /* message type: ClientHello */
goto out;
p++; n--;
if (n < 3) {
*sz = -1;
goto out;
}
DBG_printf("message len: %02x %02x %02x\n", p[0], p[1], p[2]);
ssize_t msglen = p[2] + (p[1] << 8) + (p[0] << 16);
DBG_printf("msglen=%zd\n", msglen);
if (msglen < 4)
goto out;
p += 3; n -= 3;
if (n < msglen) {
*sz = -1;
goto out;
}
n = msglen; /* only parse first message */
if (n < 2)
goto out;
DBG_printf("clienthello version %02x %02x\n", p[0], p[1]);
if (p[0] != 3)
goto out;
p += 2; n -= 2;
if (n < 32)
goto out;
DBG_printf("clienthello random %02x %02x %02x %02x ...\n",
p[0], p[1], p[2], p[3]);
DBG_printf("compare localtime: %08x\n", (unsigned int)time(NULL));
p += 32; n -= 32;
if (n < 1)
goto out;
DBG_printf("clienthello sidlen %02x\n", *p);
ssize_t sidlen = *p; /* session id length, 0..32 */
p += 1; n -= 1;
if (n < sidlen)
goto out;
p += sidlen; n -= sidlen;
if (n < 2)
goto out;
DBG_printf("clienthello cipher suites length %02x %02x\n", p[0], p[1]);
ssize_t suiteslen = p[1] + (p[0] << 8);
p += 2; n -= 2;
if (n < suiteslen) {
DBG_printf("n < suiteslen (%zd, %zd)\n", n, suiteslen);
goto out;
}
p += suiteslen;
n -= suiteslen;
if (n < 1)
goto out;
DBG_printf("clienthello compress methods length %02x\n", *p);
ssize_t compslen = *p;
p++; n--;
if (n < compslen)
goto out;
p += compslen;
n -= compslen;
/* begin of extensions */
if (n < 2)
goto out;
DBG_printf("tlsexts length %02x %02x\n", p[0], p[1]);
ssize_t tlsextslen = p[1] + (p[0] << 8);
DBG_printf("tlsextslen %zd\n", tlsextslen);
p += 2;
n -= 2;
if (n < tlsextslen)
goto out;
n = tlsextslen; /* only parse extensions, ignore trailing bits */
while (n > 0) {
if (n < 4)
goto out;
DBG_printf("tlsext type %02x %02x len %02x %02x\n",
if (n < 2) {
DBG_printf("===> Truncated: rv 1, *clienthello set\n");
return 1;
}
DBG_printf("version: %02x %02x\n", p[0], p[1]);
/* This supports up to TLS 1.2 (0x03 0x03) and will need to be
* updated for TLS 1.3 once that is standardized and still
* compatible with this parser; remember to also update the
* inner version check below */
if (p[0] != 0x03 && p[1] > 0x03)
continue;
p += 2; n -= 2;
if (n < 2) {
DBG_printf("===> Truncated: rv 1, *clienthello set\n");
return 1;
}
DBG_printf("length: %02x %02x\n", p[0], p[1]);
ssize_t recordlen = p[1] + (p[0] << 8);
DBG_printf("recordlen=%zd\n", recordlen);
p += 2; n -= 2;
if (recordlen < 36) /* arbitrary size too small for a c-h */
continue;
if (n < recordlen) {
DBG_printf("n < recordlen: n=%zd\n", n);
DBG_printf("===> Truncated: rv 1, *clienthello set\n");
return 1;
}
/* from here we give up on a candidate if there is not enough
* data available in the buffer, because we already checked the
* availability of the whole record. */
if (n < 1)
continue;
DBG_printf("message type: %i\n", *p);
if (*p != 0x01) /* message type: ClientHello */
continue;
p++; n--;
if (n < 3)
continue;
DBG_printf("message len: %02x %02x %02x\n", p[0], p[1], p[2]);
ssize_t msglen = p[2] + (p[1] << 8) + (p[0] << 16);
DBG_printf("msglen=%zd\n", msglen);
p += 3; n -= 3;
if (msglen < 32) /* arbitrary size too small for a c-h */
continue;
if (msglen != recordlen - 4) {
DBG_printf("msglen != recordlen - 4\n");
continue;
}
if (n < msglen)
continue;
n = msglen; /* only parse first message */
if (n < 2)
continue;
DBG_printf("clienthello version %02x %02x\n", p[0], p[1]);
/* inner version check, see outer one above */
if (p[0] != 0x03 || p[1] > 0x03)
continue;
p += 2; n -= 2;
if (n < 32)
continue;
DBG_printf("clienthello random %02x %02x %02x %02x ...\n",
p[0], p[1], p[2], p[3]);
unsigned short exttype = p[1] + (p[0] << 8);
ssize_t extlen = p[3] + (p[2] << 8);
p += 4;
n -= 4;
if (n < extlen)
goto out;
switch (exttype) {
case 0:
{
DBG_printf("compare localtime: %08x\n",
(unsigned int)time(NULL));
p += 32; n -= 32;
if (n < 1)
continue;
DBG_printf("clienthello sidlen %02x\n", *p);
ssize_t sidlen = *p; /* session id length, 0..32 */
p += 1; n -= 1;
if (n < sidlen)
continue;
p += sidlen; n -= sidlen;
if (n < 2)
continue;
DBG_printf("clienthello cipher suites length %02x %02x\n",
p[0], p[1]);
ssize_t suiteslen = p[1] + (p[0] << 8);
p += 2; n -= 2;
if (n < suiteslen)
continue;
p += suiteslen;
n -= suiteslen;
if (n < 1)
continue;
DBG_printf("clienthello compress methods length %02x\n", *p);
ssize_t compslen = *p;
p++; n--;
if (n < compslen)
continue;
p += compslen;
n -= compslen;
/* begin of extensions */
if (n == 0) {
/* valid ClientHello without extensions */
DBG_printf("===> Match: rv 0, *clienthello set\n");
if (servername)
*servername = NULL;
return 0;
}
if (n < 2)
continue;
DBG_printf("tlsexts length %02x %02x\n", p[0], p[1]);
ssize_t tlsextslen = p[1] + (p[0] << 8);
DBG_printf("tlsextslen %zd\n", tlsextslen);
p += 2; n -= 2;
if (n < tlsextslen)
continue;
n = tlsextslen; /* only parse exts, ignore trailing bits */
while (n > 0) {
if (n < 4)
goto continue_search;
DBG_printf("tlsext type %02x %02x len %02x %02x\n",
p[0], p[1], p[2], p[3]);
unsigned short exttype = p[1] + (p[0] << 8);
ssize_t extlen = p[3] + (p[2] << 8);
p += 4; n -= 4;
if (n < extlen)
goto continue_search;
switch (exttype) {
case 0: {
ssize_t extn = extlen;
const unsigned char *extp = p;
if (extn < 2)
goto out;
goto continue_search;
DBG_printf("list length %02x %02x\n",
extp[0], extp[1]);
ssize_t namelistlen = extp[1] + (extp[0] << 8);
@ -1854,11 +1925,11 @@ ssl_tls_clienthello_parse_sni(const unsigned char *buf, ssize_t *sz)
extn -= 2;
if (namelistlen != extn)
goto out;
goto continue_search;
while (extn > 0) {
if (extn < 3)
goto out;
goto continue_search;
DBG_printf("ServerName type %02x"
" len %02x %02x\n",
extp[0], extp[1], extp[2]);
@ -1867,17 +1938,23 @@ ssl_tls_clienthello_parse_sni(const unsigned char *buf, ssize_t *sz)
extp += 3;
extn -= 3;
if (snlen > extn)
goto out;
goto continue_search;
if (snlen > TLSEXT_MAXLEN_host_name)
goto out;
if (sntype == 0) {
servername = malloc(snlen + 1);
memcpy(servername, extp, snlen);
servername[snlen] = '\0';
goto continue_search;
/*
* We copy the first name only.
* RFC 6066: "The ServerNameList MUST
* NOT contain more than one name of
* the same name_type."
*/
if (servername &&
sntype == 0 && sn == NULL) {
sn = malloc(snlen + 1);
memcpy(sn, extp, snlen);
sn[snlen] = '\0';
/* deliberately not checking
* for malformed hostnames
* containing invalid chars */
goto out;
}
extp += snlen;
extn -= snlen;
@ -1887,103 +1964,36 @@ ssl_tls_clienthello_parse_sni(const unsigned char *buf, ssize_t *sz)
default:
DBG_printf("skipped\n");
break;
}
p += extlen;
n -= extlen;
} /* while have more extensions */
#ifdef DEBUG_CLIENTHELLO_PARSER
if (n > 0) {
DBG_printf("unparsed next bytes %02x %02x %02x %02x\n",
p[0], p[1], p[2], p[3]);
}
p += extlen;
n -= extlen;
}
#endif /* DEBUG_CLIENTHELLO_PARSER */
DBG_printf("%zd bytes unparsed\n", n);
#ifdef DEBUG_SNI_PARSER
if (n > 0) {
DBG_printf("unparsed next bytes %02x %02x %02x %02x\n",
p[0], p[1], p[2], p[3]);
}
#endif /* DEBUG_SNI_PARSER */
out:
DBG_printf("%zd bytes unparsed\n", n);
return servername;
}
#endif /* !OPENSSL_NO_TLSEXT */
int
ssl_tls_clienthello_identify(const unsigned char *buf, ssize_t *sz)
{
#ifdef DEBUG_SNI_PARSER
#define DBG_printf(...) log_dbg_printf("SNI Parser: " __VA_ARGS__)
#else /* !DEBUG_SNI_PARSER */
#define DBG_printf(...)
#endif /* !DEBUG_SNI_PARSER */
const unsigned char *p = buf;
ssize_t n = *sz;
DBG_printf("buffer length %zd\n", n);
if (n < 1) {
*sz = -1;
goto out2;
}
DBG_printf("byte 0: %02x\n", *p);
/* first byte 0x80, third byte 0x01 is SSLv2 clientHello;
* first byte 0x22, second byte 0x03 is SSLv3/TLSv1.x clientHello */
if (*p != 22) /* record type: handshake protocol */
goto out2;
p++; n--;
if (n < 2) {
*sz = -1;
goto out2;
}
DBG_printf("version: %02x %02x\n", p[0], p[1]);
if (p[0] != 3)
goto out2;
p += 2; n -= 2;
if (n < 2) {
*sz = -1;
goto out2;
}
DBG_printf("length: %02x %02x\n", p[0], p[1]);
#ifdef DEBUG_SNI_PARSER
ssize_t recordlen = p[1] + (p[0] << 8);
DBG_printf("recordlen=%zd\n", recordlen);
#endif /* DEBUG_SNI_PARSER */
p += 2; n -= 2;
if (n < 1) {
*sz = -1;
goto out2;
}
DBG_printf("message type: %i\n", *p);
if (*p != 1) /* message type: ClientHello */
goto out2;
p++; n--;
if (n < 3) {
*sz = -1;
goto out2;
}
DBG_printf("message len: %02x %02x %02x\n", p[0], p[1], p[2]);
ssize_t msglen = p[2] + (p[1] << 8) + (p[0] << 16);
DBG_printf("msglen=%zd\n", msglen);
if (msglen < 4)
goto out2;
p += 3; n -= 3;
if (n < msglen) {
*sz = -1;
goto out2;
/* Valid ClientHello with or without server name */
DBG_printf("===> Match: rv 0, *clienthello set\n");
if (servername)
*servername = sn;
return 0;
continue_search:
;
} while (search && n > 0);
/* No valid ClientHello messages found, not even a truncated one */
DBG_printf("===> No match: rv 1, *clienthello NULL\n");
*clienthello = NULL;
if (sn) {
free(sn);
sn = NULL;
}
n = msglen; /* only parse first message */
if (n < 2)
goto out2;
DBG_printf("clienthello version %02x %02x\n", p[0], p[1]);
if (p[0] != 3)
goto out2;
p += 2; n -= 2;
return 1;
out2:
DBG_printf("%zd bytes unparsed\n", n);
return 0;
}
/* vim: set noet ft=c: */

15
ssl.h

@ -80,6 +80,12 @@
X509 * ssl_ssl_cert_get(SSL *);
#endif /* OpenSSL 0.9.8y or 1.0.0k or 1.0.1e */
#ifdef OPENSSL_NO_TLSEXT
#ifndef TLSEXT_MAXLEN_host_name
#define TLSEXT_MAXLEN_host_name 255
#endif /* !TLSEXT_MAXLEN_host_name */
#endif /* OPENSSL_NO_TLSEXT */
#if defined(SSL_OP_NO_SSLv2) && defined(WITH_SSLV2)
#define SSL2_S "ssl2 "
#else /* !(SSL_OP_NO_SSLv2 && WITH_SSLV2) */
@ -164,12 +170,9 @@ int ssl_session_is_valid(SSL_SESSION *) NONNULL(1);
int ssl_is_ocspreq(const unsigned char *, size_t) NONNULL(1) WUNRES;
#ifndef OPENSSL_NO_TLSEXT
char * ssl_tls_clienthello_parse_sni(const unsigned char *, ssize_t *)
NONNULL(1,2) MALLOC;
#endif /* !OPENSSL_NO_TLSEXT */
int ssl_tls_clienthello_identify(const unsigned char *, ssize_t *)
NONNULL(1,2);
int ssl_tls_clienthello_parse(const unsigned char *, ssize_t, int,
const unsigned char **, char **)
NONNULL(1,4) WUNRES;
int ssl_dnsname_match(const char *, size_t, const char *, size_t)
NONNULL(1,3) WUNRES;
char * ssl_wildcardify(const char *) NONNULL(1) MALLOC;

@ -237,7 +237,6 @@ START_TEST(ssl_dnsname_match_16)
}
END_TEST
#ifndef OPENSSL_NO_TLSEXT
static unsigned char clienthello01[] =
"\x80\x67\x01\x03\x00\x00\x4e\x00\x00\x00\x10\x01\x00\x80\x03\x00"
"\x80\x07\x00\xc0\x06\x00\x40\x02\x00\x80\x04\x00\x80\x00\x00\x39"
@ -312,97 +311,192 @@ static unsigned char clienthello05[] =
"\x01\x01";
/* TLS 1.2, SNI extension with hostname "daniel.roe.ch" */
START_TEST(ssl_tls_clienthello_parse_sni_01)
static unsigned char clienthello06[] =
"I will start TLS now: "
"\x16\x03\x03\x01\x7d\x01\x00\x01\x79\x03\x03\x4f\x7f\x27\xd0\x76"
"\x5f\xc1\x3b\xba\x73\xd5\x07\x8b\xd9\x79\xf9\x51\xd4\xce\x7d\x9a"
"\xdb\xdf\xf8\x4e\x95\x86\x38\x61\xdd\x84\x2a\x00\x00\xca\xc0\x30"
"\xc0\x2c\xc0\x28\xc0\x24\xc0\x14\xc0\x0a\xc0\x22\xc0\x21\x00\xa3"
"\x00\x9f\x00\x6b\x00\x6a\x00\x39\x00\x38\x00\x88\x00\x87\xc0\x19"
"\xc0\x20\x00\xa7\x00\x6d\x00\x3a\x00\x89\xc0\x32\xc0\x2e\xc0\x2a"
"\xc0\x26\xc0\x0f\xc0\x05\x00\x9d\x00\x3d\x00\x35\x00\x84\xc0\x12"
"\xc0\x08\xc0\x1c\xc0\x1b\x00\x16\x00\x13\xc0\x17\xc0\x1a\x00\x1b"
"\xc0\x0d\xc0\x03\x00\x0a\xc0\x2f\xc0\x2b\xc0\x27\xc0\x23\xc0\x13"
"\xc0\x09\xc0\x1f\xc0\x1e\x00\xa2\x00\x9e\x00\x67\x00\x40\x00\x33"
"\x00\x32\x00\x9a\x00\x99\x00\x45\x00\x44\xc0\x18\xc0\x1d\x00\xa6"
"\x00\x6c\x00\x34\x00\x9b\x00\x46\xc0\x31\xc0\x2d\xc0\x29\xc0\x25"
"\xc0\x0e\xc0\x04\x00\x9c\x00\x3c\x00\x2f\x00\x96\x00\x41\x00\x07"
"\xc0\x11\xc0\x07\xc0\x16\x00\x18\xc0\x0c\xc0\x02\x00\x05\x00\x04"
"\x00\x15\x00\x12\x00\x1a\x00\x09\x00\x14\x00\x11\x00\x19\x00\x08"
"\x00\x06\x00\x17\x00\x03\x00\xff\x02\x01\x00\x00\x85\x00\x00\x00"
"\x12\x00\x10\x00\x00\x0d\x64\x61\x6e\x69\x65\x6c\x2e\x72\x6f\x65"
"\x2e\x63\x68\x00\x0b\x00\x04\x03\x00\x01\x02\x00\x0a\x00\x34\x00"
"\x32\x00\x0e\x00\x0d\x00\x19\x00\x0b\x00\x0c\x00\x18\x00\x09\x00"
"\x0a\x00\x16\x00\x17\x00\x08\x00\x06\x00\x07\x00\x14\x00\x15\x00"
"\x04\x00\x05\x00\x12\x00\x13\x00\x01\x00\x02\x00\x03\x00\x0f\x00"
"\x10\x00\x11\x00\x23\x00\x00\x00\x0d\x00\x22\x00\x20\x06\x01\x06"
"\x02\x06\x03\x05\x01\x05\x02\x05\x03\x04\x01\x04\x02\x04\x03\x03"
"\x01\x03\x02\x03\x03\x02\x01\x02\x02\x02\x03\x01\x01\x00\x0f\x00"
"\x01\x01";
/* TLS 1.2, SNI extension with hostname "daniel.roe.ch" */
START_TEST(ssl_tls_clienthello_parse_01)
{
ssize_t sz;
char *sni;
int rv;
const unsigned char *ch = (void *)0xDEADBEEF;
char *sni = (void *)0xDEADBEEF;
sz = sizeof(clienthello01) - 1;
sni = ssl_tls_clienthello_parse_sni(clienthello01, &sz);
fail_unless(sni == NULL, "sni not null but should be");
fail_unless(sz != -1, "size is -1 but should not");
rv = ssl_tls_clienthello_parse(clienthello01,
sizeof(clienthello01) - 1,
0, &ch, &sni);
fail_unless(rv == 1, "rv not 1");
fail_unless(ch == NULL, "ch not NULL");
fail_unless(sni == (void*)0xDEADBEEF, "sni was modified");
}
END_TEST
START_TEST(ssl_tls_clienthello_parse_sni_02)
START_TEST(ssl_tls_clienthello_parse_02)
{
ssize_t sz;
int rv;
const unsigned char *ch;
char *sni;
sz = sizeof(clienthello02) - 1;
sni = ssl_tls_clienthello_parse_sni(clienthello02, &sz);
fail_unless(sni == NULL, "sni not null but should be");
fail_unless(sz != -1, "size is -1 but should not");
rv = ssl_tls_clienthello_parse(clienthello02,
sizeof(clienthello02) - 1,
0, &ch, &sni);
fail_unless(rv == 0, "rv not 0");
fail_unless(ch != NULL, "ch is NULL");
fail_unless(sni == NULL, "sni not NULL");
}
END_TEST
START_TEST(ssl_tls_clienthello_parse_sni_03)
START_TEST(ssl_tls_clienthello_parse_03)
{
ssize_t sz;
int rv;
const unsigned char *ch;
char *sni;
sz = sizeof(clienthello03) - 1;
sni = ssl_tls_clienthello_parse_sni(clienthello03, &sz);
rv = ssl_tls_clienthello_parse(clienthello03,
sizeof(clienthello03) - 1,
0, &ch, &sni);
fail_unless(rv == 0, "rv not 0");
fail_unless(ch != NULL, "ch is NULL");
fail_unless(sni && !strcmp(sni, "192.168.100.4"),
"sni not '192.168.100.4' but should be");
fail_unless(sz != -1, "size is -1 but should not");
}
END_TEST
START_TEST(ssl_tls_clienthello_parse_sni_04)
START_TEST(ssl_tls_clienthello_parse_04)
{
ssize_t sz;
int rv;
const unsigned char *ch;
char *sni;
sz = sizeof(clienthello04) - 1;
sni = ssl_tls_clienthello_parse_sni(clienthello04, &sz);
rv = ssl_tls_clienthello_parse(clienthello04,
sizeof(clienthello04) - 1,
0, &ch, &sni);
fail_unless(rv == 0, "rv not 0");
fail_unless(ch != NULL, "ch is NULL");
fail_unless(sni && !strcmp(sni, "kamesh.com"),
"sni not 'kamesh.com' but should be");
fail_unless(sz != -1, "size is -1 but should not");
}
END_TEST
START_TEST(ssl_tls_clienthello_parse_sni_05)
START_TEST(ssl_tls_clienthello_parse_05)
{
for (size_t i = 0; i < sizeof(clienthello04) - 1; i++) {
int rv;
const unsigned char *ch;
char *sni = (void*)0xDEADBEEF;
ssize_t sz;
char *sni;
sz = (ssize_t)i;
sni = ssl_tls_clienthello_parse_sni(clienthello04, &sz);
fail_unless(sni == NULL, "sni not null but should be");
fail_unless(sz == -1, "size is not -1 but should be");
rv = ssl_tls_clienthello_parse(clienthello04, sz, 0, &ch, &sni);
fail_unless(rv == 1, "rv not 1");
fail_unless(ch != NULL, "ch is NULL");
fail_unless(sni == (void*)0xDEADBEEF, "sni modified");
}
}
END_TEST
START_TEST(ssl_tls_clienthello_parse_sni_06)
START_TEST(ssl_tls_clienthello_parse_06)
{
ssize_t sz;
int rv;
const unsigned char *ch;
char *sni;
sz = sizeof(clienthello05) - 1;
sni = ssl_tls_clienthello_parse_sni(clienthello05, &sz);
rv = ssl_tls_clienthello_parse(clienthello05,
sizeof(clienthello05) - 1,
0, &ch, &sni);
fail_unless(rv == 0, "rv not 0");
fail_unless(ch != NULL, "ch is NULL");
fail_unless(sni && !strcmp(sni, "daniel.roe.ch"),
"sni not 'daniel.roe.ch' but should be");
fail_unless(sz != -1, "size is -1 but should not");
}
END_TEST
START_TEST(ssl_tls_clienthello_parse_sni_07)
START_TEST(ssl_tls_clienthello_parse_07)
{
for (size_t i = 0; i < sizeof(clienthello05) - 1; i++) {
int rv;
const unsigned char *ch;
char *sni = (void*)0xDEADBEEF;
ssize_t sz;
char *sni;
sz = (ssize_t)i;
sni = ssl_tls_clienthello_parse_sni(clienthello05, &sz);
fail_unless(sni == NULL, "sni not null but should be");
fail_unless(sz == -1, "size is not -1 but should be");
rv = ssl_tls_clienthello_parse(clienthello05, sz, 0, &ch, &sni);
fail_unless(rv == 1, "rv not 1");
fail_unless(ch != NULL, "ch is NULL");
fail_unless(sni == (void*)0xDEADBEEF, "sni modified");
}
}
END_TEST
#endif /* !OPENSSL_NO_TLSEXT */
START_TEST(ssl_tls_clienthello_parse_08)
{
int rv;
const unsigned char *ch;
char *sni = (void *)0xDEADBEEF;
rv = ssl_tls_clienthello_parse(clienthello06,
sizeof(clienthello06) - 1,
0, &ch, &sni);
fail_unless(rv == 1, "rv not 1");
fail_unless(ch == NULL, "ch not NULL");
fail_unless(sni == (void*)0xDEADBEEF, "sni modified");
}
END_TEST
START_TEST(ssl_tls_clienthello_parse_09)
{
int rv;
const unsigned char *ch;
char *sni;
rv = ssl_tls_clienthello_parse(clienthello06,
sizeof(clienthello06) - 1,
1, &ch, &sni);
fail_unless(rv == 0, "rv not 0");
fail_unless(ch != NULL, "ch is NULL");
fail_unless((ch - clienthello06) != 21, "ch does not point to start");
fail_unless(sni && !strcmp(sni, "daniel.roe.ch"),
"sni not 'daniel.roe.ch' but should be");
}
END_TEST
START_TEST(ssl_tls_clienthello_parse_10)
{
int rv;
const unsigned char *ch;
rv = ssl_tls_clienthello_parse(clienthello06,
sizeof(clienthello06) - 1,
1, &ch, NULL);
fail_unless(rv == 0, "rv not 0");
fail_unless(ch != NULL, "ch is NULL");
fail_unless((ch - clienthello06) != 21, "ch does not point to start");
}
END_TEST
START_TEST(ssl_key_identifier_sha1_01)
{
@ -614,17 +708,18 @@ ssl_suite(void)
tcase_add_test(tc, ssl_dnsname_match_16);
suite_add_tcase(s, tc);
#ifndef OPENSSL_NO_TLSEXT
tc = tcase_create("ssl_tls_clienthello_parse_sni");
tcase_add_test(tc, ssl_tls_clienthello_parse_sni_01);
tcase_add_test(tc, ssl_tls_clienthello_parse_sni_02);
tcase_add_test(tc, ssl_tls_clienthello_parse_sni_03);
tcase_add_test(tc, ssl_tls_clienthello_parse_sni_04);
tcase_add_test(tc, ssl_tls_clienthello_parse_sni_05);
tcase_add_test(tc, ssl_tls_clienthello_parse_sni_06);
tcase_add_test(tc, ssl_tls_clienthello_parse_sni_07);
tc = tcase_create("ssl_tls_clienthello_parse");
tcase_add_test(tc, ssl_tls_clienthello_parse_01);
tcase_add_test(tc, ssl_tls_clienthello_parse_02);
tcase_add_test(tc, ssl_tls_clienthello_parse_03);
tcase_add_test(tc, ssl_tls_clienthello_parse_04);
tcase_add_test(tc, ssl_tls_clienthello_parse_05);
tcase_add_test(tc, ssl_tls_clienthello_parse_06);
tcase_add_test(tc, ssl_tls_clienthello_parse_07);
tcase_add_test(tc, ssl_tls_clienthello_parse_08);
tcase_add_test(tc, ssl_tls_clienthello_parse_09);
tcase_add_test(tc, ssl_tls_clienthello_parse_10);
suite_add_tcase(s, tc);
#endif /* !OPENSSL_NO_TLSEXT */
tc = tcase_create("ssl_key_identifier_sha1");
tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown);

Loading…
Cancel
Save