]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
iov: add iterator interface for giovec_t
authorDaiki Ueno <dueno@redhat.com>
Thu, 1 Aug 2019 15:41:45 +0000 (17:41 +0200)
committerDaiki Ueno <dueno@redhat.com>
Fri, 9 Aug 2019 06:47:05 +0000 (08:47 +0200)
This adds an iterator interface over giovec_t array, extracting a
fixed sized block.

Signed-off-by: Daiki Ueno <dueno@redhat.com>
.gitignore
lib/Makefile.am
lib/iov.c [new file with mode: 0644]
lib/iov.h [new file with mode: 0644]
lib/libgnutls.map
tests/Makefile.am
tests/iov.c [new file with mode: 0644]

index e80cff45399d3e620696d6aca594123a8c2b3dba..26d29fcf347f7f72c3336f0ecd7269f896a809ce 100644 (file)
@@ -431,6 +431,7 @@ tests/infoaccess
 tests/init_fds
 tests/init_roundtrip
 tests/insecure_key
+tests/iov
 tests/ip-check
 tests/ip-utils
 tests/key-export-pkcs8
index ffc72e4c2cdd484259efe0dfa1e1474c17be6808..9fe78afbdcdab7981689567257ed065e6e2cce52 100644 (file)
@@ -80,7 +80,8 @@ COBJECTS = range.c record.c compress.c debug.c cipher.c gthreads.h handshake-tls
        system-keys.h urls.c urls.h prf.c auto-verify.c dh-session.c \
        cert-session.c handshake-checks.c dtls-sw.c dh-primes.c openpgp_compat.c \
        crypto-selftests.c crypto-selftests-pk.c secrets.c extv.c extv.h \
-       hello_ext_lib.c hello_ext_lib.h ocsp-api.c stek.c cert-cred-rawpk.c
+       hello_ext_lib.c hello_ext_lib.h ocsp-api.c stek.c cert-cred-rawpk.c \
+       iov.c iov.h
 
 if WINDOWS
 COBJECTS += system/keys-win.c
diff --git a/lib/iov.c b/lib/iov.c
new file mode 100644 (file)
index 0000000..5dc29c5
--- /dev/null
+++ b/lib/iov.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Author: Daiki Ueno
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#include "gnutls_int.h"
+#include "iov.h"
+
+/**
+ * _gnutls_iov_iter_init:
+ * @iter: the iterator
+ * @iov: the data buffers
+ * @iov_count: the number of data buffers
+ * @block_size: block size to iterate
+ *
+ * Initialize the iterator.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
+ *   an error code is returned
+ */
+int
+_gnutls_iov_iter_init(struct iov_iter_st *iter,
+                     const giovec_t *iov, size_t iov_count,
+                     size_t block_size)
+{
+       if (unlikely(block_size > MAX_CIPHER_BLOCK_SIZE))
+               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+       iter->iov = iov;
+       iter->iov_count = iov_count;
+       iter->iov_index = 0;
+       iter->iov_offset = 0;
+       iter->block_size = block_size;
+       iter->block_offset = 0;
+       return 0;
+}
+
+/**
+ * _gnutls_iov_iter_next:
+ * @iter: the iterator
+ * @data: the return location of extracted data
+ *
+ * Retrieve block(s) pointed by @iter and advance it to the next
+ * position.  It returns the number of consecutive blocks in @data.
+ * At the end of iteration, 0 is returned.
+ *
+ * If the data stored in @iter is not multiple of the block size, the
+ * remaining data is stored in the "block" field of @iter with the
+ * size stored in the "block_offset" field.
+ *
+ * Returns: On success, a value greater than or equal to zero is
+ *   returned, otherwise a negative error code is returned
+ */
+ssize_t
+_gnutls_iov_iter_next(struct iov_iter_st *iter, uint8_t **data)
+{
+       while (iter->iov_index < iter->iov_count) {
+               const giovec_t *iov = &iter->iov[iter->iov_index];
+               uint8_t *p = iov->iov_base;
+               size_t len = iov->iov_len;
+               size_t block_left;
+
+               if (unlikely(len < iter->iov_offset))
+                       return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+               len -= iter->iov_offset;
+               p += iter->iov_offset;
+
+               /* We have at least one full block, return a whole set
+                * of full blocks immediately. */
+               if (iter->block_offset == 0 && len >= iter->block_size) {
+                       if ((len % iter->block_size) == 0) {
+                               iter->iov_index++;
+                               iter->iov_offset = 0;
+                       } else
+                               iter->iov_offset +=
+                                       len - (len % iter->block_size);
+
+                       /* Return the blocks. */
+                       *data = p;
+                       return len / iter->block_size;
+               }
+
+               /* We can complete one full block to return. */
+               block_left = iter->block_size - iter->block_offset;
+               if (len >= block_left) {
+                       memcpy(iter->block + iter->block_offset, p, block_left);
+                       iter->iov_offset += block_left;
+                       iter->block_offset = 0;
+
+                       /* Return the filled block. */
+                       *data = iter->block;
+                       return 1;
+               }
+
+               /* Not enough data for a full block, store in temp
+                * memory and continue. */
+               memcpy(iter->block + iter->block_offset, p, len);
+               iter->block_offset += len;
+               iter->iov_index++;
+               iter->iov_offset = 0;
+       }
+       return 0;
+}
diff --git a/lib/iov.h b/lib/iov.h
new file mode 100644 (file)
index 0000000..47fba55
--- /dev/null
+++ b/lib/iov.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Author: Daiki Ueno
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_LIB_IOV_H
+#define GNUTLS_LIB_IOV_H
+
+#include "gnutls_int.h"
+
+struct iov_iter_st {
+       const giovec_t *iov;
+       size_t iov_count;       /* the number of iov */
+       size_t iov_index;       /* index of the current buffer */
+       size_t iov_offset;      /* byte offset in the current buffer */
+
+       uint8_t block[MAX_CIPHER_BLOCK_SIZE]; /* incomplete block for reading */
+       size_t block_size;      /* actual block size of the cipher */
+       size_t block_offset;    /* offset in block */
+
+};
+
+int _gnutls_iov_iter_init(struct iov_iter_st *iter,
+                         const giovec_t *iov, size_t iov_count,
+                         size_t block_size);
+
+ssize_t _gnutls_iov_iter_next(struct iov_iter_st *iter, uint8_t **data);
+
+#endif /* GNUTLS_LIB_IOV_H */
index 0f31f4aef42ac51ca248b3bd5737b3b7d4f46892..fc93c0857f818593edc1b8f14922c3136996e1e2 100644 (file)
@@ -1384,4 +1384,7 @@ GNUTLS_PRIVATE_3_4 {
        _gnutls_anti_replay_check;
        # needed by gnutls-strcodes.c
        _gnutls_ecc_curve_is_supported;
+       # needed by tests/iov:
+       _gnutls_iov_iter_init;
+       _gnutls_iov_iter_next;
 } GNUTLS_3_4;
