net: lwip: extend wget to support CA (root) certificates

Add the "cacert" (Certification Authority certificates) subcommand to
wget to pass root certificates to the code handling the HTTPS protocol.
The subcommand is enabled by the WGET_CACERT Kconfig symbol.

Usage example:

 => dhcp
 # Download some root certificates (note: not authenticated!)
 => wget https://cacerts.digicert.com/DigiCertTLSECCP384RootG5.crt
 # Provide root certificates
 => wget cacert $fileaddr $filesize
 # Enforce verification (it is optional by default)
 => wget cacert required
 # Forget the root certificates
 => wget cacert 0 0
 # Disable verification
 => wget cacert none

Signed-off-by: Jerome Forissier <jerome.forissier@linaro.org>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
This commit is contained in:
Jerome Forissier
2025-03-05 15:26:42 +01:00
parent 64ce9bfc6d
commit 2df965d385
3 changed files with 121 additions and 6 deletions

View File

@@ -2176,6 +2176,14 @@ 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.
endif # if CMD_NET
config CMD_PXE

View File

@@ -27,9 +27,20 @@ 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)"
#endif
);
#endif

View File

@@ -285,9 +285,68 @@ 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;
}
static int set_cacert(char * const saddr, char * const ssz)
{
mbedtls_x509_crt crt;
ulong addr, sz;
int ret;
if (cacert)
free(cacert);
addr = hextoul(saddr, NULL);
sz = hextoul(ssz, NULL);
if (!addr) {
cacert = NULL;
cacert_size = 0;
return CMD_RET_SUCCESS;
}
cacert = malloc(sz);
if (!cacert)
return CMD_RET_FAILURE;
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;
}
return CMD_RET_SUCCESS;
}
#endif
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 +371,34 @@ 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 = cacert;
size_t 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 +451,20 @@ 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 (!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;