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