]>
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"); | |
54267162 | 79 | ret = -EINVAL; |
19c402af SG |
80 | goto err_rsa; |
81 | } | |
82 | fclose(f); | |
83 | EVP_PKEY_free(key); | |
84 | X509_free(cert); | |
85 | *rsap = rsa; | |
86 | ||
87 | return 0; | |
88 | ||
89 | err_rsa: | |
90 | EVP_PKEY_free(key); | |
91 | err_pubkey: | |
92 | X509_free(cert); | |
93 | err_cert: | |
94 | fclose(f); | |
95 | return ret; | |
96 | } | |
97 | ||
98 | /** | |
99 | * rsa_get_priv_key() - read a private key from a .key file | |
100 | * | |
101 | * @keydir: Directory containins the key | |
102 | * @name Name of key file (will have a .key extension) | |
103 | * @rsap Returns RSA object, or NULL on failure | |
104 | * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) | |
105 | */ | |
106 | static int rsa_get_priv_key(const char *keydir, const char *name, RSA **rsap) | |
107 | { | |
108 | char path[1024]; | |
109 | RSA *rsa; | |
110 | FILE *f; | |
111 | ||
112 | *rsap = NULL; | |
113 | snprintf(path, sizeof(path), "%s/%s.key", keydir, name); | |
114 | f = fopen(path, "r"); | |
115 | if (!f) { | |
116 | fprintf(stderr, "Couldn't open RSA private key: '%s': %s\n", | |
117 | path, strerror(errno)); | |
118 | return -ENOENT; | |
119 | } | |
120 | ||
121 | rsa = PEM_read_RSAPrivateKey(f, 0, NULL, path); | |
122 | if (!rsa) { | |
123 | rsa_err("Failure reading private key"); | |
124 | fclose(f); | |
125 | return -EPROTO; | |
126 | } | |
127 | fclose(f); | |
128 | *rsap = rsa; | |
129 | ||
130 | return 0; | |
131 | } | |
132 | ||
133 | static int rsa_init(void) | |
134 | { | |
135 | int ret; | |
136 | ||
137 | ret = SSL_library_init(); | |
138 | if (!ret) { | |
139 | fprintf(stderr, "Failure to init SSL library\n"); | |
140 | return -1; | |
141 | } | |
142 | SSL_load_error_strings(); | |
143 | ||
144 | OpenSSL_add_all_algorithms(); | |
145 | OpenSSL_add_all_digests(); | |
146 | OpenSSL_add_all_ciphers(); | |
147 | ||
148 | return 0; | |
149 | } | |
150 | ||
151 | static void rsa_remove(void) | |
152 | { | |
153 | CRYPTO_cleanup_all_ex_data(); | |
154 | ERR_free_strings(); | |
155 | #ifdef HAVE_ERR_REMOVE_THREAD_STATE | |
156 | ERR_remove_thread_state(NULL); | |
157 | #else | |
158 | ERR_remove_state(0); | |
159 | #endif | |
160 | EVP_cleanup(); | |
161 | } | |
162 | ||
646257d1 HS |
163 | static int rsa_sign_with_key(RSA *rsa, struct checksum_algo *checksum_algo, |
164 | const struct image_region region[], int region_count, | |
165 | uint8_t **sigp, uint *sig_size) | |
19c402af SG |
166 | { |
167 | EVP_PKEY *key; | |
168 | EVP_MD_CTX *context; | |
169 | int size, ret = 0; | |
170 | uint8_t *sig; | |
171 | int i; | |
172 | ||
173 | key = EVP_PKEY_new(); | |
174 | if (!key) | |
175 | return rsa_err("EVP_PKEY object creation failed"); | |
176 | ||
177 | if (!EVP_PKEY_set1_RSA(key, rsa)) { | |
178 | ret = rsa_err("EVP key setup failed"); | |
179 | goto err_set; | |
180 | } | |
181 | ||
182 | size = EVP_PKEY_size(key); | |
183 | sig = malloc(size); | |
184 | if (!sig) { | |
185 | fprintf(stderr, "Out of memory for signature (%d bytes)\n", | |
186 | size); | |
187 | ret = -ENOMEM; | |
188 | goto err_alloc; | |
189 | } | |
190 | ||
191 | context = EVP_MD_CTX_create(); | |
192 | if (!context) { | |
193 | ret = rsa_err("EVP context creation failed"); | |
194 | goto err_create; | |
195 | } | |
196 | EVP_MD_CTX_init(context); | |
29a23f9d | 197 | if (!EVP_SignInit(context, checksum_algo->calculate_sign())) { |
19c402af SG |
198 | ret = rsa_err("Signer setup failed"); |
199 | goto err_sign; | |
200 | } | |
201 | ||
202 | for (i = 0; i < region_count; i++) { | |
203 | if (!EVP_SignUpdate(context, region[i].data, region[i].size)) { | |
204 | ret = rsa_err("Signing data failed"); | |
205 | goto err_sign; | |
206 | } | |
207 | } | |
208 | ||
209 | if (!EVP_SignFinal(context, sig, sig_size, key)) { | |
210 | ret = rsa_err("Could not obtain signature"); | |
211 | goto err_sign; | |
212 | } | |
213 | EVP_MD_CTX_cleanup(context); | |
214 | EVP_MD_CTX_destroy(context); | |
215 | EVP_PKEY_free(key); | |
216 | ||
217 | debug("Got signature: %d bytes, expected %d\n", *sig_size, size); | |
218 | *sigp = sig; | |
219 | *sig_size = size; | |
220 | ||
221 | return 0; | |
222 | ||
223 | err_sign: | |
224 | EVP_MD_CTX_destroy(context); | |
225 | err_create: | |
226 | free(sig); | |
227 | err_alloc: | |
228 | err_set: | |
229 | EVP_PKEY_free(key); | |
230 | return ret; | |
231 | } | |
232 | ||
233 | int rsa_sign(struct image_sign_info *info, | |
234 | const struct image_region region[], int region_count, | |
235 | uint8_t **sigp, uint *sig_len) | |
236 | { | |
237 | RSA *rsa; | |
238 | int ret; | |
239 | ||
240 | ret = rsa_init(); | |
241 | if (ret) | |
242 | return ret; | |
243 | ||
244 | ret = rsa_get_priv_key(info->keydir, info->keyname, &rsa); | |
245 | if (ret) | |
246 | goto err_priv; | |
646257d1 HS |
247 | ret = rsa_sign_with_key(rsa, info->algo->checksum, region, |
248 | region_count, sigp, sig_len); | |
19c402af SG |
249 | if (ret) |
250 | goto err_sign; | |
251 | ||
252 | RSA_free(rsa); | |
253 | rsa_remove(); | |
254 | ||
255 | return ret; | |
256 | ||
257 | err_sign: | |
258 | RSA_free(rsa); | |
259 | err_priv: | |
260 | rsa_remove(); | |
261 | return ret; | |
262 | } | |
263 | ||
e0f2f155 MW |
264 | /* |
265 | * rsa_get_exponent(): - Get the public exponent from an RSA key | |
266 | */ | |
267 | static int rsa_get_exponent(RSA *key, uint64_t *e) | |
268 | { | |
269 | int ret; | |
270 | BIGNUM *bn_te; | |
271 | uint64_t te; | |
272 | ||
273 | ret = -EINVAL; | |
274 | bn_te = NULL; | |
275 | ||
276 | if (!e) | |
277 | goto cleanup; | |
278 | ||
279 | if (BN_num_bits(key->e) > 64) | |
280 | goto cleanup; | |
281 | ||
282 | *e = BN_get_word(key->e); | |
283 | ||
284 | if (BN_num_bits(key->e) < 33) { | |
285 | ret = 0; | |
286 | goto cleanup; | |
287 | } | |
288 | ||
289 | bn_te = BN_dup(key->e); | |
290 | if (!bn_te) | |
291 | goto cleanup; | |
292 | ||
293 | if (!BN_rshift(bn_te, bn_te, 32)) | |
294 | goto cleanup; | |
295 | ||
296 | if (!BN_mask_bits(bn_te, 32)) | |
297 | goto cleanup; | |
298 | ||
299 | te = BN_get_word(bn_te); | |
300 | te <<= 32; | |
301 | *e |= te; | |
302 | ret = 0; | |
303 | ||
304 | cleanup: | |
305 | if (bn_te) | |
306 | BN_free(bn_te); | |
307 | ||
308 | return ret; | |
309 | } | |
310 | ||
19c402af SG |
311 | /* |
312 | * rsa_get_params(): - Get the important parameters of an RSA public key | |
313 | */ | |
e0f2f155 MW |
314 | int rsa_get_params(RSA *key, uint64_t *exponent, uint32_t *n0_invp, |
315 | BIGNUM **modulusp, BIGNUM **r_squaredp) | |
19c402af SG |
316 | { |
317 | BIGNUM *big1, *big2, *big32, *big2_32; | |
318 | BIGNUM *n, *r, *r_squared, *tmp; | |
319 | BN_CTX *bn_ctx = BN_CTX_new(); | |
320 | int ret = 0; | |
321 | ||
322 | /* Initialize BIGNUMs */ | |
323 | big1 = BN_new(); | |
324 | big2 = BN_new(); | |
325 | big32 = BN_new(); | |
326 | r = BN_new(); | |
327 | r_squared = BN_new(); | |
328 | tmp = BN_new(); | |
329 | big2_32 = BN_new(); | |
330 | n = BN_new(); | |
331 | if (!big1 || !big2 || !big32 || !r || !r_squared || !tmp || !big2_32 || | |
332 | !n) { | |
333 | fprintf(stderr, "Out of memory (bignum)\n"); | |
334 | return -ENOMEM; | |
335 | } | |
336 | ||
e0f2f155 MW |
337 | if (0 != rsa_get_exponent(key, exponent)) |
338 | ret = -1; | |
339 | ||
19c402af SG |
340 | if (!BN_copy(n, key->n) || !BN_set_word(big1, 1L) || |
341 | !BN_set_word(big2, 2L) || !BN_set_word(big32, 32L)) | |
342 | ret = -1; | |
343 | ||
344 | /* big2_32 = 2^32 */ | |
345 | if (!BN_exp(big2_32, big2, big32, bn_ctx)) | |
346 | ret = -1; | |
347 | ||
348 | /* Calculate n0_inv = -1 / n[0] mod 2^32 */ | |
349 | if (!BN_mod_inverse(tmp, n, big2_32, bn_ctx) || | |
350 | !BN_sub(tmp, big2_32, tmp)) | |
351 | ret = -1; | |
352 | *n0_invp = BN_get_word(tmp); | |
353 | ||
354 | /* Calculate R = 2^(# of key bits) */ | |
355 | if (!BN_set_word(tmp, BN_num_bits(n)) || | |
356 | !BN_exp(r, big2, tmp, bn_ctx)) | |
357 | ret = -1; | |
358 | ||
359 | /* Calculate r_squared = R^2 mod n */ | |
360 | if (!BN_copy(r_squared, r) || | |
361 | !BN_mul(tmp, r_squared, r, bn_ctx) || | |
362 | !BN_mod(r_squared, tmp, n, bn_ctx)) | |
363 | ret = -1; | |
364 | ||
365 | *modulusp = n; | |
366 | *r_squaredp = r_squared; | |
367 | ||
368 | BN_free(big1); | |
369 | BN_free(big2); | |
370 | BN_free(big32); | |
371 | BN_free(r); | |
372 | BN_free(tmp); | |
373 | BN_free(big2_32); | |
374 | if (ret) { | |
375 | fprintf(stderr, "Bignum operations failed\n"); | |
376 | return -ENOMEM; | |
377 | } | |
378 | ||
379 | return ret; | |
380 | } | |
381 | ||
382 | static int fdt_add_bignum(void *blob, int noffset, const char *prop_name, | |
383 | BIGNUM *num, int num_bits) | |
384 | { | |
385 | int nwords = num_bits / 32; | |
386 | int size; | |
387 | uint32_t *buf, *ptr; | |
388 | BIGNUM *tmp, *big2, *big32, *big2_32; | |
389 | BN_CTX *ctx; | |
390 | int ret; | |
391 | ||
392 | tmp = BN_new(); | |
393 | big2 = BN_new(); | |
394 | big32 = BN_new(); | |
395 | big2_32 = BN_new(); | |
396 | if (!tmp || !big2 || !big32 || !big2_32) { | |
397 | fprintf(stderr, "Out of memory (bignum)\n"); | |
398 | return -ENOMEM; | |
399 | } | |
400 | ctx = BN_CTX_new(); | |
401 | if (!tmp) { | |
402 | fprintf(stderr, "Out of memory (bignum context)\n"); | |
403 | return -ENOMEM; | |
404 | } | |
405 | BN_set_word(big2, 2L); | |
406 | BN_set_word(big32, 32L); | |
407 | BN_exp(big2_32, big2, big32, ctx); /* B = 2^32 */ | |
408 | ||
409 | size = nwords * sizeof(uint32_t); | |
410 | buf = malloc(size); | |
411 | if (!buf) { | |
412 | fprintf(stderr, "Out of memory (%d bytes)\n", size); | |
413 | return -ENOMEM; | |
414 | } | |
415 | ||
416 | /* Write out modulus as big endian array of integers */ | |
417 | for (ptr = buf + nwords - 1; ptr >= buf; ptr--) { | |
418 | BN_mod(tmp, num, big2_32, ctx); /* n = N mod B */ | |
419 | *ptr = cpu_to_fdt32(BN_get_word(tmp)); | |
420 | BN_rshift(num, num, 32); /* N = N/B */ | |
421 | } | |
422 | ||
713fb2dc | 423 | /* |
424 | * We try signing with successively increasing size values, so this | |
425 | * might fail several times | |
426 | */ | |
19c402af | 427 | ret = fdt_setprop(blob, noffset, prop_name, buf, size); |
2b9ec762 | 428 | if (ret) |
429 | return -FDT_ERR_NOSPACE; | |
19c402af SG |
430 | free(buf); |
431 | BN_free(tmp); | |
432 | BN_free(big2); | |
433 | BN_free(big32); | |
434 | BN_free(big2_32); | |
435 | ||
436 | return ret; | |
437 | } | |
438 | ||
439 | int rsa_add_verify_data(struct image_sign_info *info, void *keydest) | |
440 | { | |
441 | BIGNUM *modulus, *r_squared; | |
e0f2f155 | 442 | uint64_t exponent; |
19c402af SG |
443 | uint32_t n0_inv; |
444 | int parent, node; | |
445 | char name[100]; | |
446 | int ret; | |
447 | int bits; | |
448 | RSA *rsa; | |
449 | ||
450 | debug("%s: Getting verification data\n", __func__); | |
451 | ret = rsa_get_pub_key(info->keydir, info->keyname, &rsa); | |
452 | if (ret) | |
453 | return ret; | |
e0f2f155 | 454 | ret = rsa_get_params(rsa, &exponent, &n0_inv, &modulus, &r_squared); |
19c402af SG |
455 | if (ret) |
456 | return ret; | |
457 | bits = BN_num_bits(modulus); | |
458 | parent = fdt_subnode_offset(keydest, 0, FIT_SIG_NODENAME); | |
459 | if (parent == -FDT_ERR_NOTFOUND) { | |
460 | parent = fdt_add_subnode(keydest, 0, FIT_SIG_NODENAME); | |
461 | if (parent < 0) { | |
597a8b2c SG |
462 | ret = parent; |
463 | if (ret != -FDT_ERR_NOSPACE) { | |
464 | fprintf(stderr, "Couldn't create signature node: %s\n", | |
465 | fdt_strerror(parent)); | |
466 | } | |
19c402af SG |
467 | } |
468 | } | |
597a8b2c SG |
469 | if (ret) |
470 | goto done; | |
19c402af SG |
471 | |
472 | /* Either create or overwrite the named key node */ | |
473 | snprintf(name, sizeof(name), "key-%s", info->keyname); | |
474 | node = fdt_subnode_offset(keydest, parent, name); | |
475 | if (node == -FDT_ERR_NOTFOUND) { | |
476 | node = fdt_add_subnode(keydest, parent, name); | |
477 | if (node < 0) { | |
597a8b2c SG |
478 | ret = node; |
479 | if (ret != -FDT_ERR_NOSPACE) { | |
480 | fprintf(stderr, "Could not create key subnode: %s\n", | |
481 | fdt_strerror(node)); | |
482 | } | |
19c402af SG |
483 | } |
484 | } else if (node < 0) { | |
485 | fprintf(stderr, "Cannot select keys parent: %s\n", | |
486 | fdt_strerror(node)); | |
597a8b2c | 487 | ret = node; |
19c402af SG |
488 | } |
489 | ||
597a8b2c SG |
490 | if (!ret) { |
491 | ret = fdt_setprop_string(keydest, node, "key-name-hint", | |
19c402af | 492 | info->keyname); |
597a8b2c | 493 | } |
4f427a42 SG |
494 | if (!ret) |
495 | ret = fdt_setprop_u32(keydest, node, "rsa,num-bits", bits); | |
496 | if (!ret) | |
497 | ret = fdt_setprop_u32(keydest, node, "rsa,n0-inverse", n0_inv); | |
e0f2f155 MW |
498 | if (!ret) { |
499 | ret = fdt_setprop_u64(keydest, node, "rsa,exponent", exponent); | |
500 | } | |
4f427a42 SG |
501 | if (!ret) { |
502 | ret = fdt_add_bignum(keydest, node, "rsa,modulus", modulus, | |
503 | bits); | |
504 | } | |
505 | if (!ret) { | |
506 | ret = fdt_add_bignum(keydest, node, "rsa,r-squared", r_squared, | |
507 | bits); | |
508 | } | |
509 | if (!ret) { | |
510 | ret = fdt_setprop_string(keydest, node, FIT_ALGO_PROP, | |
511 | info->algo->name); | |
512 | } | |
2b9ec762 | 513 | if (!ret && info->require_keys) { |
4f427a42 SG |
514 | ret = fdt_setprop_string(keydest, node, "required", |
515 | info->require_keys); | |
19c402af | 516 | } |
597a8b2c | 517 | done: |
19c402af SG |
518 | BN_free(modulus); |
519 | BN_free(r_squared); | |
520 | if (ret) | |
597a8b2c | 521 | return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO; |
19c402af SG |
522 | |
523 | return 0; | |
524 | } |