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