Politician 1.0.0
WiFi Auditing Library for ESP32
Loading...
Searching...
No Matches
PoliticianWPS.h
Go to the documentation of this file.
1#pragma once
2/**
3 * @file PoliticianWPS.h
4 * @brief Opt-in WPS M1 capture utilities for the Politician engine.
5 *
6 * Include this header alongside Politician.h to enable WPS M1 device fingerprinting.
7 * The engine passively captures the first unencrypted EAP-WSC message (M1) sent by
8 * a WPS Enrollee, exposing device attributes without any active interaction.
9 *
10 * Usage:
11 * #include "Politician.h"
12 * #include "PoliticianWPS.h" // Add this line
13 *
14 * engine.setWpsCallback([](const WpsRecord &rec) {
15 * Serial.printf("[WPS] %s by %s (%s)\n",
16 * rec.device_name, rec.manufacturer, PoliticianWPS::configMethodsStr(rec.config_methods));
17 * PoliticianWPS::print(Serial, rec);
18 * });
19 *
20 * Notes:
21 * - Only M1 (Enrollee → AP) is unencrypted and parseable passively.
22 * - Subsequent WPS messages (M2-M8) are encrypted; PIN cracking is not possible passively.
23 * - Enable by calling engine.setWpsCallback() — zero overhead if callback is null.
24 * - WPS exchange occurs during association; channel hopping must be active for discovery.
25 */
26
27#include "PoliticianTypes.h"
28#include <Arduino.h>
29
30namespace politician {
31
32namespace PoliticianWPS {
33
34// ─── Device Type Category Strings ────────────────────────────────────────────
35// Primary Device Type category codes (WPS spec Table E-3)
36inline const char* devTypeCatStr(uint16_t cat) {
37 switch (cat) {
38 case 1: return "Computer";
39 case 2: return "Input Device";
40 case 3: return "Printer/Scanner/Fax/Copier";
41 case 4: return "Camera";
42 case 5: return "Storage";
43 case 6: return "Network Infrastructure";
44 case 7: return "Displays";
45 case 8: return "Multimedia Device";
46 case 9: return "Gaming";
47 case 10: return "Telephone";
48 case 11: return "Audio";
49 case 12: return "Docking Device";
50 case 255: return "Other";
51 default: return "Unknown";
52 }
53}
54
55// ─── Config Methods Bitmask Helpers ──────────────────────────────────────────
56// Config Methods field bits (WPS spec Table E-4, 0x1012 attribute)
57static const uint16_t CFG_USBA = 0x0001;
58static const uint16_t CFG_ETHERNET = 0x0002;
59static const uint16_t CFG_LABEL = 0x0004;
60static const uint16_t CFG_DISPLAY = 0x0008;
61static const uint16_t CFG_EXT_NFC = 0x0010;
62static const uint16_t CFG_INT_NFC = 0x0020;
63static const uint16_t CFG_NFC_IFACE = 0x0040;
64static const uint16_t CFG_PUSH_BUTTON = 0x0080;
65static const uint16_t CFG_KEYPAD = 0x0100;
66static const uint16_t CFG_VIRTUAL_PBC = 0x0200;
67static const uint16_t CFG_PHYSICAL_PBC = 0x0400;
68static const uint16_t CFG_VIRTUAL_PIN = 0x2000;
69static const uint16_t CFG_PHYSICAL_PIN = 0x4000;
70
71/** @brief Returns a compact human-readable string of supported WPS setup methods. */
72inline const char* configMethodsStr(uint16_t methods, char *buf, size_t bufSz) {
73 if (!buf || bufSz == 0) return "";
74 buf[0] = '\0';
75 if (methods & CFG_PUSH_BUTTON) strncat(buf, "PBC ", bufSz - strlen(buf) - 1);
76 if (methods & CFG_KEYPAD) strncat(buf, "PIN-Keypad ", bufSz - strlen(buf) - 1);
77 if (methods & CFG_LABEL) strncat(buf, "PIN-Label ", bufSz - strlen(buf) - 1);
78 if (methods & CFG_DISPLAY) strncat(buf, "Display ", bufSz - strlen(buf) - 1);
79 if (methods & CFG_NFC_IFACE) strncat(buf, "NFC ", bufSz - strlen(buf) - 1);
80 if (buf[0] == '\0') strncat(buf, "None", bufSz - strlen(buf) - 1);
81 // Trim trailing space
82 size_t n = strlen(buf);
83 if (n > 0 && buf[n - 1] == ' ') buf[n - 1] = '\0';
84 return buf;
85}
86
87/** @brief Compatibility overload using a static buffer (not thread-safe). */
88inline const char* configMethodsStr(uint16_t methods) {
89 static char buf[64];
90 return configMethodsStr(methods, buf, sizeof(buf));
91}
92
93// ─── Auth Type Flags ──────────────────────────────────────────────────────────
94/// @defgroup wps_auth WPS Authentication Type Flags
95/// Bitmask values for the WPS Authentication Type attribute (ID 0x1004).
96/// Source: WPS specification v2.0.5, Table M-10.
97/// Test WpsRecord::auth_type_flags against these masks.
98/// @{
99static const uint16_t AUTH_OPEN = 0x0001; ///< Open (no authentication)
100static const uint16_t AUTH_WPAPSK = 0x0002; ///< WPA Personal (PSK)
101static const uint16_t AUTH_SHARED = 0x0004; ///< Shared Key (deprecated WEP-era)
102static const uint16_t AUTH_WPA = 0x0008; ///< WPA Enterprise (802.1X)
103static const uint16_t AUTH_WPA2 = 0x0010; ///< WPA2 Enterprise (802.1X)
104static const uint16_t AUTH_WPA2PSK = 0x0020; ///< WPA2 Personal (PSK)
105/// @}
106
107// ─── Print Helper ─────────────────────────────────────────────────────────────────────────────
108/** @brief Pretty-prints a WpsRecord to any Print-compatible stream (Serial, etc.). */
109template<typename TStream>
110inline void print(TStream &out, const WpsRecord &rec) {
111 char mac[18];
112 snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X",
113 rec.sta[0], rec.sta[1], rec.sta[2], rec.sta[3], rec.sta[4], rec.sta[5]);
114 out.printf("┌─ WPS M1 Enrollee ───────────────────────\n");
115 out.printf("│ STA: %s ch%d %d dBm\n", mac, rec.channel, rec.rssi);
116 out.printf("│ Device Name: %s\n", rec.device_name[0] ? rec.device_name : "(unknown)");
117 out.printf("│ Manufacturer: %s\n", rec.manufacturer[0] ? rec.manufacturer : "(unknown)");
118 char methodsBuf[64];
119 out.printf("│ Model: %s %s\n",
120 rec.model_name[0] ? rec.model_name : "",
121 rec.model_number[0] ? rec.model_number : "");
122 out.printf("│ Serial: %s\n", rec.serial_number[0] ? rec.serial_number : "(unknown)");
123 out.printf("│ Dev Type: %s (cat 0x%04X)\n",
125 out.printf("│ Config Meth: %s (0x%04X)\n",
126 configMethodsStr(rec.config_methods, methodsBuf, sizeof(methodsBuf)), rec.config_methods);
127 out.printf("│ RF Bands: %s%s\n",
128 (rec.rf_bands & 0x01) ? "2.4GHz " : "",
129 (rec.rf_bands & 0x02) ? "5GHz" : "");
130 out.printf("└─────────────────────────────────────────\n");
131}
132
133} // namespace PoliticianWPS
134
135} // namespace politician
static const uint16_t AUTH_OPEN
Open (no authentication)
static const uint16_t AUTH_SHARED
Shared Key (deprecated WEP-era)
static const uint16_t AUTH_WPA2PSK
WPA2 Personal (PSK)
static const uint16_t AUTH_WPA
WPA Enterprise (802.1X)
static const uint16_t AUTH_WPA2
WPA2 Enterprise (802.1X)
static const uint16_t AUTH_WPAPSK
WPA Personal (PSK)
static const uint16_t CFG_DISPLAY
static const uint16_t CFG_VIRTUAL_PIN
const char * devTypeCatStr(uint16_t cat)
static const uint16_t CFG_KEYPAD
static const uint16_t CFG_EXT_NFC
static const uint16_t CFG_LABEL
static const uint16_t CFG_PHYSICAL_PIN
static const uint16_t CFG_ETHERNET
static const uint16_t CFG_NFC_IFACE
const char * configMethodsStr(uint16_t methods, char *buf, size_t bufSz)
Returns a compact human-readable string of supported WPS setup methods.
static const uint16_t CFG_INT_NFC
static const uint16_t CFG_USBA
static const uint16_t CFG_VIRTUAL_PBC
void print(TStream &out, const WpsRecord &rec)
Pretty-prints a WpsRecord to any Print-compatible stream (Serial, etc.).
static const uint16_t CFG_PHYSICAL_PBC
static const uint16_t CFG_PUSH_BUTTON
WPS M1 device attributes harvested from an EAP-WSC exchange.