[Openvpn-devel,RFC,net-next,v2,01/14] ovpn: prepare packet ID state for usage limits
Commit Message
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 <ralf@mandelbit.com>
---
No changes since v1 https://lore.kernel.org/openvpn-devel/6c66a38af8ea53e4fbc587f087c594573fd8ee6a.1782919654.git.ralf@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(-)
@@ -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
@@ -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)
@@ -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 */