diff --git a/src/bio.c b/src/bio.c index b93298e6f..9c3441e5f 100644 --- a/src/bio.c +++ b/src/bio.c @@ -128,19 +128,24 @@ static int wolfSSL_BIO_MEMORY_read(WOLFSSL_BIO* bio, void* buf, int len) bio->rdIdx += sz; if (bio->rdIdx >= bio->wrSz) { - /* All data read resize down to WOLFSSL_BIO_RESIZE_THRESHOLD */ - if (bio->mem_buf->max > WOLFSSL_BIO_RESIZE_THRESHOLD && - wolfSSL_BUF_MEM_resize(bio->mem_buf, - WOLFSSL_BIO_RESIZE_THRESHOLD) == 0) { - WOLFSSL_MSG("wolfSSL_BUF_MEM_resize error"); - return WOLFSSL_BIO_ERROR; + if (bio->flags & BIO_FLAGS_MEM_RDONLY) { + bio->wrSz = bio->wrSzReset; + } + else { + /* All data read resize down to WOLFSSL_BIO_RESIZE_THRESHOLD */ + if (bio->mem_buf->max > WOLFSSL_BIO_RESIZE_THRESHOLD && + wolfSSL_BUF_MEM_resize(bio->mem_buf, WOLFSSL_BIO_RESIZE_THRESHOLD) == 0) { + WOLFSSL_MSG("wolfSSL_BUF_MEM_resize error"); + return WOLFSSL_BIO_ERROR; + } + bio->rdIdx = 0; + bio->wrSz = 0; + bio->mem_buf->length = 0; } - bio->wrSz = 0; - bio->rdIdx = 0; - bio->mem_buf->length = 0; bio->ptr = bio->mem_buf->data; } - else if (bio->rdIdx >= WOLFSSL_BIO_RESIZE_THRESHOLD) { + else if (bio->rdIdx >= WOLFSSL_BIO_RESIZE_THRESHOLD && + !(bio->flags & BIO_FLAGS_MEM_RDONLY)) { /* Resize the memory so we are not taking up more than necessary. * memmove reverts internally to memcpy if areas don't overlap */ XMEMMOVE(bio->mem_buf->data, bio->mem_buf->data + bio->rdIdx, @@ -516,6 +521,9 @@ static int wolfSSL_BIO_MEMORY_write(WOLFSSL_BIO* bio, const void* data, WOLFSSL_MSG("one of input parameters is null"); return WOLFSSL_FAILURE; } + if (bio->flags & BIO_FLAGS_MEM_RDONLY) { + return WOLFSSL_FAILURE; + } if (len == 0) return WOLFSSL_SUCCESS; /* Return early to make logic simpler */ @@ -535,6 +543,7 @@ static int wolfSSL_BIO_MEMORY_write(WOLFSSL_BIO* bio, const void* data, bio->ptr = bio->mem_buf->data; bio->num = (int)bio->mem_buf->max; bio->wrSz += len; + bio->wrIdx += len; return len; } @@ -1431,15 +1440,20 @@ int wolfSSL_BIO_reset(WOLFSSL_BIO *bio) case WOLFSSL_BIO_MEMORY: bio->rdIdx = 0; - bio->wrIdx = 0; - bio->wrSz = 0; - XFREE(bio->ptr, bio->heap, DYNAMIC_TYPE_OPENSSL); - bio->ptr = NULL; - bio->num = 0; - if (bio->mem_buf != NULL) { - bio->mem_buf->data = NULL; - bio->mem_buf->length = 0; - bio->mem_buf->max = 0; + if (bio->flags & BIO_FLAGS_MEM_RDONLY) { + bio->wrIdx = bio->wrSzReset; + bio->wrSz = bio->wrSzReset; + } + else { + bio->wrSz = 0; + XFREE(bio->ptr, bio->heap, DYNAMIC_TYPE_OPENSSL); + bio->ptr = NULL; + bio->num = 0; + if (bio->mem_buf != NULL) { + bio->mem_buf->data = NULL; + bio->mem_buf->length = 0; + bio->mem_buf->max = 0; + } } return 0; @@ -2542,6 +2556,8 @@ int wolfSSL_BIO_flush(WOLFSSL_BIO* bio) bio->ptr = bio->mem_buf->data; if (len > 0 && bio->ptr != NULL) { XMEMCPY(bio->ptr, buf, len); + bio->flags |= BIO_FLAGS_MEM_RDONLY; + bio->wrSzReset = bio->wrSz; } return bio; diff --git a/tests/api.c b/tests/api.c index c8b4c0d54..40ce66ea7 100644 --- a/tests/api.c +++ b/tests/api.c @@ -9319,13 +9319,9 @@ static int test_wolfSSL_PKCS12(void) goodPswLen = (int)XSTRLEN(goodPsw); badPswLen = (int)XSTRLEN(badPsw); - bio = BIO_new_mem_buf((void*)buf, bytes); + bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem()); AssertNotNull(bio); - pkcs12 = d2i_PKCS12_bio(bio, NULL); - AssertNotNull(pkcs12); - PKCS12_free(pkcs12); - AssertIntEQ(BIO_write(bio, buf, bytes), bytes); /* d2i consumes BIO */ d2i_PKCS12_bio(bio, &pkcs12); AssertNotNull(pkcs12); @@ -41239,7 +41235,32 @@ static int test_wolfSSL_BIO_up_ref(void) #endif return res; } +static int test_wolfSSL_BIO_reset(void) +{ + int res = TEST_SKIPPED; +#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) + BIO* bio; + byte buf[16]; + AssertNotNull(bio = BIO_new_mem_buf("secure your data", + (word32)XSTRLEN("secure your data"))); + AssertIntEQ(BIO_read(bio, buf, 6), 6); + AssertIntEQ(XMEMCMP(buf, "secure", 6), 0); + XMEMSET(buf, 0, 16); + AssertIntEQ(BIO_read(bio, buf, 16), 10); + AssertIntEQ(XMEMCMP(buf, " your data", 10), 0); + /* You cannot write to MEM BIO with read-only mode. */ + AssertIntEQ(BIO_write(bio, "WriteToReadonly", 15), 0); + AssertIntEQ(BIO_read(bio, buf, 16), -1); + XMEMSET(buf, 0, 16); + AssertIntEQ(BIO_reset(bio), 0); + AssertIntEQ(BIO_read(bio, buf, 16), 16); + AssertIntEQ(XMEMCMP(buf, "secure your data", 16), 0); + BIO_free(bio); + res = TEST_RES_CHECK(1); +#endif + return res; +} #endif /* !NO_BIO */ #if defined(OPENSSL_EXTRA) && defined(HAVE_IO_TESTS_DEPENDENCIES) @@ -61697,6 +61718,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_BIO_f_md), TEST_DECL(test_wolfSSL_BIO_up_ref), TEST_DECL(test_wolfSSL_BIO_tls), + TEST_DECL(test_wolfSSL_BIO_reset), #endif TEST_DECL(test_wolfSSL_cert_cb), TEST_DECL(test_wolfSSL_SESSION), diff --git a/wolfssl/openssl/bio.h b/wolfssl/openssl/bio.h index 5d6107b80..c2a0e9bc8 100644 --- a/wolfssl/openssl/bio.h +++ b/wolfssl/openssl/bio.h @@ -170,6 +170,9 @@ #define BIO_FP_WRITE 0x04 +/* You shouldn't free up or change the data if BIO_FLAGS_MEM_RDONLY is set */ +#define BIO_FLAGS_MEM_RDONLY 0x200 + #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 7f610ad76..167114701 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -544,6 +544,7 @@ struct WOLFSSL_BIO { char* infoArg; /* BIO callback argument */ wolf_bio_info_cb infoCb; /* BIO callback */ int wrSz; /* write buffer size (mem) */ + int wrSzReset; /* First buffer size (mem) - read ONLY data */ int wrIdx; /* current index for write buffer */ int rdIdx; /* current read index */ int readRq; /* read request */