X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=lib%2Frsa%2Frsa-sign.c;h=d2788bf79a4ef81ec5b78d097ae53ca3d08d99e4;hb=817669231c89a97e3934baf07d457ca9671947ea;hp=5d9716f01349f4074653f2735fa3e6204ddba8e7;hpb=5b7d0027c2463101dabf337a7cccd768fc20b85e;p=oweals%2Fu-boot.git diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c index 5d9716f013..d2788bf79a 100644 --- a/lib/rsa/rsa-sign.c +++ b/lib/rsa/rsa-sign.c @@ -1,7 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2013, Google Inc. - * - * SPDX-License-Identifier: GPL-2.0+ */ #include "mkimage.h" @@ -9,16 +8,31 @@ #include #include #include +#include #include #include #include #include #include +#include #if OPENSSL_VERSION_NUMBER >= 0x10000000L #define HAVE_ERR_REMOVE_THREAD_STATE #endif +#if OPENSSL_VERSION_NUMBER < 0x10100000L +static void RSA_get0_key(const RSA *r, + const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) +{ + if (n != NULL) + *n = r->n; + if (e != NULL) + *e = r->e; + if (d != NULL) + *d = r->d; +} +#endif + static int rsa_err(const char *msg) { unsigned long sslErr = ERR_get_error(); @@ -31,14 +45,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 +110,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,26 +220,149 @@ 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; +#if OPENSSL_VERSION_NUMBER < 0x10100000L ret = SSL_library_init(); +#else + ret = OPENSSL_init_ssl(0, NULL); +#endif if (!ret) { fprintf(stderr, "Failure to init SSL library\n"); return -1; } +#if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_load_error_strings(); OpenSSL_add_all_algorithms(); OpenSSL_add_all_digests(); OpenSSL_add_all_ciphers(); +#endif 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: +#if OPENSSL_VERSION_NUMBER < 0x10100000L + ENGINE_cleanup(); +#endif + return ret; +} + static void rsa_remove(void) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L CRYPTO_cleanup_all_ex_data(); ERR_free_strings(); #ifdef HAVE_ERR_REMOVE_THREAD_STATE @@ -158,6 +371,15 @@ static void rsa_remove(void) ERR_remove_state(0); #endif EVP_cleanup(); +#endif +} + +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, @@ -210,7 +432,11 @@ static int rsa_sign_with_key(RSA *rsa, struct checksum_algo *checksum_algo, ret = rsa_err("Could not obtain signature"); goto err_sign; } - EVP_MD_CTX_cleanup(context); + #if OPENSSL_VERSION_NUMBER < 0x10100000L + EVP_MD_CTX_cleanup(context); + #else + EVP_MD_CTX_reset(context); + #endif EVP_MD_CTX_destroy(context); EVP_PKEY_free(key); @@ -235,21 +461,30 @@ 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->algo->checksum, region, + ret = rsa_sign_with_key(rsa, info->checksum, region, region_count, sigp, sig_len); if (ret) goto err_sign; RSA_free(rsa); + if (info->engine_id) + rsa_engine_remove(e); rsa_remove(); return ret; @@ -257,6 +492,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; } @@ -268,6 +506,7 @@ static int rsa_get_exponent(RSA *key, uint64_t *e) { int ret; BIGNUM *bn_te; + const BIGNUM *key_e; uint64_t te; ret = -EINVAL; @@ -276,17 +515,18 @@ static int rsa_get_exponent(RSA *key, uint64_t *e) if (!e) goto cleanup; - if (BN_num_bits(key->e) > 64) + RSA_get0_key(key, NULL, &key_e, NULL); + if (BN_num_bits(key_e) > 64) goto cleanup; - *e = BN_get_word(key->e); + *e = BN_get_word(key_e); - if (BN_num_bits(key->e) < 33) { + if (BN_num_bits(key_e) < 33) { ret = 0; goto cleanup; } - bn_te = BN_dup(key->e); + bn_te = BN_dup(key_e); if (!bn_te) goto cleanup; @@ -316,6 +556,7 @@ int rsa_get_params(RSA *key, uint64_t *exponent, uint32_t *n0_invp, { BIGNUM *big1, *big2, *big32, *big2_32; BIGNUM *n, *r, *r_squared, *tmp; + const BIGNUM *key_n; BN_CTX *bn_ctx = BN_CTX_new(); int ret = 0; @@ -337,7 +578,8 @@ int rsa_get_params(RSA *key, uint64_t *exponent, uint32_t *n0_invp, if (0 != rsa_get_exponent(key, exponent)) ret = -1; - if (!BN_copy(n, key->n) || !BN_set_word(big1, 1L) || + RSA_get0_key(key, &key_n, NULL, NULL); + if (!BN_copy(n, key_n) || !BN_set_word(big1, 1L) || !BN_set_word(big2, 2L) || !BN_set_word(big32, 32L)) ret = -1; @@ -420,11 +662,13 @@ static int fdt_add_bignum(void *blob, int noffset, const char *prop_name, BN_rshift(num, num, 32); /* N = N/B */ } + /* + * We try signing with successively increasing size values, so this + * might fail several times + */ ret = fdt_setprop(blob, noffset, prop_name, buf, size); - if (ret) { - fprintf(stderr, "Failed to write public key to FIT\n"); - return -ENOSPC; - } + if (ret) + return -FDT_ERR_NOSPACE; free(buf); BN_free(tmp); BN_free(big2); @@ -444,14 +688,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) { @@ -506,9 +756,9 @@ int rsa_add_verify_data(struct image_sign_info *info, void *keydest) } if (!ret) { ret = fdt_setprop_string(keydest, node, FIT_ALGO_PROP, - info->algo->name); + info->name); } - if (info->require_keys) { + if (!ret && info->require_keys) { ret = fdt_setprop_string(keydest, node, "required", info->require_keys); } @@ -516,7 +766,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; }