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.
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;