From: Guus Sliepen <guus@tinc-vpn.org>
Date: Sat, 29 Oct 2016 20:10:32 +0000 (+0200)
Subject: Really fix byte budget calculation.
X-Git-Tag: release-1.0.30~3
X-Git-Url: http://git.tinc-vpn.org/git/browse?a=commitdiff_plain;h=5c8a2a840a648b65b1396efbb0ddb84151ddc7e3;p=tinc

Really fix byte budget calculation.

We want to use the underlying cipher's block length, but if it's a stream
mode this will be 1. In that case, use the IV length. Ensure we never get
a budget that cannot be stored in a 64 bits integer.

Thanks to Wessel Dankers for helping getting this right.
---

diff --git a/src/protocol_auth.c b/src/protocol_auth.c
index 96e6b6e2..8288847e 100644
--- a/src/protocol_auth.c
+++ b/src/protocol_auth.c
@@ -113,6 +113,21 @@ bool id_h(connection_t *c) {
 	return send_metakey(c);
 }
 
+static uint64_t byte_budget(const EVP_CIPHER *cipher) {
+	/* Hopefully some failsafe way to calculate the maximum amount of bytes to
+	   send/receive with a given cipher before we might run into birthday paradox
+	   attacks. Because we might use different modes, the block size of the mode
+	   might be 1 byte. In that case, use the IV length. Ensure the whole thing
+	   is limited to what can be represented with a 64 bits integer.
+	 */
+
+	int ivlen = EVP_CIPHER_iv_length(cipher);
+	int blklen = EVP_CIPHER_block_size(cipher);
+	int len = blklen > 1 ? blklen : ivlen > 1 ? ivlen : 8;
+	int bits = len * 4 - 1;
+	return bits < 64 ? UINT64_C(1) << bits : UINT64_MAX;
+}
+
 bool send_metakey(connection_t *c) {
 	bool x;
 
@@ -195,7 +210,7 @@ bool send_metakey(connection_t *c) {
 			return false;
 		}
 
-		c->outbudget = (uint64_t)1 << EVP_CIPHER_key_length(c->outcipher) * 4;
+		c->outbudget = byte_budget(c->outcipher);
 		c->status.encryptout = true;
 	}
 
@@ -274,7 +289,7 @@ bool metakey_h(connection_t *c) {
 			return false;
 		}
 
-		c->inbudget = (uint64_t)1 << EVP_CIPHER_key_length(c->incipher) * 4;
+		c->inbudget = byte_budget(c->incipher);
 		c->status.decryptin = true;
 	} else {
 		c->incipher = NULL;