index a8c2d152ec81594ce393918836561d2315f633ca..a2883570f333b87461c475c0140730b20952d2e9 100644 (file)
@@ -214,7 +214,7 @@ ctests += mini-record-2 simple gnutls_hmac_fast set_pkcs12_cred cert certuniquei
         null_retrieve_function tls-record-size-limit tls-crt_type-neg \
         resume-with-stek-expiration resume-with-previous-stek rawpk-api \
         tls-record-size-limit-asym dh-compute ecdh-compute sign-verify-data-newapi \
-        sign-verify-newapi sign-verify-deterministic
+        sign-verify-newapi sign-verify-deterministic iov
 
 if HAVE_SECCOMP_TESTS
 ctests += dtls-with-seccomp tls-with-seccomp dtls-client-with-seccomp tls-client-with-seccomp
@@ -460,6 +460,10 @@ tls13_anti_replay_CPPFLAGS = $(AM_CPPFLAGS) \
        -I$(top_builddir)/gl    \
        $(NETTLE_CFLAGS)
 
+iov_CPPFLAGS = $(AM_CPPFLAGS) \
+       -I$(top_srcdir)/gl      \
+       -I$(top_builddir)/gl
+
 if ENABLE_PKCS11
 if !WINDOWS
 ctests += tls13/post-handshake-with-cert-pkcs11 pkcs11/tls-neg-pkcs11-no-key
