xref: /rk3399_rockchip-uboot/lib/rsa/rsa-verify.c (revision 2b9912e6a7df7b1f60beb7942bd0e6fa5f9d0167)
119c402afSSimon Glass /*
219c402afSSimon Glass  * Copyright (c) 2013, Google Inc.
319c402afSSimon Glass  *
41a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
519c402afSSimon Glass  */
619c402afSSimon Glass 
729a23f9dSHeiko Schocher #ifndef USE_HOSTCC
819c402afSSimon Glass #include <common.h>
919c402afSSimon Glass #include <fdtdec.h>
1029a23f9dSHeiko Schocher #include <asm/types.h>
1129a23f9dSHeiko Schocher #include <asm/byteorder.h>
1229a23f9dSHeiko Schocher #include <asm/errno.h>
1329a23f9dSHeiko Schocher #include <asm/types.h>
1429a23f9dSHeiko Schocher #include <asm/unaligned.h>
1529a23f9dSHeiko Schocher #else
1629a23f9dSHeiko Schocher #include "fdt_host.h"
1729a23f9dSHeiko Schocher #include "mkimage.h"
1829a23f9dSHeiko Schocher #include <fdt_support.h>
1929a23f9dSHeiko Schocher #endif
20*2b9912e6SJeroen Hofstee #include <u-boot/rsa.h>
21*2b9912e6SJeroen Hofstee #include <u-boot/sha1.h>
22*2b9912e6SJeroen Hofstee #include <u-boot/sha256.h>
2319c402afSSimon Glass 
2419c402afSSimon Glass #define UINT64_MULT32(v, multby)  (((uint64_t)(v)) * ((uint32_t)(multby)))
2519c402afSSimon Glass 
2629a23f9dSHeiko Schocher #define get_unaligned_be32(a) fdt32_to_cpu(*(uint32_t *)a)
2729a23f9dSHeiko Schocher #define put_unaligned_be32(a, b) (*(uint32_t *)(b) = cpu_to_fdt32(a))
2829a23f9dSHeiko Schocher 
2919c402afSSimon Glass /**
3019c402afSSimon Glass  * subtract_modulus() - subtract modulus from the given value
3119c402afSSimon Glass  *
3219c402afSSimon Glass  * @key:	Key containing modulus to subtract
3319c402afSSimon Glass  * @num:	Number to subtract modulus from, as little endian word array
3419c402afSSimon Glass  */
3519c402afSSimon Glass static void subtract_modulus(const struct rsa_public_key *key, uint32_t num[])
3619c402afSSimon Glass {
3719c402afSSimon Glass 	int64_t acc = 0;
3819c402afSSimon Glass 	uint i;
3919c402afSSimon Glass 
4019c402afSSimon Glass 	for (i = 0; i < key->len; i++) {
4119c402afSSimon Glass 		acc += (uint64_t)num[i] - key->modulus[i];
4219c402afSSimon Glass 		num[i] = (uint32_t)acc;
4319c402afSSimon Glass 		acc >>= 32;
4419c402afSSimon Glass 	}
4519c402afSSimon Glass }
4619c402afSSimon Glass 
4719c402afSSimon Glass /**
4819c402afSSimon Glass  * greater_equal_modulus() - check if a value is >= modulus
4919c402afSSimon Glass  *
5019c402afSSimon Glass  * @key:	Key containing modulus to check
5119c402afSSimon Glass  * @num:	Number to check against modulus, as little endian word array
5219c402afSSimon Glass  * @return 0 if num < modulus, 1 if num >= modulus
5319c402afSSimon Glass  */
5419c402afSSimon Glass static int greater_equal_modulus(const struct rsa_public_key *key,
5519c402afSSimon Glass 				 uint32_t num[])
5619c402afSSimon Glass {
5719c402afSSimon Glass 	uint32_t i;
5819c402afSSimon Glass 
5919c402afSSimon Glass 	for (i = key->len - 1; i >= 0; i--) {
6019c402afSSimon Glass 		if (num[i] < key->modulus[i])
6119c402afSSimon Glass 			return 0;
6219c402afSSimon Glass 		if (num[i] > key->modulus[i])
6319c402afSSimon Glass 			return 1;
6419c402afSSimon Glass 	}
6519c402afSSimon Glass 
6619c402afSSimon Glass 	return 1;  /* equal */
6719c402afSSimon Glass }
6819c402afSSimon Glass 
6919c402afSSimon Glass /**
7019c402afSSimon Glass  * montgomery_mul_add_step() - Perform montgomery multiply-add step
7119c402afSSimon Glass  *
7219c402afSSimon Glass  * Operation: montgomery result[] += a * b[] / n0inv % modulus
7319c402afSSimon Glass  *
7419c402afSSimon Glass  * @key:	RSA key
7519c402afSSimon Glass  * @result:	Place to put result, as little endian word array
7619c402afSSimon Glass  * @a:		Multiplier
7719c402afSSimon Glass  * @b:		Multiplicand, as little endian word array
7819c402afSSimon Glass  */
7919c402afSSimon Glass static void montgomery_mul_add_step(const struct rsa_public_key *key,
8019c402afSSimon Glass 		uint32_t result[], const uint32_t a, const uint32_t b[])
8119c402afSSimon Glass {
8219c402afSSimon Glass 	uint64_t acc_a, acc_b;
8319c402afSSimon Glass 	uint32_t d0;
8419c402afSSimon Glass 	uint i;
8519c402afSSimon Glass 
8619c402afSSimon Glass 	acc_a = (uint64_t)a * b[0] + result[0];
8719c402afSSimon Glass 	d0 = (uint32_t)acc_a * key->n0inv;
8819c402afSSimon Glass 	acc_b = (uint64_t)d0 * key->modulus[0] + (uint32_t)acc_a;
8919c402afSSimon Glass 	for (i = 1; i < key->len; i++) {
9019c402afSSimon Glass 		acc_a = (acc_a >> 32) + (uint64_t)a * b[i] + result[i];
9119c402afSSimon Glass 		acc_b = (acc_b >> 32) + (uint64_t)d0 * key->modulus[i] +
9219c402afSSimon Glass 				(uint32_t)acc_a;
9319c402afSSimon Glass 		result[i - 1] = (uint32_t)acc_b;
9419c402afSSimon Glass 	}
9519c402afSSimon Glass 
9619c402afSSimon Glass 	acc_a = (acc_a >> 32) + (acc_b >> 32);
9719c402afSSimon Glass 
9819c402afSSimon Glass 	result[i - 1] = (uint32_t)acc_a;
9919c402afSSimon Glass 
10019c402afSSimon Glass 	if (acc_a >> 32)
10119c402afSSimon Glass 		subtract_modulus(key, result);
10219c402afSSimon Glass }
10319c402afSSimon Glass 
10419c402afSSimon Glass /**
10519c402afSSimon Glass  * montgomery_mul() - Perform montgomery mutitply
10619c402afSSimon Glass  *
10719c402afSSimon Glass  * Operation: montgomery result[] = a[] * b[] / n0inv % modulus
10819c402afSSimon Glass  *
10919c402afSSimon Glass  * @key:	RSA key
11019c402afSSimon Glass  * @result:	Place to put result, as little endian word array
11119c402afSSimon Glass  * @a:		Multiplier, as little endian word array
11219c402afSSimon Glass  * @b:		Multiplicand, as little endian word array
11319c402afSSimon Glass  */
11419c402afSSimon Glass static void montgomery_mul(const struct rsa_public_key *key,
11519c402afSSimon Glass 		uint32_t result[], uint32_t a[], const uint32_t b[])
11619c402afSSimon Glass {
11719c402afSSimon Glass 	uint i;
11819c402afSSimon Glass 
11919c402afSSimon Glass 	for (i = 0; i < key->len; ++i)
12019c402afSSimon Glass 		result[i] = 0;
12119c402afSSimon Glass 	for (i = 0; i < key->len; ++i)
12219c402afSSimon Glass 		montgomery_mul_add_step(key, result, a[i], b);
12319c402afSSimon Glass }
12419c402afSSimon Glass 
12519c402afSSimon Glass /**
12619c402afSSimon Glass  * pow_mod() - in-place public exponentiation
12719c402afSSimon Glass  *
12819c402afSSimon Glass  * @key:	RSA key
12919c402afSSimon Glass  * @inout:	Big-endian word array containing value and result
13019c402afSSimon Glass  */
13119c402afSSimon Glass static int pow_mod(const struct rsa_public_key *key, uint32_t *inout)
13219c402afSSimon Glass {
13319c402afSSimon Glass 	uint32_t *result, *ptr;
13419c402afSSimon Glass 	uint i;
13519c402afSSimon Glass 
13619c402afSSimon Glass 	/* Sanity check for stack size - key->len is in 32-bit words */
13719c402afSSimon Glass 	if (key->len > RSA_MAX_KEY_BITS / 32) {
13819c402afSSimon Glass 		debug("RSA key words %u exceeds maximum %d\n", key->len,
13919c402afSSimon Glass 		      RSA_MAX_KEY_BITS / 32);
14019c402afSSimon Glass 		return -EINVAL;
14119c402afSSimon Glass 	}
14219c402afSSimon Glass 
14319c402afSSimon Glass 	uint32_t val[key->len], acc[key->len], tmp[key->len];
14419c402afSSimon Glass 	result = tmp;  /* Re-use location. */
14519c402afSSimon Glass 
14619c402afSSimon Glass 	/* Convert from big endian byte array to little endian word array. */
14719c402afSSimon Glass 	for (i = 0, ptr = inout + key->len - 1; i < key->len; i++, ptr--)
14819c402afSSimon Glass 		val[i] = get_unaligned_be32(ptr);
14919c402afSSimon Glass 
15019c402afSSimon Glass 	montgomery_mul(key, acc, val, key->rr);  /* axx = a * RR / R mod M */
15119c402afSSimon Glass 	for (i = 0; i < 16; i += 2) {
15219c402afSSimon Glass 		montgomery_mul(key, tmp, acc, acc); /* tmp = acc^2 / R mod M */
15319c402afSSimon Glass 		montgomery_mul(key, acc, tmp, tmp); /* acc = tmp^2 / R mod M */
15419c402afSSimon Glass 	}
15519c402afSSimon Glass 	montgomery_mul(key, result, acc, val);  /* result = XX * a / R mod M */
15619c402afSSimon Glass 
15719c402afSSimon Glass 	/* Make sure result < mod; result is at most 1x mod too large. */
15819c402afSSimon Glass 	if (greater_equal_modulus(key, result))
15919c402afSSimon Glass 		subtract_modulus(key, result);
16019c402afSSimon Glass 
16119c402afSSimon Glass 	/* Convert to bigendian byte array */
16219c402afSSimon Glass 	for (i = key->len - 1, ptr = inout; (int)i >= 0; i--, ptr++)
16319c402afSSimon Glass 		put_unaligned_be32(result[i], ptr);
16419c402afSSimon Glass 	return 0;
16519c402afSSimon Glass }
16619c402afSSimon Glass 
16719c402afSSimon Glass static int rsa_verify_key(const struct rsa_public_key *key, const uint8_t *sig,
168646257d1SHeiko Schocher 			  const uint32_t sig_len, const uint8_t *hash,
169646257d1SHeiko Schocher 			  struct checksum_algo *algo)
17019c402afSSimon Glass {
17119c402afSSimon Glass 	const uint8_t *padding;
17219c402afSSimon Glass 	int pad_len;
17319c402afSSimon Glass 	int ret;
17419c402afSSimon Glass 
175646257d1SHeiko Schocher 	if (!key || !sig || !hash || !algo)
17619c402afSSimon Glass 		return -EIO;
17719c402afSSimon Glass 
17819c402afSSimon Glass 	if (sig_len != (key->len * sizeof(uint32_t))) {
17919c402afSSimon Glass 		debug("Signature is of incorrect length %d\n", sig_len);
18019c402afSSimon Glass 		return -EINVAL;
18119c402afSSimon Glass 	}
18219c402afSSimon Glass 
183646257d1SHeiko Schocher 	debug("Checksum algorithm: %s", algo->name);
184646257d1SHeiko Schocher 
18519c402afSSimon Glass 	/* Sanity check for stack size */
18619c402afSSimon Glass 	if (sig_len > RSA_MAX_SIG_BITS / 8) {
18719c402afSSimon Glass 		debug("Signature length %u exceeds maximum %d\n", sig_len,
18819c402afSSimon Glass 		      RSA_MAX_SIG_BITS / 8);
18919c402afSSimon Glass 		return -EINVAL;
19019c402afSSimon Glass 	}
19119c402afSSimon Glass 
19219c402afSSimon Glass 	uint32_t buf[sig_len / sizeof(uint32_t)];
19319c402afSSimon Glass 
19419c402afSSimon Glass 	memcpy(buf, sig, sig_len);
19519c402afSSimon Glass 
19619c402afSSimon Glass 	ret = pow_mod(key, buf);
19719c402afSSimon Glass 	if (ret)
19819c402afSSimon Glass 		return ret;
19919c402afSSimon Glass 
200646257d1SHeiko Schocher 	padding = algo->rsa_padding;
201db1b5f3dSHeiko Schocher 	pad_len = algo->pad_len - algo->checksum_len;
20219c402afSSimon Glass 
20319c402afSSimon Glass 	/* Check pkcs1.5 padding bytes. */
20419c402afSSimon Glass 	if (memcmp(buf, padding, pad_len)) {
20519c402afSSimon Glass 		debug("In RSAVerify(): Padding check failed!\n");
20619c402afSSimon Glass 		return -EINVAL;
20719c402afSSimon Glass 	}
20819c402afSSimon Glass 
20919c402afSSimon Glass 	/* Check hash. */
21019c402afSSimon Glass 	if (memcmp((uint8_t *)buf + pad_len, hash, sig_len - pad_len)) {
21119c402afSSimon Glass 		debug("In RSAVerify(): Hash check failed!\n");
21219c402afSSimon Glass 		return -EACCES;
21319c402afSSimon Glass 	}
21419c402afSSimon Glass 
21519c402afSSimon Glass 	return 0;
21619c402afSSimon Glass }
21719c402afSSimon Glass 
21819c402afSSimon Glass static void rsa_convert_big_endian(uint32_t *dst, const uint32_t *src, int len)
21919c402afSSimon Glass {
22019c402afSSimon Glass 	int i;
22119c402afSSimon Glass 
22219c402afSSimon Glass 	for (i = 0; i < len; i++)
22319c402afSSimon Glass 		dst[i] = fdt32_to_cpu(src[len - 1 - i]);
22419c402afSSimon Glass }
22519c402afSSimon Glass 
22619c402afSSimon Glass static int rsa_verify_with_keynode(struct image_sign_info *info,
22719c402afSSimon Glass 		const void *hash, uint8_t *sig, uint sig_len, int node)
22819c402afSSimon Glass {
22919c402afSSimon Glass 	const void *blob = info->fdt_blob;
23019c402afSSimon Glass 	struct rsa_public_key key;
23119c402afSSimon Glass 	const void *modulus, *rr;
23219c402afSSimon Glass 	int ret;
23319c402afSSimon Glass 
23419c402afSSimon Glass 	if (node < 0) {
23519c402afSSimon Glass 		debug("%s: Skipping invalid node", __func__);
23619c402afSSimon Glass 		return -EBADF;
23719c402afSSimon Glass 	}
23819c402afSSimon Glass 	if (!fdt_getprop(blob, node, "rsa,n0-inverse", NULL)) {
23919c402afSSimon Glass 		debug("%s: Missing rsa,n0-inverse", __func__);
24019c402afSSimon Glass 		return -EFAULT;
24119c402afSSimon Glass 	}
24219c402afSSimon Glass 	key.len = fdtdec_get_int(blob, node, "rsa,num-bits", 0);
24319c402afSSimon Glass 	key.n0inv = fdtdec_get_int(blob, node, "rsa,n0-inverse", 0);
24419c402afSSimon Glass 	modulus = fdt_getprop(blob, node, "rsa,modulus", NULL);
24519c402afSSimon Glass 	rr = fdt_getprop(blob, node, "rsa,r-squared", NULL);
24619c402afSSimon Glass 	if (!key.len || !modulus || !rr) {
24719c402afSSimon Glass 		debug("%s: Missing RSA key info", __func__);
24819c402afSSimon Glass 		return -EFAULT;
24919c402afSSimon Glass 	}
25019c402afSSimon Glass 
25119c402afSSimon Glass 	/* Sanity check for stack size */
25219c402afSSimon Glass 	if (key.len > RSA_MAX_KEY_BITS || key.len < RSA_MIN_KEY_BITS) {
25319c402afSSimon Glass 		debug("RSA key bits %u outside allowed range %d..%d\n",
25419c402afSSimon Glass 		      key.len, RSA_MIN_KEY_BITS, RSA_MAX_KEY_BITS);
25519c402afSSimon Glass 		return -EFAULT;
25619c402afSSimon Glass 	}
25719c402afSSimon Glass 	key.len /= sizeof(uint32_t) * 8;
25819c402afSSimon Glass 	uint32_t key1[key.len], key2[key.len];
25919c402afSSimon Glass 
26019c402afSSimon Glass 	key.modulus = key1;
26119c402afSSimon Glass 	key.rr = key2;
26219c402afSSimon Glass 	rsa_convert_big_endian(key.modulus, modulus, key.len);
26319c402afSSimon Glass 	rsa_convert_big_endian(key.rr, rr, key.len);
26419c402afSSimon Glass 	if (!key.modulus || !key.rr) {
26519c402afSSimon Glass 		debug("%s: Out of memory", __func__);
26619c402afSSimon Glass 		return -ENOMEM;
26719c402afSSimon Glass 	}
26819c402afSSimon Glass 
26919c402afSSimon Glass 	debug("key length %d\n", key.len);
270646257d1SHeiko Schocher 	ret = rsa_verify_key(&key, sig, sig_len, hash, info->algo->checksum);
27119c402afSSimon Glass 	if (ret) {
27219c402afSSimon Glass 		printf("%s: RSA failed to verify: %d\n", __func__, ret);
27319c402afSSimon Glass 		return ret;
27419c402afSSimon Glass 	}
27519c402afSSimon Glass 
27619c402afSSimon Glass 	return 0;
27719c402afSSimon Glass }
27819c402afSSimon Glass 
27919c402afSSimon Glass int rsa_verify(struct image_sign_info *info,
28019c402afSSimon Glass 	       const struct image_region region[], int region_count,
28119c402afSSimon Glass 	       uint8_t *sig, uint sig_len)
28219c402afSSimon Glass {
28319c402afSSimon Glass 	const void *blob = info->fdt_blob;
284646257d1SHeiko Schocher 	/* Reserve memory for maximum checksum-length */
285db1b5f3dSHeiko Schocher 	uint8_t hash[info->algo->checksum->pad_len];
28619c402afSSimon Glass 	int ndepth, noffset;
28719c402afSSimon Glass 	int sig_node, node;
28819c402afSSimon Glass 	char name[100];
289646257d1SHeiko Schocher 	int ret;
290646257d1SHeiko Schocher 
291646257d1SHeiko Schocher 	/*
292646257d1SHeiko Schocher 	 * Verify that the checksum-length does not exceed the
293646257d1SHeiko Schocher 	 * rsa-signature-length
294646257d1SHeiko Schocher 	 */
295db1b5f3dSHeiko Schocher 	if (info->algo->checksum->checksum_len >
296db1b5f3dSHeiko Schocher 	    info->algo->checksum->pad_len) {
297db1b5f3dSHeiko Schocher 		debug("%s: invlaid checksum-algorithm %s for %s\n",
298db1b5f3dSHeiko Schocher 		      __func__, info->algo->checksum->name, info->algo->name);
299646257d1SHeiko Schocher 		return -EINVAL;
300646257d1SHeiko Schocher 	}
30119c402afSSimon Glass 
30219c402afSSimon Glass 	sig_node = fdt_subnode_offset(blob, 0, FIT_SIG_NODENAME);
30319c402afSSimon Glass 	if (sig_node < 0) {
30419c402afSSimon Glass 		debug("%s: No signature node found\n", __func__);
30519c402afSSimon Glass 		return -ENOENT;
30619c402afSSimon Glass 	}
30719c402afSSimon Glass 
308646257d1SHeiko Schocher 	/* Calculate checksum with checksum-algorithm */
309646257d1SHeiko Schocher 	info->algo->checksum->calculate(region, region_count, hash);
31019c402afSSimon Glass 
31119c402afSSimon Glass 	/* See if we must use a particular key */
31219c402afSSimon Glass 	if (info->required_keynode != -1) {
31319c402afSSimon Glass 		ret = rsa_verify_with_keynode(info, hash, sig, sig_len,
31419c402afSSimon Glass 			info->required_keynode);
31519c402afSSimon Glass 		if (!ret)
31619c402afSSimon Glass 			return ret;
31719c402afSSimon Glass 	}
31819c402afSSimon Glass 
31919c402afSSimon Glass 	/* Look for a key that matches our hint */
32019c402afSSimon Glass 	snprintf(name, sizeof(name), "key-%s", info->keyname);
32119c402afSSimon Glass 	node = fdt_subnode_offset(blob, sig_node, name);
32219c402afSSimon Glass 	ret = rsa_verify_with_keynode(info, hash, sig, sig_len, node);
32319c402afSSimon Glass 	if (!ret)
32419c402afSSimon Glass 		return ret;
32519c402afSSimon Glass 
32619c402afSSimon Glass 	/* No luck, so try each of the keys in turn */
32719c402afSSimon Glass 	for (ndepth = 0, noffset = fdt_next_node(info->fit, sig_node, &ndepth);
32819c402afSSimon Glass 			(noffset >= 0) && (ndepth > 0);
32919c402afSSimon Glass 			noffset = fdt_next_node(info->fit, noffset, &ndepth)) {
33019c402afSSimon Glass 		if (ndepth == 1 && noffset != node) {
33119c402afSSimon Glass 			ret = rsa_verify_with_keynode(info, hash, sig, sig_len,
33219c402afSSimon Glass 						      noffset);
33319c402afSSimon Glass 			if (!ret)
33419c402afSSimon Glass 				break;
33519c402afSSimon Glass 		}
33619c402afSSimon Glass 	}
33719c402afSSimon Glass 
33819c402afSSimon Glass 	return ret;
33919c402afSSimon Glass }
340