linux-crypto.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC][PATCH 0/6] KEYS: Introduce user mode key and signature parsers
@ 2023-04-25 17:35 Roberto Sassu
  2023-04-25 17:35 ` [RFC][PATCH 1/6] KEYS: asymmetric: Introduce UMD-based asymmetric key parser Roberto Sassu
                   ` (5 more replies)
  0 siblings, 6 replies; 13+ messages in thread
From: Roberto Sassu @ 2023-04-25 17:35 UTC (permalink / raw)
  To: dhowells, dwmw2, herbert, davem, jarkko, ast, daniel, andrii,
	martin.lau, song, yhs, john.fastabend, kpsingh, sdf, haoluo,
	jolsa, rostedt, mhiramat, mykolal, shuah
  Cc: linux-kernel, keyrings, linux-crypto, bpf, linux-trace-kernel,
	linux-kselftest, Roberto Sassu

From: Roberto Sassu <roberto.sassu@huawei.com>

Goals
=====

Support new key and signature formats with the same kernel component.

Verify the authenticity of system data with newly supported data formats.

Mitigate the risk of parsing arbitrary data in the kernel.


Motivation
==========

Adding new functionality to the kernel comes with an increased risk of
introducing new bugs which, once exploited, can lead to a partial or full
system compromise.

Parsing arbitrary data is particularly critical, since it allows an
attacker to send a malicious sequence of bytes to exploit vulnerabilities
in the parser code. The attacker might be able to overwrite kernel memory
to bypass kernel protections, and obtain more privileges.

User Mode Drivers (UMDs) can effectively mitigate this risk. If the parser
runs in user space, even if it has a bug, it won't allow the attacker to
overwrite kernel memory.

The communication protocol between the UMD and the kernel should be simple
enough, that the kernel can immediately recognize malformed data sent by an
attacker controlling the UMD, and discard it.


Solution
========

Register a new parser of the asymmetric key type which, instead of parsing
the key blob, forwards it to a UMD, and populates the key fields from the
UMD response. That response contains the data for each field of the public
key structure, defined in the kernel, and possibly a key description.

Supporting new data formats can be achieved by simply extending the UMD. As
long as the UMD recognizes them, and provides the crypto material to the
kernel Crypto API in the expected format, the kernel does not need to be
aware of the UMD changes.

Add a new API to verify the authenticity of system data, similar to the one
for PKCS#7 signatures. As for the key parser, send the signature to a UMD,
and fill the public_key_signature structure from the UMD response.

The API still supports a very basic trust model, it accepts a key for
signature verification if it is in the supplied keyring. The API can be
extended later to support more sophisticated models.


Use cases
=========

eBPF
----

The eBPF infrastructure already offers to eBPF programs the ability to
verify PKCS#7 signatures, through the bpf_verify_pkcs7_signature() kfunc.

Add the new bpf_verify_umd_signature() kfunc, to allow eBPF programs verify
signatures in a data format that is not PKCS#7 (for example PGP).


IMA Appraisal
-------------

An alternative to appraising each file with its signature (Fedora 38) is to
build a repository of reference file digests from signed RPM headers, and
lookup the calculated digest of files being accessed in that repository
(DIGLIM[1]).

With this patch set, the kernel can verify the authenticity of RPM headers
from their PGP signature against the Linux distribution GPG keys. Once
verified, RPM headers can be parsed with a UMD to build the repository of
reference file digests.

With DIGLIM, Linux distributions are not required to change anything in
their building infrastructure (no extra data in the RPM header, no new PKI
for IMA signatures).

[1]: https://lore.kernel.org/linux-integrity/20210914163401.864635-1-roberto.sassu@huawei.com/


UMD development
===============

The header file crypto/asymmetric_keys/umd_key_sig_umh.h contains the
details of the communication protocol between the kernel and the UMD
handler.

The UMD handler should implement the commands defined, CMD_KEY and CMD_SIG,
should set the result of the processing, and fill the key and
signature-specific structures umd_key_msg_out and umd_sig_msg_out.

The UMD handler should provide the key and signature blobs in a format that
is understood by the kernel. For example, for RSA keys, it should provide
them in ASN.1 format (SEQUENCE of INTEGER).

The auth IDs of the keys and signatures should match, for signature
verification. Auth ID matching can be partial.


Patch set dependencies
======================

This patch set depends on 'usermode_driver: Add management library and
API':

https://lore.kernel.org/bpf/20230317145240.363908-1-roberto.sassu@huaweicloud.com/


Patch set content
=================

Patch 1 introduces the new parser for the asymmetric key type.

Patch 2 introduces the parser for signatures and its API.

Patch 3 introduces the system-level API for signature verification.

Patch 4 extends eBPF to use the new system-level API.

Patch 5 adds a test for UMD-parser signatures (not executed until the UMD
supports PGP).

Patch 6 introduces the skeleton of the UMD handler.


PGP
===

A work in progress implementation of the PGP format (RFC 4880 and RFC 6637)
in the UMD handler is available at:

https://github.com/robertosassu/linux/commits/pgp-signatures-umd-v1-devel-v24

It is based on a previous work of David Howells, available at:

https://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-modsign.git/log/?h=pgp-parser

The patches have been adapted for use in user space.

Roberto Sassu (6):
  KEYS: asymmetric: Introduce UMD-based asymmetric key parser
  KEYS: asymmetric: Introduce UMD-based asymmetric key signature parser
  verification: Introduce verify_umd_signature() and
    verify_umd_message_sig()
  bpf: Introduce bpf_verify_umd_signature() kfunc
  selftests/bpf: Prepare a test for UMD-parsed signatures
  KEYS: asymmetric: Add UMD handler

 .gitignore                                    |   3 +
 MAINTAINERS                                   |   1 +
 certs/system_keyring.c                        | 125 ++++++
 crypto/asymmetric_keys/Kconfig                |  32 ++
 crypto/asymmetric_keys/Makefile               |  23 +
 crypto/asymmetric_keys/asymmetric_type.c      |   3 +-
 crypto/asymmetric_keys/umd_key.h              |  28 ++
 crypto/asymmetric_keys/umd_key_parser.c       | 203 +++++++++
 crypto/asymmetric_keys/umd_key_sig_loader.c   |  32 ++
 crypto/asymmetric_keys/umd_key_sig_umh.h      |  71 +++
 crypto/asymmetric_keys/umd_key_sig_umh_blob.S |   7 +
 crypto/asymmetric_keys/umd_key_sig_umh_user.c |  84 ++++
 crypto/asymmetric_keys/umd_sig_parser.c       | 416 ++++++++++++++++++
 include/crypto/umd_sig.h                      |  71 +++
 include/keys/asymmetric-type.h                |   1 +
 include/linux/verification.h                  |  48 ++
 kernel/trace/bpf_trace.c                      |  69 ++-
 ...ify_pkcs7_sig.c => verify_pkcs7_umd_sig.c} | 109 +++--
 ...kcs7_sig.c => test_verify_pkcs7_umd_sig.c} |  18 +-
 .../testing/selftests/bpf/verify_sig_setup.sh |  82 +++-
 20 files changed, 1378 insertions(+), 48 deletions(-)
 create mode 100644 crypto/asymmetric_keys/umd_key.h
 create mode 100644 crypto/asymmetric_keys/umd_key_parser.c
 create mode 100644 crypto/asymmetric_keys/umd_key_sig_loader.c
 create mode 100644 crypto/asymmetric_keys/umd_key_sig_umh.h
 create mode 100644 crypto/asymmetric_keys/umd_key_sig_umh_blob.S
 create mode 100644 crypto/asymmetric_keys/umd_key_sig_umh_user.c
 create mode 100644 crypto/asymmetric_keys/umd_sig_parser.c
 create mode 100644 include/crypto/umd_sig.h
 rename tools/testing/selftests/bpf/prog_tests/{verify_pkcs7_sig.c => verify_pkcs7_umd_sig.c} (75%)
 rename tools/testing/selftests/bpf/progs/{test_verify_pkcs7_sig.c => test_verify_pkcs7_umd_sig.c} (82%)

-- 
2.25.1


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

* [RFC][PATCH 1/6] KEYS: asymmetric: Introduce UMD-based asymmetric key parser
  2023-04-25 17:35 [RFC][PATCH 0/6] KEYS: Introduce user mode key and signature parsers Roberto Sassu
@ 2023-04-25 17:35 ` Roberto Sassu
  2023-04-25 17:35 ` [RFC][PATCH 2/6] KEYS: asymmetric: Introduce UMD-based asymmetric key signature parser Roberto Sassu
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Roberto Sassu @ 2023-04-25 17:35 UTC (permalink / raw)
  To: dhowells, dwmw2, herbert, davem, jarkko, ast, daniel, andrii,
	martin.lau, song, yhs, john.fastabend, kpsingh, sdf, haoluo,
	jolsa, rostedt, mhiramat, mykolal, shuah
  Cc: linux-kernel, keyrings, linux-crypto, bpf, linux-trace-kernel,
	linux-kselftest, Roberto Sassu

From: Roberto Sassu <roberto.sassu@huawei.com>

Introduce a new parser for the asymmetric key type. The parser forwards the
key payload to a User Mode Driver (UMD) handler, which replies with the
data necessary to populate a public_key structure (blob, IDs and algorithm)
and, possibly, with a key description.

The parser then validates the response, fills the key payload fields from
it, and sets the key description if provided.

The main advantage of this approach is that potential risks of parsing data
from the kernel are avoided, as the UMD handler does not have access to the
kernel memory.

If the UMD handler is corrupted, the damage is likely limited to user
space. The parser sanitizes malicious data sent by the UMD. In addition,
seccomp can further limit which system calls the UMD is authorized to
invoke.

The communication protocol between the parser and the UMD handler consists
of two main structures: msg_in for the parser request, and msg_out for the
UMD handler response.

msg_in contains a buffer for a generic request, not only for parsing keys,
and the type of command (CMD_KEY for key parsing).

msg_out contains the result of the operation to communicate to the parser,
and the specific structure umd_key_msg_out for storing the key payload
fields and the key description.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 crypto/asymmetric_keys/Kconfig           |  11 ++
 crypto/asymmetric_keys/Makefile          |   5 +
 crypto/asymmetric_keys/asymmetric_type.c |   3 +-
 crypto/asymmetric_keys/umd_key.h         |  20 +++
 crypto/asymmetric_keys/umd_key_parser.c  | 203 +++++++++++++++++++++++
 crypto/asymmetric_keys/umd_key_sig_umh.h |  52 ++++++
 include/keys/asymmetric-type.h           |   1 +
 7 files changed, 294 insertions(+), 1 deletion(-)
 create mode 100644 crypto/asymmetric_keys/umd_key.h
 create mode 100644 crypto/asymmetric_keys/umd_key_parser.c
 create mode 100644 crypto/asymmetric_keys/umd_key_sig_umh.h

diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
index 1ef3b46d6f6..5f627026476 100644
--- a/crypto/asymmetric_keys/Kconfig
+++ b/crypto/asymmetric_keys/Kconfig
@@ -85,4 +85,15 @@ config FIPS_SIGNATURE_SELFTEST
 	depends on ASYMMETRIC_KEY_TYPE
 	depends on PKCS7_MESSAGE_PARSER=X509_CERTIFICATE_PARSER
 
+config UMD_KEY_PARSER
+	bool "UMD-based parser for the asymmetric key type"
+	depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
+	select USERMODE_DRIVER
+	help
+	  This option introduces a new parser for the asymmetric key type.
+	  The parser forwards the request to a User Mode Driver (UMD) handler,
+	  which replies with the result.
+
+	  On success, the parser fills the key from the UMD handler response.
+
 endif # ASYMMETRIC_KEY_TYPE
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
index 0d1fa1b692c..d8f266cdeeb 100644
--- a/crypto/asymmetric_keys/Makefile
+++ b/crypto/asymmetric_keys/Makefile
@@ -76,3 +76,8 @@ verify_signed_pefile-y := \
 
 $(obj)/mscode_parser.o: $(obj)/mscode.asn1.h $(obj)/mscode.asn1.h
 $(obj)/mscode.asn1.o: $(obj)/mscode.asn1.c $(obj)/mscode.asn1.h
+
+#
+# UMD asymmetric key parser
+#
+obj-$(CONFIG_UMD_KEY_PARSER) += umd_key_parser.o
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
index 41a2f0eb4ce..f1752eb8ff8 100644
--- a/crypto/asymmetric_keys/asymmetric_type.c
+++ b/crypto/asymmetric_keys/asymmetric_type.c
@@ -431,7 +431,7 @@ static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
 /*
  * Clean up the key ID list
  */
-static void asymmetric_key_free_kids(struct asymmetric_key_ids *kids)
+void asymmetric_key_free_kids(struct asymmetric_key_ids *kids)
 {
 	int i;
 
@@ -441,6 +441,7 @@ static void asymmetric_key_free_kids(struct asymmetric_key_ids *kids)
 		kfree(kids);
 	}
 }
+EXPORT_SYMBOL_GPL(asymmetric_key_free_kids);
 
 /*
  * Clean up the preparse data
diff --git a/crypto/asymmetric_keys/umd_key.h b/crypto/asymmetric_keys/umd_key.h
new file mode 100644
index 00000000000..7e641bbf884
--- /dev/null
+++ b/crypto/asymmetric_keys/umd_key.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * Header file of the UMD asymmetric key parser.
+ */
+
+#include <linux/usermode_driver_mgmt.h>
+#include <keys/asymmetric-subtype.h>
+#include <keys/asymmetric-parser.h>
+
+#include "umd_key_sig_umh.h"
+
+extern struct umd_mgmt key_ops;
+extern const char *pub_key_algos[PUBKEY_ALGO__LAST];
+
+int umd_get_kids(struct umd_asymmetric_key_ids *umd_kids,
+		 struct asymmetric_key_id *id[3]);
diff --git a/crypto/asymmetric_keys/umd_key_parser.c b/crypto/asymmetric_keys/umd_key_parser.c
new file mode 100644
index 00000000000..bd7d09d89f3
--- /dev/null
+++ b/crypto/asymmetric_keys/umd_key_parser.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * Implement the UMD asymmetric key parser.
+ */
+
+#include <linux/module.h>
+#include <crypto/public_key.h>
+
+#include "umd_key.h"
+
+const char *pub_key_algos[PUBKEY_ALGO__LAST] = {
+	[PUBKEY_ALGO_RSA] = "rsa",
+	[PUBKEY_ALGO_ECDSA] = "ecdsa",
+	[PUBKEY_ALGO_ECDSA_NIST_P192] = "ecdsa-nist-p192",
+	[PUBKEY_ALGO_ECDSA_NIST_P256] = "ecdsa-nist-p256",
+	[PUBKEY_ALGO_ECDSA_NIST_P384] = "ecdsa-nist-p384",
+};
+
+struct umd_mgmt key_ops = {
+	.info.driver_name = "umd_key_sig_umh",
+	.kmod = "umd_key_sig_user",
+	.lock = __MUTEX_INITIALIZER(key_ops.lock),
+};
+EXPORT_SYMBOL_GPL(key_ops);
+
+static struct public_key *get_public_key(struct msg_out *out)
+{
+	struct public_key *pub;
+
+	if (out->key.pkey_algo >= PUBKEY_ALGO__LAST) {
+		pr_err("Unexpected key algo %d\n", out->key.pkey_algo);
+		return ERR_PTR(-EBADMSG);
+	}
+
+	if (!out->key.pub_key_len) {
+		pr_err("Unexpected zero-length for public key\n");
+		return ERR_PTR(-EBADMSG);
+	}
+
+	if (out->key.pub_key_len > sizeof(out->key.pub_key)) {
+		pr_err("Public key length %ld greater than expected %ld\n",
+		       out->key.pub_key_len, sizeof(out->key.pub_key));
+		return ERR_PTR(-EBADMSG);
+	}
+
+	pub = kzalloc(sizeof(*pub), GFP_KERNEL);
+	if (!pub)
+		return ERR_PTR(-ENOMEM);
+
+	pub->id_type = "UMD";
+	pub->pkey_algo = pub_key_algos[out->key.pkey_algo];
+
+	pub->key = kmemdup(out->key.pub_key, out->key.pub_key_len, GFP_KERNEL);
+	if (!pub->key) {
+		kfree(pub);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	pub->keylen = out->key.pub_key_len;
+	return pub;
+}
+
+int umd_get_kids(struct umd_asymmetric_key_ids *umd_kids,
+		 struct asymmetric_key_id **id)
+{
+	int ret = 0, i, j;
+
+	for (i = 0; i < ARRAY_SIZE(umd_kids->kid1_len); i++) {
+		if (!umd_kids->kid1_len[i] && !umd_kids->kid2_len[i])
+			continue;
+
+		if (umd_kids->kid1_len[i] > sizeof(umd_kids->kid1[0])) {
+			pr_err("Key ID 1 length %ld greater than expected %ld\n",
+			       umd_kids->kid1_len[i],
+			       sizeof(umd_kids->kid1[0]));
+			ret = -EBADMSG;
+			break;
+		}
+
+		if (umd_kids->kid2_len[i] > sizeof(umd_kids->kid2[0])) {
+			pr_err("Key ID 2 length %ld greater than expected %ld\n",
+			       umd_kids->kid2_len[i],
+			       sizeof(umd_kids->kid2[0]));
+			ret = -EBADMSG;
+			break;
+		}
+
+		id[i] = asymmetric_key_generate_id(umd_kids->kid1[i],
+						   umd_kids->kid1_len[i],
+						   umd_kids->kid2[i],
+						   umd_kids->kid2_len[i]);
+		if (!id[i]) {
+			ret = -ENOMEM;
+			break;
+		}
+	}
+
+	if (ret) {
+		for (j = 0; j < i; j++)
+			kfree(id[j]);
+	}
+
+	return ret;
+}
+
+static int umd_key_parse(struct key_preparsed_payload *prep)
+{
+	struct msg_in *in = NULL;
+	struct msg_out *out = NULL;
+	struct asymmetric_key_ids *kids = NULL;
+	struct public_key *pub = NULL;
+	int ret = -ENOMEM;
+
+	in = kzalloc(sizeof(*in), GFP_KERNEL);
+	if (!in)
+		goto out;
+
+	out = kzalloc(sizeof(*out), GFP_KERNEL);
+	if (!out)
+		goto out;
+
+	in->cmd = CMD_KEY;
+	in->data_len = prep->datalen;
+	/* Truncate the input, there might be multiple keys in the same blob. */
+	memcpy(in->data, prep->data, min(prep->datalen, sizeof(in->data)));
+
+	out->ret = -EINVAL;
+
+	ret = umd_mgmt_send_recv(&key_ops, in, sizeof(*in), out, sizeof(*out));
+	if (ret)
+		goto out;
+
+	if (out->ret) {
+		ret = out->ret;
+		goto out;
+	}
+
+	pub = get_public_key(out);
+	if (IS_ERR(pub)) {
+		ret = PTR_ERR(pub);
+		pub = NULL;
+		goto out;
+	}
+
+	kids = kzalloc(sizeof(*kids), GFP_KERNEL);
+	if (!kids) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = umd_get_kids(&out->key.kids,
+			   (struct asymmetric_key_id **)kids->id);
+	if (ret)
+		goto out;
+
+	if (strlen(out->key.key_desc)) {
+		prep->description = kstrdup(out->key.key_desc, GFP_KERNEL);
+		if (!prep->description)
+			ret = -ENOMEM;
+	}
+
+out:
+	kfree(in);
+	kfree(out);
+
+	if (ret) {
+		public_key_free(pub);
+		asymmetric_key_free_kids(kids);
+		return ret;
+	}
+
+	/* We're pinning the module by being linked against it */
+	__module_get(public_key_subtype.owner);
+	prep->payload.data[asym_subtype] = &public_key_subtype;
+	prep->payload.data[asym_key_ids] = kids;
+	prep->payload.data[asym_crypto] = pub;
+	prep->quotalen = 100;
+	return 0;
+}
+
+static struct asymmetric_key_parser umd_key_parser = {
+	.owner = THIS_MODULE,
+	.name = "umd_key",
+	.parse = umd_key_parse
+};
+
+static int __init umd_key_init(void)
+{
+	return register_asymmetric_key_parser(&umd_key_parser);
+}
+
+static void __exit umd_key_exit(void)
+{
+	unregister_asymmetric_key_parser(&umd_key_parser);
+}
+
+module_init(umd_key_init);
+module_exit(umd_key_exit);
+MODULE_LICENSE("GPL");
diff --git a/crypto/asymmetric_keys/umd_key_sig_umh.h b/crypto/asymmetric_keys/umd_key_sig_umh.h
new file mode 100644
index 00000000000..e01c9e341c6
--- /dev/null
+++ b/crypto/asymmetric_keys/umd_key_sig_umh.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * Header file for communication between the kernel and the UMD handler.
+ */
+
+#define MAX_KEY_SIZE 1024
+#define MAX_KEY_DESC_SIZE 256
+#define MAX_PAYLOAD_SIZE 8192
+#define MAX_KID_SIZE 256
+
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+
+enum cmds { CMD_KEY, CMD__LAST };
+
+/* Public key algorithms that the kernel supports. */
+enum pub_key_algos { PUBKEY_ALGO_RSA, PUBKEY_ALGO_ECDSA,
+		     PUBKEY_ALGO_ECDSA_NIST_P192, PUBKEY_ALGO_ECDSA_NIST_P256,
+		     PUBKEY_ALGO_ECDSA_NIST_P384, PUBKEY_ALGO__LAST };
+
+struct msg_in {
+	enum cmds cmd;
+	size_t data_len;
+	unsigned char data[MAX_PAYLOAD_SIZE];
+} __packed;
+
+struct umd_asymmetric_key_ids {
+	size_t kid1_len[3];
+	unsigned char kid1[3][MAX_KID_SIZE];
+	size_t kid2_len[3];
+	unsigned char kid2[3][MAX_KID_SIZE];
+} __packed;
+
+struct umd_key_msg_out {
+	size_t pub_key_len;
+	unsigned char pub_key[MAX_KEY_SIZE];
+	enum pub_key_algos pkey_algo;
+	struct umd_asymmetric_key_ids kids;
+	char key_desc[MAX_KEY_DESC_SIZE];
+} __packed;
+
+struct msg_out {
+	int ret;
+	union {
+		struct umd_key_msg_out key;
+	};
+} __packed;
diff --git a/include/keys/asymmetric-type.h b/include/keys/asymmetric-type.h
index 69a13e1e5b2..acbb8c805f6 100644
--- a/include/keys/asymmetric-type.h
+++ b/include/keys/asymmetric-type.h
@@ -66,6 +66,7 @@ extern struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1,
 							    size_t len_1,
 							    const void *val_2,
 							    size_t len_2);
