Blame SOURCES/gnutls-3.6.8-fix-aead-cipher-encryptv2.patch

cde47b
From bbb312749780928cc10b45662c6d7eadcaa98f0b Mon Sep 17 00:00:00 2001
cde47b
From: Daiki Ueno <dueno@redhat.com>
cde47b
Date: Thu, 3 Oct 2019 10:34:18 +0200
cde47b
Subject: [PATCH 1/3] iov: _gnutls_iov_iter_next: return bytes instead of
cde47b
 blocks
cde47b
cde47b
This eliminates the need of special handling of final block.  Also
cde47b
adds more tests in exceptional cases.
cde47b
cde47b
Signed-off-by: Daiki Ueno <dueno@redhat.com>
cde47b
---
cde47b
 lib/crypto-api.c |  82 +++++-------------------------
cde47b
 lib/iov.c        |  31 +++++++++---
cde47b
 tests/iov.c      | 126 ++++++++++++++++++++++++++++++++---------------
cde47b
 3 files changed, 121 insertions(+), 118 deletions(-)
cde47b
cde47b
diff --git a/lib/crypto-api.c b/lib/crypto-api.c
cde47b
index 09b3d7bfc..41e759b74 100644
cde47b
--- a/lib/crypto-api.c
cde47b
+++ b/lib/crypto-api.c
cde47b
@@ -992,9 +992,9 @@ gnutls_aead_cipher_encryptv(gnutls_aead_cipher_hd_t handle,
cde47b
 	uint8_t *dst;
cde47b
 	size_t dst_size, total = 0;
cde47b
 	uint8_t *p;
cde47b
+	size_t len;
cde47b
 	size_t blocksize = handle->ctx_enc.e->blocksize;
cde47b
 	struct iov_iter_st iter;
cde47b
-	size_t blocks;
cde47b
 
cde47b
 	/* Limitation: this function provides an optimization under the internally registered
cde47b
 	 * AEAD ciphers. When an AEAD cipher is used registered with gnutls_crypto_register_aead_cipher(),
cde47b
@@ -1045,15 +1045,7 @@ gnutls_aead_cipher_encryptv(gnutls_aead_cipher_hd_t handle,
cde47b
 			return gnutls_assert_val(ret);
cde47b
 		if (ret == 0)
cde47b
 			break;
cde47b
-		blocks = ret;
cde47b
-		ret = _gnutls_cipher_auth(&handle->ctx_enc, p,
cde47b
-					  blocksize * blocks);
cde47b
-		if (unlikely(ret < 0))
cde47b
-			return gnutls_assert_val(ret);
cde47b
-	}
cde47b
-	if (iter.block_offset > 0) {
cde47b
-		ret = _gnutls_cipher_auth(&handle->ctx_enc,
cde47b
-					  iter.block, iter.block_offset);
cde47b
+		ret = _gnutls_cipher_auth(&handle->ctx_enc, p, ret);
cde47b
 		if (unlikely(ret < 0))
cde47b
 			return gnutls_assert_val(ret);
cde47b
 	}
cde47b
@@ -1070,29 +1062,15 @@ gnutls_aead_cipher_encryptv(gnutls_aead_cipher_hd_t handle,
cde47b
 			return gnutls_assert_val(ret);
cde47b
 		if (ret == 0)
cde47b
 			break;
cde47b
-		blocks = ret;
cde47b
-		if (unlikely(dst_size < blocksize * blocks))
cde47b
-			return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
cde47b
-		ret = _gnutls_cipher_encrypt2(&handle->ctx_enc, p,
cde47b
-					      blocksize * blocks,
cde47b
-					      dst, dst_size);
cde47b
-		if (unlikely(ret < 0))
cde47b
-			return gnutls_assert_val(ret);
cde47b
-		DECR_LEN(dst_size, blocksize * blocks);
cde47b
-		dst += blocksize * blocks;
cde47b
-		total += blocksize * blocks;
cde47b
-	}
cde47b
-	if (iter.block_offset > 0) {
cde47b
-		if (unlikely(dst_size < iter.block_offset))
cde47b
-			return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
cde47b
+		len = ret;
cde47b
 		ret = _gnutls_cipher_encrypt2(&handle->ctx_enc,
cde47b
-					      iter.block, iter.block_offset,
cde47b
+					      p, len,
cde47b
 					      dst, dst_size);
cde47b
 		if (unlikely(ret < 0))
cde47b
 			return gnutls_assert_val(ret);
cde47b
-		DECR_LEN(dst_size, iter.block_offset);
cde47b
-		dst += iter.block_offset;
cde47b
-		total += iter.block_offset;
cde47b
+		DECR_LEN(dst_size, len);
cde47b
+		dst += len;
cde47b
+		total += len;
cde47b
 	}
cde47b
 
cde47b
 	if (dst_size < tag_size)
cde47b
@@ -1137,7 +1115,6 @@ gnutls_aead_cipher_encryptv2(gnutls_aead_cipher_hd_t handle,
cde47b
 	uint8_t *p;
cde47b
 	ssize_t blocksize = handle->ctx_enc.e->blocksize;
cde47b
 	struct iov_iter_st iter;
cde47b
-	size_t blocks;
cde47b
 	size_t _tag_size;
cde47b
 
cde47b
 	if (tag_size == NULL || *tag_size == 0)
cde47b
@@ -1220,15 +1197,7 @@ gnutls_aead_cipher_encryptv2(gnutls_aead_cipher_hd_t handle,
cde47b
 			return gnutls_assert_val(ret);
cde47b
 		if (ret == 0)
cde47b
 			break;
cde47b
-		blocks = ret;
cde47b
-		ret = _gnutls_cipher_auth(&handle->ctx_enc, p,
cde47b
-					  blocksize * blocks);
cde47b
-		if (unlikely(ret < 0))
cde47b
-			return gnutls_assert_val(ret);
cde47b
-	}
cde47b
-	if (iter.block_offset > 0) {
cde47b
-		ret = _gnutls_cipher_auth(&handle->ctx_enc,
cde47b
-					  iter.block, iter.block_offset);
cde47b
+		ret = _gnutls_cipher_auth(&handle->ctx_enc, p, ret);
cde47b
 		if (unlikely(ret < 0))
cde47b
 			return gnutls_assert_val(ret);
cde47b
 	}
cde47b
@@ -1242,17 +1211,7 @@ gnutls_aead_cipher_encryptv2(gnutls_aead_cipher_hd_t handle,
cde47b
 			return gnutls_assert_val(ret);
cde47b
 		if (ret == 0)
cde47b
 			break;
cde47b
-		blocks = ret;
cde47b
-		ret = _gnutls_cipher_encrypt2(&handle->ctx_enc,
cde47b
-					      p, blocksize * blocks,
cde47b
-					      p, blocksize * blocks);
cde47b
-		if (unlikely(ret < 0))
cde47b
-			return gnutls_assert_val(ret);
cde47b
-	}
cde47b
-	if (iter.block_offset > 0) {
cde47b
-		ret = _gnutls_cipher_encrypt2(&handle->ctx_enc,
cde47b
-					      iter.block, iter.block_offset,
cde47b
-					      iter.block, iter.block_offset);
cde47b
+		ret = _gnutls_cipher_encrypt2(&handle->ctx_enc, p, ret, p, ret);
cde47b
 		if (unlikely(ret < 0))
cde47b
 			return gnutls_assert_val(ret);
cde47b
 	}
cde47b
@@ -1296,7 +1255,6 @@ gnutls_aead_cipher_decryptv2(gnutls_aead_cipher_hd_t handle,
cde47b
 	uint8_t *p;
cde47b
 	ssize_t blocksize = handle->ctx_enc.e->blocksize;
cde47b
 	struct iov_iter_st iter;
cde47b
-	size_t blocks;
cde47b
 	uint8_t _tag[MAX_HASH_SIZE];
cde47b
 
cde47b
 	if (tag_size == 0)
cde47b
@@ -1370,15 +1328,7 @@ gnutls_aead_cipher_decryptv2(gnutls_aead_cipher_hd_t handle,
cde47b
 			return gnutls_assert_val(ret);
cde47b
 		if (ret == 0)
cde47b
 			break;
cde47b
-		blocks = ret;
cde47b
-		ret = _gnutls_cipher_auth(&handle->ctx_enc, p,
cde47b
-					  blocksize * blocks);
cde47b
-		if (unlikely(ret < 0))
cde47b
-			return gnutls_assert_val(ret);
cde47b
-	}
cde47b
-	if (iter.block_offset > 0) {
cde47b
-		ret = _gnutls_cipher_auth(&handle->ctx_enc,
cde47b
-					  iter.block, iter.block_offset);
cde47b
+		ret = _gnutls_cipher_auth(&handle->ctx_enc, p, ret);
cde47b
 		if (unlikely(ret < 0))
cde47b
 			return gnutls_assert_val(ret);
cde47b
 	}
cde47b
@@ -1392,17 +1342,7 @@ gnutls_aead_cipher_decryptv2(gnutls_aead_cipher_hd_t handle,
cde47b
 			return gnutls_assert_val(ret);
cde47b
 		if (ret == 0)
cde47b
 			break;
cde47b
-		blocks = ret;
cde47b
-		ret = _gnutls_cipher_decrypt2(&handle->ctx_enc,
cde47b
-					      p, blocksize * blocks,
cde47b
-					      p, blocksize * blocks);
cde47b
-		if (unlikely(ret < 0))
cde47b
-			return gnutls_assert_val(ret);
cde47b
-	}
cde47b
-	if (iter.block_offset > 0) {
cde47b
-		ret = _gnutls_cipher_decrypt2(&handle->ctx_enc,
cde47b
-					      iter.block, iter.block_offset,
cde47b
-					      iter.block, iter.block_offset);
cde47b
+		ret = _gnutls_cipher_decrypt2(&handle->ctx_enc, p, ret, p, ret);
cde47b
 		if (unlikely(ret < 0))
cde47b
 			return gnutls_assert_val(ret);
cde47b
 	}
cde47b
diff --git a/lib/iov.c b/lib/iov.c
cde47b
index 5dc29c54b..17272886c 100644
cde47b
--- a/lib/iov.c
cde47b
+++ b/lib/iov.c
cde47b
@@ -58,8 +58,8 @@ _gnutls_iov_iter_init(struct iov_iter_st *iter,
cde47b
  * @data: the return location of extracted data
cde47b
  *
cde47b
  * Retrieve block(s) pointed by @iter and advance it to the next
cde47b
- * position.  It returns the number of consecutive blocks in @data.
cde47b
- * At the end of iteration, 0 is returned.
cde47b
+ * position.  It returns the number of bytes in @data.  At the end of
cde47b
+ * iteration, 0 is returned.
cde47b
  *
cde47b
  * If the data stored in @iter is not multiple of the block size, the
cde47b
  * remaining data is stored in the "block" field of @iter with the
cde47b
@@ -88,25 +88,30 @@ _gnutls_iov_iter_next(struct iov_iter_st *iter, uint8_t **data)
cde47b
 			if ((len % iter->block_size) == 0) {
cde47b
 				iter->iov_index++;
cde47b
 				iter->iov_offset = 0;
cde47b
-			} else
cde47b
-				iter->iov_offset +=
cde47b
-					len - (len % iter->block_size);
cde47b
+			} else {
cde47b
+				len -= (len % iter->block_size);
cde47b
+				iter->iov_offset += len;
cde47b
+			}
cde47b
 
cde47b
 			/* Return the blocks. */
cde47b
 			*data = p;
cde47b
-			return len / iter->block_size;
cde47b
+			return len;
cde47b
 		}
cde47b
 
cde47b
 		/* We can complete one full block to return. */
cde47b
 		block_left = iter->block_size - iter->block_offset;
cde47b
 		if (len >= block_left) {
cde47b
 			memcpy(iter->block + iter->block_offset, p, block_left);
cde47b
-			iter->iov_offset += block_left;
cde47b
+			if (len == block_left) {
cde47b
+				iter->iov_index++;
cde47b
+				iter->iov_offset = 0;
cde47b
+			} else
cde47b
+				iter->iov_offset += block_left;
cde47b
 			iter->block_offset = 0;
cde47b
 
cde47b
 			/* Return the filled block. */
cde47b
 			*data = iter->block;
cde47b
-			return 1;
cde47b
+			return iter->block_size;
cde47b
 		}
cde47b
 
cde47b
 		/* Not enough data for a full block, store in temp
cde47b
@@ -116,5 +121,15 @@ _gnutls_iov_iter_next(struct iov_iter_st *iter, uint8_t **data)
cde47b
 		iter->iov_index++;
cde47b
 		iter->iov_offset = 0;
cde47b
 	}
cde47b
+
cde47b
+	if (iter->block_offset > 0) {
cde47b
+		size_t len = iter->block_offset;
cde47b
+
cde47b
+		/* Return the incomplete block. */
cde47b
+		*data = iter->block;
cde47b
+		iter->block_offset = 0;
cde47b
+		return len;
cde47b
+	}
cde47b
+
cde47b
 	return 0;
cde47b
 }
cde47b
diff --git a/tests/iov.c b/tests/iov.c
cde47b
index eda5583a7..3d116b471 100644
cde47b
--- a/tests/iov.c
cde47b
+++ b/tests/iov.c
cde47b
@@ -32,7 +32,6 @@ struct exp_st {
cde47b
 	ssize_t ret;
cde47b
 	size_t iov_index;
cde47b
 	size_t iov_offset;
cde47b
-	size_t block_offset;
cde47b
 };
cde47b
 
cde47b
 struct test_st {
cde47b
@@ -42,7 +41,6 @@ struct test_st {
cde47b
 	size_t block_size;
cde47b
 	const struct exp_st *exp;
cde47b
 	size_t expcnt;
cde47b
-	size_t remaining;
cde47b
 };
cde47b
 
cde47b
 static const giovec_t iov16[] = {
cde47b
@@ -53,40 +51,41 @@ static const giovec_t iov16[] = {
cde47b
 };
cde47b
 
cde47b
 static const struct exp_st exp16_64[] = {
cde47b
-	{1, 3, 16, 0},
cde47b
-	{0, 0, 0, 0}
cde47b
+	{64, 4, 0},
cde47b
+	{0, 0, 0}
cde47b
 };
cde47b
 
cde47b
 static const struct exp_st exp16_32[] = {
cde47b
-	{1, 1, 16, 0},
cde47b
-	{1, 3, 16, 0},
cde47b
-	{0, 0, 0, 0}
cde47b
+	{32, 2, 0},
cde47b
+	{32, 4, 0},
cde47b
+	{0, 0, 0}
cde47b
 };
cde47b
 
cde47b
 static const struct exp_st exp16_16[] = {
cde47b
-	{1, 1, 0, 0},
cde47b
-	{1, 2, 0, 0},
cde47b
-	{1, 3, 0, 0},
cde47b
-	{1, 4, 0, 0},
cde47b
-	{0, 0, 0, 0}
cde47b
+	{16, 1, 0},
cde47b
+	{16, 2, 0},
cde47b
+	{16, 3, 0},
cde47b
+	{16, 4, 0},
cde47b
+	{0, 0, 0}
cde47b
 };
cde47b
 
cde47b
 static const struct exp_st exp16_4[] = {
cde47b
-	{4, 1, 0, 0},
cde47b
-	{4, 2, 0, 0},
cde47b
-	{4, 3, 0, 0},
cde47b
-	{4, 4, 0, 0},
cde47b
-	{0, 0, 0, 0}
cde47b
+	{16, 1, 0},
cde47b
+	{16, 2, 0},
cde47b
+	{16, 3, 0},
cde47b
+	{16, 4, 0},
cde47b
+	{0, 0, 0}
cde47b
 };
cde47b
 
cde47b
 static const struct exp_st exp16_3[] = {
cde47b
-	{5, 0, 15, 0},
cde47b
-	{1, 1, 2, 0},
cde47b
-	{4, 1, 14, 0},
cde47b
-	{1, 2, 1, 0},
cde47b
-	{5, 3, 0, 0},
cde47b
-	{5, 3, 15, 0},
cde47b
-	{0, 0, 0, 1}
cde47b
+	{15, 0, 15},
cde47b
+	{3, 1, 2},
cde47b
+	{12, 1, 14},
cde47b
+	{3, 2, 1},
cde47b
+	{15, 3, 0},
cde47b
+	{15, 3, 15},
cde47b
+	{1, 4, 0},
cde47b
+	{0, 0, 0}
cde47b
 };
cde47b
 
cde47b
 static const giovec_t iov8[] = {
cde47b
@@ -97,22 +96,74 @@ static const giovec_t iov8[] = {
cde47b
 };
cde47b
 
cde47b
 static const struct exp_st exp8_64[] = {
cde47b
-	{0, 0, 0, 32}
cde47b
+	{32, 4, 0},
cde47b
+	{0, 0, 0}
cde47b
+};
cde47b
+
cde47b
+static const giovec_t iov_odd[] = {
cde47b
+	{(void *) "0", 1},
cde47b
+	{(void *) "012", 3},
cde47b
+	{(void *) "01234", 5},
cde47b
+	{(void *) "0123456", 7},
cde47b
+	{(void *) "012345678", 9},
cde47b
+	{(void *) "01234567890", 11},
cde47b
+	{(void *) "0123456789012", 13},
cde47b
+	{(void *) "012345678901234", 15}
cde47b
+};
cde47b
+
cde47b
+static const struct exp_st exp_odd_16[] = {
cde47b
+	{16, 4, 0},
cde47b
+	{16, 5, 7},
cde47b
+	{16, 6, 12},
cde47b
+	{16, 8, 0},
cde47b
+	{0, 0, 0}
cde47b
+};
cde47b
+
cde47b
+static const giovec_t iov_skip[] = {
cde47b
+	{(void *) "0123456789012345", 16},
cde47b
+	{(void *) "01234567", 8},
cde47b
+	{(void *) "", 0},
cde47b
+	{(void *) "", 0},
cde47b
+	{(void *) "0123456789012345", 16}
cde47b
+};
cde47b
+
cde47b
+static const struct exp_st exp_skip_16[] = {
cde47b
+	{16, 1, 0},
cde47b
+	{16, 4, 8},
cde47b
+	{8, 5, 0},
cde47b
+	{0, 0, 0}
cde47b
+};
cde47b
+
cde47b
+static const giovec_t iov_empty[] = {
cde47b
+	{(void *) "", 0},
cde47b
+	{(void *) "", 0},
cde47b
+	{(void *) "", 0},
cde47b
+	{(void *) "", 0}
cde47b
+};
cde47b
+
cde47b
+static const struct exp_st exp_empty_16[] = {
cde47b
+	{0, 0, 0}
cde47b
 };
cde47b
 
cde47b
 static const struct test_st tests[] = {
cde47b
 	{ "16/64", iov16, sizeof(iov16)/sizeof(iov16[0]), 64,
cde47b
-	  exp16_64, sizeof(exp16_64)/sizeof(exp16_64[0]), 0 },
cde47b
+	  exp16_64, sizeof(exp16_64)/sizeof(exp16_64[0]) },
cde47b
 	{ "16/32", iov16, sizeof(iov16)/sizeof(iov16[0]), 32,
cde47b
-	  exp16_32, sizeof(exp16_32)/sizeof(exp16_32[0]), 0 },
cde47b
+	  exp16_32, sizeof(exp16_32)/sizeof(exp16_32[0]) },
cde47b
 	{ "16/16", iov16, sizeof(iov16)/sizeof(iov16[0]), 16,
cde47b
-	  exp16_16, sizeof(exp16_16)/sizeof(exp16_16[0]), 0 },
cde47b
+	  exp16_16, sizeof(exp16_16)/sizeof(exp16_16[0]) },
cde47b
 	{ "16/4", iov16, sizeof(iov16)/sizeof(iov16[0]), 4,
cde47b
-	  exp16_4, sizeof(exp16_4)/sizeof(exp16_4[0]), 0 },
cde47b
+	  exp16_4, sizeof(exp16_4)/sizeof(exp16_4[0]) },
cde47b
 	{ "16/3", iov16, sizeof(iov16)/sizeof(iov16[0]), 3,
cde47b
-	  exp16_3, sizeof(exp16_3)/sizeof(exp16_3[0]), 1 },
cde47b
+	  exp16_3, sizeof(exp16_3)/sizeof(exp16_3[0]) },
cde47b
 	{ "8/64", iov8, sizeof(iov8)/sizeof(iov8[0]), 64,
cde47b
-	  exp8_64, sizeof(exp8_64)/sizeof(exp8_64[0]), 32 }
cde47b
+	  exp8_64, sizeof(exp8_64)/sizeof(exp8_64[0]) },
cde47b
+	{ "odd/16", iov_odd, sizeof(iov_odd)/sizeof(iov_odd[0]), 16,
cde47b
+	  exp_odd_16, sizeof(exp_odd_16)/sizeof(exp_odd_16[0]) },
cde47b
+	{ "skip/16", iov_skip, sizeof(iov_skip)/sizeof(iov_skip[0]), 16,
cde47b
+	  exp_skip_16, sizeof(exp_skip_16)/sizeof(exp_skip_16[0]) },
cde47b
+	{ "empty/16", iov_empty, sizeof(iov_empty)/sizeof(iov_empty[0]), 16,
cde47b
+	  exp_empty_16, sizeof(exp_empty_16)/sizeof(exp_empty_16[0]) },
cde47b
 };
