From 58a5f13db36a46cad3925714cf7dcc9f62317ebc Mon Sep 17 00:00:00 2001 From: Andrew Beltrano Date: Wed, 3 Jul 2024 03:14:26 +0000 Subject: [PATCH 1/5] Add helper to convert an arbitrary type to a std::string_view. --- .../shared/strings/include/strings/StringHelpers.hxx | 7 +++++++ src/linux/wpa-controller/WpaResponseParser.cxx | 9 +++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/common/shared/strings/include/strings/StringHelpers.hxx b/src/common/shared/strings/include/strings/StringHelpers.hxx index d0697ef0..1b2cadef 100644 --- a/src/common/shared/strings/include/strings/StringHelpers.hxx +++ b/src/common/shared/strings/include/strings/StringHelpers.hxx @@ -82,6 +82,13 @@ CaseInsensitiveStringEquals(std::string_view lhs, std::string_view rhs); std::string GenerateRandomAsciiString(std::size_t length); +/** + * @brief Helper to convert an arbitrary input to a string view. + */ +constexpr auto ToStringView = [](auto&& sv) { + return std::string_view(sv); +}; + } // namespace Strings #endif // STRING_HELPERS_HXX diff --git a/src/linux/wpa-controller/WpaResponseParser.cxx b/src/linux/wpa-controller/WpaResponseParser.cxx index 041410d8..576c1060 100644 --- a/src/linux/wpa-controller/WpaResponseParser.cxx +++ b/src/linux/wpa-controller/WpaResponseParser.cxx @@ -17,6 +17,7 @@ #include #include #include +#include using namespace Wpa; @@ -61,10 +62,6 @@ WpaResponseParser::GetResponsePayload() const noexcept bool WpaResponseParser::TryParseProperties() { - // Convert a range to a string-view. - constexpr auto toStringView = [](auto&& sv) { - return std::string_view(sv); - }; // Convert a key-value pair to its key. constexpr auto toKey = [](auto&& keyValuePair) { return keyValuePair.Key; @@ -79,11 +76,11 @@ WpaResponseParser::TryParseProperties() } // Parse the payload into individual lines containing key value pairs. - auto lines = m_responsePayload | std::views::split(ProtocolWpa::KeyValueLineDelimeter) | std::views::transform(toStringView); + auto lines = m_responsePayload | std::views::split(ProtocolWpa::KeyValueLineDelimeter) | std::views::transform(Strings::ToStringView); // Parse each line into a key-value pair, and populate the property map with them. for (const auto line : lines) { - auto keyValuePair = line | std::views::split(ProtocolWpa::KeyValueDelimiter) | std::views::transform(toStringView); + auto keyValuePair = line | std::views::split(ProtocolWpa::KeyValueDelimiter) | std::views::transform(Strings::ToStringView); auto keyValuePairIterator = std::begin(keyValuePair); if (keyValuePairIterator == std::end(keyValuePair)) { From 5c1a6d8e07233fee3500af824bbb805d378df6c9 Mon Sep 17 00:00:00 2001 From: Andrew Beltrano Date: Wed, 3 Jul 2024 03:14:51 +0000 Subject: [PATCH 2/5] Add array of valid WpaKeyMgmt values. --- .../include/Wpa/ProtocolHostapd.hxx | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/linux/wpa-controller/include/Wpa/ProtocolHostapd.hxx b/src/linux/wpa-controller/include/Wpa/ProtocolHostapd.hxx index 6250a26e..b77b8ce9 100644 --- a/src/linux/wpa-controller/include/Wpa/ProtocolHostapd.hxx +++ b/src/linux/wpa-controller/include/Wpa/ProtocolHostapd.hxx @@ -300,6 +300,34 @@ inline constexpr std::array AllWpaKeyManagements = { WpaKeyManagement::Pasn, }; +/** + * @brief Array of all WpaKeyManagement values accepted by hostapd the control socket. + * + * magic_enum::enum_values() cannot be used since the enum values exceed [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]. + */ +inline constexpr std::array AllWpaKeyManagementsValid = { + WpaKeyManagement::Unknown, + WpaKeyManagement::Ieee8021x, + WpaKeyManagement::Psk, + WpaKeyManagement::FtIeee8021x, + WpaKeyManagement::FtPsk, + WpaKeyManagement::Ieee8021xSha256, + WpaKeyManagement::PskSha256, + WpaKeyManagement::Sae, + WpaKeyManagement::FtSae, + WpaKeyManagement::Osen, + WpaKeyManagement::Ieee8021xSuiteB, + WpaKeyManagement::Ieee8021xSuiteB192, + WpaKeyManagement::FilsSha256, + WpaKeyManagement::FilsSha384, + WpaKeyManagement::FtFilsSha256, + WpaKeyManagement::FtFilsSha384, + WpaKeyManagement::Owe, + WpaKeyManagement::Dpp, + WpaKeyManagement::FtIeee8021xSha384, + WpaKeyManagement::Pasn, +}; + /** * @brief A bitmask containing all valid WpaKeyManagement values supporting fast-transition (FT). */ From ead5be6649fb192ad2c01e95b1c9876ef3ebbbe4 Mon Sep 17 00:00:00 2001 From: Andrew Beltrano Date: Wed, 3 Jul 2024 03:15:34 +0000 Subject: [PATCH 3/5] Add function to convert string to single WpaKeyManagement enumeration value. --- src/linux/wpa-controller/ProtocolHostapd.cxx | 103 ++++++++++-------- .../wpa-controller/WpaCommandGetConfig.cxx | 2 +- .../include/Wpa/ProtocolHostapd.hxx | 11 +- 3 files changed, 70 insertions(+), 46 deletions(-) diff --git a/src/linux/wpa-controller/ProtocolHostapd.cxx b/src/linux/wpa-controller/ProtocolHostapd.cxx index d9c252c8..b75bf666 100644 --- a/src/linux/wpa-controller/ProtocolHostapd.cxx +++ b/src/linux/wpa-controller/ProtocolHostapd.cxx @@ -1,4 +1,6 @@ +#include +#include #include #include #include @@ -6,6 +8,7 @@ #include #include +#include using namespace Wpa; @@ -87,54 +90,66 @@ Wpa::WpaPreSharedKeyPropertyKeyAndValue(const WpaPreSharedKey& wpaPreSharedKey) return std::make_pair(propertyName, std::move(propertyValue)); } -std::vector +WpaKeyManagement Wpa::WpaKeyManagementFromPropertyValue(std::string_view wpaKeyManagementProperty) noexcept { - std::string wpaKeyManagementString(wpaKeyManagementProperty); - std::istringstream wpaKeyManagementStream(wpaKeyManagementString); - std::vector wpaKeyManagements{}; + // String values used here were from hostapd config_file.c::hostapd_config_parse_key_mgmt(). + // https://w1.fi/cgit/hostap/tree/hostapd/config_file.c?h=hostap_2_10#n682 - for (std::string wpaKeyManagement; wpaKeyManagementStream >> wpaKeyManagement;) { - if (wpaKeyManagement == "WPA-EAP") { - wpaKeyManagements.push_back(WpaKeyManagement::Ieee8021x); - } else if (wpaKeyManagement == "WPA-PSK") { - wpaKeyManagements.push_back(WpaKeyManagement::Psk); - } else if (wpaKeyManagement == "FT-EAP") { - wpaKeyManagements.push_back(WpaKeyManagement::FtIeee8021x); - } else if (wpaKeyManagement == "FT-PSK") { - wpaKeyManagements.push_back(WpaKeyManagement::FtPsk); - } else if (wpaKeyManagement == "WPA-EAP-SHA256") { - wpaKeyManagements.push_back(WpaKeyManagement::Ieee8021xSha256); - } else if (wpaKeyManagement == "WPA-PSK-SHA256") { - wpaKeyManagements.push_back(WpaKeyManagement::PskSha256); - } else if (wpaKeyManagement == "SAE") { - wpaKeyManagements.push_back(WpaKeyManagement::Sae); - } else if (wpaKeyManagement == "FT-SAE") { - wpaKeyManagements.push_back(WpaKeyManagement::FtSae); - } else if (wpaKeyManagement == "OSEN") { - wpaKeyManagements.push_back(WpaKeyManagement::Osen); - } else if (wpaKeyManagement == "WPA-EAP-SUITE-B") { - wpaKeyManagements.push_back(WpaKeyManagement::Ieee8021xSuiteB); - } else if (wpaKeyManagement == "WPA-EAP-SUITE-B-192") { - wpaKeyManagements.push_back(WpaKeyManagement::Ieee8021xSuiteB192); - } else if (wpaKeyManagement == "FILS-SHA256") { - wpaKeyManagements.push_back(WpaKeyManagement::FilsSha256); - } else if (wpaKeyManagement == "FILS-SHA384") { - wpaKeyManagements.push_back(WpaKeyManagement::FilsSha384); - } else if (wpaKeyManagement == "FT-FILS-SHA256") { - wpaKeyManagements.push_back(WpaKeyManagement::FtFilsSha256); - } else if (wpaKeyManagement == "FT-FILS-SHA384") { - wpaKeyManagements.push_back(WpaKeyManagement::FtFilsSha384); - } else if (wpaKeyManagement == "OWE") { - wpaKeyManagements.push_back(WpaKeyManagement::Owe); - } else if (wpaKeyManagement == "DPP") { - wpaKeyManagements.push_back(WpaKeyManagement::Dpp); - } else if (wpaKeyManagement == "FT-EAP-SHA384") { - wpaKeyManagements.push_back(WpaKeyManagement::FtIeee8021xSha384); - } else if (wpaKeyManagement == "PASN") { - wpaKeyManagements.push_back(WpaKeyManagement::Pasn); - } + // NOLINTBEGIN(readability-else-after-return) + if (wpaKeyManagementProperty == "WPA-EAP") { + return WpaKeyManagement::Ieee8021x; + } else if (wpaKeyManagementProperty == "WPA-PSK") { + return WpaKeyManagement::Psk; + } else if (wpaKeyManagementProperty == "FT-EAP") { + return WpaKeyManagement::FtIeee8021x; + } else if (wpaKeyManagementProperty == "FT-PSK") { + return WpaKeyManagement::FtPsk; + } else if (wpaKeyManagementProperty == "WPA-EAP-SHA256") { + return WpaKeyManagement::Ieee8021xSha256; + } else if (wpaKeyManagementProperty == "WPA-PSK-SHA256") { + return WpaKeyManagement::PskSha256; + } else if (wpaKeyManagementProperty == "SAE") { + return WpaKeyManagement::Sae; + } else if (wpaKeyManagementProperty == "FT-SAE") { + return WpaKeyManagement::FtSae; + } else if (wpaKeyManagementProperty == "OSEN") { + return WpaKeyManagement::Osen; + } else if (wpaKeyManagementProperty == "WPA-EAP-SUITE-B") { + return WpaKeyManagement::Ieee8021xSuiteB; + } else if (wpaKeyManagementProperty == "WPA-EAP-SUITE-B-192") { + return WpaKeyManagement::Ieee8021xSuiteB192; + } else if (wpaKeyManagementProperty == "FILS-SHA256") { + return WpaKeyManagement::FilsSha256; + } else if (wpaKeyManagementProperty == "FILS-SHA384") { + return WpaKeyManagement::FilsSha384; + } else if (wpaKeyManagementProperty == "FT-FILS-SHA256") { + return WpaKeyManagement::FtFilsSha256; + } else if (wpaKeyManagementProperty == "FT-FILS-SHA384") { + return WpaKeyManagement::FtFilsSha384; + } else if (wpaKeyManagementProperty == "OWE") { + return WpaKeyManagement::Owe; + } else if (wpaKeyManagementProperty == "DPP") { + return WpaKeyManagement::Dpp; + } else if (wpaKeyManagementProperty == "FT-EAP-SHA384") { + return WpaKeyManagement::FtIeee8021xSha384; + } else if (wpaKeyManagementProperty == "PASN") { + return WpaKeyManagement::Pasn; + } else { + return WpaKeyManagement::Unknown; } + // NOLINTEND(readability-else-after-return) +} + +std::vector +Wpa::WpaKeyManagementsFromPropertyValue(std::string_view wpaKeyManagementProperty) noexcept +{ + auto wpaKeyManagementStrings = std::views::split(wpaKeyManagementProperty, ' ') | std::views::transform(Strings::ToStringView) | std::views::transform(WpaKeyManagementFromPropertyValue); + + std::vector wpaKeyManagements{ + std::make_move_iterator(std::begin(wpaKeyManagementStrings)), + std::make_move_iterator(std::end(wpaKeyManagementStrings)) + }; return wpaKeyManagements; } diff --git a/src/linux/wpa-controller/WpaCommandGetConfig.cxx b/src/linux/wpa-controller/WpaCommandGetConfig.cxx index d4b8844f..3a0e573d 100644 --- a/src/linux/wpa-controller/WpaCommandGetConfig.cxx +++ b/src/linux/wpa-controller/WpaCommandGetConfig.cxx @@ -57,7 +57,7 @@ WpaGetConfigResponseParser::ParsePayload() ParseInt(value, wpa); configuration.Wpa = static_cast(wpa); } else if (key == ProtocolHostapd::ResponseGetConfigPropertyKeyWpaKeyMgmt) { - configuration.WpaKeyMgmt = WpaKeyManagementFromPropertyValue(value); + configuration.WpaKeyMgmt = WpaKeyManagementsFromPropertyValue(value); } else if (key == ProtocolHostapd::ResponseGetConfigPropertyKeyGroupCipher) { configuration.GroupCipher = WpaCipherFromPropertyValue(value); } else if (key == ProtocolHostapd::ResponseGetConfigPropertyKeyRsnPairwiseCipher) { diff --git a/src/linux/wpa-controller/include/Wpa/ProtocolHostapd.hxx b/src/linux/wpa-controller/include/Wpa/ProtocolHostapd.hxx index b77b8ce9..468f9c51 100644 --- a/src/linux/wpa-controller/include/Wpa/ProtocolHostapd.hxx +++ b/src/linux/wpa-controller/include/Wpa/ProtocolHostapd.hxx @@ -858,6 +858,15 @@ WpaKeyManagementPropertyValue(WpaKeyManagement wpaKeyManagement) noexcept } } +/** + * @brief Convert a string to a single WpaKeyManagement value. + * + * @param wpaKeyManagementProperty The hostapd property value string to convert. + * @return WpaKeyManagement The corresponding WpaKeyManagement value. + */ +WpaKeyManagement +WpaKeyManagementFromPropertyValue(std::string_view wpaKeyManagementProperty) noexcept; + /** * @brief Convert a hostapd 'wpa_key_mgmt' property value string to the corresponding WpaKeyManagement value. * This string may have several whitespace-separated values, such as "WPA-PSK SAE". @@ -866,7 +875,7 @@ WpaKeyManagementPropertyValue(WpaKeyManagement wpaKeyManagement) noexcept * @return std::vector The corresponding WpaKeyManagement values. */ std::vector -WpaKeyManagementFromPropertyValue(std::string_view wpaKeyManagementProperty) noexcept; +WpaKeyManagementsFromPropertyValue(std::string_view wpaKeyManagementProperty) noexcept; /** * @brief WpaCipher sentinel for an invalid value. From dc60fc101cdd50f27589b5ffaf288b3747eac42a Mon Sep 17 00:00:00 2001 From: Andrew Beltrano Date: Wed, 3 Jul 2024 03:15:58 +0000 Subject: [PATCH 4/5] Add WpaKeyManagement conversion stability test. --- tests/unit/linux/wpa-controller/CMakeLists.txt | 1 + .../wpa-controller/TestWpaProtocolHostapd.cxx | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 tests/unit/linux/wpa-controller/TestWpaProtocolHostapd.cxx diff --git a/tests/unit/linux/wpa-controller/CMakeLists.txt b/tests/unit/linux/wpa-controller/CMakeLists.txt index a439a21a..0521c8c3 100644 --- a/tests/unit/linux/wpa-controller/CMakeLists.txt +++ b/tests/unit/linux/wpa-controller/CMakeLists.txt @@ -9,6 +9,7 @@ target_sources(wpa-controller-test-unit Main.cxx TestHostapd.cxx TestWpaController.cxx + TestWpaProtocolHostapd.cxx ) target_include_directories(wpa-controller-test-unit diff --git a/tests/unit/linux/wpa-controller/TestWpaProtocolHostapd.cxx b/tests/unit/linux/wpa-controller/TestWpaProtocolHostapd.cxx new file mode 100644 index 00000000..7cdeba1c --- /dev/null +++ b/tests/unit/linux/wpa-controller/TestWpaProtocolHostapd.cxx @@ -0,0 +1,15 @@ + +#include +#include + +TEST_CASE("Test WpaKeyManagement conversions", "[wpa][hostapd][client]") +{ + using namespace Wpa; + + SECTION("Conversion is stable") + { + for (auto wpaKeyManagement : AllWpaKeyManagementsValid) { + REQUIRE(WpaKeyManagementFromPropertyValue(WpaKeyManagementPropertyValue(wpaKeyManagement)) == wpaKeyManagement); + } + } +} From d42ea9ca988585bad581b296a54f518a4db8b1cc Mon Sep 17 00:00:00 2001 From: Andrew Beltrano Date: Wed, 3 Jul 2024 03:27:38 +0000 Subject: [PATCH 5/5] Add missing root annotation. --- tests/unit/linux/wpa-controller/TestWpaProtocolHostapd.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/linux/wpa-controller/TestWpaProtocolHostapd.cxx b/tests/unit/linux/wpa-controller/TestWpaProtocolHostapd.cxx index 7cdeba1c..6af6c77e 100644 --- a/tests/unit/linux/wpa-controller/TestWpaProtocolHostapd.cxx +++ b/tests/unit/linux/wpa-controller/TestWpaProtocolHostapd.cxx @@ -2,7 +2,7 @@ #include #include -TEST_CASE("Test WpaKeyManagement conversions", "[wpa][hostapd][client]") +TEST_CASE("Test WpaKeyManagement conversions (root)", "[wpa][hostapd][client]") { using namespace Wpa;