Skip to content

Commit b2e7d7f

Browse files
krish2718kartben
authored andcommitted
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 zephyrproject-rtos#79564. Signed-off-by: Chaitanya Tata <Chaitanya.Tata@nordicsemi.no>
1 parent 90cd350 commit b2e7d7f

File tree

3 files changed

+285
-26
lines changed

3 files changed

+285
-26
lines changed

doc/connectivity/networking/api/wifi.rst

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,15 @@ Wi-Fi PSA crypto supported build
3030

3131
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.
3232

33-
Wi-Fi Enterprise test: X.509 Certificate header generation
34-
**********************************************************
33+
Wi-Fi Enterprise test: X.509 Certificate management
34+
***************************************************
3535

36-
Wi-Fi enterprise security requires use of X.509 certificates, test certificates
37-
in PEM format are committed to the repo at :zephyr_file:`samples/net/wifi/test_certs` and the during the
36+
Wi-Fi enterprise security requires use of X.509 certificates, two methods of installing certificates are supported:
37+
38+
Compile time certificates
39+
-------------------------
40+
41+
Test certificates in PEM format are committed to the repo at :zephyr_file:`samples/net/wifi/test_certs` and the during the
3842
build process the certificates are converted to a C header file that is included by the Wi-Fi shell
3943
module.
4044

@@ -55,6 +59,12 @@ For using variable size network buffer, the following overlay file can be used:
5559
$ west build -p -b <board> samples/net/wifi -- -DEXTRA_CONF_FILE=overlay-enterprise-variable-bufs.conf
5660
5761
62+
Run time certificates
63+
---------------------
64+
65+
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.
66+
The sample or application need to enable the :kconfig:option:`CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES` option to use this feature.
67+
5868

5969
To initiate Wi-Fi connection, the following command can be used:
6070

subsys/net/l2/wifi/Kconfig

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,27 @@ config WIFI_ENT_IDENTITY_MAX_USERS
125125
default 8
126126
help
127127
This option defines the maximum number of identity users allowed connection.
128+
129+
if WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE
130+
131+
config WIFI_SHELL_RUNTIME_CERTIFICATES
132+
bool "Provide Wi-Fi enterprise security certificates at run-time"
133+
select TLS_CREDENTIALS
134+
select TLS_CREDENTIALS_SHELL
135+
select BASE64
136+
help
137+
This option enables providing Wi-Fi enterprise security certificates at run-time.
138+
Uses the TLS credentials subsystem to store and manage the certificates.
139+
140+
if WIFI_SHELL_RUNTIME_CERTIFICATES
141+
142+
config HEAP_MEM_POOL_ADD_SIZE_WIFI_CERT
143+
int "Wi-Fi enterprise security certificates memory pool size"
144+
# STA - 6 certs and each assume 1500 bytes
145+
default 12000
146+
help
147+
The size of the memory pool used by the Wi-Fi enterprise security certificates.
148+
149+
endif # WIFI_SHELL_RUNTIME_CERTIFICATES
150+
151+
endif # WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE

subsys/net/l2/wifi/wifi_shell.c

Lines changed: 247 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,29 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF);
3030

3131
#include "net_shell_private.h"
3232
#include <math.h>
33-
#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE
33+
#if defined CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE || \
34+
defined CONFIG_WIFI_NM_HOSTAPD_CRYPTO_ENTERPRISE
35+
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
36+
#include <zephyr/net/tls_credentials.h>
37+
enum wifi_enterprise_cert_sec_tags {
38+
WIFI_CERT_CA_SEC_TAG = 0x1020001,
39+
WIFI_CERT_CLIENT_KEY_SEC_TAG,
40+
WIFI_CERT_SERVER_KEY_SEC_TAG,
41+
WIFI_CERT_CLIENT_SEC_TAG,
42+
WIFI_CERT_SERVER_SEC_TAG,
43+
/* Phase 2 */
44+
WIFI_CERT_CA_P2_SEC_TAG,
45+
WIFI_CERT_CLIENT_KEY_P2_SEC_TAG,
46+
WIFI_CERT_CLIENT_P2_SEC_TAG,
47+
};
48+
49+
struct wifi_cert_data {
50+
enum tls_credential_type type;
51+
uint32_t sec_tag;
52+
uint8_t **data;
53+
size_t *len;
54+
};
55+
#else
3456
static const char ca_cert_test[] = {
3557
#include <wifi_enterprise_test_certs/ca.pem.inc>
3658
'\0'
@@ -67,7 +89,8 @@ static const char server_key_test[] = {
6789
#include <wifi_enterprise_test_certs/server-key.pem.inc>
6890
'\0'
6991
};
70-
#endif
92+
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
93+
#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE */
7194

7295
#define WIFI_SHELL_MODULE "wifi"
7396

@@ -105,6 +128,12 @@ static struct {
105128
};
106129
uint8_t all;
107130
};
131+
#if defined CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE || \
132+
defined CONFIG_WIFI_NM_HOSTAPD_CRYPTO_ENTERPRISE
133+
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
134+
struct wifi_enterprise_creds_params enterprise_creds_params;
135+
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
136+
#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE */
108137
} context;
109138

