diff options
author | Matt Caswell <matt@openssl.org> | 2022-06-16 16:08:37 +0100 |
---|---|---|
committer | Hugo Landau <hlandau@openssl.org> | 2022-07-28 08:06:52 +0100 |
commit | 5a4ba72f00f9b336a4d65abff822699ceb9617c6 (patch) | |
tree | 0182c29aa292abc6a13a70ab8b86a615dda05d40 /crypto | |
parent | 08c00377cb82f7eefcf7433606e687f348b9e7a0 (diff) |
Give BIO_s_mem() the ability to support datagrams
We introduce a new BIO ctrl that switches a BIO_s_mem() into datagram
mode. Packet boundaries are respected.
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/18596)
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/bio/bss_mem.c | 128 |
1 files changed, 120 insertions, 8 deletions
diff --git a/crypto/bio/bss_mem.c b/crypto/bio/bss_mem.c index 9153c1f1cd..a753380e64 100644 --- a/crypto/bio/bss_mem.c +++ b/crypto/bio/bss_mem.c @@ -18,6 +18,7 @@ static int mem_puts(BIO *h, const char *str); static int mem_gets(BIO *h, char *str, int size); static long mem_ctrl(BIO *h, int cmd, long arg1, void *arg2); static int mem_new(BIO *h); +static int dgram_mem_new(BIO *h); static int secmem_new(BIO *h); static int mem_free(BIO *data); static int mem_buf_free(BIO *data); @@ -38,6 +39,21 @@ static const BIO_METHOD mem_method = { NULL, /* mem_callback_ctrl */ }; +static const BIO_METHOD dgram_mem_method = { + BIO_TYPE_MEM, + "datagram memory buffer", + bwrite_conv, + mem_write, + bread_conv, + mem_read, + mem_puts, + mem_gets, + mem_ctrl, + dgram_mem_new, + mem_free, + NULL, /* mem_callback_ctrl */ +}; + static const BIO_METHOD secmem_method = { BIO_TYPE_MEM, "secure memory buffer", @@ -53,6 +69,12 @@ static const BIO_METHOD secmem_method = { NULL, /* mem_callback_ctrl */ }; +struct buf_mem_dgram_st { + char *dgram; /* Pointer into the buffer for where the dgram starts */ + size_t dgramlen; /* Length of the dgram */ + struct buf_mem_dgram_st *next; /* Next dgram to read */ +}; + /* * BIO memory stores buffer and read pointer * however the roles are different for read only BIOs. @@ -62,6 +84,9 @@ static const BIO_METHOD secmem_method = { typedef struct bio_buf_mem_st { struct buf_mem_st *buf; /* allocated buffer */ struct buf_mem_st *readp; /* read pointer */ + struct buf_mem_dgram_st *dgrams; /* linked list of dgram data */ + struct buf_mem_dgram_st *last; /* last dgram in the linked list */ + int use_dgrams; } BIO_BUF_MEM; /* @@ -74,6 +99,11 @@ const BIO_METHOD *BIO_s_mem(void) return &mem_method; } +const BIO_METHOD *BIO_s_dgram_mem(void) +{ + return &dgram_mem_method; +} + const BIO_METHOD *BIO_s_secmem(void) { return(&secmem_method); @@ -134,11 +164,39 @@ static int mem_new(BIO *bi) return mem_init(bi, 0L); } +static int dgram_mem_new(BIO *bi) +{ + BIO_BUF_MEM *bbm; + + if (!mem_init(bi, 0L)) + return 0; + + bbm = (BIO_BUF_MEM *)bi->ptr; + + bbm->use_dgrams = 1; + bi->num = -1; + + return 1; +} + static int secmem_new(BIO *bi) { return mem_init(bi, BUF_MEM_FLAG_SECURE); } +static void clear_all_dgrams(BIO_BUF_MEM *bbm) +{ + struct buf_mem_dgram_st *dgrams = bbm->dgrams; + + while (dgrams != NULL) { + struct buf_mem_dgram_st *tmp = dgrams; + + dgrams = dgrams->next; + OPENSSL_free(tmp); + } + bbm->dgrams = NULL; +} + static int mem_free(BIO *a) { BIO_BUF_MEM *bb; @@ -150,6 +208,7 @@ static int mem_free(BIO *a) if (!mem_buf_free(a)) return 0; OPENSSL_free(bb->readp); + clear_all_dgrams(bb); OPENSSL_free(bb); return 1; } @@ -193,17 +252,43 @@ static int mem_read(BIO *b, char *out, int outl) int ret = -1; BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; BUF_MEM *bm = bbm->readp; + size_t maxreadlen = 0; + int eof = 0; 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 (bbm->use_dgrams) { + if (bbm->dgrams != NULL) { + maxreadlen = bbm->dgrams->dgramlen; + if (!ossl_assert(maxreadlen <= bm->length)) + return 0; + } else { + eof = 1; + } + } else { + maxreadlen = bm->length; + eof = (maxreadlen == 0); + } + ret = (outl >= 0 && (size_t)outl > maxreadlen) ? (int)maxreadlen : outl; if ((out != NULL) && (ret > 0)) { + size_t flushlen; + memcpy(out, bm->data, ret); - bm->length -= ret; - bm->max -= ret; - bm->data += ret; - } else if (bm->length == 0) { + flushlen = bbm->use_dgrams ? maxreadlen : (size_t)ret; + + bm->length -= flushlen; + bm->max -= flushlen; + bm->data += flushlen; + if (bbm->use_dgrams) { + struct buf_mem_dgram_st *tmp = bbm->dgrams; + + bbm->dgrams = tmp->next; + OPENSSL_free(tmp); + if (bbm->dgrams == NULL) + bbm->last = NULL; + } + } else if (eof) { ret = b->num; if (ret != 0) BIO_set_retry_read(b); @@ -222,8 +307,10 @@ static int mem_write(BIO *b, const char *in, int inl) 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; @@ -232,8 +319,28 @@ static int mem_write(BIO *b, const char *in, int inl) mem_buf_sync(b); if (BUF_MEM_grow_clean(bbm->buf, blen + inl) == 0) goto end; + memcpy(bbm->buf->data + blen, in, inl); *bbm->readp = *bbm->buf; + + if (bbm->use_dgrams) { + struct buf_mem_dgram_st *dgram = OPENSSL_malloc(sizeof(*dgram)); + + if (dgram == NULL) { + ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE); + goto end; + } + + dgram->dgram = bbm->buf->data + blen; + dgram->dgramlen = inl; + dgram->next = NULL; + if (bbm->dgrams == NULL) + bbm->dgrams = dgram; + else + bbm->last->next = dgram; + bbm->last = dgram; + } + ret = inl; end: return ret; @@ -272,6 +379,7 @@ static long mem_ctrl(BIO *b, int cmd, long num, void *ptr) *bbm->buf = *bbm->readp; } } + clear_all_dgrams(bbm); break; case BIO_C_FILE_SEEK: if (num < 0 || num > off + remain) @@ -286,10 +394,13 @@ static long mem_ctrl(BIO *b, int cmd, long num, void *ptr) ret = off; break; case BIO_CTRL_EOF: - ret = (long)(bm->length == 0); + ret = (long)(bm->length == 0 && bbm->use_dgrams == 0); break; case BIO_C_SET_BUF_MEM_EOF_RETURN: - b->num = (int)num; + if (!bbm->use_dgrams) + b->num = (int)num; + else + ret = -1; break; case BIO_CTRL_INFO: ret = (long)bm->length; @@ -349,7 +460,8 @@ static int mem_gets(BIO *bp, char *buf, int size) if (bp->flags & BIO_FLAGS_MEM_RDONLY) bm = bbm->buf; BIO_clear_retry_flags(bp); - j = bm->length; + j = (!bbm->use_dgrams || bbm->dgrams == NULL) ? bm->length + : bbm->dgrams->dgramlen; if ((size - 1) < j) j = size - 1; if (j <= 0) { |