From: Stefan Hanreich <s.hanreich@proxmox.com>
To: Proxmox VE development discussion <pve-devel@lists.proxmox.com>,
Christoph Heiss <c.heiss@proxmox.com>
Subject: Re: [pve-devel] [PATCH proxmox 06/11] wireguard: init configuration support crate
Date: Fri, 13 Feb 2026 11:13:28 +0100 [thread overview]
Message-ID: <0c44a626-af78-4bb9-89a3-e5e5c6f6fd1b@proxmox.com> (raw)
In-Reply-To: <20260116153317.1146323-7-c.heiss@proxmox.com>
comments inline
On 1/16/26 4:33 PM, Christoph Heiss wrote:
[snip]
> +impl PrivateKey {
> + /// Length of the raw private key data in bytes.
> + pub const RAW_LENGTH: usize = ed25519_dalek::SECRET_KEY_LENGTH;
> +
> + /// Generates a new private key suitable for use with WireGuard.
> + pub fn generate() -> Result<Self, Error> {
> + generate_key().map(Self)
> + }
> +
> + /// Calculates the public key from the private key.
> + pub fn public_key(&self) -> PublicKey {
> + PublicKey(
> + ed25519_dalek::SigningKey::from_bytes(&self.0)
> + .verifying_key()
> + .to_bytes(),
> + )
> + }
> +
> + /// Returns the raw private key material.
> + #[must_use]
> + pub fn raw(&self) -> &ed25519_dalek::SecretKey {
> + &self.0
> + }
might be better to implement AsRef instead for ergonomics?
> + /// Builds a new [`PrivateKey`] from raw key material.
> + #[must_use]
> + pub fn from_raw(data: ed25519_dalek::SecretKey) -> Self {
> + // [`SigningKey`] takes care of correct key clamping.
> + Self(SigningKey::from(&data).to_bytes())
> + }
> +}
> +
> +impl From<ed25519_dalek::SecretKey> for PrivateKey {
> + fn from(value: ed25519_dalek::SecretKey) -> Self {
> + Self(value)
> + }
> +}
> +
> +/// Preshared key between two WireGuard peers.
> +#[derive(Clone, Deserialize, Serialize)]
> +#[serde(transparent)]
> +pub struct PresharedKey(
> + #[serde(with = "proxmox_serde::byte_array_as_base64")] ed25519_dalek::SecretKey,
> +);
> +
> +impl fmt::Debug for PresharedKey {
> + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
> + write!(f, "<preshared-key>")
> + }
> +}
> +
> +impl PresharedKey {
> + /// Length of the raw private key data in bytes.
> + pub const RAW_LENGTH: usize = ed25519_dalek::SECRET_KEY_LENGTH;
> +
> + /// Generates a new preshared key suitable for use with WireGuard.
> + pub fn generate() -> Result<Self, Error> {
> + generate_key().map(Self)
> + }
> +
> + /// Returns the raw private key material.
> + #[must_use]
> + pub fn raw(&self) -> &ed25519_dalek::SecretKey {
> + &self.0
> + }
> +
here too: might be better to implement AsRef instead for ergonomics?
> + /// Builds a new [`PrivateKey`] from raw key material.
> + #[must_use]
> + pub fn from_raw(data: ed25519_dalek::SecretKey) -> Self {
> + // [`SigningKey`] takes care of correct key clamping.
> + Self(SigningKey::from(&data).to_bytes())
> + }
> +}
> +
> +/// A single WireGuard peer.
> +#[derive(Serialize, Debug)]
> +#[serde(rename_all = "PascalCase")]
> +pub struct WireGuardPeer {
> + /// Public key, matching the private key of of the remote peer.
> + pub public_key: PublicKey,
> + /// Additional key preshared between two peers. Adds an additional layer of symmetric-key
> + /// cryptography to be mixed into the already existing public-key cryptography, for
> + /// post-quantum resistance.
> + pub preshared_key: PresharedKey,
> + /// List of IPv4/v6 CIDRs from which incoming traffic for this peer is allowed and to which
> + /// outgoing traffic for this peer is directed. The catch-all 0.0.0.0/0 may be specified for
> + /// matching all IPv4 addresses, and ::/0 may be specified for matching all IPv6 addresses.
> + #[serde(rename = "AllowedIPs")]
> + pub allowed_ips: Vec<Cidr>,
potentially missing skip_serializing_if = "Vec::is_empty"?
[snip]
> +#[cfg(test)]
> +mod tests {
> + use std::net::Ipv4Addr;
> +
> + use proxmox_network_types::ip_address::Cidr;
> +
> + use crate::{PresharedKey, PrivateKey, WireGuardConfig, WireGuardInterface, WireGuardPeer};
> +
> + fn mock_private_key(v: u8) -> PrivateKey {
> + let base = v * 32;
> + PrivateKey((base..base + 32).collect::<Vec<u8>>().try_into().unwrap())
> + }
> +
> + fn mock_preshared_key(v: u8) -> PresharedKey {
> + let base = v * 32;
> + PresharedKey((base..base + 32).collect::<Vec<u8>>().try_into().unwrap())
> + }
> +
> + #[test]
> + fn single_peer() {
> + let config = WireGuardConfig {
> + interface: WireGuardInterface {
> + private_key: mock_private_key(0),
> + listen_port: Some(51820),
> + fw_mark: Some(127),
> + },
> + peers: vec![WireGuardPeer {
> + public_key: mock_private_key(1).public_key(),
> + preshared_key: mock_preshared_key(1),
> + allowed_ips: vec![Cidr::new_v4(Ipv4Addr::new(192, 168, 0, 0), 24).unwrap()],
> + endpoint: Some("foo.example.com:51820".parse().unwrap()),
> + persistent_keepalive: Some(25),
> + }],
> + };
> +
> + pretty_assertions::assert_eq!(
> + config.to_raw_config().unwrap(),
> + "[Interface]
> +PrivateKey = AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=
> +ListenPort = 51820
> +FwMark = 127
> +
> +[Peer]
> +PublicKey = Kay64UG8yvCyLhqU000LxzYeUm0L/hLIl5S8kyKWbdc=
> +PresharedKey = ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8=
> +AllowedIPs = 192.168.0.0/24
> +Endpoint = foo.example.com:51820
> +PersistentKeepalive = 25
> +"
> + );
> + }
> +
> + #[test]
> + fn multiple_peers() {
> + let config = WireGuardConfig {
> + interface: WireGuardInterface {
> + private_key: mock_private_key(0),
> + listen_port: Some(51820),
> + fw_mark: None,
> + },
> + peers: vec![
> + WireGuardPeer {
> + public_key: mock_private_key(1).public_key(),
> + preshared_key: mock_preshared_key(1),
> + allowed_ips: vec![Cidr::new_v4(Ipv4Addr::new(192, 168, 0, 0), 24).unwrap()],
> + endpoint: Some("foo.example.com:51820".parse().unwrap()),
> + persistent_keepalive: None,
> + },
> + WireGuardPeer {
> + public_key: mock_private_key(2).public_key(),
> + preshared_key: mock_preshared_key(2),
> + allowed_ips: vec![Cidr::new_v4(Ipv4Addr::new(192, 168, 1, 0), 24).unwrap()],
> + endpoint: None,
> + persistent_keepalive: Some(25),
> + },
> + WireGuardPeer {
> + public_key: mock_private_key(3).public_key(),
> + preshared_key: mock_preshared_key(3),
> + allowed_ips: vec![Cidr::new_v4(Ipv4Addr::new(192, 168, 2, 0), 24).unwrap()],
> + endpoint: None,
> + persistent_keepalive: None,
> + },
> + ],
> + };
> +
> + pretty_assertions::assert_eq!(
> + config.to_raw_config().unwrap(),
> + "[Interface]
> +PrivateKey = AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=
> +ListenPort = 51820
> +
> +[Peer]
> +PublicKey = Kay64UG8yvCyLhqU000LxzYeUm0L/hLIl5S8kyKWbdc=
> +PresharedKey = ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8=
> +AllowedIPs = 192.168.0.0/24
> +Endpoint = foo.example.com:51820
> +
> +[Peer]
> +PublicKey = JUO5L/EJVRFHatyDadtt3JM2ZaEZeN2hQE7hBmypVZ0=
> +PresharedKey = QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl8=
> +AllowedIPs = 192.168.1.0/24
> +PersistentKeepalive = 25
> +
> +[Peer]
> +PublicKey = F0VTtFbd38aQjsqxwQH+arIeK6oGF3lbfUOmNIKZP9U=
> +PresharedKey = YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8=
> +AllowedIPs = 192.168.2.0/24
> +"
> + );
> + }
> +}
maybe add some test cases for missing properties as well (or adapt the
existing ones)?
next prev parent reply other threads:[~2026-02-13 10:12 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-16 15:33 [pve-devel] [PATCH proxmox{, -ve-rs} 00/11] sdn: add wireguard fabric configuration support Christoph Heiss
2026-01-16 15:33 ` [pve-devel] [PATCH proxmox 01/11] serde: implement ini serializer Christoph Heiss
2026-02-11 16:36 ` Stefan Hanreich
2026-02-11 18:40 ` Christoph Heiss
2026-02-12 10:59 ` Stefan Hanreich
2026-01-16 15:33 ` [pve-devel] [PATCH proxmox 02/11] serde: add base64 module for byte arrays Christoph Heiss
2026-01-16 15:33 ` [pve-devel] [PATCH proxmox 03/11] network-types: add ServiceEndpoint type as host/port tuple abstraction Christoph Heiss
2026-02-13 10:11 ` Stefan Hanreich
2026-01-16 15:33 ` [pve-devel] [PATCH proxmox 04/11] schema: provide integer schema for node ports Christoph Heiss
2026-01-16 15:33 ` [pve-devel] [PATCH proxmox 05/11] schema: api-types: add ed25519 base64 encoded key schema Christoph Heiss
2026-01-16 15:33 ` [pve-devel] [PATCH proxmox 06/11] wireguard: init configuration support crate Christoph Heiss
2026-02-13 10:13 ` Stefan Hanreich [this message]
2026-01-16 15:33 ` [pve-devel] [PATCH proxmox 07/11] wireguard: implement api for PublicKey Christoph Heiss
2026-02-13 10:12 ` Stefan Hanreich
2026-01-16 15:33 ` [pve-devel] [PATCH proxmox 08/11] wireguard: make per-peer preshared key optional Christoph Heiss
2026-01-16 15:33 ` [pve-devel] [PATCH proxmox-ve-rs 09/11] sdn-types: add wireguard-specific PersistentKeepalive api type Christoph Heiss
2026-01-16 15:33 ` [pve-devel] [PATCH proxmox-ve-rs 10/11] ve-config: fabric: refactor fabric config entry impl using macro Christoph Heiss
2026-01-16 15:33 ` [pve-devel] [PATCH proxmox-ve-rs 11/11] ve-config: sdn: fabrics: add wireguard section config types Christoph Heiss
2026-02-13 10:14 ` [pve-devel] [PATCH proxmox{, -ve-rs} 00/11] sdn: add wireguard fabric configuration support Stefan Hanreich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=0c44a626-af78-4bb9-89a3-e5e5c6f6fd1b@proxmox.com \
--to=s.hanreich@proxmox.com \
--cc=c.heiss@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox