Skip to content

Commit

Permalink
hostap: add WPA2 EAP_TLS support
Browse files Browse the repository at this point in the history
Add basic wpa2 EAP_TLS support.
Support set CA/client cert and client key.

Signed-off-by: Maochen Wang <maochen.wang@nxp.com>
  • Loading branch information
MaochenWang1 committed Jul 30, 2024
1 parent 81ea7eb commit de335e3
Show file tree
Hide file tree
Showing 17 changed files with 1,220 additions and 5 deletions.
33 changes: 33 additions & 0 deletions doc/connectivity/networking/api/wifi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,36 @@ API Reference
*************

.. doxygengroup:: wifi_mgmt

.. _wifi_shell_test_certs:
X.509 Certificate header generation
###################################

Wi-Fi enterprise security requires use of X.509 certificates, test certificates
in PEM format are committed to the repo and the below steps to be followed to convert
them to C header file that can be included in Wi-Fi shell module.

Convert CA format from PEM to DER
=================================
To convert the CA format from PEM to DER, use the following command:
.. code-block:: none
openssl x509 -outform der -in cas.pem -out ca.der

Convert RSA Key format to DER
=============================
To convert the RSA Key format to DER, use the following command:
.. code-block:: none
openssl rsa -in wifiuser.key -outform DER -out client_key.der

Convert .der to header file
===========================
To convert the .der file to a header file, use the following command:
.. code-block:: none
xxd -i ca.der > ca.h

Replace corresponding cert header files
=======================================
Replace the corresponding cert header files at the following path:
subsys/net/l2/wifi/test_certs/

.. note:: Please ensure that the parameter names are the same.
4 changes: 4 additions & 0 deletions include/zephyr/net/wifi.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ const char *wifi_band_txt(enum wifi_frequency_bands band);
#define WIFI_SAE_PSWD_MAX_LEN 128
/** MAC address length */
#define WIFI_MAC_ADDR_LEN 6
/** Max enterprise identity length */
#define WIFI_ENT_IDENTITY_MAX_LEN 64
/** Max enterprise password length */
#define WIFI_ENT_PSWD_MAX_LEN 128

/** Minimum channel number */
#define WIFI_CHANNEL_MIN 1
Expand Down
41 changes: 41 additions & 0 deletions include/zephyr/net/wifi_mgmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ enum net_request_wifi_cmd {
NET_REQUEST_WIFI_CMD_AP_CONFIG_PARAM,
/** Flush PMKSA cache entries */
NET_REQUEST_WIFI_CMD_PMKSA_FLUSH,
/** Set enterprise mode credential */
NET_REQUEST_WIFI_CMD_ENTERPRISE_CREDS,
/** @cond INTERNAL_HIDDEN */
NET_REQUEST_WIFI_CMD_MAX
/** @endcond */
Expand Down Expand Up @@ -214,6 +216,12 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_CONFIG_PARAM);

NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_PMKSA_FLUSH);

/** Set Wi-Fi enterprise mode CA/client Cert and key */
#define NET_REQUEST_WIFI_ENTERPRISE_CREDS \
(_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_ENTERPRISE_CREDS)

NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_ENTERPRISE_CREDS);

