From dc4159546b97338f7e66ec8c4fc4b6ed95cde992 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Mon, 27 Mar 2017 15:05:39 -0600 Subject: [PATCH] refactor WOLFSSL_BIO read/write to bio.c and update read and write for base64 formating --- src/bio.c | 380 +++++++++++++++++++++++++++++++++++++++++- src/ssl.c | 242 +-------------------------- tests/api.c | 63 ++++++- wolfssl/openssl/bio.h | 1 + 4 files changed, 447 insertions(+), 239 deletions(-) diff --git a/src/bio.c b/src/bio.c index c558f38c8..beb0acfe6 100644 --- a/src/bio.c +++ b/src/bio.c @@ -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; } diff --git a/src/ssl.c b/src/ssl.c index 0a6daf152..03bcb8382 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -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"); diff --git a/tests/api.c b/tests/api.c index 4277cc4aa..f7c245421 100644 --- a/tests/api.c +++ b/tests/api.c @@ -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(); diff --git a/wolfssl/openssl/bio.h b/wolfssl/openssl/bio.h index de37d2c16..9063f7d08 100644 --- a/wolfssl/openssl/bio.h +++ b/wolfssl/openssl/bio.h @@ -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