]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Do not attempt to decrypt packets anymore after 2**36 failed decryptions
authorArne Schwabe <arne@rfc2549.org>
Thu, 9 Jan 2025 17:49:28 +0000 (18:49 +0100)
committerGert Doering <gert@greenie.muc.de>
Thu, 9 Jan 2025 21:20:56 +0000 (22:20 +0100)
To avoid attacks (especially on Chacha20-Poly1305) we do not allow
decryption anymore after 2**36 failed verifications.

After 2**35, we trigger a renegotiation (to avoid that situation).

For the theoretical background, see

   - https://datatracker.ietf.org/doc/draft-irtf-cfrg-aead-limits/
   - RFC 9147 (DTLS 1.3) section 4.5.3 "AEAD limits"
   - https://eprint.iacr.org/2024/051.pdf

Change-Id: I81440ac28a1ad553652e201234e5ddfe03a8c190
Signed-off-by: Arne Schwabe <arne@rfc2549.org>
Acked-by: MaxF <max@max-fillinger.net>
Message-Id: <20250109174928.17862-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg30387.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
src/openvpn/crypto.c
src/openvpn/crypto.h
src/openvpn/ssl.c

index df38cdd360aa5d6bc3e1e8182c073e2156d55316..ee9b0c6a2d0c3af704a1342316fe739c14555db3 100644 (file)
@@ -405,7 +405,13 @@ openvpn_decrypt_aead(struct buffer *buf, struct buffer work,
 {
     static const char error_prefix[] = "AEAD Decrypt error";
     struct packet_id_net pin = { 0 };
-    const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt;
+    struct key_ctx *ctx = &opt->key_ctx_bi.decrypt;
+
+    if (cipher_decrypt_verify_fail_exceeded(ctx))
+    {
+        CRYPT_DROP("Decryption failed verification limit reached.");
+    }
+
     int outlen;
     struct gc_arena gc;
 
@@ -511,6 +517,7 @@ openvpn_decrypt_aead(struct buffer *buf, struct buffer work,
     if (!cipher_ctx_final_check_tag(ctx->cipher, BPTR(&work) + outlen,
                                     &outlen, tag_ptr, tag_size))
     {
+        ctx->failed_verifications++;
         CRYPT_DROP("packet tag authentication failed");
     }
     ASSERT(buf_inc_len(&work, outlen));
index 3ad31c5379bc0fa2266424ceefb9b615d49c5a17..fe81c7f31a21718d2c2605e81f77b803680f4cf1 100644 (file)
@@ -209,6 +209,8 @@ struct key_ctx
      * with the current key in number of 128 bit blocks (only used for
      * AEAD ciphers) */
     uint64_t plaintext_blocks;
+    /** number of failed verification using this cipher */
+    uint64_t failed_verifications;
 };
 
 #define KEY_DIRECTION_BIDIRECTIONAL 0 /* same keys for both directions */
@@ -660,6 +662,32 @@ create_kt(const char *cipher, const char *md, const char *optname)
 uint64_t
 cipher_get_aead_limits(const char *ciphername);
 
+/**
+ * Check if the number of failed decryption is over the acceptable limit.
+ */
+static inline bool
+cipher_decrypt_verify_fail_exceeded(const struct key_ctx *ctx)
+{
+    /* Use 2**36, same as DTLS 1.3. Strictly speaking this only guarantees
+     * the security margin for packets up to 2^10 blocks (16384 bytes)
+     * but we accept slightly lower security bound for the edge
+     * of Chacha20-Poly1305 and packets over 16k as MTUs over 16k are
+     * extremely rarely used */
+    return ctx->failed_verifications >  (1ull << 36);
+}
+
+/**
+ * Check if the number of failed decryption is approaching the limit and we
+ * should try to move to a new key
+ */
+static inline bool
+cipher_decrypt_verify_fail_warn(const struct key_ctx *ctx)
+{
+    /* Use 2**35, half the amount after which we refuse to decrypt */
+    return ctx->failed_verifications >  (1ull << 35);
+}
+
+
 /**
  * Blocksize used for the AEAD limit caluclation
  *
index cf7f34f2ada7ec3fcfd900a5390f3ce285bee8cc..e4a7b57a6c3825195476414f9f593f289304a9ea 100644 (file)
@@ -3005,6 +3005,11 @@ should_trigger_renegotiation(const struct tls_session *session, const struct key
         return true;
     }
 
+    if (cipher_decrypt_verify_fail_warn(&key_ctx_bi->decrypt))
+    {
+        return true;
+    }
+
     return false;
 }
 /*