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:
+22
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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,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
@@ -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
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user