cde47b
 
cde47b
 void
cde47b
@@ -155,16 +206,13 @@ doit (void)
cde47b
 				else if (debug)
cde47b
 					success("iter.iov_offset: %u == %u\n",
cde47b
 					     (unsigned) iter.iov_offset, (unsigned) exp[j].iov_offset);
cde47b
-				if (iter.block_offset != exp[j].block_offset)
cde47b
-					fail("iter.block_offset: %u != %u\n",
cde47b
-					     (unsigned) iter.block_offset, (unsigned) exp[j].block_offset);
cde47b
+				if (iter.block_offset != 0)
cde47b
+					fail("iter.block_offset: %u != 0\n",
cde47b
+					     (unsigned) iter.block_offset);
cde47b
 				else if (debug)
cde47b
-					success("iter.block_offset: %u == %u\n",
cde47b
-					     (unsigned) iter.block_offset, (unsigned) exp[j].block_offset);
cde47b
+					success("iter.block_offset: %u == 0\n",
cde47b
+					     (unsigned) iter.block_offset);
cde47b
 			}
cde47b
 		}
cde47b
-		if (iter.block_offset != tests[i].remaining)
cde47b
-			fail("remaining: %u != %u\n",
cde47b
-			     (unsigned) iter.block_offset, (unsigned) tests[i].remaining);
cde47b
 	}
