vtls: move common early data code into vtls.c
With now 2 backends implementing early data, it makes sense to have the common handling in a single place. Closes #16450
This commit is contained in:
parent
a1d00da81e
commit
4ed9db9eef
129
lib/vtls/gtls.c
129
lib/vtls/gtls.c
@ -1064,7 +1064,7 @@ static CURLcode gtls_on_session_reuse(struct Curl_cfilter *cf,
|
|||||||
else {
|
else {
|
||||||
infof(data, "SSL session allows %zu bytes of early data, "
|
infof(data, "SSL session allows %zu bytes of early data, "
|
||||||
"reusing ALPN '%s'", connssl->earlydata_max, scs->alpn);
|
"reusing ALPN '%s'", connssl->earlydata_max, scs->alpn);
|
||||||
connssl->earlydata_state = ssl_earlydata_use;
|
connssl->earlydata_state = ssl_earlydata_await;
|
||||||
connssl->state = ssl_connection_deferred;
|
connssl->state = ssl_connection_deferred;
|
||||||
result = Curl_alpn_set_negotiated(cf, data, connssl,
|
result = Curl_alpn_set_negotiated(cf, data, connssl,
|
||||||
(const unsigned char *)scs->alpn,
|
(const unsigned char *)scs->alpn,
|
||||||
@ -1756,30 +1756,6 @@ out:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CURLcode gtls_set_earlydata(struct Curl_cfilter *cf,
|
|
||||||
struct Curl_easy *data,
|
|
||||||
const void *buf, size_t blen)
|
|
||||||
{
|
|
||||||
struct ssl_connect_data *connssl = cf->ctx;
|
|
||||||
ssize_t nwritten = 0;
|
|
||||||
CURLcode result = CURLE_OK;
|
|
||||||
|
|
||||||
DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_use);
|
|
||||||
DEBUGASSERT(Curl_bufq_is_empty(&connssl->earlydata));
|
|
||||||
if(blen) {
|
|
||||||
if(blen > connssl->earlydata_max)
|
|
||||||
blen = connssl->earlydata_max;
|
|
||||||
nwritten = Curl_bufq_write(&connssl->earlydata, buf, blen, &result);
|
|
||||||
CURL_TRC_CF(data, cf, "gtls_set_earlydata(len=%zu) -> %zd",
|
|
||||||
blen, nwritten);
|
|
||||||
if(nwritten < 0)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
connssl->earlydata_state = ssl_earlydata_sending;
|
|
||||||
connssl->earlydata_skip = Curl_bufq_len(&connssl->earlydata);
|
|
||||||
return CURLE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static CURLcode gtls_send_earlydata(struct Curl_cfilter *cf,
|
static CURLcode gtls_send_earlydata(struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data)
|
struct Curl_easy *data)
|
||||||
{
|
{
|
||||||
@ -1855,7 +1831,7 @@ static CURLcode gtls_connect_common(struct Curl_cfilter *cf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(connssl->connecting_state == ssl_connect_2) {
|
if(connssl->connecting_state == ssl_connect_2) {
|
||||||
if(connssl->earlydata_state == ssl_earlydata_use) {
|
if(connssl->earlydata_state == ssl_earlydata_await) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
else if(connssl->earlydata_state == ssl_earlydata_sending) {
|
else if(connssl->earlydata_state == ssl_earlydata_sending) {
|
||||||
@ -1863,8 +1839,6 @@ static CURLcode gtls_connect_common(struct Curl_cfilter *cf,
|
|||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
connssl->earlydata_state = ssl_earlydata_sent;
|
connssl->earlydata_state = ssl_earlydata_sent;
|
||||||
if(!Curl_ssl_cf_is_proxy(cf))
|
|
||||||
Curl_pgrsEarlyData(data, (curl_off_t)connssl->earlydata_skip);
|
|
||||||
}
|
}
|
||||||
DEBUGASSERT((connssl->earlydata_state == ssl_earlydata_none) ||
|
DEBUGASSERT((connssl->earlydata_state == ssl_earlydata_none) ||
|
||||||
(connssl->earlydata_state == ssl_earlydata_sent));
|
(connssl->earlydata_state == ssl_earlydata_sent));
|
||||||
@ -1896,31 +1870,19 @@ static CURLcode gtls_connect_common(struct Curl_cfilter *cf,
|
|||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if(connssl->earlydata_state == ssl_earlydata_sent) {
|
if(connssl->earlydata_state > ssl_earlydata_none) {
|
||||||
/* report the true time the handshake was done */
|
/* We should be in this state by now */
|
||||||
connssl->handshake_done = Curl_now();
|
DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_sent);
|
||||||
Curl_pgrsTimeWas(data, TIMER_APPCONNECT, connssl->handshake_done);
|
connssl->earlydata_state =
|
||||||
if(gnutls_session_get_flags(backend->gtls.session) &
|
(gnutls_session_get_flags(backend->gtls.session) &
|
||||||
GNUTLS_SFLAGS_EARLY_DATA) {
|
GNUTLS_SFLAGS_EARLY_DATA) ?
|
||||||
connssl->earlydata_state = ssl_earlydata_accepted;
|
ssl_earlydata_accepted : ssl_earlydata_rejected;
|
||||||
infof(data, "Server accepted %zu bytes of TLS early data.",
|
|
||||||
connssl->earlydata_skip);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
connssl->earlydata_state = ssl_earlydata_rejected;
|
|
||||||
if(!Curl_ssl_cf_is_proxy(cf))
|
|
||||||
Curl_pgrsEarlyData(data, -(curl_off_t)connssl->earlydata_skip);
|
|
||||||
infof(data, "Server rejected TLS early data.");
|
|
||||||
connssl->earlydata_skip = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
connssl->connecting_state = ssl_connect_done;
|
connssl->connecting_state = ssl_connect_done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ssl_connect_done == connssl->connecting_state) {
|
if(connssl->connecting_state == ssl_connect_done)
|
||||||
connssl->state = ssl_connection_complete;
|
DEBUGASSERT(connssl->state == ssl_connection_complete);
|
||||||
*done = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if(result == CURLE_AGAIN) {
|
if(result == CURLE_AGAIN) {
|
||||||
@ -1938,7 +1900,8 @@ static CURLcode gtls_connect(struct Curl_cfilter *cf,
|
|||||||
bool *done)
|
bool *done)
|
||||||
{
|
{
|
||||||
struct ssl_connect_data *connssl = cf->ctx;
|
struct ssl_connect_data *connssl = cf->ctx;
|
||||||
if(connssl->state == ssl_connection_deferred) {
|
if((connssl->state == ssl_connection_deferred) &&
|
||||||
|
(connssl->earlydata_state == ssl_earlydata_await)) {
|
||||||
/* We refuse to be pushed, we are waiting for someone to send/recv. */
|
/* We refuse to be pushed, we are waiting for someone to send/recv. */
|
||||||
*done = TRUE;
|
*done = TRUE;
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
@ -1946,26 +1909,6 @@ static CURLcode gtls_connect(struct Curl_cfilter *cf,
|
|||||||
return gtls_connect_common(cf, data, done);
|
return gtls_connect_common(cf, data, done);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CURLcode gtls_connect_deferred(struct Curl_cfilter *cf,
|
|
||||||
struct Curl_easy *data,
|
|
||||||
const void *buf,
|
|
||||||
size_t blen,
|
|
||||||
bool *done)
|
|
||||||
{
|
|
||||||
struct ssl_connect_data *connssl = cf->ctx;
|
|
||||||
CURLcode result = CURLE_OK;
|
|
||||||
|
|
||||||
DEBUGASSERT(connssl->state == ssl_connection_deferred);
|
|
||||||
*done = FALSE;
|
|
||||||
if(connssl->earlydata_state == ssl_earlydata_use) {
|
|
||||||
result = gtls_set_earlydata(cf, data, buf, blen);
|
|
||||||
if(result)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return gtls_connect_common(cf, data, done);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool gtls_data_pending(struct Curl_cfilter *cf,
|
static bool gtls_data_pending(struct Curl_cfilter *cf,
|
||||||
const struct Curl_easy *data)
|
const struct Curl_easy *data)
|
||||||
{
|
{
|
||||||
@ -1993,38 +1936,9 @@ static ssize_t gtls_send(struct Curl_cfilter *cf,
|
|||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
size_t nwritten, total_written = 0;
|
size_t nwritten, total_written = 0;
|
||||||
|
|
||||||
|
(void)data;
|
||||||
DEBUGASSERT(backend);
|
DEBUGASSERT(backend);
|
||||||
|
|
||||||
if(connssl->state == ssl_connection_deferred) {
|
|
||||||
bool done = FALSE;
|
|
||||||
*curlcode = gtls_connect_deferred(cf, data, buf, blen, &done);
|
|
||||||
if(*curlcode) {
|
|
||||||
rc = -1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
else if(!done) {
|
|
||||||
*curlcode = CURLE_AGAIN;
|
|
||||||
rc = -1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
DEBUGASSERT(connssl->state == ssl_connection_complete);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(connssl->earlydata_skip) {
|
|
||||||
if(connssl->earlydata_skip >= blen) {
|
|
||||||
connssl->earlydata_skip -= blen;
|
|
||||||
*curlcode = CURLE_OK;
|
|
||||||
rc = (ssize_t)blen;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
total_written += connssl->earlydata_skip;
|
|
||||||
buf = ((const char *)buf) + connssl->earlydata_skip;
|
|
||||||
blen -= connssl->earlydata_skip;
|
|
||||||
connssl->earlydata_skip = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while(blen) {
|
while(blen) {
|
||||||
backend->gtls.io_result = CURLE_OK;
|
backend->gtls.io_result = CURLE_OK;
|
||||||
rc = gnutls_record_send(backend->gtls.session, buf, blen);
|
rc = gnutls_record_send(backend->gtls.session, buf, blen);
|
||||||
@ -2171,21 +2085,6 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf,
|
|||||||
(void)data;
|
(void)data;
|
||||||
DEBUGASSERT(backend);
|
DEBUGASSERT(backend);
|
||||||
|
|
||||||
if(connssl->state == ssl_connection_deferred) {
|
|
||||||
bool done = FALSE;
|
|
||||||
*curlcode = gtls_connect_deferred(cf, data, NULL, 0, &done);
|
|
||||||
if(*curlcode) {
|
|
||||||
ret = -1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
else if(!done) {
|
|
||||||
*curlcode = CURLE_AGAIN;
|
|
||||||
ret = -1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
DEBUGASSERT(connssl->state == ssl_connection_complete);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gnutls_record_recv(backend->gtls.session, buf, buffersize);
|
ret = gnutls_record_recv(backend->gtls.session, buf, buffersize);
|
||||||
if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
|
if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
|
||||||
*curlcode = CURLE_AGAIN;
|
*curlcode = CURLE_AGAIN;
|
||||||
|
|||||||
168
lib/vtls/vtls.c
168
lib/vtls/vtls.c
@ -485,18 +485,6 @@ static void cf_ctx_free(struct ssl_connect_data *ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static CURLcode
|
|
||||||
ssl_connect(struct Curl_cfilter *cf, struct Curl_easy *data, bool *done)
|
|
||||||
{
|
|
||||||
struct ssl_connect_data *connssl = cf->ctx;
|
|
||||||
|
|
||||||
if(!ssl_prefs_check(data))
|
|
||||||
return CURLE_SSL_CONNECT_ERROR;
|
|
||||||
|
|
||||||
/* mark this is being ssl requested from here on. */
|
|
||||||
return connssl->ssl_impl->do_connect(cf, data, done);
|
|
||||||
}
|
|
||||||
|
|
||||||
CURLcode Curl_ssl_get_channel_binding(struct Curl_easy *data, int sockindex,
|
CURLcode Curl_ssl_get_channel_binding(struct Curl_easy *data, int sockindex,
|
||||||
struct dynbuf *binding)
|
struct dynbuf *binding)
|
||||||
{
|
{
|
||||||
@ -1318,7 +1306,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
|
|||||||
struct cf_call_data save;
|
struct cf_call_data save;
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
|
|
||||||
if(cf->connected) {
|
if(cf->connected && (connssl->state != ssl_connection_deferred)) {
|
||||||
*done = TRUE;
|
*done = TRUE;
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
@ -1336,8 +1324,6 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
|
|||||||
|
|
||||||
CF_DATA_SAVE(save, cf, data);
|
CF_DATA_SAVE(save, cf, data);
|
||||||
CURL_TRC_CF(data, cf, "cf_connect()");
|
CURL_TRC_CF(data, cf, "cf_connect()");
|
||||||
DEBUGASSERT(data->conn);
|
|
||||||
DEBUGASSERT(data->conn == cf->conn);
|
|
||||||
DEBUGASSERT(connssl);
|
DEBUGASSERT(connssl);
|
||||||
|
|
||||||
*done = FALSE;
|
*done = FALSE;
|
||||||
@ -1349,7 +1335,13 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = ssl_connect(cf, data, done);
|
if(!connssl->prefs_checked) {
|
||||||
|
if(!ssl_prefs_check(data))
|
||||||
|
return CURLE_SSL_CONNECT_ERROR;
|
||||||
|
connssl->prefs_checked = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = connssl->ssl_impl->do_connect(cf, data, done);
|
||||||
|
|
||||||
if(!result && *done) {
|
if(!result && *done) {
|
||||||
cf->connected = TRUE;
|
cf->connected = TRUE;
|
||||||
@ -1358,6 +1350,8 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
|
|||||||
/* Connection can be deferred when sending early data */
|
/* Connection can be deferred when sending early data */
|
||||||
DEBUGASSERT(connssl->state == ssl_connection_complete ||
|
DEBUGASSERT(connssl->state == ssl_connection_complete ||
|
||||||
connssl->state == ssl_connection_deferred);
|
connssl->state == ssl_connection_deferred);
|
||||||
|
DEBUGASSERT(connssl->state != ssl_connection_deferred ||
|
||||||
|
connssl->earlydata_state > ssl_earlydata_none);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
CURL_TRC_CF(data, cf, "cf_connect() -> %d, done=%d", result, *done);
|
CURL_TRC_CF(data, cf, "cf_connect() -> %d, done=%d", result, *done);
|
||||||
@ -1365,6 +1359,77 @@ out:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CURLcode ssl_cf_set_earlydata(struct Curl_cfilter *cf,
|
||||||
|
struct Curl_easy *data,
|
||||||
|
const void *buf, size_t blen)
|
||||||
|
{
|
||||||
|
struct ssl_connect_data *connssl = cf->ctx;
|
||||||
|
ssize_t nwritten = 0;
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
|
||||||
|
DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_await);
|
||||||
|
DEBUGASSERT(Curl_bufq_is_empty(&connssl->earlydata));
|
||||||
|
if(blen) {
|
||||||
|
if(blen > connssl->earlydata_max)
|
||||||
|
blen = connssl->earlydata_max;
|
||||||
|
nwritten = Curl_bufq_write(&connssl->earlydata, buf, blen, &result);
|
||||||
|
CURL_TRC_CF(data, cf, "ssl_cf_set_earlydata(len=%zu) -> %zd",
|
||||||
|
blen, nwritten);
|
||||||
|
if(nwritten < 0)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURLcode ssl_cf_connect_deferred(struct Curl_cfilter *cf,
|
||||||
|
struct Curl_easy *data,
|
||||||
|
const void *buf, size_t blen,
|
||||||
|
bool *done)
|
||||||
|
{
|
||||||
|
struct ssl_connect_data *connssl = cf->ctx;
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
|
||||||
|
DEBUGASSERT(connssl->state == ssl_connection_deferred);
|
||||||
|
*done = FALSE;
|
||||||
|
if(connssl->earlydata_state == ssl_earlydata_await) {
|
||||||
|
result = ssl_cf_set_earlydata(cf, data, buf, blen);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
/* we buffered any early data we'd like to send. Actually
|
||||||
|
* do the connect now which sends it and performs the handshake. */
|
||||||
|
connssl->earlydata_state = ssl_earlydata_sending;
|
||||||
|
connssl->earlydata_skip = Curl_bufq_len(&connssl->earlydata);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = ssl_cf_connect(cf, data, done);
|
||||||
|
|
||||||
|
if(!result && *done) {
|
||||||
|
Curl_pgrsTimeWas(data, TIMER_APPCONNECT, connssl->handshake_done);
|
||||||
|
switch(connssl->earlydata_state) {
|
||||||
|
case ssl_earlydata_none:
|
||||||
|
break;
|
||||||
|
case ssl_earlydata_accepted:
|
||||||
|
if(!Curl_ssl_cf_is_proxy(cf))
|
||||||
|
Curl_pgrsEarlyData(data, (curl_off_t)connssl->earlydata_skip);
|
||||||
|
infof(data, "Server accepted %zu bytes of TLS early data.",
|
||||||
|
connssl->earlydata_skip);
|
||||||
|
break;
|
||||||
|
case ssl_earlydata_rejected:
|
||||||
|
if(!Curl_ssl_cf_is_proxy(cf))
|
||||||
|
Curl_pgrsEarlyData(data, -(curl_off_t)connssl->earlydata_skip);
|
||||||
|
infof(data, "Server rejected TLS early data.");
|
||||||
|
connssl->earlydata_skip = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* This should not happen. Either we do not use early data or we
|
||||||
|
* should know if it was accepted or not. */
|
||||||
|
DEBUGASSERT(NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static bool ssl_cf_data_pending(struct Curl_cfilter *cf,
|
static bool ssl_cf_data_pending(struct Curl_cfilter *cf,
|
||||||
const struct Curl_easy *data)
|
const struct Curl_easy *data)
|
||||||
{
|
{
|
||||||
@ -1383,21 +1448,57 @@ static bool ssl_cf_data_pending(struct Curl_cfilter *cf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t ssl_cf_send(struct Curl_cfilter *cf,
|
static ssize_t ssl_cf_send(struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data, const void *buf, size_t len,
|
struct Curl_easy *data,
|
||||||
|
const void *buf, size_t blen,
|
||||||
bool eos, CURLcode *err)
|
bool eos, CURLcode *err)
|
||||||
{
|
{
|
||||||
struct ssl_connect_data *connssl = cf->ctx;
|
struct ssl_connect_data *connssl = cf->ctx;
|
||||||
struct cf_call_data save;
|
struct cf_call_data save;
|
||||||
ssize_t nwritten = 0;
|
ssize_t nwritten = 0, early_written = 0;
|
||||||
|
|
||||||
(void)eos;
|
(void)eos;
|
||||||
/* OpenSSL and maybe other TLS libs do not like 0-length writes. Skip. */
|
|
||||||
*err = CURLE_OK;
|
*err = CURLE_OK;
|
||||||
if(len > 0) {
|
CF_DATA_SAVE(save, cf, data);
|
||||||
CF_DATA_SAVE(save, cf, data);
|
|
||||||
nwritten = connssl->ssl_impl->send_plain(cf, data, buf, len, err);
|
if(connssl->state == ssl_connection_deferred) {
|
||||||
CF_DATA_RESTORE(cf, save);
|
bool done = FALSE;
|
||||||
|
*err = ssl_cf_connect_deferred(cf, data, buf, blen, &done);
|
||||||
|
if(*err) {
|
||||||
|
nwritten = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else if(!done) {
|
||||||
|
*err = CURLE_AGAIN;
|
||||||
|
nwritten = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
DEBUGASSERT(connssl->state == ssl_connection_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(connssl->earlydata_skip) {
|
||||||
|
if(connssl->earlydata_skip >= blen) {
|
||||||
|
connssl->earlydata_skip -= blen;
|
||||||
|
*err = CURLE_OK;
|
||||||
|
nwritten = (ssize_t)blen;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
early_written = connssl->earlydata_skip;
|
||||||
|
buf = ((const char *)buf) + connssl->earlydata_skip;
|
||||||
|
blen -= connssl->earlydata_skip;
|
||||||
|
connssl->earlydata_skip = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OpenSSL and maybe other TLS libs do not like 0-length writes. Skip. */
|
||||||
|
if(blen > 0)
|
||||||
|
nwritten = connssl->ssl_impl->send_plain(cf, data, buf, blen, err);
|
||||||
|
|
||||||
|
if(nwritten >= 0)
|
||||||
|
nwritten += early_written;
|
||||||
|
|
||||||
|
out:
|
||||||
|
CF_DATA_RESTORE(cf, save);
|
||||||
return nwritten;
|
return nwritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1411,6 +1512,21 @@ static ssize_t ssl_cf_recv(struct Curl_cfilter *cf,
|
|||||||
|
|
||||||
CF_DATA_SAVE(save, cf, data);
|
CF_DATA_SAVE(save, cf, data);
|
||||||
*err = CURLE_OK;
|
*err = CURLE_OK;
|
||||||
|
if(connssl->state == ssl_connection_deferred) {
|
||||||
|
bool done = FALSE;
|
||||||
|
*err = ssl_cf_connect_deferred(cf, data, NULL, 0, &done);
|
||||||
|
if(*err) {
|
||||||
|
nread = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else if(!done) {
|
||||||
|
*err = CURLE_AGAIN;
|
||||||
|
nread = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
DEBUGASSERT(connssl->state == ssl_connection_complete);
|
||||||
|
}
|
||||||
|
|
||||||
nread = connssl->ssl_impl->recv_plain(cf, data, buf, len, err);
|
nread = connssl->ssl_impl->recv_plain(cf, data, buf, len, err);
|
||||||
if(nread > 0) {
|
if(nread > 0) {
|
||||||
DEBUGASSERT((size_t)nread <= len);
|
DEBUGASSERT((size_t)nread <= len);
|
||||||
@ -1419,6 +1535,8 @@ static ssize_t ssl_cf_recv(struct Curl_cfilter *cf,
|
|||||||
/* eof */
|
/* eof */
|
||||||
*err = CURLE_OK;
|
*err = CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len,
|
CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len,
|
||||||
nread, *err);
|
nread, *err);
|
||||||
CF_DATA_RESTORE(cf, save);
|
CF_DATA_RESTORE(cf, save);
|
||||||
@ -1433,7 +1551,9 @@ static CURLcode ssl_cf_shutdown(struct Curl_cfilter *cf,
|
|||||||
CURLcode result = CURLE_OK;
|
CURLcode result = CURLE_OK;
|
||||||
|
|
||||||
*done = TRUE;
|
*done = TRUE;
|
||||||
if(!cf->shutdown && Curl_ssl->shut_down) {
|
/* If we have done the SSL handshake, shut down the connection cleanly */
|
||||||
|
if(cf->connected && (connssl->state == ssl_connection_complete) &&
|
||||||
|
!cf->shutdown && Curl_ssl->shut_down) {
|
||||||
struct cf_call_data save;
|
struct cf_call_data save;
|
||||||
|
|
||||||
CF_DATA_SAVE(save, cf, data);
|
CF_DATA_SAVE(save, cf, data);
|
||||||
|
|||||||
@ -91,7 +91,7 @@ typedef enum {
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ssl_earlydata_none,
|
ssl_earlydata_none,
|
||||||
ssl_earlydata_use,
|
ssl_earlydata_await,
|
||||||
ssl_earlydata_sending,
|
ssl_earlydata_sending,
|
||||||
ssl_earlydata_sent,
|
ssl_earlydata_sent,
|
||||||
ssl_earlydata_accepted,
|
ssl_earlydata_accepted,
|
||||||
@ -126,6 +126,7 @@ struct ssl_connect_data {
|
|||||||
int io_need; /* TLS signals special SEND/RECV needs */
|
int io_need; /* TLS signals special SEND/RECV needs */
|
||||||
BIT(use_alpn); /* if ALPN shall be used in handshake */
|
BIT(use_alpn); /* if ALPN shall be used in handshake */
|
||||||
BIT(peer_closed); /* peer has closed connection */
|
BIT(peer_closed); /* peer has closed connection */
|
||||||
|
BIT(prefs_checked); /* SSL preferences have been checked */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -525,7 +525,7 @@ static CURLcode wssl_on_session_reuse(struct Curl_cfilter *cf,
|
|||||||
else {
|
else {
|
||||||
infof(data, "SSL session allows %zu bytes of early data, "
|
infof(data, "SSL session allows %zu bytes of early data, "
|
||||||
"reusing ALPN '%s'", connssl->earlydata_max, scs->alpn);
|
"reusing ALPN '%s'", connssl->earlydata_max, scs->alpn);
|
||||||
connssl->earlydata_state = ssl_earlydata_use;
|
connssl->earlydata_state = ssl_earlydata_await;
|
||||||
connssl->state = ssl_connection_deferred;
|
connssl->state = ssl_connection_deferred;
|
||||||
result = Curl_alpn_set_negotiated(cf, data, connssl,
|
result = Curl_alpn_set_negotiated(cf, data, connssl,
|
||||||
(const unsigned char *)scs->alpn,
|
(const unsigned char *)scs->alpn,
|
||||||
@ -1662,6 +1662,8 @@ static CURLcode wssl_handshake(struct Curl_cfilter *cf,
|
|||||||
}
|
}
|
||||||
DEBUGASSERT((connssl->earlydata_state == ssl_earlydata_none) ||
|
DEBUGASSERT((connssl->earlydata_state == ssl_earlydata_none) ||
|
||||||
(connssl->earlydata_state == ssl_earlydata_sent));
|
(connssl->earlydata_state == ssl_earlydata_sent));
|
||||||
|
#else
|
||||||
|
DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_none);
|
||||||
#endif /* WOLFSSL_EARLY_DATA */
|
#endif /* WOLFSSL_EARLY_DATA */
|
||||||
|
|
||||||
wolfSSL_ERR_clear_error();
|
wolfSSL_ERR_clear_error();
|
||||||
@ -1788,52 +1790,6 @@ static CURLcode wssl_handshake(struct Curl_cfilter *cf,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WOLFSSL_EARLY_DATA
|
|
||||||
static CURLcode wssl_set_earlydata(struct Curl_cfilter *cf,
|
|
||||||
struct Curl_easy *data,
|
|
||||||
const void *buf, size_t blen)
|
|
||||||
{
|
|
||||||
struct ssl_connect_data *connssl = cf->ctx;
|
|
||||||
ssize_t nwritten = 0;
|
|
||||||
CURLcode result = CURLE_OK;
|
|
||||||
|
|
||||||
DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_use);
|
|
||||||
DEBUGASSERT(Curl_bufq_is_empty(&connssl->earlydata));
|
|
||||||
if(blen) {
|
|
||||||
if(blen > connssl->earlydata_max)
|
|
||||||
blen = connssl->earlydata_max;
|
|
||||||
nwritten = Curl_bufq_write(&connssl->earlydata, buf, blen, &result);
|
|
||||||
CURL_TRC_CF(data, cf, "wssl_set_earlydata(len=%zu) -> %zd",
|
|
||||||
blen, nwritten);
|
|
||||||
if(nwritten < 0)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
connssl->earlydata_state = ssl_earlydata_sending;
|
|
||||||
connssl->earlydata_skip = Curl_bufq_len(&connssl->earlydata);
|
|
||||||
return CURLE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static CURLcode wssl_connect_deferred(struct Curl_cfilter *cf,
|
|
||||||
struct Curl_easy *data,
|
|
||||||
const void *buf,
|
|
||||||
size_t blen,
|
|
||||||
bool *done)
|
|
||||||
{
|
|
||||||
struct ssl_connect_data *connssl = cf->ctx;
|
|
||||||
CURLcode result = CURLE_OK;
|
|
||||||
|
|
||||||
DEBUGASSERT(connssl->state == ssl_connection_deferred);
|
|
||||||
*done = FALSE;
|
|
||||||
if(connssl->earlydata_state == ssl_earlydata_use) {
|
|
||||||
result = wssl_set_earlydata(cf, data, buf, blen);
|
|
||||||
if(result)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return wssl_connect(cf, data, done);
|
|
||||||
}
|
|
||||||
#endif /* WOLFSSL_EARLY_DATA */
|
|
||||||
|
|
||||||
static ssize_t wssl_send(struct Curl_cfilter *cf,
|
static ssize_t wssl_send(struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data,
|
struct Curl_easy *data,
|
||||||
const void *buf, size_t blen,
|
const void *buf, size_t blen,
|
||||||
@ -1847,38 +1803,6 @@ static ssize_t wssl_send(struct Curl_cfilter *cf,
|
|||||||
|
|
||||||
wolfSSL_ERR_clear_error();
|
wolfSSL_ERR_clear_error();
|
||||||
|
|
||||||
#ifdef WOLFSSL_EARLY_DATA
|
|
||||||
if(connssl->state == ssl_connection_deferred) {
|
|
||||||
bool done = FALSE;
|
|
||||||
*curlcode = wssl_connect_deferred(cf, data, buf, blen, &done);
|
|
||||||
if(*curlcode) {
|
|
||||||
nwritten = -1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
else if(!done) {
|
|
||||||
*curlcode = CURLE_AGAIN;
|
|
||||||
nwritten = -1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
DEBUGASSERT(connssl->state == ssl_connection_complete);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(connssl->earlydata_skip) {
|
|
||||||
if(connssl->earlydata_skip >= blen) {
|
|
||||||
connssl->earlydata_skip -= blen;
|
|
||||||
*curlcode = CURLE_OK;
|
|
||||||
nwritten = (ssize_t)blen;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
total_written += connssl->earlydata_skip;
|
|
||||||
buf = ((const char *)buf) + connssl->earlydata_skip;
|
|
||||||
blen -= connssl->earlydata_skip;
|
|
||||||
connssl->earlydata_skip = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* WOLFSSL_EARLY_DATA */
|
|
||||||
|
|
||||||
if(blen) {
|
if(blen) {
|
||||||
int memlen = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen;
|
int memlen = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen;
|
||||||
int rc;
|
int rc;
|
||||||
@ -2071,21 +1995,6 @@ static ssize_t wssl_recv(struct Curl_cfilter *cf,
|
|||||||
|
|
||||||
DEBUGASSERT(wssl);
|
DEBUGASSERT(wssl);
|
||||||
|
|
||||||
#ifdef WOLFSSL_EARLY_DATA
|
|
||||||
if(connssl->state == ssl_connection_deferred) {
|
|
||||||
bool done = FALSE;
|
|
||||||
*curlcode = wssl_connect_deferred(cf, data, NULL, 0, &done);
|
|
||||||
if(*curlcode) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else if(!done) {
|
|
||||||
*curlcode = CURLE_AGAIN;
|
|
||||||
return-1;
|
|
||||||
}
|
|
||||||
DEBUGASSERT(connssl->state == ssl_connection_complete);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
wolfSSL_ERR_clear_error();
|
wolfSSL_ERR_clear_error();
|
||||||
*curlcode = CURLE_OK;
|
*curlcode = CURLE_OK;
|
||||||
|
|
||||||
@ -2212,7 +2121,7 @@ static CURLcode wssl_connect(struct Curl_cfilter *cf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(ssl_connect_2 == connssl->connecting_state) {
|
if(ssl_connect_2 == connssl->connecting_state) {
|
||||||
if(connssl->earlydata_state == ssl_earlydata_use) {
|
if(connssl->earlydata_state == ssl_earlydata_await) {
|
||||||
/* We defer the handshake until request data arrives. */
|
/* We defer the handshake until request data arrives. */
|
||||||
DEBUGASSERT(connssl->state == ssl_connection_deferred);
|
DEBUGASSERT(connssl->state == ssl_connection_deferred);
|
||||||
goto out;
|
goto out;
|
||||||
@ -2272,23 +2181,13 @@ static CURLcode wssl_connect(struct Curl_cfilter *cf,
|
|||||||
connssl->state = ssl_connection_complete;
|
connssl->state = ssl_connection_complete;
|
||||||
|
|
||||||
#ifdef WOLFSSL_EARLY_DATA
|
#ifdef WOLFSSL_EARLY_DATA
|
||||||
if(connssl->earlydata_state == ssl_earlydata_sent) {
|
if(connssl->earlydata_state > ssl_earlydata_none) {
|
||||||
/* report the true time the handshake was done */
|
/* We should be in this state by now */
|
||||||
connssl->handshake_done = Curl_now();
|
DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_sent);
|
||||||
Curl_pgrsTimeWas(data, TIMER_APPCONNECT, connssl->handshake_done);
|
connssl->earlydata_state =
|
||||||
if(wolfSSL_get_early_data_status(wssl->ssl) ==
|
(wolfSSL_get_early_data_status(wssl->ssl) ==
|
||||||
WOLFSSL_EARLY_DATA_REJECTED) {
|
WOLFSSL_EARLY_DATA_REJECTED) ?
|
||||||
connssl->earlydata_state = ssl_earlydata_rejected;
|
ssl_earlydata_rejected : ssl_earlydata_accepted;
|
||||||
if(!Curl_ssl_cf_is_proxy(cf))
|
|
||||||
Curl_pgrsEarlyData(data, -(curl_off_t)connssl->earlydata_skip);
|
|
||||||
infof(data, "Server rejected TLS early data.");
|
|
||||||
connssl->earlydata_skip = 0;
|
|
||||||
}
|
|
||||||
else if(connssl->earlydata_skip) {
|
|
||||||
connssl->earlydata_state = ssl_earlydata_accepted;
|
|
||||||
infof(data, "Server accepted %zu bytes of TLS early data.",
|
|
||||||
connssl->earlydata_skip);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif /* WOLFSSL_EARLY_DATA */
|
#endif /* WOLFSSL_EARLY_DATA */
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user