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]> --- 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
