]>
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 | ||
7 | #include "mkimage.h" | |
8 | #include <stdio.h> | |
9 | #include <string.h> | |
19c402af SG |
10 | #include <image.h> |
11 | #include <time.h> | |
12 | #include <openssl/rsa.h> | |
13 | #include <openssl/pem.h> | |
14 | #include <openssl/err.h> | |
15 | #include <openssl/ssl.h> | |
16 | #include <openssl/evp.h> | |
17 | ||
18 | #if OPENSSL_VERSION_NUMBER >= 0x10000000L | |
19 | #define HAVE_ERR_REMOVE_THREAD_STATE | |
20 | #endif | |
21 | ||
22 | static int rsa_err(const char *msg) | |
23 | { | |
24 | unsigned long sslErr = ERR_get_error(); | |
25 | ||
26 | fprintf(stderr, "%s", msg); | |
27 | fprintf(stderr, ": %s\n", | |
28 | ERR_error_string(sslErr, 0)); | |
29 | ||
30 | return -1; | |
31 | } | |
32 | ||
33 | /** | |
34 | * rsa_get_pub_key() - read a public key from a .crt file | |
35 | * | |
36 | * @keydir: Directory containins the key | |
37 | * @name Name of key file (will have a .crt extension) | |
38 | * @rsap Returns RSA object, or NULL on failure | |
39 | * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) | |
40 | */ | |
41 | static int rsa_get_pub_key(const char *keydir, const char *name, RSA **rsap) | |
42 | { | |
43 | char path[1024]; | |
44 | EVP_PKEY *key; | |
45 | X509 *cert; | |
46 | RSA *rsa; | |
47 | FILE *f; | |
48 | int ret; | |
49 | ||
50 | *rsap = NULL; | |
51 | snprintf(path, sizeof(path), "%s/%s.crt", keydir, name); | |
52 | f = fopen(path, "r"); | |
53 | if (!f) { | |
54 | fprintf(stderr, "Couldn't open RSA certificate: '%s': %s\n", | |
55 | path, strerror(errno)); | |
56 | return -EACCES; | |
57 | } | |
58 | ||
59 | /* Read the certificate */ | |
60 | cert = NULL; | |
61 | if (!PEM_read_X509(f, &cert, NULL, NULL)) { | |
62 | rsa_err("Couldn't read certificate"); | |
63 | ret = -EINVAL; | |
64 | goto err_cert; | |
65 | } | |
66 | ||
67 | /* Get the public key from the certificate. */ | |
68 | key = X509_get_pubkey(cert); | |
69 | if (!key) { | |
70 | rsa_err("Couldn't read public key\n"); | |
71 | ret = -EINVAL; | |
72 | goto err_pubkey; | |
73 | } | |
74 | ||
75 | /* Convert to a RSA_style key. */ | |
76 | rsa = EVP_PKEY_get1_RSA(key); | |
77 | if (!rsa) { | |
78 | rsa_err("Couldn't convert to a RSA style key"); | |
79 | goto err_rsa; | |
80 | } | |
81 | fclose(f); | |
82 | EVP_PKEY_free(key); | |
83 | X509_free(cert); | |
84 | *rsap = rsa; | |
85 | ||
86 | return 0; | |
87 | ||
88 | err_rsa: | |
89 | EVP_PKEY_free(key); | |
90 | err_pubkey: | |
91 | X509_free(cert); | |
92 | err_cert: | |
93 | fclose(f); | |
94 | return ret; | |
95 | } | |
96 | ||
97 | /** | |
98 | * rsa_get_priv_key() - read a private key from a .key file | |
99 | * | |
100 | * @keydir: Directory containins the key | |
101 | * @name Name of key file (will have a .key extension) | |
102 | * @rsap Returns RSA object, or NULL on failure | |
103 | * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) | |
104 | */ | |
105 | static int rsa_get_priv_key(const char *keydir, const char *name, RSA **rsap) | |
106 | { | |
107 | char path[1024]; | |
108 | RSA *rsa; | |
109 | FILE *f; | |
110 | ||
111 | *rsap = NULL; | |
112 | snprintf(path, sizeof(path), "%s/%s.key", keydir, name); | |
113 | f = fopen(path, "r"); | |
114 | if (!f) { | |
115 | fprintf(stderr, "Couldn't open RSA private key: '%s': %s\n", | |
116 | path, strerror(errno)); | |
117 | return -ENOENT; | |
118 | } | |
119 | ||
120 | rsa = PEM_read_RSAPrivateKey(f, 0, NULL, path); | |
121 | if (!rsa) { | |
122 | rsa_err("Failure reading private key"); | |
123 | fclose(f); | |
124 | return -EPROTO; | |
125 | } | |
126 | fclose(f); | |
127 | *rsap = rsa; | |
128 | ||
129 | return 0; | |
130 | } | |
131 | ||
132 | static int rsa_init(void) | |
133 | { | |
134 | int ret; | |
135 | ||
136 | ret = SSL_library_init(); | |
137 | if (!ret) { | |
138 | fprintf(stderr, "Failure to init SSL library\n"); | |
139 | return -1; | |
140 | } | |
141 | SSL_load_error_strings(); | |
142 | ||
143 | OpenSSL_add_all_algorithms(); | |
144 | OpenSSL_add_all_digests(); | |
145 | OpenSSL_add_all_ciphers(); | |
146 | ||
147 | return 0; | |
148 | } | |
149 | ||
150 | static void rsa_remove(void) | |
151 | { | |
152 | CRYPTO_cleanup_all_ex_data(); | |
153 | ERR_free_strings(); | |
154 | #ifdef HAVE_ERR_REMOVE_THREAD_STATE | |
155 | ERR_remove_thread_state(NULL); | |
156 | #else | |
157 | ERR_remove_state(0); | |
158 | #endif | |
159 | EVP_cleanup(); | |
160 | } | |
161 | ||
646257d1 HS |
162 | static int rsa_sign_with_key(RSA *rsa, struct checksum_algo *checksum_algo, |
163 | const struct image_region region[], int region_count, | |
164 | uint8_t **sigp, uint *sig_size) | |
19c402af SG |
165 | { |
166 | EVP_PKEY *key; | |
167 | EVP_MD_CTX *context; | |
168 | int size, ret = 0; | |
169 | uint8_t *sig; | |
170 | int i; | |
171 | ||
172 | key = EVP_PKEY_new(); | |
173 | if (!key) | |
174 | return rsa_err("EVP_PKEY object creation failed"); | |
175 | ||
176 | if (!EVP_PKEY_set1_RSA(key, rsa)) { | |
177 | ret = rsa_err("EVP key setup failed"); | |
178 | goto err_set; | |
179 | } | |
180 | ||
181 | size = EVP_PKEY_size(key); | |
182 | sig = malloc(size); | |
183 | if (!sig) { | |
184 | fprintf(stderr, "Out of memory for signature (%d bytes)\n", | |
185 | size); | |
186 | ret = -ENOMEM; | |
187 | goto err_alloc; | |
188 | } | |
189 | ||
190 | context = EVP_MD_CTX_create(); | |
191 | if (!context) { | |
192 | ret = rsa_err("EVP context creation failed"); | |
193 | goto err_create; | |
194 | } | |
195 | EVP_MD_CTX_init(context); | |
29a23f9d | 196 | if (!EVP_SignInit(context, checksum_algo->calculate_sign())) { |
19c402af SG |
197 | ret = rsa_err("Signer setup failed"); |
198 | goto err_sign; | |
199 | } | |
200 | ||
201 | for (i = 0; i < region_count; i++) { | |
202 | if (!EVP_SignUpdate(context, region[i].data, region[i].size)) { | |
203 | ret = rsa_err("Signing data failed"); | |
204 | goto err_sign; | |
205 | } | |
206 | } | |
207 | ||
208 | if (!EVP_SignFinal(context, sig, sig_size, key)) { | |
209 | ret = rsa_err("Could not obtain signature"); | |
210 | goto err_sign; | |
211 | } | |
212 | EVP_MD_CTX_cleanup(context); | |
213 | EVP_MD_CTX_destroy(context); | |
214 | EVP_PKEY_free(key); | |
215 | ||
216 | debug("Got signature: %d bytes, expected %d\n", *sig_size, size); | |
217 | *sigp = sig; | |
218 | *sig_size = size; | |
219 | ||
220 | return 0; | |
221 | ||
222 | err_sign: | |
223 | EVP_MD_CTX_destroy(context); | |
224 | err_create: | |
225 | free(sig); | |
226 | err_alloc: | |
227 | err_set: | |
228 | EVP_PKEY_free(key); | |
229 | return ret; | |
230 | } | |
231 | ||
232 | int rsa_sign(struct image_sign_info *info, | |
233 | const struct image_region region[], int region_count, | |
234 | uint8_t **sigp, uint *sig_len) | |
235 | { | |
236 | RSA *rsa; | |
237 | int ret; | |
238 | ||
239 | ret = rsa_init(); | |
240 | if (ret) | |
241 | return ret; | |
242 | ||
243 | ret = rsa_get_priv_key(info->keydir, info->keyname, &rsa); | |
244 | if (ret) | |
245 | goto err_priv; | |
646257d1 HS |
246 | ret = rsa_sign_with_key(rsa, info->algo->checksum, region, |
247 | region_count, sigp, sig_len); | |
19c402af SG |
248 | if (ret) |
249 | goto err_sign; | |
250 | ||
251 | RSA_free(rsa); | |
252 | rsa_remove(); | |
253 | ||
254 | return ret; | |
255 | ||
256 | err_sign: | |
257 | RSA_free(rsa); | |
258 | err_priv: | |
259 | rsa_remove(); | |
260 | return ret; | |
261 | } | |
262 | ||
263 | /* | |
264 | * rsa_get_params(): - Get the important parameters of an RSA public key | |
265 | */ | |
266 | int rsa_get_params(RSA *key, uint32_t *n0_invp, BIGNUM **modulusp, | |
267 | BIGNUM **r_squaredp) | |
268 | { | |
269 | BIGNUM *big1, *big2, *big32, *big2_32; | |
270 | BIGNUM *n, *r, *r_squared, *tmp; | |
271 | BN_CTX *bn_ctx = BN_CTX_new(); | |
272 | int ret = 0; | |
273 | ||
274 | /* Initialize BIGNUMs */ | |
275 | big1 = BN_new(); | |
276 | big2 = BN_new(); | |
277 | big32 = BN_new(); | |
278 | r = BN_new(); | |
279 | r_squared = BN_new(); | |
280 | tmp = BN_new(); | |
281 | big2_32 = BN_new(); | |
282 | n = BN_new(); | |
283 | if (!big1 || !big2 || !big32 || !r || !r_squared || !tmp || !big2_32 || | |
284 | !n) { | |
285 | fprintf(stderr, "Out of memory (bignum)\n"); | |
286 | return -ENOMEM; | |
287 | } | |
288 | ||
289 | if (!BN_copy(n, key->n) || !BN_set_word(big1, 1L) || | |
290 | !BN_set_word(big2, 2L) || !BN_set_word(big32, 32L)) | |
291 | ret = -1; | |
292 | ||
293 | /* big2_32 = 2^32 */ | |
294 | if (!BN_exp(big2_32, big2, big32, bn_ctx)) | |
295 | ret = -1; | |
296 | ||
297 | /* Calculate n0_inv = -1 / n[0] mod 2^32 */ | |
298 | if (!BN_mod_inverse(tmp, n, big2_32, bn_ctx) || | |
299 | !BN_sub(tmp, big2_32, tmp)) | |
300 | ret = -1; | |
301 | *n0_invp = BN_get_word(tmp); | |
302 | ||
303 | /* Calculate R = 2^(# of key bits) */ | |
304 | if (!BN_set_word(tmp, BN_num_bits(n)) || | |
305 | !BN_exp(r, big2, tmp, bn_ctx)) | |
306 | ret = -1; | |
307 | ||
308 | /* Calculate r_squared = R^2 mod n */ | |
309 | if (!BN_copy(r_squared, r) || | |
310 | !BN_mul(tmp, r_squared, r, bn_ctx) || | |
311 | !BN_mod(r_squared, tmp, n, bn_ctx)) | |
312 | ret = -1; | |
313 | ||
314 | *modulusp = n; | |
315 | *r_squaredp = r_squared; | |
316 | ||
317 | BN_free(big1); | |
318 | BN_free(big2); | |
319 | BN_free(big32); | |
320 | BN_free(r); | |
321 | BN_free(tmp); | |
322 | BN_free(big2_32); | |
323 | if (ret) { | |
324 | fprintf(stderr, "Bignum operations failed\n"); | |
325 | return -ENOMEM; | |
326 | } | |
327 | ||
328 | return ret; | |
329 | } | |
330 | ||
331 | static int fdt_add_bignum(void *blob, int noffset, const char *prop_name, | |
332 | BIGNUM *num, int num_bits) | |
333 | { | |
334 | int nwords = num_bits / 32; | |
335 | int size; | |
336 | uint32_t *buf, *ptr; | |
337 | BIGNUM *tmp, *big2, *big32, *big2_32; | |
338 | BN_CTX *ctx; | |
339 | int ret; | |
340 | ||
341 | tmp = BN_new(); | |
342 | big2 = BN_new(); | |
343 | big32 = BN_new(); | |
344 | big2_32 = BN_new(); | |
345 | if (!tmp || !big2 || !big32 || !big2_32) { | |
346 | fprintf(stderr, "Out of memory (bignum)\n"); | |
347 | return -ENOMEM; | |
348 | } | |
349 | ctx = BN_CTX_new(); | |
350 | if (!tmp) { | |
351 | fprintf(stderr, "Out of memory (bignum context)\n"); | |
352 | return -ENOMEM; | |
353 | } | |
354 | BN_set_word(big2, 2L); | |
355 | BN_set_word(big32, 32L); | |
356 | BN_exp(big2_32, big2, big32, ctx); /* B = 2^32 */ | |
357 | ||
358 | size = nwords * sizeof(uint32_t); | |
359 | buf = malloc(size); | |
360 | if (!buf) { | |
361 | fprintf(stderr, "Out of memory (%d bytes)\n", size); | |
362 | return -ENOMEM; | |
363 | } | |
364 | ||
365 | /* Write out modulus as big endian array of integers */ | |
366 | for (ptr = buf + nwords - 1; ptr >= buf; ptr--) { | |
367 | BN_mod(tmp, num, big2_32, ctx); /* n = N mod B */ | |
368 | *ptr = cpu_to_fdt32(BN_get_word(tmp)); | |
369 | BN_rshift(num, num, 32); /* N = N/B */ | |
370 | } | |
371 | ||
372 | ret = fdt_setprop(blob, noffset, prop_name, buf, size); | |
373 | if (ret) { | |
374 | fprintf(stderr, "Failed to write public key to FIT\n"); | |
375 | return -ENOSPC; | |
376 | } | |
377 | free(buf); | |
378 | BN_free(tmp); | |
379 | BN_free(big2); | |
380 | BN_free(big32); | |
381 | BN_free(big2_32); | |
382 | ||
383 | return ret; | |
384 | } | |
385 | ||
386 | int rsa_add_verify_data(struct image_sign_info *info, void *keydest) | |
387 | { | |
388 | BIGNUM *modulus, *r_squared; | |
389 | uint32_t n0_inv; | |
390 | int parent, node; | |
391 | char name[100]; | |
392 | int ret; | |
393 | int bits; | |
394 | RSA *rsa; | |
395 | ||
396 | debug("%s: Getting verification data\n", __func__); | |
397 | ret = rsa_get_pub_key(info->keydir, info->keyname, &rsa); | |
398 | if (ret) | |
399 | return ret; | |
400 | ret = rsa_get_params(rsa, &n0_inv, &modulus, &r_squared); | |
401 | if (ret) | |
402 | return ret; | |
403 | bits = BN_num_bits(modulus); | |
404 | parent = fdt_subnode_offset(keydest, 0, FIT_SIG_NODENAME); | |
405 | if (parent == -FDT_ERR_NOTFOUND) { | |
406 | parent = fdt_add_subnode(keydest, 0, FIT_SIG_NODENAME); | |
407 | if (parent < 0) { | |
408 | fprintf(stderr, "Couldn't create signature node: %s\n", | |
409 | fdt_strerror(parent)); | |
410 | return -EINVAL; | |
411 | } | |
412 | } | |
413 | ||
414 | /* Either create or overwrite the named key node */ | |
415 | snprintf(name, sizeof(name), "key-%s", info->keyname); | |
416 | node = fdt_subnode_offset(keydest, parent, name); | |
417 | if (node == -FDT_ERR_NOTFOUND) { | |
418 | node = fdt_add_subnode(keydest, parent, name); | |
419 | if (node < 0) { | |
420 | fprintf(stderr, "Could not create key subnode: %s\n", | |
421 | fdt_strerror(node)); | |
422 | return -EINVAL; | |
423 | } | |
424 | } else if (node < 0) { | |
425 | fprintf(stderr, "Cannot select keys parent: %s\n", | |
426 | fdt_strerror(node)); | |
427 | return -ENOSPC; | |
428 | } | |
429 | ||
430 | ret = fdt_setprop_string(keydest, node, "key-name-hint", | |
431 | info->keyname); | |
432 | ret |= fdt_setprop_u32(keydest, node, "rsa,num-bits", bits); | |
433 | ret |= fdt_setprop_u32(keydest, node, "rsa,n0-inverse", n0_inv); | |
434 | ret |= fdt_add_bignum(keydest, node, "rsa,modulus", modulus, bits); | |
435 | ret |= fdt_add_bignum(keydest, node, "rsa,r-squared", r_squared, bits); | |
436 | ret |= fdt_setprop_string(keydest, node, FIT_ALGO_PROP, | |
437 | info->algo->name); | |
438 | if (info->require_keys) { | |
439 | fdt_setprop_string(keydest, node, "required", | |
440 | info->require_keys); | |
441 | } | |
442 | BN_free(modulus); | |
443 | BN_free(r_squared); | |
444 | if (ret) | |
445 | return -EIO; | |
446 | ||
447 | return 0; | |
448 | } |