net: lib: wifi_credentials: Add support for Enterprise security

Add support for configuring enterprise mode security.

Signed-off-by: Ravi Dondaputi <ravi.dondaputi@nordicsemi.no>
This commit is contained in:
Ravi Dondaputi 2025-04-15 17:32:28 +05:30 committed by Dan Kalowsky
parent 15d324cbd4
commit d289bed4af
2 changed files with 234 additions and 16 deletions

View File

@ -73,6 +73,32 @@ config WIFI_CREDENTIALS_CONNECT_STORED_CONNECTION_TIMEOUT
help
Wait period before falling back to the next entry in the list of stored SSIDs.
if WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE
config WIFI_CREDENTIALS_RUNTIME_CERTIFICATES
bool "Provide Wi-Fi enterprise security certificates at run-time"
select TLS_CREDENTIALS
select TLS_CREDENTIALS_SHELL
select BASE64
default y if WIFI_SHELL_RUNTIME_CERTIFICATES
help
This option enables providing Wi-Fi enterprise security certificates at run-time.
Uses the TLS credentials subsystem to store and manage the certificates.
if WIFI_CREDENTIALS_RUNTIME_CERTIFICATES
config HEAP_MEM_POOL_ADD_SIZE_WIFI_CERT
int "Wi-Fi enterprise security certificates memory pool size"
# STA - 6 certs and each assume 1500 bytes
default 12000
help
The size of the memory pool used by the Wi-Fi enterprise security certificates.
endif # WIFI_CREDENTIALS_RUNTIME_CERTIFICATES
endif # WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE
endif # WIFI_CREDENTIALS_CONNECT_STORED
endif # WIFI_CREDENTIALS

View File

