]>
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> | |
c3b43281 | 12 | #include <openssl/bn.h> |
19c402af SG |
13 | #include <openssl/rsa.h> |
14 | #include <openssl/pem.h> | |
15 | #include <openssl/err.h> | |
16 | #include <openssl/ssl.h> | |
17 | #include <openssl/evp.h> | |
f1ca1fde | 18 | #include <openssl/engine.h> |
19c402af SG |
19 | |
20 | #if OPENSSL_VERSION_NUMBER >= 0x10000000L | |
21 | #define HAVE_ERR_REMOVE_THREAD_STATE | |
22 | #endif | |
23 | ||
c3b43281 JW |
24 | #if OPENSSL_VERSION_NUMBER < 0x10100000L |
25 | static void RSA_get0_key(const RSA *r, | |
26 | const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) | |
27 | { | |
28 | if (n != NULL) | |
29 | *n = r->n; | |
30 | if (e != NULL) | |
31 | *e = r->e; | |
32 | if (d != NULL) | |
33 | *d = r->d; | |
34 | } | |
35 | #endif | |
36 | ||
19c402af SG |
37 | static int rsa_err(const char *msg) |
38 | { | |
39 | unsigned long sslErr = ERR_get_error(); | |
40 | ||
41 | fprintf(stderr, "%s", msg); | |
42 | fprintf(stderr, ": %s\n", | |
43 | ERR_error_string(sslErr, 0)); | |
44 | ||
45 | return -1; | |
46 | } | |
47 | ||
48 | /** | |
f1ca1fde | 49 | * rsa_pem_get_pub_key() - read a public key from a .crt file |
19c402af SG |
50 | * |
51 | * @keydir: Directory containins the key | |
52 | * @name Name of key file (will have a .crt extension) | |
53 | * @rsap Returns RSA object, or NULL on failure | |
54 | * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) | |
55 | */ | |
f1ca1fde | 56 | static int rsa_pem_get_pub_key(const char *keydir, const char *name, RSA **rsap) |
19c402af SG |
57 | { |
58 | char path[1024]; | |
59 | EVP_PKEY *key; | |
60 | X509 *cert; | |
61 | RSA *rsa; | |
62 | FILE *f; | |
63 | int ret; | |
64 | ||
65 | *rsap = NULL; | |
66 | snprintf(path, sizeof(path), "%s/%s.crt", keydir, name); | |
67 | f = fopen(path, "r"); | |
68 | if (!f) { | |
69 | fprintf(stderr, "Couldn't open RSA certificate: '%s': %s\n", | |
70 | path, strerror(errno)); | |
71 | return -EACCES; | |
72 | } | |
73 | ||
74 | /* Read the certificate */ | |
75 | cert = NULL; | |
76 | if (!PEM_read_X509(f, &cert, NULL, NULL)) { | |
77 | rsa_err("Couldn't read certificate"); | |
78 | ret = -EINVAL; | |
79 | goto err_cert; | |
80 | } | |
81 | ||
82 | /* Get the public key from the certificate. */ | |
83 | key = X509_get_pubkey(cert); | |
84 | if (!key) { | |
85 | rsa_err("Couldn't read public key\n"); | |
86 | ret = -EINVAL; | |
87 | goto err_pubkey; | |
88 | } | |
89 | ||
90 | /* Convert to a RSA_style key. */ | |
91 | rsa = EVP_PKEY_get1_RSA(key); | |
92 | if (!rsa) { | |
93 | rsa_err("Couldn't convert to a RSA style key"); | |
54267162 | 94 | ret = -EINVAL; |
19c402af SG |
95 | goto err_rsa; |
96 | } | |
97 | fclose(f); | |
98 | EVP_PKEY_free(key); | |
99 | X509_free(cert); | |
100 | *rsap = rsa; | |
101 | ||
102 | return 0; | |
103 | ||
104 | err_rsa: | |
105 | EVP_PKEY_free(key); | |
106 | err_pubkey: | |
107 | X509_free(cert); | |
108 | err_cert: | |
109 | fclose(f); | |
110 | return ret; | |
111 | } | |
112 | ||
113 | /** | |
f1ca1fde | 114 | * rsa_engine_get_pub_key() - read a public key from given engine |
19c402af | 115 | * |
f1ca1fde GM |
116 | * @keydir: Key prefix |
117 | * @name Name of key | |
118 | * @engine Engine to use | |
119 | * @rsap Returns RSA object, or NULL on failure | |
120 | * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) | |
121 | */ | |
122 | static int rsa_engine_get_pub_key(const char *keydir, const char *name, | |
123 | ENGINE *engine, RSA **rsap) | |
124 | { | |
125 | const char *engine_id; | |
126 | char key_id[1024]; | |
127 | EVP_PKEY *key; | |
128 | RSA *rsa; | |
129 | int ret; | |
130 | ||
131 | *rsap = NULL; | |
132 | ||
133 | engine_id = ENGINE_get_id(engine); | |
134 | ||
135 | if (engine_id && !strcmp(engine_id, "pkcs11")) { | |
136 | if (keydir) | |
137 | snprintf(key_id, sizeof(key_id), | |
138 | "pkcs11:%s;object=%s;type=public", | |
139 | keydir, name); | |
140 | else | |
141 | snprintf(key_id, sizeof(key_id), | |
142 | "pkcs11:object=%s;type=public", | |
143 | name); | |
144 | } else { | |
145 | fprintf(stderr, "Engine not supported\n"); | |
146 | return -ENOTSUP; | |
147 | } | |
148 | ||
149 | key = ENGINE_load_public_key(engine, key_id, NULL, NULL); | |
150 | if (!key) | |
151 | return rsa_err("Failure loading public key from engine"); | |
152 | ||
153 | /* Convert to a RSA_style key. */ | |
154 | rsa = EVP_PKEY_get1_RSA(key); | |
155 | if (!rsa) { | |
156 | rsa_err("Couldn't convert to a RSA style key"); | |
157 | ret = -EINVAL; | |
158 | goto err_rsa; | |
159 | } | |
160 | ||
161 | EVP_PKEY_free(key); | |
162 | *rsap = rsa; | |
163 | ||
164 | return 0; | |
165 | ||
166 | err_rsa: | |
167 | EVP_PKEY_free(key); | |
168 | return ret; | |
169 | } | |
170 | ||
171 | /** | |
172 | * rsa_get_pub_key() - read a public key | |
173 | * | |
174 | * @keydir: Directory containing the key (PEM file) or key prefix (engine) | |
175 | * @name Name of key file (will have a .crt extension) | |
176 | * @engine Engine to use | |
177 | * @rsap Returns RSA object, or NULL on failure | |
178 | * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) | |
179 | */ | |
180 | static int rsa_get_pub_key(const char *keydir, const char *name, | |
181 | ENGINE *engine, RSA **rsap) | |
182 | { | |
183 | if (engine) | |
184 | return rsa_engine_get_pub_key(keydir, name, engine, rsap); | |
185 | return rsa_pem_get_pub_key(keydir, name, rsap); | |
186 | } | |
187 | ||
188 | /** | |
189 | * rsa_pem_get_priv_key() - read a private key from a .key file | |
190 | * | |
191 | * @keydir: Directory containing the key | |
19c402af SG |
192 | * @name Name of key file (will have a .key extension) |
193 | * @rsap Returns RSA object, or NULL on failure | |
194 | * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) | |
195 | */ | |
f1ca1fde GM |
196 | static int rsa_pem_get_priv_key(const char *keydir, const char *name, |
197 | RSA **rsap) | |
19c402af SG |
198 | { |
199 | char path[1024]; | |
200 | RSA *rsa; | |
201 | FILE *f; | |
202 | ||
203 | *rsap = NULL; | |
204 | snprintf(path, sizeof(path), "%s/%s.key", keydir, name); | |
205 | f = fopen(path, "r"); | |
206 | if (!f) { | |
207 | fprintf(stderr, "Couldn't open RSA private key: '%s': %s\n", | |
208 | path, strerror(errno)); | |
209 | return -ENOENT; | |
210 | } | |
211 | ||
212 | rsa = PEM_read_RSAPrivateKey(f, 0, NULL, path); | |
213 | if (!rsa) { | |
214 | rsa_err("Failure reading private key"); | |
215 | fclose(f); | |
216 | return -EPROTO; | |
217 | } | |
218 | fclose(f); | |
219 | *rsap = rsa; | |
220 | ||
221 | return 0; | |
222 | } | |
223 | ||
f1ca1fde GM |
224 | /** |
225 | * rsa_engine_get_priv_key() - read a private key from given engine | |
226 | * | |
227 | * @keydir: Key prefix | |
228 | * @name Name of key | |
229 | * @engine Engine to use | |
230 | * @rsap Returns RSA object, or NULL on failure | |
231 | * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) | |
232 | */ | |
233 | static int rsa_engine_get_priv_key(const char *keydir, const char *name, | |
234 | ENGINE *engine, RSA **rsap) | |
235 | { | |
236 | const char *engine_id; | |
237 | char key_id[1024]; | |
238 | EVP_PKEY *key; | |
239 | RSA *rsa; | |
240 | int ret; | |
241 | ||
242 | *rsap = NULL; | |
243 | ||
244 | engine_id = ENGINE_get_id(engine); | |
245 | ||
246 | if (engine_id && !strcmp(engine_id, "pkcs11")) { | |
247 | if (keydir) | |
248 | snprintf(key_id, sizeof(key_id), | |
249 | "pkcs11:%s;object=%s;type=private", | |
250 | keydir, name); | |
251 | else | |
252 | snprintf(key_id, sizeof(key_id), | |
253 | "pkcs11:object=%s;type=private", | |
254 | name); | |
255 | } else { | |
256 | fprintf(stderr, "Engine not supported\n"); | |
257 | return -ENOTSUP; | |
258 | } | |
259 | ||
260 | key = ENGINE_load_private_key(engine, key_id, NULL, NULL); | |
261 | if (!key) | |
262 | return rsa_err("Failure loading private key from engine"); | |
263 | ||
264 | /* Convert to a RSA_style key. */ | |
265 | rsa = EVP_PKEY_get1_RSA(key); | |
266 | if (!rsa) { | |
267 | rsa_err("Couldn't convert to a RSA style key"); | |
268 | ret = -EINVAL; | |
269 | goto err_rsa; | |
270 | } | |
271 | ||
272 | EVP_PKEY_free(key); | |
273 | *rsap = rsa; | |
274 | ||
275 | return 0; | |
276 | ||
277 | err_rsa: | |
278 | EVP_PKEY_free(key); | |
279 | return ret; | |
280 | } | |
281 | ||
282 | /** | |
283 | * rsa_get_priv_key() - read a private key | |
284 | * | |
285 | * @keydir: Directory containing the key (PEM file) or key prefix (engine) | |
286 | * @name Name of key | |
287 | * @engine Engine to use for signing | |
288 | * @rsap Returns RSA object, or NULL on failure | |
289 | * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) | |
290 | */ | |
291 | static int rsa_get_priv_key(const char *keydir, const char *name, | |
292 | ENGINE *engine, RSA **rsap) | |
293 | { | |
294 | if (engine) | |
295 | return rsa_engine_get_priv_key(keydir, name, engine, rsap); | |
296 | return rsa_pem_get_priv_key(keydir, name, rsap); | |
297 | } | |
298 | ||
19c402af SG |
299 | static int rsa_init(void) |
300 | { | |
301 | int ret; | |
302 | ||
c3b43281 | 303 | #if OPENSSL_VERSION_NUMBER < 0x10100000L |
19c402af | 304 | ret = SSL_library_init(); |
c3b43281 JW |
305 | #else |
306 | ret = OPENSSL_init_ssl(0, NULL); | |
307 | #endif | |
19c402af SG |
308 | if (!ret) { |
309 | fprintf(stderr, "Failure to init SSL library\n"); | |
310 | return -1; | |
311 | } | |
c3b43281 | 312 | #if OPENSSL_VERSION_NUMBER < 0x10100000L |
19c402af SG |
313 | SSL_load_error_strings(); |
314 | ||
315 | OpenSSL_add_all_algorithms(); | |
316 | OpenSSL_add_all_digests(); | |
317 | OpenSSL_add_all_ciphers(); | |
c3b43281 | 318 | #endif |
19c402af SG |
319 | |
320 | return 0; | |
321 | } | |
322 | ||
f1ca1fde GM |
323 | static int rsa_engine_init(const char *engine_id, ENGINE **pe) |
324 | { | |
325 | ENGINE *e; | |
326 | int ret; | |
327 | ||
328 | ENGINE_load_builtin_engines(); | |
329 | ||
330 | e = ENGINE_by_id(engine_id); | |
331 | if (!e) { | |
332 | fprintf(stderr, "Engine isn't available\n"); | |
333 | ret = -1; | |
334 | goto err_engine_by_id; | |
335 | } | |
336 | ||
337 | if (!ENGINE_init(e)) { | |
338 | fprintf(stderr, "Couldn't initialize engine\n"); | |
339 | ret = -1; | |
340 | goto err_engine_init; | |
341 | } | |
342 | ||
343 | if (!ENGINE_set_default_RSA(e)) { | |
344 | fprintf(stderr, "Couldn't set engine as default for RSA\n"); | |
345 | ret = -1; | |
346 | goto err_set_rsa; | |
347 | } | |
348 | ||
349 | *pe = e; | |
350 | ||
351 | return 0; | |
352 | ||
353 | err_set_rsa: | |
354 | ENGINE_finish(e); | |
355 | err_engine_init: | |
356 | ENGINE_free(e); | |
357 | err_engine_by_id: | |
c3b43281 | 358 | #if OPENSSL_VERSION_NUMBER < 0x10100000L |
f1ca1fde | 359 | ENGINE_cleanup(); |
c3b43281 | 360 | #endif |
f1ca1fde GM |
361 | return ret; |
362 | } | |
363 | ||
19c402af SG |
364 | static void rsa_remove(void) |
365 | { | |
c3b43281 | 366 | #if OPENSSL_VERSION_NUMBER < 0x10100000L |
19c402af SG |
367 | CRYPTO_cleanup_all_ex_data(); |
368 | ERR_free_strings(); | |
369 | #ifdef HAVE_ERR_REMOVE_THREAD_STATE | |
370 | ERR_remove_thread_state(NULL); | |
371 | #else | |
372 | ERR_remove_state(0); | |
373 | #endif | |
374 | EVP_cleanup(); | |
c3b43281 | 375 | #endif |
19c402af SG |
376 | } |
377 | ||
f1ca1fde GM |
378 | static void rsa_engine_remove(ENGINE *e) |
379 | { | |
380 | if (e) { | |
381 | ENGINE_finish(e); | |
382 | ENGINE_free(e); | |
383 | } | |
384 | } | |
385 | ||
646257d1 HS |
386 | static int rsa_sign_with_key(RSA *rsa, struct checksum_algo *checksum_algo, |
387 | const struct image_region region[], int region_count, | |
388 | uint8_t **sigp, uint *sig_size) | |
19c402af SG |
389 | { |
390 | EVP_PKEY *key; | |
391 | EVP_MD_CTX *context; | |
392 | int size, ret = 0; | |
393 | uint8_t *sig; | |
394 | int i; | |
395 | ||
396 | key = EVP_PKEY_new(); | |
397 | if (!key) | |
398 | return rsa_err("EVP_PKEY object creation failed"); | |
399 | ||
400 | if (!EVP_PKEY_set1_RSA(key, rsa)) { | |
401 | ret = rsa_err("EVP key setup failed"); | |
402 | goto err_set; | |
403 | } | |
404 | ||
405 | size = EVP_PKEY_size(key); | |
406 | sig = malloc(size); | |
407 | if (!sig) { | |
408 | fprintf(stderr, "Out of memory for signature (%d bytes)\n", | |
409 | size); | |
410 | ret = -ENOMEM; | |
411 | goto err_alloc; | |
412 | } | |
413 | ||
414 | context = EVP_MD_CTX_create(); | |
415 | if (!context) { | |
416 | ret = rsa_err("EVP context creation failed"); | |
417 | goto err_create; | |
418 | } | |
419 | EVP_MD_CTX_init(context); | |
29a23f9d | 420 | if (!EVP_SignInit(context, checksum_algo->calculate_sign())) { |
19c402af SG |
421 | ret = rsa_err("Signer setup failed"); |
422 | goto err_sign; | |
423 | } | |
424 | ||
425 | for (i = 0; i < region_count; i++) { | |
426 | if (!EVP_SignUpdate(context, region[i].data, region[i].size)) { | |
427 | ret = rsa_err("Signing data failed"); | |
428 | goto err_sign; | |
429 | } | |
430 | } | |
431 | ||
432 | if (!EVP_SignFinal(context, sig, sig_size, key)) { | |
433 | ret = rsa_err("Could not obtain signature"); | |
434 | goto err_sign; | |
435 | } | |
c3b43281 JW |
436 | #if OPENSSL_VERSION_NUMBER < 0x10100000L |
437 | EVP_MD_CTX_cleanup(context); | |
438 | #else | |
439 | EVP_MD_CTX_reset(context); | |
440 | #endif | |
19c402af SG |
441 | EVP_MD_CTX_destroy(context); |
442 | EVP_PKEY_free(key); | |
443 | ||
444 | debug("Got signature: %d bytes, expected %d\n", *sig_size, size); | |
445 | *sigp = sig; | |
446 | *sig_size = size; | |
447 | ||
448 | return 0; | |
449 | ||
450 | err_sign: | |
451 | EVP_MD_CTX_destroy(context); | |
452 | err_create: | |
453 | free(sig); | |
454 | err_alloc: | |
455 | err_set: | |
456 | EVP_PKEY_free(key); | |
457 | return ret; | |
458 | } | |
459 | ||
460 | int rsa_sign(struct image_sign_info *info, | |
461 | const struct image_region region[], int region_count, | |
462 | uint8_t **sigp, uint *sig_len) | |
463 | { | |
464 | RSA *rsa; | |
f1ca1fde | 465 | ENGINE *e = NULL; |
19c402af SG |
466 | int ret; |
467 | ||
468 | ret = rsa_init(); | |
469 | if (ret) | |
470 | return ret; | |
471 | ||
f1ca1fde GM |
472 | if (info->engine_id) { |
473 | ret = rsa_engine_init(info->engine_id, &e); | |
474 | if (ret) | |
475 | goto err_engine; | |
476 | } | |
477 | ||
478 | ret = rsa_get_priv_key(info->keydir, info->keyname, e, &rsa); | |
19c402af SG |
479 | if (ret) |
480 | goto err_priv; | |
83dd98e0 | 481 | ret = rsa_sign_with_key(rsa, info->checksum, region, |
646257d1 | 482 | region_count, sigp, sig_len); |
19c402af SG |
483 | if (ret) |
484 | goto err_sign; | |
485 | ||
486 | RSA_free(rsa); | |
f1ca1fde GM |
487 | if (info->engine_id) |
488 | rsa_engine_remove(e); | |
19c402af SG |
489 | rsa_remove(); |
490 | ||
491 | return ret; | |
492 | ||
493 | err_sign: | |
494 | RSA_free(rsa); | |
495 | err_priv: | |
f1ca1fde GM |
496 | if (info->engine_id) |
497 | rsa_engine_remove(e); | |
498 | err_engine: | |
19c402af SG |
499 | rsa_remove(); |
500 | return ret; | |
501 | } | |
502 | ||
e0f2f155 MW |
503 | /* |
504 | * rsa_get_exponent(): - Get the public exponent from an RSA key | |
505 | */ | |
506 | static int rsa_get_exponent(RSA *key, uint64_t *e) | |
507 | { | |
508 | int ret; | |
509 | BIGNUM *bn_te; | |
c3b43281 | 510 | const BIGNUM *key_e; |
e0f2f155 MW |
511 | uint64_t te; |
512 | ||
513 | ret = -EINVAL; | |
514 | bn_te = NULL; | |
515 | ||
516 | if (!e) | |
517 | goto cleanup; | |
518 | ||
c3b43281 JW |
519 | RSA_get0_key(key, NULL, &key_e, NULL); |
520 | if (BN_num_bits(key_e) > 64) | |
e0f2f155 MW |
521 | goto cleanup; |
522 | ||
c3b43281 | 523 | *e = BN_get_word(key_e); |
e0f2f155 | 524 | |
c3b43281 | 525 | if (BN_num_bits(key_e) < 33) { |
e0f2f155 MW |
526 | ret = 0; |
527 | goto cleanup; | |
528 | } | |
529 | ||
c3b43281 | 530 | bn_te = BN_dup(key_e); |
e0f2f155 MW |
531 | if (!bn_te) |
532 | goto cleanup; | |
533 | ||
534 | if (!BN_rshift(bn_te, bn_te, 32)) | |
535 | goto cleanup; | |
536 | ||
537 | if (!BN_mask_bits(bn_te, 32)) | |
538 | goto cleanup; | |
539 | ||
540 | te = BN_get_word(bn_te); | |
541 | te <<= 32; | |
542 | *e |= te; | |
543 | ret = 0; | |
544 | ||
545 | cleanup: | |
546 | if (bn_te) | |
547 | BN_free(bn_te); | |
548 | ||
549 | return ret; | |
550 | } | |
551 | ||
19c402af SG |
552 | /* |
553 | * rsa_get_params(): - Get the important parameters of an RSA public key | |
554 | */ | |
e0f2f155 MW |
555 | int rsa_get_params(RSA *key, uint64_t *exponent, uint32_t *n0_invp, |
556 | BIGNUM **modulusp, BIGNUM **r_squaredp) | |
19c402af SG |
557 | { |
558 | BIGNUM *big1, *big2, *big32, *big2_32; | |
559 | BIGNUM *n, *r, *r_squared, *tmp; | |
c3b43281 | 560 | const BIGNUM *key_n; |
19c402af SG |
561 | BN_CTX *bn_ctx = BN_CTX_new(); |
562 | int ret = 0; | |
563 | ||
564 | /* Initialize BIGNUMs */ | |
565 | big1 = BN_new(); | |
566 | big2 = BN_new(); | |
567 | big32 = BN_new(); | |
568 | r = BN_new(); | |
569 | r_squared = BN_new(); | |
570 | tmp = BN_new(); | |
571 | big2_32 = BN_new(); | |
572 | n = BN_new(); | |
573 | if (!big1 || !big2 || !big32 || !r || !r_squared || !tmp || !big2_32 || | |
574 | !n) { | |
575 | fprintf(stderr, "Out of memory (bignum)\n"); | |
576 | return -ENOMEM; | |
577 | } | |
578 | ||
e0f2f155 MW |
579 | if (0 != rsa_get_exponent(key, exponent)) |
580 | ret = -1; | |
581 | ||
c3b43281 JW |
582 | RSA_get0_key(key, &key_n, NULL, NULL); |
583 | if (!BN_copy(n, key_n) || !BN_set_word(big1, 1L) || | |
19c402af SG |
584 | !BN_set_word(big2, 2L) || !BN_set_word(big32, 32L)) |
585 | ret = -1; | |
586 | ||
587 | /* big2_32 = 2^32 */ | |
588 | if (!BN_exp(big2_32, big2, big32, bn_ctx)) | |
589 | ret = -1; | |
590 | ||
591 | /* Calculate n0_inv = -1 / n[0] mod 2^32 */ | |
592 | if (!BN_mod_inverse(tmp, n, big2_32, bn_ctx) || | |
593 | !BN_sub(tmp, big2_32, tmp)) | |
594 | ret = -1; | |
595 | *n0_invp = BN_get_word(tmp); | |
596 | ||
597 | /* Calculate R = 2^(# of key bits) */ | |
598 | if (!BN_set_word(tmp, BN_num_bits(n)) || | |
599 | !BN_exp(r, big2, tmp, bn_ctx)) | |
600 | ret = -1; | |
601 | ||
602 | /* Calculate r_squared = R^2 mod n */ | |
603 | if (!BN_copy(r_squared, r) || | |
604 | !BN_mul(tmp, r_squared, r, bn_ctx) || | |
605 | !BN_mod(r_squared, tmp, n, bn_ctx)) | |
606 | ret = -1; | |
607 | ||
608 | *modulusp = n; | |
609 | *r_squaredp = r_squared; | |
610 | ||
611 | BN_free(big1); | |
612 | BN_free(big2); | |
613 | BN_free(big32); | |
614 | BN_free(r); | |
615 | BN_free(tmp); | |
616 | BN_free(big2_32); | |
617 | if (ret) { | |
618 | fprintf(stderr, "Bignum operations failed\n"); | |
619 | return -ENOMEM; | |
620 | } | |
621 | ||
622 | return ret; | |
623 | } | |
624 | ||
625 | static int fdt_add_bignum(void *blob, int noffset, const char *prop_name, | |
626 | BIGNUM *num, int num_bits) | |
627 | { | |
628 | int nwords = num_bits / 32; | |
629 | int size; | |
630 | uint32_t *buf, *ptr; | |
631 | BIGNUM *tmp, *big2, *big32, *big2_32; | |
632 | BN_CTX *ctx; | |
633 | int ret; | |
634 | ||
635 | tmp = BN_new(); | |
636 | big2 = BN_new(); | |
637 | big32 = BN_new(); | |
638 | big2_32 = BN_new(); | |
639 | if (!tmp || !big2 || !big32 || !big2_32) { | |
640 | fprintf(stderr, "Out of memory (bignum)\n"); | |
641 | return -ENOMEM; | |
642 | } | |
643 | ctx = BN_CTX_new(); | |
644 | if (!tmp) { | |
645 | fprintf(stderr, "Out of memory (bignum context)\n"); | |
646 | return -ENOMEM; | |
647 | } | |
648 | BN_set_word(big2, 2L); | |
649 | BN_set_word(big32, 32L); | |
650 | BN_exp(big2_32, big2, big32, ctx); /* B = 2^32 */ | |
651 | ||
652 | size = nwords * sizeof(uint32_t); | |
653 | buf = malloc(size); | |
654 | if (!buf) { | |
655 | fprintf(stderr, "Out of memory (%d bytes)\n", size); | |
656 | return -ENOMEM; | |
657 | } | |
658 | ||
659 | /* Write out modulus as big endian array of integers */ | |
660 | for (ptr = buf + nwords - 1; ptr >= buf; ptr--) { | |
661 | BN_mod(tmp, num, big2_32, ctx); /* n = N mod B */ | |
662 | *ptr = cpu_to_fdt32(BN_get_word(tmp)); | |
663 | BN_rshift(num, num, 32); /* N = N/B */ | |
664 | } | |
665 | ||
713fb2dc | 666 | /* |
667 | * We try signing with successively increasing size values, so this | |
668 | * might fail several times | |
669 | */ | |
19c402af | 670 | ret = fdt_setprop(blob, noffset, prop_name, buf, size); |
2b9ec762 | 671 | if (ret) |
672 | return -FDT_ERR_NOSPACE; | |
19c402af SG |
673 | free(buf); |
674 | BN_free(tmp); | |
675 | BN_free(big2); | |
676 | BN_free(big32); | |
677 | BN_free(big2_32); | |
678 | ||
679 | return ret; | |
680 | } | |
681 | ||
682 | int rsa_add_verify_data(struct image_sign_info *info, void *keydest) | |
683 | { | |
684 | BIGNUM *modulus, *r_squared; | |
e0f2f155 | 685 | uint64_t exponent; |
19c402af SG |
686 | uint32_t n0_inv; |
687 | int parent, node; | |
688 | char name[100]; | |
689 | int ret; | |
690 | int bits; | |
691 | RSA *rsa; | |
f1ca1fde | 692 | ENGINE *e = NULL; |
19c402af SG |
693 | |
694 | debug("%s: Getting verification data\n", __func__); | |
f1ca1fde GM |
695 | if (info->engine_id) { |
696 | ret = rsa_engine_init(info->engine_id, &e); | |
697 | if (ret) | |
698 | return ret; | |
699 | } | |
700 | ret = rsa_get_pub_key(info->keydir, info->keyname, e, &rsa); | |
19c402af | 701 | if (ret) |
f1ca1fde | 702 | goto err_get_pub_key; |
e0f2f155 | 703 | ret = rsa_get_params(rsa, &exponent, &n0_inv, &modulus, &r_squared); |
19c402af | 704 | if (ret) |
f1ca1fde | 705 | goto err_get_params; |
19c402af SG |
706 | bits = BN_num_bits(modulus); |
707 | parent = fdt_subnode_offset(keydest, 0, FIT_SIG_NODENAME); | |
708 | if (parent == -FDT_ERR_NOTFOUND) { | |
709 | parent = fdt_add_subnode(keydest, 0, FIT_SIG_NODENAME); | |
710 | if (parent < 0) { | |
597a8b2c SG |
711 | ret = parent; |
712 | if (ret != -FDT_ERR_NOSPACE) { | |
713 | fprintf(stderr, "Couldn't create signature node: %s\n", | |
714 | fdt_strerror(parent)); | |
715 | } | |
19c402af SG |
716 | } |
717 | } | |
597a8b2c SG |
718 | if (ret) |
719 | goto done; | |
19c402af SG |
720 | |
721 | /* Either create or overwrite the named key node */ | |
722 | snprintf(name, sizeof(name), "key-%s", info->keyname); | |
723 | node = fdt_subnode_offset(keydest, parent, name); | |
724 | if (node == -FDT_ERR_NOTFOUND) { | |
725 | node = fdt_add_subnode(keydest, parent, name); | |
726 | if (node < 0) { | |
597a8b2c SG |
727 | ret = node; |
728 | if (ret != -FDT_ERR_NOSPACE) { | |
729 | fprintf(stderr, "Could not create key subnode: %s\n", | |
730 | fdt_strerror(node)); | |
731 | } | |
19c402af SG |
732 | } |
733 | } else if (node < 0) { | |
734 | fprintf(stderr, "Cannot select keys parent: %s\n", | |
735 | fdt_strerror(node)); | |
597a8b2c | 736 | ret = node; |
19c402af SG |
737 | } |
738 | ||
597a8b2c SG |
739 | if (!ret) { |
740 | ret = fdt_setprop_string(keydest, node, "key-name-hint", | |
19c402af | 741 | info->keyname); |
597a8b2c | 742 | } |
4f427a42 SG |
743 | if (!ret) |
744 | ret = fdt_setprop_u32(keydest, node, "rsa,num-bits", bits); | |
745 | if (!ret) | |
746 | ret = fdt_setprop_u32(keydest, node, "rsa,n0-inverse", n0_inv); | |
e0f2f155 MW |
747 | if (!ret) { |
748 | ret = fdt_setprop_u64(keydest, node, "rsa,exponent", exponent); | |
749 | } | |
4f427a42 SG |
750 | if (!ret) { |
751 | ret = fdt_add_bignum(keydest, node, "rsa,modulus", modulus, | |
752 | bits); | |
753 | } | |
754 | if (!ret) { | |
755 | ret = fdt_add_bignum(keydest, node, "rsa,r-squared", r_squared, | |
756 | bits); | |
757 | } | |
758 | if (!ret) { | |
759 | ret = fdt_setprop_string(keydest, node, FIT_ALGO_PROP, | |
83dd98e0 | 760 | info->name); |
4f427a42 | 761 | } |
2b9ec762 | 762 | if (!ret && info->require_keys) { |
4f427a42 SG |
763 | ret = fdt_setprop_string(keydest, node, "required", |
764 | info->require_keys); | |
19c402af | 765 | } |
597a8b2c | 766 | done: |
19c402af SG |
767 | BN_free(modulus); |
768 | BN_free(r_squared); | |
769 | if (ret) | |
f1ca1fde GM |
770 | ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO; |
771 | err_get_params: | |
772 | RSA_free(rsa); | |
773 | err_get_pub_key: | |
774 | if (info->engine_id) | |
775 | rsa_engine_remove(e); | |
19c402af | 776 | |
f1ca1fde | 777 | return ret; |
19c402af | 778 | } |