|
@@ -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;
|
|
|
}
|