diff --git a/board/aarch64/bananapi-bpi-r3/rootfs/usr/share/product/bananapi,bpi-r3/etc/factory-config.cfg b/board/aarch64/bananapi-bpi-r3/rootfs/usr/share/product/bananapi,bpi-r3/etc/factory-config.cfg index 672a768a5..723b25a28 100644 --- a/board/aarch64/bananapi-bpi-r3/rootfs/usr/share/product/bananapi,bpi-r3/etc/factory-config.cfg +++ b/board/aarch64/bananapi-bpi-r3/rootfs/usr/share/product/bananapi,bpi-r3/etc/factory-config.cfg @@ -218,8 +218,8 @@ "symmetric-key": [ { "name": "wifi", - "infix-keystore:symmetric-key": "infixinfix", - "infix-keystore:key-format": "infix-crypto-types:wifi-preshared-key-format" + "cleartext-symmetric-key": "aW5maXhpbmZpeA==", + "key-format": "infix-crypto-types:passphrase-key-format" } ] } diff --git a/board/aarch64/raspberrypi-rpi64/README.md b/board/aarch64/raspberrypi-rpi64/README.md index 5c9dff8cb..4619d12ca 100644 --- a/board/aarch64/raspberrypi-rpi64/README.md +++ b/board/aarch64/raspberrypi-rpi64/README.md @@ -107,8 +107,10 @@ To configure WiFi as a client, first store your WiFi password in the keystore: ``` admin@infix:/> configure admin@infix:/config/> edit keystore symmetric-key mywifi -admin@infix:/config/keystore/…/mywifi/> set key-format wifi-preshared-key-format -admin@infix:/config/keystore/…/mywifi/> set symmetric-key YourWiFiPassword +admin@infix:/config/keystore/…/mywifi/> set key-format passphrase-key-format +admin@infix:/config/keystore/…/mywifi/> change cleartext-symmetric-key +Passphrase: ************ +Retype passphrase: ************ admin@infix:/config/keystore/…/mywifi/> leave ``` diff --git a/board/common/rootfs/usr/bin/askpass b/board/common/rootfs/usr/bin/askpass index c2896e889..7c47f1d21 100755 --- a/board/common/rootfs/usr/bin/askpass +++ b/board/common/rootfs/usr/bin/askpass @@ -1,23 +1,49 @@ #!/bin/sh +# Prompt for a secret with confirmation, then encode and output it. +# +# Default mode: hash with mkpasswd (for system passwords) +# askpass [OUTPUT] +# +# Base64 mode (-b): base64-encode (for keystore passphrases) +# askpass -b [OUTPUT] +# +# If OUTPUT is given, result is written to the file. +# If omitted, result is written to stdout. # shellcheck disable=SC3045 +LABEL="New password" +MODE=hash +if [ "$1" = "-b" ]; then + LABEL="Passphrase" + MODE=base64 + shift +fi OUTPUT=$1 -read -r -s -p "New password: " password +read -r -s -p "$LABEL: " secret >&2 echo -read -r -s -p "Retype password: " password_again +read -r -s -p "Retype $LABEL: " secret_again >&2 echo -if [ "$password" != "$password_again" ]; then - echo "Passwords do not match, try again." +if [ "$secret" != "$secret_again" ]; then + echo "${LABEL}s do not match, try again." exit 1 fi -if [ -z "$OUTPUT" ]; then - echo "$password" - exit 0 +if [ -z "$secret" ]; then + echo "Empty $LABEL, try again." + exit 1 +fi + +if [ "$MODE" = "base64" ]; then + encoded=$(printf '%s' "$secret" | base64 -w 0) +else + encoded=$(printf '%s\n' "$secret" | mkpasswd -s) fi umask 0177 -echo "$password" | mkpasswd -s > "$OUTPUT" -exit 0 +if [ -z "$OUTPUT" ]; then + echo "$encoded" +else + printf '%s' "$encoded" > "$OUTPUT" +fi diff --git a/doc/ChangeLog.md b/doc/ChangeLog.md index 7486a2035..4ea50d9f9 100644 --- a/doc/ChangeLog.md +++ b/doc/ChangeLog.md @@ -23,7 +23,7 @@ All notable changes to the project are documented in this file. Noteworthy changes and additions in this release are marked below in bold text. -- Upgrade Linux kernel to 6.18.8 (LTS) +- **Upgrade Linux kernel from 6.12.65 to 6.18.8 (LTS)** - Upgrade Buildroot to 2025.02.10 (LTS) - Upgrade libyang to 4.2.2 - Upgrade sysrepo to 4.2.10 @@ -53,6 +53,9 @@ Noteworthy changes and additions in this release are marked below in bold text. removed during upgrade (for the rest of the configuration to apply) and you need to reconfigure them again. See the [WiFi][] documentation for details - Add support for **WireGuard VPN tunnels**. +- Updated CLI `change` command to also support `cleartext-symmetric-key` which + is `type binary` and shared (using different `key-format`) between Wireguard + and WiFi applications for both keys and passphrases - New default NACM privilege levels (user levels) in `factory-config`: `operator` (network & container manager) and `guest` (read-only). For details, see the updated system configuration documentation, as well as a diff --git a/doc/keystore.md b/doc/keystore.md new file mode 100644 index 000000000..0c6a431ce --- /dev/null +++ b/doc/keystore.md @@ -0,0 +1,164 @@ +# Keystore + +The Infix keystore is a centralized storage system for cryptographic keys +used throughout the system. It is based on the IETF standards [RFC 9641][1] +(Keystore) and [RFC 9640][2] (Cryptographic Types), with Infix extensions +for WiFi and WireGuard key formats. + +## Overview + +The keystore supports two types of cryptographic keys: + +1. **Asymmetric Keys** — public/private key pairs used for: + - SSH host authentication (RSA keys) + - WireGuard VPN tunnels (X25519 keys) + +2. **Symmetric Keys** — shared secrets used for: + - WiFi authentication (WPA2/WPA3 pre-shared keys) + - WireGuard VPN pre-shared keys + +All keys are stored under the `ietf-keystore` configuration path and can be +managed via CLI, NETCONF, or RESTCONF. + +### Supported Formats + +| Asymmetric Key Format | Use Case | Key Type | +|----------------------------------------------------------|---------------|------------| +| `rsa-private-key-format` / `ssh-public-key-format` | SSH host keys | RSA | +| `x25519-private-key-format` / `x25519-public-key-format` | WireGuard VPN | Curve25519 | + +| Symmetric Key Format | Use Case | +|-----------------------------|-----------------------------------| +| `passphrase-key-format` | Human-readable passphrases (WiFi) | +| `octet-string-key-format` | Raw symmetric keys (WireGuard) | + +## Asymmetric Keys + +Asymmetric keys consist of a public/private key pair. The public key can be +shared freely, while the private key must be kept secure. + +### SSH Host Keys + +SSH host keys identify the system during SSH and NETCONF connections. The +default host key is automatically generated on first boot and stored in the +keystore with the name `genkey`. + +See [SSH Management](management.md) for details on generating and importing +custom SSH host keys. + +### WireGuard Keys + +WireGuard uses X25519 elliptic curve cryptography for key exchange. Each +WireGuard interface requires a public/private key pair stored as an asymmetric +key in the keystore. Key pairs can be generated directly from the CLI: + +
admin@example:/> wireguard genkey
+Private: aMqBvZqkSP5JrqBvZqkSP5JrqBvZqkSP5JrqBvZqkSP=
+Public: bN1CwZ1lTP6KsrCwZ1lTP6KsrCwZ1lTP6KsrCwZ1lTP=
+
+
+See [WireGuard VPN](vpn-wireguard.md) for key generation and configuration
+examples.
+
+## Symmetric Keys
+
+Symmetric keys are shared secrets where the same key must be configured on
+all systems that need to communicate.
+
+### WiFi Pre-Shared Keys
+
+WiFi networks secured with WPA2 or WPA3 use pre-shared keys stored as
+symmetric keys in the keystore with `passphrase-key-format`. The
+passphrase must be 8-63 printable ASCII characters.
+
+Since symmetric keys are stored as binary (base64-encoded), the CLI
+provides the `change` command to enter passphrases interactively:
+
+admin@example:/config/keystore/…/my-wifi-key/> change cleartext-symmetric-key
+Passphrase: ************
+Retype passphrase: ************
+
+
+See [WiFi](wifi.md) for complete configuration examples.
+
+### WireGuard Pre-Shared Keys
+
+WireGuard supports optional pre-shared keys (PSK) that add a layer of
+symmetric encryption alongside Curve25519. PSKs use the standard IETF
+`octet-string-key-format` (32 random bytes). This provides defense-in-depth
+against future quantum computers that might break elliptic curve cryptography.
+Note that peer authentication still relies on Curve25519, so PSKs alone do
+not provide complete post-quantum security.
+
+PSKs can be generated directly from the CLI:
+
+admin@example:/> wireguard genpsk
+cO2DxZ2mUQ7LtsrDxZ2mUQ7LtsrDxZ2mUQ7LtsrDxZ2m=
+
+
+See [WireGuard VPN](vpn-wireguard.md) for PSK generation and usage examples.
+
+## Viewing Keys
+
+admin@example:/> configure
+admin@example:/config/> show keystore
+asymmetric-keys {
+ asymmetric-key genkey {
+ public-key-format ssh-public-key-format;
+ public-key MIIBCgKCAQEAm6uCENSafz7mIfIJ8O.... AQAB;
+ private-key-format rsa-private-key-format;
+ cleartext-private-key MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYw...b7dyPr4mpHg==;
+ }
+}
+
+
+> [!WARNING]
+> The `show keystore` command displays private keys in cleartext. Be careful
+> when viewing keys on shared screens or in logged sessions.
+
+To list only asymmetric or symmetric keys:
+
+admin@example:/config/> show keystore asymmetric-keys
+admin@example:/config/> show keystore symmetric-keys
+
+
+## Deleting Keys
+
+admin@example:/> configure
+admin@example:/config/> delete keystore asymmetric-key mykey
+admin@example:/config/> leave
+
+
+> [!CAUTION]
+> Deleting a key that is referenced by a service (SSH, WireGuard, WiFi) will
+> cause that service to fail. Verify the key is not in use before deletion.
+
+## Security Considerations
+
+The keystore is protected by NACM (Network Access Control Model) rules.
+Only users in the `admin` group can view or modify cryptographic keys.
+See [NACM](nacm.md) for details on access control.
+
+Private keys are stored in cleartext in the configuration database.
+Configuration files and backups containing the keystore should be treated
+as sensitive and protected accordingly.
+
+### Key Validation
+
+Symmetric key values are stored as binary (base64-encoded). The backend
+validates decoded key values based on their declared format:
+
+- **WiFi passphrase** (`passphrase-key-format`): Must decode to 8-63 ASCII characters
+- **WireGuard PSK** (`octet-string-key-format`): Must decode to exactly 32 bytes
+
+## References
+
+- [RFC 9641 - A YANG Data Model for a Keystore][1]
+- [RFC 9640 - YANG Data Types and Groupings for Cryptography][2]
+- [WiFi Documentation](wifi.md)
+- [WireGuard VPN Documentation](vpn-wireguard.md)
+- [SSH Management](management.md)
+- [NACM Access Control](nacm.md)
+
+[1]: https://datatracker.ietf.org/doc/html/rfc9641
+[2]: https://datatracker.ietf.org/doc/html/rfc9640
diff --git a/doc/management.md b/doc/management.md
index ece5abca4..1c3cb094c 100644
--- a/doc/management.md
+++ b/doc/management.md
@@ -47,6 +47,11 @@ RSA for now, thus the private key must be
`ietf-crypto-types:rsa-private-key-format` and the public key
`ietf-crypto-types:ssh-public-key-format`
+> [!TIP]
+> For comprehensive information about the keystore, including key management,
+> security considerations, and examples for different key types, see the
+> [Keystore documentation](keystore.md).
+
### Use your own SSH hostkeys
Hostkeys can be generated with OpenSSL:
diff --git a/doc/vpn-wireguard.md b/doc/vpn-wireguard.md
index a5ceff8db..10255847e 100644
--- a/doc/vpn-wireguard.md
+++ b/doc/vpn-wireguard.md
@@ -26,31 +26,25 @@ Key features of WireGuard:
WireGuard uses public-key cryptography similar to SSH. Each WireGuard interface
requires a private key, and each peer is identified by its public key.
-**Generate a WireGuard key pair using the `wg` command:**
-
-```bash
-admin@example:~$ wg genkey | tee privatekey | wg pubkey > publickey
-admin@example:~$ cat privatekey
-aMqBvZqkSP5JrqBvZqkSP5JrqBvZqkSP5JrqBvZqkSP=
-admin@example:~$ cat publickey
-bN1CwZ1lTP6KsrCwZ1lTP6KsrCwZ1lTP6KsrCwZ1lTP=
-```
-
-This generates a private key, saves it to `privatekey`, derives the public key,
-and saves it to `publickey`.
-
-**Import the private key into the keystore:**
+**Import the key pair into the keystore:**
admin@example:/> configure
admin@example:/config/> edit keystore asymmetric-key wg-site-a
+admin@example:/config/keystore/asymmetric-key/wg-site-a/> do wireguard genkey
+Private: aMqBvZqkSP5JrqBvZqkSP5JrqBvZqkSP5JrqBvZqkSP=
+Public: bN1CwZ1lTP6KsrCwZ1lTP6KsrCwZ1lTP6KsrCwZ1lTP=
admin@example:/config/keystore/asymmetric-key/wg-site-a/> set public-key-format x25519-public-key-format
admin@example:/config/keystore/asymmetric-key/wg-site-a/> set private-key-format x25519-private-key-format
admin@example:/config/keystore/asymmetric-key/wg-site-a/> set public-key bN1CwZ1lTP6KsrCwZ1lTP6KsrCwZ1lTP6KsrCwZ1lTP=
-admin@example:/config/keystore/asymmetric-key/wg-site-a/> set private-key aMqBvZqkSP5JrqBvZqkSP5JrqBvZqkSP5JrqBvZqkSP=
+admin@example:/config/keystore/asymmetric-key/wg-site-a/> set cleartext-private-key aMqBvZqkSP5JrqBvZqkSP5JrqBvZqkSP5JrqBvZqkSP=
admin@example:/config/keystore/asymmetric-key/wg-site-a/> leave
admin@example:/>
+> [!TIP]
+> The `do` prefix allows running admin-exec commands from configure context.
+> Use the base for `wireguard genkey` when in admin-exec context.
+
**Import peer public keys into the truststore:**
admin@example:/> configure
@@ -63,8 +57,7 @@ admin@example:/>
> [!IMPORTANT]
> Keep private keys secure! Never share your private key. Only exchange
-> public keys with peers. Delete the `privatekey` file after importing it
-> into the keystore.
+> public keys with peers.
## Point-to-Point Configuration
@@ -394,20 +387,17 @@ recording traffic today would still need the PSK even if they break Curve25519
later. However, peer authentication still relies on Curve25519, so PSKs don't
provide complete post-quantum security.
-**Generate a preshared key using `wg genpsk`:**
+**Generate a preshared key:**
-```bash
-admin@example:~$ wg genpsk > preshared.key
-admin@example:~$ cat preshared.key
+admin@example:/config/> do wireguard genpsk
cO2DxZ2mUQ7LtsrDxZ2mUQ7LtsrDxZ2mUQ7LtsrDxZ2m=
-```
+
**Import the preshared key into the keystore:**
-admin@example:/> configure
-admin@example:/config/> edit keystore symmetric-key wg-psk
-admin@example:/config/keystore/symmetric-key/wg-psk/> set key-format wireguard-symmetric-key-format
-admin@example:/config/keystore/symmetric-key/wg-psk/> set key cO2DxZ2mUQ7LtsrDxZ2mUQ7LtsrDxZ2mUQ7LtsrDxZ2m=
+admin@example:/config/> edit keystore symmetric-key wg-psk
+admin@example:/config/keystore/symmetric-key/wg-psk/> set key-format octet-string-key-format
+admin@example:/config/keystore/symmetric-key/wg-psk/> set cleartext-symmetric-key cO2DxZ2mUQ7LtsrDxZ2mUQ7LtsrDxZ2mUQ7LtsrDxZ2m=
admin@example:/config/keystore/symmetric-key/wg-psk/> end
admin@example:/config/interface/wg0/> edit wireguard peers wg-peers peer remote
admin@example:/config/interface/…/wg-peers/peer/remote/> set preshared-key wg-psk
@@ -420,5 +410,4 @@ on both sides.
> [!IMPORTANT]
> Preshared keys must be kept secret and exchanged through a secure channel,
-> just like passwords. Delete the `preshared.key` file after importing it
-> into both peer keystores.
+> just like passwords.
diff --git a/doc/wifi.md b/doc/wifi.md
index 73190f3fd..5d83b4e7b 100644
--- a/doc/wifi.md
+++ b/doc/wifi.md
@@ -253,11 +253,16 @@ Create a keystore entry for your WiFi password (8-63 characters):
admin@example:/> configure
admin@example:/config/> edit keystore symmetric-key my-wifi-key
-admin@example:/config/keystore/…/my-wifi-key/> set key-format wifi-preshared-key-format
-admin@example:/config/keystore/…/my-wifi-key/> set symmetric-key MyPassword123
+admin@example:/config/keystore/…/my-wifi-key/> set key-format passphrase-key-format
+admin@example:/config/keystore/…/my-wifi-key/> change cleartext-symmetric-key
+Passphrase: ************
+Retype passphrase: ************
admin@example:/config/keystore/…/my-wifi-key/> leave
+> The `change` command prompts for the passphrase interactively and
+> handles the base64 encoding required by the keystore automatically.
+
### Step 2: Connect to Network
Configure station mode with the SSID and password to connect:
@@ -310,8 +315,10 @@ create a keystore entry for your WiFi password and configure the AP interface:
admin@example:/> configure
admin@example:/config/> edit keystore symmetric-key my-wifi-secret
-admin@example:/config/keystore/…/my-wifi-secret/> set key-format wifi-preshared-key-format
-admin@example:/config/keystore/…/my-wifi-secret/> set symmetric-key MySecurePassword123
+admin@example:/config/keystore/…/my-wifi-secret/> set key-format passphrase-key-format
+admin@example:/config/keystore/…/my-wifi-secret/> change cleartext-symmetric-key
+Passphrase: ************
+Retype passphrase: ************
admin@example:/config/keystore/…/my-wifi-secret/> end
@@ -371,14 +378,20 @@ admin@example:/config/hardware/component/radio0/wifi-radio/> leave
admin@example:/> configure
admin@example:/config/> edit keystore symmetric-key main-secret
-admin@example:/config/keystore/…/main-secret/> set key-format wifi-preshared-key-format
-admin@example:/config/keystore/…/main-secret/> set symmetric-key MyMainPassword
+admin@example:/config/keystore/…/main-secret/> set key-format passphrase-key-format
+admin@example:/config/keystore/…/main-secret/> change cleartext-symmetric-key
+Passphrase: ************
+Retype passphrase: ************
admin@example:/config/> edit keystore symmetric-key guest-secret
-admin@example:/config/keystore/…/guest-secret/> set key-format wifi-preshared-key-format
-admin@example:/config/keystore/…/guest-secret/> set symmetric-key GuestPassword123
+admin@example:/config/keystore/…/guest-secret/> set key-format passphrase-key-format
+admin@example:/config/keystore/…/guest-secret/> change cleartext-symmetric-key
+Passphrase: ************
+Retype passphrase: ************
admin@example:/config/> edit keystore symmetric-key iot-secret
-admin@example:/config/keystore/…/iot-secret/> set key-format wifi-preshared-key-format
-admin@example:/config/keystore/…/iot-secret/> set symmetric-key IoTDevices2025
+admin@example:/config/keystore/…/iot-secret/> set key-format passphrase-key-format
+admin@example:/config/keystore/…/iot-secret/> change cleartext-symmetric-key
+Passphrase: ************
+Retype passphrase: ************
admin@example:/config/keystore/…/iot-secret/> leave
diff --git a/mkdocs.yml b/mkdocs.yml
index cc03ed1ef..73768a6e0 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -53,6 +53,7 @@ nav:
- Access Control (NACM): nacm.md
- Hardware Info & Status: hardware.md
- Management: management.md
+ - Keystore: keystore.md
- Syslog Support: syslog.md
- Support Data: support.md
- Upgrade: upgrade.md
diff --git a/package/klish-plugin-sysrepo/klish-plugin-sysrepo.hash b/package/klish-plugin-sysrepo/klish-plugin-sysrepo.hash
index c38d7e9ca..c652e519d 100644
--- a/package/klish-plugin-sysrepo/klish-plugin-sysrepo.hash
+++ b/package/klish-plugin-sysrepo/klish-plugin-sysrepo.hash
@@ -1,3 +1,3 @@
# Locally calculated
sha256 9d9d33b873917ca5d0bdcc47a36d2fd385971ab0c045d1472fcadf95ee5bcf5b LICENCE
-sha256 6e098390be2a78a56cf94eecb9d28b11c1791dd2c364e59602bbd664b508fd57 klish-plugin-sysrepo-a4b1fae697b51614dc75989e8f4fc8d277689d16-git4.tar.gz
+sha256 7bfdaef838ee8bd3995140c40144abe79ff1c6391c7b48445e6728cd4e7e56a8 klish-plugin-sysrepo-2f14503c7ea6eb24c8adaf0cf2cf7a511114b09e-git4.tar.gz
diff --git a/package/klish-plugin-sysrepo/klish-plugin-sysrepo.mk b/package/klish-plugin-sysrepo/klish-plugin-sysrepo.mk
index 0c6b1daa7..488407fff 100644
--- a/package/klish-plugin-sysrepo/klish-plugin-sysrepo.mk
+++ b/package/klish-plugin-sysrepo/klish-plugin-sysrepo.mk
@@ -4,7 +4,7 @@
#
################################################################################
-KLISH_PLUGIN_SYSREPO_VERSION = a4b1fae697b51614dc75989e8f4fc8d277689d16
+KLISH_PLUGIN_SYSREPO_VERSION = 2f14503c7ea6eb24c8adaf0cf2cf7a511114b09e
KLISH_PLUGIN_SYSREPO_SITE = https://github.com/kernelkit/klish-plugin-sysrepo.git
#KLISH_PLUGIN_SYSREPO_VERSION = cdd3eb51a7f7ee0ed5bd925fa636061d3b1b85fb
#KLISH_PLUGIN_SYSREPO_SITE = https://src.libcode.org/pkun/klish-plugin-sysrepo.git
diff --git a/src/confd/share/migrate/1.7/20-keystore-cleartext-key-rename.sh b/src/confd/share/migrate/1.7/20-keystore-cleartext-key-rename.sh
index b55b42d79..067db0c62 100755
--- a/src/confd/share/migrate/1.7/20-keystore-cleartext-key-rename.sh
+++ b/src/confd/share/migrate/1.7/20-keystore-cleartext-key-rename.sh
@@ -1,5 +1,13 @@
#!/bin/sh
-# Rename cleartext-key to symmetric-key
+# Migrate symmetric keys from v1.6 (v25.11) to IETF standard format.
+#
+# v1.6 had WiFi keys stored as:
+# - infix-keystore:cleartext-key (type string, plaintext)
+# - infix-keystore:key-format wifi-preshared-key-format
+#
+# v1.7 uses the IETF standard leaf and updated format names:
+# - cleartext-symmetric-key (type binary, base64-encoded)
+# - key-format passphrase-key-format
file=$1
temp=${file}.tmp
@@ -7,12 +15,17 @@ temp=${file}.tmp
jq '
if .["ietf-keystore:keystore"]?."symmetric-keys"?."symmetric-key" then
.["ietf-keystore:keystore"]."symmetric-keys"."symmetric-key" |= map(
+ if ."infix-keystore:key-format" then
+ del(."infix-keystore:key-format") |
+ . + { "key-format": "infix-crypto-types:passphrase-key-format" }
+ else
+ .
+ end |
+
if ."infix-keystore:cleartext-key" then
- # Rename cleartext-key to symmetric-key
- ."infix-keystore:cleartext-key" as $key_value |
- del(."infix-keystore:cleartext-key") | . + {
- "infix-keystore:symmetric-key": $key_value
- }
+ ."infix-keystore:cleartext-key" as $val |
+ del(."infix-keystore:cleartext-key") |
+ . + { "cleartext-symmetric-key": ($val | @base64) }
else
.
end
diff --git a/src/confd/src/hardware.c b/src/confd/src/hardware.c
index 0ea34f7b4..6d441fe7f 100644
--- a/src/confd/src/hardware.c
+++ b/src/confd/src/hardware.c
@@ -12,6 +12,7 @@
#include "core.h"
#include "interfaces.h"
#include "dagger.h"
+#include "base64.h"
#define XPATH_BASE_ "/ietf-hardware:hardware"
#define HOSTAPD_CONF "/etc/hostapd-%s.conf"
@@ -235,8 +236,9 @@ static int wifi_find_radio_aps(struct lyd_node *cifs, const char *radio_name,
/* Helper: Write SSID and security configuration (shared between primary and BSS) */
static void wifi_gen_ssid_config(FILE *hostapd, struct lyd_node *cif, struct lyd_node *config, bool is_bss)
{
- const char *ssid, *hidden, *security_mode, *secret_name, *secret;
+ const char *ssid, *hidden, *security_mode, *secret_name;
struct lyd_node *wifi, *ap, *security, *secret_node;
+ unsigned char *secret = NULL;
const char *ifname;
char bssid[18];
@@ -282,15 +284,19 @@ static void wifi_gen_ssid_config(FILE *hostapd, struct lyd_node *cif, struct lyd
security_mode = "open";
/* Get secret from keystore if needed */
- secret = NULL;
if (strcmp(security_mode, "open") != 0) {
secret_name = lydx_get_cattr(security, "secret");
if (secret_name) {
+ const char *b64;
+
secret_node = lydx_get_xpathf(config,
- "/keystore/symmetric-keys/symmetric-key[name='%s']/symmetric-key",
+ "/keystore/symmetric-keys/symmetric-key[name='%s']/cleartext-symmetric-key",
secret_name);
- if (secret_node)
- secret = lyd_get_value(secret_node);
+ if (secret_node) {
+ b64 = lyd_get_value(secret_node);
+ if (b64)
+ secret = base64_decode((const unsigned char *)b64, strlen(b64), NULL);
+ }
}
}
@@ -329,6 +335,8 @@ static void wifi_gen_ssid_config(FILE *hostapd, struct lyd_node *cif, struct lyd
/* ieee80211w=1: MFP capable but optional, for WPA2 client compatibility */
fprintf(hostapd, "ieee80211w=1\n");
}
+
+ free(secret);
}
/* Helper: Write radio-specific configuration */
diff --git a/src/confd/src/if-wifi.c b/src/confd/src/if-wifi.c
index f7d5bef50..430512487 100644
--- a/src/confd/src/if-wifi.c
+++ b/src/confd/src/if-wifi.c
@@ -11,6 +11,7 @@
#include
#include "interfaces.h"
+#include "base64.h"
#define WPA_SUPPLICANT_CONF "/etc/wpa_supplicant-%s.conf"
@@ -59,8 +60,9 @@ int wifi_mode_changed(struct lyd_node *wifi)
*/
int wifi_gen_station(struct lyd_node *cif)
{
- const char *ifname, *ssid, *secret_name, *secret, *security_mode, *radio;
+ const char *ifname, *ssid, *secret_name, *security_mode, *radio;
struct lyd_node *security, *secret_node, *radio_node, *station, *wifi;
+ unsigned char *secret = NULL;
FILE *wpa_supplicant = NULL;
char *security_str = NULL;
const char *country;
@@ -91,12 +93,14 @@ int wifi_gen_station(struct lyd_node *cif)
country = lydx_get_cattr(radio_node, "country-code");
if (secret_name && strcmp(security_mode, "disabled") != 0) {
+ const char *b64;
+
secret_node = lydx_get_xpathf(cif,
"../../keystore/symmetric-keys/symmetric-key[name='%s']",
secret_name);
- secret = lydx_get_cattr(secret_node, "symmetric-key");
- } else {
- secret = NULL;
+ b64 = lydx_get_cattr(secret_node, "cleartext-symmetric-key");
+ if (b64)
+ secret = base64_decode((const unsigned char *)b64, strlen(b64), NULL);
}
oldmask = umask(0077);
@@ -152,6 +156,7 @@ int wifi_gen_station(struct lyd_node *cif)
}
out:
+ free(secret);
if (wpa_supplicant)
fclose(wpa_supplicant);
umask(oldmask);
diff --git a/src/confd/yang/confd/infix-crypto-types.yang b/src/confd/yang/confd/infix-crypto-types.yang
index f6b06e926..ab7ab37ab 100644
--- a/src/confd/yang/confd/infix-crypto-types.yang
+++ b/src/confd/yang/confd/infix-crypto-types.yang
@@ -15,32 +15,46 @@ module infix-crypto-types {
revision 2025-02-04 {
description "Initial";
}
+
identity private-key-format {
+ base ct:private-key-format;
description
- "Base key-format identity for private keys.";
+ "Base for Infix private key format extensions.";
}
+
identity public-key-format {
+ base ct:public-key-format;
description
- "Base key-format identity for public keys.";
+ "Base for Infix public key format extensions.";
}
+
identity rsa-private-key-format {
base private-key-format;
base ct:rsa-private-key-format;
+ description
+ "RSA private key in PKCS#1 format (RFC 8017).
+ Used for SSH host keys.";
}
+
identity ssh-public-key-format {
base public-key-format;
base ct:ssh-public-key-format;
+ description
+ "SSH public key format (RFC 4253, Section 6.6).
+ Used for SSH host keys.";
}
identity symmetric-key-format {
+ base ct:symmetric-key-format;
description
- "Base for symmetric key format";
+ "Base for Infix symmetric key format extensions.";
}
- identity wifi-preshared-key-format {
+
+ identity passphrase-key-format {
base ct:symmetric-key-format;
base symmetric-key-format;
description
- "WiFi secret key";
+ "Human-readable passphrase, e.g., WiFi WPA2/WPA3 passwords.";
}
identity x25519-public-key-format {
@@ -48,7 +62,7 @@ module infix-crypto-types {
base ct:public-key-format;
description
"X25519 (Curve25519) public key format for Diffie-Hellman key exchange.
- This is the format used by WireGuard.";
+ This format is used by network protocols such as WireGuard VPN.";
}
identity x25519-private-key-format {
@@ -56,15 +70,6 @@ module infix-crypto-types {
base ct:private-key-format;
description
"X25519 (Curve25519) private key format for Diffie-Hellman key exchange.
- This is the format used by WireGuard.";
- }
-
- identity wireguard-symmetric-key-format {
- base ct:symmetric-key-format;
- base symmetric-key-format;
- description
- "WireGuard pre-shared key format.
- 32-byte base64-encoded key used as an optional additional layer
- of symmetric encryption for post-quantum resistance.";
+ This format is used by network protocols such as WireGuard VPN.";
}
}
diff --git a/src/confd/yang/confd/infix-if-wireguard.yang b/src/confd/yang/confd/infix-if-wireguard.yang
index ea5e2c2d0..7441ce254 100644
--- a/src/confd/yang/confd/infix-if-wireguard.yang
+++ b/src/confd/yang/confd/infix-if-wireguard.yang
@@ -10,6 +10,9 @@ submodule infix-if-wireguard {
import ietf-inet-types {
prefix inet;
}
+ import ietf-crypto-types {
+ prefix ct;
+ }
import infix-crypto-types {
prefix ixct;
}
@@ -75,8 +78,8 @@ submodule infix-if-wireguard {
This provides post-quantum resistance as an attacker would need
to break both the Curve25519 key exchange and this symmetric key.";
- must "derived-from-or-self(deref(.)/../infix-ks:key-format, 'ixct:wireguard-symmetric-key-format')" {
- error-message "Preshared key must be in wireguard-symmetric-key-format";
+ must "derived-from-or-self(deref(.)/../ks:key-format, 'ct:octet-string-key-format')" {
+ error-message "Preshared key must be in octet-string-key-format";
}
}
diff --git a/src/confd/yang/confd/infix-keystore.yang b/src/confd/yang/confd/infix-keystore.yang
index 9f1f61bd6..c27fbcf81 100644
--- a/src/confd/yang/confd/infix-keystore.yang
+++ b/src/confd/yang/confd/infix-keystore.yang
@@ -5,15 +5,12 @@ module infix-keystore {
import ietf-keystore {
prefix ks;
}
- import ietf-crypto-types {
- prefix ct;
- }
import infix-crypto-types {
prefix infix-ct;
}
revision 2025-12-17 {
- description "Add WireGuard support";
+ description "Add WireGuard support, see infix-crypto-types.yang";
}
revision 2025-12-10 {
description "Adapt to changes in final version of ietf-keystore";
@@ -24,59 +21,4 @@ module infix-keystore {
revision 2025-02-04 {
description "Initial";
}
- deviation "/ks:keystore/ks:asymmetric-keys/ks:asymmetric-key/ks:public-key-format" {
- deviate replace {
- type identityref {
- base infix-ct:public-key-format;
- }
- }
- }
- deviation "/ks:keystore/ks:asymmetric-keys/ks:asymmetric-key/ks:private-key-format" {
- deviate replace {
- type identityref {
- base infix-ct:private-key-format;
- }
- }
- }
- deviation "/ks:keystore/ks:symmetric-keys/ks:symmetric-key/ks:key-format" {
- deviate not-supported;
- }
- augment "/ks:keystore/ks:symmetric-keys/ks:symmetric-key" {
- leaf key-format {
- type identityref {
- base infix-ct:symmetric-key-format;
- }
- description
- "Identifies the symmetric key's format
-
- Valid symmetric key formats are:
- wifi-preshared-key-format - WiFi preshared key
- wireguard-symmetric-key-format - WireGuard preshared key";
- }
- }
- deviation "/ks:keystore/ks:symmetric-keys/ks:symmetric-key/ks:key-type/ks:cleartext-symmetric-key" {
- deviate not-supported;
- }
- augment "/ks:keystore/ks:symmetric-keys/ks:symmetric-key/ks:key-type" {
- case cleartext-symmetric-key {
- leaf symmetric-key {
- type string;
- must "../infix-ks:key-format != 'infix-ct:wifi-preshared-key-format' or " +
- "(string-length(.) >= 8 and string-length(.) <= 63)" {
- error-message "WiFi pre-shared key must be 8-63 characters long";
- }
- must "../infix-ks:key-format != 'infix-ct:wireguard-symmetric-key-format' or " +
- "string-length(.) = 44" {
- error-message "WireGuard pre-shared key must be 44 characters (32-byte base64-encoded)";
- }
- description
- "Cleartext symmetric key value.
-
- Format depends on key-format:
- - WiFi pre-shared key: 8-63 printable ASCII characters
- - WireGuard pre-shared key: 32-byte base64-encoded key (44 chars with padding)";
-
- }
- }
- }
}
diff --git a/src/klish-plugin-infix/xml/infix.xml b/src/klish-plugin-infix/xml/infix.xml
index e6b29cbf8..5a66eec5c 100644
--- a/src/klish-plugin-infix/xml/infix.xml
+++ b/src/klish-plugin-infix/xml/infix.xml
@@ -259,6 +259,21 @@
+
+
+
+priv=$(wg genkey)
+pub=$(printf '%s' "$priv" | wg pubkey)
+echo "Private: $priv"
+echo "Public: $pub"
+
+
+
+
+ wg genpsk
+
+
+
diff --git a/test/case/interfaces/wireguard_multipoint/test.py b/test/case/interfaces/wireguard_multipoint/test.py
index 531192103..c790ae520 100755
--- a/test/case/interfaces/wireguard_multipoint/test.py
+++ b/test/case/interfaces/wireguard_multipoint/test.py
@@ -75,12 +75,12 @@ def configure_server(dut):
"symmetric-keys": {
"symmetric-key": [{
"name": "psk-client1",
- "infix-keystore:symmetric-key": psk_client1,
- "infix-keystore:key-format": "infix-crypto-types:wireguard-symmetric-key-format"
+ "cleartext-symmetric-key": psk_client1,
+ "key-format": "ietf-crypto-types:octet-string-key-format"
}, {
"name": "psk-client2",
- "infix-keystore:symmetric-key": psk_client2,
- "infix-keystore:key-format": "infix-crypto-types:wireguard-symmetric-key-format"
+ "cleartext-symmetric-key": psk_client2,
+ "key-format": "ietf-crypto-types:octet-string-key-format"
}]
}
}
@@ -226,8 +226,8 @@ def configure_client1(dut):
"symmetric-keys": {
"symmetric-key": [{
"name": "psk-server",
- "infix-keystore:symmetric-key": psk_client1,
- "infix-keystore:key-format": "infix-crypto-types:wireguard-symmetric-key-format"
+ "cleartext-symmetric-key": psk_client1,
+ "key-format": "ietf-crypto-types:octet-string-key-format"
}]
}
}
@@ -360,8 +360,8 @@ def configure_client2(dut):
"symmetric-keys": {
"symmetric-key": [{
"name": "psk-server",
- "infix-keystore:symmetric-key": psk_client2,
- "infix-keystore:key-format": "infix-crypto-types:wireguard-symmetric-key-format"
+ "cleartext-symmetric-key": psk_client2,
+ "key-format": "ietf-crypto-types:octet-string-key-format"
}]
}
}