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 */
