You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by tw...@apache.org on 2021/07/11 22:26:22 UTC

[mina-sshd] 01/03: [SSHD-1191] Abstract session: correct rekey block count limit

This is an automated email from the ASF dual-hosted git repository.

twolf pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git

commit 1c5987d4130f5883795d0098c69cf04cc619b11b
Author: Thomas Wolf <tw...@apache.org>
AuthorDate: Sun Jul 11 23:35:29 2021 +0200

    [SSHD-1191] Abstract session: correct rekey block count limit
    
    Follow the recommendation from RFC 4344: if the cipher block size
    is smaller than 16, re-key after 1GB of data.[1] Otherwise, we'd
    re-key far too often; for instance with a block size of 8 after 64k
    blocks, i.e., after 512kB of data. Note that chacha20-poly1305 has
    a block size of 8.
    
    OpenSSH uses the same implementation.[2]
    
    [1] https://datatracker.ietf.org/doc/html/rfc4344#section-3.2
    [2]https://github.com/openssh/openssh-portable/blob/99981d5f/packet.c#L940
---
 .../common/session/helpers/AbstractSession.java    | 49 ++++++++++++++++++----
 1 file changed, 40 insertions(+), 9 deletions(-)

diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java b/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java
index 14da167..ffd0d2c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java
@@ -1760,16 +1760,10 @@ public abstract class AbstractSession extends SessionHelper {
         // TODO add support for configurable compression level
         inCompression.init(Compression.Type.Inflater, -1);
 
-        // see https://tools.ietf.org/html/rfc4344#section-3.2
-        // select the lowest cipher size
-        int avgCipherBlockSize = Math.min(inCipherSize, outCipherSize);
-        long recommendedByteRekeyBlocks = 1L << Math.min((avgCipherBlockSize * Byte.SIZE) / 4,
-                63); // in case (block-size / 4) > 63
-        long effectiveRekeyBlocksCount = CoreModuleProperties.REKEY_BLOCKS_LIMIT.getRequired(this);
-        maxRekeyBlocks.set(effectiveRekeyBlocksCount > 0 ? effectiveRekeyBlocksCount : recommendedByteRekeyBlocks);
+        maxRekeyBlocks.set(determineRekeyBlockLimit(inCipherSize, outCipherSize));
         if (debugEnabled) {
-            log.debug("receiveNewKeys({}) inCipher={}, outCipher={}, recommended blocks limit={}, actual={}",
-                    this, inCipher, outCipher, recommendedByteRekeyBlocks, maxRekeyBlocks);
+            log.debug("receiveNewKeys({}) inCipher={}, outCipher={}, blocks limit={}", this, inCipher, outCipher,
+                    maxRekeyBlocks);
         }
 
         inBytesCount.set(0L);
@@ -1783,6 +1777,43 @@ public abstract class AbstractSession extends SessionHelper {
     }
 
     /**
+     * Compute the number of blocks after which we should re-key again. See RFC 4344.
+     *
+     * @param  inCipherBlockSize  block size of the input cipher
+     * @param  outCipherBlockSize block size of the output cipher
+     * @return                    the number of block after which re-keying occur at the latest
+     * @see                       <a href= "https://tools.ietf.org/html/rfc4344#section-3.2">RFC 4344, section 3.2</a>
+     */
+    protected long determineRekeyBlockLimit(int inCipherBlockSize, int outCipherBlockSize) {
+        // see https://tools.ietf.org/html/rfc4344#section-3.2
+        // select the lowest cipher size
+        long rekeyBlocksLimit = CoreModuleProperties.REKEY_BLOCKS_LIMIT.getRequired(this);
+        if (rekeyBlocksLimit <= 0) {
+            // Default per RFC 4344
+            int minCipherBlockBytes = Math.min(inCipherSize, outCipherSize);
+            if (minCipherBlockBytes >= 16) {
+                rekeyBlocksLimit = 1L << Math.min(minCipherBlockBytes * 2, 63);
+            } else {
+                // With a block size of 8 we'd end up with 2^16. That would re-key very often.
+                // RFC 4344: "If L is less than 128 [...], then, although it may be too
+                // expensive to rekey every 2**(L/4) blocks, it is still advisable for SSH
+                // implementations to follow the original recommendation in [RFC4253]: rekey at
+                // least once for every gigabyte of transmitted data."
+                //
+                // Note that chacha20-poly1305 has a block size of 8. The OpenSSH recommendation
+                // is: "ChaCha20 must never reuse a {key, nonce} for encryption nor may it be
+                // used to encrypt more than 2^70 bytes under the same {key, nonce}. The
+                // SSH Transport protocol (RFC4253) recommends a far more conservative
+                // rekeying every 1GB of data sent or received. If this recommendation
+                // is followed, then chacha20-poly1305@openssh.com requires no special
+                // handling in this area."
+                rekeyBlocksLimit = (1L << 30) / minCipherBlockBytes; // 1GB
+            }
+        }
+        return rekeyBlocksLimit;
+    }
+
+    /**
      * Send a {@code SSH_MSG_UNIMPLEMENTED} packet. This packet should contain the sequence id of the unsupported
      * packet: this number is assumed to be the last packet received.
      *