/*
- * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
#include <stdio.h>
#include <errno.h>
-#include "bio_lcl.h"
+#include "bio_local.h"
#include "internal/cryptlib.h"
static int mem_write(BIO *h, const char *buf, int num);
static int mem_new(BIO *h);
static int secmem_new(BIO *h);
static int mem_free(BIO *data);
-static int mem_buf_free(BIO *data, int free_all);
+static int mem_buf_free(BIO *data);
static int mem_buf_sync(BIO *h);
static const BIO_METHOD mem_method = {
BIO_TYPE_MEM,
"memory buffer",
- /* TODO: Convert to new style write function */
bwrite_conv,
mem_write,
- /* TODO: Convert to new style read function */
bread_conv,
mem_read,
mem_puts,
static const BIO_METHOD secmem_method = {
BIO_TYPE_MEM,
"secure memory buffer",
- /* TODO: Convert to new style write function */
bwrite_conv,
mem_write,
- /* TODO: Convert to new style read function */
bread_conv,
mem_read,
mem_puts,
NULL, /* mem_callback_ctrl */
};
-/* BIO memory stores buffer and read pointer */
+/*
+ * BIO memory stores buffer and read pointer
+ * however the roles are different for read only BIOs.
+ * In that case the readp just stores the original state
+ * to be used for reset.
+ */
typedef struct bio_buf_mem_st {
struct buf_mem_st *buf; /* allocated buffer */
struct buf_mem_st *readp; /* read pointer */
size_t sz;
if (buf == NULL) {
- BIOerr(BIO_F_BIO_NEW_MEM_BUF, BIO_R_NULL_PARAMETER);
+ ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
sz = (len < 0) ? strlen(buf) : (size_t)len;
static int mem_free(BIO *a)
{
- return mem_buf_free(a, 1);
+ BIO_BUF_MEM *bb;
+
+ if (a == NULL)
+ return 0;
+
+ bb = (BIO_BUF_MEM *)a->ptr;
+ if (!mem_buf_free(a))
+ return 0;
+ OPENSSL_free(bb->readp);
+ OPENSSL_free(bb);
+ return 1;
}
-static int mem_buf_free(BIO *a, int free_all)
+static int mem_buf_free(BIO *a)
{
if (a == NULL)
return 0;
if (a->flags & BIO_FLAGS_MEM_RDONLY)
b->data = NULL;
BUF_MEM_free(b);
- if (free_all) {
- OPENSSL_free(bb->readp);
- OPENSSL_free(bb);
- }
- a->ptr = NULL;
}
return 1;
}
/*
* Reallocate memory buffer if read pointer differs
+ * NOT FOR RDONLY
*/
static int mem_buf_sync(BIO *b)
{
BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr;
BUF_MEM *bm = bbm->readp;
+ if (b->flags & BIO_FLAGS_MEM_RDONLY)
+ bm = bbm->buf;
BIO_clear_retry_flags(b);
ret = (outl >= 0 && (size_t)outl > bm->length) ? (int)bm->length : outl;
if ((out != NULL) && (ret > 0)) {
memcpy(out, bm->data, ret);
bm->length -= ret;
+ bm->max -= ret;
bm->data += ret;
} else if (bm->length == 0) {
ret = b->num;
int blen;
BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr;
- if (in == NULL) {
- BIOerr(BIO_F_MEM_WRITE, BIO_R_NULL_PARAMETER);
- goto end;
- }
if (b->flags & BIO_FLAGS_MEM_RDONLY) {
- BIOerr(BIO_F_MEM_WRITE, BIO_R_WRITE_TO_READ_ONLY_BIO);
+ ERR_raise(ERR_LIB_BIO, BIO_R_WRITE_TO_READ_ONLY_BIO);
goto end;
}
BIO_clear_retry_flags(b);
if (inl == 0)
return 0;
+ if (in == NULL) {
+ ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER);
+ goto end;
+ }
blen = bbm->readp->length;
mem_buf_sync(b);
if (BUF_MEM_grow_clean(bbm->buf, blen + inl) == 0)
long ret = 1;
char **pptr;
BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr;
- BUF_MEM *bm;
+ BUF_MEM *bm, *bo; /* bio_mem, bio_other */
+ long off, remain;
+
+ if (b->flags & BIO_FLAGS_MEM_RDONLY) {
+ bm = bbm->buf;
+ bo = bbm->readp;
+ } else {
+ bm = bbm->readp;
+ bo = bbm->buf;
+ }
+ off = (bm->data == bo->data) ? 0 : bm->data - bo->data;
+ remain = bm->length;
switch (cmd) {
case BIO_CTRL_RESET:
bm = bbm->buf;
if (bm->data != NULL) {
- /* For read only case reset to the start again */
- if ((b->flags & BIO_FLAGS_MEM_RDONLY) || (b->flags & BIO_FLAGS_NONCLEAR_RST)) {
- bm->length = bm->max;
+ if (!(b->flags & BIO_FLAGS_MEM_RDONLY)) {
+ if (!(b->flags & BIO_FLAGS_NONCLEAR_RST)) {
+ memset(bm->data, 0, bm->max);
+ bm->length = 0;
+ }
+ *bbm->readp = *bbm->buf;
} else {
- memset(bm->data, 0, bm->max);
- bm->length = 0;
+ /* For read only case just reset to the start again */
+ *bbm->buf = *bbm->readp;
}
- *bbm->readp = *bbm->buf;
}
break;
+ case BIO_C_FILE_SEEK:
+ if (num < 0 || num > off + remain)
+ return -1; /* Can't see outside of the current buffer */
+
+ bm->data = (num != 0) ? bo->data + num : bo->data;
+ bm->length = bo->length - num;
+ bm->max = bo->max - num;
+ off = num;
+ /* FALLTHRU */
+ case BIO_C_FILE_TELL:
+ ret = off;
+ break;
case BIO_CTRL_EOF:
- bm = bbm->readp;
ret = (long)(bm->length == 0);
break;
case BIO_C_SET_BUF_MEM_EOF_RETURN:
b->num = (int)num;
break;
case BIO_CTRL_INFO:
- bm = bbm->readp;
ret = (long)bm->length;
if (ptr != NULL) {
pptr = (char **)ptr;
- *pptr = (char *)&(bm->data[0]);
+ *pptr = (char *)(bm->data);
}
break;
case BIO_C_SET_BUF_MEM:
- mem_buf_free(b, 0);
+ mem_buf_free(b);
b->shutdown = (int)num;
bbm->buf = ptr;
*bbm->readp = *bbm->buf;
- b->ptr = bbm;
break;
case BIO_C_GET_BUF_MEM_PTR:
if (ptr != NULL) {
- mem_buf_sync(b);
- bm = bbm->readp;
+ if (!(b->flags & BIO_FLAGS_MEM_RDONLY))
+ mem_buf_sync(b);
+ bm = bbm->buf;
pptr = (char **)ptr;
*pptr = (char *)bm;
}
ret = 0L;
break;
case BIO_CTRL_PENDING:
- bm = bbm->readp;
ret = (long)bm->length;
break;
case BIO_CTRL_DUP:
BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)bp->ptr;
BUF_MEM *bm = bbm->readp;
+ if (bp->flags & BIO_FLAGS_MEM_RDONLY)
+ bm = bbm->buf;
BIO_clear_retry_flags(bp);
j = bm->length;
if ((size - 1) < j)