WOLFSSL_BIO_SSL BIO should use remaining chain for IO

This is accomplished by passing the next BIO in the chain in to the `wolfSSL_set_bio` API.
pull/3824/head
Juliusz Sosinowicz 2021-02-26 17:05:07 +01:00
parent 4c1a94a6ad
commit d7838155e5
7 changed files with 196 additions and 62 deletions

View File

@ -202,8 +202,9 @@ int wolfSSL_BIO_read(WOLFSSL_BIO* bio, void* buf, int len)
}
}
/* start at end of list and work backwards */
while ((bio != NULL) && (bio->next != NULL)) {
/* start at end of list (or a WOLFSSL_BIO_SSL object since it takes care of
* the rest of the chain) and work backwards */
while (bio != NULL && bio->next != NULL && bio->type != WOLFSSL_BIO_SSL) {
bio = bio->next;
}
@ -250,6 +251,10 @@ int wolfSSL_BIO_read(WOLFSSL_BIO* bio, void* buf, int len)
}
#endif
if (bio->type == WOLFSSL_BIO_SOCKET) {
ret = wolfIO_Recv(bio->num, (char*)buf, len, 0);
}
/* case where front of list is done */
if (bio == front) {
break; /* at front of list so be done */
@ -606,6 +611,8 @@ int wolfSSL_BIO_write(WOLFSSL_BIO* bio, const void* data, int len)
else {
ret = wolfSSL_BIO_SSL_write(bio, data, len, front);
}
/* Rest of chain is taken care of inside call */
break;
}
if (bio->type == WOLFSSL_BIO_MD) {
@ -615,6 +622,10 @@ int wolfSSL_BIO_write(WOLFSSL_BIO* bio, const void* data, int len)
}
#endif /* WOLFCRYPT_ONLY */
if (bio->type == WOLFSSL_BIO_SOCKET) {
ret = wolfIO_Send(bio->num, (char*)data, len, 0);
}
/* advance to the next bio in list */
bio = bio->next;
}
@ -944,6 +955,21 @@ size_t wolfSSL_BIO_wpending(const WOLFSSL_BIO *bio)
return 0;
}
/* Custom wolfSSL API to check if current bio object supports checking
* pending state.
*/
int wolfSSL_BIO_supports_pending(const WOLFSSL_BIO *bio)
{
while (bio) {
if (bio->type == WOLFSSL_BIO_SSL ||
bio->type == WOLFSSL_BIO_MEMORY ||
bio->type == WOLFSSL_BIO_BIO)
return 1;
bio = bio->next;
}
return 0;
}
/* Return the number of pending bytes in read and write buffers */
size_t wolfSSL_BIO_ctrl_pending(WOLFSSL_BIO *bio)
{

View File

@ -6426,9 +6426,14 @@ void SSL_ResourceFree(WOLFSSL* ssl)
#endif /* WOLFSSL_DTLS */
#ifdef OPENSSL_EXTRA
#ifndef NO_BIO
/* Don't free if there was/is a previous element in the chain.
* This means that this BIO was part of a chain that will be
* free'd separately. */
if (ssl->biord != ssl->biowr) /* only free write if different */
wolfSSL_BIO_free(ssl->biowr);
wolfSSL_BIO_free(ssl->biord); /* always free read bio */
if (ssl->biowr != NULL && ssl->biowr->prev == NULL)
wolfSSL_BIO_free(ssl->biowr);
if (ssl->biord != NULL && ssl->biord->prev == NULL)
wolfSSL_BIO_free(ssl->biord);
ssl->biowr = NULL;
ssl->biord = NULL;
#endif

View File

@ -15136,37 +15136,27 @@ int wolfSSL_set_compression(WOLFSSL* ssl)
return;
}
/* if WOLFSSL_BIO is socket type then set WOLFSSL socket to use */
if (rd != NULL && rd->type == WOLFSSL_BIO_SOCKET) {
wolfSSL_set_rfd(ssl, rd->num);
}
if (wr != NULL && wr->type == WOLFSSL_BIO_SOCKET) {
wolfSSL_set_wfd(ssl, wr->num);
}
/* free any existing WOLFSSL_BIOs in use */
/* free any existing WOLFSSL_BIOs in use but don't free those in
* a chain */
if (ssl->biord != NULL) {
if (ssl->biord != ssl->biowr) {
if (ssl->biowr != NULL) {
if (ssl->biowr != NULL && ssl->biowr->prev != NULL)
wolfSSL_BIO_free(ssl->biowr);
ssl->biowr = NULL;
}
ssl->biowr = NULL;
}
wolfSSL_BIO_free(ssl->biord);
if (ssl->biord->prev != NULL)
wolfSSL_BIO_free(ssl->biord);
ssl->biord = NULL;
}
ssl->biord = rd;
ssl->biowr = wr;
/* set SSL to use BIO callbacks instead */
if (((ssl->cbioFlag & WOLFSSL_CBIO_RECV) == 0) &&
(rd != NULL && rd->type != WOLFSSL_BIO_SOCKET)) {
if (((ssl->cbioFlag & WOLFSSL_CBIO_RECV) == 0)) {
ssl->CBIORecv = BioReceive;
}
if (((ssl->cbioFlag & WOLFSSL_CBIO_SEND) == 0) &&
(wr != NULL && wr->type != WOLFSSL_BIO_SOCKET)) {
if (((ssl->cbioFlag & WOLFSSL_CBIO_SEND) == 0)) {
ssl->CBIOSend = BioSend;
}
@ -16049,6 +16039,21 @@ int wolfSSL_set_compression(WOLFSSL* ssl)
return 0;
}
long wolfSSL_BIO_do_handshake(WOLFSSL_BIO *b)
{
WOLFSSL_ENTER("wolfSSL_BIO_do_handshake");
if (b == NULL) {
WOLFSSL_MSG("Bad parameter");
return WOLFSSL_FAILURE;
}
if (b->type == WOLFSSL_BIO_SSL && b->ptr != NULL) {
return wolfSSL_negotiate((WOLFSSL*)b->ptr);
}
else {
WOLFSSL_MSG("Not SSL BIO or no SSL object set");
return WOLFSSL_FAILURE;
}
}
long wolfSSL_BIO_set_ssl(WOLFSSL_BIO* b, WOLFSSL* ssl, int closeF)
{
@ -16059,6 +16064,8 @@ int wolfSSL_set_compression(WOLFSSL* ssl)
if (b != NULL) {
b->ptr = ssl;
b->shutdown = (byte)closeF;
if (b->next != NULL)
wolfSSL_set_bio(ssl, b->next, b->next);
/* add to ssl for bio free if SSL_free called before/instead of free_all? */
ret = WOLFSSL_SUCCESS;
}
@ -16280,6 +16287,10 @@ int wolfSSL_set_compression(WOLFSSL* ssl)
top->next = append;
append->prev = top;
/* SSL BIO's should use the next object in the chain for IO */
if (top->type == WOLFSSL_BIO_SSL && top->ptr)
wolfSSL_set_bio((WOLFSSL*)top->ptr, append, append);
return top;
}
#endif /* !NO_BIO */

View File

@ -133,31 +133,46 @@ int BioReceive(WOLFSSL* ssl, char* buf, int sz, void* ctx)
return WOLFSSL_CBIO_ERR_GENERAL;
}
if (ssl->biord->method && ssl->biord->method->readCb) {
WOLFSSL_MSG("Calling custom biord");
recvd = ssl->biord->method->readCb(ssl->biord, buf, sz);
if (recvd < 0 && recvd != WOLFSSL_CBIO_ERR_WANT_READ)
return WOLFSSL_CBIO_ERR_GENERAL;
return recvd;
if (wolfSSL_BIO_supports_pending(ssl->biord) &&
wolfSSL_BIO_ctrl_pending(ssl->biord) == 0) {
WOLFSSL_MSG("BIO want read");
return WOLFSSL_CBIO_ERR_WANT_READ;
}
recvd = wolfSSL_BIO_read(ssl->biord, buf, sz);
if (recvd <= 0) {
if (ssl->biord->type == WOLFSSL_BIO_SOCKET) {
int err;
switch (ssl->biord->type) {
case WOLFSSL_BIO_MEMORY:
case WOLFSSL_BIO_BIO:
if (wolfSSL_BIO_ctrl_pending(ssl->biord) == 0) {
WOLFSSL_MSG("BIO want read");
return WOLFSSL_CBIO_ERR_WANT_READ;
if (recvd == 0) {
WOLFSSL_MSG("BioReceive connection closed");
return WOLFSSL_CBIO_ERR_CONN_CLOSE;
}
recvd = wolfSSL_BIO_read(ssl->biord, buf, sz);
if (recvd <= 0) {
WOLFSSL_MSG("BIO general error");
err = wolfSSL_LastError(recvd);
if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
WOLFSSL_MSG("\tWould block");
return WOLFSSL_CBIO_ERR_WANT_READ;
}
else if (err == SOCKET_ECONNRESET) {
WOLFSSL_MSG("\tConnection reset");
return WOLFSSL_CBIO_ERR_CONN_RST;
}
else if (err == SOCKET_EINTR) {
WOLFSSL_MSG("\tSocket interrupted");
return WOLFSSL_CBIO_ERR_ISR;
}
else if (err == SOCKET_ECONNABORTED) {
WOLFSSL_MSG("\tConnection aborted");
return WOLFSSL_CBIO_ERR_CONN_CLOSE;
}
else {
WOLFSSL_MSG("\tGeneral error");
return WOLFSSL_CBIO_ERR_GENERAL;
}
break;
}
default:
WOLFSSL_MSG("This BIO type is unknown / unsupported");
return WOLFSSL_CBIO_ERR_GENERAL;
WOLFSSL_MSG("BIO general error");
return WOLFSSL_CBIO_ERR_GENERAL;
}
(void)ctx;
@ -186,27 +201,32 @@ int BioSend(WOLFSSL* ssl, char *buf, int sz, void *ctx)
return WOLFSSL_CBIO_ERR_GENERAL;
}
if (ssl->biowr->method && ssl->biowr->method->writeCb) {
WOLFSSL_MSG("Calling custom biowr");
sent = ssl->biowr->method->writeCb(ssl->biowr, buf, sz);
if ((sent < 0) && (sent != WOLFSSL_CBIO_ERR_WANT_WRITE)) {
return WOLFSSL_CBIO_ERR_GENERAL;
}
return sent;
}
switch (ssl->biowr->type) {
case WOLFSSL_BIO_MEMORY:
case WOLFSSL_BIO_BIO:
sent = wolfSSL_BIO_write(ssl->biowr, buf, sz);
if (sent < 0) {
sent = wolfSSL_BIO_write(ssl->biowr, buf, sz);
if (sent < 0) {
if (ssl->biowr->type == WOLFSSL_BIO_SOCKET) {
int err = wolfSSL_LastError(sent);
if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
WOLFSSL_MSG("\tWould Block");
return WOLFSSL_CBIO_ERR_WANT_WRITE;
}
else if (err == SOCKET_ECONNRESET) {
WOLFSSL_MSG("\tConnection reset");
return WOLFSSL_CBIO_ERR_CONN_RST;
}
else if (err == SOCKET_EINTR) {
WOLFSSL_MSG("\tSocket interrupted");
return WOLFSSL_CBIO_ERR_ISR;
}
else if (err == SOCKET_EPIPE) {
WOLFSSL_MSG("\tSocket EPIPE");
return WOLFSSL_CBIO_ERR_CONN_CLOSE;
}
else {
WOLFSSL_MSG("\tGeneral error");
return WOLFSSL_CBIO_ERR_GENERAL;
}
break;
default:
WOLFSSL_MSG("This BIO type is unknown / unsupported");
return WOLFSSL_CBIO_ERR_GENERAL;
}
return WOLFSSL_CBIO_ERR_GENERAL;
}
(void)ctx;

View File

@ -31459,6 +31459,75 @@ static void test_wolfSSL_BIO_should_retry(void)
#endif
}
static void test_wolfSSL_BIO_connect(void)
{
#if defined(OPENSSL_ALL) && defined(HAVE_IO_TESTS_DEPENDENCIES)
tcp_ready ready;
func_args server_args;
THREAD_TYPE serverThread;
BIO *tcp_bio;
BIO *ssl_bio;
SSL_CTX* ctx;
SSL *ssl;
char msg[] = "hello wolfssl!";
char reply[30];
char buff[10] = {0};
printf(testingFmt, "wolfSSL_BIO_new_connect()");
/* Setup server */
XMEMSET(&server_args, 0, sizeof(func_args));
StartTCP();
InitTcpReady(&ready);
#if defined(USE_WINDOWS_API)
/* use RNG to get random port if using windows */
ready.port = GetRandomPort();
#endif
server_args.signal = &ready;
start_thread(test_server_nofail, &server_args, &serverThread);
wait_tcp_ready(&server_args);
AssertIntGT(XSPRINTF(buff, "%d", ready.port), 0);
/* Start the test proper */
/* Setup the TCP BIO */
AssertNotNull(tcp_bio = BIO_new_connect(wolfSSLIP));
AssertIntEQ(BIO_set_conn_port(tcp_bio, buff), 1);
/* Setup the SSL object */
AssertNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
AssertIntEQ(WOLFSSL_SUCCESS,
wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0));
AssertIntEQ(WOLFSSL_SUCCESS,
wolfSSL_CTX_use_certificate_file(ctx, cliCertFile, SSL_FILETYPE_PEM));
AssertIntEQ(WOLFSSL_SUCCESS,
wolfSSL_CTX_use_PrivateKey_file(ctx, cliKeyFile, SSL_FILETYPE_PEM));
AssertNotNull(ssl = SSL_new(ctx));
SSL_set_connect_state(ssl);
/* Setup the SSL BIO */
AssertNotNull(ssl_bio = BIO_new(BIO_f_ssl()));
AssertIntEQ(BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE), 1);
/* Link BIO's so that ssl_bio uses tcp_bio for IO */
AssertPtrEq(BIO_push(ssl_bio, tcp_bio), ssl_bio);
/* Do TCP connect */
AssertIntEQ(BIO_do_connect(ssl_bio), 1);
/* Do TLS handshake */
AssertIntEQ(BIO_do_handshake(ssl_bio), 1);
/* Test writing */
AssertIntEQ(BIO_write(ssl_bio, msg, sizeof(msg)), sizeof(msg));
/* Expect length of default wolfSSL reply */
AssertIntEQ(BIO_read(ssl_bio, reply, sizeof(reply)), 23);
/* Clean it all up */
BIO_free_all(ssl_bio);
SSL_CTX_free(ctx);
/* Server clean up */
join_thread(serverThread);
FreeTcpReady(&ready);
printf(resultFmt, passed);
#endif
}
static void test_wolfSSL_BIO_write(void)
{
#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_BASE64_ENCODE)
@ -40621,6 +40690,7 @@ void ApiTest(void)
test_wolfSSL_BIO_should_retry();
test_wolfSSL_d2i_PUBKEY();
test_wolfSSL_BIO_write();
test_wolfSSL_BIO_connect();
test_wolfSSL_BIO_printf();
test_wolfSSL_BIO_f_md();
#endif

View File

@ -672,11 +672,10 @@ wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_
#define BIO_set_write_buffer_size wolfSSL_BIO_set_write_buffer_size
#define BIO_f_ssl wolfSSL_BIO_f_ssl
#define BIO_new_socket wolfSSL_BIO_new_socket
#ifndef NO_WOLFSSL_STUB
#define BIO_new_connect wolfSSL_BIO_new_connect
#define BIO_set_conn_port wolfSSL_BIO_set_conn_port
#define BIO_do_connect wolfSSL_BIO_do_connect
#endif
#define BIO_do_handshake wolfSSL_BIO_do_handshake
#define SSL_set_bio wolfSSL_set_bio
#define BIO_set_ssl wolfSSL_BIO_set_ssl
#define BIO_eof wolfSSL_BIO_eof

View File

@ -1325,6 +1325,8 @@ WOLFSSL_API WOLFSSL_BIO *wolfSSL_BIO_new_connect(const char *str);
WOLFSSL_API long wolfSSL_BIO_set_conn_port(WOLFSSL_BIO *b, char* port);
WOLFSSL_API long wolfSSL_BIO_do_connect(WOLFSSL_BIO *b);
WOLFSSL_API long wolfSSL_BIO_do_handshake(WOLFSSL_BIO *b);
WOLFSSL_API long wolfSSL_BIO_ctrl(WOLFSSL_BIO *bp, int cmd, long larg, void *parg);
WOLFSSL_API long wolfSSL_BIO_int_ctrl(WOLFSSL_BIO *bp, int cmd, long larg, int iarg);
@ -3549,6 +3551,7 @@ WOLFSSL_API size_t wolfSSL_get_client_random(const WOLFSSL* ssl,
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)
WOLFSSL_API size_t wolfSSL_BIO_wpending(const WOLFSSL_BIO *bio);
WOLFSSL_API int wolfSSL_BIO_supports_pending(const WOLFSSL_BIO *bio);
WOLFSSL_API size_t wolfSSL_BIO_ctrl_pending(WOLFSSL_BIO *b);
WOLFSSL_API int wolfSSL_get_server_tmp_key(const WOLFSSL*, WOLFSSL_EVP_PKEY**);