@ -22,10 +22,33 @@
#include <zephyr/net/wifi_credentials.h>
LOG_MODULE_REGISTER(wifi_credentials_shell, CONFIG_WIFI_CREDENTIALS_LOG_LEVEL);
#define MAX_BANDS_STR_LEN 64
#define MACSTR "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx"
#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE
#ifdef CONFIG_WIFI_CREDENTIALS_RUNTIME_CERTIFICATES
#include <zephyr/net/tls_credentials.h>
enum wifi_enterprise_cert_sec_tags {
WIFI_CERT_CA_SEC_TAG = 0x1020001,
WIFI_CERT_CLIENT_KEY_SEC_TAG,
WIFI_CERT_SERVER_KEY_SEC_TAG,
WIFI_CERT_CLIENT_SEC_TAG,
WIFI_CERT_SERVER_SEC_TAG,
/* Phase 2 */
WIFI_CERT_CA_P2_SEC_TAG,
WIFI_CERT_CLIENT_KEY_P2_SEC_TAG,
WIFI_CERT_CLIENT_P2_SEC_TAG,
};
struct wifi_cert_data {
enum tls_credential_type type;
uint32_t sec_tag;
uint8_t **data;
size_t *len;
};
#else
static const char ca_cert_test[] = {
#include <wifi_enterprise_test_certs/ca.pem.inc>
'\0'
@ -52,25 +75,184 @@ static const char client_cert2_test[] = {
static const char client_key2_test[] = {
#include <wifi_enterprise_test_certs/client-key2.pem.inc>
'\0'};
#endif /* CONFIG_WIFI_CREDENTIALS_RUNTIME_CERTIFICATES */
#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE */
#if defined CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE
static int cmd_wifi_set_enterprise_creds(const struct shell *sh, struct net_if *iface)
#ifdef CONFIG_WIFI_CREDENTIALS_RUNTIME_CERTIFICATES
struct wifi_enterprise_creds_params enterprise_creds_params;
static int process_certificates(struct wifi_cert_data *certs, size_t cert_count)
{
for (size_t i = 0; i < cert_count; i++) {
int err;
size_t len = 0;
uint8_t *cert_tmp;
err = tls_credential_get(certs[i].sec_tag, certs[i].type, NULL, &len);
if (err != -EFBIG) {
LOG_ERR("Failed to get credential tag: %d length, err: %d",
certs[i].sec_tag, err);
return err;
}
cert_tmp = k_malloc(len);
if (!cert_tmp) {
LOG_ERR("Failed to allocate memory for credential tag: %d",
certs[i].sec_tag);
return -ENOMEM;
}
err = tls_credential_get(certs[i].sec_tag, certs[i].type, cert_tmp, &len);
if (err) {
LOG_ERR("Failed to get credential tag: %d", certs[i].sec_tag);
k_free(cert_tmp);
return err;
}
*certs[i].data = cert_tmp;
*certs[i].len = len;
}
return 0;
}
static void set_enterprise_creds_params(struct wifi_enterprise_creds_params *params,
bool is_ap)
{
struct wifi_cert_data certs_common[] = {
{
.type = TLS_CREDENTIAL_CA_CERTIFICATE,
.sec_tag = WIFI_CERT_CA_SEC_TAG,
.data = &params->ca_cert,
.len = &params->ca_cert_len,
},
};
struct wifi_cert_data certs_sta[] = {
{
.type = TLS_CREDENTIAL_PRIVATE_KEY,
.sec_tag = WIFI_CERT_CLIENT_KEY_SEC_TAG,
.data = &params->client_key,
.len = &params->client_key_len,
},
{
.type = TLS_CREDENTIAL_PUBLIC_CERTIFICATE,
.sec_tag = WIFI_CERT_CLIENT_SEC_TAG,
.data = &params->client_cert,
.len = &params->client_cert_len,
},
{
.type = TLS_CREDENTIAL_CA_CERTIFICATE,
.sec_tag = WIFI_CERT_CA_P2_SEC_TAG,
.data = &params->ca_cert2,
.len = &params->ca_cert2_len,
},
{
.type = TLS_CREDENTIAL_PRIVATE_KEY,
.sec_tag = WIFI_CERT_CLIENT_KEY_P2_SEC_TAG,
.data = &params->client_key2,
.len = &params->client_key2_len,
},
{
.type = TLS_CREDENTIAL_PUBLIC_CERTIFICATE,
.sec_tag = WIFI_CERT_CLIENT_P2_SEC_TAG,
.data = &params->client_cert2,
.len = &params->client_cert2_len,
},
};
memset(params, 0, sizeof(*params));
/* Process common certificates */
if (process_certificates(certs_common, ARRAY_SIZE(certs_common)) != 0) {
goto cleanup;
}
/* Process STA-specific certificates */
if (!is_ap) {
if (process_certificates(certs_sta, ARRAY_SIZE(certs_sta)) != 0) {
goto cleanup;
}
}
memcpy(&enterprise_creds_params, params, sizeof(*params));
return;
cleanup:
for (size_t i = 0; i < ARRAY_SIZE(certs_common); i++) {
if (certs_common[i].data) {
k_free(*certs_common[i].data);
*certs_common[i].data = NULL;
}
}
if (!is_ap) {
for (size_t i = 0; i < ARRAY_SIZE(certs_sta); i++) {
if (certs_sta[i].data) {
k_free(*certs_sta[i].data);
*certs_sta[i].data = NULL;
}
}
}
}
static void clear_enterprise_creds_params(struct wifi_enterprise_creds_params *params)
{
if (params == NULL) {
return;
}
const uint8_t *certs[] = {
params->ca_cert,
params->client_cert,
params->client_key,
params->ca_cert2,
params->client_cert2,
params->client_key2,
};
for (size_t i = 0; i < ARRAY_SIZE(certs); i++) {
k_free((void *)certs[i]);
}
memset(params, 0, sizeof(*params));
}
#else
static void set_enterprise_creds_params(struct wifi_enterprise_creds_params *params,
bool is_ap)
{
params->ca_cert = (uint8_t *)ca_cert_test;
params->ca_cert_len = ARRAY_SIZE(ca_cert_test);
if (!is_ap) {
params->client_cert = (uint8_t *)client_cert_test;
params->client_cert_len = ARRAY_SIZE(client_cert_test);
params->client_key = (uint8_t *)client_key_test;
params->client_key_len = ARRAY_SIZE(client_key_test);
params->ca_cert2 = (uint8_t *)ca_cert2_test;
params->ca_cert2_len = ARRAY_SIZE(ca_cert2_test);
params->client_cert2 = (uint8_t *)client_cert2_test;
params->client_cert2_len = ARRAY_SIZE(client_cert2_test);
params->client_key2 = (uint8_t *)client_key2_test;
params->client_key2_len = ARRAY_SIZE(client_key2_test);
return;
}
}
#endif /* CONFIG_WIFI_CREDENTIALS_RUNTIME_CERTIFICATES */
static int wifi_set_enterprise_creds(const struct shell *sh, struct net_if *iface,
bool is_ap)
{
struct wifi_enterprise_creds_params params = {0};
params.ca_cert = (uint8_t *)ca_cert_test;
params.ca_cert_len = ARRAY_SIZE(ca_cert_test);
params.client_cert = (uint8_t *)client_cert_test;
params.client_cert_len = ARRAY_SIZE(client_cert_test);
params.client_key = (uint8_t *)client_key_test;
params.client_key_len = ARRAY_SIZE(client_key_test);
params.ca_cert2 = (uint8_t *)ca_cert2_test;
params.ca_cert2_len = ARRAY_SIZE(ca_cert2_test);
params.client_cert2 = (uint8_t *)client_cert2_test;
params.client_cert2_len = ARRAY_SIZE(client_cert2_test);
params.client_key2 = (uint8_t *)client_key2_test;
params.client_key2_len = ARRAY_SIZE(client_key2_test);
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
clear_enterprise_creds_params(&enterprise_creds_params);
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
set_enterprise_creds_params(&params, is_ap);
if (net_mgmt(NET_REQUEST_WIFI_ENTERPRISE_CREDS, iface, &params, sizeof(params))) {
shell_warn(sh, "Set enterprise credentials failed\n");
@ -340,7 +522,7 @@ static int cmd_add_network(const struct shell *sh, size_t argc, char *argv[])
}
#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE
struct net_if *iface = net_if_get_first_by_type(&NET_L2_GET_NAME(ETHERNET));
struct net_if *iface = net_if_get_wifi_sta();
/* Load the enterprise credentials if needed */
if (creds.header.type == WIFI_SECURITY_TYPE_EAP_TLS ||
@ -348,7 +530,7 @@ static int cmd_add_network(const struct shell *sh, size_t argc, char *argv[])
creds.header.type == WIFI_SECURITY_TYPE_EAP_PEAP_GTC ||
creds.header.type == WIFI_SECURITY_TYPE_EAP_TTLS_MSCHAPV2 ||
creds.header.type == WIFI_SECURITY_TYPE_EAP_PEAP_TLS) {
cmd_wifi_set_enterprise_creds(sh, iface);
wifi_set_enterprise_creds(sh, iface, 0);
}
#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE */
@ -368,6 +550,12 @@ static int cmd_delete_network(const struct shell *sh, size_t argc, char *argv[])
}
shell_print(sh, "\tDeleting network ssid: \"%s\", ssid_len: %d", argv[1], strlen(argv[1]));
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
/* Clear the certificates */
clear_enterprise_creds_params(&enterprise_creds_params);
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
return wifi_credentials_delete_by_ssid(argv[1], strlen(argv[1]));
}
@ -381,7 +569,11 @@ static int cmd_list_networks(const struct shell *sh, size_t argc, char *argv[])
static int cmd_auto_connect(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = net_if_get_first_by_type(&NET_L2_GET_NAME(ETHERNET));
struct net_if *iface = net_if_get_wifi_sta();
#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE
wifi_set_enterprise_creds(sh, iface, 0);
#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE */
int rc = net_mgmt(NET_REQUEST_WIFI_CONNECT_STORED, iface, NULL, 0);
if (rc) {