From nobody Sun Feb 8 12:37:13 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EA01F44A737 for ; Tue, 20 Jan 2026 14:51:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768920698; cv=none; b=rLpHHqS+krp6WKgWaBBEE7miYH7QZ2XUR9Fsf2oGlYMZQM83ZoKacSHYDvb/QNM7gY0UxRLIqKsEZFJv0dIiYMgtGiXi2RKFLmndyfigKk/+WRtGyuLQSQLgcRkdbQl6RinjNT+oFHz2L1meqIkkvqaJwYuB6RJIy3tFAKV4AGo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768920698; c=relaxed/simple; bh=nEUVE4lPaWMhgtTg+if4fgi14Fj6AL4hj0BAyzkMbFo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DxNerunp0/ta3yq1WDIhF1HKpHKfleNTzO35kWgwyLgePDi1Vji3TpeONLwAjohfz3WPlvOyOHtc+ke25J9vwa0WKgtAoyP5NNbYVyRqwNiOV5ut85SI3ONyzgWS3RSXSSFOz0k7nC1v4R7Kw3TIgyGRhCcOz3u/EfsMQr50Iww= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=ANQ4RMa8; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="ANQ4RMa8" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1768920693; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=PuQhGJKPGqzqhoHtMa/bMYgLGosbNaX8zOBoi3O57Cs=; b=ANQ4RMa8bJWJUAAOrf59WLxt2nJ0e4C0/OZVmVKp9DxK454WK/STWboDnuLCM4gvOqaiQt GgVgMPafKfq32C6tDG1BohNcigD8LFFrkwPCkCyqDMkbAxMXWUG34+HE0RLpkMG2iua88W FGxjgUAp7c8zRZtiSmTUnRrCHmFtMNE= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-624-78lJFojDNG25Jj1b0eSilA-1; Tue, 20 Jan 2026 09:51:30 -0500 X-MC-Unique: 78lJFojDNG25Jj1b0eSilA-1 X-Mimecast-MFC-AGG-ID: 78lJFojDNG25Jj1b0eSilA_1768920688 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 050ED1956058; Tue, 20 Jan 2026 14:51:28 +0000 (UTC) Received: from warthog.procyon.org.uk.com (unknown [10.42.28.2]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 1A6331800993; Tue, 20 Jan 2026 14:51:23 +0000 (UTC) From: David Howells To: Lukas Wunner , Ignat Korchagin Cc: David Howells , Jarkko Sakkinen , Herbert Xu , Eric Biggers , Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , "Jason A . Donenfeld" , Ard Biesheuvel , Stephan Mueller , linux-crypto@vger.kernel.org, keyrings@vger.kernel.org, linux-modules@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v13 03/12] pkcs7: Allow direct signing of data with ML-DSA Date: Tue, 20 Jan 2026 14:50:49 +0000 Message-ID: <20260120145103.1176337-4-dhowells@redhat.com> In-Reply-To: <20260120145103.1176337-1-dhowells@redhat.com> References: <20260120145103.1176337-1-dhowells@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Content-Type: text/plain; charset="utf-8" Allow the data part of a PKCS#7 or CMS messge to be passed directly to an asymmetric cipher algorithm (e.g. ML-DSA) if it wants to do the digestion itself. The normal digestion of the data is then skipped as that would be ignored unless another signed info in the message has some other algorithm that needs it. This is done by setting the digest parameters to point to the data to be verified rather than making public_key_verify_signature() access the data directly. This is so that keyctl(KEYCTL_PKEY_VERIFY) will still work. To test this with ML-DSA, sign-file must be built with openssl > v3.5 and must include the following fix: https://github.com/openssl/openssl/pull/28923 which will allow CMS_NOATTR to be used with CMS_sign() for an ML-DSA key. sign-file will remove CMS_NOATTR if openssl is earlier than v4 and signed attributes will be used. Signed-off-by: David Howells cc: Lukas Wunner cc: Ignat Korchagin cc: Stephan Mueller cc: Eric Biggers cc: Herbert Xu cc: keyrings@vger.kernel.org cc: linux-crypto@vger.kernel.org --- crypto/asymmetric_keys/mscode_parser.c | 2 +- crypto/asymmetric_keys/pkcs7_verify.c | 18 ++++++++++++++++++ crypto/asymmetric_keys/signature.c | 3 ++- crypto/asymmetric_keys/verify_pefile.c | 3 ++- crypto/asymmetric_keys/verify_pefile.h | 1 + crypto/asymmetric_keys/x509_public_key.c | 1 + include/crypto/public_key.h | 1 + 7 files changed, 26 insertions(+), 3 deletions(-) diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_key= s/mscode_parser.c index 8aecbe4637f3..54dac17f19e2 100644 --- a/crypto/asymmetric_keys/mscode_parser.c +++ b/crypto/asymmetric_keys/mscode_parser.c @@ -124,6 +124,6 @@ int mscode_note_digest(void *context, size_t hdrlen, return -ENOMEM; =20 ctx->digest_len =3D vlen; - + ctx->digest_free =3D true; return 0; } diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys= /pkcs7_verify.c index 0f9f515b784d..46eee9811023 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c @@ -30,6 +30,16 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, =20 kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo); =20 + if (!sinfo->authattrs && sig->algo_does_hash) { + /* There's no intermediate digest and the signature algo + * doesn't want the data prehashing. + */ + sig->digest =3D (void *)pkcs7->data; + sig->digest_size =3D pkcs7->data_len; + sig->digest_free =3D false; + return 0; + } + /* The digest was calculated already. */ if (sig->digest) return 0; @@ -51,6 +61,7 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, sig->digest =3D kmalloc(sig->digest_size, GFP_KERNEL); if (!sig->digest) goto error_no_desc; + sig->digest_free =3D true; =20 desc =3D kzalloc(desc_size, GFP_KERNEL); if (!desc) @@ -103,6 +114,7 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, */ if (sig->algo_does_hash) { kfree(sig->digest); + sig->digest_free =3D false; =20 ret =3D -ENOMEM; sig->digest =3D kmalloc(umax(sinfo->authattrs_len, sig->digest_size), @@ -110,6 +122,7 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, if (!sig->digest) goto error_no_desc; =20 + sig->digest_free =3D true; sig->digest_size =3D sinfo->authattrs_len; memcpy(sig->digest, sinfo->authattrs, sinfo->authattrs_len); ((u8 *)sig->digest)[0] =3D ASN1_CONS_BIT | ASN1_SET; @@ -155,6 +168,11 @@ int pkcs7_get_digest(struct pkcs7_message *pkcs7, cons= t u8 **buf, u32 *len, ret =3D pkcs7_digest(pkcs7, sinfo); if (ret) return ret; + if (!sinfo->sig->digest_free) { + pr_notice_once("%s: No digest available\n", __func__); + return -EINVAL; /* TODO: MLDSA doesn't necessarily calculate an + * intermediate digest. */ + } =20 *buf =3D sinfo->sig->digest; *len =3D sinfo->sig->digest_size; diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/si= gnature.c index 041d04b5c953..bea01cf27d0a 100644 --- a/crypto/asymmetric_keys/signature.c +++ b/crypto/asymmetric_keys/signature.c @@ -28,7 +28,8 @@ void public_key_signature_free(struct public_key_signatur= e *sig) for (i =3D 0; i < ARRAY_SIZE(sig->auth_ids); i++) kfree(sig->auth_ids[i]); kfree(sig->s); - kfree(sig->digest); + if (sig->digest_free) + kfree(sig->digest); kfree(sig); } } diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_key= s/verify_pefile.c index 1f3b227ba7f2..30c23aea3b25 100644 --- a/crypto/asymmetric_keys/verify_pefile.c +++ b/crypto/asymmetric_keys/verify_pefile.c @@ -451,6 +451,7 @@ int verify_pefile_signature(const void *pebuf, unsigned= pelen, ret =3D pefile_digest_pe(pebuf, pelen, &ctx); =20 error: - kfree_sensitive(ctx.digest); + if (ctx.digest_free) + kfree_sensitive(ctx.digest); return ret; } diff --git a/crypto/asymmetric_keys/verify_pefile.h b/crypto/asymmetric_key= s/verify_pefile.h index e1628e100cde..f641437264b4 100644 --- a/crypto/asymmetric_keys/verify_pefile.h +++ b/crypto/asymmetric_keys/verify_pefile.h @@ -22,6 +22,7 @@ struct pefile_context { /* PKCS#7 MS Individual Code Signing content */ const void *digest; /* Digest */ unsigned digest_len; /* Digest length */ + bool digest_free; /* T if digest should be freed */ const char *digest_algo; /* Digest algorithm */ }; =20 diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_k= eys/x509_public_key.c index 12e3341e806b..2243add11d48 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c @@ -56,6 +56,7 @@ int x509_get_sig_params(struct x509_certificate *cert) sig->digest =3D kmalloc(sig->digest_size, GFP_KERNEL); if (!sig->digest) goto error; + sig->digest_free =3D true; =20 desc =3D kzalloc(desc_size, GFP_KERNEL); if (!desc) diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h index e4ec8003a3a4..68899a49cd0d 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h @@ -46,6 +46,7 @@ struct public_key_signature { u8 *digest; u32 s_size; /* Number of bytes in signature */ u32 digest_size; /* Number of bytes in digest */ + bool digest_free; /* T if digest needs freeing */ bool algo_does_hash; /* Public key algo does its own hashing */ const char *pkey_algo; const char *hash_algo;