Skip to content

Commit

Permalink
Implement setting AKMs in hostapd and Ieee80211 layer.
Browse files Browse the repository at this point in the history
  • Loading branch information
abeltrano committed Mar 23, 2024
1 parent 3423dac commit d6cfc0c
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,15 @@ struct IAccessPointController
virtual AccessPointOperationStatus
SetAuthenticationAlgorithms(std::vector<Ieee80211AuthenticationAlgorithm> authenticationAlgorithms) noexcept = 0;

/**
* @brief Set the authentication and key management (akm) suites the access point should enable.
*
* @param akmSuites The akm suites to be allowed.
* @return AccessPointOperationStatus
*/
virtual AccessPointOperationStatus
SetAkmSuites(std::vector<Ieee80211AkmSuite> akmSuites) noexcept = 0;

/**
* @brief Set the pairwise cipher suites the access point should enable. These are used to encrypt unicast packets.
*
Expand Down
5 changes: 5 additions & 0 deletions src/common/wifi/core/include/microsoft/net/wifi/Ieee80211.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,15 @@ static constexpr uint8_t Ieee80211AkmSuiteIdFtFilsSha384 = 17;
static constexpr uint8_t Ieee80211AkmSuiteIdOwe = 18;
static constexpr uint8_t Ieee80211AkmSuiteIdFtPskSha384 = 19;
static constexpr uint8_t Ieee80211AkmSuiteIdPskSha384 = 20;
static constexpr uint8_t Ieee80211AkmSuiteIdPasn = 21;

/**
* @brief IEEE 802.11 Authentication and Key Management (AKM) Suites.
*
* Defined in IEEE 802.11-2020, Section 9.4.2.24.3, Table 9-151.
*/
enum class Ieee80211AkmSuite : uint32_t {
Unknown = MakeIeeeSuite(OuiInvalid, 0),
Reserved0 = MakeIeee80211Suite(Ieee80211AkmSuiteIdReserved0),
Ieee8021x = MakeIeee80211Suite(Ieee80211AkmSuiteId8021x),
Psk = MakeIeee80211Suite(Ieee80211AkmSuiteIdPsk),
Expand All @@ -207,13 +209,15 @@ enum class Ieee80211AkmSuite : uint32_t {
Owe = MakeIeee80211Suite(Ieee80211AkmSuiteIdOwe),
FtPskSha384 = MakeIeee80211Suite(Ieee80211AkmSuiteIdFtPskSha384),
PskSha384 = MakeIeee80211Suite(Ieee80211AkmSuiteIdPskSha384),
Pasn = MakeIeee80211Suite(Ieee80211AkmSuiteIdPasn),
};

/**
* @brief A listing of all known AKMs. Normally, these would be enumerated with magic_enum::enum_values(), however, that
* only supports enums with values up to UINT16_MAX-1, and the AKM suite underlying type is uint32_t, so cannot be used.
*/
constexpr std::initializer_list<uint32_t> AllIeee80211Akms{
std::to_underlying(Ieee80211AkmSuite::Unknown),
std::to_underlying(Ieee80211AkmSuite::Reserved0),
std::to_underlying(Ieee80211AkmSuite::Ieee8021x),
std::to_underlying(Ieee80211AkmSuite::Psk),
Expand All @@ -235,6 +239,7 @@ constexpr std::initializer_list<uint32_t> AllIeee80211Akms{
std::to_underlying(Ieee80211AkmSuite::Owe),
std::to_underlying(Ieee80211AkmSuite::FtPskSha384),
std::to_underlying(Ieee80211AkmSuite::PskSha384),
std::to_underlying(Ieee80211AkmSuite::Pasn),
};

/**
Expand Down
30 changes: 30 additions & 0 deletions src/linux/wifi/core/AccessPointControllerLinux.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ using namespace Microsoft::Net::Wifi;

using Microsoft::Net::Netlink::Nl80211::Nl80211Wiphy;
using Wpa::EnforceConfigurationChange;
using Wpa::HostapdException;

AccessPointControllerLinux::AccessPointControllerLinux(std::string_view interfaceName) :
AccessPointController(interfaceName),
Expand Down Expand Up @@ -269,6 +270,35 @@ AccessPointControllerLinux::SetAuthenticationAlgorithms(std::vector<Ieee80211Aut
return status;
}

AccessPointOperationStatus
AccessPointControllerLinux::SetAkmSuites(std::vector<Ieee80211AkmSuite> akmSuites) noexcept
{
AccessPointOperationStatus status{ GetInterfaceName() };
const AccessPointOperationStatusLogOnExit logStatusOnExit(&status);

// Ensure at least one akm suite is requested.
if (std::empty(akmSuites)) {
status.Code = AccessPointOperationStatusCode::InvalidParameter;
status.Details = "no akm suites specified";
return status;
}

std::vector<Wpa::WpaKeyManagement> wpaKeyManagements(std::size(akmSuites));
std::ranges::transform(akmSuites, std::begin(wpaKeyManagements), Ieee80211AkmSuiteToWpaKeyManagement);

try {
m_hostapd.SetKeyManagement(wpaKeyManagements, EnforceConfigurationChange::Now);
} catch (HostapdException& ex) {
status.Code = AccessPointOperationStatusCode::InternalError;
status.Details = std::format("failed to set akm suites - {}", ex.what());
return status;
}

status.Code = AccessPointOperationStatusCode::Succeeded;

return status;
}

AccessPointOperationStatus
AccessPointControllerLinux::SetPairwiseCipherSuites(std::unordered_map<Ieee80211SecurityProtocol, std::vector<Ieee80211CipherSuite>> pairwiseCipherSuites) noexcept
{
Expand Down
51 changes: 51 additions & 0 deletions src/linux/wifi/core/Ieee80211WpaAdapters.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,57 @@ Ieee80211SecurityProtocolToWpaSecurityProtocol(Ieee80211SecurityProtocol ieee802
}
}

Wpa::WpaKeyManagement
Ieee80211AkmSuiteToWpaKeyManagement(Ieee80211AkmSuite ieee80211AkmSuite) noexcept
{
switch (ieee80211AkmSuite) {
case Ieee80211AkmSuite::Ieee8021x:
return WpaKeyManagement::Ieee80211x;
case Ieee80211AkmSuite::Psk:
return WpaKeyManagement::Psk;
case Ieee80211AkmSuite::Ft8021x:
return WpaKeyManagement::FtIeee8021x;
case Ieee80211AkmSuite::FtPsk:
return WpaKeyManagement::FtPsk;
case Ieee80211AkmSuite::Ieee8021xSha256:
return WpaKeyManagement::Ieee8021xSha256;
case Ieee80211AkmSuite::PskSha256:
return WpaKeyManagement::PskSha256;
case Ieee80211AkmSuite::Sae:
return WpaKeyManagement::Sae;
case Ieee80211AkmSuite::FtSae:
return WpaKeyManagement::FtSae;
case Ieee80211AkmSuite::Ieee8021xSuiteB:
return WpaKeyManagement::Ieee80211xSuiteB;
case Ieee80211AkmSuite::Ieee8011xSuiteB192:
return WpaKeyManagement::Ieee80211xSuiteB192;
case Ieee80211AkmSuite::Ft8021xSha384:
return WpaKeyManagement::FtIeee8021xSha384;
case Ieee80211AkmSuite::FilsSha256:
return WpaKeyManagement::FilsSha256;
case Ieee80211AkmSuite::FilsSha384:
return WpaKeyManagement::FilsSha384;
case Ieee80211AkmSuite::FtFilsSha256:
return WpaKeyManagement::FtFilsSha256;
case Ieee80211AkmSuite::FtFilsSha384:
return WpaKeyManagement::FilsSha384;
case Ieee80211AkmSuite::Owe:
return WpaKeyManagement::Owe;
case Ieee80211AkmSuite::Reserved0:
[[fallthrough]];
case Ieee80211AkmSuite::Tdls:
[[fallthrough]];
case Ieee80211AkmSuite::ApPeerKey:
[[fallthrough]];
case Ieee80211AkmSuite::FtPskSha384:
[[fallthrough]];
case Ieee80211AkmSuite::PskSha384:
[[fallthrough]];
default:
return WpaKeyManagement::Unknown;
}
}

WpaCipher
Ieee80211CipherSuiteToWpaCipher(Ieee80211CipherSuite ieee80211CipherSuite) noexcept
{
Expand Down
21 changes: 15 additions & 6 deletions src/linux/wifi/core/Ieee80211WpaAdapters.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -49,27 +49,36 @@ Ieee80211AuthenticationAlgorithmToWpaAuthenticationAlgorithm(Ieee80211Authentica

/**
* @brief Convert a Ieee80211SecurityProtocol to a WpaSecurityProtocol.
*
*
* @param ieee80211SecurityProtocol The Ieee80211SecurityProtocol to convert.
* @return Wpa::WpaSecurityProtocol
* @return Wpa::WpaSecurityProtocol
*/
Wpa::WpaSecurityProtocol
Ieee80211SecurityProtocolToWpaSecurityProtocol(Ieee80211SecurityProtocol ieee80211SecurityProtocol) noexcept;

/**
* @brief Convert a Ieee80211AkmSuite to a WpaKeyManagement.
*
* @param ieee80211AkmSuite The Ieee80211AkmSuite to convert.
* @return Wpa::WpaKeyManagement
*/
Wpa::WpaKeyManagement
Ieee80211AkmSuiteToWpaKeyManagement(Ieee80211AkmSuite ieee80211AkmSuite) noexcept;

/**
* @brief Convert a Ieee80211CipherSuite to a WpaCipher.
*
*
* @param ieee80211CipherSuite The Ieee80211CipherSuite to convert.
* @return Wpa::WpaCipher
* @return Wpa::WpaCipher
*/
Wpa::WpaCipher
Ieee80211CipherSuiteToWpaCipher(Ieee80211CipherSuite ieee80211CipherSuite) noexcept;

/**
* @brief Convert a map of Ieee80211SecurityProtocol to list of Ieee80211CipherSuite to a map of WpaSecurityProtocol to list of WpaCipher.
*
*
* @param ieee80211CipherSuiteConfigurations The map of Ieee80211SecurityProtocol to list of Ieee80211CipherSuite to convert.
* @return std::unordered_map<Wpa::WpaSecurityProtocol, std::vector<Wpa::WpaCipher>>
* @return std::unordered_map<Wpa::WpaSecurityProtocol, std::vector<Wpa::WpaCipher>>
*/
std::unordered_map<Wpa::WpaSecurityProtocol, std::vector<Wpa::WpaCipher>>
Ieee80211CipherSuitesToWpaCipherSuites(const std::unordered_map<Ieee80211SecurityProtocol, std::vector<Ieee80211CipherSuite>>& ieee80211CipherSuiteConfigurations) noexcept;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,15 @@ struct AccessPointControllerLinux :
AccessPointOperationStatus
SetAuthenticationAlgorithms(std::vector<Ieee80211AuthenticationAlgorithm> authenticationAlgorithms) noexcept override;

/**
* @brief Set the authentication and key management (akm) suites the access point should enable.
*
* @param akmSuites The akm suites to be allowed.
* @return AccessPointOperationStatus
*/
AccessPointOperationStatus
SetAkmSuites(std::vector<Ieee80211AkmSuite> akmSuites) noexcept override;

/**
* @brief Set the pairwise cipher suites the access point should enable. These are used to encrypt unicast packets.
*
Expand Down
6 changes: 4 additions & 2 deletions src/linux/wpa-controller/include/Wpa/ProtocolHostapd.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ enum class WpaAlgorithm : uint32_t {
* Values obtained from hostap/src/common/defs.h.
*/
enum class WpaKeyManagement : uint32_t {
Unknown = 0U,
Ieee80211x = (1U << 0U),
Psk = (1U << 1U),
None = (1U << 2U),
Expand Down Expand Up @@ -266,7 +267,8 @@ enum class WpaKeyManagement : uint32_t {
*
* 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, 26> AllWpaKeyManagements = {
inline constexpr std::array<WpaKeyManagement, 27> AllWpaKeyManagements = {
WpaKeyManagement::Unknown,
WpaKeyManagement::Ieee80211x,
WpaKeyManagement::Psk,
WpaKeyManagement::None,
Expand Down Expand Up @@ -670,7 +672,7 @@ WpaCipherPropertyName(WpaSecurityProtocol WpaSecurityProtocol) noexcept
case WpaSecurityProtocol::Wpa:
return ProtocolHostapd::PropertyNameWpaPairwise;
case WpaSecurityProtocol::Wpa2:
// case WpaSecurityProtocol::Wpa3: // duplicate case value not allowed
// case WpaSecurityProtocol::Wpa3: // duplicate case value not allowed
return ProtocolHostapd::PropertyNameRsnPairwise;
default:
return ProtocolHostapd::PropertyNameInvalid;
Expand Down
15 changes: 14 additions & 1 deletion tests/unit/wifi/helpers/AccessPointControllerTest.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ AccessPointControllerTest::SetFrequencyBands(std::vector<Ieee80211FrequencyBand>
}

AccessPointOperationStatus
AccessPointControllerTest::SetAuthenticationAlgorithms([[maybe_unused]] std::vector<Ieee80211AuthenticationAlgorithm> authenticationAlgorithms) noexcept
AccessPointControllerTest::SetAuthenticationAlgorithms(std::vector<Ieee80211AuthenticationAlgorithm> authenticationAlgorithms) noexcept
{
assert(AccessPoint != nullptr);

Expand All @@ -125,6 +125,19 @@ AccessPointControllerTest::SetAuthenticationAlgorithms([[maybe_unused]] std::vec
return AccessPointOperationStatus::MakeSucceeded(AccessPoint->InterfaceName);
}

AccessPointOperationStatus
AccessPointControllerTest::SetAkmSuites(std::vector<Ieee80211AkmSuite> akmSuites) noexcept
{
assert(AccessPoint != nullptr);

if (AccessPoint == nullptr) {
return AccessPointOperationStatus::InvalidAccessPoint("null AccessPoint");
}

AccessPoint->AkmSuites = std::move(akmSuites);
return AccessPointOperationStatus::MakeSucceeded(AccessPoint->InterfaceName);
}

AccessPointOperationStatus
AccessPointControllerTest::SetPairwiseCipherSuites(std::unordered_map<Ieee80211SecurityProtocol, std::vector<Ieee80211CipherSuite>> pairwiseCipherSuites) noexcept
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,15 @@ struct AccessPointControllerTest final :
AccessPointOperationStatus
SetAuthenticationAlgorithms(std::vector<Ieee80211AuthenticationAlgorithm> authenticationAlgorithms) noexcept override;

/**
* @brief Set the authentication and key management (akm) suites the access point should enable.
*
* @param akmSuites The akm suites to be allowed.
* @return AccessPointOperationStatus
*/
AccessPointOperationStatus
SetAkmSuites(std::vector<Ieee80211AkmSuite> akmSuites) noexcept override;

/**
* @brief Set the pairwise cipher suites the access point should enable. These are used to encrypt unicast packets.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct AccessPointTest final :
Microsoft::Net::Wifi::Ieee80211PhyType PhyType{ Microsoft::Net::Wifi::Ieee80211PhyType::Unknown };
std::vector<Microsoft::Net::Wifi::Ieee80211FrequencyBand> FrequencyBands;
std::vector<Microsoft::Net::Wifi::Ieee80211AuthenticationAlgorithm> AuthenticationAlgorithms;
std::vector<Microsoft::Net::Wifi::Ieee80211AkmSuite> AkmSuites;
std::unordered_map<Ieee80211SecurityProtocol, std::vector<Ieee80211CipherSuite>> CipherSuites;
AccessPointOperationalState OperationalState{ AccessPointOperationalState::Disabled };

Expand Down

0 comments on commit d6cfc0c

Please sign in to comment.