Skip to content

Commit 9cb5555

Browse files
authored
Merge pull request #249 from microsoft/authdatasaeopts
Accept SAE password ids and peer mac addresses in CLI
2 parents b02cc07 + 8c104d0 commit 9cb5555

File tree

14 files changed

+233
-26
lines changed

14 files changed

+233
-26
lines changed

src/common/service/NetRemoteService.cxx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,12 @@ NetRemoteService::WifiAccessPointSetAuthenticationDataImpl(std::string_view acce
751751
wifiOperationStatus.set_message("No PSK passphrase provided (empty)");
752752
return wifiOperationStatus;
753753
}
754+
const auto pskPassphraseSize = std::size(pskPassphrase);
755+
if (pskPassphraseSize < Ieee80211RsnaPskPassphraseLengthMinimum || pskPassphraseSize > Ieee80211RsnaPskPassphraseLengthMaximum) {
756+
wifiOperationStatus.set_code(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeInvalidParameter);
757+
wifiOperationStatus.set_message(std::format("Invalid PSK passphrase size '{}' provided (expected {} to {} characters)", pskPassphraseSize, Ieee80211RsnaPskPassphraseLengthMinimum, Ieee80211RsnaPskPassphraseLengthMaximum));
758+
return wifiOperationStatus;
759+
}
754760
} else if (psk.has_value()) {
755761
const auto& pskValue = psk.value();
756762
if (!pskValue.has_hex() && !pskValue.has_raw()) {
@@ -769,7 +775,7 @@ NetRemoteService::WifiAccessPointSetAuthenticationDataImpl(std::string_view acce
769775
const auto& pskRaw = pskValue.raw();
770776
if (std::size(pskRaw) != Ieee80211RsnaPskLength) {
771777
wifiOperationStatus.set_code(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeInvalidParameter);
772-
wifiOperationStatus.set_message(std::format("Invalid PSK raw value provided (not {} bytes)", Ieee80211RsnaPskLength));
778+
wifiOperationStatus.set_message(std::format("Invalid PSK raw value size '{}' provided (expected {} bytes)", std::size(pskRaw), Ieee80211RsnaPskLength));
773779
return wifiOperationStatus;
774780
}
775781
}

src/common/shared/strings/CMakeLists.txt

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,22 @@
22
add_library(strings INTERFACE)
33

44
set(STRINGS_PUBLIC_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/include)
5-
set(STRINGS_PUBLIC_INCLUDE_PREFIX ${STRINGS_PUBLIC_INCLUDE}/strings)
5+
set(STRINGS_PUBLIC_INCLUDE_SUFFIX strings)
6+
set(STRINGS_PUBLIC_INCLUDE_PREFIX ${STRINGS_PUBLIC_INCLUDE}/${STRINGS_PUBLIC_INCLUDE_SUFFIX})
67

78
target_sources(strings
89
PUBLIC
10+
FILE_SET HEADERS
11+
BASE_DIRS ${STRINGS_PUBLIC_INCLUDE}
12+
FILES
913
${STRINGS_PUBLIC_INCLUDE_PREFIX}/StringHelpers.hxx
14+
${STRINGS_PUBLIC_INCLUDE_PREFIX}/StringParsing.hxx
1015
)
1116

12-
list(APPEND STRINGS_PUBLIC_HEADERS
13-
${STRINGS_PUBLIC_INCLUDE_PREFIX}/StringHelpers.hxx
14-
)
15-
16-
set_target_properties(strings PROPERTIES
17-
PUBLIC_HEADER "${STRINGS_PUBLIC_HEADERS}"
18-
INTERFACE_INCLUDE_DIRECTORIES "${STRINGS_PUBLIC_INCLUDE}"
17+
install(
18+
TARGETS strings
19+
EXPORT ${PROJECT_NAME}
20+
COMPONENT dev
21+
FILE_SET HEADERS
22+
PUBLIC_HEADER DESTINATION "${NETREMOTE_DIR_INSTALL_PUBLIC_HEADER_BASE}/${STRINGS_PUBLIC_INCLUDE_SUFFIX}"
1923
)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
2+
#ifndef STRING_PARSING_HXX
3+
#define STRING_PARSING_HXX
4+
5+
#include <charconv>
6+
#include <concepts>
7+
#include <cstdint>
8+
#include <cstdlib>
9+
#include <ranges>
10+
#include <string>
11+
#include <tuple>
12+
13+
namespace Strings
14+
{
15+
/**
16+
* @brief Parse a hex string into a container of bytes.
17+
*
18+
* @tparam ContainerT The container type to store the parsed bytes.
19+
* @param hexString The hex string to parse.
20+
* @param result The container to store the parsed bytes.
21+
* @param numberOfBytesToParse The number of bytes to parse from the hex string.
22+
* @return true If a valid hex string was parsed into the container.
23+
* @return false If the hex string was invalid or the container was too small to store the parsed bytes.
24+
*/
25+
// clang-format off
26+
template <std::ranges::range ContainerT>
27+
requires std::same_as<std::ranges::range_value_t<ContainerT>, std::uint8_t>
28+
// clang-format on
29+
bool
30+
ParseHexString(const std::string& hexString, ContainerT& result, std::size_t numberOfBytesToParse = std::tuple_size_v<ContainerT>)
31+
{
32+
// Ensure the input has enough characters to parse the requested number of bytes.
33+
if (std::size(hexString) / 2 < numberOfBytesToParse) {
34+
return false;
35+
}
36+
37+
std::string_view hexStringView{ hexString };
38+
for (std::size_t i = 0; i < std::size(result); i++) {
39+
const auto byteAsHex = hexStringView.substr(i * 2, 2); // 2 hex chars
40+
const auto byteConversionResult = std::from_chars(std::data(byteAsHex), std::data(byteAsHex) + std::size(byteAsHex), result[i], 16);
41+
if (byteConversionResult.ec != std::errc{}) {
42+
return false;
43+
}
44+
}
45+
46+
return true;
47+
}
48+
} // namespace Strings
49+
50+
#endif // STRING_PARSING_HXX

src/common/tools/cli/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ target_link_libraries(${PROJECT_NAME}-cli
2727
magic_enum::magic_enum
2828
notstd
2929
plog::plog
30+
strings
3031
PUBLIC
3132
${PROJECT_NAME}-client
3233
wifi-core

src/common/tools/cli/NetRemoteCli.cxx

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
#include <format>
3+
#include <iostream>
34
#include <map>
45
#include <memory>
56
#include <stdexcept>
@@ -20,6 +21,7 @@
2021
#include <microsoft/net/wifi/Ieee80211AccessPointConfiguration.hxx>
2122
#include <notstd/Memory.hxx>
2223
#include <plog/Log.h>
24+
#include <strings/StringParsing.hxx>
2325

2426
using namespace Microsoft::Net::Remote;
2527
using namespace Microsoft::Net::Wifi;
@@ -118,12 +120,22 @@ NetRemoteCli::AddSubcommandWifiAccessPointsEnumerate(CLI::App* parent)
118120

119121
namespace detail
120122
{
123+
/**
124+
* @brief Thin wrapper to destructure the std::tuple used to parse SAE passwords.
125+
*
126+
* @param saePasswordArgument The tuple containing the SAE password, password ID, and peer MAC address.
127+
* @return Ieee80211RsnaPassword
128+
*/
121129
Ieee80211RsnaPassword
122-
ParseSaePasswordCliArgument(const std::string& saePasswordArg)
130+
ParseSaePasswordCliArgument(std::tuple<std::string, std::optional<std::string>, std::optional<std::string>>& saePasswordArgument)
123131
{
124-
Ieee80211RsnaPassword saePassword{};
125-
// TODO: parse optional password id and peer mac address fields.
126-
saePassword.Credential = saePasswordArg;
132+
const auto& [password, passwordId, peerMacAddress] = saePasswordArgument; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)
133+
134+
Ieee80211RsnaPassword saePassword{
135+
.Credential = std::move(password),
136+
.PasswordId = std::move(passwordId),
137+
.PeerMacAddress = peerMacAddress.and_then(Ieee80211MacAddressFromString)
138+
};
127139

128140
return saePassword;
129141
}
@@ -138,6 +150,14 @@ NetRemoteCli::WifiAccessPointEnableCallback()
138150
auto& psk = ieee80211AccessPointConfiguration.AuthenticationData.Psk.emplace();
139151
psk.Psk = m_cliData->WifiAccessPointPskPassphrase;
140152
}
153+
if (!std::empty(m_cliData->WifiAccessPointPskHex)) {
154+
auto& psk = ieee80211AccessPointConfiguration.AuthenticationData.Psk.emplace();
155+
auto& pskValue = psk.Psk.emplace<Ieee80211RsnaPskValue>();
156+
if (!Strings::ParseHexString(m_cliData->WifiAccessPointPskHex, pskValue)) {
157+
std::cerr << "Failed to parse PSK value (must be 64 hex characters)" << std::endl;
158+
return;
159+
}
160+
}
141161

142162
if (!std::empty(m_cliData->WifiAccessPointSaePasswords)) {
143163
auto& sae = ieee80211AccessPointConfiguration.AuthenticationData.Sae.emplace();
@@ -274,8 +294,9 @@ NetRemoteCli::AddSubcommandWifiAccessPointEnable(CLI::App* parent)
274294
->transform(CLI::CheckedTransformer(detail::Ieee80211AuthenticationAlgorithmNames(), CLI::ignore_case));
275295
cliAppWifiAccessPointEnable->add_option("--akm,--akms,--akmSuite,--akmSuites,--keyManagement,--keyManagements", m_cliData->WifiAccessPointAkmSuites, "The AKM suites of the access point to enable")
276296
->transform(CLI::CheckedTransformer(detail::Ieee80211AkmSuiteNames(), CLI::ignore_case));
277-
cliAppWifiAccessPointEnable->add_option("--passphrase,--pskPassphrase", m_cliData->WifiAccessPointPskPassphrase, "The PSK passphrase of the access point to enable");
278-
cliAppWifiAccessPointEnable->add_option("--sae,--password,--passwords,--saePassword,--saePasswords", m_cliData->WifiAccessPointSaePasswords, "The SAE passwords of the access point to enable");
297+
cliAppWifiAccessPointEnable->add_option("--psk", m_cliData->WifiAccessPointPskHex, "The PSK of the access point to enable");
298+
cliAppWifiAccessPointEnable->add_option("--passphrase,--pskPassphrase", m_cliData->WifiAccessPointPskPassphrase, "The PSK passphrase of the access point to enable")->excludes("--psk");
299+
cliAppWifiAccessPointEnable->add_option("--sae,--password,--passwords,--saePassword,--saePasswords", m_cliData->WifiAccessPointSaePasswords, "The SAE passwords of the access point to enable")->type_size(1, 3);
279300
cliAppWifiAccessPointEnable->callback([this] {
280301
WifiAccessPointEnableCallback();
281302
});

src/common/tools/cli/include/microsoft/net/remote/NetRemoteCliData.hxx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include <optional>
66
#include <string>
7+
#include <tuple>
78
#include <vector>
89

910
#include <microsoft/net/remote/protocol/NetRemoteProtocol.hxx>
@@ -26,7 +27,8 @@ struct NetRemoteCliData
2627
std::string WifiAccessPointId{};
2728
std::string WifiAccessPointSsid{};
2829
std::string WifiAccessPointPskPassphrase;
29-
std::vector<std::string> WifiAccessPointSaePasswords{};
30+
std::string WifiAccessPointPskHex;
31+
std::vector<std::tuple<std::string, std::optional<std::string>, std::optional<std::string>>> WifiAccessPointSaePasswords{};
3032
std::vector<Microsoft::Net::Wifi::Ieee80211FrequencyBand> WifiAccessPointFrequencyBands{};
3133
std::vector<Microsoft::Net::Wifi::Ieee80211AuthenticationAlgorithm> WifiAccessPointAuthenticationAlgorithms{};
3234
std::vector<Microsoft::Net::Wifi::Ieee80211AkmSuite> WifiAccessPointAkmSuites{};

src/common/wifi/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ target_link_libraries(wifi-core
3434
PRIVATE
3535
magic_enum::magic_enum
3636
notstd
37+
strings
3738
PUBLIC
3839
plog::plog
3940
)

src/common/wifi/core/Ieee80211.cxx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11

2+
#include <algorithm>
3+
#include <charconv>
24
#include <format>
5+
#include <optional>
36
#include <string>
7+
#include <string_view>
48

59
#include <microsoft/net/wifi/Ieee80211.hxx>
10+
#include <strings/StringParsing.hxx>
611

712
namespace Microsoft::Net::Wifi
813
{
@@ -11,4 +16,24 @@ Ieee80211MacAddressToString(const Ieee80211MacAddress& macAddress)
1116
{
1217
return std::format("{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", macAddress[0], macAddress[1], macAddress[2], macAddress[3], macAddress[4], macAddress[5]);
1318
}
19+
20+
std::optional<Ieee80211MacAddress>
21+
Ieee80211MacAddressFromString(std::string macAddress)
22+
{
23+
constexpr auto isDelimeter = [](const char c) {
24+
return c == ':' || c == '-';
25+
};
26+
27+
const auto eraseRange = std::ranges::remove_if(macAddress, isDelimeter);
28+
if (!std::empty(eraseRange)) {
29+
macAddress.erase(std::begin(eraseRange), std::end(eraseRange));
30+
}
31+
32+
Ieee80211MacAddress result{};
33+
if (!Strings::ParseHexString(macAddress, result)) {
34+
return std::nullopt;
35+
}
36+
37+
return result;
38+
}
1439
} // namespace Microsoft::Net::Wifi

src/common/wifi/core/include/microsoft/net/wifi/Ieee80211.hxx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <cmath>
77
#include <cstdint>
88
#include <initializer_list>
9+
#include <optional>
910
#include <string>
1011
#include <utility>
1112

@@ -423,6 +424,15 @@ using Ieee80211MacAddress = std::array<uint8_t, MacAddressNumOctets>;
423424
std::string
424425
Ieee80211MacAddressToString(const Ieee80211MacAddress& macAddress);
425426

427+
/**
428+
* @brief Parse a string into a MAC address.
429+
*
430+
* @param macAddress The MAC address string to parse.
431+
* @return std::optional<Ieee80211MacAddress>
432+
*/
433+
std::optional<Ieee80211MacAddress>
434+
Ieee80211MacAddressFromString(std::string macAddress);
435+
426436
/**
427437
* @brief Information about a BSS.
428438
*/

src/common/wifi/core/include/microsoft/net/wifi/Ieee80211Authentication.hxx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ using Ieee80211RsnaPskVariant = std::variant<Ieee80211RsnaPskPassphrase, Ieee802
2626
* @brief Encoding of a pre-shared key.
2727
*/
2828
enum class Ieee80211RsnaPskEncoding {
29+
Invalid,
2930
Passphrase,
3031
Value,
3132
};
@@ -50,9 +51,13 @@ struct Ieee80211RsnaPsk :
5051
constexpr Ieee80211RsnaPskEncoding
5152
Encoding() const noexcept
5253
{
54+
// clang-format off
5355
return std::holds_alternative<Ieee80211RsnaPskPassphrase>(*this)
5456
? Ieee80211RsnaPskEncoding::Passphrase
55-
: Ieee80211RsnaPskEncoding::Value;
57+
: std::holds_alternative<Ieee80211RsnaPskValue>(*this)
58+
? Ieee80211RsnaPskEncoding::Value
59+
: Ieee80211RsnaPskEncoding::Invalid;
60+
// clang-format on
5661
}
5762

5863
/**

0 commit comments

Comments
 (0)