ssl_stream集成新的client hello解析模块。

This commit is contained in:
zhengchao
2018-09-14 18:43:28 +08:00
parent eb756779b3
commit 7c49a89755
8 changed files with 175 additions and 167 deletions

View File

@@ -70,7 +70,7 @@ struct ssl_mgr
unsigned int no_tls12;
CONST_SSL_METHOD * (* sslmethod)(void); //Parameter of SSL_CTX_new
int sslversion;
int ssl_min_version, ssl_max_version;
char ssl_session_context[8];
unsigned int cache_slots;
@@ -116,17 +116,10 @@ struct ssl_stream
struct __ssl_stream_debug _do_not_use;
};
struct ssl_chello
{
//client hello
int version;
char * sni;
char * cipher_suites;
};
struct peek_client_hello_ctx
{
struct ssl_chello chello;
struct ssl_chello* chello;
unsigned char sni_peek_retries; /* max 64 SNI parse retries */
struct event * ev;
struct event_base * evbase;
@@ -203,32 +196,10 @@ static void sslctx_set_opts(SSL_CTX * sslctx, struct ssl_mgr * mgr);
struct ssl_chello * ssl_peek_result_release_chello(future_result_t * result)
{
struct ssl_chello * p = (struct ssl_chello *) result, * copy = NULL;
copy = ALLOC(struct ssl_chello, 1);
if (p != NULL)
{
copy->sni = tfe_strdup(p->sni);
copy->cipher_suites = tfe_strdup(p->cipher_suites);
copy->version = p->version;
}
return copy;
}
void ssl_free_chello(struct ssl_chello * p)
{
if (p == NULL)
{
return;
}
free(p->sni);
p->sni = NULL;
free(p->cipher_suites);
p->cipher_suites = NULL;
free(p);
return;
struct peek_client_hello_ctx* ctx= (struct peek_client_hello_ctx*) result;
struct ssl_chello * p = ctx->chello;
ctx->chello=NULL;
return p;
}
struct ssl_stream * ssl_stream_new(struct ssl_mgr * mgr, evutil_socket_t fd, enum tfe_conn_dir dir,
@@ -270,8 +241,8 @@ static void ssl_stream_free(struct ssl_stream * s_stream)
break;
case CONN_DIR_UPSTREAM:
if (s_stream->client_hello != NULL)
{
ssl_free_chello(s_stream->client_hello);
{
ssl_chello_free(s_stream->client_hello);
s_stream->client_hello = NULL;
}
break;
@@ -369,10 +340,12 @@ struct ssl_mgr * ssl_manager_init(const char * ini_profile, const char * section
mgr->logger = logger;
mgr->ev_base_gc=ev_base_gc;
mgr->fs_handle=fs;
MESA_load_profile_string_def(ini_profile, section, "ssl_version", version_str, sizeof(version_str), "tls12");
mgr->sslversion = sslver_str2num(version_str);
if (mgr->sslversion < 0)
MESA_load_profile_string_def(ini_profile, section, "ssl_min_version", version_str, sizeof(version_str), "ssl3");
mgr->ssl_min_version = sslver_str2num(version_str);
MESA_load_profile_string_def(ini_profile, section, "ssl_max_version", version_str, sizeof(version_str), "tls12");
mgr->ssl_max_version = sslver_str2num(version_str);
if (mgr->ssl_min_version < 0)
{
TFE_LOG_ERROR(logger, "Unsupported SSL/TLS protocol %s", version_str);
goto error_out;
@@ -479,10 +452,11 @@ void peek_client_hello_ctx_free(struct peek_client_hello_ctx * _ctx)
{
event_free(_ctx->ev);
_ctx->ev = NULL;
free(_ctx->chello.sni);
_ctx->chello.sni = NULL;
free(_ctx->chello.cipher_suites);
_ctx->chello.cipher_suites = NULL;
if(_ctx->chello!=NULL)
{
ssl_chello_free(_ctx->chello);
_ctx->chello=NULL;
}
free(_ctx);
}
@@ -497,11 +471,11 @@ static void peek_client_hello_cb(evutil_socket_t fd, short what, void * arg)
struct promise * promise = (struct promise *) arg;
//use promise_get_ctx instead of promise_dettach_ctx for try more times.
struct peek_client_hello_ctx * ctx = (struct peek_client_hello_ctx *) promise_get_ctx(promise);
enum chello_parse_result chello_status=CHELLO_PARSE_INVALID_FORMAT;
struct ssl_chello* chello=NULL;
const char * reason = NULL;
unsigned char buf[1024];
unsigned char buf[2048];
ssize_t n = 0;
const unsigned char * chello = NULL;
int rv = 0;
n = recv(fd, buf, sizeof(buf), MSG_PEEK);
if (n == -1)
@@ -515,49 +489,57 @@ static void peek_client_hello_cb(evutil_socket_t fd, short what, void * arg)
goto failed;
}
//todo: parse version and cipher suites.
//or we should use sni proxy instead? https://github.com/dlundquist/sniproxy/blob/master/src/tls.c
rv = ssl_tls_clienthello_parse(buf, n, 0, &chello, &(ctx->chello.sni));
if (rv == 0)
chello=ssl_chello_parse(buf,n, &chello_status);
switch(chello_status)
{
promise_dettach_ctx(promise);
promise_success(promise, &(ctx->chello));
peek_client_hello_ctx_free(ctx);
}
else
{
if (!chello)
case CHELLO_PARSE_SUCCESS:
{
promise_dettach_ctx(promise);
ctx->chello=chello;
promise_success(promise, ctx);
peek_client_hello_ctx_free(ctx);
break;
}
case CHELLO_PARSE_NOT_ENOUGH_BUFF:
{
ssl_chello_free(chello);
chello=NULL;
if (ctx->sni_peek_retries++ > MAX_NET_RETRIES)
{
TFE_LOG_ERROR(ctx->logger, "Peek failed due to too many retries\n");
reason = "too many peek retries";
goto failed;
}
/* 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
* order to prevent busy looping over the read event.
* Because we only peeked at the pending bytes and
* never actually read them, fd is still ready for
* reading now. We use 25 * 0.2 s = 5 s timeout. */
struct timeval retry_delay = {0, 100};
event_free(ctx->ev);
ctx->ev = event_new(ctx->evbase, fd, 0, peek_client_hello_cb, promise);
assert(ctx->ev != NULL);
event_add(ctx->ev, &retry_delay);
break;
}
case CHELLO_PARSE_INVALID_FORMAT:
{
ssl_chello_free(chello);
chello=NULL;
TFE_LOG_ERROR(ctx->logger,
"Peeking did not yield a (truncated) ClientHello message, aborting connection\n");
reason = "see no client hello";
goto failed;
break;
}
if (ctx->sni_peek_retries++ > MAX_NET_RETRIES)
{
TFE_LOG_ERROR(ctx->logger, "Peek failed due to too many retries\n");
reason = "too many peek retries";
goto failed;
}
/* 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
* order to prevent busy looping over the read event.
* Because we only peeked at the pending bytes and
* never actually read them, fd is still ready for
* reading now. We use 25 * 0.2 s = 5 s timeout. */
struct timeval retry_delay = {0, 100};
event_free(ctx->ev);
ctx->ev = event_new(ctx->evbase, fd, 0, peek_client_hello_cb, promise);
assert(ctx->ev != NULL);
event_add(ctx->ev, &retry_delay);
default:
assert(0);
}
return;
failed:
@@ -589,14 +571,28 @@ static SSL * upstream_ssl_create(struct ssl_mgr * mgr, const struct ssl_chello *
SSL_CTX * sslctx = NULL;
SSL * ssl = NULL;
SSL_SESSION * sess = NULL;
sslctx = SSL_CTX_new(mgr->sslmethod());
sslctx_set_opts(sslctx, mgr);
if (mgr->sslversion)
int ret=0;
if(chello->cipher_suites!=NULL)
{
if (SSL_CTX_set_min_proto_version(sslctx, chello->version) == 0 ||
SSL_CTX_set_max_proto_version(sslctx, chello->version) == 0)
//SSL_CTX_set_cipher_list() and SSL_set_cipher_list() return 1 if any cipher could be selected and 0 on complete failure.
ret=SSL_CTX_set_cipher_list(sslctx, chello->cipher_suites);
if(ret==0)
{
TFE_LOG_ERROR(mgr->logger, "SSL_CTX_set_cipher_list %s failed.", chello->cipher_suites);
SSL_CTX_set_cipher_list(sslctx, mgr->default_ciphers);
}
}
else
{
ret=SSL_CTX_set_cipher_list(sslctx, mgr->default_ciphers);
}
if (mgr->ssl_min_version)
{
if (SSL_CTX_set_min_proto_version(sslctx, MAX(chello->min_version.ossl_format, mgr->ssl_min_version)) == 0 ||
SSL_CTX_set_max_proto_version(sslctx, MIN(chello->max_version.ossl_format, mgr->ssl_max_version)) == 0)
{
SSL_CTX_free(sslctx);
return NULL;
@@ -623,7 +619,7 @@ static SSL * upstream_ssl_create(struct ssl_mgr * mgr, const struct ssl_chello *
struct sockaddr_storage addr;
socklen_t addrlen = sizeof(struct sockaddr_storage);
int ret = getpeername(fd, (struct sockaddr *) (&addr), &addrlen);
ret = getpeername(fd, (struct sockaddr *) (&addr), &addrlen);
assert(ret == 0);
/* session resuming based on remote endpoint address and port */
@@ -1004,7 +1000,6 @@ static void sslctx_set_opts(SSL_CTX * sslctx, struct ssl_mgr * mgr)
#endif /* SSL_OP_NO_COMPRESSION */
SSL_CTX_set_cipher_list(sslctx, mgr->default_ciphers);
}
/*
@@ -1019,12 +1014,13 @@ static SSL * downstream_ssl_create(struct ssl_mgr * mgr, struct keyring * crt)
SSL * ssl = NULL;
int ret = 0;
sslctx_set_opts(sslctx, mgr);
SSL_CTX_set_cipher_list(sslctx, mgr->default_ciphers);
//TFE's OPENSSL_VERSION_NUMBER >= 0x10100000L
if (mgr->sslversion)
if (mgr->ssl_min_version)
{
if (SSL_CTX_set_min_proto_version(sslctx, mgr->sslversion) == 0 ||
SSL_CTX_set_max_proto_version(sslctx, mgr->sslversion) == 0)
if (SSL_CTX_set_min_proto_version(sslctx, mgr->ssl_min_version) == 0 ||
SSL_CTX_set_max_proto_version(sslctx, mgr->ssl_min_version) == 0)
{
SSL_CTX_free(sslctx);
return NULL;