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