[Openvpn-devel,RFC,net-next,v2,00/14] ovpn: add epoch data channel keys

Message ID cover.1782986577.git.ralf@mandelbit.com
Headers
Series ovpn: add epoch data channel keys |

Message

Ralf Lici July 2, 2026, 11:52 a.m. UTC
  Hi,

This is a respin of the series that adds support for OpenVPN epoch data
channel keys to the ovpn kernel module.

Epoch keys are described in the OpenVPN wire protocol draft:

  https://openvpn.github.io/openvpn-rfc/openvpn-wire-protocol.html#section-7.2
  https://openvpn.github.io/openvpn-rfc/openvpn-wire-protocol.html#section-7.5

At a high level, epoch keys allow OpenVPN to rotate data-channel AEAD
keys without requiring a full userspace renegotiation whenever a
data-channel key reaches a usage or packet-ID limit. Instead of
installing one concrete AEAD key and nonce tail per direction, userspace
installs per-direction epoch PRKs. The kernel derives the concrete AEAD
key and implicit IV for each epoch using the OpenVPN HKDF-Expand-Label
construction, and can then move between pre-derived epochs in the data
path.

This is conceptually the same mechanism (D)TLS 1.3 already uses:
OVPN-Expand-Label is TLS 1.3's HKDF-Expand-Label with an "ovpn " prefix
instead of "tls13 ", and advancing an epoch is the data-channel analogue
of a TLS 1.3 key update / DTLS 1.3 epoch increment.

The DATA_V2 opcode is still used, but epoch packets use the extended
packet ID layout defined by the draft: a 64-bit packet ID carrying a
16-bit epoch and a 48-bit sequence number, an XOR-based IV construction,
and the AEAD tag at the end of the packet. Carrying the tag after the
ciphertext, rather than prepending it as the direct-key format does,
matches how AEAD implementations stream their output and lets the data
path map payload and tag as a single contiguous scatterlist.

The series is structured in three parts. The first adds packet-ID and
AES-GCM usage-limit accounting. TX now notifies userspace before
packet-ID wrap or AES-GCM hard exhaustion, and stops before the hard
limit. RX accounts authenticated packets and reports threshold crossings
without dropping packets solely because the peer crossed a local usage
threshold. The series also limits AEAD decrypt verification failures.

The middle part moves per-direction key state into explicit key
contexts, makes those contexts refcounted for async crypto completion,
and makes packet layout handling explicit. This keeps the epoch
implementation from adding more special cases to the direct-key path.

The epoch implementation keeps current TX/RX key contexts, one retiring
RX key for reordered packets, and bounded rings of future TX/RX keys. TX
rotates to a future key before hard packet-ID or AEAD usage exhaustion,
and also rotates on the soft AEAD threshold. RX authenticates a packet
with a future key before promoting that key to current, then refills
consumed future-key slots from workqueue context.

Selftest coverage is intentionally limited: the tests install epoch keys
and verify steady-state UDP/TCP packet layout, including the epoch field
in captured DATA_V2 packets. They do not exercise rotation or future-key
refill because the production thresholds are cryptographic safety
limits, so reaching them needs an enormous packet-ID/AEAD budget and
lowering them would mean test-only knobs in security-sensitive data-path
policy.

The HKDF-Expand implementation added here (crypto_epoch.c) overlaps with
the open-coded HKDF-Expand already carried by fscrypt and nvme. We
intend to unify all three into a single shared helper in a follow-up
series, rather than block this work on that refactor.

Thanks,

Ralf Lici
Mandelbit Srl

---
Changes since v1 https://lore.kernel.org/openvpn-devel/cover.1782919654.git.ralf@mandelbit.com/
- Address review findings by avoiding PRK advancement on failed
  future-key refill, zeroing derived key material on all epoch key
  creation paths, fixing epoch scatterlist sizing/termination, and
  preventing refill work from outliving module text.
- Expand the cover letter based on Arne's suggestion.
- Mention in the cover letter that we're aiming for a unified
  HKDF-Expand implementation as follow-up work.

Ralf Lici (14):
  ovpn: prepare packet ID state for usage limits
  ovpn: enforce AES-GCM usage limits
  ovpn: limit AEAD decrypt verification failures
  ovpn: make direct-key AEAD layout explicit
  ovpn: move key slot lifecycle out of AEAD
  ovpn: move direct key state into key contexts
  ovpn: make key contexts refcounted
  ovpn: generalize AEAD packet ID handling
  ovpn: add epoch key derivation support
  ovpn: add epoch key slot state
  ovpn: handle epoch AEAD packet format
  ovpn: rotate epoch data keys
  ovpn: accept epoch keys from netlink
  selftests: ovpn: exercise epoch keys

 Documentation/netlink/specs/ovpn.yaml         |  31 +
 drivers/net/Kconfig                           |   2 +
 drivers/net/ovpn/Makefile                     |   2 +
 drivers/net/ovpn/crypto.c                     |   7 +-
 drivers/net/ovpn/crypto.h                     | 125 +++-
 drivers/net/ovpn/crypto_aead.c                | 609 +++++++++++-------
 drivers/net/ovpn/crypto_aead.h                |   9 +-
 drivers/net/ovpn/crypto_epoch.c               | 223 +++++++
 drivers/net/ovpn/crypto_epoch.h               |  58 ++
 drivers/net/ovpn/crypto_key.c                 | 575 +++++++++++++++++
 drivers/net/ovpn/crypto_limits.h              | 125 ++++
 drivers/net/ovpn/io.c                         | 246 ++++++-
 drivers/net/ovpn/io.h                         |   8 +-
 drivers/net/ovpn/main.c                       |  15 +-
 drivers/net/ovpn/netlink-gen.c                |   9 +-
 drivers/net/ovpn/netlink-gen.h                |   3 +-
 drivers/net/ovpn/netlink.c                    | 111 +++-
 drivers/net/ovpn/pktid.c                      |  13 +-
 drivers/net/ovpn/pktid.h                      | 164 ++++-
 drivers/net/ovpn/proto.h                      |  38 ++
 drivers/net/ovpn/skb.h                        |   2 +
 include/uapi/linux/ovpn.h                     |  11 +
 tools/testing/selftests/net/ovpn/Makefile     |   2 +
 tools/testing/selftests/net/ovpn/common.sh    |  30 +-
 tools/testing/selftests/net/ovpn/ovpn-cli.c   | 116 +++-
 .../selftests/net/ovpn/test-epoch-tcp.sh      |  11 +
 .../testing/selftests/net/ovpn/test-epoch.sh  |  10 +
 tools/testing/selftests/net/ovpn/test-mark.sh |   3 +-
 tools/testing/selftests/net/ovpn/test.sh      |  12 +-
 29 files changed, 2241 insertions(+), 329 deletions(-)
 create mode 100644 drivers/net/ovpn/crypto_epoch.c
 create mode 100644 drivers/net/ovpn/crypto_epoch.h
 create mode 100644 drivers/net/ovpn/crypto_key.c
 create mode 100644 drivers/net/ovpn/crypto_limits.h
 create mode 100755 tools/testing/selftests/net/ovpn/test-epoch-tcp.sh
 create mode 100755 tools/testing/selftests/net/ovpn/test-epoch.sh


base-commit: 903db046d5579bef0ea699eae4b279dd6455fc9f