diff --git a/tests/iov.c b/tests/iov.c
new file mode 100644 (file)
index 0000000..eda5583
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Author: Daiki Ueno
+ *
+ * This file is part of GnuTLS.
+ *
+ * GnuTLS is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuTLS is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gnutls_int.h"
+#include "../lib/iov.h"
+
+#include "utils.h"
+
+struct exp_st {
+       ssize_t ret;
+       size_t iov_index;
+       size_t iov_offset;
+       size_t block_offset;
+};
+
+struct test_st {
+       const char *name;
+       const giovec_t *iov;
+       size_t iovcnt;
+       size_t block_size;
+       const struct exp_st *exp;
+       size_t expcnt;
+       size_t remaining;
+};
+
+static const giovec_t iov16[] = {
+       {(void *) "0123456789abcdef", 16},
+       {(void *) "0123456789abcdef", 16},
+       {(void *) "0123456789abcdef", 16},
+       {(void *) "0123456789abcdef", 16}
+};
+
+static const struct exp_st exp16_64[] = {
+       {1, 3, 16, 0},
+       {0, 0, 0, 0}
+};
+
+static const struct exp_st exp16_32[] = {
+       {1, 1, 16, 0},
+       {1, 3, 16, 0},
+       {0, 0, 0, 0}
+};
+
+static const struct exp_st exp16_16[] = {
+       {1, 1, 0, 0},
+       {1, 2, 0, 0},
+       {1, 3, 0, 0},
+       {1, 4, 0, 0},
+       {0, 0, 0, 0}
+};
+
+static const struct exp_st exp16_4[] = {
+       {4, 1, 0, 0},
+       {4, 2, 0, 0},
+       {4, 3, 0, 0},
+       {4, 4, 0, 0},
+       {0, 0, 0, 0}
+};
+
+static const struct exp_st exp16_3[] = {
+       {5, 0, 15, 0},
+       {1, 1, 2, 0},
+       {4, 1, 14, 0},
+       {1, 2, 1, 0},
+       {5, 3, 0, 0},
+       {5, 3, 15, 0},
+       {0, 0, 0, 1}
+};
+
+static const giovec_t iov8[] = {
+       {(void *) "01234567", 8},
+       {(void *) "01234567", 8},
+       {(void *) "01234567", 8},
+       {(void *) "01234567", 8}
+};
+
+static const struct exp_st exp8_64[] = {
+       {0, 0, 0, 32}
+};
+
+static const struct test_st tests[] = {
+       { "16/64", iov16, sizeof(iov16)/sizeof(iov16[0]), 64,
+         exp16_64, sizeof(exp16_64)/sizeof(exp16_64[0]), 0 },
+       { "16/32", iov16, sizeof(iov16)/sizeof(iov16[0]), 32,
+         exp16_32, sizeof(exp16_32)/sizeof(exp16_32[0]), 0 },
+       { "16/16", iov16, sizeof(iov16)/sizeof(iov16[0]), 16,
+         exp16_16, sizeof(exp16_16)/sizeof(exp16_16[0]), 0 },
+       { "16/4", iov16, sizeof(iov16)/sizeof(iov16[0]), 4,
+         exp16_4, sizeof(exp16_4)/sizeof(exp16_4[0]), 0 },
+       { "16/3", iov16, sizeof(iov16)/sizeof(iov16[0]), 3,
+         exp16_3, sizeof(exp16_3)/sizeof(exp16_3[0]), 1 },
+       { "8/64", iov8, sizeof(iov8)/sizeof(iov8[0]), 64,
+         exp8_64, sizeof(exp8_64)/sizeof(exp8_64[0]), 32 }
+};
+
+void
+doit (void)
+{
+       size_t i;
+
+       for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
+               struct iov_iter_st iter;
+               const struct exp_st *exp = tests[i].exp;
+               uint8_t *data;
+               size_t j;
+
+               success("%s\n", tests[i].name);
+               assert(_gnutls_iov_iter_init(&iter,
+                                            tests[i].iov, tests[i].iovcnt,
+                                            tests[i].block_size) == 0);
+               for (j = 0; j < tests[i].expcnt; j++) {
+                       ssize_t ret;
+
+                       ret = _gnutls_iov_iter_next(&iter, &data);
+                       if (ret != exp[j].ret)
+                               fail("iov_iter_next: %d != %d\n",
+                                    (int) ret, (int) exp[j].ret);
+                       else if (debug)
+                               success("iov_iter_next: %d == %d\n",
+                                       (int) ret, (int) exp[j].ret);
+                       if (ret == 0)
+                               break;
+                       if (ret > 0) {
+                               if (iter.iov_index != exp[j].iov_index)
+                                       fail("iter.iov_index: %u != %u\n",
+                                            (unsigned) iter.iov_index, (unsigned) exp[j].iov_index);
+                               else if (debug)
+                                       success("iter.iov_index: %u == %u\n",
+                                            (unsigned) iter.iov_index, (unsigned) exp[j].iov_index);
+                               if (iter.iov_offset != exp[j].iov_offset)
+                                       fail("iter.iov_offset: %u != %u\n",
+                                            (unsigned) iter.iov_offset, (unsigned) exp[j].iov_offset);
+                               else if (debug)
+                                       success("iter.iov_offset: %u == %u\n",
+                                            (unsigned) iter.iov_offset, (unsigned) exp[j].iov_offset);
+                               if (iter.block_offset != exp[j].block_offset)
+                                       fail("iter.block_offset: %u != %u\n",
+                                            (unsigned) iter.block_offset, (unsigned) exp[j].block_offset);
+                               else if (debug)
+                                       success("iter.block_offset: %u == %u\n",
+                                            (unsigned) iter.block_offset, (unsigned) exp[j].block_offset);
+                       }
+               }
+               if (iter.block_offset != tests[i].remaining)
+                       fail("remaining: %u != %u\n",
+                            (unsigned) iter.block_offset, (unsigned) tests[i].remaining);
+       }
+}