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