import java.util.*; /** * Unit test for zephyr-0001: wifi_credentials_shell.c print_network_info() * prints WiFi PSK and EAP-TLS key_passwd verbatim to the shell (CWE-312). * * Models the C pattern in print_network_info(): * * shell_fprintf(sh, ..., ", password: \"%.*s\", password_len: %d", * (int)creds.password_len, creds.password, creds.password_len); * * When a user runs "wifi cred list" on a Zephyr shell, all stored network * credentials including WPA2-PSK passwords and EAP-TLS private-key passphrases * are printed in cleartext. On serial/UART consoles this is visible to anyone * with physical access; logging backends may persist the secret. * * Fix: replace the credential value with "[redacted]", keep the length. */ public class ZephyrWifiCredShellTest { static final String REDACTED = "[redacted]"; // Security type constants (mirroring Zephyr wifi_security_type) static final int WIFI_SECURITY_TYPE_NONE = 0; static final int WIFI_SECURITY_TYPE_PSK = 1; static final int WIFI_SECURITY_TYPE_PSK_SHA256 = 2; static final int WIFI_SECURITY_TYPE_SAE = 3; static final int WIFI_SECURITY_TYPE_WPA_PSK = 9; static final int WIFI_SECURITY_TYPE_EAP_TLS = 7; // --- Defective version: prints password verbatim --- static String printNetworkInfoDefective(String ssid, int secType, String password, String keyPasswd) { StringBuilder sb = new StringBuilder(); sb.append(String.format(" network ssid: \"%s\", ssid_len: %d, type: %d", ssid, ssid.length(), secType)); if (secType == WIFI_SECURITY_TYPE_PSK || secType == WIFI_SECURITY_TYPE_PSK_SHA256 || secType == WIFI_SECURITY_TYPE_SAE || secType == WIFI_SECURITY_TYPE_WPA_PSK) { // DEFECT: password value logged verbatim sb.append(String.format(", password: \"%s\", password_len: %d", password, password.length())); } if (secType == WIFI_SECURITY_TYPE_EAP_TLS && keyPasswd != null && !keyPasswd.isEmpty()) { // DEFECT: key_passwd value logged verbatim sb.append(String.format(", key_passwd: \"%s\", key_passwd_len: %d", keyPasswd, keyPasswd.length())); } return sb.toString(); } // --- Fixed version: redacts password and key_passwd --- static String printNetworkInfoFixed(String ssid, int secType, String password, String keyPasswd) { StringBuilder sb = new StringBuilder(); sb.append(String.format(" network ssid: \"%s\", ssid_len: %d, type: %d", ssid, ssid.length(), secType)); if (secType == WIFI_SECURITY_TYPE_PSK || secType == WIFI_SECURITY_TYPE_PSK_SHA256 || secType == WIFI_SECURITY_TYPE_SAE || secType == WIFI_SECURITY_TYPE_WPA_PSK) { // FIX: redact password value, keep length sb.append(String.format(", password: %s, password_len: %d", REDACTED, password.length())); } if (secType == WIFI_SECURITY_TYPE_EAP_TLS && keyPasswd != null && !keyPasswd.isEmpty()) { // FIX: redact key_passwd value, keep length sb.append(String.format(", key_passwd: %s, key_passwd_len: %d", REDACTED, keyPasswd.length())); } return sb.toString(); } public static void main(String[] args) { System.out.println("=== zephyr-0001: wifi_credentials_shell PSK/key_passwd CWE-312 ===\n"); int pass = 0, total = 0; // Test 1: WPA2-PSK defective path leaks password { total++; String psk = "SuperSecretWifi123!"; String out = printNetworkInfoDefective("HomeNetwork", WIFI_SECURITY_TYPE_PSK, psk, null); boolean leaks = out.contains(psk); assert leaks : "FAIL T1: expected defective path to contain PSK"; System.out.println("T1 CONFIRMED defective: PSK in output = " + leaks + " out=" + out); pass++; } // Test 2: WPA2-PSK fixed path redacts password { total++; String psk = "SuperSecretWifi123!"; String out = printNetworkInfoFixed("HomeNetwork", WIFI_SECURITY_TYPE_PSK, psk, null); boolean hidden = !out.contains(psk); boolean hasRedacted = out.contains(REDACTED); boolean hasLen = out.contains(String.valueOf(psk.length())); assert hidden : "FAIL T2: fixed path should not contain PSK"; assert hasRedacted : "FAIL T2: fixed path should contain [redacted]"; assert hasLen : "FAIL T2: fixed path should still show password_len"; System.out.printf("T2 PASS fixed: hidden=%b redacted=%b len_present=%b%n", hidden, hasRedacted, hasLen); pass++; } // Test 3: SAE (WPA3) password redacted { total++; String saePass = "WPA3SensitivePass"; String out = printNetworkInfoFixed("Office5G", WIFI_SECURITY_TYPE_SAE, saePass, null); assert !out.contains(saePass) : "FAIL T3: SAE password should be redacted"; assert out.contains(REDACTED) : "FAIL T3: [redacted] marker expected"; System.out.println("T3 PASS: SAE password redacted correctly"); pass++; } // Test 4: EAP-TLS key_passwd defective path leaks passphrase { total++; String keyPass = "PrivKeyPassphrase42"; String out = printNetworkInfoDefective("EnterpriseNet", WIFI_SECURITY_TYPE_EAP_TLS, "", keyPass); boolean leaks = out.contains(keyPass); assert leaks : "FAIL T4: expected defective EAP-TLS path to contain key_passwd"; System.out.println("T4 CONFIRMED defective: EAP key_passwd in output = " + leaks); pass++; } // Test 5: EAP-TLS key_passwd fixed path redacts passphrase { total++; String keyPass = "PrivKeyPassphrase42"; String out = printNetworkInfoFixed("EnterpriseNet", WIFI_SECURITY_TYPE_EAP_TLS, "", keyPass); boolean hidden = !out.contains(keyPass); boolean hasRedacted = out.contains(REDACTED); assert hidden : "FAIL T5: fixed EAP-TLS path should not contain key_passwd"; assert hasRedacted : "FAIL T5: [redacted] expected in EAP-TLS output"; System.out.printf("T5 PASS: EAP key_passwd hidden=%b redacted=%b%n", hidden, hasRedacted); pass++; } // Test 6: OPEN network (no password) - no redacted marker, no password field { total++; String out = printNetworkInfoFixed("PublicWifi", WIFI_SECURITY_TYPE_NONE, "", null); boolean noPassword = !out.contains("password:"); assert noPassword : "FAIL T6: OPEN network should not have password field"; System.out.println("T6 PASS: OPEN network - no password field in output"); pass++; } // Test 7: SSID is still shown (not a secret) { total++; String ssid = "MyHomeNetwork"; String psk = "secret123"; String out = printNetworkInfoFixed(ssid, WIFI_SECURITY_TYPE_PSK, psk, null); assert out.contains(ssid) : "FAIL T7: SSID should still be visible"; assert !out.contains(psk) : "FAIL T7: PSK should be redacted"; assert out.contains(REDACTED) : "FAIL T7: [redacted] expected"; System.out.println("T7 PASS: SSID visible, PSK redacted"); pass++; } // Test 8: WPA-PSK (legacy) also redacted { total++; String psk = "OldSchoolPass"; String out = printNetworkInfoFixed("LegacyAP", WIFI_SECURITY_TYPE_WPA_PSK, psk, null); assert !out.contains(psk) : "FAIL T8: WPA-PSK password should be redacted"; assert out.contains(REDACTED) : "FAIL T8: [redacted] expected for WPA-PSK"; System.out.println("T8 PASS: WPA-PSK (legacy) password redacted"); pass++; } System.out.printf("%n%d/%d tests PASS%n", pass, total); if (pass != total) { System.exit(1); } } }