Limit the set of crypto combinations that may be used for module signing as
no indication of hash algorithm used for signing is added to the hash of
the data, so in theory a data blob hashed with a different algorithm can be
substituted provided it has the same hash output.
This also rejects the use of less secure algorithms.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Stephan Mueller <smueller@chronox.de>
cc: Eric Biggers <ebiggers@kernel.org>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
crypto/asymmetric_keys/public_key.c | 55 +++++++++++++++++++++++++++--
1 file changed, 53 insertions(+), 2 deletions(-)
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index 13a5616becaa..90b98e1a952d 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -24,6 +24,52 @@ MODULE_DESCRIPTION("In-software asymmetric public-key subtype");
MODULE_AUTHOR("Red Hat, Inc.");
MODULE_LICENSE("GPL");
+struct public_key_restriction {
+ const char *pkey_algo; /* Signing algorithm (e.g. "rsa") */
+ const char *pkey_enc; /* Signature encoding (e.g. "pkcs1") */
+ const char *hash_algo; /* Content hash algorithm (e.g. "sha256") */
+};
+
+static const struct public_key_restriction public_key_restrictions[] = {
+ /* algo encoding hash */
+ { "rsa", "pkcs1", "sha256" },
+ { "rsa", "pkcs1", "sha384" },
+ { "rsa", "pkcs1", "sha512" },
+ { "rsa", "emsa-pss", "sha512" },
+ { "ecdsa", "x962", "sha256" },
+ { "ecdsa", "x962", "sha384" },
+ { "ecdsa", "x962", "sha512" },
+ { "ecrdsa", "raw", "sha256" },
+ { "ecrdsa", "raw", "sha384" },
+ { "ecrdsa", "raw", "sha512" },
+ { "mldsa44", "raw", "sha512" },
+ { "mldsa65", "raw", "sha512" },
+ { "mldsa87", "raw", "sha512" },
+ /* ML-DSA may also do its own hashing over the entire message. */
+ { "mldsa44", "raw", "-" },
+ { "mldsa65", "raw", "-" },
+ { "mldsa87", "raw", "-" },
+};
+
+/*
+ * Determine if a particular key/hash combination is allowed.
+ */
+static int is_public_key_sig_allowed(const struct public_key_signature *sig)
+{
+ for (int i = 0; i < ARRAY_SIZE(public_key_restrictions); i++) {
+ if (strcmp(public_key_restrictions[i].pkey_algo, sig->pkey_algo) != 0)
+ continue;
+ if (strcmp(public_key_restrictions[i].pkey_enc, sig->encoding) != 0)
+ continue;
+ if (strcmp(public_key_restrictions[i].hash_algo, sig->hash_algo) != 0)
+ continue;
+ return 0;
+ }
+ pr_warn_once("Public key signature combo (%s,%s,%s) rejected\n",
+ sig->pkey_algo, sig->encoding, sig->hash_algo);
+ return -EKEYREJECTED;
+}
+
/*
* Provide a part of a description of the key for /proc/keys.
*/
@@ -391,12 +437,17 @@ int public_key_verify_signature(const struct public_key *pkey,
bool issig;
int ret;
- pr_devel("==>%s()\n", __func__);
-
BUG_ON(!pkey);
BUG_ON(!sig);
BUG_ON(!sig->s);
+ ret = is_public_key_sig_allowed(sig);
+ if (ret < 0)
+ return ret;
+
+ pr_devel("==>%s(%s,%s,%s)\n",
+ __func__, sig->pkey_algo, sig->encoding, sig->hash_algo);
+
/*
* If the signature specifies a public key algorithm, it *must* match
* the key's actual public key algorithm.
On Tue, Jan 20, 2026 at 02:50:57PM +0000, David Howells wrote:
> Limit the set of crypto combinations that may be used for module signing as
> no indication of hash algorithm used for signing is added to the hash of
> the data, so in theory a data blob hashed with a different algorithm can be
> substituted provided it has the same hash output.
>
> This also rejects the use of less secure algorithms.
>
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Lukas Wunner <lukas@wunner.de>
> cc: Ignat Korchagin <ignat@cloudflare.com>
> cc: Stephan Mueller <smueller@chronox.de>
> cc: Eric Biggers <ebiggers@kernel.org>
> cc: Herbert Xu <herbert@gondor.apana.org.au>
> cc: keyrings@vger.kernel.org
> cc: linux-crypto@vger.kernel.org
> ---
> crypto/asymmetric_keys/public_key.c | 55 +++++++++++++++++++++++++++--
> 1 file changed, 53 insertions(+), 2 deletions(-)
>
> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
> index 13a5616becaa..90b98e1a952d 100644
> --- a/crypto/asymmetric_keys/public_key.c
> +++ b/crypto/asymmetric_keys/public_key.c
> @@ -24,6 +24,52 @@ MODULE_DESCRIPTION("In-software asymmetric public-key subtype");
> MODULE_AUTHOR("Red Hat, Inc.");
> MODULE_LICENSE("GPL");
>
> +struct public_key_restriction {
> + const char *pkey_algo; /* Signing algorithm (e.g. "rsa") */
> + const char *pkey_enc; /* Signature encoding (e.g. "pkcs1") */
> + const char *hash_algo; /* Content hash algorithm (e.g. "sha256") */
> +};
> +
> +static const struct public_key_restriction public_key_restrictions[] = {
> + /* algo encoding hash */
> + { "rsa", "pkcs1", "sha256" },
> + { "rsa", "pkcs1", "sha384" },
> + { "rsa", "pkcs1", "sha512" },
> + { "rsa", "emsa-pss", "sha512" },
> + { "ecdsa", "x962", "sha256" },
> + { "ecdsa", "x962", "sha384" },
> + { "ecdsa", "x962", "sha512" },
> + { "ecrdsa", "raw", "sha256" },
> + { "ecrdsa", "raw", "sha384" },
> + { "ecrdsa", "raw", "sha512" },
> + { "mldsa44", "raw", "sha512" },
> + { "mldsa65", "raw", "sha512" },
> + { "mldsa87", "raw", "sha512" },
> + /* ML-DSA may also do its own hashing over the entire message. */
> + { "mldsa44", "raw", "-" },
> + { "mldsa65", "raw", "-" },
> + { "mldsa87", "raw", "-" },
> +};
Have you read software_key_determine_akcipher()? It's the place where
the encoding and hash_algo are validated currently. This commit adds a
second set of slightly different checks alongside the existing ones.
It's unclear whether the existing checks were considered.
Also, the ML-DSA and RSASSA-PSS support is new in this patchset, and
this commit is a fix for it. Instead of committing buggy code that is
fixed by a later commit, it's preferable to commit correct code in the
first place.
- Eric
David,
On Tue, Jan 20, 2026 at 02:50:57PM +0000, David Howells wrote:
> Limit the set of crypto combinations that may be used for module signing as
> no indication of hash algorithm used for signing is added to the hash of
> the data, so in theory a data blob hashed with a different algorithm can be
> substituted provided it has the same hash output.
>
> This also rejects the use of less secure algorithms.
>
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Lukas Wunner <lukas@wunner.de>
> cc: Ignat Korchagin <ignat@cloudflare.com>
> cc: Stephan Mueller <smueller@chronox.de>
> cc: Eric Biggers <ebiggers@kernel.org>
> cc: Herbert Xu <herbert@gondor.apana.org.au>
> cc: keyrings@vger.kernel.org
> cc: linux-crypto@vger.kernel.org
> ---
> crypto/asymmetric_keys/public_key.c | 55 +++++++++++++++++++++++++++--
> 1 file changed, 53 insertions(+), 2 deletions(-)
>
> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
> index 13a5616becaa..90b98e1a952d 100644
> --- a/crypto/asymmetric_keys/public_key.c
> +++ b/crypto/asymmetric_keys/public_key.c
> @@ -24,6 +24,52 @@ MODULE_DESCRIPTION("In-software asymmetric public-key subtype");
> MODULE_AUTHOR("Red Hat, Inc.");
> MODULE_LICENSE("GPL");
>
> +struct public_key_restriction {
> + const char *pkey_algo; /* Signing algorithm (e.g. "rsa") */
> + const char *pkey_enc; /* Signature encoding (e.g. "pkcs1") */
> + const char *hash_algo; /* Content hash algorithm (e.g. "sha256") */
> +};
> +
> +static const struct public_key_restriction public_key_restrictions[] = {
> + /* algo encoding hash */
> + { "rsa", "pkcs1", "sha256" },
> + { "rsa", "pkcs1", "sha384" },
> + { "rsa", "pkcs1", "sha512" },
> + { "rsa", "emsa-pss", "sha512" },
> + { "ecdsa", "x962", "sha256" },
> + { "ecdsa", "x962", "sha384" },
> + { "ecdsa", "x962", "sha512" },
> + { "ecrdsa", "raw", "sha256" },
> + { "ecrdsa", "raw", "sha384" },
> + { "ecrdsa", "raw", "sha512" },
Why such hash choice? Aren't it should be streebog256 and streebog512?
Thanks,
> + { "mldsa44", "raw", "sha512" },
> + { "mldsa65", "raw", "sha512" },
> + { "mldsa87", "raw", "sha512" },
> + /* ML-DSA may also do its own hashing over the entire message. */
> + { "mldsa44", "raw", "-" },
> + { "mldsa65", "raw", "-" },
> + { "mldsa87", "raw", "-" },
> +};
> +
> +/*
> + * Determine if a particular key/hash combination is allowed.
> + */
> +static int is_public_key_sig_allowed(const struct public_key_signature *sig)
> +{
> + for (int i = 0; i < ARRAY_SIZE(public_key_restrictions); i++) {
> + if (strcmp(public_key_restrictions[i].pkey_algo, sig->pkey_algo) != 0)
> + continue;
> + if (strcmp(public_key_restrictions[i].pkey_enc, sig->encoding) != 0)
> + continue;
> + if (strcmp(public_key_restrictions[i].hash_algo, sig->hash_algo) != 0)
> + continue;
> + return 0;
> + }
> + pr_warn_once("Public key signature combo (%s,%s,%s) rejected\n",
> + sig->pkey_algo, sig->encoding, sig->hash_algo);
> + return -EKEYREJECTED;
> +}
> +
> /*
> * Provide a part of a description of the key for /proc/keys.
> */
> @@ -391,12 +437,17 @@ int public_key_verify_signature(const struct public_key *pkey,
> bool issig;
> int ret;
>
> - pr_devel("==>%s()\n", __func__);
> -
> BUG_ON(!pkey);
> BUG_ON(!sig);
> BUG_ON(!sig->s);
>
> + ret = is_public_key_sig_allowed(sig);
> + if (ret < 0)
> + return ret;
> +
> + pr_devel("==>%s(%s,%s,%s)\n",
> + __func__, sig->pkey_algo, sig->encoding, sig->hash_algo);
> +
> /*
> * If the signature specifies a public key algorithm, it *must* match
> * the key's actual public key algorithm.
>
Vitaly Chikunov <vt@altlinux.org> wrote:
> > +static const struct public_key_restriction public_key_restrictions[] = {
> > + /* algo encoding hash */
> > + { "rsa", "pkcs1", "sha256" },
> > + { "rsa", "pkcs1", "sha384" },
> > + { "rsa", "pkcs1", "sha512" },
> > + { "rsa", "emsa-pss", "sha512" },
> > + { "ecdsa", "x962", "sha256" },
> > + { "ecdsa", "x962", "sha384" },
> > + { "ecdsa", "x962", "sha512" },
> > + { "ecrdsa", "raw", "sha256" },
> > + { "ecrdsa", "raw", "sha384" },
> > + { "ecrdsa", "raw", "sha512" },
>
> Why such hash choice? Aren't it should be streebog256 and streebog512?
Maybe? I don't have any example ecrdsa (assuming you're talking about that
specifically), nor does it seem that it was added to the choice of module
signing. Possibly I should drop the encoding column - or just have a list of
hashes that we accept - but we might want to limit the hashes that can use
with ML-DSA more strictly (ie. only allow SHA512).
David
Hi David,
On Tue, Jan 20, 2026 at 2:52 PM David Howells <dhowells@redhat.com> wrote:
>
> Limit the set of crypto combinations that may be used for module signing as
> no indication of hash algorithm used for signing is added to the hash of
> the data, so in theory a data blob hashed with a different algorithm can be
> substituted provided it has the same hash output.
>
> This also rejects the use of less secure algorithms.
>
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Lukas Wunner <lukas@wunner.de>
> cc: Ignat Korchagin <ignat@cloudflare.com>
> cc: Stephan Mueller <smueller@chronox.de>
> cc: Eric Biggers <ebiggers@kernel.org>
> cc: Herbert Xu <herbert@gondor.apana.org.au>
> cc: keyrings@vger.kernel.org
> cc: linux-crypto@vger.kernel.org
> ---
> crypto/asymmetric_keys/public_key.c | 55 +++++++++++++++++++++++++++--
> 1 file changed, 53 insertions(+), 2 deletions(-)
>
> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
> index 13a5616becaa..90b98e1a952d 100644
> --- a/crypto/asymmetric_keys/public_key.c
> +++ b/crypto/asymmetric_keys/public_key.c
> @@ -24,6 +24,52 @@ MODULE_DESCRIPTION("In-software asymmetric public-key subtype");
> MODULE_AUTHOR("Red Hat, Inc.");
> MODULE_LICENSE("GPL");
>
> +struct public_key_restriction {
> + const char *pkey_algo; /* Signing algorithm (e.g. "rsa") */
> + const char *pkey_enc; /* Signature encoding (e.g. "pkcs1") */
> + const char *hash_algo; /* Content hash algorithm (e.g. "sha256") */
> +};
> +
> +static const struct public_key_restriction public_key_restrictions[] = {
> + /* algo encoding hash */
> + { "rsa", "pkcs1", "sha256" },
> + { "rsa", "pkcs1", "sha384" },
> + { "rsa", "pkcs1", "sha512" },
> + { "rsa", "emsa-pss", "sha512" },
Don't we want to allow sha256 for emsa-pss?
> + { "ecdsa", "x962", "sha256" },
> + { "ecdsa", "x962", "sha384" },
> + { "ecdsa", "x962", "sha512" },
> + { "ecrdsa", "raw", "sha256" },
> + { "ecrdsa", "raw", "sha384" },
> + { "ecrdsa", "raw", "sha512" },
> + { "mldsa44", "raw", "sha512" },
> + { "mldsa65", "raw", "sha512" },
> + { "mldsa87", "raw", "sha512" },
> + /* ML-DSA may also do its own hashing over the entire message. */
> + { "mldsa44", "raw", "-" },
> + { "mldsa65", "raw", "-" },
> + { "mldsa87", "raw", "-" },
> +};
> +
> +/*
> + * Determine if a particular key/hash combination is allowed.
> + */
> +static int is_public_key_sig_allowed(const struct public_key_signature *sig)
> +{
> + for (int i = 0; i < ARRAY_SIZE(public_key_restrictions); i++) {
> + if (strcmp(public_key_restrictions[i].pkey_algo, sig->pkey_algo) != 0)
> + continue;
> + if (strcmp(public_key_restrictions[i].pkey_enc, sig->encoding) != 0)
> + continue;
> + if (strcmp(public_key_restrictions[i].hash_algo, sig->hash_algo) != 0)
> + continue;
> + return 0;
> + }
> + pr_warn_once("Public key signature combo (%s,%s,%s) rejected\n",
> + sig->pkey_algo, sig->encoding, sig->hash_algo);
> + return -EKEYREJECTED;
> +}
> +
> /*
> * Provide a part of a description of the key for /proc/keys.
> */
> @@ -391,12 +437,17 @@ int public_key_verify_signature(const struct public_key *pkey,
> bool issig;
> int ret;
>
> - pr_devel("==>%s()\n", __func__);
> -
> BUG_ON(!pkey);
> BUG_ON(!sig);
> BUG_ON(!sig->s);
>
> + ret = is_public_key_sig_allowed(sig);
> + if (ret < 0)
> + return ret;
> +
> + pr_devel("==>%s(%s,%s,%s)\n",
> + __func__, sig->pkey_algo, sig->encoding, sig->hash_algo);
> +
> /*
> * If the signature specifies a public key algorithm, it *must* match
> * the key's actual public key algorithm.
>
Ignat
Ignat Korchagin <ignat@cloudflare.com> wrote:
> > + { "rsa", "emsa-pss", "sha512" },
>
> Don't we want to allow sha256 for emsa-pss?
We do. I already added that for v14.
David
© 2016 - 2026 Red Hat, Inc.