all lists on lists.proxmox.com
 help / color / mirror / Atom feed
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)?




  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal