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;


Reply via email to