bearssl: handshake fix, provide proper get_select_socks() implementation

- bring bearssl handshake times down from +200ms down to other TLS backends
- vtls: improve generic get_select_socks() implementation
- tests: provide Apache with a suitable ssl session cache

Closes #11675
This commit is contained in:
Stefan Eissing 2023-08-17 11:16:11 +02:00 committed by Daniel Stenberg
parent 57e81ff3db
commit 1bccee76c8
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
3 changed files with 72 additions and 19 deletions

View File

@ -587,6 +587,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
const bool verifyhost = conn_config->verifyhost;
CURLcode ret;
unsigned version_min, version_max;
int session_set = 0;
#ifdef ENABLE_IPV6
struct in6_addr addr;
#else
@ -594,6 +595,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
#endif
DEBUGASSERT(backend);
CURL_TRC_CF(data, cf, "connect_step1");
switch(conn_config->version) {
case CURL_SSLVERSION_SSLv2:
@ -631,6 +633,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
source.data = ca_info_blob->data;
source.len = ca_info_blob->len;
CURL_TRC_CF(data, cf, "connect_step1, load ca_info_blob");
ret = load_cafile(&source, &backend->anchors, &backend->anchors_len);
if(ret != CURLE_OK) {
failf(data, "error importing CA certificate blob");
@ -644,6 +647,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
source.data = ssl_cafile;
source.len = 0;
CURL_TRC_CF(data, cf, "connect_step1, load cafile");
ret = load_cafile(&source, &backend->anchors, &backend->anchors_len);
if(ret != CURLE_OK) {
failf(data, "error setting certificate verify locations."
@ -663,6 +667,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
if(conn_config->cipher_list) {
/* Override the ciphers as specified. For the default cipher list see the
BearSSL source code of br_ssl_client_init_full() */
CURL_TRC_CF(data, cf, "connect_step1, set ciphers");
ret = bearssl_set_selected_ciphers(data, &backend->ctx.eng,
conn_config->cipher_list);
if(ret)
@ -678,9 +683,11 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
if(ssl_config->primary.sessionid) {
void *session;
CURL_TRC_CF(data, cf, "connect_step1, check session cache");
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, &session, NULL)) {
br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
session_set = 1;
infof(data, "BearSSL: re-using session ID");
}
Curl_ssl_sessionid_unlock(data);
@ -718,6 +725,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
}
hostname = snihost;
CURL_TRC_CF(data, cf, "connect_step1, SNI set");
}
/* give application a chance to interfere with SSL set up. */
@ -732,7 +740,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
}
}
if(!br_ssl_client_reset(&backend->ctx, hostname, 1))
if(!br_ssl_client_reset(&backend->ctx, hostname, session_set))
return CURLE_FAILED_INIT;
backend->active = TRUE;
@ -741,6 +749,28 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
return CURLE_OK;
}
static int bearssl_get_select_socks(struct Curl_cfilter *cf,
struct Curl_easy *data,
curl_socket_t *socks)
{
struct ssl_connect_data *connssl = cf->ctx;
curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
if(sock == CURL_SOCKET_BAD)
return GETSOCK_BLANK;
else {
struct bearssl_ssl_backend_data *backend =
(struct bearssl_ssl_backend_data *)connssl->backend;
unsigned state = br_ssl_engine_current_state(&backend->ctx.eng);
if(state & BR_SSL_SENDREC) {
socks[0] = sock;
return GETSOCK_WRITESOCK(0);
}
}
socks[0] = sock;
return GETSOCK_READSOCK(0);
}
static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
struct Curl_easy *data,
unsigned target)
@ -792,6 +822,7 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
if(state & BR_SSL_SENDREC) {
buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len);
ret = Curl_conn_cf_send(cf->next, data, (char *)buf, len, &result);
CURL_TRC_CF(data, cf, "ssl_send(len=%zu) -> %zd, %d", len, ret, result);
if(ret <= 0) {
return result;
}
@ -800,6 +831,7 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
else if(state & BR_SSL_RECVREC) {
buf = br_ssl_engine_recvrec_buf(&backend->ctx.eng, &len);
ret = Curl_conn_cf_recv(cf->next, data, (char *)buf, len, &result);
CURL_TRC_CF(data, cf, "ssl_recv(len=%zu) -> %zd, %d", len, ret, result);
if(ret == 0) {
failf(data, "SSL: EOF without close notify");
return CURLE_READ_ERROR;
@ -821,16 +853,26 @@ static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf,
CURLcode ret;
DEBUGASSERT(backend);
CURL_TRC_CF(data, cf, "connect_step2");
ret = bearssl_run_until(cf, data, BR_SSL_SENDAPP | BR_SSL_RECVAPP);
if(ret == CURLE_AGAIN)
return CURLE_OK;
if(ret == CURLE_OK) {
unsigned int tver;
if(br_ssl_engine_current_state(&backend->ctx.eng) == BR_SSL_CLOSED) {
failf(data, "SSL: connection closed during handshake");
return CURLE_SSL_CONNECT_ERROR;
}
connssl->connecting_state = ssl_connect_3;
/* Informational message */
tver = br_ssl_engine_get_version(&backend->ctx.eng);
if(tver == 0x0303)
infof(data, "SSL connection using TLSv1.2");
else if(tver == 0x0304)
infof(data, "SSL connection using TLSv1.3");
else
infof(data, "SSL connection using TLS 0x%x", tver);
}
return ret;
}
@ -846,6 +888,7 @@ static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
DEBUGASSERT(backend);
CURL_TRC_CF(data, cf, "connect_step3");
if(connssl->alpn) {
const char *proto;
@ -954,8 +997,10 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf,
timediff_t timeout_ms;
int what;
CURL_TRC_CF(data, cf, "connect_common(blocking=%d)", !nonblocking);
/* check if the connection has already been established */
if(ssl_connection_complete == connssl->state) {
CURL_TRC_CF(data, cf, "connect_common, connected");
*done = TRUE;
return CURLE_OK;
}
@ -987,8 +1032,10 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf,
curl_socket_t readfd = ssl_connect_2_reading ==
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
CURL_TRC_CF(data, cf, "connect_common, check socket");
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
nonblocking?0:timeout_ms);
CURL_TRC_CF(data, cf, "connect_common, check socket -> %d", what);
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
@ -1163,7 +1210,7 @@ const struct Curl_ssl Curl_ssl_bearssl = {
Curl_none_cert_status_request, /* cert_status_request */
bearssl_connect, /* connect */
bearssl_connect_nonblocking, /* connect_nonblocking */
Curl_ssl_get_select_socks, /* getsock */
bearssl_get_select_socks, /* getsock */
bearssl_get_internals, /* get_internals */
bearssl_close, /* close_one */
Curl_none_close_all, /* close_all */

View File

@ -635,19 +635,16 @@ int Curl_ssl_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data,
struct ssl_connect_data *connssl = cf->ctx;
curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
if(sock != CURL_SOCKET_BAD) {
if(connssl->connecting_state == ssl_connect_2_writing) {
/* write mode */
socks[0] = sock;
return GETSOCK_WRITESOCK(0);
}
if(connssl->connecting_state == ssl_connect_2_reading) {
/* read mode */
socks[0] = sock;
return GETSOCK_READSOCK(0);
}
if(sock == CURL_SOCKET_BAD)
return GETSOCK_BLANK;
if(connssl->connecting_state == ssl_connect_2_writing) {
/* we are only interested in writing */
socks[0] = sock;
return GETSOCK_WRITESOCK(0);
}
return GETSOCK_BLANK;
socks[0] = sock;
return GETSOCK_READSOCK(0);
}
/* Selects an SSL crypto engine
@ -1512,6 +1509,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
}
CF_DATA_SAVE(save, cf, data);
CURL_TRC_CF(data, cf, "cf_connect()");
(void)connssl;
DEBUGASSERT(data->conn);
DEBUGASSERT(data->conn == cf->conn);
@ -1541,6 +1539,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
DEBUGASSERT(connssl->state == ssl_connection_complete);
}
out:
CURL_TRC_CF(data, cf, "cf_connect() -> %d, done=%d", result, *done);
CF_DATA_RESTORE(cf, save);
return result;
}
@ -1601,12 +1600,17 @@ static int ssl_cf_get_select_socks(struct Curl_cfilter *cf,
curl_socket_t *socks)
{
struct cf_call_data save;
int result;
int fds = GETSOCK_BLANK;
CF_DATA_SAVE(save, cf, data);
result = Curl_ssl->get_select_socks(cf, data, socks);
CF_DATA_RESTORE(cf, save);
return result;
if(!cf->next->connected) {
fds = cf->next->cft->get_select_socks(cf->next, data, socks);
}
else if(!cf->connected) {
CF_DATA_SAVE(save, cf, data);
fds = Curl_ssl->get_select_socks(cf, data, socks);
CF_DATA_RESTORE(cf, save);
}
return fds;
}
static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf,

View File

@ -48,6 +48,7 @@ class Httpd:
'authz_user', 'authz_core', 'authz_host',
'auth_basic', 'auth_digest',
'env', 'filter', 'headers', 'mime',
'socache_shmcb',
'rewrite', 'http2', 'ssl', 'proxy', 'proxy_http', 'proxy_connect',
'mpm_event',
]
@ -251,6 +252,7 @@ class Httpd:
f'Listen {self.env.proxy_port}',
f'Listen {self.env.proxys_port}',
f'TypesConfig "{self._conf_dir}/mime.types',
f'SSLSessionCache "shmcb:ssl_gcache_data(32000)"',
]
if 'base' in self._extra_configs:
conf.extend(self._extra_configs['base'])