Hi Heinrich, On 3/5/25 16:07, Heinrich Schuchardt wrote: > On 05.03.25 15:26, Jerome Forissier wrote: >> 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.foriss...@linaro.org> >> --- >> cmd/Kconfig | 8 ++++ >> cmd/net-lwip.c | 17 ++++++-- >> net/lwip/wget.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++-- >> 3 files changed, 121 insertions(+), 6 deletions(-) >> >> diff --git a/cmd/Kconfig b/cmd/Kconfig >> index 8dd42571abc..d469217c0ea 100644 >> --- a/cmd/Kconfig >> +++ b/cmd/Kconfig >> @@ -2177,6 +2177,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. >> + > > Shouldn't we build CA certs into U-Boot? > Downloading certs from unsafe media is not a good replacement.
That's the purpose of patch 4/6 [1]. Although downloading may still be a valid option when used with hash verification as I mentioned in a reply to Ilias in v1 [2]. [1] https://lists.denx.de/pipermail/u-boot/2025-March/582567.html [2] https://lists.denx.de/pipermail/u-boot/2025-February/582102.html Best, -- Jerome > > Best regards > > Heinrich > >> endif # if CMD_NET >> >> config CMD_PXE >> diff --git a/cmd/net-lwip.c b/cmd/net-lwip.c >> index 0fd446ecb20..1152c94a6dc 100644 >> --- a/cmd/net-lwip.c >> +++ b/cmd/net-lwip.c >> @@ -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 >> diff --git a/net/lwip/wget.c b/net/lwip/wget.c >> index 14f27d42998..c22843ee10d 100644 >> --- a/net/lwip/wget.c >> +++ b/net/lwip/wget.c >> @@ -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; >> >