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