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;
}
/*
#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)
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
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,
}
}
-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)
out:
cf->shutdown = (result || *done);
+ if(cf->shutdown || (connssl->io_need != CURL_SSL_IO_NEED_NONE))
+ connssl->input_pending = FALSE;
return result;
}
(void)data;
DEBUGASSERT(octx);
+ connssl->input_pending = FALSE;
if(octx->ssl) {
SSL_free(octx->ssl);
octx->ssl = NULL;
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' */
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();
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: {
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);
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();
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
}
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
* 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,
* 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;
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) {
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,
* 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 =
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);
* 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;
}
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
* 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;
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;
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) {
}
}
- 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;
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? */
- }
- else if(nread == 0) {
- /* We got the close notify alert and are done. */
- *done = TRUE;
- }
- else if(result == CURLE_AGAIN) {
+ if(result == CURLE_AGAIN) {
connssl->io_need = CURL_SSL_IO_NEED_RECV;
result = CURLE_OK;
}
- else {
+ 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;
+ }
out:
cf->shutdown = (result || *done);
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) {
SECPKG_ATTR_STREAM_SIZES,
&backend->stream_sizes);
if(sspi_status != SEC_E_OK) {
- *err = CURLE_SEND_ERROR;
- return -1;
+ return CURLE_SEND_ERROR;
}
}
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) */
/* 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;
*/
/* 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)
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;
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
*/
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,
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;
}
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;
}
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;
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;
}
/* 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;
}
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;
}
/* 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;
}
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;
}
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;
}
}
*/
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) {
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,
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? */
}
}
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 = {
/* 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:
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;
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;
}
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);
}
}
-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;
}
{
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,
}
}
-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;
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);
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)