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