]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Give BIO_s_mem() the ability to support datagrams
authorMatt Caswell <matt@openssl.org>
Thu, 16 Jun 2022 15:08:37 +0000 (16:08 +0100)
committerHugo Landau <hlandau@openssl.org>
Thu, 28 Jul 2022 07:06:52 +0000 (08:06 +0100)
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)

crypto/bio/bss_mem.c
include/openssl/bio.h.in
util/libcrypto.num

index 9153c1f1cd8163e0c48036a21260ef660b467cd3..a753380e64269a10fb290aa7564a96390b78e797 100644 (file)
@@ -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) {
index 46697ce3d75319473167943375ab3a28ab39b17a..1de1790ba75e3b85db89bee75bf6c29f73ea20ec 100644 (file)
@@ -649,6 +649,7 @@ int BIO_nwrite0(BIO *bio, char **buf);
 int BIO_nwrite(BIO *bio, char **buf, int num);
 
 const BIO_METHOD *BIO_s_mem(void);
+const BIO_METHOD *BIO_s_dgram_mem(void);
 const BIO_METHOD *BIO_s_secmem(void);
 BIO *BIO_new_mem_buf(const void *buf, int len);
 # ifndef OPENSSL_NO_SOCK
index e9338aabab2d5af39254641fb0dd752a4a74a407..6406849f3facf526d83f4205851e90a77075489c 100644 (file)
@@ -5447,3 +5447,4 @@ CMS_SignedData_new                      ? 3_1_0   EXIST::FUNCTION:CMS
 CMS_SignedData_verify                   ?      3_1_0   EXIST::FUNCTION:CMS
 OPENSSL_strcasecmp                      ?      3_0_3   EXIST::FUNCTION:
 OPENSSL_strncasecmp                     ?      3_0_3   EXIST::FUNCTION:
+BIO_s_dgram_mem                         ?      3_1_0   EXIST::FUNCTION: