mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/5] Allow to compile in rsa public keys directly
@ 2019-10-15  7:55 Sascha Hauer
  2019-10-15  7:55 ` [PATCH 1/5] Kbuild: Add config_filename macro from kernel Sascha Hauer
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Sascha Hauer @ 2019-10-15  7:55 UTC (permalink / raw)
  To: Barebox List

So far we relied on U-Boots mkimage tool to generate dts snippets from
RSA public keys which are then compiled into barebox. This series
simplifies this by allowing to compile in RSA public keys directly into
barebox. Keys are retrieved from certificate files in PEM format or from
PKCS#11 URIs.

Sascha Hauer (5):
  Kbuild: Add config_filename macro from kernel
  scripts: Add rsatoc tool
  rsa: let rsa_of_read_key() return a fully allocated key
  rsa: Allow to directly compile in rsa public keys
  fit-image: Use compiled-in keys

 common/image-fit.c                |  27 +-
 crypto/.gitignore                 |   2 +
 crypto/Kconfig                    |  19 ++
 crypto/Makefile                   |  10 +
 crypto/rsa.c                      |  59 +++-
 include/asm-generic/barebox.lds.h |   6 +
 include/rsa.h                     |   5 +-
 scripts/.gitignore                |   1 +
 scripts/Kbuild.include            |  49 ++++
 scripts/Makefile                  |   3 +
 scripts/Makefile.lib              |  18 ++
 scripts/rsatoc.c                  | 445 ++++++++++++++++++++++++++++++
 12 files changed, 629 insertions(+), 15 deletions(-)
 create mode 100644 crypto/.gitignore
 create mode 100644 scripts/rsatoc.c

-- 
2.23.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/5] Kbuild: Add config_filename macro from kernel
  2019-10-15  7:55 [PATCH 0/5] Allow to compile in rsa public keys directly Sascha Hauer
@ 2019-10-15  7:55 ` Sascha Hauer
  2019-10-15  7:55 ` [PATCH 2/5] scripts: Add rsatoc tool Sascha Hauer
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Sascha Hauer @ 2019-10-15  7:55 UTC (permalink / raw)
  To: Barebox List

The config_filename allows to extract a filename from a Kconfig string
option.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 scripts/Kbuild.include | 49 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index a2dbbd8a00..c08b9a824d 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -268,6 +268,55 @@ why =                                                                        \
 echo-why = $(call escsq, $(strip $(why)))
 endif
 
+###############################################################################
+#
+# When a Kconfig string contains a filename, it is suitable for
+# passing to shell commands. It is surrounded by double-quotes, and
+# any double-quotes or backslashes within it are escaped by
+# backslashes.
+#
+# This is no use for dependencies or $(wildcard). We need to strip the
+# surrounding quotes and the escaping from quotes and backslashes, and
+# we *do* need to escape any spaces in the string. So, for example:
+#
+# Usage: $(eval $(call config_filename,FOO))
+#
+# Defines FOO_FILENAME based on the contents of the CONFIG_FOO option,
+# transformed as described above to be suitable for use within the
+# makefile.
+#
+# Also, if the filename is a relative filename and exists in the source
+# tree but not the build tree, define FOO_SRCPREFIX as $(srctree)/ to
+# be prefixed to *both* command invocation and dependencies.
+#
+# Note: We also print the filenames in the quiet_cmd_foo text, and
+# perhaps ought to have a version specially escaped for that purpose.
+# But it's only cosmetic, and $(patsubst "%",%,$(CONFIG_FOO)) is good
+# enough.  It'll strip the quotes in the common case where there's no
+# space and it's a simple filename, and it'll retain the quotes when
+# there's a space. There are some esoteric cases in which it'll print
+# the wrong thing, but we don't really care. The actual dependencies
+# and commands *do* get it right, with various combinations of single
+# and double quotes, backslashes and spaces in the filenames.
+#
+###############################################################################
+#
+define config_filename
+ifneq ($$(CONFIG_$(1)),"")
+$(1)_FILENAME := $$(subst \\,\,$$(subst \$$(quote),$$(quote),$$(subst $$(space_escape),\$$(space),$$(patsubst "%",%,$$(subst $$(space),$$(space_escape),$$(CONFIG_$(1)))))))
+ifneq ($$(patsubst /%,%,$$(firstword $$($(1)_FILENAME))),$$(firstword $$($(1)_FILENAME)))
+else
+ifeq ($$(wildcard $$($(1)_FILENAME)),)
+ifneq ($$(wildcard $$(srctree)/$$($(1)_FILENAME)),)
+$(1)_SRCPREFIX := $(srctree)/
+endif
+endif
+endif
+endif
+endef
+#
+###############################################################################
+
 # delete partially updated (i.e. corrupted) files on error
 .DELETE_ON_ERROR:
 
-- 
2.23.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 2/5] scripts: Add rsatoc tool
  2019-10-15  7:55 [PATCH 0/5] Allow to compile in rsa public keys directly Sascha Hauer
  2019-10-15  7:55 ` [PATCH 1/5] Kbuild: Add config_filename macro from kernel Sascha Hauer
@ 2019-10-15  7:55 ` Sascha Hauer
  2019-10-15 10:21   ` Ahmad Fatoum
  2019-10-15  7:55 ` [PATCH 3/5] rsa: let rsa_of_read_key() return a fully allocated key Sascha Hauer
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Sascha Hauer @ 2019-10-15  7:55 UTC (permalink / raw)
  To: Barebox List

The rsatoc tool converts rsa public keys into C structs suitable to
compile with barebox. Most of the openssl rsa related stuff has been
taken from the U-Boot mkimage tool.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 scripts/.gitignore |   1 +
 scripts/Makefile   |   3 +
 scripts/rsatoc.c   | 445 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 449 insertions(+)
 create mode 100644 scripts/rsatoc.c

diff --git a/scripts/.gitignore b/scripts/.gitignore
index 45c81bf8f4..76ea271abb 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -29,3 +29,4 @@ mxs-usb-loader
 omap4_usbboot
 omap3-usb-loader
 mips-relocs
+rsatoc
diff --git a/scripts/Makefile b/scripts/Makefile
index dffab53c73..81d1a501b0 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -10,6 +10,9 @@ hostprogs-y                      += fix_size
 hostprogs-y                      += bareboxenv
 hostprogs-y                      += bareboxcrc32
 hostprogs-y                      += kernel-install
+hostprogs-$(CONFIG_CRYPTO_RSA_BUILTIN_KEYS) += rsatoc
+HOSTCFLAGS_rsatoc = `pkg-config --cflags openssl`
+HOSTLDLIBS_rsatoc = `pkg-config --libs openssl`
 hostprogs-$(CONFIG_IMD)          += bareboximd
 hostprogs-$(CONFIG_KALLSYMS)     += kallsyms
 hostprogs-$(CONFIG_MIPS)         += mips-relocs
diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c
new file mode 100644
index 0000000000..f853691908
--- /dev/null
+++ b/scripts/rsatoc.c
@@ -0,0 +1,445 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * rsatoc - utility to convert an RSA key to a C struct
+ *
+ * This tool converts an RSA key given as file or PKCS#11
+ * URI to a C struct suitable to compile with barebox.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+#include <openssl/evp.h>
+#include <openssl/engine.h>
+
+static int rsa_err(const char *msg)
+{
+	unsigned long sslErr = ERR_get_error();
+
+	fprintf(stderr, "%s", msg);
+	fprintf(stderr, ": %s\n",
+		ERR_error_string(sslErr, 0));
+
+	return -1;
+}
+
+/**
+ * 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_pem_get_pub_key(const char *path, RSA **rsap)
+{
+	EVP_PKEY *key;
+	X509 *cert;
+	RSA *rsa;
+	FILE *f;
+	int ret;
+
+	*rsap = NULL;
+	f = fopen(path, "r");
+	if (!f) {
+		fprintf(stderr, "Couldn't open RSA certificate: '%s': %s\n",
+			path, strerror(errno));
+		return -EACCES;
+	}
+
+	/* Read the certificate */
+	cert = NULL;
+	if (!PEM_read_X509(f, &cert, NULL, NULL)) {
+		rsa_err("Couldn't read certificate");
+		ret = -EINVAL;
+		goto err_cert;
+	}
+
+	/* Get the public key from the certificate. */
+	key = X509_get_pubkey(cert);
+	if (!key) {
+		rsa_err("Couldn't read public key\n");
+		ret = -EINVAL;
+		goto err_pubkey;
+	}
+
+	/* 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;
+	}
+	fclose(f);
+	EVP_PKEY_free(key);
+	X509_free(cert);
+	*rsap = rsa;
+
+	return 0;
+
+err_rsa:
+	EVP_PKEY_free(key);
+err_pubkey:
+	X509_free(cert);
+err_cert:
+	fclose(f);
+	return ret;
+}
+
+/**
+ * rsa_engine_get_pub_key() - read a public 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_pub_key(const char *key_id,
+				  ENGINE *engine, RSA **rsap)
+{
+	EVP_PKEY *key;
+	RSA *rsa;
+	int ret;
+
+	*rsap = NULL;
+
+	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_exponent(): - Get the public exponent from an RSA key
+ */
+static int rsa_get_exponent(RSA *key, uint64_t *e)
+{
+	int ret;
+	BIGNUM *bn_te;
+	const BIGNUM *key_e;
+	uint64_t te;
+
+	ret = -EINVAL;
+	bn_te = NULL;
+
+	if (!e)
+		goto cleanup;
+
+	RSA_get0_key(key, NULL, &key_e, NULL);
+	if (BN_num_bits(key_e) > 64)
+		goto cleanup;
+
+	*e = BN_get_word(key_e);
+
+	if (BN_num_bits(key_e) < 33) {
+		ret = 0;
+		goto cleanup;
+	}
+
+	bn_te = BN_dup(key_e);
+	if (!bn_te)
+		goto cleanup;
+
+	if (!BN_rshift(bn_te, bn_te, 32))
+		goto cleanup;
+
+	if (!BN_mask_bits(bn_te, 32))
+		goto cleanup;
+
+	te = BN_get_word(bn_te);
+	te <<= 32;
+	*e |= te;
+	ret = 0;
+
+cleanup:
+	if (bn_te)
+		BN_free(bn_te);
+
+	return ret;
+}
+
+/*
+ * rsa_get_params(): - Get the important parameters of an RSA public key
+ */
+int rsa_get_params(RSA *key, uint64_t *exponent, uint32_t *n0_invp,
+		   BIGNUM **modulusp, BIGNUM **r_squaredp)
+{
+	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;
+
+	/* Initialize BIGNUMs */
+	big1 = BN_new();
+	big2 = BN_new();
+	big32 = BN_new();
+	r = BN_new();
+	r_squared = BN_new();
+	tmp = BN_new();
+	big2_32 = BN_new();
+	n = BN_new();
+	if (!big1 || !big2 || !big32 || !r || !r_squared || !tmp || !big2_32 ||
+	    !n) {
+		fprintf(stderr, "Out of memory (bignum)\n");
+		return -ENOMEM;
+	}
+
+	if (0 != rsa_get_exponent(key, exponent))
+		ret = -1;
+
+	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;
+
+	/* big2_32 = 2^32 */
+	if (!BN_exp(big2_32, big2, big32, bn_ctx))
+		ret = -1;
+
+	/* Calculate n0_inv = -1 / n[0] mod 2^32 */
+	if (!BN_mod_inverse(tmp, n, big2_32, bn_ctx) ||
+	    !BN_sub(tmp, big2_32, tmp))
+		ret = -1;
+	*n0_invp = BN_get_word(tmp);
+
+	/* Calculate R = 2^(# of key bits) */
+	if (!BN_set_word(tmp, BN_num_bits(n)) ||
+	    !BN_exp(r, big2, tmp, bn_ctx))
+		ret = -1;
+
+	/* Calculate r_squared = R^2 mod n */
+	if (!BN_copy(r_squared, r) ||
+	    !BN_mul(tmp, r_squared, r, bn_ctx) ||
+	    !BN_mod(r_squared, tmp, n, bn_ctx))
+		ret = -1;
+
+	*modulusp = n;
+	*r_squaredp = r_squared;
+
+	BN_free(big1);
+	BN_free(big2);
+	BN_free(big32);
+	BN_free(r);
+	BN_free(tmp);
+	BN_free(big2_32);
+	if (ret) {
+		fprintf(stderr, "Bignum operations failed\n");
+		return -ENOMEM;
+	}
+
+	return ret;
+}
+
+static int rsa_engine_init(ENGINE **pe)
+{
+	ENGINE *e;
+	int ret;
+
+	ENGINE_load_builtin_engines();
+
+	e = ENGINE_by_id("pkcs11");
+	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 || \
+	(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x02070000fL)
+	ENGINE_cleanup();
+#endif
+	return ret;
+}
+
+static int print_bignum(BIGNUM *num, int num_bits)
+{
+	BIGNUM *tmp, *big2, *big32, *big2_32;
+	BN_CTX *ctx;
+	int i;
+
+	tmp = BN_new();
+	big2 = BN_new();
+	big32 = BN_new();
+	big2_32 = BN_new();
+
+	/*
+	 * Note: This code assumes that all of the above succeed, or all fail.
+	 * In practice memory allocations generally do not fail (unless the
+	 * process is killed), so it does not seem worth handling each of these
+	 * as a separate case. Technicaly this could leak memory on failure,
+	 * but a) it won't happen in practice, and b) it doesn't matter as we
+	 * will immediately exit with a failure code.
+	 */
+	if (!tmp || !big2 || !big32 || !big2_32) {
+		fprintf(stderr, "Out of memory (bignum)\n");
+		return -ENOMEM;
+	}
+	ctx = BN_CTX_new();
+	if (!tmp) {
+		fprintf(stderr, "Out of memory (bignum context)\n");
+		return -ENOMEM;
+	}
+	BN_set_word(big2, 2L);
+	BN_set_word(big32, 32L);
+	BN_exp(big2_32, big2, big32, ctx); /* B = 2^32 */
+
+	for (i = 0; i < num_bits / 32; i++) {
+		BN_mod(tmp, num, big2_32, ctx); /* n = N mod B */
+		if (i % 4)
+			printf(" ");
+		else
+			printf("\n\t");
+		printf("0x%08lx,", BN_get_word(tmp));
+		BN_rshift(num, num, 32); /*  N = N/B */
+	}
+
+	BN_free(tmp);
+	BN_free(big2);
+	BN_free(big32);
+	BN_free(big2_32);
+
+	return 0;
+}
+
+static int gen_key(const char *keyname, const char *path)
+{
+	BIGNUM *modulus, *r_squared;
+	uint64_t exponent;
+	uint32_t n0_inv;
+	int ret;
+	int bits;
+	RSA *rsa;
+	ENGINE *e = NULL;
+	char *tmp, *key_name_c;
+
+	tmp = key_name_c = strdup(keyname);
+
+	while (*tmp) {
+		if (*tmp == '-')
+			*tmp = '_';
+		tmp++;
+	}
+
+	if (!strncmp(path, "__ENV__", 7)) {
+		const char *var = getenv(path + 7);
+		if (!var) {
+			fprintf(stderr,
+				"environment variable \"%s\" is empty\n", path + 7);
+			exit(1);
+		}
+		path = var;
+	}
+
+	if (!strncmp(path, "pkcs11:", 7)) {
+		ret = rsa_engine_init(&e);
+		if (ret)
+			exit(1);
+		ret = rsa_engine_get_pub_key(path, e, &rsa);
+		if (ret)
+			exit(1);
+	} else {
+		ret = rsa_pem_get_pub_key(path, &rsa);
+		if (ret)
+			exit(1);
+	}
+
+	ret = rsa_get_params(rsa, &exponent, &n0_inv, &modulus, &r_squared);
+	if (ret)
+		return ret;
+
+	bits = BN_num_bits(modulus);
+
+	printf("\nstatic uint32_t %s_modulus[] = {", key_name_c);
+	print_bignum(modulus, bits);
+	printf("\n};\n\n");
+
+	printf("static uint32_t %s_rr[] = {", key_name_c);
+	print_bignum(r_squared, bits);
+	printf("\n};\n\n");
+
+	printf("static struct rsa_public_key %s = {\n", key_name_c);
+	printf("\t.len = %d,\n", bits / 32);
+	printf("\t.n0inv = 0x%0x,\n", n0_inv);
+	printf("\t.modulus = %s_modulus,\n", key_name_c);
+	printf("\t.rr = %s_rr,\n", key_name_c);
+	printf("\t.exponent = 0x%0lx,\n", exponent);
+	printf("\t.key_name_hint = \"%s\",\n", keyname);
+	printf("};\n\n");
+
+	printf("struct rsa_public_key *%sp __attribute__((section(\".rsa_keys.rodata.%s\"))) = &%s;\n",
+	       key_name_c, key_name_c, key_name_c);
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	char *path, *keyname;
+	int i;
+
+	if (argc < 2) {
+		fprintf(stderr, "Usage: %s <key_name_hint>:<crt> ...\n", argv[0]);
+		exit(1);
+	}
+
+	for (i = 1; i < argc; i++) {
+		keyname = argv[i];
+
+		path = strchr(keyname, ':');
+		if (!path) {
+			fprintf(stderr,
+				"keys must be given as <key_name_hint>:<crt>\n");
+			exit(1);
+		}
+
+		*path = 0;
+		path++;
+
+		gen_key(keyname, path);
+	}
+
+	exit(0);
+}
-- 
2.23.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 3/5] rsa: let rsa_of_read_key() return a fully allocated key
  2019-10-15  7:55 [PATCH 0/5] Allow to compile in rsa public keys directly Sascha Hauer
  2019-10-15  7:55 ` [PATCH 1/5] Kbuild: Add config_filename macro from kernel Sascha Hauer
  2019-10-15  7:55 ` [PATCH 2/5] scripts: Add rsatoc tool Sascha Hauer
@ 2019-10-15  7:55 ` Sascha Hauer
  2019-10-15  7:55 ` [PATCH 4/5] rsa: Allow to directly compile in rsa public keys Sascha Hauer
  2019-10-15  7:55 ` [PATCH 5/5] fit-image: Use compiled-in keys Sascha Hauer
  4 siblings, 0 replies; 9+ messages in thread
From: Sascha Hauer @ 2019-10-15  7:55 UTC (permalink / raw)
  To: Barebox List

Until now rsa_of_read_key() took a pointer to a key and filled the
struct rsa_public_key members with allocated values. So far we have
never freed these values. Change rsa_of_read_key() to always return
a fully allocated key and provide rsa_key_free() to free it. Let the
FIT image code free the key after usage.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 common/image-fit.c | 10 ++++++----
 crypto/rsa.c       | 26 ++++++++++++++++++++++----
 include/rsa.h      |  3 ++-
 3 files changed, 30 insertions(+), 9 deletions(-)

diff --git a/common/image-fit.c b/common/image-fit.c
index 6ac4644686..71053fbef5 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -269,7 +269,7 @@ static struct digest *fit_alloc_digest(struct device_node *sig_node,
 static int fit_check_rsa_signature(struct device_node *sig_node,
 				   enum hash_algo algo, void *hash)
 {
-	struct rsa_public_key key = {};
+	struct rsa_public_key *key;
 	const char *key_name;
 	char *key_path;
 	struct device_node *key_node;
@@ -296,18 +296,20 @@ static int fit_check_rsa_signature(struct device_node *sig_node,
 	}
 	free(key_path);
 
-	ret = rsa_of_read_key(key_node, &key);
-	if (ret) {
+	key = rsa_of_read_key(key_node);
+	if (IS_ERR(key)) {
 		pr_info("failed to read key in %s\n", key_node->full_name);
 		return -ENOENT;
 	}
 
-	ret = rsa_verify(&key, sig_value, sig_len, hash, algo);
+	ret = rsa_verify(key, sig_value, sig_len, hash, algo);
 	if (ret)
 		pr_err("image signature BAD\n");
 	else
 		pr_info("image signature OK\n");
 
+	rsa_key_free(key);
+
 	return ret;
 }
 
diff --git a/crypto/rsa.c b/crypto/rsa.c
index 591d15c415..2e70c8127d 100644
--- a/crypto/rsa.c
+++ b/crypto/rsa.c
@@ -380,11 +380,15 @@ static void rsa_convert_big_endian(uint32_t *dst, const uint32_t *src, int len)
 		dst[i] = fdt32_to_cpu(src[len - 1 - i]);
 }
 
-int rsa_of_read_key(struct device_node *node, struct rsa_public_key *key)
+struct rsa_public_key *rsa_of_read_key(struct device_node *node)
 {
 	const void *modulus, *rr;
 	const uint64_t *public_exponent;
 	int length;
+	struct rsa_public_key *key;
+	int err;
+
+	key = xzalloc(sizeof(*key));
 
 	of_property_read_u32(node, "rsa,num-bits", &key->len);
 	of_property_read_u32(node, "rsa,n0-inverse", &key->n0inv);
@@ -400,14 +404,16 @@ int rsa_of_read_key(struct device_node *node, struct rsa_public_key *key)
 
 	if (!key->len || !modulus || !rr) {
 		debug("%s: Missing RSA key info", __func__);
-		return -EFAULT;
+		err = -EFAULT;
+		goto out;
 	}
 
 	/* Sanity check for stack size */
 	if (key->len > RSA_MAX_KEY_BITS || key->len < RSA_MIN_KEY_BITS) {
 		debug("RSA key bits %u outside allowed range %d..%d\n",
 		      key->len, RSA_MIN_KEY_BITS, RSA_MAX_KEY_BITS);
-		return -EFAULT;
+		err = -EFAULT;
+		goto out;
 	}
 
 	key->len /= sizeof(uint32_t) * 8;
@@ -418,5 +424,17 @@ int rsa_of_read_key(struct device_node *node, struct rsa_public_key *key)
 	rsa_convert_big_endian(key->modulus, modulus, key->len);
 	rsa_convert_big_endian(key->rr, rr, key->len);
 
-	return 0;
+	err = 0;
+out:
+	if (err)
+		free(key);
+
+	return err ? ERR_PTR(err) : key;
+}
+
+void rsa_key_free(struct rsa_public_key *key)
+{
+	free(key->modulus);
+	free(key->rr);
+	free(key);
 }
diff --git a/include/rsa.h b/include/rsa.h
index feb8c31200..cf2e6c7e08 100644
--- a/include/rsa.h
+++ b/include/rsa.h
@@ -49,6 +49,7 @@ int rsa_verify(const struct rsa_public_key *key, const uint8_t *sig,
 /* This is the maximum signature length that we support, in bits */
 #define RSA_MAX_SIG_BITS	4096
 
-int rsa_of_read_key(struct device_node *node, struct rsa_public_key *key);
+struct rsa_public_key *rsa_of_read_key(struct device_node *node);
+void rsa_key_free(struct rsa_public_key *key);
 
 #endif
-- 
2.23.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 4/5] rsa: Allow to directly compile in rsa public keys
  2019-10-15  7:55 [PATCH 0/5] Allow to compile in rsa public keys directly Sascha Hauer
                   ` (2 preceding siblings ...)
  2019-10-15  7:55 ` [PATCH 3/5] rsa: let rsa_of_read_key() return a fully allocated key Sascha Hauer
@ 2019-10-15  7:55 ` Sascha Hauer
  2019-10-15  7:55 ` [PATCH 5/5] fit-image: Use compiled-in keys Sascha Hauer
  4 siblings, 0 replies; 9+ messages in thread
From: Sascha Hauer @ 2019-10-15  7:55 UTC (permalink / raw)
  To: Barebox List

So far we relied on the U-Boot mkimage tool to generate us device tree
snippets containing rsa public keys which we then compiled into barebox.
Make this easier and allow to directly specify a filename or PKCS#11 URI
in Kconfig. With this we no longer need the U-Boot mkimage tool here and
no more external steps to prepare device tree snippets.

With this rsa public keys can be directly compiled as C structs into
barebox which is much more direct than putting it into the device tree.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 crypto/.gitignore                 |  2 ++
 crypto/Kconfig                    | 19 ++++++++++++++++++
 crypto/Makefile                   | 10 ++++++++++
 crypto/rsa.c                      | 33 +++++++++++++++++++++++++++++++
 include/asm-generic/barebox.lds.h |  6 ++++++
 include/rsa.h                     |  2 ++
 scripts/Makefile.lib              | 18 +++++++++++++++++
 7 files changed, 90 insertions(+)
 create mode 100644 crypto/.gitignore

diff --git a/crypto/.gitignore b/crypto/.gitignore
new file mode 100644
index 0000000000..92d8af3cf4
--- /dev/null
+++ b/crypto/.gitignore
@@ -0,0 +1,2 @@
+rsa-keys.h
+rsa-keys.h.tmp
diff --git a/crypto/Kconfig b/crypto/Kconfig
index c06d3c054e..42b018b296 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -94,6 +94,25 @@ config CRYPTO_PBKDF2
 config CRYPTO_RSA
 	bool
 
+config CRYPTO_RSA_BUILTIN_KEYS
+	bool
+	default y if CRYPTO_RSA_KEYS != ""
+
+config CRYPTO_RSA_KEY
+	depends on CRYPTO_RSA
+	string "RSA key to compile in"
+	help
+	  This option should be a filename of a PEM-formatted file containing
+	  X.509 certificates to be included into barebox. If the string starts
+	  with "pkcs11:" it is interpreted as a PKCS#11 URI rather than a file.
+
+config CRYPTO_RSA_KEY_NAME_HINT
+	depends on CRYPTO_RSA
+	string "FIT image key name hint"
+	help
+	  In FIT images keys are identified by a key name hint string. Provide
+	  the key name hint here.
+
 config CRYPTO_KEYSTORE
 	bool "Keystore"
 	help
diff --git a/crypto/Makefile b/crypto/Makefile
index d6fb74aad9..018f85e253 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -16,3 +16,13 @@ obj-$(CONFIG_DIGEST_SHA512_GENERIC)	+= sha4.o
 obj-$(CONFIG_CRYPTO_PBKDF2)	+= pbkdf2.o
 obj-$(CONFIG_CRYPTO_RSA)	+= rsa.o
 obj-$(CONFIG_CRYPTO_KEYSTORE)	+= keystore.o
+
+extra-y += rsa-keys.h
+
+ifdef CONFIG_CRYPTO_RSA_BUILTIN_KEYS
+
+$(obj)/rsa.o: $(obj)/rsa-keys.h
+$(eval $(call config_filename,CRYPTO_RSA_KEY))
+$(obj)/rsa-keys.h: FORCE
+	$(call cmd,rsa_keys,$(CONFIG_CRYPTO_RSA_KEY_NAME_HINT):$(CRYPTO_RSA_KEY_SRCPREFIX)$(CRYPTO_RSA_KEY_FILENAME))
+endif
diff --git a/crypto/rsa.c b/crypto/rsa.c
index 2e70c8127d..64241854c8 100644
--- a/crypto/rsa.c
+++ b/crypto/rsa.c
@@ -438,3 +438,36 @@ void rsa_key_free(struct rsa_public_key *key)
 	free(key->rr);
 	free(key);
 }
+
+#ifdef CONFIG_CRYPTO_RSA_BUILTIN_KEYS
+#include "rsa-keys.h"
+
+extern const struct rsa_public_key * const __rsa_keys_start;
+extern const struct rsa_public_key * const __rsa_keys_end;
+
+struct rsa_public_key *rsa_get_key(const char *name)
+{
+	const struct rsa_public_key *key;
+	struct rsa_public_key *new;
+	const struct rsa_public_key * const *iter;
+
+	for (iter = &__rsa_keys_start; iter != &__rsa_keys_end; iter++) {
+		key = *iter;
+		if (!strcmp(name, key->key_name_hint))
+			goto found;
+	}
+
+	return ERR_PTR(-ENOENT);
+found:
+	new = xmemdup(key, sizeof(*key));
+	new->modulus = xmemdup(key->modulus, key->len * sizeof(uint32_t));
+	new->rr = xmemdup(key->rr, key->len  * sizeof(uint32_t));
+
+	return new;
+}
+#else
+struct rsa_public_key *rsa_get_key(const char *name)
+{
+	return ERR_PTR(-ENOENT);
+}
+#endif
diff --git a/include/asm-generic/barebox.lds.h b/include/asm-generic/barebox.lds.h
index 8e8ae183db..b6ca8eb2be 100644
--- a/include/asm-generic/barebox.lds.h
+++ b/include/asm-generic/barebox.lds.h
@@ -98,6 +98,11 @@
 #define BAREBOX_PCI_FIXUP
 #endif
 
