Really fix byte budget calculation.
authorGuus Sliepen <guus@tinc-vpn.org>
Sat, 29 Oct 2016 20:10:32 +0000 (22:10 +0200)
committerGuus Sliepen <guus@tinc-vpn.org>
Sat, 29 Oct 2016 20:10:32 +0000 (22:10 +0200)
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.

src/protocol_auth.c

index 96e6b6e2953ccc39d34944aa9e22f87425010e3b..8288847e5ec1823ff7896a48513fd75405630b74 100644 (file)
@@ -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;