net: l2: wifi: Add support for run-time certificates
Using TLS credentials library add support for run-time certificates where the installed certs are retrieved from the credential store (as of now only volatile backend is tested). This helps in production environments. Implements #79564. Signed-off-by: Chaitanya Tata <Chaitanya.Tata@nordicsemi.no>
This commit is contained in:
parent
90cd350c5a
commit
b2e7d7fc0c
3 changed files with 285 additions and 26 deletions
|
@ -30,11 +30,15 @@ Wi-Fi PSA crypto supported build
|
|||
|
||||
To enable PSA crypto API supported Wi-Fi build, the :kconfig:option:`CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ALT` and the :kconfig:option:`CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_MBEDTLS_PSA` need to be set.
|
||||
|
||||
Wi-Fi Enterprise test: X.509 Certificate header generation
|
||||
**********************************************************
|
||||
Wi-Fi Enterprise test: X.509 Certificate management
|
||||
***************************************************
|
||||
|
||||
Wi-Fi enterprise security requires use of X.509 certificates, test certificates
|
||||
in PEM format are committed to the repo at :zephyr_file:`samples/net/wifi/test_certs` and the during the
|
||||
Wi-Fi enterprise security requires use of X.509 certificates, two methods of installing certificates are supported:
|
||||
|
||||
Compile time certificates
|
||||
-------------------------
|
||||
|
||||
Test certificates in PEM format are committed to the repo at :zephyr_file:`samples/net/wifi/test_certs` and the during the
|
||||
build process the certificates are converted to a C header file that is included by the Wi-Fi shell
|
||||
module.
|
||||
|
||||
|
@ -55,6 +59,12 @@ For using variable size network buffer, the following overlay file can be used:
|
|||
$ west build -p -b <board> samples/net/wifi -- -DEXTRA_CONF_FILE=overlay-enterprise-variable-bufs.conf
|
||||
|
||||
|
||||
Run time certificates
|
||||
---------------------
|
||||
|
||||
The Wi-Fi shell module uses TLS credentials subsystem to store and manage the certificates. The certificates can be added at runtime using the shell commands, see :ref:`tls_credentials_shell` for more details.
|
||||
The sample or application need to enable the :kconfig:option:`CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES` option to use this feature.
|
||||
|
||||
|
||||
To initiate Wi-Fi connection, the following command can be used:
|
||||
|
||||
|
|
|
@ -125,3 +125,27 @@ config WIFI_ENT_IDENTITY_MAX_USERS
|
|||
default 8
|
||||
help
|
||||
This option defines the maximum number of identity users allowed connection.
|
||||
|
||||
if WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE
|
||||
|
||||
config WIFI_SHELL_RUNTIME_CERTIFICATES
|
||||
bool "Provide Wi-Fi enterprise security certificates at run-time"
|
||||
select TLS_CREDENTIALS
|
||||
select TLS_CREDENTIALS_SHELL
|
||||
select BASE64
|
||||
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_SHELL_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_SHELL_RUNTIME_CERTIFICATES
|
||||
|
||||
endif # WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE
|
||||
|
|
|
@ -30,7 +30,29 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF);
|
|||
|
||||
#include "net_shell_private.h"
|
||||
#include <math.h>
|
||||
#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE
|
||||
#if defined CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE || \
|
||||
defined CONFIG_WIFI_NM_HOSTAPD_CRYPTO_ENTERPRISE
|
||||
#ifdef CONFIG_WIFI_SHELL_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'
|
||||
|
@ -67,7 +89,8 @@ static const char server_key_test[] = {
|
|||
#include <wifi_enterprise_test_certs/server-key.pem.inc>
|
||||
'\0'
|
||||
};
|
||||
#endif
|
||||
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
|
||||
#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE */
|
||||
|
||||
#define WIFI_SHELL_MODULE "wifi"
|
||||
|
||||
|
@ -105,6 +128,12 @@ static struct {
|
|||
};
|
||||
uint8_t all;
|
||||
};
|
||||
#if defined CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE || \
|
||||
defined CONFIG_WIFI_NM_HOSTAPD_CRYPTO_ENTERPRISE
|
||||
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
|
||||
struct wifi_enterprise_creds_params enterprise_creds_params;
|
||||
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
|
||||
#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE */
|
||||
} context;
|
||||
|
||||
static struct net_mgmt_event_callback wifi_shell_mgmt_cb;
|
||||
|
@ -121,27 +150,212 @@ static struct wifi_ap_sta_node sta_list[CONFIG_WIFI_SHELL_MAX_AP_STA];
|
|||
|
||||
#if defined CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE || \
|
||||
defined CONFIG_WIFI_NM_HOSTAPD_CRYPTO_ENTERPRISE
|
||||
static int cmd_wifi_set_enterprise_creds(const struct shell *sh, struct net_if *iface)
|
||||
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
|
||||
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 = ¶ms->ca_cert,
|
||||
.len = ¶ms->ca_cert_len,
|
||||
},
|
||||
};
|
||||
|
||||
struct wifi_cert_data certs_sta[] = {
|
||||
{
|
||||
.type = TLS_CREDENTIAL_PRIVATE_KEY,
|
||||
.sec_tag = WIFI_CERT_CLIENT_KEY_SEC_TAG,
|
||||
.data = ¶ms->client_key,
|
||||
.len = ¶ms->client_key_len,
|
||||
},
|
||||
{
|
||||
.type = TLS_CREDENTIAL_PUBLIC_CERTIFICATE,
|
||||
.sec_tag = WIFI_CERT_CLIENT_SEC_TAG,
|
||||
.data = ¶ms->client_cert,
|
||||
.len = ¶ms->client_cert_len,
|
||||
},
|
||||
{
|
||||
.type = TLS_CREDENTIAL_CA_CERTIFICATE,
|
||||
.sec_tag = WIFI_CERT_CA_P2_SEC_TAG,
|
||||
.data = ¶ms->ca_cert2,
|
||||
.len = ¶ms->ca_cert2_len,
|
||||
},
|
||||
{
|
||||
.type = TLS_CREDENTIAL_PRIVATE_KEY,
|
||||
.sec_tag = WIFI_CERT_CLIENT_KEY_P2_SEC_TAG,
|
||||
.data = ¶ms->client_key2,
|
||||
.len = ¶ms->client_key2_len,
|
||||
},
|
||||
{
|
||||
.type = TLS_CREDENTIAL_PUBLIC_CERTIFICATE,
|
||||
.sec_tag = WIFI_CERT_CLIENT_P2_SEC_TAG,
|
||||
.data = ¶ms->client_cert2,
|
||||
.len = ¶ms->client_cert2_len,
|
||||
},
|
||||
};
|
||||
|
||||
struct wifi_cert_data certs_ap[] = {
|
||||
{
|
||||
.type = TLS_CREDENTIAL_PUBLIC_CERTIFICATE,
|
||||
.sec_tag = WIFI_CERT_SERVER_SEC_TAG,
|
||||
.data = ¶ms->server_cert,
|
||||
.len = ¶ms->server_cert_len,
|
||||
},
|
||||
{
|
||||
.type = TLS_CREDENTIAL_PRIVATE_KEY,
|
||||
.sec_tag = WIFI_CERT_SERVER_KEY_SEC_TAG,
|
||||
.data = ¶ms->server_key,
|
||||
.len = ¶ms->server_key_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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process AP-specific certificates if is_ap is true */
|
||||
if (is_ap) {
|
||||
if (process_certificates(certs_ap, ARRAY_SIZE(certs_ap)) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&context.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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_ap) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(certs_ap); i++) {
|
||||
if (certs_ap[i].data) {
|
||||
k_free(*certs_ap[i].data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_enterprise_creds_params(struct wifi_enterprise_creds_params *params)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!params) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t *certs[] = {
|
||||
params->ca_cert,
|
||||
params->client_cert,
|
||||
params->client_key,
|
||||
params->server_cert,
|
||||
params->server_key,
|
||||
params->ca_cert2,
|
||||
params->client_cert2,
|
||||
params->client_key2,
|
||||
};
|
||||
|
||||
for (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;
|
||||
}
|
||||
|
||||
params->server_cert = (uint8_t *)server_cert_test;
|
||||
params->server_cert_len = ARRAY_SIZE(server_cert_test);
|
||||
params->server_key = (uint8_t *)server_key_test;
|
||||
params->server_key_len = ARRAY_SIZE(server_key_test);
|
||||
}
|
||||
#endif /* CONFIG_WIFI_SHELL_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);
|
||||
params.server_cert = (uint8_t *)server_cert_test;
|
||||
params.server_cert_len = ARRAY_SIZE(server_cert_test);
|
||||
params.server_key = (uint8_t *)server_key_test;
|
||||
params.server_key_len = ARRAY_SIZE(server_key_test);
|
||||
|
||||
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
|
||||
clear_enterprise_creds_params(&context.enterprise_creds_params);
|
||||
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
|
||||
set_enterprise_creds_params(¶ms, is_ap);
|
||||
if (net_mgmt(NET_REQUEST_WIFI_ENTERPRISE_CREDS, iface, ¶ms, sizeof(params))) {
|
||||
PR_WARNING("Set enterprise credentials failed\n");
|
||||
return -1;
|
||||
|
@ -967,7 +1181,7 @@ static int cmd_wifi_connect(const struct shell *sh, size_t argc,
|
|||
cnx_params.security == WIFI_SECURITY_TYPE_EAP_PEAP_GTC ||
|
||||
cnx_params.security == WIFI_SECURITY_TYPE_EAP_TTLS_MSCHAPV2 ||
|
||||
cnx_params.security == WIFI_SECURITY_TYPE_EAP_PEAP_TLS) {
|
||||
cmd_wifi_set_enterprise_creds(sh, iface);
|
||||
wifi_set_enterprise_creds(sh, iface, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1009,6 +1223,11 @@ static int cmd_wifi_disconnect(const struct shell *sh, size_t argc,
|
|||
PR("Disconnect requested\n");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
|
||||
/* Clear the certificates */
|
||||
clear_enterprise_creds_params(&context.enterprise_creds_params);
|
||||
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1979,7 +2198,7 @@ static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc,
|
|||
cnx_params.security == WIFI_SECURITY_TYPE_EAP_PEAP_GTC ||
|
||||
cnx_params.security == WIFI_SECURITY_TYPE_EAP_TTLS_MSCHAPV2 ||
|
||||
cnx_params.security == WIFI_SECURITY_TYPE_EAP_PEAP_TLS) {
|
||||
cmd_wifi_set_enterprise_creds(sh, iface);
|
||||
wifi_set_enterprise_creds(sh, iface, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2010,6 +2229,12 @@ static int cmd_wifi_ap_disable(const struct shell *sh, size_t argc,
|
|||
}
|
||||
|
||||
PR("AP mode disable requested\n");
|
||||
|
||||
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
|
||||
/* Clear the certificates */
|
||||
clear_enterprise_creds_params(&context.enterprise_creds_params);
|
||||
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue