[PATCH v2 1/6] net: lwip: extend wget to support CA (root) certificates
Jerome Forissier
jerome.forissier at linaro.org
Wed Mar 5 16:13:39 CET 2025
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.forissier at 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;
>>
>
More information about the U-Boot
mailing list