Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-factor WpaKeyManagement conversion helpers #309

Merged
merged 5 commits into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/common/shared/strings/include/strings/StringHelpers.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -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
103 changes: 59 additions & 44 deletions src/linux/wpa-controller/ProtocolHostapd.cxx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@

#include <iterator>
#include <ranges>
#include <sstream>
#include <string>
#include <string_view>
#include <utility>
#include <variant>

#include <Wpa/ProtocolHostapd.hxx>
#include <strings/StringHelpers.hxx>

using namespace Wpa;

Expand Down Expand Up @@ -87,54 +90,66 @@ Wpa::WpaPreSharedKeyPropertyKeyAndValue(const WpaPreSharedKey& wpaPreSharedKey)
return std::make_pair(propertyName, std::move(propertyValue));
}

std::vector<WpaKeyManagement>
WpaKeyManagement
Wpa::WpaKeyManagementFromPropertyValue(std::string_view wpaKeyManagementProperty) noexcept
{
std::string wpaKeyManagementString(wpaKeyManagementProperty);
std::istringstream wpaKeyManagementStream(wpaKeyManagementString);
std::vector<WpaKeyManagement> 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<WpaKeyManagement>
Wpa::WpaKeyManagementsFromPropertyValue(std::string_view wpaKeyManagementProperty) noexcept
{
auto wpaKeyManagementStrings = std::views::split(wpaKeyManagementProperty, ' ') | std::views::transform(Strings::ToStringView) | std::views::transform(WpaKeyManagementFromPropertyValue);

std::vector<WpaKeyManagement> wpaKeyManagements{
std::make_move_iterator(std::begin(wpaKeyManagementStrings)),
std::make_move_iterator(std::end(wpaKeyManagementStrings))
};

return wpaKeyManagements;
}
2 changes: 1 addition & 1 deletion src/linux/wpa-controller/WpaCommandGetConfig.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ WpaGetConfigResponseParser::ParsePayload()
ParseInt(value, wpa);
configuration.Wpa = static_cast<Wpa::WpaSecurityProtocol>(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) {
Expand Down
9 changes: 3 additions & 6 deletions src/linux/wpa-controller/WpaResponseParser.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <Wpa/WpaResponse.hxx>
#include <Wpa/WpaResponseParser.hxx>
#include <plog/Log.h>
#include <strings/StringHelpers.hxx>

using namespace Wpa;

Expand Down Expand Up @@ -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;
Expand All @@ -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)) {
Expand Down
39 changes: 38 additions & 1 deletion src/linux/wpa-controller/include/Wpa/ProtocolHostapd.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,34 @@ inline constexpr std::array<WpaKeyManagement, 27> 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<WpaKeyManagement, 20> 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).
*/
Expand Down Expand Up @@ -830,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".
Expand All @@ -838,7 +875,7 @@ WpaKeyManagementPropertyValue(WpaKeyManagement wpaKeyManagement) noexcept
* @return std::vector<WpaKeyManagement> The corresponding WpaKeyManagement values.
*/
std::vector<WpaKeyManagement>
WpaKeyManagementFromPropertyValue(std::string_view wpaKeyManagementProperty) noexcept;
WpaKeyManagementsFromPropertyValue(std::string_view wpaKeyManagementProperty) noexcept;

/**
* @brief WpaCipher sentinel for an invalid value.
Expand Down
1 change: 1 addition & 0 deletions tests/unit/linux/wpa-controller/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 15 additions & 0 deletions tests/unit/linux/wpa-controller/TestWpaProtocolHostapd.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

#include <Wpa/ProtocolHostapd.hxx>
#include <catch2/catch_test_macros.hpp>

TEST_CASE("Test WpaKeyManagement conversions (root)", "[wpa][hostapd][client]")
{
using namespace Wpa;

SECTION("Conversion is stable")
{
for (auto wpaKeyManagement : AllWpaKeyManagementsValid) {
REQUIRE(WpaKeyManagementFromPropertyValue(WpaKeyManagementPropertyValue(wpaKeyManagement)) == wpaKeyManagement);
}
}
}