+#define BAREBOX_RSA_KEYS			\
+	__rsa_keys_start = .;			\
+	KEEP(*(.rsa_keys.rodata.*));		\
+	__rsa_keys_end = .;			\
+
 #define RO_DATA_SECTION				\
 	BAREBOX_INITCALLS			\
 	BAREBOX_EXITCALLS			\
@@ -107,6 +112,7 @@
 	BAREBOX_MAGICVARS			\
 	BAREBOX_CLK_TABLE			\
 	BAREBOX_DTB				\
+	BAREBOX_RSA_KEYS			\
 	BAREBOX_PCI_FIXUP
 
 #if defined(CONFIG_ARCH_BAREBOX_MAX_BARE_INIT_SIZE) && \
diff --git a/include/rsa.h b/include/rsa.h
index cf2e6c7e08..803660d19a 100644
--- a/include/rsa.h
+++ b/include/rsa.h
@@ -28,6 +28,7 @@ struct rsa_public_key {
 	uint32_t *modulus;	/* modulus as little endian array */
 	uint32_t *rr;		/* R^2 as little endian array */
 	uint64_t exponent;	/* public exponent */
+	char *key_name_hint;
 };
 
 /**
@@ -51,5 +52,6 @@ int rsa_verify(const struct rsa_public_key *key, const uint8_t *sig,
 
 struct rsa_public_key *rsa_of_read_key(struct device_node *node);
 void rsa_key_free(struct rsa_public_key *key);
+struct rsa_public_key *rsa_get_key(const char *name);
 
 #endif
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index c4d307ae30..ecaf5e1e7b 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -526,5 +526,23 @@ quiet_cmd_stm32_image = STM32-IMG $@
 quiet_cmd_b64dec = B64DEC  $@
       cmd_b64dec = base64 -d $< > $@
 
+# rsa_keys
+# ---------------------------------------------------------------------------
+# Build a header file containing a rsa public key.
+#
+# The keys can change without the build system noticing, so we always
+# have to call rsatoc. To avoid unnecessary rebuilds of barebox compare
+# its output to the last rsatoc output. Only if it differs overwrite the
+# target file.
+quiet_cmd_rsa_keys = RSAKEY  $@
+cmd_rsa_keys = \
+	$(srctree)/scripts/rsatoc $2 \
+		> $@.tmp &&						\
+	if cmp -s $@.tmp $@; then					\
+		rm $@.tmp;						\
+	else								\
+		mv $@.tmp $@;						\
+	fi
+
 %: %.base64
 	$(call cmd,b64dec)
-- 
2.23.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 5/5] fit-image: Use compiled-in keys
  2019-10-15  7:55 [PATCH 0/5] Allow to compile in rsa public keys directly Sascha Hauer
                   ` (3 preceding siblings ...)
  2019-10-15  7:55 ` [PATCH 4/5] rsa: Allow to directly compile in rsa public keys Sascha Hauer
@ 2019-10-15  7:55 ` Sascha Hauer
  4 siblings, 0 replies; 9+ messages in thread
From: Sascha Hauer @ 2019-10-15  7:55 UTC (permalink / raw)
  To: Barebox List

The compiled-in keys can be retrieved with rsa_get_key(). Try to use
them first before falling back to looking up the keys in the device
tree.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 common/image-fit.c | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/common/image-fit.c b/common/image-fit.c
index 71053fbef5..ca4d9ca10c 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -287,16 +287,21 @@ static int fit_check_rsa_signature(struct device_node *sig_node,
 		pr_err("key name not found in %s\n", sig_node->full_name);
 		return -EINVAL;
 	}
-	key_path = xasprintf("/signature/key-%s", key_name);
-	key_node = of_find_node_by_path(key_path);
-	if (!key_node) {
-		pr_info("failed to find key node %s\n", key_path);
+
+	key = rsa_get_key(key_name);
+	if (IS_ERR(key)) {
+		key_path = xasprintf("/signature/key-%s", key_name);
+		key_node = of_find_node_by_path(key_path);
+		if (!key_node) {
+			pr_info("failed to find key node %s\n", key_path);
+			free(key_path);
+			return -ENOENT;
+		}
 		free(key_path);
-		return -ENOENT;
+
+		key = rsa_of_read_key(key_node);
 	}
-	free(key_path);
 
-	key = rsa_of_read_key(key_node);
 	if (IS_ERR(key)) {
 		pr_info("failed to read key in %s\n", key_node->full_name);
 		return -ENOENT;
-- 
2.23.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/5] scripts: Add rsatoc tool
  2019-10-15  7:55 ` [PATCH 2/5] scripts: Add rsatoc tool Sascha Hauer
@ 2019-10-15 10:21   ` Ahmad Fatoum
  2019-10-15 13:15     ` Sascha Hauer
  0 siblings, 1 reply; 9+ messages in thread
From: Ahmad Fatoum @ 2019-10-15 10:21 UTC (permalink / raw)
  To: barebox, Sascha Hauer

Hello Sascha,

On 10/15/19 9:55 AM, Sascha Hauer wrote:
> The rsatoc tool converts rsa public keys into C structs suitable to
> compile with barebox. Most of the openssl rsa related stuff has been
> taken from the U-Boot mkimage tool.

I don't have any FIT image or RSA options enabled, yet my build fails now with:

  RSAKEY  crypto/rsa-keys.h                                                                                     
/bin/sh: 1: ./scripts/rsatoc: not found                           
./crypto/Makefile:27: recipe for target 'crypto/rsa-keys.h' failed
make[2]: *** [crypto/rsa-keys.h] Error 127                                                                      
./Makefile:802: recipe for target 'crypto' failed                 
make[1]: *** [crypto] Error 2                                                                                   

Cheers
Ahmad

> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  scripts/.gitignore |   1 +
>  scripts/Makefile   |   3 +
>  scripts/rsatoc.c   | 445 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 449 insertions(+)
>  create mode 100644 scripts/rsatoc.c
> 
> diff --git a/scripts/.gitignore b/scripts/.gitignore
> index 45c81bf8f4..76ea271abb 100644
> --- a/scripts/.gitignore
> +++ b/scripts/.gitignore
> @@ -29,3 +29,4 @@ mxs-usb-loader
>  omap4_usbboot
>  omap3-usb-loader
>  mips-relocs
> +rsatoc
> diff --git a/scripts/Makefile b/scripts/Makefile
> index dffab53c73..81d1a501b0 100644
> --- a/scripts/Makefile
> +++ b/scripts/Makefile
> @@ -10,6 +10,9 @@ hostprogs-y                      += fix_size
>  hostprogs-y                      += bareboxenv
>  hostprogs-y                      += bareboxcrc32
>  hostprogs-y                      += kernel-install
> +hostprogs-$(CONFIG_CRYPTO_RSA_BUILTIN_KEYS) += rsatoc
> +HOSTCFLAGS_rsatoc = `pkg-config --cflags openssl`
> +HOSTLDLIBS_rsatoc = `pkg-config --libs openssl`
>  hostprogs-$(CONFIG_IMD)          += bareboximd
>  hostprogs-$(CONFIG_KALLSYMS)     += kallsyms
>  hostprogs-$(CONFIG_MIPS)         += mips-relocs
> diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c
> new file mode 100644
> index 0000000000..f853691908
> --- /dev/null
> +++ b/scripts/rsatoc.c
> @@ -0,0 +1,445 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * rsatoc - utility to convert an RSA key to a C struct
> + *
> + * This tool converts an RSA key given as file or PKCS#11
> + * URI to a C struct suitable to compile with barebox.
> + */
> +#include <stdio.h>
> +#include <string.h>
> +#include <time.h>
> +#include <openssl/bn.h>
> +#include <openssl/rsa.h>
> +#include <openssl/pem.h>
> +#include <openssl/err.h>
> +#include <openssl/ssl.h>
> +#include <openssl/evp.h>
> +#include <openssl/engine.h>
> +
> +static int rsa_err(const char *msg)
> +{
> +	unsigned long sslErr = ERR_get_error();
> +
> +	fprintf(stderr, "%s", msg);
> +	fprintf(stderr, ": %s\n",
> +		ERR_error_string(sslErr, 0));
> +
> +	return -1;
> +}
> +
> +/**
> + * 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_pem_get_pub_key(const char *path, RSA **rsap)
> +{
> +	EVP_PKEY *key;
> +	X509 *cert;
> +	RSA *rsa;
> +	FILE *f;
> +	int ret;
> +
> +	*rsap = NULL;
> +	f = fopen(path, "r");
> +	if (!f) {
> +		fprintf(stderr, "Couldn't open RSA certificate: '%s': %s\n",
> +			path, strerror(errno));
> +		return -EACCES;
> +	}
> +
> +	/* Read the certificate */
> +	cert = NULL;
> +	if (!PEM_read_X509(f, &cert, NULL, NULL)) {
> +		rsa_err("Couldn't read certificate");
> +		ret = -EINVAL;
> +		goto err_cert;
> +	}
> +
> +	/* Get the public key from the certificate. */
> +	key = X509_get_pubkey(cert);
> +	if (!key) {
> +		rsa_err("Couldn't read public key\n");
> +		ret = -EINVAL;
> +		goto err_pubkey;
> +	}
> +
> +	/* 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;
> +	}
> +	fclose(f);
> +	EVP_PKEY_free(key);
> +	X509_free(cert);
> +	*rsap = rsa;
> +
> +	return 0;
> +
> +err_rsa:
> +	EVP_PKEY_free(key);
> +err_pubkey:
> +	X509_free(cert);
> +err_cert:
> +	fclose(f);
> +	return ret;
> +}
> +
> +/**
> + * rsa_engine_get_pub_key() - read a public 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_pub_key(const char *key_id,
> +				  ENGINE *engine, RSA **rsap)
> +{
> +	EVP_PKEY *key;
> +	RSA *rsa;
> +	int ret;
> +
> +	*rsap = NULL;
> +
> +	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_exponent(): - Get the public exponent from an RSA key
> + */
> +static int rsa_get_exponent(RSA *key, uint64_t *e)
> +{
> +	int ret;
> +	BIGNUM *bn_te;
> +	const BIGNUM *key_e;
> +	uint64_t te;
> +
> +	ret = -EINVAL;
> +	bn_te = NULL;
> +
> +	if (!e)
> +		goto cleanup;
> +
> +	RSA_get0_key(key, NULL, &key_e, NULL);
> +	if (BN_num_bits(key_e) > 64)
> +		goto cleanup;
> +
> +	*e = BN_get_word(key_e);
> +
> +	if (BN_num_bits(key_e) < 33) {
> +		ret = 0;
> +		goto cleanup;
> +	}
> +
> +	bn_te = BN_dup(key_e);
> +	if (!bn_te)
> +		goto cleanup;
> +
> +	if (!BN_rshift(bn_te, bn_te, 32))
> +		goto cleanup;
> +
> +	if (!BN_mask_bits(bn_te, 32))
> +		goto cleanup;
> +
> +	te = BN_get_word(bn_te);
> +	te <<= 32;
> +	*e |= te;
> +	ret = 0;
> +
> +cleanup:
> +	if (bn_te)
> +		BN_free(bn_te);
> +
> +	return ret;
> +}
> +
> +/*
> + * rsa_get_params(): - Get the important parameters of an RSA public key
> + */
> +int rsa_get_params(RSA *key, uint64_t *exponent, uint32_t *n0_invp,
> +		   BIGNUM **modulusp, BIGNUM **r_squaredp)
> +{
> +	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;
> +
> +	/* Initialize BIGNUMs */
> +	big1 = BN_new();
> +	big2 = BN_new();
> +	big32 = BN_new();
> +	r = BN_new();
> +	r_squared = BN_new();
> +	tmp = BN_new();
> +	big2_32 = BN_new();
> +	n = BN_new();
> +	if (!big1 || !big2 || !big32 || !r || !r_squared || !tmp || !big2_32 ||
> +	    !n) {
> +		fprintf(stderr, "Out of memory (bignum)\n");
> +		return -ENOMEM;
> +	}
> +
> +	if (0 != rsa_get_exponent(key, exponent))
> +		ret = -1;
> +
> +	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;
> +
> +	/* big2_32 = 2^32 */
> +	if (!BN_exp(big2_32, big2, big32, bn_ctx))
> +		ret = -1;
> +
> +	/* Calculate n0_inv = -1 / n[0] mod 2^32 */
> +	if (!BN_mod_inverse(tmp, n, big2_32, bn_ctx) ||
> +	    !BN_sub(tmp, big2_32, tmp))
> +		ret = -1;
> +	*n0_invp = BN_get_word(tmp);
> +
> +	/* Calculate R = 2^(# of key bits) */
> +	if (!BN_set_word(tmp, BN_num_bits(n)) ||
> +	    !BN_exp(r, big2, tmp, bn_ctx))
> +		ret = -1;
> +
> +	/* Calculate r_squared = R^2 mod n */
> +	if (!BN_copy(r_squared, r) ||
> +	    !BN_mul(tmp, r_squared, r, bn_ctx) ||
> +	    !BN_mod(r_squared, tmp, n, bn_ctx))
> +		ret = -1;
> +
> +	*modulusp = n;
> +	*r_squaredp = r_squared;
> +
> +	BN_free(big1);
> +	BN_free(big2);
> +	BN_free(big32);
> +	BN_free(r);
> +	BN_free(tmp);
> +	BN_free(big2_32);
> +	if (ret) {
> +		fprintf(stderr, "Bignum operations failed\n");
> +		return -ENOMEM;
> +	}
> +
> +	return ret;
> +}
> +
> +static int rsa_engine_init(ENGINE **pe)
> +{
> +	ENGINE *e;
> +	int ret;
> +
> +	ENGINE_load_builtin_engines();
> +
> +	e = ENGINE_by_id("pkcs11");
> +	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 || \
> +	(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x02070000fL)
> +	ENGINE_cleanup();
> +#endif
> +	return ret;
> +}
> +
> +static int print_bignum(BIGNUM *num, int num_bits)
> +{
> +	BIGNUM *tmp, *big2, *big32, *big2_32;
> +	BN_CTX *ctx;
> +	int i;
> +
> +	tmp = BN_new();
> +	big2 = BN_new();
> +	big32 = BN_new();
> +	big2_32 = BN_new();
> +
> +	/*
> +	 * Note: This code assumes that all of the above succeed, or all fail.
> +	 * In practice memory allocations generally do not fail (unless the
> +	 * process is killed), so it does not seem worth handling each of these
> +	 * as a separate case. Technicaly this could leak memory on failure,
> +	 * but a) it won't happen in practice, and b) it doesn't matter as we
> +	 * will immediately exit with a failure code.
> +	 */
> +	if (!tmp || !big2 || !big32 || !big2_32) {
> +		fprintf(stderr, "Out of memory (bignum)\n");
> +		return -ENOMEM;
> +	}
> +	ctx = BN_CTX_new();
> +	if (!tmp) {
> +		fprintf(stderr, "Out of memory (bignum context)\n");
> +		return -ENOMEM;
> +	}
> +	BN_set_word(big2, 2L);
> +	BN_set_word(big32, 32L);
> +	BN_exp(big2_32, big2, big32, ctx); /* B = 2^32 */
> +
> +	for (i = 0; i < num_bits / 32; i++) {
> +		BN_mod(tmp, num, big2_32, ctx); /* n = N mod B */
> +		if (i % 4)
> +			printf(" ");
> +		else
> +			printf("\n\t");
> +		printf("0x%08lx,", BN_get_word(tmp));
> +		BN_rshift(num, num, 32); /*  N = N/B */
> +	}
> +
> +	BN_free(tmp);
> +	BN_free(big2);
> +	BN_free(big32);
> +	BN_free(big2_32);
> +
> +	return 0;
> +}
> +
> +static int gen_key(const char *keyname, const char *path)
> +{
> +	BIGNUM *modulus, *r_squared;
> +	uint64_t exponent;
> +	uint32_t n0_inv;
> +	int ret;
> +	int bits;
> +	RSA *rsa;
> +	ENGINE *e = NULL;
> +	char *tmp, *key_name_c;
> +
> +	tmp = key_name_c = strdup(keyname);
> +
> +	while (*tmp) {
> +		if (*tmp == '-')
> +			*tmp = '_';
> +		tmp++;
> +	}
> +
> +	if (!strncmp(path, "__ENV__", 7)) {
> +		const char *var = getenv(path + 7);
> +		if (!var) {
> +			fprintf(stderr,
> +				"environment variable \"%s\" is empty\n", path + 7);
> +			exit(1);
> +		}
> +		path = var;
> +	}
> +
> +	if (!strncmp(path, "pkcs11:", 7)) {
> +		ret = rsa_engine_init(&e);
> +		if (ret)
> +			exit(1);
> +		ret = rsa_engine_get_pub_key(path, e, &rsa);
> +		if (ret)
> +			exit(1);
> +	} else {
> +		ret = rsa_pem_get_pub_key(path, &rsa);
> +		if (ret)
> +			exit(1);
> +	}
> +
> +	ret = rsa_get_params(rsa, &exponent, &n0_inv, &modulus, &r_squared);
> +	if (ret)
> +		return ret;
> +
> +	bits = BN_num_bits(modulus);
> +
> +	printf("\nstatic uint32_t %s_modulus[] = {", key_name_c);
> +	print_bignum(modulus, bits);
> +	printf("\n};\n\n");
> +
> +	printf("static uint32_t %s_rr[] = {", key_name_c);
> +	print_bignum(r_squared, bits);
> +	printf("\n};\n\n");
> +
> +	printf("static struct rsa_public_key %s = {\n", key_name_c);
> +	printf("\t.len = %d,\n", bits / 32);
> +	printf("\t.n0inv = 0x%0x,\n", n0_inv);
> +	printf("\t.modulus = %s_modulus,\n", key_name_c);
> +	printf("\t.rr = %s_rr,\n", key_name_c);
> +	printf("\t.exponent = 0x%0lx,\n", exponent);
> +	printf("\t.key_name_hint = \"%s\",\n", keyname);
> +	printf("};\n\n");
> +
> +	printf("struct rsa_public_key *%sp __attribute__((section(\".rsa_keys.rodata.%s\"))) = &%s;\n",
> +	       key_name_c, key_name_c, key_name_c);
> +
> +	return 0;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	char *path, *keyname;
> +	int i;
> +
> +	if (argc < 2) {
> +		fprintf(stderr, "Usage: %s <key_name_hint>:<crt> ...\n", argv[0]);
> +		exit(1);
> +	}
> +
> +	for (i = 1; i < argc; i++) {
> +		keyname = argv[i];
> +
> +		path = strchr(keyname, ':');
> +		if (!path) {
> +			fprintf(stderr,
> +				"keys must be given as <key_name_hint>:<crt>\n");
> +			exit(1);
> +		}
> +
> +		*path = 0;
> +		path++;
> +
> +		gen_key(keyname, path);
> +	}
> +
> +	exit(0);
> +}
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/5] scripts: Add rsatoc tool
  2019-10-15 10:21   ` Ahmad Fatoum
@ 2019-10-15 13:15     ` Sascha Hauer
  2019-10-15 13:19       ` Ahmad Fatoum
  0 siblings, 1 reply; 9+ messages in thread
From: Sascha Hauer @ 2019-10-15 13:15 UTC (permalink / raw)
  To: Ahmad Fatoum; +Cc: barebox

On Tue, Oct 15, 2019 at 12:21:31PM +0200, Ahmad Fatoum wrote:
> Hello Sascha,
> 
> On 10/15/19 9:55 AM, Sascha Hauer wrote:
> > The rsatoc tool converts rsa public keys into C structs suitable to
> > compile with barebox. Most of the openssl rsa related stuff has been
> > taken from the U-Boot mkimage tool.
> 
> I don't have any FIT image or RSA options enabled, yet my build fails now with:
> 
>   RSAKEY  crypto/rsa-keys.h                                                                                     
> /bin/sh: 1: ./scripts/rsatoc: not found                           
> ./crypto/Makefile:27: recipe for target 'crypto/rsa-keys.h' failed
> make[2]: *** [crypto/rsa-keys.h] Error 127                                                                      
> ./Makefile:802: recipe for target 'crypto' failed                 
> make[1]: *** [crypto] Error 2                                                                                  

Try again.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/5] scripts: Add rsatoc tool
  2019-10-15 13:15     ` Sascha Hauer