110139
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];
121150

122151
#if defined CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE || \
123152
defined CONFIG_WIFI_NM_HOSTAPD_CRYPTO_ENTERPRISE
124-
static int cmd_wifi_set_enterprise_creds(const struct shell *sh, struct net_if *iface)
153+
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
154+
static int process_certificates(struct wifi_cert_data *certs, size_t cert_count)
125155
{
126-
struct wifi_enterprise_creds_params params = {0};
156+
for (size_t i = 0; i < cert_count; i++) {
157+
int err;
158+
size_t len = 0;
159+
uint8_t *cert_tmp;
160+
161+
err = tls_credential_get(certs[i].sec_tag, certs[i].type, NULL, &len);
162+
if (err != -EFBIG) {
163+
LOG_ERR("Failed to get credential tag: %d length, err: %d",
164+
certs[i].sec_tag, err);
165+
return err;
166+
}
127167

128-
params.ca_cert = (uint8_t *)ca_cert_test;
129-
params.ca_cert_len = ARRAY_SIZE(ca_cert_test);
130-
params.client_cert = (uint8_t *)client_cert_test;
131-
params.client_cert_len = ARRAY_SIZE(client_cert_test);
132-
params.client_key = (uint8_t *)client_key_test;
133-
params.client_key_len = ARRAY_SIZE(client_key_test);
134-
params.ca_cert2 = (uint8_t *)ca_cert2_test;
135-
params.ca_cert2_len = ARRAY_SIZE(ca_cert2_test);
136-
params.client_cert2 = (uint8_t *)client_cert2_test;
137-
params.client_cert2_len = ARRAY_SIZE(client_cert2_test);
138-
params.client_key2 = (uint8_t *)client_key2_test;
139-
params.client_key2_len = ARRAY_SIZE(client_key2_test);
140-
params.server_cert = (uint8_t *)server_cert_test;
141-
params.server_cert_len = ARRAY_SIZE(server_cert_test);
142-
params.server_key = (uint8_t *)server_key_test;
143-
params.server_key_len = ARRAY_SIZE(server_key_test);
168+
cert_tmp = k_malloc(len);
169+
if (!cert_tmp) {
170+
LOG_ERR("Failed to allocate memory for credential tag: %d",
171+
certs[i].sec_tag);
172+
return -ENOMEM;
173+
}
144174

175+
err = tls_credential_get(certs[i].sec_tag, certs[i].type, cert_tmp, &len);
176+
if (err) {
177+
LOG_ERR("Failed to get credential tag: %d", certs[i].sec_tag);
178+
k_free(cert_tmp);
179+
return err;
180+
}
181+
182+
*certs[i].data = cert_tmp;
183+
*certs[i].len = len;
184+
}
185+
186+
return 0;
187+
}
188+
189+
static void set_enterprise_creds_params(struct wifi_enterprise_creds_params *params,
190+
bool is_ap)
191+
{
192+
struct wifi_cert_data certs_common[] = {
193+
{
194+
.type = TLS_CREDENTIAL_CA_CERTIFICATE,
195+
.sec_tag = WIFI_CERT_CA_SEC_TAG,
196+
.data = &params->ca_cert,
197+
.len = &params->ca_cert_len,
198+
},
199+
};
200+
201+
struct wifi_cert_data certs_sta[] = {
202+
{
203+
.type = TLS_CREDENTIAL_PRIVATE_KEY,
204+
.sec_tag = WIFI_CERT_CLIENT_KEY_SEC_TAG,
205+
.data = &params->client_key,
206+
.len = &params->client_key_len,
207+
},
208+
{
209+
.type = TLS_CREDENTIAL_PUBLIC_CERTIFICATE,
210+
.sec_tag = WIFI_CERT_CLIENT_SEC_TAG,
211+
.data = &params->client_cert,
212+
.len = &params->client_cert_len,
213+
},
214+
{
215+
.type = TLS_CREDENTIAL_CA_CERTIFICATE,
216+
.sec_tag = WIFI_CERT_CA_P2_SEC_TAG,
217+
.data = &params->ca_cert2,
218+
.len = &params->ca_cert2_len,
219+
},
220+
{
221+
.type = TLS_CREDENTIAL_PRIVATE_KEY,
222+
.sec_tag = WIFI_CERT_CLIENT_KEY_P2_SEC_TAG,
223+
.data = &params->client_key2,
224+
.len = &params->client_key2_len,
225+
},
226+
{
227+
.type = TLS_CREDENTIAL_PUBLIC_CERTIFICATE,
228+
.sec_tag = WIFI_CERT_CLIENT_P2_SEC_TAG,
229+
.data = &params->client_cert2,
230+
.len = &params->client_cert2_len,
231+
},
232+
};
233+
234+
struct wifi_cert_data certs_ap[] = {
235+
{
236+
.type = TLS_CREDENTIAL_PUBLIC_CERTIFICATE,
237+
.sec_tag = WIFI_CERT_SERVER_SEC_TAG,
238+
.data = &params->server_cert,
239+
.len = &params->server_cert_len,
240+
},
241+
{
242+
.type = TLS_CREDENTIAL_PRIVATE_KEY,
243+
.sec_tag = WIFI_CERT_SERVER_KEY_SEC_TAG,
244+
.data = &params->server_key,
245+
.len = &params->server_key_len,
246+
},
247+
};
248+
249+
memset(params, 0, sizeof(*params));
250+
251+
/* Process common certificates */
252+
if (process_certificates(certs_common, ARRAY_SIZE(certs_common)) != 0) {
253+
goto cleanup;
254+
}
255+
256+
/* Process STA-specific certificates */
257+
if (!is_ap) {
258+
if (process_certificates(certs_sta, ARRAY_SIZE(certs_sta)) != 0) {
259+
goto cleanup;
260+
}
261+
}
262+
263+
/* Process AP-specific certificates if is_ap is true */
264+
if (is_ap) {
265+
if (process_certificates(certs_ap, ARRAY_SIZE(certs_ap)) != 0) {
266+
goto cleanup;
267+
}
268+
}
269+
270+
memcpy(&context.enterprise_creds_params, params, sizeof(*params));
271+
return;
272+
273+
cleanup:
274+
for (size_t i = 0; i < ARRAY_SIZE(certs_common); i++) {
275+
if (certs_common[i].data) {
276+
k_free(*certs_common[i].data);
277+
}
278+
}
279+
280+
if (!is_ap) {
281+
for (size_t i = 0; i < ARRAY_SIZE(certs_sta); i++) {
282+
if (certs_sta[i].data) {
283+
k_free(*certs_sta[i].data);
284+
}
285+
}
286+
}
287+
288+
if (is_ap) {
289+
for (size_t i = 0; i < ARRAY_SIZE(certs_ap); i++) {
290+
if (certs_ap[i].data) {
291+
k_free(*certs_ap[i].data);
292+
}
293+
}
294+
}
295+
}
296+
297+
static void clear_enterprise_creds_params(struct wifi_enterprise_creds_params *params)
298+
{
299+
size_t i;
300+
301+
if (!params) {
302+
return;
303+
}
304+
305+
const uint8_t *certs[] = {
306+
params->ca_cert,
307+
params->client_cert,
308+
params->client_key,
309+
params->server_cert,
310+
params->server_key,
311+
params->ca_cert2,
312+
params->client_cert2,
313+
params->client_key2,
314+
};
315+
316+
for (i = 0; i < ARRAY_SIZE(certs); i++) {
317+
k_free((void *)certs[i]);
318+
}
319+
memset(params, 0, sizeof(*params));
320+
}
321+
#else
322+
static void set_enterprise_creds_params(struct wifi_enterprise_creds_params *params,
323+
bool is_ap)
324+
{
325+
params->ca_cert = (uint8_t *)ca_cert_test;
326+
params->ca_cert_len = ARRAY_SIZE(ca_cert_test);
327+
328+
if (!is_ap) {
329+
params->client_cert = (uint8_t *)client_cert_test;
330+
params->client_cert_len = ARRAY_SIZE(client_cert_test);
331+
params->client_key = (uint8_t *)client_key_test;
332+
params->client_key_len = ARRAY_SIZE(client_key_test);
333+
params->ca_cert2 = (uint8_t *)ca_cert2_test;
334+
params->ca_cert2_len = ARRAY_SIZE(ca_cert2_test);
335+
params->client_cert2 = (uint8_t *)client_cert2_test;
336+
params->client_cert2_len = ARRAY_SIZE(client_cert2_test);
337+
params->client_key2 = (uint8_t *)client_key2_test;
338+
params->client_key2_len = ARRAY_SIZE(client_key2_test);
339+
340+
return;
341+
}
342+
343+
params->server_cert = (uint8_t *)server_cert_test;
344+
params->server_cert_len = ARRAY_SIZE(server_cert_test);
345+
params->server_key = (uint8_t *)server_key_test;
346+
params->server_key_len = ARRAY_SIZE(server_key_test);
347+
}
348+
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
349+
350+
static int wifi_set_enterprise_creds(const struct shell *sh, struct net_if *iface,
351+
bool is_ap)
352+
{
353+
struct wifi_enterprise_creds_params params = {0};
354+
355+
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
356+
clear_enterprise_creds_params(&context.enterprise_creds_params);
357+
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
358+
set_enterprise_creds_params(&params, is_ap);
145359
if (net_mgmt(NET_REQUEST_WIFI_ENTERPRISE_CREDS, iface, &params, sizeof(params))) {
146360
PR_WARNING("Set enterprise credentials failed\n");
147361
return -1;
@@ -967,7 +1181,7 @@ static int cmd_wifi_connect(const struct shell *sh, size_t argc,
9671181
cnx_params.security == WIFI_SECURITY_TYPE_EAP_PEAP_GTC ||
9681182
cnx_params.security == WIFI_SECURITY_TYPE_EAP_TTLS_MSCHAPV2 ||
9691183
cnx_params.security == WIFI_SECURITY_TYPE_EAP_PEAP_TLS) {
970-
cmd_wifi_set_enterprise_creds(sh, iface);
1184+
wifi_set_enterprise_creds(sh, iface, 0);
9711185
}
9721186
#endif
9731187

@@ -1009,6 +1223,11 @@ static int cmd_wifi_disconnect(const struct shell *sh, size_t argc,
10091223
PR("Disconnect requested\n");
10101224
}
10111225

1226+
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
1227+
/* Clear the certificates */
1228+
clear_enterprise_creds_params(&context.enterprise_creds_params);
1229+
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
1230+
10121231
return 0;
10131232
}
10141233

@@ -1979,7 +2198,7 @@ static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc,
19792198
cnx_params.security == WIFI_SECURITY_TYPE_EAP_PEAP_GTC ||
19802199
cnx_params.security == WIFI_SECURITY_TYPE_EAP_TTLS_MSCHAPV2 ||
19812200
cnx_params.security == WIFI_SECURITY_TYPE_EAP_PEAP_TLS) {
1982-
cmd_wifi_set_enterprise_creds(sh, iface);
2201+
wifi_set_enterprise_creds(sh, iface, 1);
19832202
}
19842203
#endif
19852204

@@ -2010,6 +2229,12 @@ static int cmd_wifi_ap_disable(const struct shell *sh, size_t argc,
20102229
}
20112230

20122231
PR("AP mode disable requested\n");
2232+
2233+
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
2234+
/* Clear the certificates */
2235+
clear_enterprise_creds_params(&context.enterprise_creds_params);
2236+
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
2237+
20132238
return 0;
20142239
}
20152240

0 commit comments

Comments
 (0)