OpenVPN needs packet-ID and cipher usage thresholds to decide when a
data-channel key should be renewed or stopped. The existing transmit
packet-ID helper only returns the next ID and has no way to request a
threshold notification.

Teach the transmit packet-ID helper to return 1 when the fixed OpenVPN
packet-ID soft threshold is crossed. The counter is monotonic, so the
exact crossing is naturally reported only once. The hard packet-ID wrap
check still stops TX; this only gives userspace a chance to rekey while
packet-ID space is still available.

Signed-off-by: Ralf Lici <[email protected]>
---
No changes since v1 
https://lore.kernel.org/openvpn-devel/6c66a38af8ea53e4fbc587f087c594573fd8ee6a.1782919654.git.r...@mandelbit.com/

 drivers/net/ovpn/crypto_aead.c |  3 +++
 drivers/net/ovpn/netlink.c     |  4 ++--
 drivers/net/ovpn/pktid.h       | 31 +++++++++++++++++++++++++------
 3 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ovpn/crypto_aead.c b/drivers/net/ovpn/crypto_aead.c
index 8f07c418622b..86b69aeddcf7 100644
--- a/drivers/net/ovpn/crypto_aead.c
+++ b/drivers/net/ovpn/crypto_aead.c
@@ -19,6 +19,7 @@
 #include "pktid.h"
 #include "crypto_aead.h"
 #include "crypto.h"
+#include "netlink.h"
 #include "peer.h"
 #include "proto.h"
 #include "skb.h"
@@ -207,6 +208,8 @@ int ovpn_aead_encrypt(struct ovpn_peer *peer, struct 
ovpn_crypto_key_slot *ks,
        ret = ovpn_pktid_xmit_next(&ks->pid_xmit, &pktid);
        if (unlikely(ret < 0))
                return ret;
+       if (unlikely(ret > 0))
+               ovpn_nl_key_swap_notify(peer, ks->key_id);
 
        /* concat 4 bytes packet id and 8 bytes nonce tail into 12 bytes
         * nonce
diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c
index 4c66c1ec497e..83d81a468b5a 100644
--- a/drivers/net/ovpn/netlink.c
+++ b/drivers/net/ovpn/netlink.c
@@ -1312,8 +1312,8 @@ int ovpn_nl_key_swap_notify(struct ovpn_peer *peer, u8 
key_id)
        int ret = -EMSGSIZE;
        void *hdr;
 
-       netdev_info(peer->ovpn->dev, "peer with id %u must rekey - primary key 
unusable.\n",
-                   peer->id);
+       netdev_info(peer->ovpn->dev, "peer with id %u should rekey key %u\n",
+                   peer->id, key_id);
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
        if (!msg)
diff --git a/drivers/net/ovpn/pktid.h b/drivers/net/ovpn/pktid.h
index 21845f353bc8..82f59256b4a3 100644
--- a/drivers/net/ovpn/pktid.h
+++ b/drivers/net/ovpn/pktid.h
@@ -17,6 +17,9 @@
  */
 #define PKTID_RECV_EXPIRE (30 * HZ)
 
+/* notify userspace when the packet ID space is close to wrapping */
+#define PKTID_XMIT_REKEY_NOTIFY 0xff000000U
+
 /* Packet-ID state for transmitter */
 struct ovpn_pktid_xmit {
        atomic_t seq_num;
@@ -52,20 +55,36 @@ struct ovpn_pktid_recv {
        spinlock_t lock;
 };
 
-/* Get the next packet ID for xmit */
+/**
+ * ovpn_pktid_xmit_next - allocate a transmit packet ID
+ * @pid: transmit packet ID state
+ * @pktid: location where the generated packet ID is stored
+ *
+ * The returned packet ID becomes part of the AEAD nonce, so the helper rejects
+ * the packet before the 32-bit packet-ID space wraps.
+ *
+ * The packet-ID soft threshold does not reject the packet. It returns 1 once
+ * so the caller can notify userspace to rekey while packet-ID space remains.
+ *
+ * Return: 1 if userspace should be notified, 0 if no notification is needed,
+ * or a negative error code otherwise.
+ */
 static inline int ovpn_pktid_xmit_next(struct ovpn_pktid_xmit *pid, u32 *pktid)
 {
        const u32 seq_num = atomic_fetch_add_unless(&pid->seq_num, 1, 0);
-       /* when the 32bit space is over, we return an error because the packet
-        * ID is used to create the cipher IV and we do not want to reuse the
-        * same value more than once
-        */
+       int ret = 0;
+
+       /* packet IDs are used to create cipher IVs and must not wrap */
        if (unlikely(!seq_num))
                return -ERANGE;
 
+       /* notify userspace before the packet ID space is close to wrapping */
+       if (unlikely(seq_num == PKTID_XMIT_REKEY_NOTIFY))
+               ret = 1;
+
        *pktid = seq_num;
 
-       return 0;
+       return ret;
 }
 
 /* Write 12-byte AEAD IV to dest */
-- 
2.54.0


_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Reply via email to