1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2013, Google Inc.
4  */
5 
6 #ifdef USE_HOSTCC
7 #include "mkimage.h"
8 #include <time.h>
9 #else
10 #include <common.h>
11 #include <log.h>
12 #include <malloc.h>
13 #include <asm/global_data.h>
14 DECLARE_GLOBAL_DATA_PTR;
15 #endif /* !USE_HOSTCC*/
16 #include <fdt_region.h>
17 #include <image.h>
18 #include <u-boot/rsa.h>
19 #include <u-boot/hash-checksum.h>
20 
21 #define IMAGE_MAX_HASHED_NODES		100
22 
23 /**
24  * fit_region_make_list() - Make a list of image regions
25  *
26  * Given a list of fdt_regions, create a list of image_regions. This is a
27  * simple conversion routine since the FDT and image code use different
28  * structures.
29  *
30  * @fit: FIT image
31  * @fdt_regions: Pointer to FDT regions
32  * @count: Number of FDT regions
33  * @region: Pointer to image regions, which must hold @count records. If
34  * region is NULL, then (except for an SPL build) the array will be
35  * allocated.
36  * @return: Pointer to image regions
37  */
fit_region_make_list(const void * fit,struct fdt_region * fdt_regions,int count,struct image_region * region)38 struct image_region *fit_region_make_list(const void *fit,
39 					  struct fdt_region *fdt_regions,
40 					  int count,
41 					  struct image_region *region)
42 {
43 	int i;
44 
45 	debug("Hash regions:\n");
46 	debug("%10s %10s\n", "Offset", "Size");
47 
48 	/*
49 	 * Use malloc() except in SPL (to save code size). In SPL the caller
50 	 * must allocate the array.
51 	 */
52 	if (!IS_ENABLED(CONFIG_SPL_BUILD) && !region)
53 		region = calloc(sizeof(*region), count);
54 	if (!region)
55 		return NULL;
56 	for (i = 0; i < count; i++) {
57 		debug("%10x %10x\n", fdt_regions[i].offset,
58 		      fdt_regions[i].size);
59 		region[i].data = fit + fdt_regions[i].offset;
60 		region[i].size = fdt_regions[i].size;
61 	}
62 
63 	return region;
64 }
65 
fit_image_setup_verify(struct image_sign_info * info,const void * fit,int noffset,int required_keynode,char ** err_msgp)66 static int fit_image_setup_verify(struct image_sign_info *info,
67 				  const void *fit, int noffset,
68 				  int required_keynode, char **err_msgp)
69 {
70 	char *algo_name;
71 	const char *padding_name;
72 
73 	if (fdt_totalsize(fit) > CONFIG_VAL(FIT_SIGNATURE_MAX_SIZE)) {
74 		*err_msgp = "Total size too large";
75 		return 1;
76 	}
77 	if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
78 		*err_msgp = "Can't get hash algo property";
79 		return -1;
80 	}
81 
82 	padding_name = fdt_getprop(fit, noffset, "padding", NULL);
83 	if (!padding_name)
84 		padding_name = RSA_DEFAULT_PADDING_NAME;
85 
86 	memset(info, '\0', sizeof(*info));
87 	info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
88 	info->fit = fit;
89 	info->node_offset = noffset;
90 	info->name = algo_name;
91 	info->checksum = image_get_checksum_algo(algo_name);
92 	info->crypto = image_get_crypto_algo(algo_name);
93 	info->padding = image_get_padding_algo(padding_name);
94 	info->fdt_blob = gd_fdt_blob();
95 	info->required_keynode = required_keynode;
96 	printf("%s:%s", algo_name, info->keyname);
97 
98 	if (!info->checksum || !info->crypto || !info->padding) {
99 		*err_msgp = "Unknown signature algorithm";
100 		return -1;
101 	}
102 
103 	return 0;
104 }
105 
fit_image_check_sig(const void * fit,int noffset,const void * data,size_t size,int required_keynode,char ** err_msgp)106 int fit_image_check_sig(const void *fit, int noffset, const void *data,
107 			size_t size, int required_keynode, char **err_msgp)
108 {
109 	struct image_sign_info info;
110 	struct image_region region;
111 	uint8_t *fit_value;
112 	int fit_value_len;
113 
114 	*err_msgp = NULL;
115 	if (fit_image_setup_verify(&info, fit, noffset, required_keynode,
116 				   err_msgp))
117 		return -1;
118 
119 	if (fit_image_hash_get_value(fit, noffset, &fit_value,
120 				     &fit_value_len)) {
121 		*err_msgp = "Can't get hash value property";
122 		return -1;
123 	}
124 
125 	region.data = data;
126 	region.size = size;
127 
128 	if (info.crypto->verify(&info, &region, 1, fit_value, fit_value_len)) {
129 		*err_msgp = "Verification failed";
130 		return -1;
131 	}
132 
133 	return 0;
134 }
135 
fit_image_verify_sig(const void * fit,int image_noffset,const char * data,size_t size,const void * sig_blob,int sig_offset)136 static int fit_image_verify_sig(const void *fit, int image_noffset,
137 				const char *data, size_t size,
138 				const void *sig_blob, int sig_offset)
139 {
140 	int noffset;
141 	char *err_msg = "";
142 	int verified = 0;
143 	int ret;
144 
145 	/* Process all hash subnodes of the component image node */
146 	fdt_for_each_subnode(noffset, fit, image_noffset) {
147 		const char *name = fit_get_name(fit, noffset, NULL);
148 
149 		/*
150 		 * We don't support this since libfdt considers names with the
151 		 * name root but different @ suffix to be equal
152 		 */
153 		if (strchr(name, '@')) {
154 			err_msg = "Node name contains @";
155 			goto error;
156 		}
157 		if (!strncmp(name, FIT_SIG_NODENAME,
158 			     strlen(FIT_SIG_NODENAME))) {
159 			ret = fit_image_check_sig(fit, noffset, data,
160 						  size, -1, &err_msg);
161 			if (ret) {
162 				puts("- ");
163 			} else {
164 				puts("+ ");
165 				verified = 1;
166 				break;
167 			}
168 		}
169 	}
170 
171 	if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
172 		err_msg = "Corrupted or truncated tree";
173 		goto error;
174 	}
175 
176 	return verified ? 0 : -EPERM;
177 
178 error:
179 	printf(" error!\n%s for '%s' hash node in '%s' image node\n",
180 	       err_msg, fit_get_name(fit, noffset, NULL),
181 	       fit_get_name(fit, image_noffset, NULL));
182 	return -1;
183 }
184 
fit_image_verify_required_sigs(const void * fit,int image_noffset,const char * data,size_t size,const void * sig_blob,int * no_sigsp)185 int fit_image_verify_required_sigs(const void *fit, int image_noffset,
186 				   const char *data, size_t size,
187 				   const void *sig_blob, int *no_sigsp)
188 {
189 	int verify_count = 0;
190 	int noffset;
191 	int sig_node;
192 
193 	/* Work out what we need to verify */
194 	*no_sigsp = 1;
195 	sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
196 	if (sig_node < 0) {
197 		debug("%s: No signature node found: %s\n", __func__,
198 		      fdt_strerror(sig_node));
199 		return 0;
200 	}
201 
202 	fdt_for_each_subnode(noffset, sig_blob, sig_node) {
203 		const char *required;
204 		int ret;
205 
206 		required = fdt_getprop(sig_blob, noffset, FIT_KEY_REQUIRED,
207 				       NULL);
208 		if (!required || strcmp(required, "image"))
209 			continue;
210 		ret = fit_image_verify_sig(fit, image_noffset, data, size,
211 					   sig_blob, noffset);
212 		if (ret) {
213 			printf("Failed to verify required signature '%s'\n",
214 			       fit_get_name(sig_blob, noffset, NULL));
215 			return ret;
216 		}
217 		verify_count++;
218 	}
219 
220 	if (verify_count)
221 		*no_sigsp = 0;
222 
223 	return 0;
224 }
225 
226 /**
227  * fit_config_check_sig() - Check the signature of a config
228  *
229  * @fit: FIT to check
230  * @noffset: Offset of configuration node (e.g. /configurations/conf-1)
231  * @required_keynode:	Offset in the control FDT of the required key node,
232  *			if any. If this is given, then the configuration wil not
233  *			pass verification unless that key is used. If this is
234  *			-1 then any signature will do.
235  * @conf_noffset: Offset of the configuration subnode being checked (e.g.
236  *	 /configurations/conf-1/kernel)
237  * @err_msgp:		In the event of an error, this will be pointed to a
238  *			help error string to display to the user.
239  * @return 0 if all verified ok, <0 on error
240  */
fit_config_check_sig(const void * fit,int noffset,int required_keynode,int conf_noffset,char ** err_msgp)241 static int fit_config_check_sig(const void *fit, int noffset,
242 				int required_keynode, int conf_noffset,
243 				char **err_msgp)
244 {
245 	static char * const exc_prop[] = {
246 		"data",
247 		"data-size",
248 		"data-position",
249 		"data-offset"
250 	};
251 
252 	const char *prop, *end, *name;
253 	struct image_sign_info info;
254 	const uint32_t *strings;
255 	const char *config_name;
256 	uint8_t *fit_value;
257 	int fit_value_len;
258 	bool found_config;
259 	int max_regions;
260 	int i, prop_len;
261 	char path[200];
262 	int count;
263 
264 	config_name = fit_get_name(fit, conf_noffset, NULL);
265 	debug("%s: fdt=%p, conf='%s', sig='%s'\n", __func__, gd_fdt_blob(),
266 	      fit_get_name(fit, noffset, NULL),
267 	      fit_get_name(gd_fdt_blob(), required_keynode, NULL));
268 	*err_msgp = NULL;
269 	if (fit_image_setup_verify(&info, fit, noffset, required_keynode,
270 				   err_msgp))
271 		return -1;
272 
273 	if (fit_image_hash_get_value(fit, noffset, &fit_value,
274 				     &fit_value_len)) {
275 		*err_msgp = "Can't get hash value property";
276 		return -1;
277 	}
278 
279 	/* Count the number of strings in the property */
280 	prop = fdt_getprop(fit, noffset, "hashed-nodes", &prop_len);
281 	end = prop ? prop + prop_len : prop;
282 	for (name = prop, count = 0; name < end; name++)
283 		if (!*name)
284 			count++;
285 	if (!count) {
286 		*err_msgp = "Can't get hashed-nodes property";
287 		return -1;
288 	}
289 
290 	if (prop && prop_len > 0 && prop[prop_len - 1] != '\0') {
291 		*err_msgp = "hashed-nodes property must be null-terminated";
292 		return -1;
293 	}
294 
295 	/* Add a sanity check here since we are using the stack */
296 	if (count > IMAGE_MAX_HASHED_NODES) {
297 		*err_msgp = "Number of hashed nodes exceeds maximum";
298 		return -1;
299 	}
300 
301 	/* Create a list of node names from those strings */
302 	char *node_inc[count];
303 
304 	debug("Hash nodes (%d):\n", count);
305 	found_config = false;
306 	for (name = prop, i = 0; name < end; name += strlen(name) + 1, i++) {
307 		debug("   '%s'\n", name);
308 		node_inc[i] = (char *)name;
309 		if (!strncmp(FIT_CONFS_PATH, name, strlen(FIT_CONFS_PATH)) &&
310 		    name[sizeof(FIT_CONFS_PATH) - 1] == '/' &&
311 		    !strcmp(name + sizeof(FIT_CONFS_PATH), config_name)) {
312 			debug("      (found config node %s)", config_name);
313 			found_config = true;
314 		}
315 	}
316 	if (!found_config) {
317 		*err_msgp = "Selected config not in hashed nodes";
318 		return -1;
319 	}
320 
321 	/*
322 	 * Each node can generate one region for each sub-node. Allow for
323 	 * 7 sub-nodes (hash-1, signature-1, etc.) and some extra.
324 	 */
325 	max_regions = 20 + count * 7;
326 	struct fdt_region fdt_regions[max_regions];
327 
328 	/* Get a list of regions to hash */
329 	count = fdt_find_regions(fit, node_inc, count,
330 				 exc_prop, ARRAY_SIZE(exc_prop),
331 				 fdt_regions, max_regions - 1,
332 				 path, sizeof(path), 0);
333 	if (count < 0) {
334 		*err_msgp = "Failed to hash configuration";
335 		return -1;
336 	}
337 	if (count == 0) {
338 		*err_msgp = "No data to hash";
339 		return -1;
340 	}
341 	if (count >= max_regions - 1) {
342 		*err_msgp = "Too many hash regions";
343 		return -1;
344 	}
345 
346 	/* Add the strings */
347 	strings = fdt_getprop(fit, noffset, "hashed-strings", NULL);
348 	if (strings) {
349 		/*
350 		 * The strings region offset must be a static 0x0.
351 		 * This is set in tool/image-host.c
352 		 */
353 		fdt_regions[count].offset = fdt_off_dt_strings(fit);
354 		fdt_regions[count].size = fdt32_to_cpu(strings[1]);
355 		count++;
356 	}
357 
358 	/* Allocate the region list on the stack */
359 	struct image_region region[count];
360 
361 	fit_region_make_list(fit, fdt_regions, count, region);
362 	if (info.crypto->verify(&info, region, count, fit_value,
363 				fit_value_len)) {
364 		*err_msgp = "Verification failed";
365 		return -1;
366 	}
367 
368 	return 0;
369 }
370 
fit_config_verify_sig(const void * fit,int conf_noffset,const void * sig_blob,int sig_offset)371 static int fit_config_verify_sig(const void *fit, int conf_noffset,
372 				 const void *sig_blob, int sig_offset)
373 {
374 	int noffset;
375 	char *err_msg = "No 'signature' subnode found";
376 	int verified = 0;
377 	int ret;
378 
379 	/* Process all hash subnodes of the component conf node */
380 	fdt_for_each_subnode(noffset, fit, conf_noffset) {
381 		const char *name = fit_get_name(fit, noffset, NULL);
382 
383 		if (!strncmp(name, FIT_SIG_NODENAME,
384 			     strlen(FIT_SIG_NODENAME))) {
385 			ret = fit_config_check_sig(fit, noffset, sig_offset,
386 						   conf_noffset, &err_msg);
387 			if (ret) {
388 				puts("- ");
389 			} else {
390 				puts("+ ");
391 				verified = 1;
392 				break;
393 			}
394 		}
395 	}
396 
397 	if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
398 		err_msg = "Corrupted or truncated tree";
399 		goto error;
400 	}
401 
402 	if (verified)
403 		return 0;
404 
405 error:
406 	printf(" error!\n%s for '%s' hash node in '%s' config node\n",
407 	       err_msg, fit_get_name(fit, noffset, NULL),
408 	       fit_get_name(fit, conf_noffset, NULL));
409 	return -EPERM;
410 }
411 
fit_config_verify_required_sigs(const void * fit,int conf_noffset,const void * sig_blob)412 static int fit_config_verify_required_sigs(const void *fit, int conf_noffset,
413 					   const void *sig_blob)
414 {
415 	const char *name = fit_get_name(fit, conf_noffset, NULL);
416 	int noffset;
417 	int sig_node;
418 	int verified = 0;
419 	int reqd_sigs = 0;
420 	bool reqd_policy_all = true;
421 	const char *reqd_mode;
422 
423 	/*
424 	 * We don't support this since libfdt considers names with the
425 	 * name root but different @ suffix to be equal
426 	 */
427 	if (strchr(name, '@')) {
428 		printf("Configuration node '%s' contains '@'\n", name);
429 		return -EPERM;
430 	}
431 
432 	/* Work out what we need to verify */
433 	sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
434 	if (sig_node < 0) {
435 		debug("%s: No signature node found: %s\n", __func__,
436 		      fdt_strerror(sig_node));
437 		return 0;
438 	}
439 
440 	/* Get required-mode policy property from DTB */
441 	reqd_mode = fdt_getprop(sig_blob, sig_node, "required-mode", NULL);
442 	if (reqd_mode && !strcmp(reqd_mode, "any"))
443 		reqd_policy_all = false;
444 
445 	debug("%s: required-mode policy set to '%s'\n", __func__,
446 	      reqd_policy_all ? "all" : "any");
447 
448 	fdt_for_each_subnode(noffset, sig_blob, sig_node) {
449 		const char *required;
450 		int ret;
451 
452 		required = fdt_getprop(sig_blob, noffset, FIT_KEY_REQUIRED,
453 				       NULL);
454 		if (!required || strcmp(required, "conf"))
455 			continue;
456 
457 		reqd_sigs++;
458 
459 		ret = fit_config_verify_sig(fit, conf_noffset, sig_blob,
460 					    noffset);
461 		if (ret) {
462 			if (reqd_policy_all) {
463 				printf("Failed to verify required signature '%s'\n",
464 				       fit_get_name(sig_blob, noffset, NULL));
465 				return ret;
466 			}
467 		} else {
468 			verified++;
469 			if (!reqd_policy_all)
470 				break;
471 		}
472 	}
473 
474 	if (reqd_sigs && !verified) {
475 		printf("Failed to verify 'any' of the required signature(s)\n");
476 		return -EPERM;
477 	}
478 
479 	return 0;
480 }
481 
fit_config_verify(const void * fit,int conf_noffset)482 int fit_config_verify(const void *fit, int conf_noffset)
483 {
484 	return fit_config_verify_required_sigs(fit, conf_noffset,
485 					       gd_fdt_blob());
486 }
487