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