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 b55b42d7..067db0c6 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 0ea34f7b..6d441fe7 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 f7d5bef5..bb35a96a 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); @@ -121,11 +125,13 @@ int wifi_gen_station(struct lyd_node *cif) /* If SSID is present, create network block. Otherwise, scan-only mode */ if (ssid) { /* Station mode with network configured */ - if (!strcmp(security_mode, "disabled")) { + if (!strcmp(security_mode, "disabled")) asprintf(&security_str, "key_mgmt=NONE"); - } else if (secret) { - asprintf(&security_str, "key_mgmt=SAE WPA-PSK\npsk=\"%s\"", secret); - } + else if (secret) + asprintf(&security_str, + "key_mgmt=SAE WPA-PSK\n" + " psk=\"%s\"", secret); + fprintf(wpa_supplicant, "network={\n" " bgscan=\"simple: 30:-45:300\"\n" @@ -152,6 +158,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 f6b06e92..ab7ab37a 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 ea5e2c2d..7441ce25 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 9f1f61bd..c27fbcf8 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/test/case/interfaces/wireguard_multipoint/test.py b/test/case/interfaces/wireguard_multipoint/test.py index 53119210..c790ae52 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" }] } }