Commit f1ca1fdebf1cde1c37c91b3d85f8b7af111112ea
Committed by
Tom Rini
1 parent
b1c6a54a53
Exists in
smarc_8mq_lf_v2020.04
and in
22 other branches
mkimage: Add support for signing with pkcs11
Add support for signing with the pkcs11 engine. This allows FIT images to be signed with keys securely stored on a smartcard, hardware security module, etc without exposing the keys. Support for other engines can be added in the future by modifying rsa_engine_get_pub_key() and rsa_engine_get_priv_key() to construct correct key_id strings. Signed-off-by: George McCollister <george.mccollister@gmail.com>
Showing 7 changed files with 408 additions and 28 deletions Side-by-side Diff
doc/uImage.FIT/signature.txt
... | ... | @@ -385,6 +385,149 @@ |
385 | 385 | Test passed |
386 | 386 | |
387 | 387 | |
388 | +Hardware Signing with PKCS#11 | |
389 | +----------------------------- | |
390 | + | |
391 | +Securely managing private signing keys can challenging, especially when the | |
392 | +keys are stored on the file system of a computer that is connected to the | |
393 | +Internet. If an attacker is able to steal the key, they can sign malicious FIT | |
394 | +images which will appear genuine to your devices. | |
395 | + | |
396 | +An alternative solution is to keep your signing key securely stored on hardware | |
397 | +device like a smartcard, USB token or Hardware Security Module (HSM) and have | |
398 | +them perform the signing. PKCS#11 is standard for interfacing with these crypto | |
399 | +device. | |
400 | + | |
401 | +Requirements: | |
402 | +Smartcard/USB token/HSM which can work with the pkcs11 engine | |
403 | +openssl | |
404 | +libp11 (provides pkcs11 engine) | |
405 | +p11-kit (recommended to simplify setup) | |
406 | +opensc (for smartcards and smartcard like USB devices) | |
407 | +gnutls (recommended for key generation, p11tool) | |
408 | + | |
409 | +The following examples use the Nitrokey Pro. Instructions for other devices may vary. | |
410 | + | |
411 | +Notes on pkcs11 engine setup: | |
412 | + | |
413 | +Make sure p11-kit, opensc are installed and that p11-kit is setup to use opensc. | |
414 | +/usr/share/p11-kit/modules/opensc.module should be present on your system. | |
415 | + | |
416 | + | |
417 | +Generating Keys On the Nitrokey: | |
418 | + | |
419 | +$ gpg --card-edit | |
420 | + | |
421 | +Reader ...........: Nitrokey Nitrokey Pro (xxxxxxxx0000000000000000) 00 00 | |
422 | +Application ID ...: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | |
423 | +Version ..........: 2.1 | |
424 | +Manufacturer .....: ZeitControl | |
425 | +Serial number ....: xxxxxxxx | |
426 | +Name of cardholder: [not set] | |
427 | +Language prefs ...: de | |
428 | +Sex ..............: unspecified | |
429 | +URL of public key : [not set] | |
430 | +Login data .......: [not set] | |
431 | +Signature PIN ....: forced | |
432 | +Key attributes ...: rsa2048 rsa2048 rsa2048 | |
433 | +Max. PIN lengths .: 32 32 32 | |
434 | +PIN retry counter : 3 0 3 | |
435 | +Signature counter : 0 | |
436 | +Signature key ....: [none] | |
437 | +Encryption key....: [none] | |
438 | +Authentication key: [none] | |
439 | +General key info..: [none] | |
440 | + | |
441 | +gpg/card> generate | |
442 | +Make off-card backup of encryption key? (Y/n) n | |
443 | + | |
444 | +Please note that the factory settings of the PINs are | |
445 | + PIN = '123456' Admin PIN = '12345678' | |
446 | +You should change them using the command --change-pin | |
447 | + | |
448 | +What keysize do you want for the Signature key? (2048) 4096 | |
449 | +The card will now be re-configured to generate a key of 4096 bits | |
450 | +Note: There is no guarantee that the card supports the requested size. | |
451 | + If the key generation does not succeed, please check the | |
452 | + documentation of your card to see what sizes are allowed. | |
453 | +What keysize do you want for the Encryption key? (2048) 4096 | |
454 | +The card will now be re-configured to generate a key of 4096 bits | |
455 | +What keysize do you want for the Authentication key? (2048) 4096 | |
456 | +The card will now be re-configured to generate a key of 4096 bits | |
457 | +Please specify how long the key should be valid. | |
458 | + 0 = key does not expire | |
459 | + <n> = key expires in n days | |
460 | + <n>w = key expires in n weeks | |
461 | + <n>m = key expires in n months | |
462 | + <n>y = key expires in n years | |
463 | +Key is valid for? (0) | |
464 | +Key does not expire at all | |
465 | +Is this correct? (y/N) y | |
466 | + | |
467 | +GnuPG needs to construct a user ID to identify your key. | |
468 | + | |
469 | +Real name: John Doe | |
470 | +Email address: john.doe@email.com | |
471 | +Comment: | |
472 | +You selected this USER-ID: | |
473 | + "John Doe <john.doe@email.com>" | |
474 | + | |
475 | +Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o | |
476 | + | |
477 | + | |
478 | +Using p11tool to get the token URL: | |
479 | + | |
480 | +Depending on system configuration, gpg-agent may need to be killed first. | |
481 | + | |
482 | +$ p11tool --provider /usr/lib/opensc-pkcs11.so --list-tokens | |
483 | +Token 0: | |
484 | +URL: pkcs11:model=PKCS%2315%20emulated;manufacturer=ZeitControl;serial=000xxxxxxxxx;token=OpenPGP%20card%20%28User%20PIN%20%28sig%29%29 | |
485 | +Label: OpenPGP card (User PIN (sig)) | |
486 | +Type: Hardware token | |
487 | +Manufacturer: ZeitControl | |
488 | +Model: PKCS#15 emulated | |
489 | +Serial: 000xxxxxxxxx | |
490 | +Module: (null) | |
491 | + | |
492 | + | |
493 | +Token 1: | |
494 | +URL: pkcs11:model=PKCS%2315%20emulated;manufacturer=ZeitControl;serial=000xxxxxxxxx;token=OpenPGP%20card%20%28User%20PIN%29 | |
495 | +Label: OpenPGP card (User PIN) | |
496 | +Type: Hardware token | |
497 | +Manufacturer: ZeitControl | |
498 | +Model: PKCS#15 emulated | |
499 | +Serial: 000xxxxxxxxx | |
500 | +Module: (null) | |
501 | + | |
502 | +Use the portion of the signature token URL after "pkcs11:" as the keydir argument (-k) to mkimage below. | |
503 | + | |
504 | + | |
505 | +Use the URL of the token to list the private keys: | |
506 | + | |
507 | +$ p11tool --login --provider /usr/lib/opensc-pkcs11.so --list-privkeys \ | |
508 | +"pkcs11:model=PKCS%2315%20emulated;manufacturer=ZeitControl;serial=000xxxxxxxxx;token=OpenPGP%20card%20%28User%20PIN%20%28sig%29%29" | |
509 | +Token 'OpenPGP card (User PIN (sig))' with URL 'pkcs11:model=PKCS%2315%20emulated;manufacturer=ZeitControl;serial=000xxxxxxxxx;token=OpenPGP%20card%20%28User%20PIN%20%28sig%29%29' requires user PIN | |
510 | +Enter PIN: | |
511 | +Object 0: | |
512 | +URL: pkcs11:model=PKCS%2315%20emulated;manufacturer=ZeitControl;serial=000xxxxxxxxx;token=OpenPGP%20card%20%28User%20PIN%20%28sig%29%29;id=%01;object=Signature%20key;type=private | |
513 | +Type: Private key | |
514 | +Label: Signature key | |
515 | +Flags: CKA_PRIVATE; CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE; | |
516 | +ID: 01 | |
517 | + | |
518 | +Use the label, in this case "Signature key" as the key-name-hint in your FIT. | |
519 | + | |
520 | +Create the fitImage: | |
521 | +$ ./tools/mkimage -f fit-image.its fitImage | |
522 | + | |
523 | + | |
524 | +Sign the fitImage with the hardware key: | |
525 | + | |
526 | +$ ./tools/mkimage -F -k \ | |
527 | +"model=PKCS%2315%20emulated;manufacturer=ZeitControl;serial=000xxxxxxxxx;token=OpenPGP%20card%20%28User%20PIN%20%28sig%29%29" \ | |
528 | +-K u-boot.dtb -N pkcs11 -r fitImage | |
529 | + | |
530 | + | |
388 | 531 | Future Work |
389 | 532 | ----------- |
390 | 533 | - Roll-back protection using a TPM is done using the tpm command. This can |
include/image.h
... | ... | @@ -965,6 +965,7 @@ |
965 | 965 | * @fit: Pointer to the FIT format image header |
966 | 966 | * @comment: Comment to add to signature nodes |
967 | 967 | * @require_keys: Mark all keys as 'required' |
968 | + * @engine_id: Engine to use for signing | |
968 | 969 | * |
969 | 970 | * Adds hash values for all component images in the FIT blob. |
970 | 971 | * Hashes are calculated for all component images which have hash subnodes |
... | ... | @@ -977,7 +978,8 @@ |
977 | 978 | * libfdt error code, on failure |
978 | 979 | */ |
979 | 980 | int fit_add_verification_data(const char *keydir, void *keydest, void *fit, |
980 | - const char *comment, int require_keys); | |
981 | + const char *comment, int require_keys, | |
982 | + const char *engine_id); | |
981 | 983 | |
982 | 984 | int fit_image_verify(const void *fit, int noffset); |
983 | 985 | int fit_config_verify(const void *fit, int conf_noffset); |
... | ... | @@ -1057,6 +1059,7 @@ |
1057 | 1059 | const void *fdt_blob; /* FDT containing public keys */ |
1058 | 1060 | int required_keynode; /* Node offset of key to use: -1=any */ |
1059 | 1061 | const char *require_keys; /* Value for 'required' property */ |
1062 | + const char *engine_id; /* Engine to use for signing */ | |
1060 | 1063 | }; |
1061 | 1064 | #endif /* Allow struct image_region to always be defined for rsa.h */ |
1062 | 1065 |
lib/rsa/rsa-sign.c
... | ... | @@ -14,6 +14,7 @@ |
14 | 14 | #include <openssl/err.h> |
15 | 15 | #include <openssl/ssl.h> |
16 | 16 | #include <openssl/evp.h> |
17 | +#include <openssl/engine.h> | |
17 | 18 | |
18 | 19 | #if OPENSSL_VERSION_NUMBER >= 0x10000000L |
19 | 20 | #define HAVE_ERR_REMOVE_THREAD_STATE |
20 | 21 | |
... | ... | @@ -31,14 +32,14 @@ |
31 | 32 | } |
32 | 33 | |
33 | 34 | /** |
34 | - * rsa_get_pub_key() - read a public key from a .crt file | |
35 | + * rsa_pem_get_pub_key() - read a public key from a .crt file | |
35 | 36 | * |
36 | 37 | * @keydir: Directory containins the key |
37 | 38 | * @name Name of key file (will have a .crt extension) |
38 | 39 | * @rsap Returns RSA object, or NULL on failure |
39 | 40 | * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) |
40 | 41 | */ |
41 | -static int rsa_get_pub_key(const char *keydir, const char *name, RSA **rsap) | |
42 | +static int rsa_pem_get_pub_key(const char *keydir, const char *name, RSA **rsap) | |
42 | 43 | { |
43 | 44 | char path[1024]; |
44 | 45 | EVP_PKEY *key; |
45 | 46 | |
46 | 47 | |
... | ... | @@ -96,14 +97,90 @@ |
96 | 97 | } |
97 | 98 | |
98 | 99 | /** |
99 | - * rsa_get_priv_key() - read a private key from a .key file | |
100 | + * rsa_engine_get_pub_key() - read a public key from given engine | |
100 | 101 | * |
101 | - * @keydir: Directory containins the key | |
102 | + * @keydir: Key prefix | |
103 | + * @name Name of key | |
104 | + * @engine Engine to use | |
105 | + * @rsap Returns RSA object, or NULL on failure | |
106 | + * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) | |
107 | + */ | |
108 | +static int rsa_engine_get_pub_key(const char *keydir, const char *name, | |
109 | + ENGINE *engine, RSA **rsap) | |
110 | +{ | |
111 | + const char *engine_id; | |
112 | + char key_id[1024]; | |
113 | + EVP_PKEY *key; | |
114 | + RSA *rsa; | |
115 | + int ret; | |
116 | + | |
117 | + *rsap = NULL; | |
118 | + | |
119 | + engine_id = ENGINE_get_id(engine); | |
120 | + | |
121 | + if (engine_id && !strcmp(engine_id, "pkcs11")) { | |
122 | + if (keydir) | |
123 | + snprintf(key_id, sizeof(key_id), | |
124 | + "pkcs11:%s;object=%s;type=public", | |
125 | + keydir, name); | |
126 | + else | |
127 | + snprintf(key_id, sizeof(key_id), | |
128 | + "pkcs11:object=%s;type=public", | |
129 | + name); | |
130 | + } else { | |
131 | + fprintf(stderr, "Engine not supported\n"); | |
132 | + return -ENOTSUP; | |
133 | + } | |
134 | + | |
135 | + key = ENGINE_load_public_key(engine, key_id, NULL, NULL); | |
136 | + if (!key) | |
137 | + return rsa_err("Failure loading public key from engine"); | |
138 | + | |
139 | + /* Convert to a RSA_style key. */ | |
140 | + rsa = EVP_PKEY_get1_RSA(key); | |
141 | + if (!rsa) { | |
142 | + rsa_err("Couldn't convert to a RSA style key"); | |
143 | + ret = -EINVAL; | |
144 | + goto err_rsa; | |
145 | + } | |
146 | + | |
147 | + EVP_PKEY_free(key); | |
148 | + *rsap = rsa; | |
149 | + | |
150 | + return 0; | |
151 | + | |
152 | +err_rsa: | |
153 | + EVP_PKEY_free(key); | |
154 | + return ret; | |
155 | +} | |
156 | + | |
157 | +/** | |
158 | + * rsa_get_pub_key() - read a public key | |
159 | + * | |
160 | + * @keydir: Directory containing the key (PEM file) or key prefix (engine) | |
161 | + * @name Name of key file (will have a .crt extension) | |
162 | + * @engine Engine to use | |
163 | + * @rsap Returns RSA object, or NULL on failure | |
164 | + * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) | |
165 | + */ | |
166 | +static int rsa_get_pub_key(const char *keydir, const char *name, | |
167 | + ENGINE *engine, RSA **rsap) | |
168 | +{ | |
169 | + if (engine) | |
170 | + return rsa_engine_get_pub_key(keydir, name, engine, rsap); | |
171 | + return rsa_pem_get_pub_key(keydir, name, rsap); | |
172 | +} | |
173 | + | |
174 | +/** | |
175 | + * rsa_pem_get_priv_key() - read a private key from a .key file | |
176 | + * | |
177 | + * @keydir: Directory containing the key | |
102 | 178 | * @name Name of key file (will have a .key extension) |
103 | 179 | * @rsap Returns RSA object, or NULL on failure |
104 | 180 | * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) |
105 | 181 | */ |
106 | -static int rsa_get_priv_key(const char *keydir, const char *name, RSA **rsap) | |
182 | +static int rsa_pem_get_priv_key(const char *keydir, const char *name, | |
183 | + RSA **rsap) | |
107 | 184 | { |
108 | 185 | char path[1024]; |
109 | 186 | RSA *rsa; |
... | ... | @@ -130,6 +207,81 @@ |
130 | 207 | return 0; |
131 | 208 | } |
132 | 209 | |
210 | +/** | |
211 | + * rsa_engine_get_priv_key() - read a private key from given engine | |
212 | + * | |
213 | + * @keydir: Key prefix | |
214 | + * @name Name of key | |
215 | + * @engine Engine to use | |
216 | + * @rsap Returns RSA object, or NULL on failure | |
217 | + * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) | |
218 | + */ | |
219 | +static int rsa_engine_get_priv_key(const char *keydir, const char *name, | |
220 | + ENGINE *engine, RSA **rsap) | |
221 | +{ | |
222 | + const char *engine_id; | |
223 | + char key_id[1024]; | |
224 | + EVP_PKEY *key; | |
225 | + RSA *rsa; | |
226 | + int ret; | |
227 | + | |
228 | + *rsap = NULL; | |
229 | + | |
230 | + engine_id = ENGINE_get_id(engine); | |
231 | + | |
232 | + if (engine_id && !strcmp(engine_id, "pkcs11")) { | |
233 | + if (keydir) | |
234 | + snprintf(key_id, sizeof(key_id), | |
235 | + "pkcs11:%s;object=%s;type=private", | |
236 | + keydir, name); | |
237 | + else | |
238 | + snprintf(key_id, sizeof(key_id), | |
239 | + "pkcs11:object=%s;type=private", | |
240 | + name); | |
241 | + } else { | |
242 | + fprintf(stderr, "Engine not supported\n"); | |
243 | + return -ENOTSUP; | |
244 | + } | |
245 | + | |
246 | + key = ENGINE_load_private_key(engine, key_id, NULL, NULL); | |
247 | + if (!key) | |
248 | + return rsa_err("Failure loading private key from engine"); | |
249 | + | |
250 | + /* Convert to a RSA_style key. */ | |
251 | + rsa = EVP_PKEY_get1_RSA(key); | |
252 | + if (!rsa) { | |
253 | + rsa_err("Couldn't convert to a RSA style key"); | |
254 | + ret = -EINVAL; | |
255 | + goto err_rsa; | |
256 | + } | |
257 | + | |
258 | + EVP_PKEY_free(key); | |
259 | + *rsap = rsa; | |
260 | + | |
261 | + return 0; | |
262 | + | |
263 | +err_rsa: | |
264 | + EVP_PKEY_free(key); | |
265 | + return ret; | |
266 | +} | |
267 | + | |
268 | +/** | |
269 | + * rsa_get_priv_key() - read a private key | |
270 | + * | |
271 | + * @keydir: Directory containing the key (PEM file) or key prefix (engine) | |
272 | + * @name Name of key | |
273 | + * @engine Engine to use for signing | |
274 | + * @rsap Returns RSA object, or NULL on failure | |
275 | + * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) | |
276 | + */ | |
277 | +static int rsa_get_priv_key(const char *keydir, const char *name, | |
278 | + ENGINE *engine, RSA **rsap) | |
279 | +{ | |
280 | + if (engine) | |
281 | + return rsa_engine_get_priv_key(keydir, name, engine, rsap); | |
282 | + return rsa_pem_get_priv_key(keydir, name, rsap); | |
283 | +} | |
284 | + | |
133 | 285 | static int rsa_init(void) |
134 | 286 | { |
135 | 287 | int ret; |
... | ... | @@ -148,6 +300,45 @@ |
148 | 300 | return 0; |
149 | 301 | } |
150 | 302 | |
303 | +static int rsa_engine_init(const char *engine_id, ENGINE **pe) | |
304 | +{ | |
305 | + ENGINE *e; | |
306 | + int ret; | |
307 | + | |
308 | + ENGINE_load_builtin_engines(); | |
309 | + | |
310 | + e = ENGINE_by_id(engine_id); | |
311 | + if (!e) { | |
312 | + fprintf(stderr, "Engine isn't available\n"); | |
313 | + ret = -1; | |
314 | + goto err_engine_by_id; | |
315 | + } | |
316 | + | |
317 | + if (!ENGINE_init(e)) { | |
318 | + fprintf(stderr, "Couldn't initialize engine\n"); | |
319 | + ret = -1; | |
320 | + goto err_engine_init; | |
321 | + } | |
322 | + | |
323 | + if (!ENGINE_set_default_RSA(e)) { | |
324 | + fprintf(stderr, "Couldn't set engine as default for RSA\n"); | |
325 | + ret = -1; | |
326 | + goto err_set_rsa; | |
327 | + } | |
328 | + | |
329 | + *pe = e; | |
330 | + | |
331 | + return 0; | |
332 | + | |
333 | +err_set_rsa: | |
334 | + ENGINE_finish(e); | |
335 | +err_engine_init: | |
336 | + ENGINE_free(e); | |
337 | +err_engine_by_id: | |
338 | + ENGINE_cleanup(); | |
339 | + return ret; | |
340 | +} | |
341 | + | |
151 | 342 | static void rsa_remove(void) |
152 | 343 | { |
153 | 344 | CRYPTO_cleanup_all_ex_data(); |
... | ... | @@ -160,6 +351,14 @@ |
160 | 351 | EVP_cleanup(); |
161 | 352 | } |
162 | 353 | |
354 | +static void rsa_engine_remove(ENGINE *e) | |
355 | +{ | |
356 | + if (e) { | |
357 | + ENGINE_finish(e); | |
358 | + ENGINE_free(e); | |
359 | + } | |
360 | +} | |
361 | + | |
163 | 362 | static int rsa_sign_with_key(RSA *rsa, struct checksum_algo *checksum_algo, |
164 | 363 | const struct image_region region[], int region_count, |
165 | 364 | uint8_t **sigp, uint *sig_size) |
166 | 365 | |
... | ... | @@ -235,13 +434,20 @@ |
235 | 434 | uint8_t **sigp, uint *sig_len) |
236 | 435 | { |
237 | 436 | RSA *rsa; |
437 | + ENGINE *e = NULL; | |
238 | 438 | int ret; |
239 | 439 | |
240 | 440 | ret = rsa_init(); |
241 | 441 | if (ret) |
242 | 442 | return ret; |
243 | 443 | |
244 | - ret = rsa_get_priv_key(info->keydir, info->keyname, &rsa); | |
444 | + if (info->engine_id) { | |
445 | + ret = rsa_engine_init(info->engine_id, &e); | |
446 | + if (ret) | |
447 | + goto err_engine; | |
448 | + } | |
449 | + | |
450 | + ret = rsa_get_priv_key(info->keydir, info->keyname, e, &rsa); | |
245 | 451 | if (ret) |
246 | 452 | goto err_priv; |
247 | 453 | ret = rsa_sign_with_key(rsa, info->checksum, region, |
... | ... | @@ -250,6 +456,8 @@ |
250 | 456 | goto err_sign; |
251 | 457 | |
252 | 458 | RSA_free(rsa); |
459 | + if (info->engine_id) | |
460 | + rsa_engine_remove(e); | |
253 | 461 | rsa_remove(); |
254 | 462 | |
255 | 463 | return ret; |
... | ... | @@ -257,6 +465,9 @@ |
257 | 465 | err_sign: |
258 | 466 | RSA_free(rsa); |
259 | 467 | err_priv: |
468 | + if (info->engine_id) | |
469 | + rsa_engine_remove(e); | |
470 | +err_engine: | |
260 | 471 | rsa_remove(); |
261 | 472 | return ret; |
262 | 473 | } |
263 | 474 | |
264 | 475 | |
265 | 476 | |
... | ... | @@ -446,14 +657,20 @@ |
446 | 657 | int ret; |
447 | 658 | int bits; |
448 | 659 | RSA *rsa; |
660 | + ENGINE *e = NULL; | |
449 | 661 | |
450 | 662 | debug("%s: Getting verification data\n", __func__); |
451 | - ret = rsa_get_pub_key(info->keydir, info->keyname, &rsa); | |
663 | + if (info->engine_id) { | |
664 | + ret = rsa_engine_init(info->engine_id, &e); | |
665 | + if (ret) | |
666 | + return ret; | |
667 | + } | |
668 | + ret = rsa_get_pub_key(info->keydir, info->keyname, e, &rsa); | |
452 | 669 | if (ret) |
453 | - return ret; | |
670 | + goto err_get_pub_key; | |
454 | 671 | ret = rsa_get_params(rsa, &exponent, &n0_inv, &modulus, &r_squared); |
455 | 672 | if (ret) |
456 | - return ret; | |
673 | + goto err_get_params; | |
457 | 674 | bits = BN_num_bits(modulus); |
458 | 675 | parent = fdt_subnode_offset(keydest, 0, FIT_SIG_NODENAME); |
459 | 676 | if (parent == -FDT_ERR_NOTFOUND) { |
460 | 677 | |
... | ... | @@ -518,8 +735,13 @@ |
518 | 735 | BN_free(modulus); |
519 | 736 | BN_free(r_squared); |
520 | 737 | if (ret) |
521 | - return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO; | |
738 | + ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO; | |
739 | +err_get_params: | |
740 | + RSA_free(rsa); | |
741 | +err_get_pub_key: | |
742 | + if (info->engine_id) | |
743 | + rsa_engine_remove(e); | |
522 | 744 | |
523 | - return 0; | |
745 | + return ret; | |
524 | 746 | } |
tools/fit_image.c
tools/image-host.c
... | ... | @@ -149,7 +149,7 @@ |
149 | 149 | |
150 | 150 | static int fit_image_setup_sig(struct image_sign_info *info, |
151 | 151 | const char *keydir, void *fit, const char *image_name, |
152 | - int noffset, const char *require_keys) | |
152 | + int noffset, const char *require_keys, const char *engine_id) | |
153 | 153 | { |
154 | 154 | const char *node_name; |
155 | 155 | char *algo_name; |
... | ... | @@ -170,6 +170,7 @@ |
170 | 170 | info->checksum = image_get_checksum_algo(algo_name); |
171 | 171 | info->crypto = image_get_crypto_algo(algo_name); |
172 | 172 | info->require_keys = require_keys; |
173 | + info->engine_id = engine_id; | |
173 | 174 | if (!info->checksum || !info->crypto) { |
174 | 175 | printf("Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n", |
175 | 176 | algo_name, node_name, image_name); |
176 | 177 | |
... | ... | @@ -194,12 +195,13 @@ |
194 | 195 | * @size: size of data in bytes |
195 | 196 | * @comment: Comment to add to signature nodes |
196 | 197 | * @require_keys: Mark all keys as 'required' |
198 | + * @engine_id: Engine to use for signing | |
197 | 199 | * @return 0 if ok, -1 on error |
198 | 200 | */ |
199 | 201 | static int fit_image_process_sig(const char *keydir, void *keydest, |
200 | 202 | void *fit, const char *image_name, |
201 | 203 | int noffset, const void *data, size_t size, |
202 | - const char *comment, int require_keys) | |
204 | + const char *comment, int require_keys, const char *engine_id) | |
203 | 205 | { |
204 | 206 | struct image_sign_info info; |
205 | 207 | struct image_region region; |
... | ... | @@ -209,7 +211,7 @@ |
209 | 211 | int ret; |
210 | 212 | |
211 | 213 | if (fit_image_setup_sig(&info, keydir, fit, image_name, noffset, |
212 | - require_keys ? "image" : NULL)) | |
214 | + require_keys ? "image" : NULL, engine_id)) | |
213 | 215 | return -1; |
214 | 216 | |
215 | 217 | node_name = fit_get_name(fit, noffset, NULL); |
216 | 218 | |
... | ... | @@ -288,11 +290,12 @@ |
288 | 290 | * @image_noffset: Requested component image node |
289 | 291 | * @comment: Comment to add to signature nodes |
290 | 292 | * @require_keys: Mark all keys as 'required' |
293 | + * @engine_id: Engine to use for signing | |
291 | 294 | * @return: 0 on success, <0 on failure |
292 | 295 | */ |
293 | 296 | int fit_image_add_verification_data(const char *keydir, void *keydest, |
294 | 297 | void *fit, int image_noffset, const char *comment, |
295 | - int require_keys) | |
298 | + int require_keys, const char *engine_id) | |
296 | 299 | { |
297 | 300 | const char *image_name; |
298 | 301 | const void *data; |
... | ... | @@ -329,7 +332,7 @@ |
329 | 332 | strlen(FIT_SIG_NODENAME))) { |
330 | 333 | ret = fit_image_process_sig(keydir, keydest, |
331 | 334 | fit, image_name, noffset, data, size, |
332 | - comment, require_keys); | |
335 | + comment, require_keys, engine_id); | |
333 | 336 | } |
334 | 337 | if (ret) |
335 | 338 | return ret; |
... | ... | @@ -569,7 +572,8 @@ |
569 | 572 | |
570 | 573 | static int fit_config_process_sig(const char *keydir, void *keydest, |
571 | 574 | void *fit, const char *conf_name, int conf_noffset, |
572 | - int noffset, const char *comment, int require_keys) | |
575 | + int noffset, const char *comment, int require_keys, | |
576 | + const char *engine_id) | |
573 | 577 | { |
574 | 578 | struct image_sign_info info; |
575 | 579 | const char *node_name; |
... | ... | @@ -587,7 +591,7 @@ |
587 | 591 | return -1; |
588 | 592 | |
589 | 593 | if (fit_image_setup_sig(&info, keydir, fit, conf_name, noffset, |
590 | - require_keys ? "conf" : NULL)) | |
594 | + require_keys ? "conf" : NULL, engine_id)) | |
591 | 595 | return -1; |
592 | 596 | |
593 | 597 | ret = info.crypto->sign(&info, region, region_count, &value, |
... | ... | @@ -635,7 +639,7 @@ |
635 | 639 | |
636 | 640 | static int fit_config_add_verification_data(const char *keydir, void *keydest, |
637 | 641 | void *fit, int conf_noffset, const char *comment, |
638 | - int require_keys) | |
642 | + int require_keys, const char *engine_id) | |
639 | 643 | { |
640 | 644 | const char *conf_name; |
641 | 645 | int noffset; |
... | ... | @@ -654,7 +658,7 @@ |
654 | 658 | strlen(FIT_SIG_NODENAME))) { |
655 | 659 | ret = fit_config_process_sig(keydir, keydest, |
656 | 660 | fit, conf_name, conf_noffset, noffset, comment, |
657 | - require_keys); | |
661 | + require_keys, engine_id); | |
658 | 662 | } |
659 | 663 | if (ret) |
660 | 664 | return ret; |
... | ... | @@ -664,7 +668,8 @@ |
664 | 668 | } |
665 | 669 | |
666 | 670 | int fit_add_verification_data(const char *keydir, void *keydest, void *fit, |
667 | - const char *comment, int require_keys) | |
671 | + const char *comment, int require_keys, | |
672 | + const char *engine_id) | |
668 | 673 | { |
669 | 674 | int images_noffset, confs_noffset; |
670 | 675 | int noffset; |
... | ... | @@ -687,7 +692,7 @@ |
687 | 692 | * i.e. component image node. |
688 | 693 | */ |
689 | 694 | ret = fit_image_add_verification_data(keydir, keydest, |
690 | - fit, noffset, comment, require_keys); | |
695 | + fit, noffset, comment, require_keys, engine_id); | |
691 | 696 | if (ret) |
692 | 697 | return ret; |
693 | 698 | } |
... | ... | @@ -710,7 +715,8 @@ |
710 | 715 | noffset = fdt_next_subnode(fit, noffset)) { |
711 | 716 | ret = fit_config_add_verification_data(keydir, keydest, |
712 | 717 | fit, noffset, comment, |
713 | - require_keys); | |
718 | + require_keys, | |
719 | + engine_id); | |
714 | 720 | if (ret) |
715 | 721 | return ret; |
716 | 722 | } |
tools/imagetool.h
... | ... | @@ -76,6 +76,7 @@ |
76 | 76 | bool external_data; /* Store data outside the FIT */ |
77 | 77 | bool quiet; /* Don't output text in normal operation */ |
78 | 78 | unsigned int external_offset; /* Add padding to external data */ |
79 | + const char *engine_id; /* Engine to use for signing */ | |
79 | 80 | }; |
80 | 81 | |
81 | 82 | /* |
tools/mkimage.c
... | ... | @@ -98,14 +98,15 @@ |
98 | 98 | " -i => input filename for ramdisk file\n"); |
99 | 99 | #ifdef CONFIG_FIT_SIGNATURE |
100 | 100 | fprintf(stderr, |
101 | - "Signing / verified boot options: [-E] [-k keydir] [-K dtb] [ -c <comment>] [-p addr] [-r]\n" | |
101 | + "Signing / verified boot options: [-E] [-k keydir] [-K dtb] [ -c <comment>] [-p addr] [-r] [-N engine]\n" | |
102 | 102 | " -E => place data outside of the FIT structure\n" |
103 | 103 | " -k => set directory containing private keys\n" |
104 | 104 | " -K => write public keys to this .dtb file\n" |
105 | 105 | " -c => add comment in signature node\n" |
106 | 106 | " -F => re-sign existing FIT image\n" |
107 | 107 | " -p => place external data at a static position\n" |
108 | - " -r => mark keys used as 'required' in dtb\n"); | |
108 | + " -r => mark keys used as 'required' in dtb\n" | |
109 | + " -N => engine to use for signing (pkcs11)\n"); | |
109 | 110 | #else |
110 | 111 | fprintf(stderr, |
111 | 112 | "Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n"); |
... | ... | @@ -143,7 +144,7 @@ |
143 | 144 | int opt; |
144 | 145 | |
145 | 146 | while ((opt = getopt(argc, argv, |
146 | - "a:A:b:c:C:d:D:e:Ef:Fk:i:K:ln:p:O:rR:qsT:vVx")) != -1) { | |
147 | + "a:A:b:c:C:d:D:e:Ef:Fk:i:K:ln:N:p:O:rR:qsT:vVx")) != -1) { | |
147 | 148 | switch (opt) { |
148 | 149 | case 'a': |
149 | 150 | params.addr = strtoull(optarg, &ptr, 16); |
... | ... | @@ -223,6 +224,9 @@ |
223 | 224 | break; |
224 | 225 | case 'n': |
225 | 226 | params.imagename = optarg; |
227 | + break; | |
228 | + case 'N': | |
229 | + params.engine_id = optarg; | |
226 | 230 | break; |
227 | 231 | case 'O': |
228 | 232 | params.os = genimg_get_os_id(optarg); |