mirror of
https://github.com/curl/curl.git
synced 2026-07-16 00:07:22 +03:00
vtls: change send/recv signatures of tls backends
Similar to connection filter changes, return a CURLcode and the read/written amount as size_t *. Closes #17593
This commit is contained in:
parent
17f8b1db5c
commit
b7c676d13f
8 changed files with 310 additions and 348 deletions
110
lib/vtls/gtls.c
110
lib/vtls/gtls.c
|
|
@ -1948,48 +1948,49 @@ static bool gtls_data_pending(struct Curl_cfilter *cf,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static ssize_t gtls_send(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
const void *buf,
|
||||
size_t blen,
|
||||
CURLcode *curlcode)
|
||||
static CURLcode gtls_send(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
const void *buf,
|
||||
size_t blen,
|
||||
size_t *pnwritten)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct gtls_ssl_backend_data *backend =
|
||||
(struct gtls_ssl_backend_data *)connssl->backend;
|
||||
ssize_t rc;
|
||||
size_t nwritten, total_written = 0;
|
||||
CURLcode result = CURLE_OK;
|
||||
ssize_t nwritten;
|
||||
size_t remain = blen;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(backend);
|
||||
*pnwritten = 0;
|
||||
|
||||
while(blen) {
|
||||
while(remain) {
|
||||
backend->gtls.io_result = CURLE_OK;
|
||||
rc = gnutls_record_send(backend->gtls.session, buf, blen);
|
||||
nwritten = gnutls_record_send(backend->gtls.session, buf, remain);
|
||||
|
||||
if(rc < 0) {
|
||||
if(total_written && (rc == GNUTLS_E_AGAIN)) {
|
||||
*curlcode = CURLE_OK;
|
||||
rc = (ssize_t)total_written;
|
||||
if(nwritten >= 0) {
|
||||
*pnwritten += (size_t)nwritten;
|
||||
DEBUGASSERT((size_t)nwritten <= remain);
|
||||
buf = (char *)CURL_UNCONST(buf) + (size_t)nwritten;
|
||||
remain -= (size_t)nwritten;
|
||||
}
|
||||
else {
|
||||
if(*pnwritten && (nwritten == GNUTLS_E_AGAIN)) {
|
||||
result = CURLE_OK;
|
||||
goto out;
|
||||
}
|
||||
*curlcode = (rc == GNUTLS_E_AGAIN) ?
|
||||
result = (nwritten == GNUTLS_E_AGAIN) ?
|
||||
CURLE_AGAIN :
|
||||
(backend->gtls.io_result ? backend->gtls.io_result : CURLE_SEND_ERROR);
|
||||
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
nwritten = (size_t)rc;
|
||||
total_written += nwritten;
|
||||
DEBUGASSERT(nwritten <= blen);
|
||||
buf = (char *)CURL_UNCONST(buf) + nwritten;
|
||||
blen -= nwritten;
|
||||
}
|
||||
rc = total_written;
|
||||
|
||||
out:
|
||||
return rc;
|
||||
CURL_TRC_CF(data, cf, "gtls_send(len=%zu) -> %d, %zu",
|
||||
blen, result, *pnwritten);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2095,50 +2096,49 @@ static void gtls_close(struct Curl_cfilter *cf,
|
|||
#endif
|
||||
}
|
||||
|
||||
static ssize_t gtls_recv(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
char *buf,
|
||||
size_t buffersize,
|
||||
CURLcode *curlcode)
|
||||
static CURLcode gtls_recv(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
char *buf, size_t blen,
|
||||
size_t *pnread)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct gtls_ssl_backend_data *backend =
|
||||
(struct gtls_ssl_backend_data *)connssl->backend;
|
||||
ssize_t ret;
|
||||
CURLcode result = CURLE_OK;
|
||||
ssize_t nread;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
ret = gnutls_record_recv(backend->gtls.session, buf, buffersize);
|
||||
if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
|
||||
*curlcode = CURLE_AGAIN;
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
nread = gnutls_record_recv(backend->gtls.session, buf, blen);
|
||||
|
||||
if(ret == GNUTLS_E_REHANDSHAKE) {
|
||||
/* BLOCKING call, this is bad but a work-around for now. Fixing this "the
|
||||
proper way" takes a whole lot of work. */
|
||||
CURLcode result = handshake(cf, data);
|
||||
if(result)
|
||||
*curlcode = result;
|
||||
else
|
||||
*curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if(ret < 0) {
|
||||
failf(data, "GnuTLS recv error (%d): %s",
|
||||
(int)ret, gnutls_strerror((int)ret));
|
||||
*curlcode = backend->gtls.io_result ?
|
||||
backend->gtls.io_result : CURLE_RECV_ERROR;
|
||||
ret = -1;
|
||||
goto out;
|
||||
if(nread >= 0)
|
||||
*pnread = (size_t)nread;
|
||||
else {
|
||||
if((nread == GNUTLS_E_AGAIN) || (nread == GNUTLS_E_INTERRUPTED)) {
|
||||
result = CURLE_AGAIN;
|
||||
goto out;
|
||||
}
|
||||
else if(nread == GNUTLS_E_REHANDSHAKE) {
|
||||
/* BLOCKING call, this is bad but a work-around for now. Fixing this "the
|
||||
proper way" takes a whole lot of work. */
|
||||
result = handshake(cf, data);
|
||||
if(!result)
|
||||
result = CURLE_AGAIN; /* then return as if this was a wouldblock */
|
||||
goto out;
|
||||
}
|
||||
else {
|
||||
failf(data, "GnuTLS recv error (%d): %s",
|
||||
(int)nread, gnutls_strerror((int)nread));
|
||||
result = backend->gtls.io_result ?
|
||||
backend->gtls.io_result : CURLE_RECV_ERROR;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
CURL_TRC_CF(data, cf, "gtls_recv(len=%zu) -> 0, %zu", blen, *pnread);
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t Curl_gtls_version(char *buffer, size_t size)
|
||||
|
|
|
|||
|
|
@ -1203,16 +1203,18 @@ out:
|
|||
return result;
|
||||
}
|
||||
|
||||
static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
const void *mem, size_t len,
|
||||
CURLcode *curlcode)
|
||||
static CURLcode mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
const void *mem, size_t len,
|
||||
size_t *pnwritten)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct mbed_ssl_backend_data *backend =
|
||||
(struct mbed_ssl_backend_data *)connssl->backend;
|
||||
int ret = -1;
|
||||
CURLcode result = CURLE_OK;
|
||||
int nwritten;
|
||||
|
||||
(void)data;
|
||||
*pnwritten = 0;
|
||||
DEBUGASSERT(backend);
|
||||
/* mbedtls is picky when a mbedtls_ssl_write) was previously blocked.
|
||||
* It requires to be called with the same amount of bytes again, or it
|
||||
|
|
@ -1225,28 +1227,29 @@ static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
len = backend->send_blocked_len;
|
||||
}
|
||||
|
||||
ret = mbedtls_ssl_write(&backend->ssl, (const unsigned char *)mem, len);
|
||||
nwritten = mbedtls_ssl_write(&backend->ssl, (const unsigned char *)mem, len);
|
||||
|
||||
if(ret < 0) {
|
||||
if(nwritten >= 0) {
|
||||
*pnwritten = (size_t)nwritten;
|
||||
backend->send_blocked = FALSE;
|
||||
}
|
||||
else {
|
||||
CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> -0x%04X",
|
||||
len, -ret);
|
||||
*curlcode = ((ret == MBEDTLS_ERR_SSL_WANT_WRITE)
|
||||
len, -nwritten);
|
||||
result = ((nwritten == MBEDTLS_ERR_SSL_WANT_WRITE)
|
||||
#ifdef HAS_TLS13_SUPPORT
|
||||
|| (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
|
||||
|| (nwritten == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
|
||||
#endif
|
||||
) ? CURLE_AGAIN : CURLE_SEND_ERROR;
|
||||
ret = -1;
|
||||
if((*curlcode == CURLE_AGAIN) && !backend->send_blocked) {
|
||||
if((result == CURLE_AGAIN) && !backend->send_blocked) {
|
||||
backend->send_blocked = TRUE;
|
||||
backend->send_blocked_len = len;
|
||||
}
|
||||
}
|
||||
else {
|
||||
CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> %d", len, ret);
|
||||
backend->send_blocked = FALSE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> %d, %zu",
|
||||
len, result, *pnwritten);
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode mbedtls_shutdown(struct Curl_cfilter *cf,
|
||||
|
|
@ -1365,48 +1368,48 @@ static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
}
|
||||
}
|
||||
|
||||
static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
char *buf, size_t buffersize,
|
||||
CURLcode *curlcode)
|
||||
static CURLcode mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
char *buf, size_t buffersize,
|
||||
size_t *pnread)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct mbed_ssl_backend_data *backend =
|
||||
(struct mbed_ssl_backend_data *)connssl->backend;
|
||||
int ret = -1;
|
||||
CURLcode result = CURLE_OK;
|
||||
int nread;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(backend);
|
||||
*pnread = 0;
|
||||
|
||||
ret = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf,
|
||||
buffersize);
|
||||
if(ret <= 0) {
|
||||
nread = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, buffersize);
|
||||
if(nread > 0)
|
||||
*pnread = (size_t)nread;
|
||||
else {
|
||||
CURL_TRC_CF(data, cf, "mbedtls_ssl_read(len=%zu) -> -0x%04X",
|
||||
buffersize, -ret);
|
||||
switch(ret) {
|
||||
buffersize, -nread);
|
||||
switch(nread) {
|
||||
#ifdef HAS_SESSION_TICKETS
|
||||
case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET:
|
||||
mbed_new_session(cf, data);
|
||||
FALLTHROUGH();
|
||||
#endif
|
||||
case MBEDTLS_ERR_SSL_WANT_READ:
|
||||
*curlcode = CURLE_AGAIN;
|
||||
ret = -1;
|
||||
result = CURLE_AGAIN;
|
||||
break;
|
||||
case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
|
||||
*curlcode = CURLE_OK;
|
||||
ret = 0;
|
||||
result = CURLE_OK;
|
||||
break;
|
||||
default: {
|
||||
char errorbuf[128];
|
||||
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
|
||||
failf(data, "ssl_read returned: (-0x%04X) %s", -ret, errorbuf);
|
||||
*curlcode = CURLE_RECV_ERROR;
|
||||
ret = -1;
|
||||
mbedtls_strerror(nread, errorbuf, sizeof(errorbuf));
|
||||
failf(data, "ssl_read returned: (-0x%04X) %s", -nread, errorbuf);
|
||||
result = CURLE_RECV_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (ssize_t)ret;
|
||||
return result;
|
||||
}
|
||||
|
||||
static size_t mbedtls_version(char *buffer, size_t size)
|
||||
|
|
|
|||
|
|
@ -2177,6 +2177,8 @@ static CURLcode ossl_shutdown(struct Curl_cfilter *cf,
|
|||
|
||||
out:
|
||||
cf->shutdown = (result || *done);
|
||||
if(cf->shutdown || (connssl->io_need != CURL_SSL_IO_NEED_NONE))
|
||||
connssl->input_pending = FALSE;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -2188,6 +2190,7 @@ static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
(void)data;
|
||||
DEBUGASSERT(octx);
|
||||
|
||||
connssl->input_pending = FALSE;
|
||||
if(octx->ssl) {
|
||||
SSL_free(octx->ssl);
|
||||
octx->ssl = NULL;
|
||||
|
|
@ -5227,11 +5230,11 @@ static bool ossl_data_pending(struct Curl_cfilter *cf,
|
|||
return connssl->input_pending;
|
||||
}
|
||||
|
||||
static ssize_t ossl_send(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
const void *mem,
|
||||
size_t len,
|
||||
CURLcode *curlcode)
|
||||
static CURLcode ossl_send(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
const void *mem,
|
||||
size_t len,
|
||||
size_t *pnwritten)
|
||||
{
|
||||
/* SSL_write() is said to return 'int' while write() and send() returns
|
||||
'size_t' */
|
||||
|
|
@ -5239,39 +5242,39 @@ static ssize_t ossl_send(struct Curl_cfilter *cf,
|
|||
char error_buffer[256];
|
||||
sslerr_t sslerror;
|
||||
int memlen;
|
||||
int rc;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
|
||||
CURLcode result = CURLE_OK;
|
||||
int nwritten;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(octx);
|
||||
|
||||
*pnwritten = 0;
|
||||
ERR_clear_error();
|
||||
|
||||
connssl->io_need = CURL_SSL_IO_NEED_NONE;
|
||||
memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
|
||||
rc = SSL_write(octx->ssl, mem, memlen);
|
||||
nwritten = SSL_write(octx->ssl, mem, memlen);
|
||||
|
||||
if(rc <= 0) {
|
||||
err = SSL_get_error(octx->ssl, rc);
|
||||
if(nwritten > 0)
|
||||
*pnwritten = (size_t)nwritten;
|
||||
else {
|
||||
err = SSL_get_error(octx->ssl, nwritten);
|
||||
|
||||
switch(err) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
connssl->io_need = CURL_SSL_IO_NEED_RECV;
|
||||
*curlcode = CURLE_AGAIN;
|
||||
rc = -1;
|
||||
result = CURLE_AGAIN;
|
||||
goto out;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
*curlcode = CURLE_AGAIN;
|
||||
rc = -1;
|
||||
result = CURLE_AGAIN;
|
||||
goto out;
|
||||
case SSL_ERROR_SYSCALL:
|
||||
{
|
||||
int sockerr = SOCKERRNO;
|
||||
|
||||
if(octx->io_result == CURLE_AGAIN) {
|
||||
*curlcode = CURLE_AGAIN;
|
||||
rc = -1;
|
||||
result = CURLE_AGAIN;
|
||||
goto out;
|
||||
}
|
||||
sslerror = ERR_get_error();
|
||||
|
|
@ -5285,8 +5288,7 @@ static ssize_t ossl_send(struct Curl_cfilter *cf,
|
|||
|
||||
failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d",
|
||||
error_buffer, sockerr);
|
||||
*curlcode = CURLE_SEND_ERROR;
|
||||
rc = -1;
|
||||
result = CURLE_SEND_ERROR;
|
||||
goto out;
|
||||
}
|
||||
case SSL_ERROR_SSL: {
|
||||
|
|
@ -5295,49 +5297,50 @@ static ssize_t ossl_send(struct Curl_cfilter *cf,
|
|||
sslerror = ERR_get_error();
|
||||
failf(data, "SSL_write() error: %s",
|
||||
ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)));
|
||||
*curlcode = CURLE_SEND_ERROR;
|
||||
rc = -1;
|
||||
result = CURLE_SEND_ERROR;
|
||||
goto out;
|
||||
}
|
||||
default:
|
||||
/* a true error */
|
||||
failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d",
|
||||
SSL_ERROR_to_str(err), SOCKERRNO);
|
||||
*curlcode = CURLE_SEND_ERROR;
|
||||
rc = -1;
|
||||
result = CURLE_SEND_ERROR;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
*curlcode = CURLE_OK;
|
||||
|
||||
out:
|
||||
return (ssize_t)rc; /* number of bytes */
|
||||
return result;
|
||||
}
|
||||
|
||||
static ssize_t ossl_recv(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data, /* transfer */
|
||||
char *buf, /* store read data here */
|
||||
size_t buffersize, /* max amount to read */
|
||||
CURLcode *curlcode)
|
||||
static CURLcode ossl_recv(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data, /* transfer */
|
||||
char *buf, /* store read data here */
|
||||
size_t buffersize, /* max amount to read */
|
||||
size_t *pnread)
|
||||
{
|
||||
char error_buffer[256];
|
||||
unsigned long sslerror;
|
||||
ssize_t nread;
|
||||
int buffsize;
|
||||
struct connectdata *conn = cf->conn;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
|
||||
CURLcode result = CURLE_OK;
|
||||
int nread;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(octx);
|
||||
|
||||
*pnread = 0;
|
||||
ERR_clear_error();
|
||||
|
||||
connssl->io_need = CURL_SSL_IO_NEED_NONE;
|
||||
buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
|
||||
nread = (ssize_t)SSL_read(octx->ssl, buf, buffsize);
|
||||
nread = SSL_read(octx->ssl, buf, buffsize);
|
||||
|
||||
if(nread <= 0) {
|
||||
if(nread > 0)
|
||||
*pnread = (size_t)nread;
|
||||
else {
|
||||
/* failed SSL_read */
|
||||
int err = SSL_get_error(octx->ssl, (int)nread);
|
||||
|
||||
|
|
@ -5352,21 +5355,18 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf,
|
|||
connclose(conn, "TLS close_notify");
|
||||
break;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
*curlcode = CURLE_AGAIN;
|
||||
nread = -1;
|
||||
result = CURLE_AGAIN;
|
||||
goto out;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
connssl->io_need = CURL_SSL_IO_NEED_SEND;
|
||||
*curlcode = CURLE_AGAIN;
|
||||
nread = -1;
|
||||
result = CURLE_AGAIN;
|
||||
goto out;
|
||||
default:
|
||||
/* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return
|
||||
value/errno" */
|
||||
/* https://docs.openssl.org/master/man3/ERR_get_error/ */
|
||||
if(octx->io_result == CURLE_AGAIN) {
|
||||
*curlcode = CURLE_AGAIN;
|
||||
nread = -1;
|
||||
result = CURLE_AGAIN;
|
||||
goto out;
|
||||
}
|
||||
sslerror = ERR_get_error();
|
||||
|
|
@ -5383,18 +5383,17 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf,
|
|||
SSL_ERROR_to_str(err));
|
||||
failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d",
|
||||
error_buffer, sockerr);
|
||||
*curlcode = CURLE_RECV_ERROR;
|
||||
nread = -1;
|
||||
result = CURLE_RECV_ERROR;
|
||||
goto out;
|
||||
}
|
||||
else if(err == SSL_ERROR_SYSCALL) {
|
||||
if(octx->io_result) {
|
||||
/* logging handling in underlying filter already */
|
||||
*curlcode = octx->io_result;
|
||||
result = octx->io_result;
|
||||
}
|
||||
else if(connssl->peer_closed) {
|
||||
failf(data, "Connection closed abruptly");
|
||||
*curlcode = CURLE_RECV_ERROR;
|
||||
result = CURLE_RECV_ERROR;
|
||||
}
|
||||
else {
|
||||
/* We should no longer get here nowadays. But handle
|
||||
|
|
@ -5408,16 +5407,15 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf,
|
|||
}
|
||||
failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d",
|
||||
error_buffer, sockerr);
|
||||
*curlcode = CURLE_RECV_ERROR;
|
||||
result = CURLE_RECV_ERROR;
|
||||
}
|
||||
nread = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if(!nread || ((nread < 0) && (*curlcode == CURLE_AGAIN))) {
|
||||
if((!result && !*pnread) || (result == CURLE_AGAIN)) {
|
||||
/* This happens when:
|
||||
* - we read an EOF
|
||||
* - OpenSSLs buffers are empty, there is no more data
|
||||
|
|
@ -5426,7 +5424,9 @@ out:
|
|||
* until more data arrives */
|
||||
connssl->input_pending = FALSE;
|
||||
}
|
||||
return nread;
|
||||
CURL_TRC_CF(data, cf, "ossl_recv(len=%zu) -> %d, %zu (in_pending=%d)",
|
||||
buffersize, result, *pnread, connssl->input_pending);
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode ossl_get_channel_binding(struct Curl_easy *data, int sockindex,
|
||||
|
|
|
|||
|
|
@ -195,37 +195,37 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf,
|
|||
* buffer, and process packets, but will not consume bytes from Rustls'
|
||||
* plaintext output buffer.
|
||||
*/
|
||||
static ssize_t
|
||||
static CURLcode
|
||||
cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
char *plainbuf, size_t plainlen, CURLcode *err)
|
||||
char *plainbuf, size_t plainlen, size_t *pnread)
|
||||
{
|
||||
const struct ssl_connect_data *const connssl = cf->ctx;
|
||||
struct rustls_ssl_backend_data *const backend =
|
||||
(struct rustls_ssl_backend_data *)connssl->backend;
|
||||
struct rustls_connection *rconn = NULL;
|
||||
CURLcode result = CURLE_OK;
|
||||
size_t n = 0;
|
||||
size_t plain_bytes_copied = 0;
|
||||
rustls_result rresult = 0;
|
||||
ssize_t nread;
|
||||
bool eof = FALSE;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
*pnread = 0;
|
||||
rconn = backend->conn;
|
||||
|
||||
while(plain_bytes_copied < plainlen) {
|
||||
while(*pnread < plainlen) {
|
||||
if(!backend->data_in_pending) {
|
||||
if(tls_recv_more(cf, data, err) < 0) {
|
||||
if(*err != CURLE_AGAIN) {
|
||||
nread = -1;
|
||||
if(tls_recv_more(cf, data, &result) < 0) {
|
||||
if(result != CURLE_AGAIN) {
|
||||
goto out;
|
||||
}
|
||||
result = CURLE_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rresult = rustls_connection_read(rconn,
|
||||
(uint8_t *)plainbuf + plain_bytes_copied,
|
||||
plainlen - plain_bytes_copied,
|
||||
(uint8_t *)plainbuf + *pnread,
|
||||
plainlen - *pnread,
|
||||
&n);
|
||||
if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) {
|
||||
backend->data_in_pending = FALSE;
|
||||
|
|
@ -233,15 +233,13 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
else if(rresult == RUSTLS_RESULT_UNEXPECTED_EOF) {
|
||||
failf(data, "rustls: peer closed TCP connection "
|
||||
"without first closing TLS connection");
|
||||
*err = CURLE_RECV_ERROR;
|
||||
nread = -1;
|
||||
result = CURLE_RECV_ERROR;
|
||||
goto out;
|
||||
}
|
||||
else if(rresult != RUSTLS_RESULT_OK) {
|
||||
/* n always equals 0 in this case, do not need to check it */
|
||||
rustls_failf(data, rresult, "rustls_connection_read");
|
||||
*err = CURLE_RECV_ERROR;
|
||||
nread = -1;
|
||||
result = CURLE_RECV_ERROR;
|
||||
goto out;
|
||||
}
|
||||
else if(n == 0) {
|
||||
|
|
@ -252,27 +250,18 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
break;
|
||||
}
|
||||
else {
|
||||
plain_bytes_copied += n;
|
||||
*pnread += n;
|
||||
}
|
||||
}
|
||||
|
||||
if(plain_bytes_copied) {
|
||||
*err = CURLE_OK;
|
||||
nread = (ssize_t)plain_bytes_copied;
|
||||
}
|
||||
else if(eof) {
|
||||
*err = CURLE_OK;
|
||||
nread = 0;
|
||||
}
|
||||
else {
|
||||
*err = CURLE_AGAIN;
|
||||
nread = -1;
|
||||
if(!eof && !*pnread) {
|
||||
result = CURLE_AGAIN;
|
||||
}
|
||||
|
||||
out:
|
||||
CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d",
|
||||
plainlen, nread, *err);
|
||||
return nread;
|
||||
CURL_TRC_CF(data, cf, "rustls_recv(len=%zu) -> %d, %zu",
|
||||
plainlen, result, *pnread);
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
|
|
@ -320,9 +309,9 @@ static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
* In that case, it will not read anything into Rustls' plaintext input buffer.
|
||||
* It will only drain Rustls' plaintext output buffer into the socket.
|
||||
*/
|
||||
static ssize_t
|
||||
static CURLcode
|
||||
cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
const void *plainbuf, size_t plainlen, CURLcode *err)
|
||||
const void *plainbuf, size_t plainlen, size_t *pnwritten)
|
||||
{
|
||||
const struct ssl_connect_data *const connssl = cf->ctx;
|
||||
struct rustls_ssl_backend_data *const backend =
|
||||
|
|
@ -330,10 +319,11 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
struct rustls_connection *rconn = NULL;
|
||||
size_t plainwritten = 0;
|
||||
const unsigned char *buf = plainbuf;
|
||||
CURLcode result = CURLE_OK;
|
||||
size_t blen = plainlen;
|
||||
ssize_t nwritten = 0;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
*pnwritten = 0;
|
||||
rconn = backend->conn;
|
||||
DEBUGASSERT(rconn);
|
||||
|
||||
|
|
@ -344,18 +334,18 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
* if successful, deduct the previous plain bytes from the current
|
||||
* send. */
|
||||
if(backend->plain_out_buffered) {
|
||||
*err = cr_flush_out(cf, data, rconn);
|
||||
result = cr_flush_out(cf, data, rconn);
|
||||
CURL_TRC_CF(data, cf, "cf_send: flushing %zu previously added bytes -> %d",
|
||||
backend->plain_out_buffered, *err);
|
||||
if(*err)
|
||||
return -1;
|
||||
backend->plain_out_buffered, result);
|
||||
if(result)
|
||||
return result;
|
||||
if(blen > backend->plain_out_buffered) {
|
||||
blen -= backend->plain_out_buffered;
|
||||
buf += backend->plain_out_buffered;
|
||||
}
|
||||
else
|
||||
blen = 0;
|
||||
nwritten += (ssize_t)backend->plain_out_buffered;
|
||||
*pnwritten += (ssize_t)backend->plain_out_buffered;
|
||||
backend->plain_out_buffered = 0;
|
||||
}
|
||||
|
||||
|
|
@ -365,37 +355,35 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
rresult = rustls_connection_write(rconn, buf, blen, &plainwritten);
|
||||
if(rresult != RUSTLS_RESULT_OK) {
|
||||
rustls_failf(data, rresult, "rustls_connection_write");
|
||||
*err = CURLE_WRITE_ERROR;
|
||||
return -1;
|
||||
result = CURLE_WRITE_ERROR;
|
||||
goto out;
|
||||
}
|
||||
else if(plainwritten == 0) {
|
||||
failf(data, "rustls_connection_write: EOF");
|
||||
*err = CURLE_WRITE_ERROR;
|
||||
return -1;
|
||||
result = CURLE_WRITE_ERROR;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
*err = cr_flush_out(cf, data, rconn);
|
||||
if(*err) {
|
||||
if(CURLE_AGAIN == *err) {
|
||||
result = cr_flush_out(cf, data, rconn);
|
||||
if(result) {
|
||||
if(CURLE_AGAIN == result) {
|
||||
/* The TLS bytes may have been partially written, but we fail the
|
||||
* complete send() and remember how much we already added to Rustls. */
|
||||
CURL_TRC_CF(data, cf, "cf_send: EAGAIN, remember we added %zu plain"
|
||||
" bytes already to Rustls", blen);
|
||||
backend->plain_out_buffered = plainwritten;
|
||||
if(nwritten) {
|
||||
*err = CURLE_OK;
|
||||
return (ssize_t)nwritten;
|
||||
if(*pnwritten) {
|
||||
result = CURLE_OK;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
nwritten += (ssize_t)plainwritten;
|
||||
*pnwritten += (ssize_t)plainwritten;
|
||||
|
||||
CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %d, %zd",
|
||||
plainlen, *err, nwritten);
|
||||
return nwritten;
|
||||
out:
|
||||
CURL_TRC_CF(data, cf, "rustls_send(len=%zu) -> %d, %zd",
|
||||
plainlen, result, *pnwritten);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* A server certificate verify callback for Rustls that always returns
|
||||
|
|
@ -1184,8 +1172,9 @@ cr_connect(struct Curl_cfilter *cf,
|
|||
* send its FINISHED message off. We attempt to let it write
|
||||
* one more time. Oh my.
|
||||
*/
|
||||
size_t nwritten;
|
||||
cr_set_negotiated_alpn(cf, data, rconn);
|
||||
cr_send(cf, data, NULL, 0, &tmperr);
|
||||
tmperr = cr_send(cf, data, NULL, 0, &nwritten);
|
||||
if(tmperr == CURLE_AGAIN) {
|
||||
connssl->io_need = CURL_SSL_IO_NEED_SEND;
|
||||
return CURLE_OK;
|
||||
|
|
@ -1258,8 +1247,9 @@ cr_connect(struct Curl_cfilter *cf,
|
|||
DEBUGASSERT(wants_read || wants_write);
|
||||
|
||||
if(wants_write) {
|
||||
size_t nwritten;
|
||||
CURL_TRC_CF(data, cf, "rustls_connection wants us to write_tls.");
|
||||
cr_send(cf, data, NULL, 0, &tmperr);
|
||||
tmperr = cr_send(cf, data, NULL, 0, &nwritten);
|
||||
if(tmperr == CURLE_AGAIN) {
|
||||
CURL_TRC_CF(data, cf, "writing would block");
|
||||
connssl->io_need = CURL_SSL_IO_NEED_SEND;
|
||||
|
|
@ -1312,8 +1302,7 @@ cr_shutdown(struct Curl_cfilter *cf,
|
|||
struct rustls_ssl_backend_data *backend =
|
||||
(struct rustls_ssl_backend_data *)connssl->backend;
|
||||
CURLcode result = CURLE_OK;
|
||||
ssize_t nwritten, nread;
|
||||
size_t i;
|
||||
size_t i, nread, nwritten;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
if(!backend->conn || cf->shutdown) {
|
||||
|
|
@ -1332,8 +1321,8 @@ cr_shutdown(struct Curl_cfilter *cf,
|
|||
}
|
||||
}
|
||||
|
||||
nwritten = cr_send(cf, data, NULL, 0, &result);
|
||||
if(nwritten < 0) {
|
||||
result = cr_send(cf, data, NULL, 0, &nwritten);
|
||||
if(result) {
|
||||
if(result == CURLE_AGAIN) {
|
||||
connssl->io_need = CURL_SSL_IO_NEED_SEND;
|
||||
result = CURLE_OK;
|
||||
|
|
@ -1346,26 +1335,23 @@ cr_shutdown(struct Curl_cfilter *cf,
|
|||
|
||||
for(i = 0; i < 10; ++i) {
|
||||
char buf[1024];
|
||||
nread = cr_recv(cf, data, buf, (int)sizeof(buf), &result);
|
||||
if(nread <= 0)
|
||||
result = cr_recv(cf, data, buf, (int)sizeof(buf), &nread);
|
||||
if(result)
|
||||
break;
|
||||
}
|
||||
|
||||
if(nread > 0) {
|
||||
/* still data coming in? */
|
||||
if(result == CURLE_AGAIN) {
|
||||
connssl->io_need = CURL_SSL_IO_NEED_RECV;
|
||||
result = CURLE_OK;
|
||||
}
|
||||
else if(result) {
|
||||
DEBUGASSERT(result);
|
||||
CURL_TRC_CF(data, cf, "shutdown, error: %d", result);
|
||||
}
|
||||
else if(nread == 0) {
|
||||
/* We got the close notify alert and are done. */
|
||||
*done = TRUE;
|
||||
}
|
||||
else if(result == CURLE_AGAIN) {
|
||||
connssl->io_need = CURL_SSL_IO_NEED_RECV;
|
||||
result = CURLE_OK;
|
||||
}
|
||||
else {
|
||||
DEBUGASSERT(result);
|
||||
CURL_TRC_CF(data, cf, "shutdown, error: %d", result);
|
||||
}
|
||||
|
||||
out:
|
||||
cf->shutdown = (result || *done);
|
||||
|
|
|
|||
|
|
@ -1714,22 +1714,22 @@ static CURLcode schannel_connect(struct Curl_cfilter *cf,
|
|||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
static CURLcode
|
||||
schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
const void *buf, size_t len, CURLcode *err)
|
||||
const void *buf, size_t len, size_t *pnwritten)
|
||||
{
|
||||
ssize_t written = -1;
|
||||
size_t data_len = 0;
|
||||
unsigned char *ptr = NULL;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
SecBuffer outbuf[4];
|
||||
SecBufferDesc outbuf_desc;
|
||||
SECURITY_STATUS sspi_status = SEC_E_OK;
|
||||
CURLcode result;
|
||||
CURLcode result = CURLE_OK;
|
||||
struct schannel_ssl_backend_data *backend =
|
||||
(struct schannel_ssl_backend_data *)connssl->backend;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
*pnwritten = 0;
|
||||
|
||||
/* check if the maximum stream sizes were queried */
|
||||
if(backend->stream_sizes.cbMaximumMessage == 0) {
|
||||
|
|
@ -1738,8 +1738,7 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
SECPKG_ATTR_STREAM_SIZES,
|
||||
&backend->stream_sizes);
|
||||
if(sspi_status != SEC_E_OK) {
|
||||
*err = CURLE_SEND_ERROR;
|
||||
return -1;
|
||||
return CURLE_SEND_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1753,8 +1752,7 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
backend->stream_sizes.cbTrailer;
|
||||
ptr = (unsigned char *) malloc(data_len);
|
||||
if(!ptr) {
|
||||
*err = CURLE_OUT_OF_MEMORY;
|
||||
return -1;
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
/* setup output buffers (header, data, trailer, empty) */
|
||||
|
|
@ -1777,7 +1775,6 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
|
||||
/* check if the message was encrypted */
|
||||
if(sspi_status == SEC_E_OK) {
|
||||
written = 0;
|
||||
|
||||
/* send the encrypted message including header, data and trailer */
|
||||
len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
|
||||
|
|
@ -1799,16 +1796,15 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
*/
|
||||
|
||||
/* send entire message or fail */
|
||||
while(len > (size_t)written) {
|
||||
while(len > *pnwritten) {
|
||||
size_t this_write = 0;
|
||||
int what;
|
||||
timediff_t timeout_ms = Curl_timeleft(data, NULL, FALSE);
|
||||
if(timeout_ms < 0) {
|
||||
/* we already got the timeout */
|
||||
failf(data, "schannel: timed out sending data "
|
||||
"(bytes sent: %zd)", written);
|
||||
*err = CURLE_OPERATION_TIMEDOUT;
|
||||
written = -1;
|
||||
"(bytes sent: %zu)", *pnwritten);
|
||||
result = CURLE_OPERATION_TIMEDOUT;
|
||||
break;
|
||||
}
|
||||
else if(!timeout_ms)
|
||||
|
|
@ -1817,53 +1813,49 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
if(what < 0) {
|
||||
/* fatal error */
|
||||
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
|
||||
*err = CURLE_SEND_ERROR;
|
||||
written = -1;
|
||||
result = CURLE_SEND_ERROR;
|
||||
break;
|
||||
}
|
||||
else if(0 == what) {
|
||||
failf(data, "schannel: timed out sending data "
|
||||
"(bytes sent: %zd)", written);
|
||||
*err = CURLE_OPERATION_TIMEDOUT;
|
||||
written = -1;
|
||||
"(bytes sent: %zu)", *pnwritten);
|
||||
result = CURLE_OPERATION_TIMEDOUT;
|
||||
break;
|
||||
}
|
||||
/* socket is writable */
|
||||
|
||||
result = Curl_conn_cf_send(cf->next, data,
|
||||
ptr + written, len - written,
|
||||
ptr + *pnwritten, len - *pnwritten,
|
||||
FALSE, &this_write);
|
||||
if(result == CURLE_AGAIN)
|
||||
continue;
|
||||
else if(result != CURLE_OK) {
|
||||
*err = result;
|
||||
written = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
written += (ssize_t)this_write;
|
||||
*pnwritten += this_write;
|
||||
}
|
||||
}
|
||||
else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
|
||||
*err = CURLE_OUT_OF_MEMORY;
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
else{
|
||||
*err = CURLE_SEND_ERROR;
|
||||
result = CURLE_SEND_ERROR;
|
||||
}
|
||||
|
||||
Curl_safefree(ptr);
|
||||
|
||||
if(len == (size_t)written)
|
||||
if(len == *pnwritten)
|
||||
/* Encrypted message including header, data and trailer entirely sent.
|
||||
The return value is the number of unencrypted bytes that were sent. */
|
||||
written = outbuf[1].cbBuffer;
|
||||
*pnwritten = outbuf[1].cbBuffer;
|
||||
|
||||
return written;
|
||||
return result;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
static CURLcode
|
||||
schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
char *buf, size_t len, CURLcode *err)
|
||||
char *buf, size_t len, size_t *pnread)
|
||||
{
|
||||
size_t size = 0;
|
||||
size_t nread = 0;
|
||||
|
|
@ -1879,8 +1871,10 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
|
||||
struct schannel_ssl_backend_data *backend =
|
||||
(struct schannel_ssl_backend_data *)connssl->backend;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
*pnread = 0;
|
||||
|
||||
/****************************************************************************
|
||||
* Do not return or set backend->recv_unrecoverable_err unless in the
|
||||
|
|
@ -1899,7 +1893,6 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
*/
|
||||
|
||||
SCH_DEV(infof(data, "schannel: client wants to read %zu bytes", len));
|
||||
*err = CURLE_OK;
|
||||
|
||||
if(len && len <= backend->decdata_offset) {
|
||||
SCH_DEV(infof(data,
|
||||
|
|
@ -1907,7 +1900,7 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
goto cleanup;
|
||||
}
|
||||
else if(backend->recv_unrecoverable_err) {
|
||||
*err = backend->recv_unrecoverable_err;
|
||||
result = backend->recv_unrecoverable_err;
|
||||
infof(data, "schannel: an unrecoverable error occurred in a prior call");
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -1933,7 +1926,7 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
reallocated_buffer = realloc(backend->encdata_buffer,
|
||||
reallocated_length);
|
||||
if(!reallocated_buffer) {
|
||||
*err = CURLE_OUT_OF_MEMORY;
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
failf(data, "schannel: unable to re-allocate memory");
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -1950,17 +1943,17 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
backend->encdata_offset, backend->encdata_length));
|
||||
|
||||
/* read encrypted data from socket */
|
||||
*err = Curl_conn_cf_recv(cf->next, data,
|
||||
result = Curl_conn_cf_recv(cf->next, data,
|
||||
(char *)(backend->encdata_buffer +
|
||||
backend->encdata_offset),
|
||||
size, &nread);
|
||||
if(*err) {
|
||||
if(*err == CURLE_AGAIN)
|
||||
if(result) {
|
||||
if(result == CURLE_AGAIN)
|
||||
SCH_DEV(infof(data, "schannel: recv returned CURLE_AGAIN"));
|
||||
else if(*err == CURLE_RECV_ERROR)
|
||||
else if(result == CURLE_RECV_ERROR)
|
||||
infof(data, "schannel: recv returned CURLE_RECV_ERROR");
|
||||
else
|
||||
infof(data, "schannel: recv returned error %d", *err);
|
||||
infof(data, "schannel: recv returned error %d", result);
|
||||
}
|
||||
else if(nread == 0) {
|
||||
backend->recv_connection_closed = TRUE;
|
||||
|
|
@ -2019,7 +2012,7 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
reallocated_buffer = realloc(backend->decdata_buffer,
|
||||
reallocated_length);
|
||||
if(!reallocated_buffer) {
|
||||
*err = CURLE_OUT_OF_MEMORY;
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
failf(data, "schannel: unable to re-allocate memory");
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -2070,7 +2063,7 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
/* check if server wants to renegotiate the connection context */
|
||||
if(sspi_status == SEC_I_RENEGOTIATE) {
|
||||
infof(data, "schannel: remote party requests renegotiation");
|
||||
if(*err && *err != CURLE_AGAIN) {
|
||||
if(result && result != CURLE_AGAIN) {
|
||||
infof(data, "schannel: cannot renegotiate, an error is pending");
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -2081,9 +2074,9 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
connssl->connecting_state = ssl_connect_2;
|
||||
connssl->io_need = CURL_SSL_IO_NEED_SEND;
|
||||
backend->recv_renegotiating = TRUE;
|
||||
*err = schannel_connect(cf, data, &done);
|
||||
result = schannel_connect(cf, data, &done);
|
||||
backend->recv_renegotiating = FALSE;
|
||||
if(*err) {
|
||||
if(result) {
|
||||
infof(data, "schannel: renegotiation failed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -2102,8 +2095,8 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
/* We received the close notify just fine, any error we got
|
||||
* from the lower filters afterwards (e.g. the socket), is not
|
||||
* an error on the TLS data stream. That one ended here. */
|
||||
if(*err == CURLE_RECV_ERROR)
|
||||
*err = CURLE_OK;
|
||||
if(result == CURLE_RECV_ERROR)
|
||||
result = CURLE_OK;
|
||||
infof(data,
|
||||
"schannel: server close notification received (close_notify)");
|
||||
goto cleanup;
|
||||
|
|
@ -2111,8 +2104,8 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
}
|
||||
else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
|
||||
backend->encdata_is_incomplete = TRUE;
|
||||
if(!*err)
|
||||
*err = CURLE_AGAIN;
|
||||
if(!result)
|
||||
result = CURLE_AGAIN;
|
||||
SCH_DEV(infof(data, "schannel: failed to decrypt data, need more data"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -2122,7 +2115,7 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
failf(data, "schannel: failed to read data from server: %s",
|
||||
Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
|
||||
#endif
|
||||
*err = CURLE_RECV_ERROR;
|
||||
result = CURLE_RECV_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
|
@ -2145,13 +2138,13 @@ cleanup:
|
|||
*/
|
||||
if(len && !backend->decdata_offset && backend->recv_connection_closed &&
|
||||
!backend->recv_sspi_close_notify) {
|
||||
*err = CURLE_RECV_ERROR;
|
||||
result = CURLE_RECV_ERROR;
|
||||
failf(data, "schannel: server closed abruptly (missing close_notify)");
|
||||
}
|
||||
|
||||
/* Any error other than CURLE_AGAIN is an unrecoverable error. */
|
||||
if(*err && *err != CURLE_AGAIN)
|
||||
backend->recv_unrecoverable_err = *err;
|
||||
if(result && result != CURLE_AGAIN)
|
||||
backend->recv_unrecoverable_err = result;
|
||||
|
||||
size = len < backend->decdata_offset ? len : backend->decdata_offset;
|
||||
if(size) {
|
||||
|
|
@ -2163,21 +2156,21 @@ cleanup:
|
|||
SCH_DEV(infof(data,
|
||||
"schannel: decrypted data buffer: offset %zu length %zu",
|
||||
backend->decdata_offset, backend->decdata_length));
|
||||
*err = CURLE_OK;
|
||||
return (ssize_t)size;
|
||||
*pnread = size;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
if(!*err && !backend->recv_connection_closed)
|
||||
*err = CURLE_AGAIN;
|
||||
if(!result && !backend->recv_connection_closed)
|
||||
result = CURLE_AGAIN;
|
||||
|
||||
/* it is debatable what to return when !len. We could return whatever error
|
||||
we got from decryption but instead we override here so the return is
|
||||
consistent.
|
||||
*/
|
||||
if(!len)
|
||||
*err = CURLE_OK;
|
||||
return CURLE_OK;
|
||||
|
||||
return *err ? -1 : 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool schannel_data_pending(struct Curl_cfilter *cf,
|
||||
|
|
@ -2319,23 +2312,23 @@ static CURLcode schannel_shutdown(struct Curl_cfilter *cf,
|
|||
if(backend->cred && backend->ctxt &&
|
||||
!backend->recv_sspi_close_notify && !backend->recv_connection_closed) {
|
||||
char buffer[1024];
|
||||
ssize_t nread;
|
||||
size_t nread;
|
||||
|
||||
nread = schannel_recv(cf, data, buffer, sizeof(buffer), &result);
|
||||
if(nread > 0) {
|
||||
/* still data coming in? */
|
||||
result = schannel_recv(cf, data, buffer, sizeof(buffer), &nread);
|
||||
if(result == CURLE_AGAIN) {
|
||||
connssl->io_need = CURL_SSL_IO_NEED_RECV;
|
||||
}
|
||||
else if(result) {
|
||||
CURL_TRC_CF(data, cf, "SSL shutdown, error %d", result);
|
||||
result = CURLE_RECV_ERROR;
|
||||
}
|
||||
else if(nread == 0) {
|
||||
/* We got the close notify alert and are done. */
|
||||
backend->recv_connection_closed = TRUE;
|
||||
*done = TRUE;
|
||||
}
|
||||
else if(nread < 0 && result == CURLE_AGAIN) {
|
||||
connssl->io_need = CURL_SSL_IO_NEED_RECV;
|
||||
}
|
||||
else {
|
||||
CURL_TRC_CF(data, cf, "SSL shutdown, error %d", result);
|
||||
result = CURLE_RECV_ERROR;
|
||||
/* still data coming in? */
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -917,23 +917,23 @@ static void multissl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
Curl_ssl->close(cf, data);
|
||||
}
|
||||
|
||||
static ssize_t multissl_recv_plain(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
char *buf, size_t len, CURLcode *code)
|
||||
static CURLcode multissl_recv_plain(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
char *buf, size_t len, size_t *pnread)
|
||||
{
|
||||
if(multissl_setup(NULL))
|
||||
return CURLE_FAILED_INIT;
|
||||
return Curl_ssl->recv_plain(cf, data, buf, len, code);
|
||||
return Curl_ssl->recv_plain(cf, data, buf, len, pnread);
|
||||
}
|
||||
|
||||
static ssize_t multissl_send_plain(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
const void *mem, size_t len,
|
||||
CURLcode *code)
|
||||
static CURLcode multissl_send_plain(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
const void *mem, size_t len,
|
||||
size_t *pnwritten)
|
||||
{
|
||||
if(multissl_setup(NULL))
|
||||
return CURLE_FAILED_INIT;
|
||||
return Curl_ssl->send_plain(cf, data, mem, len, code);
|
||||
return Curl_ssl->send_plain(cf, data, mem, len, pnwritten);
|
||||
}
|
||||
|
||||
static const struct Curl_ssl Curl_ssl_multi = {
|
||||
|
|
@ -1474,10 +1474,10 @@ static CURLcode ssl_cf_send(struct Curl_cfilter *cf,
|
|||
|
||||
/* OpenSSL and maybe other TLS libs do not like 0-length writes. Skip. */
|
||||
if(blen > 0) {
|
||||
ssize_t nwritten;
|
||||
nwritten = connssl->ssl_impl->send_plain(cf, data, buf, blen, &result);
|
||||
if(nwritten > 0)
|
||||
*pnwritten += (size_t)nwritten;
|
||||
size_t nwritten;
|
||||
result = connssl->ssl_impl->send_plain(cf, data, buf, blen, &nwritten);
|
||||
if(!result)
|
||||
*pnwritten += nwritten;
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
@ -1492,7 +1492,6 @@ static CURLcode ssl_cf_recv(struct Curl_cfilter *cf,
|
|||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct cf_call_data save;
|
||||
CURLcode result = CURLE_OK;
|
||||
ssize_t nread;
|
||||
|
||||
CF_DATA_SAVE(save, cf, data);
|
||||
*pnread = 0;
|
||||
|
|
@ -1508,19 +1507,9 @@ static CURLcode ssl_cf_recv(struct Curl_cfilter *cf,
|
|||
DEBUGASSERT(connssl->state == ssl_connection_complete);
|
||||
}
|
||||
|
||||
nread = connssl->ssl_impl->recv_plain(cf, data, buf, len, &result);
|
||||
if(nread > 0) {
|
||||
DEBUGASSERT((size_t)nread <= len);
|
||||
*pnread = (size_t)nread;
|
||||
}
|
||||
else if(nread == 0) {
|
||||
/* eof */
|
||||
result = CURLE_OK;
|
||||
}
|
||||
result = connssl->ssl_impl->recv_plain(cf, data, buf, len, pnread);
|
||||
|
||||
out:
|
||||
CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %d, %zd", len,
|
||||
result, *pnread);
|
||||
CF_DATA_RESTORE(cf, save);
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -178,10 +178,10 @@ struct Curl_ssl {
|
|||
|
||||
CURLcode (*sha256sum)(const unsigned char *input, size_t inputlen,
|
||||
unsigned char *sha256sum, size_t sha256sumlen);
|
||||
ssize_t (*recv_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
char *buf, size_t len, CURLcode *code);
|
||||
ssize_t (*send_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
const void *mem, size_t len, CURLcode *code);
|
||||
CURLcode (*recv_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
char *buf, size_t len, size_t *pnread);
|
||||
CURLcode (*send_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
const void *mem, size_t len, size_t *pnwritten);
|
||||
|
||||
CURLcode (*get_channel_binding)(struct Curl_easy *data, int sockindex,
|
||||
struct dynbuf *binding);
|
||||
|
|
|
|||
|
|
@ -1789,49 +1789,48 @@ static CURLcode wssl_handshake(struct Curl_cfilter *cf,
|
|||
}
|
||||
}
|
||||
|
||||
static ssize_t wssl_send(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
const void *buf, size_t blen,
|
||||
CURLcode *curlcode)
|
||||
static CURLcode wssl_send(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
const void *buf, size_t blen,
|
||||
size_t *pnwritten)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
|
||||
size_t total_written = 0;
|
||||
ssize_t nwritten = -1;
|
||||
DEBUGASSERT(wssl);
|
||||
CURLcode result = CURLE_OK;
|
||||
int nwritten;
|
||||
|
||||
DEBUGASSERT(wssl);
|
||||
*pnwritten = 0;
|
||||
wolfSSL_ERR_clear_error();
|
||||
|
||||
if(blen) {
|
||||
int memlen = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen;
|
||||
int rc;
|
||||
|
||||
rc = wolfSSL_write(wssl->ssl, buf, memlen);
|
||||
if(rc <= 0) {
|
||||
int err = wolfSSL_get_error(wssl->ssl, rc);
|
||||
nwritten = wolfSSL_write(wssl->ssl, buf, memlen);
|
||||
|
||||
if(nwritten > 0)
|
||||
*pnwritten += (size_t)nwritten;
|
||||
else {
|
||||
int err = wolfSSL_get_error(wssl->ssl, nwritten);
|
||||
|
||||
switch(err) {
|
||||
case WOLFSSL_ERROR_WANT_READ:
|
||||
case WOLFSSL_ERROR_WANT_WRITE:
|
||||
/* there is data pending, re-invoke wolfSSL_write() */
|
||||
if(total_written) {
|
||||
*curlcode = CURLE_OK;
|
||||
nwritten = total_written;
|
||||
if(*pnwritten) {
|
||||
result = CURLE_OK;
|
||||
goto out;
|
||||
}
|
||||
*curlcode = CURLE_AGAIN;
|
||||
nwritten = -1;
|
||||
result = CURLE_AGAIN;
|
||||
goto out;
|
||||
|
||||
default:
|
||||
if(wssl->io_result == CURLE_AGAIN) {
|
||||
if(total_written) {
|
||||
*curlcode = CURLE_OK;
|
||||
nwritten = total_written;
|
||||
if(*pnwritten) {
|
||||
result = CURLE_OK;
|
||||
goto out;
|
||||
}
|
||||
*curlcode = CURLE_AGAIN;
|
||||
nwritten = -1;
|
||||
result = CURLE_AGAIN;
|
||||
goto out;
|
||||
}
|
||||
{
|
||||
|
|
@ -1841,21 +1840,16 @@ static ssize_t wssl_send(struct Curl_cfilter *cf,
|
|||
sizeof(error_buffer)),
|
||||
SOCKERRNO);
|
||||
}
|
||||
*curlcode = CURLE_SEND_ERROR;
|
||||
nwritten = -1;
|
||||
result = CURLE_SEND_ERROR;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else
|
||||
total_written += rc;
|
||||
}
|
||||
|
||||
*curlcode = CURLE_OK;
|
||||
nwritten = total_written;
|
||||
out:
|
||||
CURL_TRC_CF(data, cf, "wssl_send(len=%zu) -> %" FMT_OFF_T ", %d",
|
||||
blen, nwritten, *curlcode);
|
||||
return nwritten;
|
||||
CURL_TRC_CF(data, cf, "wssl_send(len=%zu) -> %d, %zu",
|
||||
blen, result, *pnwritten);
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode wssl_shutdown(struct Curl_cfilter *cf,
|
||||
|
|
@ -1982,10 +1976,10 @@ static void wssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
}
|
||||
}
|
||||
|
||||
static ssize_t wssl_recv(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
char *buf, size_t blen,
|
||||
CURLcode *curlcode)
|
||||
static CURLcode wssl_recv(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
char *buf, size_t blen,
|
||||
size_t *pnread)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
|
||||
|
|
@ -1994,36 +1988,34 @@ static ssize_t wssl_recv(struct Curl_cfilter *cf,
|
|||
|
||||
DEBUGASSERT(wssl);
|
||||
|
||||
*pnread = 0;
|
||||
wolfSSL_ERR_clear_error();
|
||||
*curlcode = CURLE_OK;
|
||||
|
||||
nread = wolfSSL_read(wssl->ssl, buf, buffsize);
|
||||
|
||||
if(nread <= 0) {
|
||||
if(nread > 0)
|
||||
*pnread = (size_t)nread;
|
||||
else {
|
||||
int err = wolfSSL_get_error(wssl->ssl, nread);
|
||||
|
||||
switch(err) {
|
||||
case WOLFSSL_ERROR_ZERO_RETURN: /* no more data */
|
||||
CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> CLOSED", blen);
|
||||
*curlcode = CURLE_OK;
|
||||
return 0;
|
||||
return CURLE_OK;
|
||||
case WOLFSSL_ERROR_NONE:
|
||||
case WOLFSSL_ERROR_WANT_READ:
|
||||
case WOLFSSL_ERROR_WANT_WRITE:
|
||||
if(!wssl->io_result && connssl->peer_closed) {
|
||||
CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> CLOSED", blen);
|
||||
*curlcode = CURLE_OK;
|
||||
return 0;
|
||||
return CURLE_OK;
|
||||
}
|
||||
/* there is data pending, re-invoke wolfSSL_read() */
|
||||
CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> AGAIN", blen);
|
||||
*curlcode = CURLE_AGAIN;
|
||||
return -1;
|
||||
return CURLE_AGAIN;
|
||||
default:
|
||||
if(wssl->io_result == CURLE_AGAIN) {
|
||||
CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> AGAIN", blen);
|
||||
*curlcode = CURLE_AGAIN;
|
||||
return -1;
|
||||
return CURLE_AGAIN;
|
||||
}
|
||||
else if(!wssl->io_result && connssl->peer_closed) {
|
||||
CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> CLOSED", blen);
|
||||
|
|
@ -2036,13 +2028,12 @@ static ssize_t wssl_recv(struct Curl_cfilter *cf,
|
|||
sizeof(error_buffer)),
|
||||
SOCKERRNO);
|
||||
}
|
||||
*curlcode = CURLE_RECV_ERROR;
|
||||
return -1;
|
||||
return CURLE_RECV_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> %d", blen, nread);
|
||||
return nread;
|
||||
CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> 0, %zu", blen, *pnread);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
size_t Curl_wssl_version(char *buffer, size_t size)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue