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>
This commit is contained in:
parent
b1c6a54a53
commit
f1ca1fdebf
@ -385,6 +385,149 @@ Test Verified Boot Run: signed config with bad hash: OK
|
||||
Test passed
|
||||
|
||||
|
||||
Hardware Signing with PKCS#11
|
||||
-----------------------------
|
||||
|
||||
Securely managing private signing keys can challenging, especially when the
|
||||
keys are stored on the file system of a computer that is connected to the
|
||||
Internet. If an attacker is able to steal the key, they can sign malicious FIT
|
||||
images which will appear genuine to your devices.
|
||||
|
||||
An alternative solution is to keep your signing key securely stored on hardware
|
||||
device like a smartcard, USB token or Hardware Security Module (HSM) and have
|
||||
them perform the signing. PKCS#11 is standard for interfacing with these crypto
|
||||
device.
|
||||
|
||||
Requirements:
|
||||
Smartcard/USB token/HSM which can work with the pkcs11 engine
|
||||
openssl
|
||||
libp11 (provides pkcs11 engine)
|
||||
p11-kit (recommended to simplify setup)
|
||||
opensc (for smartcards and smartcard like USB devices)
|
||||
gnutls (recommended for key generation, p11tool)
|
||||
|
||||
The following examples use the Nitrokey Pro. Instructions for other devices may vary.
|
||||
|
||||
Notes on pkcs11 engine setup:
|
||||
|
||||
Make sure p11-kit, opensc are installed and that p11-kit is setup to use opensc.
|
||||
/usr/share/p11-kit/modules/opensc.module should be present on your system.
|
||||
|
||||
|
||||
Generating Keys On the Nitrokey:
|
||||
|
||||
$ gpg --card-edit
|
||||
|
||||
Reader ...........: Nitrokey Nitrokey Pro (xxxxxxxx0000000000000000) 00 00
|
||||
Application ID ...: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
Version ..........: 2.1
|
||||
Manufacturer .....: ZeitControl
|
||||
Serial number ....: xxxxxxxx
|
||||
Name of cardholder: [not set]
|
||||
Language prefs ...: de
|
||||
Sex ..............: unspecified
|
||||
URL of public key : [not set]
|
||||
Login data .......: [not set]
|
||||
Signature PIN ....: forced
|
||||
Key attributes ...: rsa2048 rsa2048 rsa2048
|
||||
Max. PIN lengths .: 32 32 32
|
||||
PIN retry counter : 3 0 3
|
||||
Signature counter : 0
|
||||
Signature key ....: [none]
|
||||
Encryption key....: [none]
|
||||
Authentication key: [none]
|
||||
General key info..: [none]
|
||||
|
||||
gpg/card> generate
|
||||
Make off-card backup of encryption key? (Y/n) n
|
||||
|
||||
Please note that the factory settings of the PINs are
|
||||
PIN = '123456' Admin PIN = '12345678'
|
||||
You should change them using the command --change-pin
|
||||
|
||||
What keysize do you want for the Signature key? (2048) 4096
|
||||
The card will now be re-configured to generate a key of 4096 bits
|
||||
Note: There is no guarantee that the card supports the requested size.
|
||||
If the key generation does not succeed, please check the
|
||||
documentation of your card to see what sizes are allowed.
|
||||
What keysize do you want for the Encryption key? (2048) 4096
|
||||
The card will now be re-configured to generate a key of 4096 bits
|
||||
What keysize do you want for the Authentication key? (2048) 4096
|
||||
The card will now be re-configured to generate a key of 4096 bits
|
||||
Please specify how long the key should be valid.
|
||||
0 = key does not expire
|
||||
<n> = key expires in n days
|
||||
<n>w = key expires in n weeks
|
||||
<n>m = key expires in n months
|
||||
<n>y = key expires in n years
|
||||
Key is valid for? (0)
|
||||
Key does not expire at all
|
||||
Is this correct? (y/N) y
|
||||
|
||||
GnuPG needs to construct a user ID to identify your key.
|
||||
|
||||
Real name: John Doe
|
||||
Email address: john.doe@email.com
|
||||
Comment:
|
||||
You selected this USER-ID:
|
||||
"John Doe <john.doe@email.com>"
|
||||
|
||||
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
|
||||
|
||||
|
||||
Using p11tool to get the token URL:
|
||||
|
||||
Depending on system configuration, gpg-agent may need to be killed first.
|
||||
|
||||
$ p11tool --provider /usr/lib/opensc-pkcs11.so --list-tokens
|
||||
Token 0:
|
||||
URL: pkcs11:model=PKCS%2315%20emulated;manufacturer=ZeitControl;serial=000xxxxxxxxx;token=OpenPGP%20card%20%28User%20PIN%20%28sig%29%29
|
||||
Label: OpenPGP card (User PIN (sig))
|
||||
Type: Hardware token
|
||||
Manufacturer: ZeitControl
|
||||
Model: PKCS#15 emulated
|
||||
Serial: 000xxxxxxxxx
|
||||
Module: (null)
|
||||
|
||||
|
||||
Token 1:
|
||||
URL: pkcs11:model=PKCS%2315%20emulated;manufacturer=ZeitControl;serial=000xxxxxxxxx;token=OpenPGP%20card%20%28User%20PIN%29
|
||||
Label: OpenPGP card (User PIN)
|
||||
Type: Hardware token
|
||||
Manufacturer: ZeitControl
|
||||
Model: PKCS#15 emulated
|
||||
Serial: 000xxxxxxxxx
|
||||
Module: (null)
|
||||
|
||||
Use the portion of the signature token URL after "pkcs11:" as the keydir argument (-k) to mkimage below.
|
||||
|
||||
|
||||
Use the URL of the token to list the private keys:
|
||||
|
||||
$ p11tool --login --provider /usr/lib/opensc-pkcs11.so --list-privkeys \
|
||||
"pkcs11:model=PKCS%2315%20emulated;manufacturer=ZeitControl;serial=000xxxxxxxxx;token=OpenPGP%20card%20%28User%20PIN%20%28sig%29%29"
|
||||
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
|
||||
Enter PIN:
|
||||
Object 0:
|
||||
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
|
||||
Type: Private key
|
||||
Label: Signature key
|
||||
Flags: CKA_PRIVATE; CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE;
|
||||
ID: 01
|
||||
|
||||
Use the label, in this case "Signature key" as the key-name-hint in your FIT.
|
||||
|
||||
Create the fitImage:
|
||||
$ ./tools/mkimage -f fit-image.its fitImage
|
||||
|
||||
|
||||
Sign the fitImage with the hardware key:
|
||||
|
||||
$ ./tools/mkimage -F -k \
|
||||
"model=PKCS%2315%20emulated;manufacturer=ZeitControl;serial=000xxxxxxxxx;token=OpenPGP%20card%20%28User%20PIN%20%28sig%29%29" \
|
||||
-K u-boot.dtb -N pkcs11 -r fitImage
|
||||
|
||||
|
||||
Future Work
|
||||
-----------
|
||||
- Roll-back protection using a TPM is done using the tpm command. This can
|
||||
|
@ -965,6 +965,7 @@ int fit_set_timestamp(void *fit, int noffset, time_t timestamp);
|
||||
* @fit: Pointer to the FIT format image header
|
||||
* @comment: Comment to add to signature nodes
|
||||
* @require_keys: Mark all keys as 'required'
|
||||
* @engine_id: Engine to use for signing
|
||||
*
|
||||
* Adds hash values for all component images in the FIT blob.
|
||||
* Hashes are calculated for all component images which have hash subnodes
|
||||
@ -977,7 +978,8 @@ int fit_set_timestamp(void *fit, int noffset, time_t timestamp);
|
||||
* libfdt error code, on failure
|
||||
*/
|
||||
int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
|
||||
const char *comment, int require_keys);
|
||||
const char *comment, int require_keys,
|
||||
const char *engine_id);
|
||||
|
||||
int fit_image_verify(const void *fit, int noffset);
|
||||
int fit_config_verify(const void *fit, int conf_noffset);
|
||||
@ -1057,6 +1059,7 @@ struct image_sign_info {
|
||||
const void *fdt_blob; /* FDT containing public keys */
|
||||
int required_keynode; /* Node offset of key to use: -1=any */
|
||||
const char *require_keys; /* Value for 'required' property */
|
||||
const char *engine_id; /* Engine to use for signing */
|
||||
};
|
||||
#endif /* Allow struct image_region to always be defined for rsa.h */
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/engine.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||
#define HAVE_ERR_REMOVE_THREAD_STATE
|
||||
@ -31,14 +32,14 @@ static int rsa_err(const char *msg)
|
||||
}
|
||||
|
||||
/**
|
||||
* rsa_get_pub_key() - read a public key from a .crt file
|
||||
* rsa_pem_get_pub_key() - read a public key from a .crt file
|
||||
*
|
||||
* @keydir: Directory containins the key
|
||||
* @name Name of key file (will have a .crt extension)
|
||||
* @rsap Returns RSA object, or NULL on failure
|
||||
* @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
|
||||
*/
|
||||
static int rsa_get_pub_key(const char *keydir, const char *name, RSA **rsap)
|
||||
static int rsa_pem_get_pub_key(const char *keydir, const char *name, RSA **rsap)
|
||||
{
|
||||
char path[1024];
|
||||
EVP_PKEY *key;
|
||||
@ -96,14 +97,90 @@ err_cert:
|
||||
}
|
||||
|
||||
/**
|
||||
* rsa_get_priv_key() - read a private key from a .key file
|
||||
* rsa_engine_get_pub_key() - read a public key from given engine
|
||||
*
|
||||
* @keydir: Directory containins the key
|
||||
* @keydir: Key prefix
|
||||
* @name Name of key
|
||||
* @engine Engine to use
|
||||
* @rsap Returns RSA object, or NULL on failure
|
||||
* @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
|
||||
*/
|
||||
static int rsa_engine_get_pub_key(const char *keydir, const char *name,
|
||||
ENGINE *engine, RSA **rsap)
|
||||
{
|
||||
const char *engine_id;
|
||||
char key_id[1024];
|
||||
EVP_PKEY *key;
|
||||
RSA *rsa;
|
||||
int ret;
|
||||
|
||||
*rsap = NULL;
|
||||
|
||||
engine_id = ENGINE_get_id(engine);
|
||||
|
||||
if (engine_id && !strcmp(engine_id, "pkcs11")) {
|
||||
if (keydir)
|
||||
snprintf(key_id, sizeof(key_id),
|
||||
"pkcs11:%s;object=%s;type=public",
|
||||
keydir, name);
|
||||
else
|
||||
snprintf(key_id, sizeof(key_id),
|
||||
"pkcs11:object=%s;type=public",
|
||||
name);
|
||||
} else {
|
||||
fprintf(stderr, "Engine not supported\n");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
key = ENGINE_load_public_key(engine, key_id, NULL, NULL);
|
||||
if (!key)
|
||||
return rsa_err("Failure loading public key from engine");
|
||||
|
||||
/* Convert to a RSA_style key. */
|
||||
rsa = EVP_PKEY_get1_RSA(key);
|
||||
if (!rsa) {
|
||||
rsa_err("Couldn't convert to a RSA style key");
|
||||
ret = -EINVAL;
|
||||
goto err_rsa;
|
||||
}
|
||||
|
||||
EVP_PKEY_free(key);
|
||||
*rsap = rsa;
|
||||
|
||||
return 0;
|
||||
|
||||
err_rsa:
|
||||
EVP_PKEY_free(key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* rsa_get_pub_key() - read a public key
|
||||
*
|
||||
* @keydir: Directory containing the key (PEM file) or key prefix (engine)
|
||||
* @name Name of key file (will have a .crt extension)
|
||||
* @engine Engine to use
|
||||
* @rsap Returns RSA object, or NULL on failure
|
||||
* @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
|
||||
*/
|
||||
static int rsa_get_pub_key(const char *keydir, const char *name,
|
||||
ENGINE *engine, RSA **rsap)
|
||||
{
|
||||
if (engine)
|
||||
return rsa_engine_get_pub_key(keydir, name, engine, rsap);
|
||||
return rsa_pem_get_pub_key(keydir, name, rsap);
|
||||
}
|
||||
|
||||
/**
|
||||
* rsa_pem_get_priv_key() - read a private key from a .key file
|
||||
*
|
||||
* @keydir: Directory containing the key
|
||||
* @name Name of key file (will have a .key extension)
|
||||
* @rsap Returns RSA object, or NULL on failure
|
||||
* @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
|
||||
*/
|
||||
static int rsa_get_priv_key(const char *keydir, const char *name, RSA **rsap)
|
||||
static int rsa_pem_get_priv_key(const char *keydir, const char *name,
|
||||
RSA **rsap)
|
||||
{
|
||||
char path[1024];
|
||||
RSA *rsa;
|
||||
@ -130,6 +207,81 @@ static int rsa_get_priv_key(const char *keydir, const char *name, RSA **rsap)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* rsa_engine_get_priv_key() - read a private key from given engine
|
||||
*
|
||||
* @keydir: Key prefix
|
||||
* @name Name of key
|
||||
* @engine Engine to use
|
||||
* @rsap Returns RSA object, or NULL on failure
|
||||
* @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
|
||||
*/
|
||||
static int rsa_engine_get_priv_key(const char *keydir, const char *name,
|
||||
ENGINE *engine, RSA **rsap)
|
||||
{
|
||||
const char *engine_id;
|
||||
char key_id[1024];
|
||||
EVP_PKEY *key;
|
||||
RSA *rsa;
|
||||
int ret;
|
||||
|
||||
*rsap = NULL;
|
||||
|
||||
engine_id = ENGINE_get_id(engine);
|
||||
|
||||
if (engine_id && !strcmp(engine_id, "pkcs11")) {
|
||||
if (keydir)
|
||||
snprintf(key_id, sizeof(key_id),
|
||||
"pkcs11:%s;object=%s;type=private",
|
||||
keydir, name);
|
||||
else
|
||||
snprintf(key_id, sizeof(key_id),
|
||||
"pkcs11:object=%s;type=private",
|
||||
name);
|
||||
} else {
|
||||
fprintf(stderr, "Engine not supported\n");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
key = ENGINE_load_private_key(engine, key_id, NULL, NULL);
|
||||
if (!key)
|
||||
return rsa_err("Failure loading private key from engine");
|
||||
|
||||
/* Convert to a RSA_style key. */
|
||||
rsa = EVP_PKEY_get1_RSA(key);
|
||||
if (!rsa) {
|
||||
rsa_err("Couldn't convert to a RSA style key");
|
||||
ret = -EINVAL;
|
||||
goto err_rsa;
|
||||
}
|
||||
|
||||
EVP_PKEY_free(key);
|
||||
*rsap = rsa;
|
||||
|
||||
return 0;
|
||||
|
||||
err_rsa:
|
||||
EVP_PKEY_free(key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* rsa_get_priv_key() - read a private key
|
||||
*
|
||||
* @keydir: Directory containing the key (PEM file) or key prefix (engine)
|
||||
* @name Name of key
|
||||
* @engine Engine to use for signing
|
||||
* @rsap Returns RSA object, or NULL on failure
|
||||
* @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
|
||||
*/
|
||||
static int rsa_get_priv_key(const char *keydir, const char *name,
|
||||
ENGINE *engine, RSA **rsap)
|
||||
{
|
||||
if (engine)
|
||||
return rsa_engine_get_priv_key(keydir, name, engine, rsap);
|
||||
return rsa_pem_get_priv_key(keydir, name, rsap);
|
||||
}
|
||||
|
||||
static int rsa_init(void)
|
||||
{
|
||||
int ret;
|
||||
@ -148,6 +300,45 @@ static int rsa_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsa_engine_init(const char *engine_id, ENGINE **pe)
|
||||
{
|
||||
ENGINE *e;
|
||||
int ret;
|
||||
|
||||
ENGINE_load_builtin_engines();
|
||||
|
||||
e = ENGINE_by_id(engine_id);
|
||||
if (!e) {
|
||||
fprintf(stderr, "Engine isn't available\n");
|
||||
ret = -1;
|
||||
goto err_engine_by_id;
|
||||
}
|
||||
|
||||
if (!ENGINE_init(e)) {
|
||||
fprintf(stderr, "Couldn't initialize engine\n");
|
||||
ret = -1;
|
||||
goto err_engine_init;
|
||||
}
|
||||
|
||||
if (!ENGINE_set_default_RSA(e)) {
|
||||
fprintf(stderr, "Couldn't set engine as default for RSA\n");
|
||||
ret = -1;
|
||||
goto err_set_rsa;
|
||||
}
|
||||
|
||||
*pe = e;
|
||||
|
||||
return 0;
|
||||
|
||||
err_set_rsa:
|
||||
ENGINE_finish(e);
|
||||
err_engine_init:
|
||||
ENGINE_free(e);
|
||||
err_engine_by_id:
|
||||
ENGINE_cleanup();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rsa_remove(void)
|
||||
{
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
@ -160,6 +351,14 @@ static void rsa_remove(void)
|
||||
EVP_cleanup();
|
||||
}
|
||||
|
||||
static void rsa_engine_remove(ENGINE *e)
|
||||
{
|
||||
if (e) {
|
||||
ENGINE_finish(e);
|
||||
ENGINE_free(e);
|
||||
}
|
||||
}
|
||||
|
||||
static int rsa_sign_with_key(RSA *rsa, struct checksum_algo *checksum_algo,
|
||||
const struct image_region region[], int region_count,
|
||||
uint8_t **sigp, uint *sig_size)
|
||||
@ -235,13 +434,20 @@ int rsa_sign(struct image_sign_info *info,
|
||||
uint8_t **sigp, uint *sig_len)
|
||||
{
|
||||
RSA *rsa;
|
||||
ENGINE *e = NULL;
|
||||
int ret;
|
||||
|
||||
ret = rsa_init();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = rsa_get_priv_key(info->keydir, info->keyname, &rsa);
|
||||
if (info->engine_id) {
|
||||
ret = rsa_engine_init(info->engine_id, &e);
|
||||
if (ret)
|
||||
goto err_engine;
|
||||
}
|
||||
|
||||
ret = rsa_get_priv_key(info->keydir, info->keyname, e, &rsa);
|
||||
if (ret)
|
||||
goto err_priv;
|
||||
ret = rsa_sign_with_key(rsa, info->checksum, region,
|
||||
@ -250,6 +456,8 @@ int rsa_sign(struct image_sign_info *info,
|
||||
goto err_sign;
|
||||
|
||||
RSA_free(rsa);
|
||||
if (info->engine_id)
|
||||
rsa_engine_remove(e);
|
||||
rsa_remove();
|
||||
|
||||
return ret;
|
||||
@ -257,6 +465,9 @@ int rsa_sign(struct image_sign_info *info,
|
||||
err_sign:
|
||||
RSA_free(rsa);
|
||||
err_priv:
|
||||
if (info->engine_id)
|
||||
rsa_engine_remove(e);
|
||||
err_engine:
|
||||
rsa_remove();
|
||||
return ret;
|
||||
}
|
||||
@ -446,14 +657,20 @@ int rsa_add_verify_data(struct image_sign_info *info, void *keydest)
|
||||
int ret;
|
||||
int bits;
|
||||
RSA *rsa;
|
||||
ENGINE *e = NULL;
|
||||
|
||||
debug("%s: Getting verification data\n", __func__);
|
||||
ret = rsa_get_pub_key(info->keydir, info->keyname, &rsa);
|
||||
if (info->engine_id) {
|
||||
ret = rsa_engine_init(info->engine_id, &e);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
ret = rsa_get_pub_key(info->keydir, info->keyname, e, &rsa);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_get_pub_key;
|
||||
ret = rsa_get_params(rsa, &exponent, &n0_inv, &modulus, &r_squared);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_get_params;
|
||||
bits = BN_num_bits(modulus);
|
||||
parent = fdt_subnode_offset(keydest, 0, FIT_SIG_NODENAME);
|
||||
if (parent == -FDT_ERR_NOTFOUND) {
|
||||
@ -518,7 +735,12 @@ done:
|
||||
BN_free(modulus);
|
||||
BN_free(r_squared);
|
||||
if (ret)
|
||||
return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
|
||||
ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
|
||||
err_get_params:
|
||||
RSA_free(rsa);
|
||||
err_get_pub_key:
|
||||
if (info->engine_id)
|
||||
rsa_engine_remove(e);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
@ -59,7 +59,8 @@ static int fit_add_file_data(struct image_tool_params *params, size_t size_inc,
|
||||
if (!ret) {
|
||||
ret = fit_add_verification_data(params->keydir, dest_blob, ptr,
|
||||
params->comment,
|
||||
params->require_keys);
|
||||
params->require_keys,
|
||||
params->engine_id);
|
||||
}
|
||||
|
||||
if (dest_blob) {
|
||||
|
@ -149,7 +149,7 @@ static int fit_image_write_sig(void *fit, int noffset, uint8_t *value,
|
||||
|
||||
static int fit_image_setup_sig(struct image_sign_info *info,
|
||||
const char *keydir, void *fit, const char *image_name,
|
||||
int noffset, const char *require_keys)
|
||||
int noffset, const char *require_keys, const char *engine_id)
|
||||
{
|
||||
const char *node_name;
|
||||
char *algo_name;
|
||||
@ -170,6 +170,7 @@ static int fit_image_setup_sig(struct image_sign_info *info,
|
||||
info->checksum = image_get_checksum_algo(algo_name);
|
||||
info->crypto = image_get_crypto_algo(algo_name);
|
||||
info->require_keys = require_keys;
|
||||
info->engine_id = engine_id;
|
||||
if (!info->checksum || !info->crypto) {
|
||||
printf("Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n",
|
||||
algo_name, node_name, image_name);
|
||||
@ -194,12 +195,13 @@ static int fit_image_setup_sig(struct image_sign_info *info,
|
||||
* @size: size of data in bytes
|
||||
* @comment: Comment to add to signature nodes
|
||||
* @require_keys: Mark all keys as 'required'
|
||||
* @engine_id: Engine to use for signing
|
||||
* @return 0 if ok, -1 on error
|
||||
*/
|
||||
static int fit_image_process_sig(const char *keydir, void *keydest,
|
||||
void *fit, const char *image_name,
|
||||
int noffset, const void *data, size_t size,
|
||||
const char *comment, int require_keys)
|
||||
const char *comment, int require_keys, const char *engine_id)
|
||||
{
|
||||
struct image_sign_info info;
|
||||
struct image_region region;
|
||||
@ -209,7 +211,7 @@ static int fit_image_process_sig(const char *keydir, void *keydest,
|
||||
int ret;
|
||||
|
||||
if (fit_image_setup_sig(&info, keydir, fit, image_name, noffset,
|
||||
require_keys ? "image" : NULL))
|
||||
require_keys ? "image" : NULL, engine_id))
|
||||
return -1;
|
||||
|
||||
node_name = fit_get_name(fit, noffset, NULL);
|
||||
@ -288,11 +290,12 @@ static int fit_image_process_sig(const char *keydir, void *keydest,
|
||||
* @image_noffset: Requested component image node
|
||||
* @comment: Comment to add to signature nodes
|
||||
* @require_keys: Mark all keys as 'required'
|
||||
* @engine_id: Engine to use for signing
|
||||
* @return: 0 on success, <0 on failure
|
||||
*/
|
||||
int fit_image_add_verification_data(const char *keydir, void *keydest,
|
||||
void *fit, int image_noffset, const char *comment,
|
||||
int require_keys)
|
||||
int require_keys, const char *engine_id)
|
||||
{
|
||||
const char *image_name;
|
||||
const void *data;
|
||||
@ -329,7 +332,7 @@ int fit_image_add_verification_data(const char *keydir, void *keydest,
|
||||
strlen(FIT_SIG_NODENAME))) {
|
||||
ret = fit_image_process_sig(keydir, keydest,
|
||||
fit, image_name, noffset, data, size,
|
||||
comment, require_keys);
|
||||
comment, require_keys, engine_id);
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -569,7 +572,8 @@ static int fit_config_get_data(void *fit, int conf_noffset, int noffset,
|
||||
|
||||
static int fit_config_process_sig(const char *keydir, void *keydest,
|
||||
void *fit, const char *conf_name, int conf_noffset,
|
||||
int noffset, const char *comment, int require_keys)
|
||||
int noffset, const char *comment, int require_keys,
|
||||
const char *engine_id)
|
||||
{
|
||||
struct image_sign_info info;
|
||||
const char *node_name;
|
||||
@ -587,7 +591,7 @@ static int fit_config_process_sig(const char *keydir, void *keydest,
|
||||
return -1;
|
||||
|
||||
if (fit_image_setup_sig(&info, keydir, fit, conf_name, noffset,
|
||||
require_keys ? "conf" : NULL))
|
||||
require_keys ? "conf" : NULL, engine_id))
|
||||
return -1;
|
||||
|
||||
ret = info.crypto->sign(&info, region, region_count, &value,
|
||||
@ -635,7 +639,7 @@ static int fit_config_process_sig(const char *keydir, void *keydest,
|
||||
|
||||
static int fit_config_add_verification_data(const char *keydir, void *keydest,
|
||||
void *fit, int conf_noffset, const char *comment,
|
||||
int require_keys)
|
||||
int require_keys, const char *engine_id)
|
||||
{
|
||||
const char *conf_name;
|
||||
int noffset;
|
||||
@ -654,7 +658,7 @@ static int fit_config_add_verification_data(const char *keydir, void *keydest,
|
||||
strlen(FIT_SIG_NODENAME))) {
|
||||
ret = fit_config_process_sig(keydir, keydest,
|
||||
fit, conf_name, conf_noffset, noffset, comment,
|
||||
require_keys);
|
||||
require_keys, engine_id);
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -664,7 +668,8 @@ static int fit_config_add_verification_data(const char *keydir, void *keydest,
|
||||
}
|
||||
|
||||
int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
|
||||
const char *comment, int require_keys)
|
||||
const char *comment, int require_keys,
|
||||
const char *engine_id)
|
||||
{
|
||||
int images_noffset, confs_noffset;
|
||||
int noffset;
|
||||
@ -687,7 +692,7 @@ int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
|
||||
* i.e. component image node.
|
||||
*/
|
||||
ret = fit_image_add_verification_data(keydir, keydest,
|
||||
fit, noffset, comment, require_keys);
|
||||
fit, noffset, comment, require_keys, engine_id);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -710,7 +715,8 @@ int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
|
||||
noffset = fdt_next_subnode(fit, noffset)) {
|
||||
ret = fit_config_add_verification_data(keydir, keydest,
|
||||
fit, noffset, comment,
|
||||
require_keys);
|
||||
require_keys,
|
||||
engine_id);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -76,6 +76,7 @@ struct image_tool_params {
|
||||
bool external_data; /* Store data outside the FIT */
|
||||
bool quiet; /* Don't output text in normal operation */
|
||||
unsigned int external_offset; /* Add padding to external data */
|
||||
const char *engine_id; /* Engine to use for signing */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -98,14 +98,15 @@ static void usage(const char *msg)
|
||||
" -i => input filename for ramdisk file\n");
|
||||
#ifdef CONFIG_FIT_SIGNATURE
|
||||
fprintf(stderr,
|
||||
"Signing / verified boot options: [-E] [-k keydir] [-K dtb] [ -c <comment>] [-p addr] [-r]\n"
|
||||
"Signing / verified boot options: [-E] [-k keydir] [-K dtb] [ -c <comment>] [-p addr] [-r] [-N engine]\n"
|
||||
" -E => place data outside of the FIT structure\n"
|
||||
" -k => set directory containing private keys\n"
|
||||
" -K => write public keys to this .dtb file\n"
|
||||
" -c => add comment in signature node\n"
|
||||
" -F => re-sign existing FIT image\n"
|
||||
" -p => place external data at a static position\n"
|
||||
" -r => mark keys used as 'required' in dtb\n");
|
||||
" -r => mark keys used as 'required' in dtb\n"
|
||||
" -N => engine to use for signing (pkcs11)\n");
|
||||
#else
|
||||
fprintf(stderr,
|
||||
"Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n");
|
||||
@ -143,7 +144,7 @@ static void process_args(int argc, char **argv)
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc, argv,
|
||||
"a:A:b:c:C:d:D:e:Ef:Fk:i:K:ln:p:O:rR:qsT:vVx")) != -1) {
|
||||
"a:A:b:c:C:d:D:e:Ef:Fk:i:K:ln:N:p:O:rR:qsT:vVx")) != -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
params.addr = strtoull(optarg, &ptr, 16);
|
||||
@ -224,6 +225,9 @@ static void process_args(int argc, char **argv)
|
||||
case 'n':
|
||||
params.imagename = optarg;
|
||||
break;
|
||||
case 'N':
|
||||
params.engine_id = optarg;
|
||||
break;
|
||||
case 'O':
|
||||
params.os = genimg_get_os_id(optarg);
|
||||
if (params.os < 0) {
|
||||
|
Loading…
Reference in New Issue
Block a user