blob: fc9bc11cd83ebd5b0fd242b15dace66cbe8dd985 [file] [log] [blame]
Jerome Forissier53a7e982025-06-25 15:19:12 +02001// SPDX-License-Identifier: GPL-2.0+
2/* Copyright (C) 2024-2025 Linaro Ltd. */
3
4#include <command.h>
Jerome Forissier2df664a2025-06-25 15:19:13 +02005#include <env.h>
6#include <image.h>
Jerome Forissier53a7e982025-06-25 15:19:12 +02007#include <net.h>
Jerome Forissier2df664a2025-06-25 15:19:13 +02008#include <lwip/altcp_tls.h>
Jerome Forissier53a7e982025-06-25 15:19:12 +02009
10U_BOOT_CMD(wget, 4, 1, do_wget,
11 "boot image via network using HTTP/HTTPS protocol"
12#if defined(CONFIG_WGET_CACERT)
13 "\nwget cacert - configure wget root certificates"
14#endif
15 ,
16 "[loadAddress] url\n"
17 "wget [loadAddress] [host:]path\n"
18 " - load file"
19#if defined(CONFIG_WGET_CACERT)
20 "\nwget cacert <address> <length>\n"
21 " - provide CA certificates (0 0 to remove current)"
22 "\nwget cacert none|optional|required\n"
23 " - set server certificate verification mode (default: optional)"
24#if defined(CONFIG_WGET_BUILTIN_CACERT)
25 "\nwget cacert builtin\n"
26 " - use the builtin CA certificates"
27#endif
28#endif
29);
Jerome Forissier2df664a2025-06-25 15:19:13 +020030
31#if CONFIG_IS_ENABLED(WGET_CACERT) || CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT)
32char *cacert;
33size_t cacert_size;
34enum auth_mode cacert_auth_mode = AUTH_OPTIONAL;
35
36#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT)
37extern const char builtin_cacert[];
38extern const size_t builtin_cacert_size;
39bool cacert_initialized;
40#endif
41
42static int _set_cacert(const void *addr, size_t sz)
43{
44 mbedtls_x509_crt crt;
45 void *p;
46 int ret;
47
48 if (cacert)
49 free(cacert);
50
51 if (!addr) {
52 cacert = NULL;
53 cacert_size = 0;
54 return CMD_RET_SUCCESS;
55 }
56
57 p = malloc(sz);
58 if (!p)
59 return CMD_RET_FAILURE;
60 cacert = p;
61 cacert_size = sz;
62
63 memcpy(cacert, (void *)addr, sz);
64
65 mbedtls_x509_crt_init(&crt);
66 ret = mbedtls_x509_crt_parse(&crt, cacert, cacert_size);
67 if (ret) {
68 if (!wget_info->silent)
69 printf("Could not parse certificates (%d)\n", ret);
70 free(cacert);
71 cacert = NULL;
72 cacert_size = 0;
73 return CMD_RET_FAILURE;
74 }
75
76#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT)
77 cacert_initialized = true;
78#endif
79 return CMD_RET_SUCCESS;
80}
81
82#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT)
83int set_cacert_builtin(void)
84{
85 cacert_auth_mode = AUTH_REQUIRED;
86 return _set_cacert(builtin_cacert, builtin_cacert_size);
87}
88#endif
89#endif /* CONFIG_WGET_CACERT || CONFIG_WGET_BUILTIN_CACERT */
90
91#if CONFIG_IS_ENABLED(WGET_CACERT)
92static int set_auth(enum auth_mode auth)
93{
94 cacert_auth_mode = auth;
95
96 return CMD_RET_SUCCESS;
97}
98
99static int set_cacert(char * const saddr, char * const ssz)
100{
101 ulong addr, sz;
102
103 addr = hextoul(saddr, NULL);
104 sz = hextoul(ssz, NULL);
105
106 return _set_cacert((void *)addr, sz);
107}
108#endif
109
110/*
111 * Legacy syntax support
112 * Convert [<server_name_or_ip>:]filename into a URL if needed
113 */
114static int parse_legacy_arg(char *arg, char *nurl, size_t rem)
115{
116 char *p = nurl;
117 size_t n;
118 char *col = strchr(arg, ':');
119 char *env;
120 char *server;
121 char *path;
122
123 if (strstr(arg, "http") == arg) {
124 n = snprintf(nurl, rem, "%s", arg);
125 if (n < 0 || n > rem)
126 return -1;
127 return 0;
128 }
129
130 n = snprintf(p, rem, "%s", "http://");
131 if (n < 0 || n > rem)
132 return -1;
133 p += n;
134 rem -= n;
135
136 if (col) {
137 n = col - arg;
138 server = arg;
139 path = col + 1;
140 } else {
141 env = env_get("httpserverip");
142 if (!env)
143 env = env_get("serverip");
144 if (!env) {
145 log_err("error: httpserver/serverip has to be set\n");
146 return -1;
147 }
148 n = strlen(env);
149 server = env;
150 path = arg;
151 }
152
153 if (rem < n)
154 return -1;
155 strncpy(p, server, n);
156 p += n;
157 rem -= n;
158 if (rem < 1)
159 return -1;
160 *p = '/';
161 p++;
162 rem--;
163 n = strlen(path);
164 if (rem < n)
165 return -1;
166 strncpy(p, path, n);
167 p += n;
168 rem -= n;
169 if (rem < 1)
170 return -1;
171 *p = '\0';
172
173 return 0;
174}
175
176int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
177{
178 char *end;
179 char *url;
180 ulong dst_addr;
181 char nurl[1024];
182
183#if CONFIG_IS_ENABLED(WGET_CACERT)
184 if (argc == 4 && !strncmp(argv[1], "cacert", strlen("cacert")))
185 return set_cacert(argv[2], argv[3]);
186 if (argc == 3 && !strncmp(argv[1], "cacert", strlen("cacert"))) {
187#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT)
188 if (!strncmp(argv[2], "builtin", strlen("builtin")))
189 return set_cacert_builtin();
190#endif
191 if (!strncmp(argv[2], "none", strlen("none")))
192 return set_auth(AUTH_NONE);
193 if (!strncmp(argv[2], "optional", strlen("optional")))
194 return set_auth(AUTH_OPTIONAL);
195 if (!strncmp(argv[2], "required", strlen("required")))
196 return set_auth(AUTH_REQUIRED);
197 return CMD_RET_USAGE;
198 }
199#endif
200
201 if (argc < 2 || argc > 3)
202 return CMD_RET_USAGE;
203
204 dst_addr = hextoul(argv[1], &end);
205 if (end == (argv[1] + strlen(argv[1]))) {
206 if (argc < 3)
207 return CMD_RET_USAGE;
208 url = argv[2];
209 } else {
210 dst_addr = image_load_addr;
211 url = argv[1];
212 }
213
214 if (parse_legacy_arg(url, nurl, sizeof(nurl)))
215 return CMD_RET_FAILURE;
216
217 wget_info = &default_wget_info;
218 if (wget_do_request(dst_addr, nurl))
219 return CMD_RET_FAILURE;
220
221 return CMD_RET_SUCCESS;
222}