refactor WOLFSSL_BIO read/write to bio.c and update read and write for base64 formating

This commit is contained in:
Jacob Barthelmeh 2017-03-27 15:05:39 -06:00
parent 91632d64f1
commit dc4159546b
4 changed files with 447 additions and 239 deletions

380
src/bio.c
View File

@ -22,6 +22,384 @@
#if !defined(WOLFSSL_BIO_INCLUDED)
#warning bio.c does not need to be compiled seperatly from ssl.c
#else
static int wolfSSL_BIO_BASE64_read(WOLFSSL_BIO* bio, void* buf, int len)
{
word32 frmtSz = len;
WOLFSSL_ENTER("wolfSSL_BIO_BASE64_read");
if (Base64_Decode((const byte*)buf, (word32)len, (byte*)buf, &frmtSz) !=0) {
WOLFSSL_MSG("Err doing base64 decode");
return SSL_FATAL_ERROR;
}
(void)bio;
return (int)frmtSz;
}
static int wolfSSL_BIO_BIO_read(WOLFSSL_BIO* bio, void* buf, int len)
{
int sz;
char* pt;
sz = wolfSSL_BIO_nread(bio, &pt, len);
if (sz > 0) {
XMEMCPY(buf, pt, sz);
}
return sz;
}
/* Handles reading from a memory type BIO and advancing the state.
*
* bio WOLFSSL_BIO to read from
* buf buffer to put data from bio in
* len amount of data to be read
*
* returns size read on success
*/
static int wolfSSL_BIO_MEMORY_read(WOLFSSL_BIO* bio, void* buf, int len)
{
int sz;
sz = wolfSSL_BIO_pending(bio);
if (sz > 0) {
const unsigned char* pt = NULL;
int memSz;
if (sz > len) {
sz = len;
}
memSz = wolfSSL_BIO_get_mem_data(bio, (void*)&pt);
if (memSz >= sz && pt != NULL) {
byte* tmp;
XMEMCPY(buf, (void*)pt, sz);
if (memSz - sz > 0) {
tmp = (byte*)XMALLOC(memSz-sz, bio->heap, DYNAMIC_TYPE_OPENSSL);
if (tmp == NULL) {
WOLFSSL_MSG("Memory error");
return WOLFSSL_BIO_ERROR;
}
XMEMCPY(tmp, (void*)(pt + sz), memSz - sz);
/* reset internal bio->mem */
XFREE(bio->mem, bio->heap, DYNAMIC_TYPE_OPENSSL);
bio->mem = tmp;
bio->memLen = memSz-sz;
}
bio->wrSz -= sz;
}
else {
WOLFSSL_MSG("Issue with getting bio mem pointer");
return 0;
}
}
else {
return WOLFSSL_BIO_ERROR;
}
return sz;
}
static int wolfSSL_BIO_SSL_read(WOLFSSL_BIO* bio, void* buf,
int len, WOLFSSL_BIO* front)
{
int ret;
WOLFSSL_ENTER("wolfSSL_BIO_SSL_write");
/* already got eof, again is error */
if (bio && front->eof)
return SSL_FATAL_ERROR;
ret = wolfSSL_read(bio->ssl, buf, len);
if (ret == 0)
front->eof = 1;
else if (ret < 0) {
int err = wolfSSL_get_error(bio->ssl, 0);
if ( !(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) )
front->eof = 1;
}
return ret;
}
int wolfSSL_BIO_read(WOLFSSL_BIO* bio, void* buf, int len)
{
int ret = 0;
WOLFSSL_BIO* front = bio;
WOLFSSL_ENTER("wolfSSL_BIO_read");
/* start at end of list and work backwards */
while (bio->next != NULL) {
bio = bio->next;
}
while (bio != NULL && ret >= 0) {
/* formating data */
if (bio->type == WOLFSSL_BIO_BASE64 && ret > 0) {
ret = wolfSSL_BIO_BASE64_read(bio, buf, len);
}
/* write BIOs */
if (bio && bio->type == WOLFSSL_BIO_BIO) {
ret = wolfSSL_BIO_BIO_read(bio, buf, len);
}
if (bio && bio->type == WOLFSSL_BIO_MEMORY) {
ret = wolfSSL_BIO_MEMORY_read(bio, buf, len);
}
#ifndef NO_FILESYSTEM
if (bio && bio->type == WOLFSSL_BIO_FILE) {
ret = (int)XFREAD(buf, 1, len, bio->file);
}
#endif
if (bio && bio->type == WOLFSSL_BIO_SSL) {
ret = wolfSSL_BIO_SSL_read(bio, buf, len, front);
}
/* case where front of list is done */
if (bio == front) {
break; /* at front of list so be done */
}
/* previous WOLFSSL_BIO in list working towards head of list */
bio = bio->prev;
}
return ret;
}
static int wolfSSL_BIO_BASE64_write(WOLFSSL_BIO* bio, const void* data,
word32 inLen, byte* out, word32* outLen)
{
WOLFSSL_ENTER("wolfSSL_BIO_BASE64_write");
#if defined(WOLFSSL_BASE64_ENCODE)
if ((bio->flags & WOLFSSL_BIO_FLAG_BASE64_NO_NL) ==
WOLFSSL_BIO_FLAG_BASE64_NO_NL) {
if (Base64_Encode_NoNl((const byte*)data, inLen,
out, outLen) < 0) {
return SSL_FATAL_ERROR;
}
}
else {
if (Base64_Encode((const byte*)data, inLen,
out, outLen) < 0) {
return SSL_FATAL_ERROR;
}
}
return (int)*outLen;
#else
(void)bio;
(void)data;
(void)inLen;
(void)out;
(void)outLen;
WOLFSSL_MSG("BASE64 encoding not compiled in");
return 0;
#endif
}
static int wolfSSL_BIO_SSL_write(WOLFSSL_BIO* bio, const void* data,
int len, WOLFSSL_BIO* front)
{
int ret;
WOLFSSL_ENTER("wolfSSL_BIO_SSL_write");
if (bio->ssl == 0) return BAD_FUNC_ARG;
ret = wolfSSL_write(bio->ssl, data, len);
if (ret == 0)
front->eof = 1;
else if (ret < 0) {
int err = wolfSSL_get_error(bio->ssl, 0);
if ( !(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) )
front->eof = 1;
}
return ret;
}
static int wolfSSL_BIO_BIO_write(WOLFSSL_BIO* bio, const void* data,
int len)
{
/* internal function where arguments have already been sanity checked */
int sz;
char* buf;
WOLFSSL_ENTER("wolfSSL_BIO_BIO_write");
sz = wolfSSL_BIO_nwrite(bio, &buf, len);
/* test space for write */
if (sz <= 0) {
WOLFSSL_MSG("No room left to write");
return sz;
}
XMEMCPY(buf, data, sz);
return sz;
}
/* for complete compatibility a bio memory write allocs its own memory
* until the application runs out ....
*
* bio structure to hold incoming data
* data buffer holding the data to be written
* len length of data buffer
*
* returns the amount of data written on success and WOLFSSL_FAILURE or
* WOLFSSL_BIO_ERROR for failure cases.
*/
static int wolfSSL_BIO_MEMORY_write(WOLFSSL_BIO* bio, const void* data,
int len)
{
/* internal function where arguments have already been sanity checked */
int sz;
int ret;
const unsigned char* buf;
WOLFSSL_ENTER("wolfSSL_BIO_MEMORY_write");
sz = wolfSSL_BIO_pending(bio);
if (sz < 0) {
WOLFSSL_MSG("Error getting memory data");
return sz;
}
if (bio->mem == NULL) {
bio->mem = (byte*)XMALLOC(len, bio->heap,
DYNAMIC_TYPE_OPENSSL);
if (bio->mem == NULL) {
WOLFSSL_MSG("Error on malloc");
return SSL_FAILURE;
}
bio->memLen = len;
}
/* check if will fit in current buffer size */
if ((ret = wolfSSL_BIO_get_mem_data(bio, (void*)&buf)) < sz + len) {
if (ret <= 0) {
return WOLFSSL_BIO_ERROR;
}
else {
bio->mem = (byte*)XREALLOC(bio->mem, sz + len, bio->heap,
DYNAMIC_TYPE_OPENSSL);
if (bio->mem == NULL) {
WOLFSSL_MSG("Error on realloc");
return SSL_FAILURE;
}
bio->memLen = sz + len;
}
}
XMEMCPY(bio->mem + sz, data, len);
bio->wrSz += len;
return len;
}
int wolfSSL_BIO_write(WOLFSSL_BIO* bio, const void* data, int len)
{
int ret = 0;
WOLFSSL_BIO* front = bio;
void* frmt = NULL;
word32 frmtSz = 0;
WOLFSSL_ENTER("wolfSSL_BIO_write");
while (bio != NULL && ret >= 0) {
/* check for formating */
if (bio && bio->type == WOLFSSL_BIO_BASE64) {
#if defined(WOLFSSL_BASE64_ENCODE)
if (bio->flags & WOLFSSL_BIO_FLAG_BASE64_NO_NL) {
if (Base64_Encode_NoNl((const byte*)data, len, NULL,
&frmtSz) != LENGTH_ONLY_E) {
WOLFSSL_MSG("Error with base 64 get length");
ret = SSL_FATAL_ERROR;
}
}
else {
if (Base64_Encode((const byte*)data, len, NULL, &frmtSz) !=
LENGTH_ONLY_E) {
WOLFSSL_MSG("Error with base 64 get length");
ret = SSL_FATAL_ERROR;
}
}
if (frmt == NULL && frmtSz > 0 && ret != SSL_FATAL_ERROR) {
frmt = (void*)XMALLOC(frmtSz, bio->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (frmt == NULL) {
WOLFSSL_MSG("Memory error");
ret = SSL_FATAL_ERROR;
}
}
#endif /* defined(WOLFSSL_BASE64_ENCODE) */
if (ret >= 0) {
/* change so that data is formated buffer */
ret = wolfSSL_BIO_BASE64_write(bio, data, (word32)len,
(byte*)frmt, &frmtSz);
data = frmt;
len = frmtSz;
}
}
/* write bios */
if (bio && bio->type == WOLFSSL_BIO_BIO) {
ret = wolfSSL_BIO_BIO_write(bio, data, len);
}
if (bio && bio->type == WOLFSSL_BIO_MEMORY) {
ret = wolfSSL_BIO_MEMORY_write(bio, data, len);
}
#ifndef NO_FILESYSTEM
if (bio && bio->type == WOLFSSL_BIO_FILE) {
ret = (int)XFWRITE(data, 1, len, bio->file);
}
#endif
if (bio && bio->type == WOLFSSL_BIO_SSL) {
/* already got eof, again is error */
if (bio && front->eof) {
ret = SSL_FATAL_ERROR;
}
else {
ret = wolfSSL_BIO_SSL_write(bio, data, len, front);
}
}
/* advance to the next bio in list */
bio = bio->next;
}
if (frmt != NULL) {
XFREE(frmt, bio->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
return ret;
}
/*** TBD ***/
WOLFSSL_API long wolfSSL_BIO_ctrl(WOLFSSL_BIO *bio, int cmd, long larg, void *parg)
@ -127,7 +505,7 @@ int wolfSSL_BIO_gets(WOLFSSL_BIO* bio, char* buf, int sz)
buf[cSz] = '\0';
}
ret = wolfSSL_BIO_read(bio, (void*)buf, cSz);
ret = wolfSSL_BIO_MEMORY_read(bio, (void*)buf, cSz);
/* ret is read after the switch statment */
break;
}

242
src/ssl.c
View File

@ -12117,240 +12117,6 @@ int wolfSSL_set_compression(WOLFSSL* ssl)
}
static int wolfSSL_BIO_BIO_read(WOLFSSL_BIO* bio, void* buf, int len)
{
int sz;
char* pt;
sz = wolfSSL_BIO_nread(bio, &pt, len);
if (sz > 0) {
XMEMCPY(buf, pt, sz);
}
return sz;
}
/* Handles reading from a memory type BIO and advancing the state.
*
* bio WOLFSSL_BIO to read from
* buf buffer to put data from bio in
* len amount of data to be read
*
* returns size read on success
*/
static int wolfSSL_BIO_MEMORY_read(WOLFSSL_BIO* bio, void* buf, int len)
{
int sz;
sz = (int)wolfSSL_BIO_ctrl_pending(bio);
if (sz > 0) {
byte* pt = NULL;
int memSz;
if (sz > len) {
sz = len;
}
memSz = wolfSSL_BIO_get_mem_data(bio, (void*)&pt);
if (memSz >= sz && pt != NULL) {
byte* tmp;
XMEMCPY(buf, pt, sz);
if (memSz - sz > 0) {
tmp = (byte*)XMALLOC(memSz-sz, bio->heap,
DYNAMIC_TYPE_OPENSSL);
if (tmp == NULL) {
WOLFSSL_MSG("Memory error");
return WOLFSSL_BIO_ERROR;
}
XMEMCPY(tmp, pt + sz, memSz - sz);
/* reset internal bio->mem, tmp gets free'd with
* wolfSSL_BIO_free */
XFREE(bio->mem, bio->heap, DYNAMIC_TYPE_OPENSSL);
bio->mem = tmp;
}
bio->wrSz -= sz;
bio->memLen = memSz - sz;
}
else {
WOLFSSL_MSG("Issue with getting bio mem pointer");
return 0;
}
}
else {
return WOLFSSL_BIO_ERROR;
}
return sz;
}
int wolfSSL_BIO_read(WOLFSSL_BIO* bio, void* buf, int len)
{
int ret;
WOLFSSL* ssl = 0;
WOLFSSL_BIO* front = bio;
WOLFSSL_ENTER("wolfSSL_BIO_read");
if (bio && bio->type == WOLFSSL_BIO_BIO) {
return wolfSSL_BIO_BIO_read(bio, buf, len);
}
if (bio && bio->type == WOLFSSL_BIO_MEMORY) {
return wolfSSL_BIO_MEMORY_read(bio, buf, len);
}
#ifndef NO_FILESYSTEM
if (bio && bio->type == WOLFSSL_BIO_FILE) {
return (int)XFREAD(buf, 1, len, bio->file);
}
#endif
/* already got eof, again is error */
if (bio && front->eof)
return WOLFSSL_FATAL_ERROR;
while(bio && ((ssl = bio->ssl) == 0) )
bio = bio->next;
if (ssl == 0) return BAD_FUNC_ARG;
ret = wolfSSL_read(ssl, buf, len);
if (ret == 0)
front->eof = 1;
else if (ret < 0) {
int err = wolfSSL_get_error(ssl, 0);
if ( !(err == WOLFSSL_ERROR_WANT_READ || err == WOLFSSL_ERROR_WANT_WRITE) )
front->eof = 1;
}
return ret;
}
static int wolfSSL_BIO_BIO_write(WOLFSSL_BIO* bio, const void* data,
int len)
{
/* internal function where arguments have already been sanity checked */
int sz;
char* buf;
sz = wolfSSL_BIO_nwrite(bio, &buf, len);
/* test space for write */
if (sz <= 0) {
WOLFSSL_MSG("No room left to write");
return sz;
}
XMEMCPY(buf, data, sz);
return sz;
}
/* for complete compatibility a bio memory write allocs its own memory
* until the application runs out ....
*
* bio structure to hold incoming data
* data buffer holding the data to be written
* len length of data buffer
*
* returns the amount of data written on success and WOLFSSL_FAILURE or
* WOLFSSL_BIO_ERROR for failure cases.
*/
static int wolfSSL_BIO_MEMORY_write(WOLFSSL_BIO* bio, const void* data,
int len)
{
/* internal function where arguments have already been sanity checked */
int sz;
int ret;
const unsigned char* buf;
sz = wolfSSL_BIO_pending(bio);
if (sz < 0) {
WOLFSSL_MSG("Error getting memory data");
return sz;
}
if (bio->mem == NULL) {
bio->mem = (byte*)XMALLOC(len, bio->heap,
DYNAMIC_TYPE_OPENSSL);
if (bio->mem == NULL) {
WOLFSSL_MSG("Error on malloc");
return WOLFSSL_FAILURE;
}
bio->memLen = len;
}
/* check if will fit in current buffer size */
if ((ret = wolfSSL_BIO_get_mem_data(bio, (void*)&buf)) < sz + len) {
if (ret < 0) {
return WOLFSSL_BIO_ERROR;
}
else {
bio->mem = (byte*)XREALLOC(bio->mem, sz + len, bio->heap,
DYNAMIC_TYPE_OPENSSL);
if (bio->mem == NULL) {
WOLFSSL_MSG("Error on realloc");
return WOLFSSL_FAILURE;
}
bio->memLen = sz + len;
}
}
XMEMCPY(bio->mem + sz, data, len);
bio->wrSz += len;
return len;
}
int wolfSSL_BIO_write(WOLFSSL_BIO* bio, const void* data, int len)
{
int ret;
WOLFSSL* ssl = 0;
WOLFSSL_BIO* front = bio;
WOLFSSL_ENTER("wolfSSL_BIO_write");
if (bio && bio->type == WOLFSSL_BIO_BIO) {
return wolfSSL_BIO_BIO_write(bio, data, len);
}
if (bio && bio->type == WOLFSSL_BIO_MEMORY) {
return wolfSSL_BIO_MEMORY_write(bio, data, len);
}
#ifndef NO_FILESYSTEM
if (bio && bio->type == WOLFSSL_BIO_FILE) {
return (int)XFWRITE(data, 1, len, bio->file);
}
#endif
/* already got eof, again is error */
if (bio && front->eof)
return WOLFSSL_FATAL_ERROR;
while(bio && ((ssl = bio->ssl) == 0) )
bio = bio->next;
if (ssl == 0) return BAD_FUNC_ARG;
ret = wolfSSL_write(ssl, data, len);
if (ret == 0)
front->eof = 1;
else if (ret < 0) {
int err = wolfSSL_get_error(ssl, 0);
if ( !(err == WOLFSSL_ERROR_WANT_READ || err == WOLFSSL_ERROR_WANT_WRITE) )
front->eof = 1;
}
return ret;
}
WOLFSSL_BIO* wolfSSL_BIO_push(WOLFSSL_BIO* top, WOLFSSL_BIO* append)
{
WOLFSSL_ENTER("BIO_push");
@ -17227,7 +16993,7 @@ WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_base64(void)
{
static WOLFSSL_BIO_METHOD meth;
WOLFSSL_STUB("wolfSSL_BIO_f_base64");
WOLFSSL_ENTER("wolfSSL_BIO_f_base64");
meth.type = WOLFSSL_BIO_BASE64;
return &meth;
@ -17241,7 +17007,7 @@ WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_base64(void)
*/
void wolfSSL_BIO_set_flags(WOLFSSL_BIO* bio, int flags)
{
WOLFSSL_STUB("wolfSSL_BIO_set_flags");
WOLFSSL_ENTER("wolfSSL_BIO_set_flags");
if (bio != NULL) {
bio->flags |= flags;
@ -20577,6 +20343,10 @@ int wolfSSL_RAND_egd(const char* nm)
}
#endif
if (nm == NULL) {
return SSL_FATAL_ERROR;
}
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd <= 0) {
WOLFSSL_MSG("Error creating socket");

View File

@ -15198,6 +15198,16 @@ static void test_wolfSSL_RAND(void)
RAND_seed(seed, sizeof(seed));
RAND_cleanup();
AssertIntEQ(RAND_egd(NULL), -1);
#ifndef NO_FILESYSTEM
{
char fname[100];
AssertNotNull(RAND_file_name(fname, sizeof(fname)));
AssertIntEQ(RAND_write_file(NULL), 0);
}
#endif
printf(resultFmt, passed);
#endif
}
@ -15534,6 +15544,54 @@ static void test_wolfSSL_BIO_gets(void)
}
static void test_wolfSSL_BIO_write(void)
{
#if defined(OPENSSL_EXTRA)
BIO* bio;
BIO* bio64;
BIO* ptr;
int sz;
char msg[] = "conversion test";
char out[25];
char expected[] = "Y29udmVyc2lvbiB0ZXN0AA==\n";
printf(testingFmt, "BIO_write()");
AssertNotNull(bio64 = BIO_new(BIO_f_base64()));
AssertNotNull(bio = BIO_push(bio64, BIO_new(BIO_s_mem())));
/* now should convert to base64 then write to memory */
AssertIntEQ(BIO_write(bio, msg, sizeof(msg)), 25);
BIO_flush(bio);
AssertNotNull(ptr = BIO_find_type(bio, BIO_TYPE_MEM));
sz = sizeof(out);
XMEMSET(out, 0, sz);
AssertIntEQ((sz = BIO_read(ptr, out, sz)), 25);
AssertIntEQ(XMEMCMP(out, expected, sz), 0);
/* now try encoding with no line ending */
BIO_set_flags(bio64, BIO_FLAG_BASE64_NO_NL);
AssertIntEQ(BIO_write(bio, msg, sizeof(msg)), 24);
BIO_flush(bio);
sz = sizeof(out);
XMEMSET(out, 0, sz);
AssertIntEQ((sz = BIO_read(ptr, out, sz)), 24);
AssertIntEQ(XMEMCMP(out, expected, sz), 0);
BIO_free_all(bio); /* frees bio64 also */
printf(resultFmt, passed);
#endif
}
static void test_wolfSSL_SESSION(void)
{
#if defined(OPENSSL_EXTRA)
printf(testingFmt, "no_op_functions()");
printf(resultFmt, passed);
#endif
}
static void test_wolfSSL_d2i_PUBKEY(void)
{
#if defined(OPENSSL_EXTRA)
@ -16368,12 +16426,10 @@ void ApiTest(void)
test_wolfSSL_X509_STORE_CTX();
test_wolfSSL_PEM_read_bio();
test_wolfSSL_BIO();
test_wolfSSL_DES_ecb_encrypt();
test_wolfSSL_ASN1_STRING();
test_wolfSSL_X509();
test_wolfSSL_RAND();
test_wolfSSL_BUF();
test_wolfSSL_DES_ecb_encrypt();
test_wolfSSL_set_tlsext_status_type();
test_wolfSSL_ASN1_TIME_adj();
test_wolfSSL_CTX_set_client_CA_list();
@ -16388,6 +16444,9 @@ void ApiTest(void)
test_wolfSSL_X509_NAME_ENTRY();
test_wolfSSL_BIO_gets();
test_wolfSSL_d2i_PUBKEY();
test_wolfSSL_BIO_write();
test_wolfSSL_SESSION();
test_wolfSSL_DES_ecb_encrypt();
/* test the no op functions for compatibility */
test_no_op_functions();

View File

@ -46,6 +46,7 @@
#define BIO_TYPE_FILE WOLFSSL_BIO_FILE
#define BIO_TYPE_BIO WOLFSSL_BIO_BIO
#define BIO_TYPE_MEM WOLFSSL_BIO_MEMORY
#define BIO_TYPE_BASE64 WOLFSSL_BIO_BASE64
#ifdef __cplusplus