@ 2019-10-15 13:19       ` Ahmad Fatoum
  0 siblings, 0 replies; 9+ messages in thread
From: Ahmad Fatoum @ 2019-10-15 13:19 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox

On 10/15/19 3:15 PM, Sascha Hauer wrote:
> On Tue, Oct 15, 2019 at 12:21:31PM +0200, Ahmad Fatoum wrote:
>> Hello Sascha,
>>
>> On 10/15/19 9:55 AM, Sascha Hauer wrote:
>>> The rsatoc tool converts rsa public keys into C structs suitable to
>>> compile with barebox. Most of the openssl rsa related stuff has been
>>> taken from the U-Boot mkimage tool.
>>
>> I don't have any FIT image or RSA options enabled, yet my build fails now with:
>>
>>   RSAKEY  crypto/rsa-keys.h                                                                                     
>> /bin/sh: 1: ./scripts/rsatoc: not found                           
>> ./crypto/Makefile:27: recipe for target 'crypto/rsa-keys.h' failed
>> make[2]: *** [crypto/rsa-keys.h] Error 127                                                                      
>> ./Makefile:802: recipe for target 'crypto' failed                 
>> make[1]: *** [crypto] Error 2                                                                                  
> 
> Try again.

Works, thanks.

> 
> Sascha
> 


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-10-15 13:20 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-15  7:55 [PATCH 0/5] Allow to compile in rsa public keys directly Sascha Hauer
2019-10-15  7:55 ` [PATCH 1/5] Kbuild: Add config_filename macro from kernel Sascha Hauer
2019-10-15  7:55 ` [PATCH 2/5] scripts: Add rsatoc tool Sascha Hauer
2019-10-15 10:21   ` Ahmad Fatoum
2019-10-15 13:15     ` Sascha Hauer
2019-10-15 13:19       ` Ahmad Fatoum
2019-10-15  7:55 ` [PATCH 3/5] rsa: let rsa_of_read_key() return a fully allocated key Sascha Hauer
2019-10-15  7:55 ` [PATCH 4/5] rsa: Allow to directly compile in rsa public keys Sascha Hauer
2019-10-15  7:55 ` [PATCH 5/5] fit-image: Use compiled-in keys Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox