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