* [PATCH v2 0/2] Add support for ML-DSA signature for EVM and IMA
@ 2026-04-08 17:41 Stefan Berger
2026-04-08 17:41 ` [PATCH v2 1/2] integrity: Refactor asymmetric_verify for reusability Stefan Berger
2026-04-08 17:41 ` [PATCH v2 2/2] integrity: Add support for sigv3 verification using ML-DSA keys Stefan Berger
0 siblings, 2 replies; 7+ messages in thread
From: Stefan Berger @ 2026-04-08 17:41 UTC (permalink / raw)
To: linux-integrity, linux-security-module
Cc: linux-kernel, zohar, roberto.sassu, ebiggers, Stefan Berger
Based on IMA sigv3 type of signatures, add support for ML-DSA signature
for EVM and IMA. Use the existing ML-DSA hashless signing mode (pure mode).
Stefan
v2:
- Dropped 1/3
- Using "none" as hash_algo in 2/2
Stefan Berger (2):
integrity: Refactor asymmetric_verify for reusability
integrity: Add support for sigv3 verification using ML-DSA keys
security/integrity/digsig_asymmetric.c | 126 +++++++++++++++++++++----
1 file changed, 107 insertions(+), 19 deletions(-)
base-commit: 82bbd447199ff1441031d2eaf9afe041550cf525
--
2.53.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/2] integrity: Refactor asymmetric_verify for reusability
2026-04-08 17:41 [PATCH v2 0/2] Add support for ML-DSA signature for EVM and IMA Stefan Berger
@ 2026-04-08 17:41 ` Stefan Berger
2026-04-15 2:00 ` Mimi Zohar
2026-04-08 17:41 ` [PATCH v2 2/2] integrity: Add support for sigv3 verification using ML-DSA keys Stefan Berger
1 sibling, 1 reply; 7+ messages in thread
From: Stefan Berger @ 2026-04-08 17:41 UTC (permalink / raw)
To: linux-integrity, linux-security-module
Cc: linux-kernel, zohar, roberto.sassu, ebiggers, Stefan Berger
Refactor asymmetric_verify for reusability. Have it call
asymmetric_verify_common with the signature verification key and the
public_key structure as parameters. sigv3 support for ML-DSA will need to
check the public key type first to decide how to do the signature
verification and therefore will have these parameters available for
calling asymmetric_verify_common.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
---
security/integrity/digsig_asymmetric.c | 42 +++++++++++++++++---------
1 file changed, 28 insertions(+), 14 deletions(-)
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
index 6e68ec3becbd..e29ed73f15cd 100644
--- a/security/integrity/digsig_asymmetric.c
+++ b/security/integrity/digsig_asymmetric.c
@@ -79,18 +79,15 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
return key;
}
-int asymmetric_verify(struct key *keyring, const char *sig,
- int siglen, const char *data, int datalen)
+static int asymmetric_verify_common(const struct key *key,
+ const struct public_key *pk,
+ const char *sig, int siglen,
+ const char *data, int datalen)
{
- struct public_key_signature pks;
struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
- const struct public_key *pk;
- struct key *key;
+ struct public_key_signature pks;
int ret;
- if (siglen <= sizeof(*hdr))
- return -EBADMSG;
-
siglen -= sizeof(*hdr);
if (siglen != be16_to_cpu(hdr->sig_size))
@@ -99,15 +96,10 @@ int asymmetric_verify(struct key *keyring, const char *sig,
if (hdr->hash_algo >= HASH_ALGO__LAST)
return -ENOPKG;
- key = request_asymmetric_key(keyring, be32_to_cpu(hdr->keyid));
- if (IS_ERR(key))
- return PTR_ERR(key);
-
memset(&pks, 0, sizeof(pks));
pks.hash_algo = hash_algo_name[hdr->hash_algo];
- pk = asymmetric_key_public_key(key);
pks.pkey_algo = pk->pkey_algo;
if (!strcmp(pk->pkey_algo, "rsa")) {
pks.encoding = "pkcs1";
@@ -127,11 +119,33 @@ int asymmetric_verify(struct key *keyring, const char *sig,
pks.s_size = siglen;
ret = verify_signature(key, &pks);
out:
- key_put(key);
pr_debug("%s() = %d\n", __func__, ret);
return ret;
}
+int asymmetric_verify(struct key *keyring, const char *sig,
+ int siglen, const char *data, int datalen)
+{
+ struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
+ const struct public_key *pk;
+ struct key *key;
+ int ret;
+
+ if (siglen <= sizeof(*hdr))
+ return -EBADMSG;
+
+ key = request_asymmetric_key(keyring, be32_to_cpu(hdr->keyid));
+ if (IS_ERR(key))
+ return PTR_ERR(key);
+ pk = asymmetric_key_public_key(key);
+
+ ret = asymmetric_verify_common(key, pk, sig, siglen, data, datalen);
+
+ key_put(key);
+
+ return ret;
+}
+
/*
* calc_file_id_hash - calculate the hash of the ima_file_id struct data
* @type: xattr type [enum evm_ima_xattr_type]
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 2/2] integrity: Add support for sigv3 verification using ML-DSA keys
2026-04-08 17:41 [PATCH v2 0/2] Add support for ML-DSA signature for EVM and IMA Stefan Berger
2026-04-08 17:41 ` [PATCH v2 1/2] integrity: Refactor asymmetric_verify for reusability Stefan Berger
@ 2026-04-08 17:41 ` Stefan Berger
2026-04-15 2:01 ` Mimi Zohar
1 sibling, 1 reply; 7+ messages in thread
From: Stefan Berger @ 2026-04-08 17:41 UTC (permalink / raw)
To: linux-integrity, linux-security-module
Cc: linux-kernel, zohar, roberto.sassu, ebiggers, Stefan Berger
Add support for sigv3 signature verification using ML-DSA in pure mode.
When a sigv3 signature is verified, first check whether the key to use
for verification is an ML-DSA key and therefore uses a hashless signature
verification scheme. The hashless signature verification method uses the
ima_file_id structure directly for signature verification rather than
its digest.
Suggested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
---
v2: Set hash_algo in public_key_signature to "none"
---
security/integrity/digsig_asymmetric.c | 84 ++++++++++++++++++++++++--
1 file changed, 79 insertions(+), 5 deletions(-)
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
index e29ed73f15cd..c80cb2b117a6 100644
--- a/security/integrity/digsig_asymmetric.c
+++ b/security/integrity/digsig_asymmetric.c
@@ -190,17 +190,91 @@ static int calc_file_id_hash(enum evm_ima_xattr_type type,
return rc;
}
+/*
+ * asymmetric_verify_v3_hashless - Use hashless signature verification on sigv3
+ * @key: The key to use for signature verification
+ * @pk: The associated public key
+ * @encoding: The encoding the key type uses
+ * @sig: The signature
+ * @siglen: The length of the xattr signature
+ * @algo: The hash algorithm
+ * @digest: The file digest
+ *
+ * Create an ima_file_id structure and use it for signature verification
+ * directly. This can be used for ML-DSA in pure mode for example.
+ */
+static int asymmetric_verify_v3_hashless(struct key *key,
+ const struct public_key *pk,
+ const char *encoding,
+ const char *sig, int siglen,
+ u8 algo,
+ const u8 *digest)
+{
+ struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
+ struct ima_file_id file_id = {
+ .hash_type = hdr->type,
+ .hash_algorithm = algo,
+ };
+ size_t digest_size = hash_digest_size[algo];
+ struct public_key_signature pks = {
+ .m = (u8 *)&file_id,
+ .m_size = sizeof(file_id) - (HASH_MAX_DIGESTSIZE - digest_size),
+ .s = hdr->sig,
+ .s_size = siglen - sizeof(*hdr),
+ .pkey_algo = pk->pkey_algo,
+ .hash_algo = "none",
+ .encoding = encoding,
+ };
+ int ret;
+
+ if (hdr->type != IMA_VERITY_DIGSIG &&
+ hdr->type != EVM_IMA_XATTR_DIGSIG &&
+ hdr->type != EVM_XATTR_PORTABLE_DIGSIG)
+ return -EINVAL;
+
+ if (pks.s_size != be16_to_cpu(hdr->sig_size))
+ return -EBADMSG;
+
+ memcpy(file_id.hash, digest, digest_size);
+
+ ret = verify_signature(key, &pks);
+ pr_debug("%s() = %d\n", __func__, ret);
+ return ret;
+}
+
int asymmetric_verify_v3(struct key *keyring, const char *sig, int siglen,
const char *data, int datalen, u8 algo)
{
struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
struct ima_max_digest_data hash;
+ const struct public_key *pk;
+ struct key *key;
int rc;
- rc = calc_file_id_hash(hdr->type, algo, data, &hash);
- if (rc)
- return -EINVAL;
+ if (siglen <= sizeof(*hdr))
+ return -EBADMSG;
+
+ key = request_asymmetric_key(keyring, be32_to_cpu(hdr->keyid));
+ if (IS_ERR(key))
+ return PTR_ERR(key);
- return asymmetric_verify(keyring, sig, siglen, hash.digest,
- hash.hdr.length);
+ pk = asymmetric_key_public_key(key);
+ if (!strncmp(pk->pkey_algo, "mldsa", 5)) {
+ rc = asymmetric_verify_v3_hashless(key, pk, "raw",
+ sig, siglen, algo, data);
+ } else {
+ rc = calc_file_id_hash(hdr->type, algo, data, &hash);
+ if (rc) {
+ rc = -EINVAL;
+ goto err_exit;
+ }
+
+ rc = asymmetric_verify_common(key, pk, sig, siglen, hash.digest,
+ hash.hdr.length);
+ }
+
+err_exit:
+ key_put(key);
+
+ return rc;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] integrity: Refactor asymmetric_verify for reusability
2026-04-08 17:41 ` [PATCH v2 1/2] integrity: Refactor asymmetric_verify for reusability Stefan Berger
@ 2026-04-15 2:00 ` Mimi Zohar
2026-04-15 20:15 ` Stefan Berger
0 siblings, 1 reply; 7+ messages in thread
From: Mimi Zohar @ 2026-04-15 2:00 UTC (permalink / raw)
To: Stefan Berger, linux-integrity, linux-security-module
Cc: linux-kernel, roberto.sassu, ebiggers
On Wed, 2026-04-08 at 13:41 -0400, Stefan Berger wrote:
> Refactor asymmetric_verify for reusability. Have it call
> asymmetric_verify_common with the signature verification key and the
> public_key structure as parameters. sigv3 support for ML-DSA will need to
> check the public key type first to decide how to do the signature
> verification and therefore will have these parameters available for
> calling asymmetric_verify_common.
>
> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Thanks, Stefan.
> ---
> security/integrity/digsig_asymmetric.c | 42 +++++++++++++++++---------
> 1 file changed, 28 insertions(+), 14 deletions(-)
>
> diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
> index 6e68ec3becbd..e29ed73f15cd 100644
> --- a/security/integrity/digsig_asymmetric.c
> +++ b/security/integrity/digsig_asymmetric.c
> @@ -79,18 +79,15 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
> return key;
> }
>
> -int asymmetric_verify(struct key *keyring, const char *sig,
> - int siglen, const char *data, int datalen)
> +static int asymmetric_verify_common(const struct key *key,
> + const struct public_key *pk,
> + const char *sig, int siglen,
> + const char *data, int datalen)
> {
> - struct public_key_signature pks;
> struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
> - const struct public_key *pk;
> - struct key *key;
> + struct public_key_signature pks;
> int ret;
>
> - if (siglen <= sizeof(*hdr))
> - return -EBADMSG;
> -
> siglen -= sizeof(*hdr);
Normally kernel-doc is unnecessary for static functions. Here, however, since
only the caller verifies the signature length, there should be a kernel-doc
function definition. It should indicate that all callers must verify the
signature length (siglen) and that the public key (pk) is not NULL, before
calling asymmetric_verify_common().
>
> if (siglen != be16_to_cpu(hdr->sig_size))
> @@ -99,15 +96,10 @@ int asymmetric_verify(struct key *keyring, const char *sig,
> if (hdr->hash_algo >= HASH_ALGO__LAST)
> return -ENOPKG;
>
> - key = request_asymmetric_key(keyring, be32_to_cpu(hdr->keyid));
> - if (IS_ERR(key))
> - return PTR_ERR(key);
> -
> memset(&pks, 0, sizeof(pks));
>
> pks.hash_algo = hash_algo_name[hdr->hash_algo];
>
> - pk = asymmetric_key_public_key(key);
> pks.pkey_algo = pk->pkey_algo;
> if (!strcmp(pk->pkey_algo, "rsa")) {
> pks.encoding = "pkcs1";
> @@ -127,11 +119,33 @@ int asymmetric_verify(struct key *keyring, const char *sig,
> pks.s_size = siglen;
> ret = verify_signature(key, &pks);
> out:
> - key_put(key);
The kernel-doc function definition should also indicate that the caller must
free the key.
> pr_debug("%s() = %d\n", __func__, ret);
> return ret;
> }
>
> +int asymmetric_verify(struct key *keyring, const char *sig,
> + int siglen, const char *data, int datalen)
> +{
> + struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
> + const struct public_key *pk;
> + struct key *key;
> + int ret;
> +
> + if (siglen <= sizeof(*hdr))
> + return -EBADMSG;
> +
> + key = request_asymmetric_key(keyring, be32_to_cpu(hdr->keyid));
> + if (IS_ERR(key))
> + return PTR_ERR(key);
> + pk = asymmetric_key_public_key(key);
Please add a test here making sure pk is not null.
thanks,
Mimi
> +
> + ret = asymmetric_verify_common(key, pk, sig, siglen, data, datalen);
> +
> + key_put(key);
> +
> + return ret;
> +}
> +
> /*
> * calc_file_id_hash - calculate the hash of the ima_file_id struct data
> * @type: xattr type [enum evm_ima_xattr_type]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 2/2] integrity: Add support for sigv3 verification using ML-DSA keys
2026-04-08 17:41 ` [PATCH v2 2/2] integrity: Add support for sigv3 verification using ML-DSA keys Stefan Berger
@ 2026-04-15 2:01 ` Mimi Zohar
2026-04-15 20:32 ` Stefan Berger
0 siblings, 1 reply; 7+ messages in thread
From: Mimi Zohar @ 2026-04-15 2:01 UTC (permalink / raw)
To: Stefan Berger, linux-integrity, linux-security-module
Cc: linux-kernel, roberto.sassu, ebiggers
On Wed, 2026-04-08 at 13:41 -0400, Stefan Berger wrote:
> Add support for sigv3 signature verification using ML-DSA in pure mode.
> When a sigv3 signature is verified, first check whether the key to use
> for verification is an ML-DSA key and therefore uses a hashless signature
> verification scheme. The hashless signature verification method uses the
> ima_file_id structure directly for signature verification rather than
> its digest.
>
> Suggested-by: Eric Biggers <ebiggers@kernel.org>
> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
>
Thanks, Stefan.
> ---
> v2: Set hash_algo in public_key_signature to "none"
> ---
> security/integrity/digsig_asymmetric.c | 84 ++++++++++++++++++++++++--
> 1 file changed, 79 insertions(+), 5 deletions(-)
>
> diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
> index e29ed73f15cd..c80cb2b117a6 100644
> --- a/security/integrity/digsig_asymmetric.c
> +++ b/security/integrity/digsig_asymmetric.c
> @@ -190,17 +190,91 @@ static int calc_file_id_hash(enum evm_ima_xattr_type type,
> return rc;
> }
>
> +/*
kernel-doc starts with "/**".
> + * asymmetric_verify_v3_hashless - Use hashless signature verification on sigv3
> + * @key: The key to use for signature verification
> + * @pk: The associated public key
> + * @encoding: The encoding the key type uses
> + * @sig: The signature
> + * @siglen: The length of the xattr signature
> + * @algo: The hash algorithm
> + * @digest: The file digest
> + *
> + * Create an ima_file_id structure and use it for signature verification
> + * directly. This can be used for ML-DSA in pure mode for example.
Like the comments on 1/2, please add a comment here indicating that all callers
must verify the signature length (siglen) and the public key (pk) is not NULL,
before calling asymmetric_verify_v3_hashless(). Also indicate that the caller
must free the key.
> + */
> +static int asymmetric_verify_v3_hashless(struct key *key,
> + const struct public_key *pk,
> + const char *encoding,
> + const char *sig, int siglen,
> + u8 algo,
> + const u8 *digest)
> +{
> + struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
> + struct ima_file_id file_id = {
> + .hash_type = hdr->type,
> + .hash_algorithm = algo,
> + };
> + size_t digest_size = hash_digest_size[algo];
Defer initializing the digest_size and .m_size, below, until after checking the
hash algorithm is valid.
> + struct public_key_signature pks = {
> + .m = (u8 *)&file_id,
> + .m_size = sizeof(file_id) - (HASH_MAX_DIGESTSIZE - digest_size),
> + .s = hdr->sig,
> + .s_size = siglen - sizeof(*hdr),
> + .pkey_algo = pk->pkey_algo,
> + .hash_algo = "none",
> + .encoding = encoding,
> + };
> + int ret;
> +
> + if (hdr->type != IMA_VERITY_DIGSIG &&
> + hdr->type != EVM_IMA_XATTR_DIGSIG &&
> + hdr->type != EVM_XATTR_PORTABLE_DIGSIG)
> + return -EINVAL;
> +
> + if (pks.s_size != be16_to_cpu(hdr->sig_size))
> + return -EBADMSG;
> +
> + memcpy(file_id.hash, digest, digest_size);
First check the hash algorithm is valid, before using digest_size.
> +
> + ret = verify_signature(key, &pks);
> + pr_debug("%s() = %d\n", __func__, ret);
> + return ret;
> +}
> +
> int asymmetric_verify_v3(struct key *keyring, const char *sig, int siglen,
> const char *data, int datalen, u8 algo)
> {
> struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
> struct ima_max_digest_data hash;
> + const struct public_key *pk;
> + struct key *key;
> int rc;
>
> - rc = calc_file_id_hash(hdr->type, algo, data, &hash);
> - if (rc)
> - return -EINVAL;
> + if (siglen <= sizeof(*hdr))
> + return -EBADMSG;
> +
> + key = request_asymmetric_key(keyring, be32_to_cpu(hdr->keyid));
> + if (IS_ERR(key))
> + return PTR_ERR(key);
>
> - return asymmetric_verify(keyring, sig, siglen, hash.digest,
> - hash.hdr.length);
> + pk = asymmetric_key_public_key(key);
Please add a test to check that 'pk' isn't null.
> + if (!strncmp(pk->pkey_algo, "mldsa", 5)) {
> + rc = asymmetric_verify_v3_hashless(key, pk, "raw",
> + sig, siglen, algo, data);
> + } else {
> + rc = calc_file_id_hash(hdr->type, algo, data, &hash);
> + if (rc) {
> + rc = -EINVAL;
> + goto err_exit;
> + }
> +
> + rc = asymmetric_verify_common(key, pk, sig, siglen, hash.digest,
> + hash.hdr.length);
> + }
> +
> +err_exit:
Normally a label named 'err*' would be preceded by a return. Here, the label
"err_exit" is always called, not only when there is an error. Please rename the
label to something more appropriate - out, cleanup, etc.
> + key_put(key);
> +
> + return rc;
> }
thanks,
Mimi
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] integrity: Refactor asymmetric_verify for reusability
2026-04-15 2:00 ` Mimi Zohar
@ 2026-04-15 20:15 ` Stefan Berger
0 siblings, 0 replies; 7+ messages in thread
From: Stefan Berger @ 2026-04-15 20:15 UTC (permalink / raw)
To: Mimi Zohar, linux-integrity, linux-security-module
Cc: linux-kernel, roberto.sassu, ebiggers
On 4/14/26 10:00 PM, Mimi Zohar wrote:
> On Wed, 2026-04-08 at 13:41 -0400, Stefan Berger wrote:
>> Refactor asymmetric_verify for reusability. Have it call
>> asymmetric_verify_common with the signature verification key and the
>> public_key structure as parameters. sigv3 support for ML-DSA will need to
>> check the public key type first to decide how to do the signature
>> verification and therefore will have these parameters available for
>> calling asymmetric_verify_common.
>>
>> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
>
> Thanks, Stefan.
>
>> ---
>> security/integrity/digsig_asymmetric.c | 42 +++++++++++++++++---------
>> 1 file changed, 28 insertions(+), 14 deletions(-)
>>
>> diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
>> index 6e68ec3becbd..e29ed73f15cd 100644
>> --- a/security/integrity/digsig_asymmetric.c
>> +++ b/security/integrity/digsig_asymmetric.c
>> @@ -79,18 +79,15 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
>> return key;
>> }
>>
>> -int asymmetric_verify(struct key *keyring, const char *sig,
>> - int siglen, const char *data, int datalen)
>> +static int asymmetric_verify_common(const struct key *key,
>> + const struct public_key *pk,
>> + const char *sig, int siglen,
>> + const char *data, int datalen)
>> {
>> - struct public_key_signature pks;
>> struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
>> - const struct public_key *pk;
>> - struct key *key;
>> + struct public_key_signature pks;
>> int ret;
>>
>> - if (siglen <= sizeof(*hdr))
>> - return -EBADMSG;
>> -
>> siglen -= sizeof(*hdr);
>
> Normally kernel-doc is unnecessary for static functions. Here, however, since
> only the caller verifies the signature length, there should be a kernel-doc
> function definition. It should indicate that all callers must verify the
> signature length (siglen) and that the public key (pk) is not NULL, before
> calling asymmetric_verify_common().
Will add.
>
>>
>> if (siglen != be16_to_cpu(hdr->sig_size))
>> @@ -99,15 +96,10 @@ int asymmetric_verify(struct key *keyring, const char *sig,
>> if (hdr->hash_algo >= HASH_ALGO__LAST)
>> return -ENOPKG;
>>
>> - key = request_asymmetric_key(keyring, be32_to_cpu(hdr->keyid));
>> - if (IS_ERR(key))
>> - return PTR_ERR(key);
>> -
>> memset(&pks, 0, sizeof(pks));
>>
>> pks.hash_algo = hash_algo_name[hdr->hash_algo];
>>
>> - pk = asymmetric_key_public_key(key);
>> pks.pkey_algo = pk->pkey_algo;
>> if (!strcmp(pk->pkey_algo, "rsa")) {
>> pks.encoding = "pkcs1";
>> @@ -127,11 +119,33 @@ int asymmetric_verify(struct key *keyring, const char *sig,
>> pks.s_size = siglen;
>> ret = verify_signature(key, &pks);
>> out:
>> - key_put(key);
>
> The kernel-doc function definition should also indicate that the caller must
> free the key.
Ok, I will add it. However, symmetric_verify_common cannot free the key
since it is passed as const(!) struct key *key...
>
>> pr_debug("%s() = %d\n", __func__, ret);
>> return ret;
>> }
>>
>> +int asymmetric_verify(struct key *keyring, const char *sig,
>> + int siglen, const char *data, int datalen)
>> +{
>> + struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
>> + const struct public_key *pk;
>> + struct key *key;
>> + int ret;
>> +
>> + if (siglen <= sizeof(*hdr))
>> + return -EBADMSG;
>> +
>> + key = request_asymmetric_key(keyring, be32_to_cpu(hdr->keyid));
>> + if (IS_ERR(key))
>> + return PTR_ERR(key);
>> + pk = asymmetric_key_public_key(key);
>
> Please add a test here making sure pk is not null.
As a separate patch for backporting?
Return -ENOKEY in case we hit a NULL pointer?
>
> thanks,
>
> Mimi
>
>> +
>> + ret = asymmetric_verify_common(key, pk, sig, siglen, data, datalen);
>> +
>> + key_put(key);
>> +
>> + return ret;
>> +}
>> +
>> /*
>> * calc_file_id_hash - calculate the hash of the ima_file_id struct data
>> * @type: xattr type [enum evm_ima_xattr_type]
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 2/2] integrity: Add support for sigv3 verification using ML-DSA keys
2026-04-15 2:01 ` Mimi Zohar
@ 2026-04-15 20:32 ` Stefan Berger
0 siblings, 0 replies; 7+ messages in thread
From: Stefan Berger @ 2026-04-15 20:32 UTC (permalink / raw)
To: Mimi Zohar, linux-integrity, linux-security-module
Cc: linux-kernel, roberto.sassu, ebiggers
On 4/14/26 10:01 PM, Mimi Zohar wrote:
> On Wed, 2026-04-08 at 13:41 -0400, Stefan Berger wrote:
>> Add support for sigv3 signature verification using ML-DSA in pure mode.
>> When a sigv3 signature is verified, first check whether the key to use
>> for verification is an ML-DSA key and therefore uses a hashless signature
>> verification scheme. The hashless signature verification method uses the
>> ima_file_id structure directly for signature verification rather than
>> its digest.
>>
>> Suggested-by: Eric Biggers <ebiggers@kernel.org>
>> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
>>
>
> Thanks, Stefan.
>> ---
>> v2: Set hash_algo in public_key_signature to "none"
>> ---
>> security/integrity/digsig_asymmetric.c | 84 ++++++++++++++++++++++++--
>> 1 file changed, 79 insertions(+), 5 deletions(-)
>>
>> diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
>> index e29ed73f15cd..c80cb2b117a6 100644
>> --- a/security/integrity/digsig_asymmetric.c
>> +++ b/security/integrity/digsig_asymmetric.c
>> @@ -190,17 +190,91 @@ static int calc_file_id_hash(enum evm_ima_xattr_type type,
>> return rc;
>> }
>>
>> +/*
>
> kernel-doc starts with "/**".
I followed the pattern of documentation of a static function that you
just moved:
/*
* calc_file_id_hash - calculate the hash of the ima_file_id struct data
* @type: xattr type [enum evm_ima_xattr_type]
>
>> + * asymmetric_verify_v3_hashless - Use hashless signature verification on sigv3
>> + * @key: The key to use for signature verification
>> + * @pk: The associated public key
>> + * @encoding: The encoding the key type uses
>> + * @sig: The signature
>> + * @siglen: The length of the xattr signature
>> + * @algo: The hash algorithm
>> + * @digest: The file digest
>> + *
>> + * Create an ima_file_id structure and use it for signature verification
>> + * directly. This can be used for ML-DSA in pure mode for example.
>
> Like the comments on 1/2, please add a comment here indicating that all callers
> must verify the signature length (siglen) and the public key (pk) is not NULL,
> before calling asymmetric_verify_v3_hashless(). Also indicate that the caller
> must free the key.
>
>> + */
>> +static int asymmetric_verify_v3_hashless(struct key *key,
>> + const struct public_key *pk,
>> + const char *encoding,
>> + const char *sig, int siglen,
>> + u8 algo,
>> + const u8 *digest)
>> +{
>> + struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
>> + struct ima_file_id file_id = {
>> + .hash_type = hdr->type,
>> + .hash_algorithm = algo,
>> + };
>> + size_t digest_size = hash_digest_size[algo];
>
> Defer initializing the digest_size and .m_size, below, until after checking the
> hash algorithm is valid.
This function is called by asymmetric_verify. asymmetric_verify calls
calc_file_id_hash, which doesn't check algo for valid range, either. I
suppose it's an untrusted value at this point (IMA never checked it's
value for valid range?) an we should check it in asymmetric_verify then
to cover both cases? Or you want to check it individually?
>
>> + struct public_key_signature pks = {
>> + .m = (u8 *)&file_id,
>> + .m_size = sizeof(file_id) - (HASH_MAX_DIGESTSIZE - digest_size),
>> + .s = hdr->sig,
>> + .s_size = siglen - sizeof(*hdr),
>> + .pkey_algo = pk->pkey_algo,
>> + .hash_algo = "none",
>> + .encoding = encoding,
>> + };
>> + int ret;
>> +
>> + if (hdr->type != IMA_VERITY_DIGSIG &&
>> + hdr->type != EVM_IMA_XATTR_DIGSIG &&
>> + hdr->type != EVM_XATTR_PORTABLE_DIGSIG)
>> + return -EINVAL;
>> +
>> + if (pks.s_size != be16_to_cpu(hdr->sig_size))
>> + return -EBADMSG;
>> +
>> + memcpy(file_id.hash, digest, digest_size);
>
> First check the hash algorithm is valid, before using digest_size.
>
>> +
>> + ret = verify_signature(key, &pks);
>> + pr_debug("%s() = %d\n", __func__, ret);
>> + return ret;
>> +}
>> +
>> int asymmetric_verify_v3(struct key *keyring, const char *sig, int siglen,
>> const char *data, int datalen, u8 algo)
>> {
>> struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
>> struct ima_max_digest_data hash;
>> + const struct public_key *pk;
>> + struct key *key;
>> int rc;
>>
>> - rc = calc_file_id_hash(hdr->type, algo, data, &hash);
>> - if (rc)
>> - return -EINVAL;
>> + if (siglen <= sizeof(*hdr))
>> + return -EBADMSG;
>> +
>> + key = request_asymmetric_key(keyring, be32_to_cpu(hdr->keyid));
>> + if (IS_ERR(key))
>> + return PTR_ERR(key);
>>
>> - return asymmetric_verify(keyring, sig, siglen, hash.digest,
>> - hash.hdr.length);
>> + pk = asymmetric_key_public_key(key);
>
> Please add a test to check that 'pk' isn't null.
>
>> + if (!strncmp(pk->pkey_algo, "mldsa", 5)) {
>> + rc = asymmetric_verify_v3_hashless(key, pk, "raw",
>> + sig, siglen, algo, data);
>> + } else {
>> + rc = calc_file_id_hash(hdr->type, algo, data, &hash);
>> + if (rc) {
>> + rc = -EINVAL;
>> + goto err_exit;
>> + }
>> +
>> + rc = asymmetric_verify_common(key, pk, sig, siglen, hash.digest,
>> + hash.hdr.length);
>> + }
>> +
>> +err_exit:
>
> Normally a label named 'err*' would be preceded by a return. Here, the label
> "err_exit" is always called, not only when there is an error. Please rename the
> label to something more appropriate - out, cleanup, etc.
Ok, will call it 'out'.
>
>> + key_put(key);
>> +
>> + return rc;
>> }
>
> thanks,
>
> Mimi
>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-04-15 20:32 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-08 17:41 [PATCH v2 0/2] Add support for ML-DSA signature for EVM and IMA Stefan Berger
2026-04-08 17:41 ` [PATCH v2 1/2] integrity: Refactor asymmetric_verify for reusability Stefan Berger
2026-04-15 2:00 ` Mimi Zohar
2026-04-15 20:15 ` Stefan Berger
2026-04-08 17:41 ` [PATCH v2 2/2] integrity: Add support for sigv3 verification using ML-DSA keys Stefan Berger
2026-04-15 2:01 ` Mimi Zohar
2026-04-15 20:32 ` Stefan Berger
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox