Component: ima-evm-utils / evmctl
Version: 1.6.2 (packaged build)
Environment:
- OpenSSL: 3.5.4 (default provider active; ML‑DSA algorithms exposed)
- OS/arch: Debian/amd64 (userspace), kernel supports IMA v2 sigs
- Command(s): evmctl ima_sign -f --key <ML‑DSA‑65 key>
- Also attempted: evmctl --provider default … (same result)
Summary
When signing a file with ML‑DSA‑65 keys via evmctl ima_sign, the tool reports “evm/ima signature: 1023 bytes” and writes a 1024‑byte .sig file. The signature payload appears truncated/garbled and is not a valid ML‑DSA‑65 signature (which should be ~3309 bytes). This occurs before any xattr write and persists even when forcing the default provider.
- ML‑DSA‑65 expected signature size: 3309 bytes (per NIST FIPS 204 and common implementations).
- MA v2 xattr format uses a 16‑bit sig_size and is intended to carry multi‑KB signatures; ext4 xattrs commonly support values up to a block (e.g., ~4 KiB), so size is not the limiting factor.
This strongly suggests a fixed‑buffer truncation or untested code path in evmctl for non‑RSA/ECC EVP signatures.
Reproducer
1) Verify versions and provider:
evmctl --version
# evmctl 1.6.2
openssl version -a
# OpenSSL 3.5.4 30 Sep 2025 (Library: OpenSSL 3.5.4 30 Sep 2025)
# Providers show "default" active
openssl list -signature-algorithms | grep -i mldsa
# { … id-ml-dsa-65, ML-DSA-65, MLDSA65 } @ default
openssl pkey -in mldsa_65_private.pem -text -noout
# ML-DSA-65 Private-Key: (key parses fine)
(OpenSSL clearly exposes ML‑DSA‑65 in the default provider and can parse the private key.)
2) Sign any test file (e.g., a kernel module):
evmctl ima_sign -f --key mldsa_65_private.pem test_mod.ko
# hash(sha256): b6679ffc...
# evm/ima signature: 1023 bytes
# Writing to test_mod.ko.sig
ls -l test_mod.ko.sig
# -rw-r--r-- 1 root root 1024 ... test_mod.ko.sig
hexdump -C test_mod.ko.sig | head
# 00000000 03 02 04 d9 ... (starts like IMA v2 header: type=0x03, ver=0x02)
# ... (subsequent bytes look like pointers/stack words, not ML‑DSA signature)
3) Try forcing the provider (same result):
evmctl --provider default -v ima_sign -f --key mldsa_65_private.pem test_mod.ko
# read_keyid_from_cert: ...: x509 certificate not found
# calc_keyid_v2: keyid: d97bb346
# evm/ima signature: 1023 bytes
# Writing to test_mod.ko.sig
(“1023 bytes” is reported at sign time, before any xattr operation, and the .sig on disk is 1024 bytes—indicating truncation happens inside evmctl’s signing/packaging path.)
Expected vs Actual
Expected: evmctl should produce an IMA v2 signature blob whose sig_size and sig[] reflect the ~3309‑byte ML‑DSA‑65 signature from OpenSSL’s EVP, and write a .sig around 3.3 KB (+ header).
Actual: evmctl reports 1023 bytes and writes a 1024‑byte file. The payload after the initial bytes does not resemble a valid ML‑DSA signature, and appears consistent with a 1 KiB fixed buffer fill/truncation.
Why this is not an IMA/xattr limitation
- The IMA v2 xattr header (struct signature_v2_hdr) includes a 16‑bit sig_size and is designed for large signatures.
- The ext4 xattr implementation commonly allows values up to a full block (e.g., ~4 KiB), so a ~3.3 KB ML‑DSA‑65 signature fits.
Analysis / Hypothesis
- evmctl’s signing path likely assumes RSA/ECDSA‑sized outputs and uses a ~1 KiB fixed buffer (or copies into a fixed structure), truncating the EVP result.
- The hexdumps show a plausible IMA v2 header prefix (0x03 0x02 …) followed by 64‑bit pointer‑like words (.. .. .. 00 7f 00 00) rather than a contiguous ML‑DSA signature—consistent with copying from an internal struct rather than the actual EVP output buffer.
- OpenSSL 3.5.4’s default provider exposes and supports ML‑DSA; openssl pkey -text and openssl list -signature-algorithms prove the algorithm is available on this host
References
Suggested resolution
-
Audit the ML‑DSA path in evmctl:
- Ensure the EVP signature output is written into a dynamically sized buffer and that the full length returned by
EVP_PKEY_sign/EVP_PKEY_sign_message (or equivalent) is preserved.
- Avoid fixed‑size arrays for the signature payload and IMA v2 blob assembly.
-
Add a unit/integration test that:
- Generates an ML‑DSA‑65 key with OpenSSL,
- Signs a short file,
- Asserts that the resulting
.sig (IMA v2) has sig_size ≈ 3309 and total file size ≈ header + 3309.
-
(Optional) Provide a provider override flag defaulting to default for OpenSSL 3.x, and document PQC coverage expectations in the README/man page.
Attachments (from the reporter)
openssl version -a and provider listing (showing ML‑DSA in default provider). [man.archlinux.org]
evmctl verbose logs showing “evm/ima signature: 1023 bytes” and the 1024‑byte .sig.
- First 10 lines of
hexdump -C test_mod.ko.sig showing 0x03 0x02 … followed by non‑signature‑looking data (available on request).
Component: ima-evm-utils / evmctl
Version: 1.6.2 (packaged build)
Environment:
Summary
When signing a file with ML‑DSA‑65 keys via evmctl ima_sign, the tool reports “evm/ima signature: 1023 bytes” and writes a 1024‑byte .sig file. The signature payload appears truncated/garbled and is not a valid ML‑DSA‑65 signature (which should be ~3309 bytes). This occurs before any xattr write and persists even when forcing the default provider.
This strongly suggests a fixed‑buffer truncation or untested code path in evmctl for non‑RSA/ECC EVP signatures.
Reproducer
1) Verify versions and provider:
(OpenSSL clearly exposes ML‑DSA‑65 in the default provider and can parse the private key.)
2) Sign any test file (e.g., a kernel module):
3) Try forcing the provider (same result):
(“1023 bytes” is reported at sign time, before any xattr operation, and the .sig on disk is 1024 bytes—indicating truncation happens inside evmctl’s signing/packaging path.)
Expected vs Actual
Expected: evmctl should produce an IMA v2 signature blob whose sig_size and sig[] reflect the ~3309‑byte ML‑DSA‑65 signature from OpenSSL’s EVP, and write a .sig around 3.3 KB (+ header).
Actual: evmctl reports 1023 bytes and writes a 1024‑byte file. The payload after the initial bytes does not resemble a valid ML‑DSA signature, and appears consistent with a 1 KiB fixed buffer fill/truncation.
Why this is not an IMA/xattr limitation
Analysis / Hypothesis
References
--sigfile,ima_setxattr): [Ubuntu manpage](https://manpages.ubuntu.com/manpages/resolute/en/man1/evmctl.1.html) / [Debian manpage](https://manpages.debian.org/bullseye-backports/ima-evm-utils/evmctl.1.en.html)signature_v2_hdrwith 16‑bitsig_size): Linux integrity header in kernel tree (format & fields). [github.com]MLDSA65_SIGNATURE_BYTES 3309. [commondata...leapis.com]Suggested resolution
Audit the ML‑DSA path in
evmctl:EVP_PKEY_sign/EVP_PKEY_sign_message(or equivalent) is preserved.Add a unit/integration test that:
.sig(IMA v2) hassig_size ≈ 3309and total file size ≈header + 3309.(Optional) Provide a provider override flag defaulting to
defaultfor OpenSSL 3.x, and document PQC coverage expectations in the README/man page.Attachments (from the reporter)
openssl version -aand provider listing (showing ML‑DSA in default provider). [man.archlinux.org]evmctlverbose logs showing “evm/ima signature: 1023 bytes” and the 1024‑byte.sig.hexdump -C test_mod.ko.sigshowing0x03 0x02 …followed by non‑signature‑looking data (available on request).