xref: /openbmc/u-boot/lib/rsa/rsa-verify.c (revision ee7bb5be)
1 /*
2  * Copyright (c) 2013, Google Inc.
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #ifndef USE_HOSTCC
8 #include <common.h>
9 #include <fdtdec.h>
10 #include <asm/types.h>
11 #include <asm/byteorder.h>
12 #include <asm/errno.h>
13 #include <asm/types.h>
14 #include <asm/unaligned.h>
15 #include <dm.h>
16 #else
17 #include "fdt_host.h"
18 #include "mkimage.h"
19 #include <fdt_support.h>
20 #endif
21 #include <u-boot/rsa-mod-exp.h>
22 #include <u-boot/rsa.h>
23 
24 /* Default public exponent for backward compatibility */
25 #define RSA_DEFAULT_PUBEXP	65537
26 
27 /**
28  * rsa_verify_key() - Verify a signature against some data using RSA Key
29  *
30  * Verify a RSA PKCS1.5 signature against an expected hash using
31  * the RSA Key properties in prop structure.
32  *
33  * @prop:	Specifies key
34  * @sig:	Signature
35  * @sig_len:	Number of bytes in signature
36  * @hash:	Pointer to the expected hash
37  * @algo:	Checksum algo structure having information on RSA padding etc.
38  * @return 0 if verified, -ve on error
39  */
40 static int rsa_verify_key(struct key_prop *prop, const uint8_t *sig,
41 			  const uint32_t sig_len, const uint8_t *hash,
42 			  struct checksum_algo *algo)
43 {
44 	const uint8_t *padding;
45 	int pad_len;
46 	int ret;
47 #if !defined(USE_HOSTCC)
48 	struct udevice *mod_exp_dev;
49 #endif
50 
51 	if (!prop || !sig || !hash || !algo)
52 		return -EIO;
53 
54 	if (sig_len != (prop->num_bits / 8)) {
55 		debug("Signature is of incorrect length %d\n", sig_len);
56 		return -EINVAL;
57 	}
58 
59 	debug("Checksum algorithm: %s", algo->name);
60 
61 	/* Sanity check for stack size */
62 	if (sig_len > RSA_MAX_SIG_BITS / 8) {
63 		debug("Signature length %u exceeds maximum %d\n", sig_len,
64 		      RSA_MAX_SIG_BITS / 8);
65 		return -EINVAL;
66 	}
67 
68 	uint8_t buf[sig_len];
69 
70 #if !defined(USE_HOSTCC)
71 	ret = uclass_get_device(UCLASS_MOD_EXP, 0, &mod_exp_dev);
72 	if (ret) {
73 		printf("RSA: Can't find Modular Exp implementation\n");
74 		return -EINVAL;
75 	}
76 
77 	ret = rsa_mod_exp(mod_exp_dev, sig, sig_len, prop, buf);
78 #else
79 	ret = rsa_mod_exp_sw(sig, sig_len, prop, buf);
80 #endif
81 	if (ret) {
82 		debug("Error in Modular exponentation\n");
83 		return ret;
84 	}
85 
86 	padding = algo->rsa_padding;
87 	pad_len = algo->pad_len - algo->checksum_len;
88 
89 	/* Check pkcs1.5 padding bytes. */
90 	if (memcmp(buf, padding, pad_len)) {
91 		debug("In RSAVerify(): Padding check failed!\n");
92 		return -EINVAL;
93 	}
94 
95 	/* Check hash. */
96 	if (memcmp((uint8_t *)buf + pad_len, hash, sig_len - pad_len)) {
97 		debug("In RSAVerify(): Hash check failed!\n");
98 		return -EACCES;
99 	}
100 
101 	return 0;
102 }
103 
104 /**
105  * rsa_verify_with_keynode() - Verify a signature against some data using
106  * information in node with prperties of RSA Key like modulus, exponent etc.
107  *
108  * Parse sign-node and fill a key_prop structure with properties of the
109  * key.  Verify a RSA PKCS1.5 signature against an expected hash using
110  * the properties parsed
111  *
112  * @info:	Specifies key and FIT information
113  * @hash:	Pointer to the expected hash
114  * @sig:	Signature
115  * @sig_len:	Number of bytes in signature
116  * @node:	Node having the RSA Key properties
117  * @return 0 if verified, -ve on error
118  */
119 static int rsa_verify_with_keynode(struct image_sign_info *info,
120 				   const void *hash, uint8_t *sig,
121 				   uint sig_len, int node)
122 {
123 	const void *blob = info->fdt_blob;
124 	struct key_prop prop;
125 	int length;
126 	int ret = 0;
127 
128 	if (node < 0) {
129 		debug("%s: Skipping invalid node", __func__);
130 		return -EBADF;
131 	}
132 
133 	prop.num_bits = fdtdec_get_int(blob, node, "rsa,num-bits", 0);
134 
135 	prop.n0inv = fdtdec_get_int(blob, node, "rsa,n0-inverse", 0);
136 
137 	prop.public_exponent = fdt_getprop(blob, node, "rsa,exponent", &length);
138 	if (!prop.public_exponent || length < sizeof(uint64_t))
139 		prop.public_exponent = NULL;
140 
141 	prop.exp_len = sizeof(uint64_t);
142 
143 	prop.modulus = fdt_getprop(blob, node, "rsa,modulus", NULL);
144 
145 	prop.rr = fdt_getprop(blob, node, "rsa,r-squared", NULL);
146 
147 	if (!prop.num_bits || !prop.modulus) {
148 		debug("%s: Missing RSA key info", __func__);
149 		return -EFAULT;
150 	}
151 
152 	ret = rsa_verify_key(&prop, sig, sig_len, hash, info->algo->checksum);
153 
154 	return ret;
155 }
156 
157 int rsa_verify(struct image_sign_info *info,
158 	       const struct image_region region[], int region_count,
159 	       uint8_t *sig, uint sig_len)
160 {
161 	const void *blob = info->fdt_blob;
162 	/* Reserve memory for maximum checksum-length */
163 	uint8_t hash[info->algo->checksum->pad_len];
164 	int ndepth, noffset;
165 	int sig_node, node;
166 	char name[100];
167 	int ret;
168 
169 	/*
170 	 * Verify that the checksum-length does not exceed the
171 	 * rsa-signature-length
172 	 */
173 	if (info->algo->checksum->checksum_len >
174 	    info->algo->checksum->pad_len) {
175 		debug("%s: invlaid checksum-algorithm %s for %s\n",
176 		      __func__, info->algo->checksum->name, info->algo->name);
177 		return -EINVAL;
178 	}
179 
180 	sig_node = fdt_subnode_offset(blob, 0, FIT_SIG_NODENAME);
181 	if (sig_node < 0) {
182 		debug("%s: No signature node found\n", __func__);
183 		return -ENOENT;
184 	}
185 
186 	/* Calculate checksum with checksum-algorithm */
187 	ret = info->algo->checksum->calculate(info->algo->checksum->name,
188 					region, region_count, hash);
189 	if (ret < 0) {
190 		debug("%s: Error in checksum calculation\n", __func__);
191 		return -EINVAL;
192 	}
193 
194 	/* See if we must use a particular key */
195 	if (info->required_keynode != -1) {
196 		ret = rsa_verify_with_keynode(info, hash, sig, sig_len,
197 			info->required_keynode);
198 		if (!ret)
199 			return ret;
200 	}
201 
202 	/* Look for a key that matches our hint */
203 	snprintf(name, sizeof(name), "key-%s", info->keyname);
204 	node = fdt_subnode_offset(blob, sig_node, name);
205 	ret = rsa_verify_with_keynode(info, hash, sig, sig_len, node);
206 	if (!ret)
207 		return ret;
208 
209 	/* No luck, so try each of the keys in turn */
210 	for (ndepth = 0, noffset = fdt_next_node(info->fit, sig_node, &ndepth);
211 			(noffset >= 0) && (ndepth > 0);
212 			noffset = fdt_next_node(info->fit, noffset, &ndepth)) {
213 		if (ndepth == 1 && noffset != node) {
214 			ret = rsa_verify_with_keynode(info, hash, sig, sig_len,
215 						      noffset);
216 			if (!ret)
217 				break;
218 		}
219 	}
220 
221 	return ret;
222 }
223