/** @brief Wi-Fi management events */
enum net_event_wifi_cmd {
/** Scan results available */
Expand Down Expand Up @@ -418,6 +426,14 @@ struct wifi_connect_req_params {
uint8_t bssid[WIFI_MAC_ADDR_LEN];
/** Connect timeout in seconds, SYS_FOREVER_MS for no timeout */
int timeout;
/** anonymous identity */
const uint8_t *anon_id;
/** anon_id length */
uint8_t aid_length; /* Max 64 */
/** Private key passwd for enterprise mode */
const uint8_t *key_passwd;
/** Private key passwd length */
uint8_t key_passwd_length; /* Max 128 */
};

/** @brief Wi-Fi connect result codes. To be overlaid on top of \ref wifi_status
Expand Down Expand Up @@ -639,6 +655,22 @@ struct wifi_twt_flow_info {
uint32_t twt_wake_ahead_duration;
};

/** Wi-Fi enterprise mode credentials */
struct wifi_enterprise_creds_params {
/** CA certification */
uint8_t *ca_cert;
/** CA certification length */
uint32_t ca_cert_len;
/** Client certification */
uint8_t *client_cert;
/** Client certification length */
uint32_t client_cert_len;
/** Client key */
uint8_t *client_key;
/** Client key length */
uint32_t client_key_len;
};

/** @brief Wi-Fi power save configuration */
struct wifi_ps_config {
/** Number of TWT flows */
Expand Down Expand Up @@ -980,6 +1012,15 @@ struct wifi_mgmt_ops {
* @return 0 if ok, < 0 if error
*/
int (*pmksa_flush)(const struct device *dev);
/** Set Wi-Fi enterprise mode CA/client Cert and key
*
* @param dev Pointer to the device structure for the driver instance.
* @param creds Pointer to the CA/client Cert and key.
*
* @return 0 if ok, < 0 if error
*/
int (*enterprise_creds)(const struct device *dev,
struct wifi_enterprise_creds_params *creds);
};

/** Wi-Fi management offload API */
Expand Down
119 changes: 119 additions & 0 deletions modules/hostap/src/supp_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ enum status_thread_state {

#define DISCONNECT_TIMEOUT_MS 5000

#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE
static struct wifi_enterprise_creds_params enterprise_creds;
#endif

K_MUTEX_DEFINE(wpa_supplicant_mutex);

extern struct k_work_q *get_workq(void);
Expand Down Expand Up @@ -323,6 +327,61 @@ static inline enum wifi_security_type wpas_key_mgmt_to_zephyr(int key_mgmt, int
}
}

#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE
int supplicant_add_enterprise_creds(const struct device *dev,
struct wifi_enterprise_creds_params *creds)
{
int ret = 0;

if (!creds) {
ret = -1;
wpa_printf(MSG_ERROR, "enterprise creds is NULL");
goto out;
}

memcpy((void *)&enterprise_creds, (void *)creds,
sizeof(struct wifi_enterprise_creds_params));

out:
return ret;
}

static int wpas_config_process_blob(struct wpa_config *config, char *name, uint8_t *data,
uint32_t data_len)
{
struct wpa_config_blob *blob;

if (!data || !data_len) {
return -1;
}

blob = os_zalloc(sizeof(*blob));
if (blob == NULL) {
return -1;
}

blob->data = os_zalloc(data_len);
if (blob->data == NULL) {
os_free(blob);
return -1;
}

blob->name = os_strdup(name);

if (blob->name == NULL) {
wpa_config_free_blob(blob);
return -1;
}

os_memcpy(blob->data, data, data_len);
blob->len = data_len;

wpa_config_set_blob(config, blob);

return 0;
}
#endif

static int wpas_add_and_config_network(struct wpa_supplicant *wpa_s,
struct wifi_connect_req_params *params,
bool mode_ap)
Expand Down Expand Up @@ -445,6 +504,66 @@ static int wpas_add_and_config_network(struct wpa_supplicant *wpa_s,
goto out;
}
}
#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE
} else if (params->security == WIFI_SECURITY_TYPE_EAP_TLS) {
if (!wpa_cli_cmd_v("set_network %d key_mgmt WPA-EAP",
resp.network_id)) {
goto out;
}

if (!wpa_cli_cmd_v("set_network %d proto RSN",
resp.network_id)) {
goto out;
}

if (!wpa_cli_cmd_v("set_network %d eap TLS",
resp.network_id)) {
goto out;
}

if (!wpa_cli_cmd_v("set_network %d anonymous_identity \"%s\"",
resp.network_id, params->anon_id)) {
goto out;
}

if (wpas_config_process_blob(wpa_s->conf, "ca_cert",
enterprise_creds.ca_cert,
enterprise_creds.ca_cert_len)) {
goto out;
}

if (!wpa_cli_cmd_v("set_network %d ca_cert \"blob://ca_cert\"",
resp.network_id)) {
goto out;
}

if (wpas_config_process_blob(wpa_s->conf, "client_cert",
enterprise_creds.client_cert,
enterprise_creds.client_cert_len)) {
goto out;
}

if (!wpa_cli_cmd_v("set_network %d client_cert \"blob://client_cert\"",
resp.network_id)) {
goto out;
}

if (wpas_config_process_blob(wpa_s->conf, "private_key",
enterprise_creds.client_key,
enterprise_creds.client_key_len)) {
goto out;
}

if (!wpa_cli_cmd_v("set_network %d private_key \"blob://private_key\"",
resp.network_id)) {
goto out;
}

if (!wpa_cli_cmd_v("set_network %d private_key_passwd \"%s\"",
resp.network_id, params->key_passwd)) {
goto out;
}
#endif
} else {
ret = -1;
wpa_printf(MSG_ERROR, "Unsupported security type: %d",
Expand Down
12 changes: 12 additions & 0 deletions modules/hostap/src/supp_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,18 @@ int supplicant_reg_domain(const struct device *dev, struct wifi_reg_domain *reg_
*/
int supplicant_mode(const struct device *dev, struct wifi_mode_info *mode);

#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE
/** Set Wi-Fi enterprise mode CA/client Cert and key
*
* @param dev Pointer to the device structure for the driver instance
* @param file Pointer to the CA/client Cert and key.
*
* @return 0 if ok, < 0 if error
*/
int supplicant_add_enterprise_creds(const struct device *dev,
struct wifi_enterprise_creds_params *creds);
#endif

/**
* @brief Set Wi-Fi packet filter for sniffing operation
*
Expand Down
1 change: 1 addition & 0 deletions modules/hostap/src/supp_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ static const struct wifi_mgmt_ops mgmt_ops = {
.ap_sta_disconnect = supplicant_ap_sta_disconnect,
#endif /* CONFIG_AP */
.pmksa_flush = supplicant_pmksa_flush,
.enterprise_creds = supplicant_add_enterprise_creds,
};

DEFINE_WIFI_NM_INSTANCE(wifi_supplicant, &mgmt_ops);
Expand Down
3 changes: 3 additions & 0 deletions subsys/net/l2/wifi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ zephyr_library_include_directories_ifdef(
zephyr_library_compile_definitions_ifdef(
CONFIG_NEWLIB_LIBC __LINUX_ERRNO_EXTENSIONS__
)
zephyr_library_include_directories_ifdef(
CONFIG_WIFI_NM_HOSTAPD_CRYPTO_ENTERPRISE test_certs
)

zephyr_library_sources_ifdef(CONFIG_NET_L2_WIFI_MGMT wifi_mgmt.c)
zephyr_library_sources_ifdef(CONFIG_NET_L2_WIFI_SHELL wifi_shell.c)
Expand Down
Loading

0 comments on commit de335e3

Please sign in to comment.