xref: /openbmc/u-boot/common/hash.c (revision f6877372)
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 #ifdef CONFIG_SHA1
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 #ifdef CONFIG_SHA256
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. Chips which support accelerated
117  * crypto could perhaps add named version of these algorithms here. Note that
118  * algorithm names must be in lower case.
119  */
120 static struct hash_algo hash_algo[] = {
121 	/*
122 	 * CONFIG_SHA_HW_ACCEL is defined if hardware acceleration is
123 	 * available.
124 	 */
125 #ifdef CONFIG_SHA_HW_ACCEL
126 	{
127 		"sha1",
128 		SHA1_SUM_LEN,
129 		hw_sha1,
130 		CHUNKSZ_SHA1,
131 #ifdef CONFIG_SHA_PROG_HW_ACCEL
132 		hw_sha_init,
133 		hw_sha_update,
134 		hw_sha_finish,
135 #endif
136 	}, {
137 		"sha256",
138 		SHA256_SUM_LEN,
139 		hw_sha256,
140 		CHUNKSZ_SHA256,
141 #ifdef CONFIG_SHA_PROG_HW_ACCEL
142 		hw_sha_init,
143 		hw_sha_update,
144 		hw_sha_finish,
145 #endif
146 	},
147 #endif
148 #ifdef CONFIG_SHA1
149 	{
150 		"sha1",
151 		SHA1_SUM_LEN,
152 		sha1_csum_wd,
153 		CHUNKSZ_SHA1,
154 		hash_init_sha1,
155 		hash_update_sha1,
156 		hash_finish_sha1,
157 	},
158 #endif
159 #ifdef CONFIG_SHA256
160 	{
161 		"sha256",
162 		SHA256_SUM_LEN,
163 		sha256_csum_wd,
164 		CHUNKSZ_SHA256,
165 		hash_init_sha256,
166 		hash_update_sha256,
167 		hash_finish_sha256,
168 	},
169 #endif
170 	{
171 		"crc32",
172 		4,
173 		crc32_wd_buf,
174 		CHUNKSZ_CRC32,
175 		hash_init_crc32,
176 		hash_update_crc32,
177 		hash_finish_crc32,
178 	},
179 };
180 
181 /* Try to minimize code size for boards that don't want much hashing */
182 #if defined(CONFIG_SHA256) || defined(CONFIG_CMD_SHA1SUM) || \
183 	defined(CONFIG_CRC32_VERIFY) || defined(CONFIG_CMD_HASH)
184 #define multi_hash()	1
185 #else
186 #define multi_hash()	0
187 #endif
188 
189 int hash_lookup_algo(const char *algo_name, struct hash_algo **algop)
190 {
191 	int i;
192 
193 	for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
194 		if (!strcmp(algo_name, hash_algo[i].name)) {
195 			*algop = &hash_algo[i];
196 			return 0;
197 		}
198 	}
199 
200 	debug("Unknown hash algorithm '%s'\n", algo_name);
201 	return -EPROTONOSUPPORT;
202 }
203 
204 int hash_progressive_lookup_algo(const char *algo_name,
205 				 struct hash_algo **algop)
206 {
207 	int i;
208 
209 	for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
210 		if (!strcmp(algo_name, hash_algo[i].name)) {
211 			if (hash_algo[i].hash_init) {
212 				*algop = &hash_algo[i];
213 				return 0;
214 			}
215 		}
216 	}
217 
218 	debug("Unknown hash algorithm '%s'\n", algo_name);
219 	return -EPROTONOSUPPORT;
220 }
221 
222 #ifndef USE_HOSTCC
223 int hash_parse_string(const char *algo_name, const char *str, uint8_t *result)
224 {
225 	struct hash_algo *algo;
226 	int ret;
227 	int i;
228 
229 	ret = hash_lookup_algo(algo_name, &algo);
230 	if (ret)
231 		return ret;
232 
233 	for (i = 0; i < algo->digest_size; i++) {
234 		char chr[3];
235 
236 		strncpy(chr, &str[i * 2], 2);
237 		result[i] = simple_strtoul(chr, NULL, 16);
238 	}
239 
240 	return 0;
241 }
242 
243 int hash_block(const char *algo_name, const void *data, unsigned int len,
244 	       uint8_t *output, int *output_size)
245 {
246 	struct hash_algo *algo;
247 	int ret;
248 
249 	ret = hash_lookup_algo(algo_name, &algo);
250 	if (ret)
251 		return ret;
252 
253 	if (output_size && *output_size < algo->digest_size) {
254 		debug("Output buffer size %d too small (need %d bytes)",
255 		      *output_size, algo->digest_size);
256 		return -ENOSPC;
257 	}
258 	if (output_size)
259 		*output_size = algo->digest_size;
260 	algo->hash_func_ws(data, len, output, algo->chunk_size);
261 
262 	return 0;
263 }
264 
265 #if defined(CONFIG_CMD_HASH) || defined(CONFIG_CMD_SHA1SUM) || defined(CONFIG_CMD_CRC32)
266 /**
267  * store_result: Store the resulting sum to an address or variable
268  *
269  * @algo:		Hash algorithm being used
270  * @sum:		Hash digest (algo->digest_size bytes)
271  * @dest:		Destination, interpreted as a hex address if it starts
272  *			with * (or allow_env_vars is 0) or otherwise as an
273  *			environment variable.
274  * @allow_env_vars:	non-zero to permit storing the result to an
275  *			variable environment
276  */
277 static void store_result(struct hash_algo *algo, const uint8_t *sum,
278 			 const char *dest, int allow_env_vars)
279 {
280 	unsigned int i;
281 	int env_var = 0;
282 
283 	/*
284 	 * If environment variables are allowed, then we assume that 'dest'
285 	 * is an environment variable, unless it starts with *, in which
286 	 * case we assume it is an address. If not allowed, it is always an
287 	 * address. This is to support the crc32 command.
288 	 */
289 	if (allow_env_vars) {
290 		if (*dest == '*')
291 			dest++;
292 		else
293 			env_var = 1;
294 	}
295 
296 	if (env_var) {
297 		char str_output[HASH_MAX_DIGEST_SIZE * 2 + 1];
298 		char *str_ptr = str_output;
299 
300 		for (i = 0; i < algo->digest_size; i++) {
301 			sprintf(str_ptr, "%02x", sum[i]);
302 			str_ptr += 2;
303 		}
304 		*str_ptr = '\0';
305 		setenv(dest, str_output);
306 	} else {
307 		ulong addr;
308 		void *buf;
309 
310 		addr = simple_strtoul(dest, NULL, 16);
311 		buf = map_sysmem(addr, algo->digest_size);
312 		memcpy(buf, sum, algo->digest_size);
313 		unmap_sysmem(buf);
314 	}
315 }
316 
317 /**
318  * parse_verify_sum: Parse a hash verification parameter
319  *
320  * @algo:		Hash algorithm being used
321  * @verify_str:		Argument to parse. If it starts with * then it is
322  *			interpreted as a hex address containing the hash.
323  *			If the length is exactly the right number of hex digits
324  *			for the digest size, then we assume it is a hex digest.
325  *			Otherwise we assume it is an environment variable, and
326  *			look up its value (it must contain a hex digest).
327  * @vsum:		Returns binary digest value (algo->digest_size bytes)
328  * @allow_env_vars:	non-zero to permit storing the result to an environment
329  *			variable. If 0 then verify_str is assumed to be an
330  *			address, and the * prefix is not expected.
331  * @return 0 if ok, non-zero on error
332  */
333 static int parse_verify_sum(struct hash_algo *algo, char *verify_str,
334 			    uint8_t *vsum, int allow_env_vars)
335 {
336 	int env_var = 0;
337 
338 	/* See comment above in store_result() */
339 	if (allow_env_vars) {
340 		if (*verify_str == '*')
341 			verify_str++;
342 		else
343 			env_var = 1;
344 	}
345 
346 	if (!env_var) {
347 		ulong addr;
348 		void *buf;
349 
350 		addr = simple_strtoul(verify_str, NULL, 16);
351 		buf = map_sysmem(addr, algo->digest_size);
352 		memcpy(vsum, buf, algo->digest_size);
353 	} else {
354 		char *vsum_str;
355 		int digits = algo->digest_size * 2;
356 
357 		/*
358 		 * As with the original code from sha1sum.c, we assume that a
359 		 * string which matches the digest size exactly is a hex
360 		 * string and not an environment variable.
361 		 */
362 		if (strlen(verify_str) == digits)
363 			vsum_str = verify_str;
364 		else {
365 			vsum_str = getenv(verify_str);
366 			if (vsum_str == NULL || strlen(vsum_str) != digits) {
367 				printf("Expected %d hex digits in env var\n",
368 				       digits);
369 				return 1;
370 			}
371 		}
372 
373 		hash_parse_string(algo->name, vsum_str, vsum);
374 	}
375 	return 0;
376 }
377 
378 static void hash_show(struct hash_algo *algo, ulong addr, ulong len, uint8_t *output)
379 {
380 	int i;
381 
382 	printf("%s for %08lx ... %08lx ==> ", algo->name, addr, addr + len - 1);
383 	for (i = 0; i < algo->digest_size; i++)
384 		printf("%02x", output[i]);
385 }
386 
387 int hash_command(const char *algo_name, int flags, cmd_tbl_t *cmdtp, int flag,
388 		 int argc, char * const argv[])
389 {
390 	ulong addr, len;
391 
392 	if ((argc < 2) || ((flags & HASH_FLAG_VERIFY) && (argc < 3)))
393 		return CMD_RET_USAGE;
394 
395 	addr = simple_strtoul(*argv++, NULL, 16);
396 	len = simple_strtoul(*argv++, NULL, 16);
397 
398 	if (multi_hash()) {
399 		struct hash_algo *algo;
400 		uint8_t output[HASH_MAX_DIGEST_SIZE];
401 		uint8_t vsum[HASH_MAX_DIGEST_SIZE];
402 		void *buf;
403 
404 		if (hash_lookup_algo(algo_name, &algo)) {
405 			printf("Unknown hash algorithm '%s'\n", algo_name);
406 			return CMD_RET_USAGE;
407 		}
408 		argc -= 2;
409 
410 		if (algo->digest_size > HASH_MAX_DIGEST_SIZE) {
411 			puts("HASH_MAX_DIGEST_SIZE exceeded\n");
412 			return 1;
413 		}
414 
415 		buf = map_sysmem(addr, len);
416 		algo->hash_func_ws(buf, len, output, algo->chunk_size);
417 		unmap_sysmem(buf);
418 
419 		/* Try to avoid code bloat when verify is not needed */
420 #if defined(CONFIG_CRC32_VERIFY) || defined(CONFIG_SHA1SUM_VERIFY) || \
421 	defined(CONFIG_HASH_VERIFY)
422 		if (flags & HASH_FLAG_VERIFY) {
423 #else
424 		if (0) {
425 #endif
426 			if (parse_verify_sum(algo, *argv, vsum,
427 					flags & HASH_FLAG_ENV)) {
428 				printf("ERROR: %s does not contain a valid "
429 					"%s sum\n", *argv, algo->name);
430 				return 1;
431 			}
432 			if (memcmp(output, vsum, algo->digest_size) != 0) {
433 				int i;
434 
435 				hash_show(algo, addr, len, output);
436 				printf(" != ");
437 				for (i = 0; i < algo->digest_size; i++)
438 					printf("%02x", vsum[i]);
439 				puts(" ** ERROR **\n");
440 				return 1;
441 			}
442 		} else {
443 			hash_show(algo, addr, len, output);
444 			printf("\n");
445 
446 			if (argc) {
447 				store_result(algo, output, *argv,
448 					flags & HASH_FLAG_ENV);
449 			}
450 		}
451 
452 	/* Horrible code size hack for boards that just want crc32 */
453 	} else {
454 		ulong crc;
455 		ulong *ptr;
456 
457 		crc = crc32_wd(0, (const uchar *)addr, len, CHUNKSZ_CRC32);
458 
459 		printf("CRC32 for %08lx ... %08lx ==> %08lx\n",
460 				addr, addr + len - 1, crc);
461 
462 		if (argc >= 3) {
463 			ptr = (ulong *)simple_strtoul(argv[0], NULL, 16);
464 			*ptr = crc;
465 		}
466 	}
467 
468 	return 0;
469 }
470 #endif /* CONFIG_CMD_HASH || CONFIG_CMD_SHA1SUM || CONFIG_CMD_CRC32) */
471 #endif /* !USE_HOSTCC */
472