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)
 {
