• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2012 The Chromium OS Authors.
4  *
5  * (C) Copyright 2011
6  * Joe Hershberger, National Instruments, joe.hershberger@ni.com
7  *
8  * (C) Copyright 2000
9  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
10  */
11 
12 #ifndef USE_HOSTCC
13 #include <common.h>
14 #include <command.h>
15 #include <malloc.h>
16 #include <mapmem.h>
17 #include <hw_sha.h>
18 #include <asm/io.h>
19 #include <linux/errno.h>
20 #else
21 #include "mkimage.h"
22 #include <time.h>
23 #include <image.h>
24 #endif /* !USE_HOSTCC*/
25 
26 #include <hash.h>
27 #include <u-boot/crc.h>
28 #include <u-boot/sha1.h>
29 #include <u-boot/sha256.h>
30 #include <u-boot/md5.h>
31 
32 #if defined(CONFIG_SHA1) && !defined(CONFIG_SHA_PROG_HW_ACCEL)
hash_init_sha1(struct hash_algo * algo,void ** ctxp)33 static int hash_init_sha1(struct hash_algo *algo, void **ctxp)
34 {
35 	sha1_context *ctx = malloc(sizeof(sha1_context));
36 	sha1_starts(ctx);
37 	*ctxp = ctx;
38 	return 0;
39 }
40 
hash_update_sha1(struct hash_algo * algo,void * ctx,const void * buf,unsigned int size,int is_last)41 static int hash_update_sha1(struct hash_algo *algo, void *ctx, const void *buf,
42 			    unsigned int size, int is_last)
43 {
44 	sha1_update((sha1_context *)ctx, buf, size);
45 	return 0;
46 }
47 
hash_finish_sha1(struct hash_algo * algo,void * ctx,void * dest_buf,int size)48 static int hash_finish_sha1(struct hash_algo *algo, void *ctx, void *dest_buf,
49 			    int size)
50 {
51 	if (size < algo->digest_size)
52 		return -1;
53 
54 	sha1_finish((sha1_context *)ctx, dest_buf);
55 	free(ctx);
56 	return 0;
57 }
58 #endif
59 
60 #if defined(CONFIG_SHA256) && !defined(CONFIG_SHA_PROG_HW_ACCEL)
hash_init_sha256(struct hash_algo * algo,void ** ctxp)61 static int hash_init_sha256(struct hash_algo *algo, void **ctxp)
62 {
63 	sha256_context *ctx = malloc(sizeof(sha256_context));
64 	sha256_starts(ctx);
65 	*ctxp = ctx;
66 	return 0;
67 }
68 
hash_update_sha256(struct hash_algo * algo,void * ctx,const void * buf,unsigned int size,int is_last)69 static int hash_update_sha256(struct hash_algo *algo, void *ctx,
70 			      const void *buf, unsigned int size, int is_last)
71 {
72 	sha256_update((sha256_context *)ctx, buf, size);
73 	return 0;
74 }
75 
hash_finish_sha256(struct hash_algo * algo,void * ctx,void * dest_buf,int size)76 static int hash_finish_sha256(struct hash_algo *algo, void *ctx, void
77 			      *dest_buf, int size)
78 {
79 	if (size < algo->digest_size)
80 		return -1;
81 
82 	sha256_finish((sha256_context *)ctx, dest_buf);
83 	free(ctx);
84 	return 0;
85 }
86 #endif
87 
hash_init_crc32(struct hash_algo * algo,void ** ctxp)88 static int hash_init_crc32(struct hash_algo *algo, void **ctxp)
89 {
90 	uint32_t *ctx = malloc(sizeof(uint32_t));
91 	*ctx = 0;
92 	*ctxp = ctx;
93 	return 0;
94 }
95 
hash_update_crc32(struct hash_algo * algo,void * ctx,const void * buf,unsigned int size,int is_last)96 static int hash_update_crc32(struct hash_algo *algo, void *ctx,
97 			     const void *buf, unsigned int size, int is_last)
98 {
99 	*((uint32_t *)ctx) = crc32(*((uint32_t *)ctx), buf, size);
100 	return 0;
101 }
102 
hash_finish_crc32(struct hash_algo * algo,void * ctx,void * dest_buf,int size)103 static int hash_finish_crc32(struct hash_algo *algo, void *ctx, void *dest_buf,
104 			     int size)
105 {
106 	if (size < algo->digest_size)
107 		return -1;
108 
109 	*((uint32_t *)dest_buf) = *((uint32_t *)ctx);
110 	free(ctx);
111 	return 0;
112 }
113 
114 /*
115  * These are the hash algorithms we support.  If we have hardware acceleration
116  * is enable we will use that, otherwise a software version of the algorithm.
117  * Note that algorithm names must be in lower case.
118  */
119 static struct hash_algo hash_algo[] = {
120 #ifdef CONFIG_SHA1
121 	{
122 		.name 		= "sha1",
123 		.digest_size	= SHA1_SUM_LEN,
124 		.chunk_size	= CHUNKSZ_SHA1,
125 #ifdef CONFIG_SHA_HW_ACCEL
126 		.hash_func_ws	= hw_sha1,
127 #else
128 		.hash_func_ws	= sha1_csum_wd,
129 #endif
130 #ifdef CONFIG_SHA_PROG_HW_ACCEL
131 		.hash_init	= hw_sha_init,
132 		.hash_update	= hw_sha_update,
133 		.hash_finish	= hw_sha_finish,
134 #else
135 		.hash_init	= hash_init_sha1,
136 		.hash_update	= hash_update_sha1,
137 		.hash_finish	= hash_finish_sha1,
138 #endif
139 	},
140 #endif
141 #ifdef CONFIG_SHA256
142 	{
143 		.name		= "sha256",
144 		.digest_size	= SHA256_SUM_LEN,
145 		.chunk_size	= CHUNKSZ_SHA256,
146 #ifdef CONFIG_SHA_HW_ACCEL
147 		.hash_func_ws	= hw_sha256,
148 #else
149 		.hash_func_ws	= sha256_csum_wd,
150 #endif
151 #ifdef CONFIG_SHA_PROG_HW_ACCEL
152 		.hash_init	= hw_sha_init,
153 		.hash_update	= hw_sha_update,
154 		.hash_finish	= hw_sha_finish,
155 #else
156 		.hash_init	= hash_init_sha256,
157 		.hash_update	= hash_update_sha256,
158 		.hash_finish	= hash_finish_sha256,
159 #endif
160 	},
161 #endif
162 	{
163 		.name		= "crc32",
164 		.digest_size	= 4,
165 		.chunk_size	= CHUNKSZ_CRC32,
166 		.hash_func_ws	= crc32_wd_buf,
167 		.hash_init	= hash_init_crc32,
168 		.hash_update	= hash_update_crc32,
169 		.hash_finish	= hash_finish_crc32,
170 	},
171 };
172 
173 /* Try to minimize code size for boards that don't want much hashing */
174 #if defined(CONFIG_SHA256) || defined(CONFIG_CMD_SHA1SUM) || \
175 	defined(CONFIG_CRC32_VERIFY) || defined(CONFIG_CMD_HASH)
176 #define multi_hash()	1
177 #else
178 #define multi_hash()	0
179 #endif
180 
hash_lookup_algo(const char * algo_name,struct hash_algo ** algop)181 int hash_lookup_algo(const char *algo_name, struct hash_algo **algop)
182 {
183 	int i;
184 
185 	for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
186 		if (!strcmp(algo_name, hash_algo[i].name)) {
187 			*algop = &hash_algo[i];
188 			return 0;
189 		}
190 	}
191 
192 	debug("Unknown hash algorithm '%s'\n", algo_name);
193 	return -EPROTONOSUPPORT;
194 }
195 
hash_progressive_lookup_algo(const char * algo_name,struct hash_algo ** algop)196 int hash_progressive_lookup_algo(const char *algo_name,
197 				 struct hash_algo **algop)
198 {
199 	int i;
200 
201 	for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
202 		if (!strcmp(algo_name, hash_algo[i].name)) {
203 			if (hash_algo[i].hash_init) {
204 				*algop = &hash_algo[i];
205 				return 0;
206 			}
207 		}
208 	}
209 
210 	debug("Unknown hash algorithm '%s'\n", algo_name);
211 	return -EPROTONOSUPPORT;
212 }
213 
214 #ifndef USE_HOSTCC
hash_parse_string(const char * algo_name,const char * str,uint8_t * result)215 int hash_parse_string(const char *algo_name, const char *str, uint8_t *result)
216 {
217 	struct hash_algo *algo;
218 	int ret;
219 	int i;
220 
221 	ret = hash_lookup_algo(algo_name, &algo);
222 	if (ret)
223 		return ret;
224 
225 	for (i = 0; i < algo->digest_size; i++) {
226 		char chr[3];
227 
228 		strncpy(chr, &str[i * 2], 2);
229 		result[i] = simple_strtoul(chr, NULL, 16);
230 	}
231 
232 	return 0;
233 }
234 
hash_block(const char * algo_name,const void * data,unsigned int len,uint8_t * output,int * output_size)235 int hash_block(const char *algo_name, const void *data, unsigned int len,
236 	       uint8_t *output, int *output_size)
237 {
238 	struct hash_algo *algo;
239 	int ret;
240 
241 	ret = hash_lookup_algo(algo_name, &algo);
242 	if (ret)
243 		return ret;
244 
245 	if (output_size && *output_size < algo->digest_size) {
246 		debug("Output buffer size %d too small (need %d bytes)",
247 		      *output_size, algo->digest_size);
248 		return -ENOSPC;
249 	}
250 	if (output_size)
251 		*output_size = algo->digest_size;
252 	algo->hash_func_ws(data, len, output, algo->chunk_size);
253 
254 	return 0;
255 }
256 
257 #if defined(CONFIG_CMD_HASH) || defined(CONFIG_CMD_SHA1SUM) || defined(CONFIG_CMD_CRC32)
258 /**
259  * store_result: Store the resulting sum to an address or variable
260  *
261  * @algo:		Hash algorithm being used
262  * @sum:		Hash digest (algo->digest_size bytes)
263  * @dest:		Destination, interpreted as a hex address if it starts
264  *			with * (or allow_env_vars is 0) or otherwise as an
265  *			environment variable.
266  * @allow_env_vars:	non-zero to permit storing the result to an
267  *			variable environment
268  */
store_result(struct hash_algo * algo,const uint8_t * sum,const char * dest,int allow_env_vars)269 static void store_result(struct hash_algo *algo, const uint8_t *sum,
270 			 const char *dest, int allow_env_vars)
271 {
272 	unsigned int i;
273 	int env_var = 0;
274 
275 	/*
276 	 * If environment variables are allowed, then we assume that 'dest'
277 	 * is an environment variable, unless it starts with *, in which
278 	 * case we assume it is an address. If not allowed, it is always an
279 	 * address. This is to support the crc32 command.
280 	 */
281 	if (allow_env_vars) {
282 		if (*dest == '*')
283 			dest++;
284 		else
285 			env_var = 1;
286 	}
287 
288 	if (env_var) {
289 		char str_output[HASH_MAX_DIGEST_SIZE * 2 + 1];
290 		char *str_ptr = str_output;
291 
292 		for (i = 0; i < algo->digest_size; i++) {
293 			sprintf(str_ptr, "%02x", sum[i]);
294 			str_ptr += 2;
295 		}
296 		*str_ptr = '\0';
297 		env_set(dest, str_output);
298 	} else {
299 		ulong addr;
300 		void *buf;
301 
302 		addr = simple_strtoul(dest, NULL, 16);
303 		buf = map_sysmem(addr, algo->digest_size);
304 		memcpy(buf, sum, algo->digest_size);
305 		unmap_sysmem(buf);
306 	}
307 }
308 
309 /**
310  * parse_verify_sum: Parse a hash verification parameter
311  *
312  * @algo:		Hash algorithm being used
313  * @verify_str:		Argument to parse. If it starts with * then it is
314  *			interpreted as a hex address containing the hash.
315  *			If the length is exactly the right number of hex digits
316  *			for the digest size, then we assume it is a hex digest.
317  *			Otherwise we assume it is an environment variable, and
318  *			look up its value (it must contain a hex digest).
319  * @vsum:		Returns binary digest value (algo->digest_size bytes)
320  * @allow_env_vars:	non-zero to permit storing the result to an environment
321  *			variable. If 0 then verify_str is assumed to be an
322  *			address, and the * prefix is not expected.
323  * @return 0 if ok, non-zero on error
324  */
parse_verify_sum(struct hash_algo * algo,char * verify_str,uint8_t * vsum,int allow_env_vars)325 static int parse_verify_sum(struct hash_algo *algo, char *verify_str,
326 			    uint8_t *vsum, int allow_env_vars)
327 {
328 	int env_var = 0;
329 
330 	/* See comment above in store_result() */
331 	if (allow_env_vars) {
332 		if (*verify_str == '*')
333 			verify_str++;
334 		else
335 			env_var = 1;
336 	}
337 
338 	if (!env_var) {
339 		ulong addr;
340 		void *buf;
341 
342 		addr = simple_strtoul(verify_str, NULL, 16);
343 		buf = map_sysmem(addr, algo->digest_size);
344 		memcpy(vsum, buf, algo->digest_size);
345 	} else {
346 		char *vsum_str;
347 		int digits = algo->digest_size * 2;
348 
349 		/*
350 		 * As with the original code from sha1sum.c, we assume that a
351 		 * string which matches the digest size exactly is a hex
352 		 * string and not an environment variable.
353 		 */
354 		if (strlen(verify_str) == digits)
355 			vsum_str = verify_str;
356 		else {
357 			vsum_str = env_get(verify_str);
358 			if (vsum_str == NULL || strlen(vsum_str) != digits) {
359 				printf("Expected %d hex digits in env var\n",
360 				       digits);
361 				return 1;
362 			}
363 		}
364 
365 		hash_parse_string(algo->name, vsum_str, vsum);
366 	}
367 	return 0;
368 }
369 
hash_show(struct hash_algo * algo,ulong addr,ulong len,uint8_t * output)370 static void hash_show(struct hash_algo *algo, ulong addr, ulong len, uint8_t *output)
371 {
372 	int i;
373 
374 	printf("%s for %08lx ... %08lx ==> ", algo->name, addr, addr + len - 1);
375 	for (i = 0; i < algo->digest_size; i++)
376 		printf("%02x", output[i]);
377 }
378 
hash_command(const char * algo_name,int flags,cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])379 int hash_command(const char *algo_name, int flags, cmd_tbl_t *cmdtp, int flag,
380 		 int argc, char * const argv[])
381 {
382 	ulong addr, len;
383 
384 	if ((argc < 2) || ((flags & HASH_FLAG_VERIFY) && (argc < 3)))
385 		return CMD_RET_USAGE;
386 
387 	addr = simple_strtoul(*argv++, NULL, 16);
388 	len = simple_strtoul(*argv++, NULL, 16);
389 
390 	if (multi_hash()) {
391 		struct hash_algo *algo;
392 		u8 *output;
393 		uint8_t vsum[HASH_MAX_DIGEST_SIZE];
394 		void *buf;
395 
396 		if (hash_lookup_algo(algo_name, &algo)) {
397 			printf("Unknown hash algorithm '%s'\n", algo_name);
398 			return CMD_RET_USAGE;
399 		}
400 		argc -= 2;
401 
402 		if (algo->digest_size > HASH_MAX_DIGEST_SIZE) {
403 			puts("HASH_MAX_DIGEST_SIZE exceeded\n");
404 			return 1;
405 		}
406 
407 		output = memalign(ARCH_DMA_MINALIGN,
408 				  sizeof(uint32_t) * HASH_MAX_DIGEST_SIZE);
409 
410 		buf = map_sysmem(addr, len);
411 		algo->hash_func_ws(buf, len, output, algo->chunk_size);
412 		unmap_sysmem(buf);
413 
414 		/* Try to avoid code bloat when verify is not needed */
415 #if defined(CONFIG_CRC32_VERIFY) || defined(CONFIG_SHA1SUM_VERIFY) || \
416 	defined(CONFIG_HASH_VERIFY)
417 		if (flags & HASH_FLAG_VERIFY) {
418 #else
419 		if (0) {
420 #endif
421 			if (parse_verify_sum(algo, *argv, vsum,
422 					flags & HASH_FLAG_ENV)) {
423 				printf("ERROR: %s does not contain a valid "
424 					"%s sum\n", *argv, algo->name);
425 				return 1;
426 			}
427 			if (memcmp(output, vsum, algo->digest_size) != 0) {
428 				int i;
429 
430 				hash_show(algo, addr, len, output);
431 				printf(" != ");
432 				for (i = 0; i < algo->digest_size; i++)
433 					printf("%02x", vsum[i]);
434 				puts(" ** ERROR **\n");
435 				return 1;
436 			}
437 		} else {
438 			hash_show(algo, addr, len, output);
439 			printf("\n");
440 
441 			if (argc) {
442 				store_result(algo, output, *argv,
443 					flags & HASH_FLAG_ENV);
444 			}
445 		unmap_sysmem(output);
446 
447 		}
448 
449 	/* Horrible code size hack for boards that just want crc32 */
450 	} else {
451 		ulong crc;
452 		ulong *ptr;
453 
454 		crc = crc32_wd(0, (const uchar *)addr, len, CHUNKSZ_CRC32);
455 
456 		printf("CRC32 for %08lx ... %08lx ==> %08lx\n",
457 				addr, addr + len - 1, crc);
458 
459 		if (argc >= 3) {
460 			ptr = (ulong *)simple_strtoul(argv[0], NULL, 16);
461 			*ptr = crc;
462 		}
463 	}
464 
465 	return 0;
466 }
467 #endif /* CONFIG_CMD_HASH || CONFIG_CMD_SHA1SUM || CONFIG_CMD_CRC32) */
468 #endif /* !USE_HOSTCC */
469