diff --git a/client/internal/engine.go b/client/internal/engine.go index 99f5c22a7..470f6a087 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -577,8 +577,9 @@ func (e *Engine) Start(netbirdConfig *mgmProto.NetbirdConfig, mgmtURL *url.URL) if pqkem.Enabled() { log.Infof("ML-KEM post-quantum exchange enabled") - // TODO(NET-1406): wire the real tunnel-UDP transport + WG PSK callback handler. - e.pqkemManager = pqkem.NewManager(publicKey.String(), noopPQTransport{}, noopPQCallbackHandler{}, nil) + // TODO(NET-1406): replace noopPQTransport with the real dedicated UDP transport + // bound on the WG overlay IPv4. + e.pqkemManager = pqkem.NewManager(publicKey.String(), noopPQTransport{}, pqCallbackHandler{wg: e.wgInterface}, nil) } e.stateManager.Start() diff --git a/client/internal/pqkem_adapter.go b/client/internal/pqkem_adapter.go index 776825c62..7410915ea 100644 --- a/client/internal/pqkem_adapter.go +++ b/client/internal/pqkem_adapter.go @@ -1,23 +1,41 @@ package internal -import "github.com/netbirdio/netbird/client/internal/pqkem" +import ( + log "github.com/sirupsen/logrus" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" -// No-op adapters wiring the engine to the ML-KEM manager's two seams. They are -// placeholders so the manager can be instantiated and its lifecycle managed while -// the real integration is built. -// -// TODO(NET-1406): -// - noopPQTransport -> real tunnel-UDP transport (send over the WG data path, -// feed inbound to Manager.OnDataPathMessage), analogue of go-rosenpass's Conn. -// - noopPQCallbackHandler -> program the derived PSK via iface/wgctrl on -// OnNewPSKReady, and tear the peer down / trigger ICE reconnect on OnRekeyFailed. + "github.com/netbirdio/netbird/client/internal/pqkem" +) +// pqPresharedKeySetter is the subset of the WireGuard interface the ML-KEM callback +// needs: programming a peer's preshared key. *iface.WGIface satisfies it. +type pqPresharedKeySetter interface { + SetPresharedKey(peerKey string, psk wgtypes.Key, updateOnly bool) error +} + +// pqCallbackHandler programs the derived PQ PSK onto the WireGuard peer. It is the +// engine-side implementation of pqkem.CallbackHandler. +type pqCallbackHandler struct { + wg pqPresharedKeySetter +} + +// OnNewPSKReady programs the freshly derived PSK for the peer (updateOnly: a no-op +// if the peer is not present, mirroring Rosenpass). remoteID is the peer's WG pubkey. +func (h pqCallbackHandler) OnNewPSKReady(remoteID string, psk pqkem.PSK) error { + return h.wg.SetPresharedKey(remoteID, wgtypes.Key(psk), true) +} + +// OnRekeyFailed reports a failed PQ (re)key convergence. +// TODO(NET-1406): tear the peer connection down / trigger ICE reconnect. +func (h pqCallbackHandler) OnRekeyFailed(remoteID string) error { + log.Warnf("pqkem: post-quantum rekey failed for peer %s", remoteID) + return nil +} + +// noopPQTransport is a placeholder data-path transport for the ML-KEM manager. +// TODO(NET-1406): replace with the real dedicated UDP transport bound on the WG +// overlay IPv4 (send over the data path, feed inbound to Manager.OnDataPathMessage), +// analogue of go-rosenpass's Conn. type noopPQTransport struct{} func (noopPQTransport) SendDataPath(remoteID string, msg []byte) error { return nil } - -type noopPQCallbackHandler struct{} - -func (noopPQCallbackHandler) OnNewPSKReady(remoteID string, psk pqkem.PSK) error { return nil } - -func (noopPQCallbackHandler) OnRekeyFailed(remoteID string) error { return nil }