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

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