修改ssl_chello_parse相关函数,处理TLS Grease导致的客户端标识不准确,详见 https://security.stackexchange.com/questions/176951/google-chrome-weird-random-cipher-suite
This commit is contained in:
@@ -213,7 +213,6 @@ struct peek_client_hello_ctx
|
||||
{
|
||||
struct ssl_chello* chello;
|
||||
unsigned char sni_peek_retries; /* max 64 SNI parse retries */
|
||||
int parse_client_cipher;
|
||||
struct event * ev;
|
||||
struct event_base * evbase;
|
||||
void * logger;
|
||||
@@ -625,7 +624,7 @@ struct ssl_mgr * ssl_manager_init(const char * ini_profile, const char * section
|
||||
SSL_EX_DATA_IDX_SSLSTREAM = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
|
||||
MESA_load_profile_uint_def(ini_profile, section, "ssl_compression", &(mgr->sslcomp), 1);
|
||||
MESA_load_profile_uint_def(ini_profile, section, "no_ssl2", &(mgr->no_ssl2), 1);
|
||||
MESA_load_profile_uint_def(ini_profile, section, "no_ssl3", &(mgr->no_ssl3), 1);
|
||||
MESA_load_profile_uint_def(ini_profile, section, "no_ssl3", &(mgr->no_ssl3), 0);
|
||||
MESA_load_profile_uint_def(ini_profile, section, "no_tls10", &(mgr->no_tls10), 0);
|
||||
MESA_load_profile_uint_def(ini_profile, section, "no_tls11", &(mgr->no_tls11), 0);
|
||||
MESA_load_profile_uint_def(ini_profile, section, "no_tls12", &(mgr->no_tls12), 0);
|
||||
@@ -753,7 +752,7 @@ static void peek_client_hello_cb(evutil_socket_t fd, short what, void * arg)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
chello=ssl_chello_parse(buf, n, ctx->parse_client_cipher, &chello_status);
|
||||
chello=ssl_chello_parse(buf, n, &chello_status);
|
||||
switch(chello_status)
|
||||
{
|
||||
case CHELLO_PARSE_SUCCESS:
|
||||
@@ -813,13 +812,12 @@ failed:
|
||||
return;
|
||||
}
|
||||
|
||||
static void ssl_async_peek_client_hello(struct future * f, evutil_socket_t fd, int parse_cipher, struct event_base * evbase,
|
||||
static void ssl_async_peek_client_hello(struct future * f, evutil_socket_t fd, struct event_base * evbase,
|
||||
void * logger)
|
||||
{
|
||||
struct promise * p = future_to_promise(f);
|
||||
struct peek_client_hello_ctx * ctx = ALLOC(struct peek_client_hello_ctx, 1);
|
||||
ctx->ev = event_new(evbase, fd, EV_READ, peek_client_hello_cb, p);
|
||||
ctx->parse_client_cipher=parse_cipher;
|
||||
ctx->logger = logger;
|
||||
promise_set_ctx(p, (void *) ctx, peek_client_hello_ctx_free_cb);
|
||||
event_add(ctx->ev, NULL);
|
||||
@@ -848,14 +846,19 @@ static void upstream_ossl_init(struct ssl_stream* s_stream)
|
||||
sslctx = SSL_CTX_new(mgr->sslmethod());
|
||||
sslctx_set_opts(sslctx, mgr);
|
||||
int ret=0;
|
||||
|
||||
if(chello->cipher_suites!=NULL)
|
||||
char common_cipher[TFE_STRING_MAX]={0}, tls13_cipher[TFE_STRING_MAX]={0};
|
||||
if(chello->cipher_suites)
|
||||
{
|
||||
ssl_cipher_suites_to_name(chello->cipher_suites, chello->cipher_suites_len,
|
||||
common_cipher, sizeof(common_cipher), tls13_cipher, sizeof(tls13_cipher));
|
||||
}
|
||||
if(strlen(common_cipher)>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);
|
||||
ret=SSL_CTX_set_cipher_list(sslctx, common_cipher);
|
||||
if(ret==0)
|
||||
{
|
||||
TFE_LOG_ERROR(mgr->logger, "SSL_CTX_set_cipher_list %s failed.", chello->cipher_suites);
|
||||
TFE_LOG_ERROR(mgr->logger, "SSL_CTX_set_cipher_list %s failed.", common_cipher);
|
||||
SSL_CTX_set_cipher_list(sslctx, mgr->default_ciphers);
|
||||
}
|
||||
}
|
||||
@@ -863,7 +866,11 @@ static void upstream_ossl_init(struct ssl_stream* s_stream)
|
||||
{
|
||||
ret=SSL_CTX_set_cipher_list(sslctx, mgr->default_ciphers);
|
||||
}
|
||||
if(strlen(tls13_cipher)>0 && s_stream->ssl_max_version==TLS1_3_VERSION)
|
||||
{
|
||||
SSL_CTX_set_ciphersuites(sslctx, tls13_cipher);
|
||||
|
||||
}
|
||||
if (SSL_CTX_set_min_proto_version(sslctx, s_stream->ssl_min_version) == 0 ||
|
||||
SSL_CTX_set_max_proto_version(sslctx, s_stream->ssl_max_version) == 0)
|
||||
{
|
||||
@@ -983,7 +990,8 @@ unsigned long ssl_stream_log_error(struct bufferevent * bev, enum tfe_conn_dir d
|
||||
/* Can happen for socket errs, ssl errs;
|
||||
* may happen for unclean ssl socket shutdowns. */
|
||||
sslerr = bufferevent_get_openssl_error(bev);
|
||||
switch(ERR_GET_REASON(sslerr))
|
||||
ret_sslerr=ERR_GET_REASON(sslerr);
|
||||
switch(ret_sslerr)
|
||||
{
|
||||
case SSL_R_INAPPROPRIATE_FALLBACK:
|
||||
if(dir==CONN_DIR_DOWNSTREAM) fs_id=SSL_DOWN_ERR_INAPPROPRIATE_FALLBACK;
|
||||
@@ -991,7 +999,11 @@ unsigned long ssl_stream_log_error(struct bufferevent * bev, enum tfe_conn_dir d
|
||||
case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
|
||||
if(dir==CONN_DIR_DOWNSTREAM) fs_id=SSL_DOWN_ERR_NO_CERT;
|
||||
break;
|
||||
case SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM:
|
||||
case SSL_R_UNSUPPORTED_PROTOCOL:
|
||||
case SSL_R_UNSUPPORTED_SSL_VERSION:
|
||||
case SSL_R_UNSUPPORTED_STATUS_TYPE:
|
||||
case SSL_R_NO_PROTOCOLS_AVAILABLE:
|
||||
if(dir==CONN_DIR_UPSTREAM) fs_id=SSL_UP_ERR_UNSUPPORT_PROTO;
|
||||
case SSL_R_NO_CIPHERS_AVAILABLE:
|
||||
if(dir==CONN_DIR_UPSTREAM) fs_id=SSL_UP_ERR_NO_CIPHER;
|
||||
@@ -1001,8 +1013,7 @@ unsigned long ssl_stream_log_error(struct bufferevent * bev, enum tfe_conn_dir d
|
||||
}
|
||||
if(fs_id>=0)
|
||||
{
|
||||
mgr->stat_val[fs_id]++;
|
||||
ret_sslerr=ERR_GET_REASON(sslerr);
|
||||
mgr->stat_val[fs_id]++;
|
||||
}
|
||||
if (!errno && !sslerr)
|
||||
{
|
||||
@@ -1306,7 +1317,7 @@ void ssl_async_upstream_create(struct future * f, struct ssl_mgr * mgr, evutil_s
|
||||
promise_set_ctx(p, ctx, wrap_ssl_connect_server_ctx_free);
|
||||
|
||||
ctx->f_peek_chello = future_create("peek_sni", peek_chello_on_succ, peek_chello_on_fail, p);
|
||||
ssl_async_peek_client_hello(ctx->f_peek_chello, fd_downstream, !mgr->no_mirror_client_cipher_suite, evbase, mgr->logger);
|
||||
ssl_async_peek_client_hello(ctx->f_peek_chello, fd_downstream, evbase, mgr->logger);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user