cde47b
 }
cde47b
-- 
cde47b
2.21.0
cde47b
cde47b
cde47b
From c684814cc456a9792a9183ce77d32d435f29e6b7 Mon Sep 17 00:00:00 2001
cde47b
From: Daiki Ueno <dueno@redhat.com>
cde47b
Date: Tue, 1 Oct 2019 18:14:48 +0200
cde47b
Subject: [PATCH 2/3] iov: add _gnutls_iov_iter_sync to write back cached data
cde47b
 to iov
cde47b
cde47b
Signed-off-by: Daiki Ueno <dueno@redhat.com>
cde47b
---
cde47b
 lib/iov.c         | 59 +++++++++++++++++++++++++++++++++++++++++++++
cde47b
 lib/iov.h         |  4 +++-
cde47b
 lib/libgnutls.map |  1 +
cde47b
 tests/iov.c       | 61 +++++++++++++++++++++++++++++++++++++++++++----
cde47b
 4 files changed, 119 insertions(+), 6 deletions(-)
cde47b
cde47b
diff --git a/lib/iov.c b/lib/iov.c
cde47b
index 17272886c..1cd8d46dd 100644
cde47b
--- a/lib/iov.c
cde47b
+++ b/lib/iov.c
cde47b
@@ -133,3 +133,62 @@ _gnutls_iov_iter_next(struct iov_iter_st *iter, uint8_t **data)
cde47b
 
cde47b
 	return 0;
cde47b
 }
cde47b
+
cde47b
+/**
cde47b
+ * _gnutls_iov_iter_sync:
cde47b
+ * @iter: the iterator
cde47b
+ * @data: data returned by _gnutls_iov_iter_next
cde47b
+ * @data_size: size of @data
cde47b
+ *
cde47b
+ * Flush the content of temp buffer (if any) to the data buffer.
cde47b
+ */
cde47b
+int
cde47b
+_gnutls_iov_iter_sync(struct iov_iter_st *iter, const uint8_t *data,
cde47b
+		      size_t data_size)
cde47b
+{
cde47b
+	size_t iov_index;
cde47b
+	size_t iov_offset;
cde47b
+
cde47b
+	/* We didn't return the cached block. */
cde47b
+	if (data != iter->block)
cde47b
+		return 0;
cde47b
+
cde47b
+	iov_index = iter->iov_index;
cde47b
+	iov_offset = iter->iov_offset;
cde47b
+
cde47b
+	/* When syncing a cache block we walk backwards because we only have a
cde47b
+	 * pointer to were the block ends in the iovec, walking backwards is
cde47b
+	 * fine as we are always writing a full block, so the whole content
cde47b
+	 * is written in the right places:
cde47b
+	 * iovec:     |--0--|---1---|--2--|-3-|
cde47b
+	 * block:     |-----------------------|
cde47b
+	 * 1st write                      |---|
cde47b
+	 * 2nd write                |-----
cde47b
+	 * 3rd write        |-------
cde47b
+	 * last write |-----
cde47b
+	 */
cde47b
+	while (data_size > 0) {
cde47b
+		const giovec_t *iov;
cde47b
+		uint8_t *p;
cde47b
+		size_t to_write;
cde47b
+
cde47b
+		while (iov_offset == 0) {
cde47b
+			if (unlikely(iov_index == 0))
cde47b
+				return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
cde47b
+
cde47b
+			iov_index--;
cde47b
+			iov_offset = iter->iov[iov_index].iov_len;
cde47b
+		}
cde47b
+
cde47b
+		iov = &iter->iov[iov_index];
cde47b
+		p = iov->iov_base;
cde47b
+		to_write = MIN(data_size, iov_offset);
cde47b
+
cde47b
+		iov_offset -= to_write;
cde47b
+		data_size -= to_write;
cde47b
+
cde47b
+		memcpy(p + iov_offset, &iter->block[data_size], to_write);
cde47b
+	}
cde47b
+
cde47b
+	return 0;
cde47b
+}
cde47b
diff --git a/lib/iov.h b/lib/iov.h
cde47b
index 47fba559a..5b9903460 100644
cde47b
--- a/lib/iov.h
cde47b
+++ b/lib/iov.h
cde47b
@@ -34,7 +34,6 @@ struct iov_iter_st {
cde47b
 	uint8_t block[MAX_CIPHER_BLOCK_SIZE]; /* incomplete block for reading */
cde47b
 	size_t block_size;	/* actual block size of the cipher */
cde47b
 	size_t block_offset;	/* offset in block */
cde47b
-
cde47b
 };
cde47b
 
cde47b
 int _gnutls_iov_iter_init(struct iov_iter_st *iter,
cde47b
@@ -43,4 +42,7 @@ int _gnutls_iov_iter_init(struct iov_iter_st *iter,
cde47b
 
cde47b
 ssize_t _gnutls_iov_iter_next(struct iov_iter_st *iter, uint8_t **data);
cde47b
 
cde47b
+int _gnutls_iov_iter_sync(struct iov_iter_st *iter, const uint8_t *data,
cde47b
+			  size_t data_size);
cde47b
+
cde47b
 #endif /* GNUTLS_LIB_IOV_H */
cde47b
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
cde47b
index f83a21e9b..d6973f72e 100644
cde47b
--- a/lib/libgnutls.map
cde47b
+++ b/lib/libgnutls.map
cde47b
@@ -1394,4 +1394,5 @@ GNUTLS_PRIVATE_3_4 {
cde47b
 	# needed by tests/iov:
cde47b
 	_gnutls_iov_iter_init;
cde47b
 	_gnutls_iov_iter_next;
cde47b
+	_gnutls_iov_iter_sync;
cde47b
 } GNUTLS_3_4;
cde47b
diff --git a/tests/iov.c b/tests/iov.c
cde47b
index 3d116b471..2acd2b5f5 100644
cde47b
--- a/tests/iov.c
cde47b
+++ b/tests/iov.c
cde47b
@@ -44,10 +44,10 @@ struct test_st {
cde47b
 };
cde47b
 
cde47b
 static const giovec_t iov16[] = {
cde47b
-	{(void *) "0123456789abcdef", 16},
cde47b
-	{(void *) "0123456789abcdef", 16},
cde47b
-	{(void *) "0123456789abcdef", 16},
cde47b
-	{(void *) "0123456789abcdef", 16}
cde47b
+	{(void *) "0123456789012345", 16},
cde47b
+	{(void *) "0123456789012345", 16},
cde47b
+	{(void *) "0123456789012345", 16},
cde47b
+	{(void *) "0123456789012345", 16}
cde47b
 };
cde47b
 
cde47b
 static const struct exp_st exp16_64[] = {
cde47b
@@ -166,20 +166,53 @@ static const struct test_st tests[] = {
cde47b
 	  exp_empty_16, sizeof(exp_empty_16)/sizeof(exp_empty_16[0]) },
cde47b
 };
cde47b
 
cde47b
+static void
cde47b
+copy(giovec_t *dst, uint8_t *buffer, const giovec_t *src, size_t iovcnt)
cde47b
+{
cde47b
+	uint8_t *p = buffer;
cde47b
+	size_t i;
cde47b
+
cde47b
+	for (i = 0; i < iovcnt; i++) {
cde47b
+		dst[i].iov_base = p;
cde47b
+		dst[i].iov_len = src[i].iov_len;
cde47b
+		memcpy(dst[i].iov_base, src[i].iov_base, src[i].iov_len);
cde47b
+		p += src[i].iov_len;
cde47b
+	}
cde47b
+}
cde47b
+
cde47b
+static void
cde47b
+translate(uint8_t *data, size_t len)
cde47b
+{
cde47b
+	for (; len > 0; len--) {
cde47b
+		uint8_t *p = &data[len - 1];
cde47b
+		if (*p >= '0' && *p <= '9')
cde47b
+			*p = 'A' + *p - '0';
cde47b
+		else if (*p >= 'A' && *p <= 'Z')
cde47b
+			*p = '0' + *p - 'A';
cde47b
+	}
cde47b
+}
cde47b
+
cde47b
+#define MAX_BUF 1024
cde47b
+#define MAX_IOV 16
cde47b
+
cde47b
 void
cde47b
 doit (void)
cde47b
 {
cde47b
+	uint8_t buffer[MAX_BUF];
cde47b
 	size_t i;
cde47b
 
cde47b
 	for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
cde47b
+		giovec_t iov[MAX_IOV];
cde47b
 		struct iov_iter_st iter;
cde47b
 		const struct exp_st *exp = tests[i].exp;
cde47b
 		uint8_t *data;
cde47b
 		size_t j;
cde47b
 
cde47b
+		copy(iov, buffer, tests[i].iov, tests[i].iovcnt);
cde47b
+
cde47b
 		success("%s\n", tests[i].name);
cde47b
 		assert(_gnutls_iov_iter_init(&iter,
cde47b
-					     tests[i].iov, tests[i].iovcnt,
cde47b
+					     iov, tests[i].iovcnt,
cde47b
 					     tests[i].block_size) == 0);
cde47b
 		for (j = 0; j < tests[i].expcnt; j++) {
cde47b
 			ssize_t ret;
cde47b
@@ -212,7 +245,25 @@ doit (void)
cde47b
 				else if (debug)
cde47b
 					success("iter.block_offset: %u == 0\n",
cde47b
 					     (unsigned) iter.block_offset);
cde47b
+
cde47b
+				translate(data, ret);
cde47b
+
cde47b
+				ret = _gnutls_iov_iter_sync(&iter, data, ret);
cde47b
+				if (ret < 0)
cde47b
+					fail("sync failed\n");
cde47b
 			}
cde47b
 		}
cde47b
+
cde47b
+		for (j = 0; j < tests[i].iovcnt; j++) {
cde47b
+			translate(iov[j].iov_base, iov[j].iov_len);
cde47b
+
cde47b
+			if (memcmp(iov[j].iov_base, tests[i].iov[j].iov_base,
cde47b
+				   iov[j].iov_len) != 0)
cde47b
+				fail("iov doesn't match: %*s != %*s\n",
cde47b
+				     (int)iov[j].iov_len,
cde47b
+				     (char *)iov[j].iov_base,
cde47b
+				     (int)tests[i].iov[j].iov_len,
cde47b
+				     (char *)tests[i].iov[j].iov_len);
cde47b
+		}
cde47b
 	}
cde47b
 }
cde47b
-- 
cde47b
2.21.0
cde47b
cde47b
cde47b
From 6df0cf1c0ec727fc237a9b429684c8f2ef5d34b7 Mon Sep 17 00:00:00 2001
cde47b
From: Daiki Ueno <dueno@redhat.com>
cde47b
Date: Tue, 1 Oct 2019 18:15:19 +0200
cde47b
Subject: [PATCH 3/3] gnutls_aead_cipher_{en,de}cryptv2: write back cached data
cde47b
 to buffers
cde47b
cde47b
Previously, those functions failed to write the output to the buffers
cde47b
if the buffer length is not multiple of cipher block size.  This makes
cde47b
sure that the cached data is always flushed.
cde47b
cde47b
Signed-off-by: Daiki Ueno <dueno@redhat.com>
cde47b
---
cde47b
 lib/crypto-api.c        | 18 ++++++++++++++++--
cde47b
 tests/aead-cipher-vec.c | 14 ++++++++------
cde47b
 2 files changed, 24 insertions(+), 8 deletions(-)
cde47b
cde47b
diff --git a/lib/crypto-api.c b/lib/crypto-api.c
cde47b
index 41e759b74..7308d7e7b 100644
cde47b
--- a/lib/crypto-api.c
cde47b
+++ b/lib/crypto-api.c
cde47b
@@ -1113,6 +1113,7 @@ gnutls_aead_cipher_encryptv2(gnutls_aead_cipher_hd_t handle,
cde47b
 	api_aead_cipher_hd_st *h = handle;
cde47b
 	ssize_t ret;
cde47b
 	uint8_t *p;
cde47b
+	size_t len;
cde47b
 	ssize_t blocksize = handle->ctx_enc.e->blocksize;
cde47b
 	struct iov_iter_st iter;
cde47b
 	size_t _tag_size;
cde47b
@@ -1211,7 +1212,13 @@ gnutls_aead_cipher_encryptv2(gnutls_aead_cipher_hd_t handle,
cde47b
 			return gnutls_assert_val(ret);
cde47b
 		if (ret == 0)
cde47b
 			break;
cde47b
-		ret = _gnutls_cipher_encrypt2(&handle->ctx_enc, p, ret, p, ret);
cde47b
+
cde47b
+		len = ret;
cde47b
+		ret = _gnutls_cipher_encrypt2(&handle->ctx_enc, p, len, p, len);
cde47b
+		if (unlikely(ret < 0))
cde47b
+			return gnutls_assert_val(ret);
cde47b
+
cde47b
+		ret = _gnutls_iov_iter_sync(&iter, p, len);
cde47b
 		if (unlikely(ret < 0))
cde47b
 			return gnutls_assert_val(ret);
cde47b
 	}
cde47b
@@ -1253,6 +1260,7 @@ gnutls_aead_cipher_decryptv2(gnutls_aead_cipher_hd_t handle,
cde47b
 	api_aead_cipher_hd_st *h = handle;
cde47b
 	ssize_t ret;
cde47b
 	uint8_t *p;
cde47b
+	size_t len;
cde47b
 	ssize_t blocksize = handle->ctx_enc.e->blocksize;
cde47b
 	struct iov_iter_st iter;
cde47b
 	uint8_t _tag[MAX_HASH_SIZE];
cde47b
@@ -1342,7 +1350,13 @@ gnutls_aead_cipher_decryptv2(gnutls_aead_cipher_hd_t handle,
cde47b
 			return gnutls_assert_val(ret);
cde47b
 		if (ret == 0)
cde47b
 			break;
cde47b
-		ret = _gnutls_cipher_decrypt2(&handle->ctx_enc, p, ret, p, ret);
cde47b
+
cde47b
+		len = ret;
cde47b
+		ret = _gnutls_cipher_decrypt2(&handle->ctx_enc, p, len, p, len);
cde47b
+		if (unlikely(ret < 0))
cde47b
+			return gnutls_assert_val(ret);
cde47b
+
cde47b
+		ret = _gnutls_iov_iter_sync(&iter, p, len);
cde47b
 		if (unlikely(ret < 0))
cde47b
 			return gnutls_assert_val(ret);
cde47b
 	}
cde47b
diff --git a/tests/aead-cipher-vec.c b/tests/aead-cipher-vec.c
cde47b
index 6c2542cf1..10e3db862 100644
cde47b
--- a/tests/aead-cipher-vec.c
cde47b
+++ b/tests/aead-cipher-vec.c
cde47b
@@ -43,9 +43,9 @@ static void start(const char *name, int algo)
cde47b
 	uint8_t key16[64];
cde47b
 	uint8_t iv16[32];
cde47b
 	uint8_t auth[128];
cde47b
-	uint8_t data[128+64];
cde47b
+	uint8_t data[64+56+36];
cde47b
 	gnutls_datum_t key, iv;
cde47b
-	giovec_t iov[2];
cde47b
+	giovec_t iov[3];
cde47b
 	giovec_t auth_iov[2];
cde47b
 	uint8_t tag[64];
cde47b
 	size_t tag_size = 0;
cde47b
@@ -60,13 +60,15 @@ static void start(const char *name, int algo)
cde47b
 
cde47b
 	memset(iv.data, 0xff, iv.size);
cde47b
 	memset(key.data, 0xfe, key.size);
cde47b
-	memset(data, 0xfa, 128);
cde47b
+	memset(data, 0xfa, sizeof(data));
cde47b
 	memset(auth, 0xaa, sizeof(auth));
cde47b
 
cde47b
 	iov[0].iov_base = data;
cde47b
 	iov[0].iov_len = 64;
cde47b
 	iov[1].iov_base = data + 64;
cde47b
-	iov[1].iov_len = 64;
cde47b
+	iov[1].iov_len = 56;
cde47b
+	iov[2].iov_base = data + 64 + 56;
cde47b
+	iov[2].iov_len = 36;
cde47b
 
cde47b
 	auth_iov[0].iov_base = auth;
cde47b
 	auth_iov[0].iov_len = 64;
cde47b
@@ -83,7 +85,7 @@ static void start(const char *name, int algo)
cde47b
 	ret = gnutls_aead_cipher_encryptv2(ch,
cde47b
 					   iv.data, iv.size,
cde47b
 					   auth_iov, 2,
cde47b
-					   iov, 2,
cde47b
+					   iov, 3,
cde47b
 					   tag, &tag_size);
cde47b
 	if (ret < 0)
cde47b
 		fail("could not encrypt data: %s\n", gnutls_strerror(ret));
cde47b
@@ -91,7 +93,7 @@ static void start(const char *name, int algo)
cde47b
 	ret = gnutls_aead_cipher_decryptv2(ch,
cde47b
 					   iv.data, iv.size,
cde47b
 					   auth_iov, 2,
cde47b
-					   iov, 2,
cde47b
+					   iov, 3,
cde47b
 					   tag, tag_size);
cde47b
 	if (ret < 0)
cde47b
 		fail("could not decrypt data: %s\n", gnutls_strerror(ret));
cde47b
-- 
cde47b
2.21.0
cde47b