+void asymmetric_key_free_kids(struct asymmetric_key_ids *kids);
 static inline
 const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key)
 {
-- 
2.25.1


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

* [RFC][PATCH 2/6] KEYS: asymmetric: Introduce UMD-based asymmetric key signature parser
  2023-04-25 17:35 [RFC][PATCH 0/6] KEYS: Introduce user mode key and signature parsers Roberto Sassu
  2023-04-25 17:35 ` [RFC][PATCH 1/6] KEYS: asymmetric: Introduce UMD-based asymmetric key parser Roberto Sassu
@ 2023-04-25 17:35 ` Roberto Sassu
  2023-04-25 17:35 ` [RFC][PATCH 3/6] verification: Introduce verify_umd_signature() and verify_umd_message_sig() Roberto Sassu
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Roberto Sassu @ 2023-04-25 17:35 UTC (permalink / raw)
  To: dhowells, dwmw2, herbert, davem, jarkko, ast, daniel, andrii,
	martin.lau, song, yhs, john.fastabend, kpsingh, sdf, haoluo,
	jolsa, rostedt, mhiramat, mykolal, shuah
  Cc: linux-kernel, keyrings, linux-crypto, bpf, linux-trace-kernel,
	linux-kselftest, Roberto Sassu

From: Roberto Sassu <roberto.sassu@huawei.com>

Like for keys, add a parser of asymmetric key signatures which forwards the
request to a UMD handler (the same used for keys) and obtains from it the
parsed fields (blob, public key algo, hash algo, signature encoding, and
additional data required for the verification).

Introduce an API for each phase of the signature verification: signature
parsing, supplying/getting the data for the verification, calculating the
digest, doing the actual signature verification and, finally, freeing the
allocated memory.

Extend the communication protocol with the UMD handler, by introducing the
new specific structure umd_sig_msg_out, to be included in msg_out, and by
introducing the new command CMD_SIG.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 MAINTAINERS                              |   1 +
 crypto/asymmetric_keys/Kconfig           |  11 +
 crypto/asymmetric_keys/Makefile          |   5 +
 crypto/asymmetric_keys/umd_key.h         |   8 +
 crypto/asymmetric_keys/umd_key_sig_umh.h |  21 +-
 crypto/asymmetric_keys/umd_sig_parser.c  | 416 +++++++++++++++++++++++
 include/crypto/umd_sig.h                 |  71 ++++
 7 files changed, 532 insertions(+), 1 deletion(-)
 create mode 100644 crypto/asymmetric_keys/umd_sig_parser.c
 create mode 100644 include/crypto/umd_sig.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 782242fef7f..dd210bbcc2b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3205,6 +3205,7 @@ F:	Documentation/crypto/asymmetric-keys.rst
 F:	crypto/asymmetric_keys/
 F:	include/crypto/pkcs7.h
 F:	include/crypto/public_key.h
+F:	include/crypto/umd_sig.h
 F:	include/linux/verification.h
 
 ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
index 5f627026476..d312feae88e 100644
--- a/crypto/asymmetric_keys/Kconfig
+++ b/crypto/asymmetric_keys/Kconfig
@@ -96,4 +96,15 @@ config UMD_KEY_PARSER
 
 	  On success, the parser fills the key from the UMD handler response.
 
+config UMD_SIG_PARSER
+	bool "UMD-based parser for asymmetric key signatures"
+	depends on UMD_KEY_PARSER
+	help
+	  This option introduces a new parser for asymmetric key signatures.
+	  The parser forwards the request to a User Mode Driver (UMD) handler
+	  (the same used for keys), which replies with the result.
+
+	  On success, the parser fills the signature from the UMD handler
+	  response.
+
 endif # ASYMMETRIC_KEY_TYPE
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
index d8f266cdeeb..060c699fbb2 100644
--- a/crypto/asymmetric_keys/Makefile
+++ b/crypto/asymmetric_keys/Makefile
@@ -81,3 +81,8 @@ $(obj)/mscode.asn1.o: $(obj)/mscode.asn1.c $(obj)/mscode.asn1.h
 # UMD asymmetric key parser
 #
 obj-$(CONFIG_UMD_KEY_PARSER) += umd_key_parser.o
+
+#
+# UMD signature parser
+#
+obj-$(CONFIG_UMD_SIG_PARSER) += umd_sig_parser.o
diff --git a/crypto/asymmetric_keys/umd_key.h b/crypto/asymmetric_keys/umd_key.h
index 7e641bbf884..91da42c5aa8 100644
--- a/crypto/asymmetric_keys/umd_key.h
+++ b/crypto/asymmetric_keys/umd_key.h
@@ -18,3 +18,11 @@ extern const char *pub_key_algos[PUBKEY_ALGO__LAST];
 
 int umd_get_kids(struct umd_asymmetric_key_ids *umd_kids,
 		 struct asymmetric_key_id *id[3]);
+
+struct umd_sig_message {
+	struct public_key_signature *sig;
+	size_t data_len;
+	const void *data;
+	size_t sig_data_len;
+	const void *sig_data;
+};
diff --git a/crypto/asymmetric_keys/umd_key_sig_umh.h b/crypto/asymmetric_keys/umd_key_sig_umh.h
index e01c9e341c6..5f5ae81a9de 100644
--- a/crypto/asymmetric_keys/umd_key_sig_umh.h
+++ b/crypto/asymmetric_keys/umd_key_sig_umh.h
@@ -7,22 +7,29 @@
  * Header file for communication between the kernel and the UMD handler.
  */
 
+#include <linux/hash_info.h>
+
 #define MAX_KEY_SIZE 1024
 #define MAX_KEY_DESC_SIZE 256
 #define MAX_PAYLOAD_SIZE 8192
 #define MAX_KID_SIZE 256
+#define MAX_SIG_SIZE MAX_KEY_SIZE
+#define MAX_SIG_DATA_SIZE 1024
 
 #ifndef __packed
 #define __packed __attribute__((packed))
 #endif
 
-enum cmds { CMD_KEY, CMD__LAST };
+enum cmds { CMD_KEY, CMD_SIG, CMD__LAST };
 
 /* Public key algorithms that the kernel supports. */
 enum pub_key_algos { PUBKEY_ALGO_RSA, PUBKEY_ALGO_ECDSA,
 		     PUBKEY_ALGO_ECDSA_NIST_P192, PUBKEY_ALGO_ECDSA_NIST_P256,
 		     PUBKEY_ALGO_ECDSA_NIST_P384, PUBKEY_ALGO__LAST };
 
+/* Signature encodings that the kernel supports. */
+enum sig_encodings { SIG_ENC_PKCS1, SIG_ENC_X962, SIG_ENC_RAW, SIG_ENC__LAST };
+
 struct msg_in {
 	enum cmds cmd;
 	size_t data_len;
@@ -44,9 +51,21 @@ struct umd_key_msg_out {
 	char key_desc[MAX_KEY_DESC_SIZE];
 } __packed;
 
+struct umd_sig_msg_out {
+	size_t sig_len;
+	unsigned char sig[MAX_SIG_SIZE];
+	enum pub_key_algos pkey_algo;
+	enum hash_algo hash_algo;
+	enum sig_encodings enc;
+	struct umd_asymmetric_key_ids auth_ids;
+	size_t sig_data_len;
+	unsigned char sig_data[MAX_SIG_DATA_SIZE];
+} __packed;
+
 struct msg_out {
 	int ret;
 	union {
 		struct umd_key_msg_out key;
+		struct umd_sig_msg_out sig;
 	};
 } __packed;
diff --git a/crypto/asymmetric_keys/umd_sig_parser.c b/crypto/asymmetric_keys/umd_sig_parser.c
new file mode 100644
index 00000000000..03bc2310f89
--- /dev/null
+++ b/crypto/asymmetric_keys/umd_sig_parser.c
@@ -0,0 +1,416 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * Implement the UMD asymmetric key signature parser.
+ */
+
+#include <linux/module.h>
+#include <keys/asymmetric-subtype.h>
+#include <keys/asymmetric-parser.h>
+#include <crypto/public_key.h>
+#include <crypto/umd_sig.h>
+#include <crypto/hash_info.h>
+#include <crypto/hash.h>
+
+#include "umd_key.h"
+
+const char *sig_encodings[SIG_ENC__LAST] = {
+	[SIG_ENC_PKCS1] = "pkcs1",
+	[SIG_ENC_X962] = "x962",
+	[SIG_ENC_RAW] = "raw",
+};
+
+static struct public_key_signature *get_sig(struct msg_out *out)
+{
+	struct public_key_signature *sig = NULL;
+	int ret;
+
+	if (!out->sig.sig_len) {
+		pr_err("Unexpected zero-length for signature\n");
+		return ERR_PTR(-EBADMSG);
+	}
+
+	if (out->sig.sig_len > sizeof(out->sig.sig)) {
+		pr_err("Signature length %ld greater than expected %ld\n",
+		       out->sig.sig_len, sizeof(out->sig.sig));
+		return ERR_PTR(-EBADMSG);
+	}
+
+	if (out->sig.pkey_algo >= PUBKEY_ALGO__LAST) {
+		pr_err("Unexpected key algo %d\n", out->sig.pkey_algo);
+		return ERR_PTR(-EBADMSG);
+	}
+
+	if (out->sig.hash_algo >= HASH_ALGO__LAST) {
+		pr_err("Unexpected hash algo %d\n", out->sig.hash_algo);
+		return ERR_PTR(-EBADMSG);
+	}
+
+	if (out->sig.enc >= SIG_ENC__LAST) {
+		pr_err("Unexpected signature encoding %d\n", out->sig.enc);
+		return ERR_PTR(-EBADMSG);
+	}
+
+	sig = kzalloc(sizeof(*sig), GFP_KERNEL);
+	if (!sig)
+		return ERR_PTR(-ENOMEM);
+
+	sig->s = kmemdup(out->sig.sig, out->sig.sig_len, GFP_KERNEL);
+	if (!sig->s) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	sig->s_size = out->sig.sig_len;
+
+	ret = umd_get_kids(&out->sig.auth_ids, sig->auth_ids);
+	if (ret)
+		goto out;
+
+	sig->pkey_algo = pub_key_algos[out->sig.pkey_algo];
+	sig->hash_algo = hash_algo_name[out->sig.hash_algo];
+	sig->digest_size = hash_digest_size[out->sig.hash_algo];
+	sig->encoding = sig_encodings[out->sig.enc];
+out:
+	if (ret) {
+		public_key_signature_free(sig);
+		sig = ERR_PTR(ret);
+	}
+
+	return sig;
+}
+
+static int get_sig_data(struct msg_out *out, struct umd_sig_message *umd_sig)
+{
+	if (!out->sig.sig_data_len)
+		return 0;
+
+	if (out->sig.sig_data_len > sizeof(out->sig.sig_data)) {
+		pr_err("Additional data length %ld greater than expected %ld\n",
+		       out->sig.sig_data_len, sizeof(out->sig.sig_data));
+		return -EBADMSG;
+	}
+
+	umd_sig->sig_data = kmemdup(out->sig.sig_data, out->sig.sig_data_len,
+				    GFP_KERNEL);
+	if (!umd_sig->sig_data)
+		return -ENOMEM;
+
+	umd_sig->sig_data_len = out->sig.sig_data_len;
+	return 0;
+}
+
+/**
+ * umd_sig_parse_message - Parse a signature with a UMD handler
+ * @sig_data: Signature blob
+ * @sig_len: Length of signature blob
+ *
+ * Pass the signature blob to a UMD handler and fill a public_key_signature
+ * structure from the UMD handler response.
+ *
+ * Return: A umd_sig_message structure on success, an error pointer on error.
+ */
+struct umd_sig_message *umd_sig_parse_message(const u8 *sig_data,
+					      size_t sig_len)
+{
+	struct msg_in *in = NULL;
+	struct msg_out *out = NULL;
+	struct umd_sig_message *umd_sig = NULL;
+	int ret = -ENOMEM;
+
+	if (sig_len > sizeof(in->data))
+		return ERR_PTR(-EINVAL);
+
+	in = kzalloc(sizeof(*in), GFP_KERNEL);
+	if (!in)
+		goto out;
+
+	out = kzalloc(sizeof(*out), GFP_KERNEL);
+	if (!out)
+		goto out;
+
+	in->cmd = CMD_SIG;
+	in->data_len = sig_len;
+	memcpy(in->data, sig_data, sig_len);
+
+	out->ret = -EINVAL;
+
+	ret = umd_mgmt_send_recv(&key_ops, in, sizeof(*in), out, sizeof(*out));
+	if (ret)
+		goto out;
+
+	if (out->ret) {
+		ret = out->ret;
+		goto out;
+	}
+
+	umd_sig = kzalloc(sizeof(*umd_sig), GFP_KERNEL);
+	if (!umd_sig) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	umd_sig->sig = get_sig(out);
+	if (IS_ERR(umd_sig->sig)) {
+		ret = PTR_ERR(umd_sig->sig);
+		umd_sig->sig = NULL;
+		goto out;
+	}
+
+	ret = get_sig_data(out, umd_sig);
+out:
+	if (ret) {
+		if (umd_sig) {
+			public_key_signature_free(umd_sig->sig);
+			kfree(umd_sig);
+		}
+
+		umd_sig = ERR_PTR(ret);
+	}
+
+	kfree(in);
+	kfree(out);
+	return umd_sig;
+}
+EXPORT_SYMBOL_GPL(umd_sig_parse_message);
+
+/**
+ * umd_sig_supply_detached_data - Supply the data to verify a UMD-parsed sig
+ * @umd_sig: The UMD-parsed signature
+ * @data: The data to be verified
+ * @data_len: The amount of data
+ *
+ * Supply the detached data needed to verify a UMD-parsed signature. Note that
+ * no attempt to retain/pin the data is made. That is left to the caller. The
+ * data will not be modified by umd_sig_verify_message() and will not be freed
+ * when the UMD-parsed signature is freed.
+ *
+ * Return: Zero on success, -EINVAL if data are already supplied.
+ */
+int umd_sig_supply_detached_data(struct umd_sig_message *umd_sig,
+				 const void *data, size_t data_len)
+{
+	if (umd_sig->data) {
+		pr_debug("Data already supplied\n");
+		return -EINVAL;
+	}
+	umd_sig->data = data;
+	umd_sig->data_len = data_len;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(umd_sig_supply_detached_data);
+
+/**
+ * umd_sig_get_content_data - Get access to content data and additional data
+ * @umd_sig: The UMD-parsed signature
+ * @_data: Place to return a pointer to the data
+ * @_data_len: Place to return the data length
+ * @_headerlen: Size of the additional data
+ *
+ * Get access to the data associated to the UMD-parsed signature. This includes
+ * the content data eventually supplied by the caller of the UMD signatures API,
+ * and the additional data resulting from the signature parsing, appended at the
+ * end (the ordering can be configurable in the future).
+ *
+ * Data is allocated, to concatenate together the two data sources, and must be
+ * freed by the caller. It is presented in a way that is suitable for
+ * calculating the digest for verifying the signature.
+ *
+ * Return: Zero if the data and additional data can be provided,
+ *         a negative value on error.
+ */
+int umd_sig_get_content_data(struct umd_sig_message *umd_sig,
+			     const void **_data, size_t *_data_len,
+			     size_t *_headerlen)
+{
+	void *data;
+
+	if (!umd_sig->data)
+		return -ENODATA;
+
+	if (!_data)
+		goto skip_data;
+
+	data = kmalloc(umd_sig->data_len + umd_sig->sig->data_size, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	memcpy(data, umd_sig->data, umd_sig->data_len);
+	memcpy(data + umd_sig->data_len, umd_sig->sig->data,
+	       umd_sig->sig->data_size);
+	*_data = data;
+skip_data:
+	if (_data_len)
+		*_data_len = umd_sig->data_len + umd_sig->sig->data_size;
+	if (_headerlen)
+		*_headerlen = umd_sig->sig->data_size;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(umd_sig_get_content_data);
+
+static int umd_sig_digest(struct umd_sig_message *umd_sig)
+{
+	struct public_key_signature *sig = umd_sig->sig;
+	struct crypto_shash *tfm;
+	struct shash_desc *desc;
+	size_t desc_size;
+	int ret;
+
+	/* The digest was calculated already. */
+	if (sig->digest)
+		return 0;
+
+	tfm = crypto_alloc_shash(sig->hash_algo, 0, 0);
+	if (IS_ERR(tfm))
+		return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
+
+	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
+
+	ret = -ENOMEM;
+	sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
+	if (!sig->digest)
+		goto error_no_desc;
+
+	desc = kzalloc(desc_size, GFP_KERNEL);
+	if (!desc)
+		goto error_no_desc;
+
+	desc->tfm = tfm;
+
+	ret = crypto_shash_init(desc);
+	if (ret < 0)
+		goto error;
+
+	ret = crypto_shash_update(desc, umd_sig->data, umd_sig->data_len);
+	if (ret < 0)
+		goto error;
+
+	ret = crypto_shash_finup(desc, umd_sig->sig_data, umd_sig->sig_data_len,
+				 sig->digest);
+error:
+	kfree(desc);
+error_no_desc:
+	crypto_free_shash(tfm);
+	return ret;
+}
+
+/**
+ * umd_sig_get_digest - Obtain the digest and algorithm of the data to verify
+ * @umd_sig: The UMD-parsed signature
+ * @digest: The buffer the digest is written to
+ * @digest_len: The length of @digest
+ * @hash_algo: The algorithm the digest is calculated with
+ *
+ * Calculate the digest of data to verify with the UMD-parsed signature, if
+ * not calculated already. Pass the pointer of the digest from the
+ * public_key_signature structure, the length and the algorithm to the caller.
+ *
+ * Return: Zero on success, a negative value otherwise.
+ */
+int umd_sig_get_digest(struct umd_sig_message *umd_sig, const u8 **digest,
+		       u32 *digest_len, enum hash_algo *hash_algo)
+{
+	struct public_key_signature *sig = umd_sig->sig;
+	int i, ret;
+
+	ret = umd_sig_digest(umd_sig);
+	if (ret)
+		return ret;
+
+	*digest = sig->digest;
+	*digest_len = sig->digest_size;
+
+	i = match_string(hash_algo_name, HASH_ALGO__LAST, sig->hash_algo);
+	if (i >= 0)
+		*hash_algo = i;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(umd_sig_get_digest);
+
+static struct key *get_key(struct umd_sig_message *umd_sig, struct key *keyring)
+{
+	struct public_key_signature *sig = umd_sig->sig;
+	struct key *key;
+
+	key = find_asymmetric_key(keyring, sig->auth_ids[0], sig->auth_ids[1],
+				  sig->auth_ids[2], true);
+	if (IS_ERR(key)) {
+		pr_debug("Public key not found (#%*phN, #%*phN, #%*phN)\n",
+			 sig->auth_ids[0]->len, sig->auth_ids[0]->data,
+			 sig->auth_ids[1]->len, sig->auth_ids[1]->data,
+			 sig->auth_ids[2]->len, sig->auth_ids[2]->data);
+
+		switch (PTR_ERR(key)) {
+			/* Hide some search errors */
+		case -EACCES:
+		case -ENOTDIR:
+		case -EAGAIN:
+			return ERR_PTR(-ENOKEY);
+		default:
+			return ERR_CAST(key);
+		}
+	}
+
+	return key;
+}
+
+/**
+ * umd_sig_verify_message - Verify the UMD-parsed signature
+ * @umd_sig: The UMD-parsed signature
+ * @keyring: Keyring containing the key for signature verification
+ *
+ * Calculate the digest, search the key for signature verification, and verify
+ * the signature.
+ *
+ * Return: Zero if the signature is valid, a negative value otherwise.
+ */
+int umd_sig_verify_message(struct umd_sig_message *umd_sig, struct key *keyring)
+{
+	const struct public_key *pub;
+	struct key *key;
+	int ret;
+
+	ret = umd_sig_digest(umd_sig);
+	if (ret < 0)
+		return ret;
+
+	key = get_key(umd_sig, keyring);
+	if (IS_ERR(key))
+		return PTR_ERR(key);
+
+	pub = key->payload.data[asym_crypto];
+
+	if (strcmp(pub->pkey_algo, umd_sig->sig->pkey_algo) != 0 &&
+	    (strncmp(pub->pkey_algo, "ecdsa-", 6) != 0 ||
+	     strcmp(umd_sig->sig->pkey_algo, "ecdsa") != 0)) {
+		ret = -EKEYREJECTED;
+		goto out;
+	}
+
+	ret = verify_signature(key, umd_sig->sig);
+out:
+	key_put(key);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(umd_sig_verify_message);
+
+/**
+ * umd_sig_free_message - Free the memory allocated
+ * @umd_sig: The UMD-parsed signature
+ *
+ * Free the memory allocated for the verification of the UMD-parsed signature.
+ */
+void umd_sig_free_message(struct umd_sig_message *umd_sig)
+{
+	if (!umd_sig)
+		return;
+
+	kfree(umd_sig->sig_data);
+	public_key_signature_free(umd_sig->sig);
+	kfree(umd_sig);
+}
+EXPORT_SYMBOL_GPL(umd_sig_free_message);
diff --git a/include/crypto/umd_sig.h b/include/crypto/umd_sig.h
new file mode 100644
index 00000000000..89b6646a4aa
--- /dev/null
+++ b/include/crypto/umd_sig.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * Header of the UMD asymmetric key signature parser.
+ */
+
+#ifndef _CRYPTO_UMD_SIG_H
+#define _CRYPTO_UMD_SIG_H
+
+#include <linux/verification.h>
+#include <linux/hash_info.h>
+#include <crypto/public_key.h>
+
+struct key;
+struct umd_sig_message;
+
+#ifdef CONFIG_UMD_SIG_PARSER
+extern struct umd_sig_message *umd_sig_parse_message(const u8 *sig_data,
+						     size_t sig_len);
+extern int umd_sig_supply_detached_data(struct umd_sig_message *umd_sig,
+					const void *data, size_t data_len);
+extern int umd_sig_get_content_data(struct umd_sig_message *umd_sig,
+				    const void **_data, size_t *_data_len,
+				    size_t *_headerlen);
+extern int umd_sig_get_digest(struct umd_sig_message *umd_sig, const u8 **buf,
+			      u32 *len, enum hash_algo *hash_algo);
+extern int umd_sig_verify_message(struct umd_sig_message *umd_sig,
+				  struct key *keyring);
+extern void umd_sig_free_message(struct umd_sig_message *umd_sig);
+#else
+static inline struct umd_sig_message *umd_sig_parse_message(const u8 *sig_data,
+							    size_t sig_len)
+{
+	return ERR_PTR(-EOPNOTSUPP);
+}
+
+static inline int umd_sig_supply_detached_data(struct umd_sig_message *umd_sig,
+					       const void *data, size_t data_len)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline int umd_sig_get_content_data(struct umd_sig_message *umd_sig,
+					   const void **_data,
+					   size_t *_data_len,
+					   size_t *_headerlen)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline int umd_sig_get_digest(struct umd_sig_message *umd_sig, const u8 **buf,
+				     u32 *len, enum hash_algo *hash_algo)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline int umd_sig_verify_message(struct umd_sig_message *umd_sig,
+					 struct key *keyring)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline void umd_sig_free_message(struct umd_sig_message *umd_sig)
+{
+}
+
+#endif /* CONFIG_UMD_SIG_PARSER */
+#endif /* _CRYPTO_UMD_SIG_H */
-- 
2.25.1


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

* [RFC][PATCH 3/6] verification: Introduce verify_umd_signature() and verify_umd_message_sig()
  2023-04-25 17:35 [RFC][PATCH 0/6] KEYS: Introduce user mode key and signature parsers Roberto Sassu
  2023-04-25 17:35 ` [RFC][PATCH 1/6] KEYS: asymmetric: Introduce UMD-based asymmetric key parser Roberto Sassu
  2023-04-25 17:35 ` [RFC][PATCH 2/6] KEYS: asymmetric: Introduce UMD-based asymmetric key signature parser Roberto Sassu
@ 2023-04-25 17:35 ` Roberto Sassu
  2023-04-26  0:28   ` Jarkko Sakkinen
  2023-04-25 17:35 ` [RFC][PATCH 4/6] bpf: Introduce bpf_verify_umd_signature() kfunc Roberto Sassu
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: Roberto Sassu @ 2023-04-25 17:35 UTC (permalink / raw)
  To: dhowells, dwmw2, herbert, davem, jarkko, ast, daniel, andrii,
	martin.lau, song, yhs, john.fastabend, kpsingh, sdf, haoluo,
	jolsa, rostedt, mhiramat, mykolal, shuah
  Cc: linux-kernel, keyrings, linux-crypto, bpf, linux-trace-kernel,
	linux-kselftest, Roberto Sassu

From: Roberto Sassu <roberto.sassu@huawei.com>

Introduce verify_umd_signature() and verify_umd_message_sig(), to verify
UMD-parsed signatures from detached data. It aims to be used by kernel
subsystems wishing to verify the authenticity of system data, with
system-defined keyrings as trust anchor.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 certs/system_keyring.c       | 125 +++++++++++++++++++++++++++++++++++
 include/linux/verification.h |  48 ++++++++++++++
 2 files changed, 173 insertions(+)

diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index a7a49b17ceb..d4c0de4dceb 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -16,6 +16,7 @@
 #include <keys/asymmetric-type.h>
 #include <keys/system_keyring.h>
 #include <crypto/pkcs7.h>
+#include <crypto/umd_sig.h>
 
 static struct key *builtin_trusted_keys;
 #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
@@ -339,6 +340,130 @@ int verify_pkcs7_signature(const void *data, size_t len,
 }
 EXPORT_SYMBOL_GPL(verify_pkcs7_signature);
 
+#ifdef CONFIG_UMD_SIG_PARSER
+/**
+ * verify_umd_message_sig - Verify a UMD-parsed signature on system data.
+ * @data: The data to be verified (must be provided)
+ * @len: Size of @data
+ * @umd_sig: The UMD-parsed signature
+ * @trusted_keys: Trusted keys to use (NULL for builtin trusted keys only,
+ *					(void *)1UL for all trusted keys)
+ *					(void *)2UL for platform keys)
+ * @usage: The use to which the key is being put
+ * @view_content: Callback to gain access to content
+ * @ctx: Context for callback
+ *
+ * Verify the UMD-parsed signature of the supplied system data, against a
+ * key (if found) in the supplied trusted keyring.
+ *
+ * Return: Zero on successful verification, a negative value otherwise.
+ */
+int verify_umd_message_sig(const void *data, size_t len,
+			   struct umd_sig_message *umd_sig,
+			   struct key *trusted_keys,
+			   enum key_being_used_for usage,
+			   int (*view_content)(void *ctx,
+					       const void *data, size_t len,
+					       size_t asn1hdrlen),
+			   void *ctx)
+{
+	int ret;
+
+	/* The data should be detached - so we need to supply it. */
+	if (data && umd_sig_supply_detached_data(umd_sig, data, len)) {
+		pr_err("Failed to supply data for UMD-parsed signature\n");
+		ret = -EBADMSG;
+		goto error;
+	}
+
+	if (!trusted_keys) {
+		trusted_keys = builtin_trusted_keys;
+	} else if (trusted_keys == VERIFY_USE_SECONDARY_KEYRING) {
+#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
+		trusted_keys = secondary_trusted_keys;
+#else
+		trusted_keys = builtin_trusted_keys;
+#endif
+	} else if (trusted_keys == VERIFY_USE_PLATFORM_KEYRING) {
+#ifdef CONFIG_INTEGRITY_PLATFORM_KEYRING
+		trusted_keys = platform_trusted_keys;
+#else
+		trusted_keys = NULL;
+#endif
+		if (!trusted_keys) {
+			ret = -ENOKEY;
+			pr_devel("Platform keyring is not available\n");
+			goto error;
+		}
+	}
+
+	ret = umd_sig_verify_message(umd_sig, trusted_keys);
+	if (ret < 0)
+		goto error;
+
+	if (view_content) {
+		size_t sig_data_len;
+
+		ret = umd_sig_get_content_data(umd_sig, &data, &len,
+					       &sig_data_len);
+		if (ret < 0) {
+			if (ret == -ENODATA)
+				pr_devel("UMD-parsed signature does not contain data\n");
+			goto error;
+		}
+
+		ret = view_content(ctx, data, len, sig_data_len);
+		kfree(data);
+	}
+error:
+	pr_devel("<==%s() = %d\n", __func__, ret);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(verify_umd_message_sig);
+
+/**
+ * verify_umd_signature - Verify a UMD-parsed signature on system data.
+ * @data: The data to be verified (must be provided)
+ * @len: Size of @data
+ * @raw_umd_sig: The raw signature to be parsed with UMD
+ * @raw_umd_sig_len: The size of @raw_umd_sig
+ * @trusted_keys: Trusted keys to use (NULL for builtin trusted keys only,
+ *					(void *)1UL for all trusted keys)
+ *					(void *)2UL for platform keys)
+ * @usage: The use to which the key is being put
+ * @view_content: Callback to gain access to content
+ * @ctx: Context for callback
+ *
+ * Verify the UMD-parsed signature of the supplied system data, against a
+ * key (if found) in the supplied trusted keyring.
+ *
+ * Return: Zero on successful verification, a negative value otherwise.
+ */
+int verify_umd_signature(const void *data, size_t len,
+			 const void *raw_umd_sig, size_t raw_umd_sig_len,
+			 struct key *trusted_keys,
+			 enum key_being_used_for usage,
+			 int (*view_content)(void *ctx,
+					     const void *data, size_t len,
+					     size_t asn1hdrlen),
+			 void *ctx)
+{
+	struct umd_sig_message *umd_sig;
+	int ret;
+
+	umd_sig = umd_sig_parse_message(raw_umd_sig, raw_umd_sig_len);
+	if (IS_ERR(umd_sig))
+		return PTR_ERR(umd_sig);
+
+	ret = verify_umd_message_sig(data, len, umd_sig, trusted_keys, usage,
+				     view_content, ctx);
+
+	umd_sig_free_message(umd_sig);
+	pr_devel("<==%s() = %d\n", __func__, ret);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(verify_umd_signature);
+#endif /* CONFIG_UMD_SIG_PARSER */
 #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */
 
 #ifdef CONFIG_INTEGRITY_PLATFORM_KEYRING
diff --git a/include/linux/verification.h b/include/linux/verification.h
index f34e50ebcf6..2e44ea17f23 100644
--- a/include/linux/verification.h
+++ b/include/linux/verification.h
@@ -43,6 +43,7 @@ extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR];
 
 struct key;
 struct pkcs7_message;
+struct umd_sig_message;
 
 extern int verify_pkcs7_signature(const void *data, size_t len,
 				  const void *raw_pkcs7, size_t pkcs7_len,
@@ -62,6 +63,53 @@ extern int verify_pkcs7_message_sig(const void *data, size_t len,
 							size_t asn1hdrlen),
 				    void *ctx);
 
+#ifdef CONFIG_UMD_SIG_PARSER
+extern int verify_umd_message_sig(const void *data, size_t len,
+				  struct umd_sig_message *umd_sig,
+				  struct key *trusted_keys,
+				  enum key_being_used_for usage,
+				  int (*view_content)(void *ctx,
+						      const void *data,
+						      size_t len,
+						      size_t asn1hdrlen),
+				  void *ctx);
+extern int verify_umd_signature(const void *data, size_t len,
+				const void *raw_pgp, size_t pgp_len,
+				struct key *trusted_keys,
+				enum key_being_used_for usage,
+				int (*view_content)(void *ctx,
+						const void *data, size_t len,
+						size_t asn1hdrlen),
+				void *ctx);
+#else
+static inline int verify_umd_message_sig(const void *data, size_t len,
+					 struct umd_sig_message *umd_sig,
+					 struct key *trusted_keys,
+					 enum key_being_used_for usage,
+					 int (*view_content)(void *ctx,
+							     const void *data,
+							     size_t len,
+							     size_t asn1hdrlen),
+					 void *ctx)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline int verify_umd_signature(const void *data, size_t len,
+				       const void *raw_umd_sig,
+				       size_t raw_umd_sig_len,
+				       struct key *trusted_keys,
+				       enum key_being_used_for usage,
+				       int (*view_content)(void *ctx,
+							   const void *data,
+							   size_t len,
+							   size_t asn1hdrlen),
+				       void *ctx)
+{
+	return -EOPNOTSUPP;
+}
+#endif /* CONFIG_UMD_SIG_PARSER */
+
 #ifdef CONFIG_SIGNED_PE_FILE_VERIFICATION
 extern int verify_pefile_signature(const void *pebuf, unsigned pelen,
 				   struct key *trusted_keys,
-- 
2.25.1


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

* [RFC][PATCH 4/6] bpf: Introduce bpf_verify_umd_signature() kfunc
  2023-04-25 17:35 [RFC][PATCH 0/6] KEYS: Introduce user mode key and signature parsers Roberto Sassu
                   ` (2 preceding siblings ...)
  2023-04-25 17:35 ` [RFC][PATCH 3/6] verification: Introduce verify_umd_signature() and verify_umd_message_sig() Roberto Sassu
@ 2023-04-25 17:35 ` Roberto Sassu
  2023-04-25 21:25   ` Yonghong Song
  2023-04-25 17:35 ` [RFC][PATCH 5/6] selftests/bpf: Prepare a test for UMD-parsed signatures Roberto Sassu
  2023-04-25 17:35 ` [RFC][PATCH 6/6] KEYS: asymmetric: Add UMD handler Roberto Sassu
  5 siblings, 1 reply; 13+ messages in thread
From: Roberto Sassu @ 2023-04-25 17:35 UTC (permalink / raw)
  To: dhowells, dwmw2, herbert, davem, jarkko, ast, daniel, andrii,
	martin.lau, song, yhs, john.fastabend, kpsingh, sdf, haoluo,
	jolsa, rostedt, mhiramat, mykolal, shuah
  Cc: linux-kernel, keyrings, linux-crypto, bpf, linux-trace-kernel,
	linux-kselftest, Roberto Sassu

From: Roberto Sassu <roberto.sassu@huawei.com>

Introduce the bpf_verify_umd_signature() kfunc, to verify UMD-parsed
signatures. The parameters and usage are the same as for
bpf_verify_pkcs7_signature().

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 kernel/trace/bpf_trace.c | 69 ++++++++++++++++++++++++++++++++--------
 1 file changed, 55 insertions(+), 14 deletions(-)

diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index e8da032bb6f..c9cae337596 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -1271,7 +1271,7 @@ __bpf_kfunc struct bpf_key *bpf_lookup_user_key(u32 serial, u64 flags)
  * The key pointer is marked as invalid, to prevent bpf_key_put() from
  * attempting to decrement the key reference count on that pointer. The key
  * pointer set in such way is currently understood only by
- * verify_pkcs7_signature().
+ * verify_pkcs7_signature() and verify_umd_signature().
  *
  * Set *id* to one of the values defined in include/linux/verification.h:
  * 0 for the primary keyring (immutable keyring of system keys);
@@ -1317,6 +1317,27 @@ __bpf_kfunc void bpf_key_put(struct bpf_key *bkey)
 }
 
 #ifdef CONFIG_SYSTEM_DATA_VERIFICATION
+static int validate_key(struct bpf_key *trusted_keyring)
+{
+	int ret = 0;
+
+	if (trusted_keyring->has_ref) {
+		/*
+		 * Do the permission check deferred in bpf_lookup_user_key().
+		 * See bpf_lookup_user_key() for more details.
+		 *
+		 * A call to key_task_permission() here would be redundant, as
+		 * it is already done by keyring_search() called by
+		 * find_asymmetric_key().
+		 */
+		ret = key_validate(trusted_keyring->key);
+		if (ret < 0)
+			return ret;
+	}
+
+	return ret;
+}
+
 /**
  * bpf_verify_pkcs7_signature - verify a PKCS#7 signature
  * @data_ptr: data to verify
@@ -1334,19 +1355,9 @@ __bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr_kern *data_ptr,
 {
 	int ret;
 
-	if (trusted_keyring->has_ref) {
-		/*
-		 * Do the permission check deferred in bpf_lookup_user_key().
-		 * See bpf_lookup_user_key() for more details.
-		 *
-		 * A call to key_task_permission() here would be redundant, as
-		 * it is already done by keyring_search() called by
-		 * find_asymmetric_key().
-		 */
-		ret = key_validate(trusted_keyring->key);
-		if (ret < 0)
-			return ret;
-	}
+	ret = validate_key(trusted_keyring);
+	if (ret < 0)
+		return ret;
 
 	return verify_pkcs7_signature(data_ptr->data,
 				      bpf_dynptr_get_size(data_ptr),
@@ -1356,6 +1367,35 @@ __bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr_kern *data_ptr,
 				      VERIFYING_UNSPECIFIED_SIGNATURE, NULL,
 				      NULL);
 }
+
+/**
+ * bpf_verify_umd_signature - Verify a UMD-parsed signature
+ * @data_ptr: Data to verify
+ * @sig_ptr: Signature of the data
+ * @trusted_keyring: Keyring with keys trusted for signature verification
+ *
+ * Verify the UMD-parsed signature *sig_ptr* against the supplied *data_ptr*
+ * with keys in a keyring referenced by *trusted_keyring*.
+ *
+ * Return: 0 on success, a negative value on error.
+ */
+__bpf_kfunc int bpf_verify_umd_signature(struct bpf_dynptr_kern *data_ptr,
+					 struct bpf_dynptr_kern *sig_ptr,
+					 struct bpf_key *trusted_keyring)
+{
+	int ret;
+
+	ret = validate_key(trusted_keyring);
+	if (ret < 0)
+		return ret;
+
+	return verify_umd_signature(data_ptr->data,
+				    bpf_dynptr_get_size(data_ptr),
+				    sig_ptr->data, bpf_dynptr_get_size(sig_ptr),
+				    trusted_keyring->key,
+				    VERIFYING_UNSPECIFIED_SIGNATURE, NULL,
+				    NULL);
+}
 #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */
 
 __diag_pop();
@@ -1366,6 +1406,7 @@ BTF_ID_FLAGS(func, bpf_lookup_system_key, KF_ACQUIRE | KF_RET_NULL)
 BTF_ID_FLAGS(func, bpf_key_put, KF_RELEASE)
 #ifdef CONFIG_SYSTEM_DATA_VERIFICATION
 BTF_ID_FLAGS(func, bpf_verify_pkcs7_signature, KF_SLEEPABLE)
+BTF_ID_FLAGS(func, bpf_verify_umd_signature, KF_SLEEPABLE)
 #endif
 BTF_SET8_END(key_sig_kfunc_set)
 
-- 
2.25.1


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

* [RFC][PATCH 5/6] selftests/bpf: Prepare a test for UMD-parsed signatures
  2023-04-25 17:35 [RFC][PATCH 0/6] KEYS: Introduce user mode key and signature parsers Roberto Sassu
                   ` (3 preceding siblings ...)
  2023-04-25 17:35 ` [RFC][PATCH 4/6] bpf: Introduce bpf_verify_umd_signature() kfunc Roberto Sassu
@ 2023-04-25 17:35 ` Roberto Sassu
  2023-04-25 17:35 ` [RFC][PATCH 6/6] KEYS: asymmetric: Add UMD handler Roberto Sassu
  5 siblings, 0 replies; 13+ messages in thread
From: Roberto Sassu @ 2023-04-25 17:35 UTC (permalink / raw)
  To: dhowells, dwmw2, herbert, davem, jarkko, ast, daniel, andrii,
	martin.lau, song, yhs, john.fastabend, kpsingh, sdf, haoluo,
	jolsa, rostedt, mhiramat, mykolal, shuah
  Cc: linux-kernel, keyrings, linux-crypto, bpf, linux-trace-kernel,
	linux-kselftest, Roberto Sassu

From: Roberto Sassu <roberto.sassu@huawei.com>

Reuse the existing test for PKCS#7 signatures, to test also UMD-parsed
signatures.

Don't enable the test just yet, as the test would fail without a UMD parser
for PGP keys and signatures.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 ...ify_pkcs7_sig.c => verify_pkcs7_umd_sig.c} | 109 ++++++++++++++----
 ...kcs7_sig.c => test_verify_pkcs7_umd_sig.c} |  18 ++-
 .../testing/selftests/bpf/verify_sig_setup.sh |  82 +++++++++++--
 3 files changed, 176 insertions(+), 33 deletions(-)
 rename tools/testing/selftests/bpf/prog_tests/{verify_pkcs7_sig.c => verify_pkcs7_umd_sig.c} (75%)
 rename tools/testing/selftests/bpf/progs/{test_verify_pkcs7_sig.c => test_verify_pkcs7_umd_sig.c} (82%)

diff --git a/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c b/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_umd_sig.c
similarity index 75%
rename from tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c
rename to tools/testing/selftests/bpf/prog_tests/verify_pkcs7_umd_sig.c
index dd7f2bc7004..94d78146989 100644
--- a/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c
+++ b/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_umd_sig.c
@@ -18,7 +18,7 @@
 #include <linux/keyctl.h>
 #include <test_progs.h>
 
-#include "test_verify_pkcs7_sig.skel.h"
+#include "test_verify_pkcs7_umd_sig.skel.h"
 
 #define MAX_DATA_SIZE (1024 * 1024)
 #define MAX_SIG_SIZE 1024
@@ -29,6 +29,24 @@
 /* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
 #define MODULE_SIG_STRING "~Module signature appended~\n"
 
+#define PKEY_ID_PGP 0
+#define PKEY_ID_X509 1
+#define PKEY_ID_PKCS7 2
+
+static char *key_types_str[PKEY_ID_PKCS7 + 1] = {
+	[PKEY_ID_PGP] = "pgp",
+	[PKEY_ID_X509] = "x509",
+	[PKEY_ID_PKCS7] = "pkcs7",
+};
+
+enum algos { ALGO_RSA, ALGO_ECDSA_P256, ALGO_ECDSA_P384, ALGO__LAST };
+
+static char *algos_str[ALGO_ECDSA_P384 + 1] = {
+	[ALGO_RSA] = "rsa",
+	[ALGO_ECDSA_P256] = "ecdsa_p256",
+	[ALGO_ECDSA_P384] = "ecdsa_p384",
+};
+
 /*
  * Module signature information block.
  *
@@ -74,13 +92,15 @@ static int libbpf_print_cb(enum libbpf_print_level level, const char *fmt,
 	return 0;
 }
 
-static int _run_setup_process(const char *setup_dir, const char *cmd)
+static int _run_setup_process(const char *setup_dir, const char *cmd,
+			      __u8 key_type, __u8 pkey_algo)
 {
 	int child_pid, child_status;
 
 	child_pid = fork();
 	if (child_pid == 0) {
-		execlp("./verify_sig_setup.sh", "./verify_sig_setup.sh", cmd,
+		execlp("./verify_sig_setup.sh", "./verify_sig_setup.sh",
+		       cmd, key_types_str[key_type], algos_str[pkey_algo] ?: "",
 		       setup_dir, NULL);
 		exit(errno);
 
@@ -92,7 +112,8 @@ static int _run_setup_process(const char *setup_dir, const char *cmd)
 	return -EINVAL;
 }
 
-static int populate_data_item_str(const char *tmp_dir, struct data *data_item)
+static int populate_data_item_str(const char *tmp_dir, __u8 key_type,
+				  struct data *data_item)
 {
 	struct stat st;
 	char data_template[] = "/tmp/dataXXXXXX";
@@ -123,10 +144,26 @@ static int populate_data_item_str(const char *tmp_dir, struct data *data_item)
 	}
 
 	if (child_pid == 0) {
-		snprintf(path, sizeof(path), "%s/signing_key.pem", tmp_dir);
-
-		return execlp("./sign-file", "./sign-file", "-d", "sha256",
-			      path, path, data_template, NULL);
+		if (key_type == PKEY_ID_PKCS7) {
+			snprintf(path, sizeof(path), "%s/signing_key.pem",
+				 tmp_dir);
+
+			return execlp("./sign-file", "./sign-file", "-d",
+				      "sha256", path, path, data_template,
+				      NULL);
+		} else {
+			snprintf(path, sizeof(path), "%s.gpg", data_template);
+
+			return execlp("gpg", "gpg", "--no-options",
+				      "--no-auto-check-trustdb",
+				      "--no-permission-warning",
+				      "--default-key", "eBPF_UMD_Test",
+				      "--sign", "-o", path, "--batch", "--yes",
+				      "--compress-algo=none", "-b",
+				      "--passphrase", "abc",
+				      "--pinentry-mode", "loopback", "-q",
+				      data_template, NULL);
+		}
 	}
 
 	waitpid(child_pid, &child_status, 0);
@@ -135,7 +172,10 @@ static int populate_data_item_str(const char *tmp_dir, struct data *data_item)
 	if (ret)
 		goto out;
 
-	snprintf(path, sizeof(path), "%s.p7s", data_template);
+	if (key_type == PKEY_ID_PKCS7)
+		snprintf(path, sizeof(path), "%s.p7s", data_template);
+	else
+		snprintf(path, sizeof(path), "%s.gpg", data_template);
 
 	ret = stat(path, &st);
 	if (ret == -1) {
@@ -254,12 +294,12 @@ static int populate_data_item_mod(struct data *data_item)
 	return ret;
 }
 
-void test_verify_pkcs7_sig(void)
+static void test_verify_pkcs7_umd_sig(__u8 key_type, __u8 pkey_algo)
 {
 	libbpf_print_fn_t old_print_cb;
 	char tmp_dir_template[] = "/tmp/verify_sigXXXXXX";
 	char *tmp_dir;
-	struct test_verify_pkcs7_sig *skel = NULL;
+	struct test_verify_pkcs7_umd_sig *skel = NULL;
 	struct bpf_map *map;
 	struct data data;
 	int ret, zero = 0;
@@ -272,37 +312,38 @@ void test_verify_pkcs7_sig(void)
 	if (!ASSERT_OK_PTR(tmp_dir, "mkdtemp"))
 		return;
 
-	ret = _run_setup_process(tmp_dir, "setup");
+	ret = _run_setup_process(tmp_dir, "setup", key_type, pkey_algo);
 	if (!ASSERT_OK(ret, "_run_setup_process"))
 		goto close_prog;
 
-	skel = test_verify_pkcs7_sig__open();
-	if (!ASSERT_OK_PTR(skel, "test_verify_pkcs7_sig__open"))
+	skel = test_verify_pkcs7_umd_sig__open();
+	if (!ASSERT_OK_PTR(skel, "test_verify_pkcs7_umd_sig__open"))
 		goto close_prog;
 
 	old_print_cb = libbpf_set_print(libbpf_print_cb);
-	ret = test_verify_pkcs7_sig__load(skel);
+	ret = test_verify_pkcs7_umd_sig__load(skel);
 	libbpf_set_print(old_print_cb);
 
 	if (ret < 0 && kfunc_not_supported) {
 		printf(
-		  "%s:SKIP:bpf_verify_pkcs7_signature() kfunc not supported\n",
+		  "%s:SKIP:bpf_verify_*_signature() kfunc not supported\n",
 		  __func__);
 		test__skip();
 		goto close_prog;
 	}
 
-	if (!ASSERT_OK(ret, "test_verify_pkcs7_sig__load"))
+	if (!ASSERT_OK(ret, "test_verify_pkcs7_umd_sig__load"))
 		goto close_prog;
 
-	ret = test_verify_pkcs7_sig__attach(skel);
-	if (!ASSERT_OK(ret, "test_verify_pkcs7_sig__attach"))
+	ret = test_verify_pkcs7_umd_sig__attach(skel);
+	if (!ASSERT_OK(ret, "test_verify_pkcs7_umd_sig__attach"))
 		goto close_prog;
 
 	map = bpf_object__find_map_by_name(skel->obj, "data_input");
 	if (!ASSERT_OK_PTR(map, "data_input not found"))
 		goto close_prog;
 
+	skel->bss->key_type = key_type;
 	skel->bss->monitored_pid = getpid();
 
 	/* Test without data and signature. */
@@ -313,7 +354,7 @@ void test_verify_pkcs7_sig(void)
 		goto close_prog;
 
 	/* Test successful signature verification with session keyring. */
-	ret = populate_data_item_str(tmp_dir, &data);
+	ret = populate_data_item_str(tmp_dir, key_type, &data);
 	if (!ASSERT_OK(ret, "populate_data_item_str"))
 		goto close_prog;
 
@@ -363,9 +404,13 @@ void test_verify_pkcs7_sig(void)
 	if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input"))
 		goto close_prog;
 
-	ret = populate_data_item_mod(&data);
-	if (!ASSERT_OK(ret, "populate_data_item_mod"))
-		goto close_prog;
+	data.data_len = 0;
+
+	if (key_type == PKEY_ID_PKCS7) {
+		ret = populate_data_item_mod(&data);
+		if (!ASSERT_OK(ret, "populate_data_item_mod"))
+			goto close_prog;
+	}
 
 	/* Test signature verification with system keyrings. */
 	if (data.data_len) {
@@ -392,11 +437,25 @@ void test_verify_pkcs7_sig(void)
 	}
 
 close_prog:
-	_run_setup_process(tmp_dir, "cleanup");
+	_run_setup_process(tmp_dir, "cleanup", key_type, pkey_algo);
 
 	if (!skel)
 		return;
 
 	skel->bss->monitored_pid = 0;
-	test_verify_pkcs7_sig__destroy(skel);
+	test_verify_pkcs7_umd_sig__destroy(skel);
+}
+
+void test_verify_pkcs7_sig(void)
+{
+	return test_verify_pkcs7_umd_sig(PKEY_ID_PKCS7, ALGO__LAST);
+}
+
+void test_verify_umd_sig(void)
+{
+	int i;
+
+	/* Change the limit to ALGO__LAST when UMD supports PGP. */
+	for (i = 0; i < 0; i++)
+		test_verify_pkcs7_umd_sig(PKEY_ID_PGP, i);
 }
diff --git a/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c b/tools/testing/selftests/bpf/progs/test_verify_pkcs7_umd_sig.c
similarity index 82%
rename from tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c
rename to tools/testing/selftests/bpf/progs/test_verify_pkcs7_umd_sig.c
index 7748cc23de8..e22b013a4e4 100644
--- a/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c
+++ b/tools/testing/selftests/bpf/progs/test_verify_pkcs7_umd_sig.c
@@ -20,10 +20,14 @@ extern void bpf_key_put(struct bpf_key *key) __ksym;
 extern int bpf_verify_pkcs7_signature(struct bpf_dynptr *data_ptr,
 				      struct bpf_dynptr *sig_ptr,
 				      struct bpf_key *trusted_keyring) __ksym;
+extern int bpf_verify_umd_signature(struct bpf_dynptr *data_ptr,
+				    struct bpf_dynptr *sig_ptr,
+				    struct bpf_key *trusted_keyring) __ksym;
 
 __u32 monitored_pid;
 __u32 user_keyring_serial;
 __u64 system_keyring_id;
+__u8 key_type;
 
 struct data {
 	__u8 data[MAX_DATA_SIZE];
@@ -86,7 +90,19 @@ int BPF_PROG(bpf, int cmd, union bpf_attr *attr, unsigned int size)
 	if (!trusted_keyring)
 		return -ENOENT;
 
-	ret = bpf_verify_pkcs7_signature(&data_ptr, &sig_ptr, trusted_keyring);
+	switch (key_type) {
+	case PKEY_ID_PKCS7:
+		ret = bpf_verify_pkcs7_signature(&data_ptr, &sig_ptr,
+						 trusted_keyring);
+		break;
+	case PKEY_ID_PGP:
+		ret = bpf_verify_umd_signature(&data_ptr, &sig_ptr,
+					       trusted_keyring);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
 
 	bpf_key_put(trusted_keyring);
 
diff --git a/tools/testing/selftests/bpf/verify_sig_setup.sh b/tools/testing/selftests/bpf/verify_sig_setup.sh
index ba08922b4a2..5f6e612aae9 100755
--- a/tools/testing/selftests/bpf/verify_sig_setup.sh
+++ b/tools/testing/selftests/bpf/verify_sig_setup.sh
@@ -26,13 +26,39 @@ subjectKeyIdentifier=hash
 authorityKeyIdentifier=keyid
 "
 
+gpg_genkey_content_common="\
+     Name-Real: eBPF_UMD_Test
+     Name-Comment: eBPF_UMD_Test
+     Name-Email: ebpf_umd_test@localhost
+     Expire-Date: 0
+     Passphrase: abc
+     %commit
+"
+gpg_genkey_content_rsa="\
+     Key-Type: RSA
+     Key-Length: 4096
+     $gpg_genkey_content_common
+"
+
+gpg_genkey_content_ecdsa_p256="\
+     Key-Type: ECDSA
+     Key-Curve: NIST P-256
+     $gpg_genkey_content_common
+"
+
+gpg_genkey_content_ecdsa_p384="\
+     Key-Type: ECDSA
+     Key-Curve: NIST P-384
+     $gpg_genkey_content_common
+"
+
 usage()
 {
-	echo "Usage: $0 <setup|cleanup <existing_tmp_dir>"
+	echo "Usage: $0 <setup|cleanup> <key type> <existing_tmp_dir>"
 	exit 1
 }
 
-setup()
+setup_pkcs7()
 {
 	local tmp_dir="$1"
 
@@ -52,11 +78,37 @@ setup()
 	keyctl link $key_id $keyring_id
 }
 
-cleanup() {
+setup_pgp()
+{
+	local tmp_dir="$1"
+	local varname="gpg_genkey_content_$2"
+
+	modprobe ecdsa_generic
+
+	echo "${!varname}" > ${tmp_dir}/gpg.genkey
+	gpg --batch --generate-key ${tmp_dir}/gpg.genkey
+
+	key_id=$(gpg --export eBPF_UMD_Test | keyctl padd asymmetric ebpf_testing_key @s)
+	keyring_id=$(keyctl newring ebpf_testing_keyring @s)
+	keyctl link $key_id $keyring_id
+}
+
+cleanup_pkcs7() {
+	local tmp_dir="$1"
+
+	keyctl unlink $(keyctl search @s asymmetric ebpf_testing_key) @s
+	keyctl unlink $(keyctl search @s keyring ebpf_testing_keyring) @s
+	rm -rf ${tmp_dir}
+}
+
+cleanup_pgp() {
 	local tmp_dir="$1"
 
 	keyctl unlink $(keyctl search @s asymmetric ebpf_testing_key) @s
 	keyctl unlink $(keyctl search @s keyring ebpf_testing_keyring) @s
+	key_fingerprint=$(gpg --fingerprint --with-colons eBPF_UMD_Test | awk -F ":" '$1 == "fpr" {print $(NF-1)}')
+	gpg --delete-secret-key --batch --yes $key_fingerprint
+	gpg --delete-key --batch --yes $key_fingerprint
 	rm -rf ${tmp_dir}
 }
 
@@ -75,17 +127,33 @@ catch()
 
 main()
 {
-	[[ $# -ne 2 ]] && usage
+	[[ $# -ne 4 ]] && usage
 
 	local action="$1"
-	local tmp_dir="$2"
+	local key_type="$2"
+	local key_algo="$3"
+	local tmp_dir="$4"
 
 	[[ ! -d "${tmp_dir}" ]] && echo "Directory ${tmp_dir} doesn't exist" && exit 1
 
 	if [[ "${action}" == "setup" ]]; then
-		setup "${tmp_dir}"
+		if [[ "${key_type}" == "pkcs7" ]]; then
+			setup_pkcs7 "${tmp_dir}"
+		elif [[ "${key_type}" == "pgp" ]]; then
+			setup_pgp "${tmp_dir}" "${key_algo}"
+		else
+			echo "Unknown key type: ${key_type}"
+			exit 1
+		fi
 	elif [[ "${action}" == "cleanup" ]]; then
-		cleanup "${tmp_dir}"
+		if [[ "${key_type}" == "pkcs7" ]]; then
+			cleanup_pkcs7 "${tmp_dir}"
+		elif [[ "${key_type}" == "pgp" ]]; then
+			cleanup_pgp "${tmp_dir}"
+		else
+			echo "Unknown key type: ${key_type}"
+			exit 1
+		fi
 	else
 		echo "Unknown action: ${action}"
 		exit 1
-- 
2.25.1


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

* [RFC][PATCH 6/6] KEYS: asymmetric: Add UMD handler
  2023-04-25 17:35 [RFC][PATCH 0/6] KEYS: Introduce user mode key and signature parsers Roberto Sassu
                   ` (4 preceding siblings ...)
  2023-04-25 17:35 ` [RFC][PATCH 5/6] selftests/bpf: Prepare a test for UMD-parsed signatures Roberto Sassu
@ 2023-04-25 17:35 ` Roberto Sassu
  5 siblings, 0 replies; 13+ messages in thread
From: Roberto Sassu @ 2023-04-25 17:35 UTC (permalink / raw)
  To: dhowells, dwmw2, herbert, davem, jarkko, ast, daniel, andrii,
	martin.lau, song, yhs, john.fastabend, kpsingh, sdf, haoluo,
	jolsa, rostedt, mhiramat, mykolal, shuah
  Cc: linux-kernel, keyrings, linux-crypto, bpf, linux-trace-kernel,
	linux-kselftest, Roberto Sassu

From: Roberto Sassu <roberto.sassu@huawei.com>

Introduce the skeleton of the UMD handler, complete enough to talk with
the new key and signature parsers in the kernel.

Commands to parse keys and signatures are not implemented.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 .gitignore                                    |  3 +
 crypto/asymmetric_keys/Kconfig                | 10 +++
 crypto/asymmetric_keys/Makefile               | 13 +++
 crypto/asymmetric_keys/umd_key_sig_loader.c   | 32 +++++++
 crypto/asymmetric_keys/umd_key_sig_umh_blob.S |  7 ++
 crypto/asymmetric_keys/umd_key_sig_umh_user.c | 84 +++++++++++++++++++
 6 files changed, 149 insertions(+)
 create mode 100644 crypto/asymmetric_keys/umd_key_sig_loader.c
 create mode 100644 crypto/asymmetric_keys/umd_key_sig_umh_blob.S
 create mode 100644 crypto/asymmetric_keys/umd_key_sig_umh_user.c

diff --git a/.gitignore b/.gitignore
index 7f86e083790..f14e42b7273 100644
--- a/.gitignore
+++ b/.gitignore
@@ -174,3 +174,6 @@ sphinx_*/
 
 # Rust analyzer configuration
 /rust-project.json
+
+# User mode driver for asymmetric keys and signatures
+/crypto/asymmetric_keys/umd_key_sig_umh
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
index d312feae88e..4b53667d209 100644
--- a/crypto/asymmetric_keys/Kconfig
+++ b/crypto/asymmetric_keys/Kconfig
@@ -107,4 +107,14 @@ config UMD_SIG_PARSER
 	  On success, the parser fills the signature from the UMD handler
 	  response.
 
+config UMD_KEY_SIG_HANDLER
+	tristate "UMD handler for asymmetric keys and signatures"
+	depends on UMD_KEY_PARSER
+	help
+	  This option introduces a UMD handler to parse data received from
+	  the key and signature kernel parsers.
+
+	  It includes just the basic program structure, to be enhanced with
+	  actual parsers.
+
 endif # ASYMMETRIC_KEY_TYPE
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
index 060c699fbb2..d870cc04fcf 100644
--- a/crypto/asymmetric_keys/Makefile
+++ b/crypto/asymmetric_keys/Makefile
@@ -86,3 +86,16 @@ obj-$(CONFIG_UMD_KEY_PARSER) += umd_key_parser.o
 # UMD signature parser
 #
 obj-$(CONFIG_UMD_SIG_PARSER) += umd_sig_parser.o
+
+#
+# UMD handler for asymmetric keys and signatures
+#
+CC=klcc
+userprogs := umd_key_sig_umh
+umd_key_sig_umh-objs := umd_key_sig_umh_user.o
+userldflags += -static
+
+$(obj)/umd_key_sig_umh_blob.o: $(obj)/umd_key_sig_umh
+
+obj-$(CONFIG_UMD_KEY_SIG_HANDLER) += umd_key_sig_user.o
+umd_key_sig_user-objs += umd_key_sig_loader.o umd_key_sig_umh_blob.o
diff --git a/crypto/asymmetric_keys/umd_key_sig_loader.c b/crypto/asymmetric_keys/umd_key_sig_loader.c
new file mode 100644
index 00000000000..b959a42b9fd
--- /dev/null
+++ b/crypto/asymmetric_keys/umd_key_sig_loader.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * Implement the loader of the UMD handler.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "umd_key.h"
+
+extern char umd_key_umh_start;
+extern char umd_key_umh_end;
+
+MODULE_LICENSE("GPL");
+
+static int __init umd_key_umh_init(void)
+{
+	return umd_mgmt_load(&key_ops, &umd_key_umh_start, &umd_key_umh_end);
+}
+
+static void __exit umd_key_umh_exit(void)
+{
+	umd_mgmt_unload(&key_ops);
+}
+
+module_init(umd_key_umh_init);
+module_exit(umd_key_umh_exit);
diff --git a/crypto/asymmetric_keys/umd_key_sig_umh_blob.S b/crypto/asymmetric_keys/umd_key_sig_umh_blob.S
new file mode 100644
index 00000000000..954cbe891bd
--- /dev/null
+++ b/crypto/asymmetric_keys/umd_key_sig_umh_blob.S
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+	.section .init.rodata, "a"
+	.global umd_key_umh_start
+umd_key_umh_start:
+	.incbin "crypto/asymmetric_keys/umd_key_sig_umh"
+	.global umd_key_umh_end
+umd_key_umh_end:
diff --git a/crypto/asymmetric_keys/umd_key_sig_umh_user.c b/crypto/asymmetric_keys/umd_key_sig_umh_user.c
new file mode 100644
index 00000000000..21f53008762
--- /dev/null
+++ b/crypto/asymmetric_keys/umd_key_sig_umh_user.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * Implement the UMD handler.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "umd_key_sig_umh.h"
+
+FILE *debug_f;
+
+int main(int argc, char *argv[])
+{
+	struct msg_in *in = NULL;
+	struct msg_out *out = NULL;
+	size_t in_len, out_len;
+	loff_t pos;
+	int ret = 0;
+
+#ifdef debug
+	debug_f = fopen("/dev/kmsg", "a");
+	fprintf(debug_f, "<5>Started %s\n", argv[0]);
+	fflush(debug_f);
+#endif
+	in = malloc(sizeof(*in));
+	if (!in)
+		goto out;
+
+	out = malloc(sizeof(*out));
+	if (!out)
+		goto out;
+
+	while (1) {
+		int n;
+
+		in_len = sizeof(*in);
+		out_len = sizeof(*out);
+
+		memset(in, 0, in_len);
+		memset(out, 0, out_len);
+
+		pos = 0;
+		while (in_len) {
+			n = read(0, (void *)in + pos, in_len);
+			if (n <= 0) {
+				ret = -EIO;
+				goto out;
+			}
+			in_len -= n;
+			pos += n;
+		}
+
+		switch (in->cmd) {
+		default:
+			out->ret = -EOPNOTSUPP;
+			break;
+		}
+
+		pos = 0;
+		while (out_len) {
+			n = write(1, (void *)out + pos, out_len);
+			if (n <= 0) {
+				ret = -EIO;
+				goto out;
+			}
+			out_len -= n;
+			pos += n;
+		}
+	}
+out:
+	free(in);
+	free(out);
+#ifdef debug
+	fclose(debug_f);
+#endif
+	return ret;
+}
-- 
2.25.1


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

* Re: [RFC][PATCH 4/6] bpf: Introduce bpf_verify_umd_signature() kfunc
  2023-04-25 17:35 ` [RFC][PATCH 4/6] bpf: Introduce bpf_verify_umd_signature() kfunc Roberto Sassu
@ 2023-04-25 21:25   ` Yonghong Song
  2023-04-26 11:44     ` Roberto Sassu
  0 siblings, 1 reply; 13+ messages in thread
From: Yonghong Song @ 2023-04-25 21:25 UTC (permalink / raw)
  To: Roberto Sassu, dhowells, dwmw2, herbert, davem, jarkko, ast,
	daniel, andrii, martin.lau, song, yhs, john.fastabend, kpsingh,
	sdf, haoluo, jolsa, rostedt, mhiramat, mykolal, shuah
  Cc: linux-kernel, keyrings, linux-crypto, bpf, linux-trace-kernel,
	linux-kselftest, Roberto Sassu



On 4/25/23 10:35 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
> 
> Introduce the bpf_verify_umd_signature() kfunc, to verify UMD-parsed
> signatures. The parameters and usage are the same as for
> bpf_verify_pkcs7_signature().
> 
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> ---
>   kernel/trace/bpf_trace.c | 69 ++++++++++++++++++++++++++++++++--------
>   1 file changed, 55 insertions(+), 14 deletions(-)
> 
> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
> index e8da032bb6f..c9cae337596 100644
> --- a/kernel/trace/bpf_trace.c
> +++ b/kernel/trace/bpf_trace.c
> @@ -1271,7 +1271,7 @@ __bpf_kfunc struct bpf_key *bpf_lookup_user_key(u32 serial, u64 flags)
>    * The key pointer is marked as invalid, to prevent bpf_key_put() from
>    * attempting to decrement the key reference count on that pointer. The key
>    * pointer set in such way is currently understood only by
> - * verify_pkcs7_signature().
> + * verify_pkcs7_signature() and verify_umd_signature().
>    *
>    * Set *id* to one of the values defined in include/linux/verification.h:
>    * 0 for the primary keyring (immutable keyring of system keys);
> @@ -1317,6 +1317,27 @@ __bpf_kfunc void bpf_key_put(struct bpf_key *bkey)
>   }
>   
>   #ifdef CONFIG_SYSTEM_DATA_VERIFICATION
> +static int validate_key(struct bpf_key *trusted_keyring)
> +{
> +	int ret = 0;
> +
> +	if (trusted_keyring->has_ref) {
> +		/*
> +		 * Do the permission check deferred in bpf_lookup_user_key().
> +		 * See bpf_lookup_user_key() for more details.
> +		 *
> +		 * A call to key_task_permission() here would be redundant, as
> +		 * it is already done by keyring_search() called by
> +		 * find_asymmetric_key().
> +		 */
> +		ret = key_validate(trusted_keyring->key);
> +		if (ret < 0)
> +			return ret;

The above
	if (ret < 0)
		return ret;
can be removed.

> +	}
> +
> +	return ret;
> +}
> +
>   /**
>    * bpf_verify_pkcs7_signature - verify a PKCS#7 signature
>    * @data_ptr: data to verify
> @@ -1334,19 +1355,9 @@ __bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr_kern *data_ptr,
>   {
>   	int ret;
>   
> -	if (trusted_keyring->has_ref) {
> -		/*
> -		 * Do the permission check deferred in bpf_lookup_user_key().
> -		 * See bpf_lookup_user_key() for more details.
> -		 *
> -		 * A call to key_task_permission() here would be redundant, as
> -		 * it is already done by keyring_search() called by
> -		 * find_asymmetric_key().
> -		 */
> -		ret = key_validate(trusted_keyring->key);
> -		if (ret < 0)
> -			return ret;
> -	}
> +	ret = validate_key(trusted_keyring);
> +	if (ret < 0)
> +		return ret;
>   
>   	return verify_pkcs7_signature(data_ptr->data,
>   				      bpf_dynptr_get_size(data_ptr),
> @@ -1356,6 +1367,35 @@ __bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr_kern *data_ptr,
>   				      VERIFYING_UNSPECIFIED_SIGNATURE, NULL,
>   				      NULL);
>   }
> +
> +/**
> + * bpf_verify_umd_signature - Verify a UMD-parsed signature
> + * @data_ptr: Data to verify
> + * @sig_ptr: Signature of the data
> + * @trusted_keyring: Keyring with keys trusted for signature verification
> + *
> + * Verify the UMD-parsed signature *sig_ptr* against the supplied *data_ptr*
> + * with keys in a keyring referenced by *trusted_keyring*.
> + *
> + * Return: 0 on success, a negative value on error.
> + */
> +__bpf_kfunc int bpf_verify_umd_signature(struct bpf_dynptr_kern *data_ptr,
> +					 struct bpf_dynptr_kern *sig_ptr,
> +					 struct bpf_key *trusted_keyring)
> +{
> +	int ret;
> +
> +	ret = validate_key(trusted_keyring);
> +	if (ret < 0)
> +		return ret;
> +
> +	return verify_umd_signature(data_ptr->data,
> +				    bpf_dynptr_get_size(data_ptr),
> +				    sig_ptr->data, bpf_dynptr_get_size(sig_ptr),
> +				    trusted_keyring->key,
> +				    VERIFYING_UNSPECIFIED_SIGNATURE, NULL,
> +				    NULL);
> +}
>   #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */
>   
>   __diag_pop();
> @@ -1366,6 +1406,7 @@ BTF_ID_FLAGS(func, bpf_lookup_system_key, KF_ACQUIRE | KF_RET_NULL)
>   BTF_ID_FLAGS(func, bpf_key_put, KF_RELEASE)
>   #ifdef CONFIG_SYSTEM_DATA_VERIFICATION
>   BTF_ID_FLAGS(func, bpf_verify_pkcs7_signature, KF_SLEEPABLE)
> +BTF_ID_FLAGS(func, bpf_verify_umd_signature, KF_SLEEPABLE)
>   #endif
>   BTF_SET8_END(key_sig_kfunc_set)
>   

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

* Re: [RFC][PATCH 3/6] verification: Introduce verify_umd_signature() and verify_umd_message_sig()
  2023-04-25 17:35 ` [RFC][PATCH 3/6] verification: Introduce verify_umd_signature() and verify_umd_message_sig() Roberto Sassu
@ 2023-04-26  0:28   ` Jarkko Sakkinen
  2023-04-26 11:42     ` Roberto Sassu
  0 siblings, 1 reply; 13+ messages in thread
From: Jarkko Sakkinen @ 2023-04-26  0:28 UTC (permalink / raw)
  To: Roberto Sassu, dhowells, dwmw2, herbert, davem, ast, daniel,
	andrii, martin.lau, song, yhs, john.fastabend, kpsingh, sdf,
	haoluo, jolsa, rostedt, mhiramat, mykolal, shuah
  Cc: linux-kernel, keyrings, linux-crypto, bpf, linux-trace-kernel,
	linux-kselftest, Roberto Sassu

On Tue Apr 25, 2023 at 8:35 PM EEST, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Introduce verify_umd_signature() and verify_umd_message_sig(), to verify
> UMD-parsed signatures from detached data. It aims to be used by kernel
> subsystems wishing to verify the authenticity of system data, with
> system-defined keyrings as trust anchor.

UMD is not generic knowledge. It is a term coined up in this patch set
so please open code it to each patch.

One discussion points should be what these handlers should be called.
Right now the patch set is misleads the reader to think as this was
some kind of "official" term and set to stone.

BR, Jarkko

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

* Re: [RFC][PATCH 3/6] verification: Introduce verify_umd_signature() and verify_umd_message_sig()
  2023-04-26  0:28   ` Jarkko Sakkinen
@ 2023-04-26 11:42     ` Roberto Sassu
  2023-04-26 18:25       ` Jarkko Sakkinen
  0 siblings, 1 reply; 13+ messages in thread
From: Roberto Sassu @ 2023-04-26 11:42 UTC (permalink / raw)
  To: Jarkko Sakkinen, dhowells, dwmw2, herbert, davem, ast, daniel,
	andrii, martin.lau, song, yhs, john.fastabend, kpsingh, sdf,
	haoluo, jolsa, rostedt, mhiramat, mykolal, shuah
  Cc: linux-kernel, keyrings, linux-crypto, bpf, linux-trace-kernel,
	linux-kselftest, Roberto Sassu

On Wed, 2023-04-26 at 03:28 +0300, Jarkko Sakkinen wrote:
> On Tue Apr 25, 2023 at 8:35 PM EEST, Roberto Sassu wrote:
> > From: Roberto Sassu <roberto.sassu@huawei.com>
> > 
> > Introduce verify_umd_signature() and verify_umd_message_sig(), to verify
> > UMD-parsed signatures from detached data. It aims to be used by kernel
> > subsystems wishing to verify the authenticity of system data, with
> > system-defined keyrings as trust anchor.
> 
> UMD is not generic knowledge. It is a term coined up in this patch set
> so please open code it to each patch.

Yes, Linus also commented on this:

https://lwn.net/ml/linux-kernel/CAHk-=wihqhksXHkcjuTrYmC-vajeRcNh3s6eeoJNxS7wp77dFQ@mail.gmail.com/

I will check if the full name is mentioned at least once. So far, it
seems that using umd for function names should be ok.

> One discussion points should be what these handlers should be called.
> Right now the patch set is misleads the reader to think as this was
> some kind of "official" term and set to stone.

I proposed some naming here (dependency of this patch set):

https://lore.kernel.org/bpf/20230317145240.363908-6-roberto.sassu@huaweicloud.com/

Please let me know if it sounds reasonable to you.

Thanks

Roberto


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

* Re: [RFC][PATCH 4/6] bpf: Introduce bpf_verify_umd_signature() kfunc
  2023-04-25 21:25   ` Yonghong Song
@ 2023-04-26 11:44     ` Roberto Sassu
  0 siblings, 0 replies; 13+ messages in thread
From: Roberto Sassu @ 2023-04-26 11:44 UTC (permalink / raw)
  To: Yonghong Song, dhowells, dwmw2, herbert, davem, jarkko, ast,
	daniel, andrii, martin.lau, song, yhs, john.fastabend, kpsingh,
	sdf, haoluo, jolsa, rostedt, mhiramat, mykolal, shuah
  Cc: linux-kernel, keyrings, linux-crypto, bpf, linux-trace-kernel,
	linux-kselftest, Roberto Sassu

On Tue, 2023-04-25 at 14:25 -0700, Yonghong Song wrote:
> 
> On 4/25/23 10:35 AM, Roberto Sassu wrote:
> > From: Roberto Sassu <roberto.sassu@huawei.com>
> > 
> > Introduce the bpf_verify_umd_signature() kfunc, to verify UMD-parsed
> > signatures. The parameters and usage are the same as for
> > bpf_verify_pkcs7_signature().
> > 
> > Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> > ---
> >   kernel/trace/bpf_trace.c | 69 ++++++++++++++++++++++++++++++++--------
> >   1 file changed, 55 insertions(+), 14 deletions(-)
> > 
> > diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
> > index e8da032bb6f..c9cae337596 100644
> > --- a/kernel/trace/bpf_trace.c
> > +++ b/kernel/trace/bpf_trace.c
> > @@ -1271,7 +1271,7 @@ __bpf_kfunc struct bpf_key *bpf_lookup_user_key(u32 serial, u64 flags)
> >    * The key pointer is marked as invalid, to prevent bpf_key_put() from
> >    * attempting to decrement the key reference count on that pointer. The key
> >    * pointer set in such way is currently understood only by
> > - * verify_pkcs7_signature().
> > + * verify_pkcs7_signature() and verify_umd_signature().
> >    *
> >    * Set *id* to one of the values defined in include/linux/verification.h:
> >    * 0 for the primary keyring (immutable keyring of system keys);
> > @@ -1317,6 +1317,27 @@ __bpf_kfunc void bpf_key_put(struct bpf_key *bkey)
> >   }
> >   
> >   #ifdef CONFIG_SYSTEM_DATA_VERIFICATION
> > +static int validate_key(struct bpf_key *trusted_keyring)
> > +{
> > +	int ret = 0;
> > +
> > +	if (trusted_keyring->has_ref) {
> > +		/*
> > +		 * Do the permission check deferred in bpf_lookup_user_key().
> > +		 * See bpf_lookup_user_key() for more details.
> > +		 *
> > +		 * A call to key_task_permission() here would be redundant, as
> > +		 * it is already done by keyring_search() called by
> > +		 * find_asymmetric_key().
> > +		 */
> > +		ret = key_validate(trusted_keyring->key);
> > +		if (ret < 0)
> > +			return ret;
> 
> The above
> 	if (ret < 0)
> 		return ret;
> can be removed.

Right, thanks!

Roberto

> > +	}
> > +
> > +	return ret;
> > +}
> > +
> >   /**
> >    * bpf_verify_pkcs7_signature - verify a PKCS#7 signature
> >    * @data_ptr: data to verify
> > @@ -1334,19 +1355,9 @@ __bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr_kern *data_ptr,
> >   {
> >   	int ret;
> >   
> > -	if (trusted_keyring->has_ref) {
> > -		/*
> > -		 * Do the permission check deferred in bpf_lookup_user_key().
> > -		 * See bpf_lookup_user_key() for more details.
> > -		 *
> > -		 * A call to key_task_permission() here would be redundant, as
> > -		 * it is already done by keyring_search() called by
> > -		 * find_asymmetric_key().
> > -		 */
> > -		ret = key_validate(trusted_keyring->key);
> > -		if (ret < 0)
> > -			return ret;
> > -	}
> > +	ret = validate_key(trusted_keyring);
> > +	if (ret < 0)
> > +		return ret;
> >   
> >   	return verify_pkcs7_signature(data_ptr->data,
> >   				      bpf_dynptr_get_size(data_ptr),
> > @@ -1356,6 +1367,35 @@ __bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr_kern *data_ptr,
> >   				      VERIFYING_UNSPECIFIED_SIGNATURE, NULL,
> >   				      NULL);
> >   }
> > +
> > +/**
> > + * bpf_verify_umd_signature - Verify a UMD-parsed signature
> > + * @data_ptr: Data to verify
> > + * @sig_ptr: Signature of the data
> > + * @trusted_keyring: Keyring with keys trusted for signature verification
> > + *
> > + * Verify the UMD-parsed signature *sig_ptr* against the supplied *data_ptr*
> > + * with keys in a keyring referenced by *trusted_keyring*.
> > + *
> > + * Return: 0 on success, a negative value on error.
> > + */
> > +__bpf_kfunc int bpf_verify_umd_signature(struct bpf_dynptr_kern *data_ptr,
> > +					 struct bpf_dynptr_kern *sig_ptr,
> > +					 struct bpf_key *trusted_keyring)
> > +{
> > +	int ret;
> > +
> > +	ret = validate_key(trusted_keyring);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	return verify_umd_signature(data_ptr->data,
> > +				    bpf_dynptr_get_size(data_ptr),
> > +				    sig_ptr->data, bpf_dynptr_get_size(sig_ptr),
> > +				    trusted_keyring->key,
> > +				    VERIFYING_UNSPECIFIED_SIGNATURE, NULL,
> > +				    NULL);
> > +}
> >   #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */
> >   
> >   __diag_pop();
> > @@ -1366,6 +1406,7 @@ BTF_ID_FLAGS(func, bpf_lookup_system_key, KF_ACQUIRE | KF_RET_NULL)
> >   BTF_ID_FLAGS(func, bpf_key_put, KF_RELEASE)
> >   #ifdef CONFIG_SYSTEM_DATA_VERIFICATION
> >   BTF_ID_FLAGS(func, bpf_verify_pkcs7_signature, KF_SLEEPABLE)
> > +BTF_ID_FLAGS(func, bpf_verify_umd_signature, KF_SLEEPABLE)
> >   #endif
> >   BTF_SET8_END(key_sig_kfunc_set)
> >   


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

* Re: [RFC][PATCH 3/6] verification: Introduce verify_umd_signature() and verify_umd_message_sig()
  2023-04-26 11:42     ` Roberto Sassu
@ 2023-04-26 18:25       ` Jarkko Sakkinen
  2023-04-26 18:27         ` Jarkko Sakkinen
  0 siblings, 1 reply; 13+ messages in thread
From: Jarkko Sakkinen @ 2023-04-26 18:25 UTC (permalink / raw)
  To: Roberto Sassu, dhowells, dwmw2, herbert, davem, ast, daniel,
	andrii, martin.lau, song, yhs, john.fastabend, kpsingh, sdf,
	haoluo, jolsa, rostedt, mhiramat, mykolal, shuah
  Cc: linux-kernel, keyrings, linux-crypto, bpf, linux-trace-kernel,
	linux-kselftest, Roberto Sassu

On Wed, 2023-04-26 at 13:42 +0200, Roberto Sassu wrote:
> On Wed, 2023-04-26 at 03:28 +0300, Jarkko Sakkinen wrote:
> > On Tue Apr 25, 2023 at 8:35 PM EEST, Roberto Sassu wrote:
> > > From: Roberto Sassu <roberto.sassu@huawei.com>
> > > 
> > > Introduce verify_umd_signature() and verify_umd_message_sig(), to verify
> > > UMD-parsed signatures from detached data. It aims to be used by kernel
> > > subsystems wishing to verify the authenticity of system data, with
> > > system-defined keyrings as trust anchor.
> > 
> > UMD is not generic knowledge. It is a term coined up in this patch set
> > so please open code it to each patch.
> 
> Yes, Linus also commented on this:
> 
> https://lwn.net/ml/linux-kernel/CAHk-=wihqhksXHkcjuTrYmC-vajeRcNh3s6eeoJNxS7wp77dFQ@mail.gmail.com/
> 
> I will check if the full name is mentioned at least once. So far, it
> seems that using umd for function names should be ok.

Also: "UMD-based parser for the asymmetric key type"

It is a tautology:

UMD is based on parser which based on UMD.

I.e. makes no sense.

Everyone hates three letter acronyms so I would consider not
inventing a new one out of the void.

So the corrective step would be to rename Kconfig flags as
USER_ASYMMETRIC_KEY_PARSER and USER_ASYMMETRIC_SIGNATURE_PARSER.

BR, Jarkko



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

* Re: [RFC][PATCH 3/6] verification: Introduce verify_umd_signature() and verify_umd_message_sig()
  2023-04-26 18:25       ` Jarkko Sakkinen
@ 2023-04-26 18:27         ` Jarkko Sakkinen
  0 siblings, 0 replies; 13+ messages in thread
From: Jarkko Sakkinen @ 2023-04-26 18:27 UTC (permalink / raw)
  To: Roberto Sassu, dhowells, dwmw2, herbert, davem, ast, daniel,
	andrii, martin.lau, song, yhs, john.fastabend, kpsingh, sdf,
	haoluo, jolsa, rostedt, mhiramat, mykolal, shuah
  Cc: linux-kernel, keyrings, linux-crypto, bpf, linux-trace-kernel,
	linux-kselftest, Roberto Sassu

On Wed, 2023-04-26 at 21:25 +0300, Jarkko Sakkinen wrote:
> On Wed, 2023-04-26 at 13:42 +0200, Roberto Sassu wrote:
> > On Wed, 2023-04-26 at 03:28 +0300, Jarkko Sakkinen wrote:
> > > On Tue Apr 25, 2023 at 8:35 PM EEST, Roberto Sassu wrote:
> > > > From: Roberto Sassu <roberto.sassu@huawei.com>
> > > > 
> > > > Introduce verify_umd_signature() and verify_umd_message_sig(), to verify
> > > > UMD-parsed signatures from detached data. It aims to be used by kernel
> > > > subsystems wishing to verify the authenticity of system data, with
> > > > system-defined keyrings as trust anchor.
> > > 
> > > UMD is not generic knowledge. It is a term coined up in this patch set
> > > so please open code it to each patch.
> > 
> > Yes, Linus also commented on this:
> > 
> > https://lwn.net/ml/linux-kernel/CAHk-=wihqhksXHkcjuTrYmC-vajeRcNh3s6eeoJNxS7wp77dFQ@mail.gmail.com/
> > 
> > I will check if the full name is mentioned at least once. So far, it
> > seems that using umd for function names should be ok.
> 
> Also: "UMD-based parser for the asymmetric key type"
> 
> It is a tautology:
> 
> UMD is based on parser which based on UMD.
> 
> I.e. makes no sense.
> 
> Everyone hates three letter acronyms so I would consider not
> inventing a new one out of the void.
> 
> So the corrective step would be to rename Kconfig flags as
> USER_ASYMMETRIC_KEY_PARSER and USER_ASYMMETRIC_SIGNATURE_PARSER.

(or along the lines)

BR, Jarkko

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

end of thread, other threads:[~2023-04-26 18:27 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-04-25 17:35 [RFC][PATCH 0/6] KEYS: Introduce user mode key and signature parsers Roberto Sassu
2023-04-25 17:35 ` [RFC][PATCH 1/6] KEYS: asymmetric: Introduce UMD-based asymmetric key parser Roberto Sassu
2023-04-25 17:35 ` [RFC][PATCH 2/6] KEYS: asymmetric: Introduce UMD-based asymmetric key signature parser Roberto Sassu
2023-04-25 17:35 ` [RFC][PATCH 3/6] verification: Introduce verify_umd_signature() and verify_umd_message_sig() Roberto Sassu
2023-04-26  0:28   ` Jarkko Sakkinen
2023-04-26 11:42     ` Roberto Sassu
2023-04-26 18:25       ` Jarkko Sakkinen
2023-04-26 18:27         ` Jarkko Sakkinen
2023-04-25 17:35 ` [RFC][PATCH 4/6] bpf: Introduce bpf_verify_umd_signature() kfunc Roberto Sassu
2023-04-25 21:25   ` Yonghong Song
2023-04-26 11:44     ` Roberto Sassu
2023-04-25 17:35 ` [RFC][PATCH 5/6] selftests/bpf: Prepare a test for UMD-parsed signatures Roberto Sassu
2023-04-25 17:35 ` [RFC][PATCH 6/6] KEYS: asymmetric: Add UMD handler Roberto Sassu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).