Merge tag 'net-next-20250310' of https://source.denx.de/u-boot/custodians/u-boot-net into next

Pull request net-next-20250310.

CI:
* https://source.denx.de/u-boot/custodians/u-boot-net/-/pipelines/25084

net-lwip:
* Add support for CA (root) certificates to HTTPS
* Add CONFIG_LWIP_DEBUG_RXTX to trace in/out messages
This commit is contained in:
Tom Rini
2025-03-11 08:57:33 -06:00
10 changed files with 295 additions and 17 deletions
+22
View File
@@ -2176,6 +2176,28 @@ config WGET_HTTPS
help
Enable TLS over http for wget.
config WGET_CACERT
bool "wget cacert"
depends on CMD_WGET
depends on WGET_HTTPS
help
Adds the "cacert" sub-command to wget to provide root certificates
to the HTTPS engine. Must be in DER format.
config WGET_BUILTIN_CACERT
bool "Built-in CA certificates"
depends on WGET_HTTPS
select BUILD_BIN2C
config WGET_BUILTIN_CACERT_PATH
string "Path to root certificates"
depends on WGET_BUILTIN_CACERT
default "cacert.crt"
help
Set this to the path to a DER-encoded X509 file containing
Certification Authority certificates, a.k.a. root certificates, for
the purpose of authenticating HTTPS connections.
endif # if CMD_NET
config CMD_PXE
+18 -3
View File
@@ -27,9 +27,24 @@ U_BOOT_CMD(dns, 3, 1, do_dns, "lookup the IP of a hostname",
#endif
#if defined(CONFIG_CMD_WGET)
U_BOOT_CMD(wget, 3, 1, do_wget,
"boot image via network using HTTP/HTTPS protocol",
U_BOOT_CMD(wget, 4, 1, do_wget,
"boot image via network using HTTP/HTTPS protocol"
#if defined(CONFIG_WGET_CACERT)
"\nwget cacert - configure wget root certificates"
#endif
,
"[loadAddress] url\n"
"wget [loadAddress] [host:]path"
"wget [loadAddress] [host:]path\n"
" - load file"
#if defined(CONFIG_WGET_CACERT)
"\nwget cacert <address> <length>\n"
" - provide CA certificates (0 0 to remove current)"
"\nwget cacert none|optional|required\n"
" - set server certificate verification mode (default: optional)"
#if defined(CONFIG_WGET_BUILTIN_CACERT)
"\nwget cacert builtin\n"
" - use the builtin CA certificates"
#endif
#endif
);
#endif
+1
View File
@@ -8,3 +8,4 @@ CONFIG_CMD_DNS=y
CONFIG_CMD_WGET=y
CONFIG_EFI_HTTP_BOOT=y
CONFIG_WGET_HTTPS=y
CONFIG_WGET_CACERT=y
+80 -2
View File
@@ -12,7 +12,9 @@ Synopsis
::
wget [address] [host:]path
wget [address] url # lwIP only
wget [address] url # lwIP only
wget cacert none|optional|required # lwIP only
wget cacert <address> <size> # lwIP only
Description
@@ -54,6 +56,32 @@ address
url
HTTP or HTTPS URL, that is: http[s]://<host>[:<port>]/<path>.
The cacert (stands for 'Certification Authority certificates') subcommand is
used to provide root certificates for the purpose of HTTPS authentication. It
also allows to enable or disable authentication.
wget cacert <address> <size>
address
memory address of the root certificates in X509 DER format
size
the size of the root certificates
wget cacert none|optional|required
none
certificate verification is disabled. HTTPS is used without any server
authentication (unsafe)
optional
certificate verification is enabled provided root certificates have been
provided via wget cacert <addr> <size> or wget cacert builtin. Otherwise
HTTPS is used without any server authentication (unsafe).
required
certificate verification is mandatory. If no root certificates have been
configured, HTTPS transfers will fail.
Examples
--------
@@ -97,11 +125,61 @@ In the example the following steps are executed:
1694892032 bytes transferred in 492181 ms (3.3 MiB/s)
Bytes transferred = 1694892032 (65060000 hex)
Here is an example showing how to configure built-in root certificates as
well as providing some at run time. In this example it is assumed that
CONFIG_WGET_BUILTIN_CACERT_PATH=DigiCertTLSRSA4096RootG5.crt downloaded from
https://cacerts.digicert.com/DigiCertTLSRSA4096RootG5.crt.
::
# Make sure IP is configured
=> dhcp
# When built-in certificates are configured, authentication is mandatory
# (i.e., "wget cacert required"). Use a test server...
=> wget https://digicert-tls-rsa4096-root-g5.chain-demos.digicert.com/
1864 bytes transferred in 1 ms (1.8 MiB/s)
Bytes transferred = 1864 (748 hex)
# Another server not signed against Digicert will fail
=> wget https://www.google.com/
Certificate verification failed
HTTP client error 4
# Disable authentication to allow the command to proceed anyways
=> wget cacert none
=> wget https://www.google.com/
WARNING: no CA certificates, HTTPS connections not authenticated
16683 bytes transferred in 15 ms (1.1 MiB/s)
Bytes transferred = 16683 (412b hex)
# Force verification but unregister the CA certificates
=> wget cacert required
=> wget cacert 0 0
# Unsurprisingly, download fails
=> wget https://digicert-tls-rsa4096-root-g5.chain-demos.digicert.com/
Error: cacert authentication mode is 'required' but no CA certificates given
# Get the same certificates as above from the network
=> wget cacert none
=> wget https://cacerts.digicert.com/DigiCertTLSRSA4096RootG5.crt
WARNING: no CA certificates, HTTPS connections not authenticated
1386 bytes transferred in 1 ms (1.3 MiB/s)
Bytes transferred = 1386 (56a hex)
# Register them and force authentication
=> wget cacert $fileaddr $filesize
=> wget cacert required
# Authentication is operational again
=> wget https://digicert-tls-rsa4096-root-g5.chain-demos.digicert.com/
1864 bytes transferred in 1 ms (1.8 MiB/s)
Bytes transferred = 1864 (748 hex)
# The builtin certificates can be restored at any time
=> wget cacert builtin
Configuration
-------------
The command is only available if CONFIG_CMD_WGET=y.
To enable lwIP support set CONFIG_NET_LWIP=y.
To enable lwIP support set CONFIG_NET_LWIP=y. In this case, root certificates
support can be enabled via CONFIG_WGET_BUILTIN_CACERT=y
CONFIG_WGET_BUILTIN_CACERT_PATH=<some path> (for built-in certificates) and/or
CONFIG_WGET_CACERT=y (for the wget cacert command).
TCP Selective Acknowledgments in the legacy network stack can be enabled via
CONFIG_PROT_TCP_SACK=y. This will improve the download speed. Selective
@@ -298,6 +298,9 @@ altcp_mbedtls_lower_recv_process(struct altcp_pcb *conn, altcp_mbedtls_state_t *
if (ret != 0) {
LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_handshake failed: %d\n", ret));
/* handshake failed, connection has to be closed */
if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
printf("Certificate verification failed\n");
}
if (conn->err) {
conn->err(conn->arg, ERR_CLSD);
}
@@ -786,6 +789,7 @@ altcp_tls_create_config(int is_server, u8_t cert_count, u8_t pkey_count, int hav
int ret;
struct altcp_tls_config *conf;
mbedtls_x509_crt *mem;
int authmode = have_ca ? MBEDTLS_SSL_VERIFY_REQUIRED : MBEDTLS_SSL_VERIFY_NONE;
if (TCP_WND < MBEDTLS_SSL_IN_CONTENT_LEN || TCP_WND < MBEDTLS_SSL_OUT_CONTENT_LEN) {
LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG|LWIP_DBG_LEVEL_SERIOUS,
@@ -840,7 +844,10 @@ altcp_tls_create_config(int is_server, u8_t cert_count, u8_t pkey_count, int hav
altcp_mbedtls_free_config(conf);
return NULL;
}
mbedtls_ssl_conf_authmode(&conf->conf, ALTCP_MBEDTLS_AUTHMODE);
if (authmode == MBEDTLS_SSL_VERIFY_NONE) {
printf("WARNING: no CA certificates, HTTPS connections not authenticated\n");
}
mbedtls_ssl_conf_authmode(&conf->conf, authmode);
mbedtls_ssl_conf_rng(&conf->conf, mbedtls_ctr_drbg_random, &altcp_tls_entropy_rng->ctr_drbg);
#if ALTCP_MBEDTLS_LIB_DEBUG != LWIP_DBG_OFF
@@ -100,12 +100,6 @@
#define ALTCP_MBEDTLS_SESSION_TICKET_TIMEOUT_SECONDS (60 * 60 * 24)
#endif
/** Certificate verification mode: MBEDTLS_SSL_VERIFY_NONE, MBEDTLS_SSL_VERIFY_OPTIONAL (default),
* MBEDTLS_SSL_VERIFY_REQUIRED (recommended)*/
#ifndef ALTCP_MBEDTLS_AUTHMODE
#define ALTCP_MBEDTLS_AUTHMODE MBEDTLS_SSL_VERIFY_OPTIONAL
#endif
#endif /* LWIP_ALTCP */
#endif /* LWIP_HDR_ALTCP_TLS_OPTS_H */
+6
View File
@@ -10,6 +10,12 @@ config LWIP_DEBUG
Prints messages to the console regarding network packets that go in
and out of the lwIP library.
config LWIP_DEBUG_RXTX
bool "Dump packets sent and received by lwIP"
help
Performs an hexadecimal & ASCII dump of the data received and sent by
the lwIP network stack.
config LWIP_ASSERT
bool "Enable assertions in the lwIP library"
help
+6
View File
@@ -6,3 +6,9 @@ obj-$(CONFIG_CMD_DNS) += dns.o
obj-$(CONFIG_CMD_PING) += ping.o
obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o
obj-$(CONFIG_WGET) += wget.o
ifeq (y,$(CONFIG_WGET_BUILTIN_CACERT))
$(obj)/builtin_cacert.c: $(CONFIG_WGET_BUILTIN_CACERT_PATH:"%"=%) FORCE
$(call if_changed,bin2c,builtin_cacert)
obj-y += builtin_cacert.o
endif
+16 -2
View File
@@ -5,6 +5,7 @@
#include <command.h>
#include <dm/device.h>
#include <dm/uclass.h>
#include <hexdump.h>
#include <lwip/ip4_addr.h>
#include <lwip/err.h>
#include <lwip/netif.h>
@@ -30,12 +31,18 @@ char *pxelinux_configfile;
struct in_addr net_ip;
char net_boot_file_name[1024];
static err_t linkoutput(struct netif *netif, struct pbuf *p)
static err_t net_lwip_tx(struct netif *netif, struct pbuf *p)
{
struct udevice *udev = netif->state;
void *pp = NULL;
int err;
if (CONFIG_IS_ENABLED(LWIP_DEBUG_RXTX)) {
printf("net_lwip_tx: %u bytes, udev %s\n", p->len, udev->name);
print_hex_dump("net_lwip_tx: ", 0, 16, 1, p->payload, p->len,
true);
}
if ((unsigned long)p->payload % PKTALIGN) {
/*
* Some net drivers have strict alignment requirements and may
@@ -60,7 +67,7 @@ static err_t linkoutput(struct netif *netif, struct pbuf *p)
static err_t net_lwip_if_init(struct netif *netif)
{
netif->output = etharp_output;
netif->linkoutput = linkoutput;
netif->linkoutput = net_lwip_tx;
netif->mtu = 1500;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
@@ -265,6 +272,13 @@ int net_lwip_rx(struct udevice *udev, struct netif *netif)
flags = 0;
if (len > 0) {
if (CONFIG_IS_ENABLED(LWIP_DEBUG_RXTX)) {
printf("net_lwip_tx: %u bytes, udev %s \n", len,
udev->name);
print_hex_dump("net_lwip_rx: ", 0, 16, 1,
packet, len, true);
}
pbuf = alloc_pbuf_and_copy(packet, len);
if (pbuf)
netif->input(pbuf, netif);
+138 -3
View File
@@ -285,9 +285,96 @@ static err_t httpc_headers_done_cb(httpc_state_t *connection, void *arg, struct
return ERR_OK;
}
#if CONFIG_IS_ENABLED(WGET_HTTPS)
enum auth_mode {
AUTH_NONE,
AUTH_OPTIONAL,
AUTH_REQUIRED,
};
static char *cacert;
static size_t cacert_size;
static enum auth_mode cacert_auth_mode = AUTH_OPTIONAL;
#endif
#if CONFIG_IS_ENABLED(WGET_CACERT)
static int set_auth(enum auth_mode auth)
{
cacert_auth_mode = auth;
return CMD_RET_SUCCESS;
}
#endif
#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT)
extern const char builtin_cacert[];
extern const size_t builtin_cacert_size;
static bool cacert_initialized;
#endif
#if CONFIG_IS_ENABLED(WGET_CACERT) || CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT)
static int _set_cacert(const void *addr, size_t sz)
{
mbedtls_x509_crt crt;
void *p;
int ret;
if (cacert)
free(cacert);
if (!addr) {
cacert = NULL;
cacert_size = 0;
return CMD_RET_SUCCESS;
}
p = malloc(sz);
if (!p)
return CMD_RET_FAILURE;
cacert = p;
cacert_size = sz;
memcpy(cacert, (void *)addr, sz);
mbedtls_x509_crt_init(&crt);
ret = mbedtls_x509_crt_parse(&crt, cacert, cacert_size);
if (ret) {
printf("Could not parse certificates (%d)\n", ret);
free(cacert);
cacert = NULL;
cacert_size = 0;
return CMD_RET_FAILURE;
}
#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT)
cacert_initialized = true;
#endif
return CMD_RET_SUCCESS;
}
#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT)
static int set_cacert_builtin(void)
{
return _set_cacert(builtin_cacert, builtin_cacert_size);
}
#endif
#if CONFIG_IS_ENABLED(WGET_CACERT)
static int set_cacert(char * const saddr, char * const ssz)
{
ulong addr, sz;
addr = hextoul(saddr, NULL);
sz = hextoul(ssz, NULL);
return _set_cacert((void *)addr, sz);
}
#endif
#endif /* CONFIG_WGET_CACERT || CONFIG_WGET_BUILTIN_CACERT */
static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri)
{
#if defined CONFIG_WGET_HTTPS
#if CONFIG_IS_ENABLED(WGET_HTTPS)
altcp_allocator_t tls_allocator;
#endif
httpc_connection_t conn;
@@ -312,11 +399,41 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri)
return -1;
memset(&conn, 0, sizeof(conn));
#if defined CONFIG_WGET_HTTPS
#if CONFIG_IS_ENABLED(WGET_HTTPS)
if (is_https) {
char *ca;
size_t ca_sz;
#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT)
if (!cacert_initialized)
set_cacert_builtin();
#endif
ca = cacert;
ca_sz = cacert_size;
if (cacert_auth_mode == AUTH_REQUIRED) {
if (!ca || !ca_sz) {
printf("Error: cacert authentication mode is "
"'required' but no CA certificates "
"given\n");
return CMD_RET_FAILURE;
}
} else if (cacert_auth_mode == AUTH_NONE) {
ca = NULL;
ca_sz = 0;
} else if (cacert_auth_mode == AUTH_OPTIONAL) {
/*
* Nothing to do, this is the default behavior of
* altcp_tls to check server certificates against CA
* certificates when the latter are provided and proceed
* with no verification if not.
*/
}
tls_allocator.alloc = &altcp_tls_alloc;
tls_allocator.arg =
altcp_tls_create_config_client(NULL, 0, ctx.server_name);
altcp_tls_create_config_client(ca, ca_sz,
ctx.server_name);
if (!tls_allocator.arg) {
log_err("error: Cannot create a TLS connection\n");
@@ -369,6 +486,24 @@ int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
ulong dst_addr;
char nurl[1024];
#if CONFIG_IS_ENABLED(WGET_CACERT)
if (argc == 4 && !strncmp(argv[1], "cacert", strlen("cacert")))
return set_cacert(argv[2], argv[3]);
if (argc == 3 && !strncmp(argv[1], "cacert", strlen("cacert"))) {
#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT)
if (!strncmp(argv[2], "builtin", strlen("builtin")))
return set_cacert_builtin();
#endif
if (!strncmp(argv[2], "none", strlen("none")))
return set_auth(AUTH_NONE);
if (!strncmp(argv[2], "optional", strlen("optional")))
return set_auth(AUTH_OPTIONAL);
if (!strncmp(argv[2], "required", strlen("required")))
return set_auth(AUTH_REQUIRED);
return CMD_RET_USAGE;
}
#endif
if (argc < 2 || argc > 3)
return CMD_RET_USAGE;