Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

pkcs7: Allow the signing algo to do whatever digestion it wants itself

Allow the data to be verified in a PKCS#7 or CMS message to be passed
directly to an asymmetric cipher algorithm (e.g. ML-DSA) if it wants to do
whatever passes for hashing/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.

The 'data to be verified' may be the content of the PKCS#7 message or it
will be the authenticatedAttributes (signedAttrs if CMS), modified, if
those are present.

This is done by:

(1) Make ->m and ->m_size 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.

(2) Add a flag, ->algo_takes_data, to indicate that the verification
algorithm wants to access the data to be verified directly rather than
having it digested first.

(3) If the PKCS#7 message has authenticatedAttributes (or CMS
signedAttrs), then the digest contained therein will be validated as
now, and the modified attrs blob will either be digested or assigned
to ->m as appropriate.

(4) If present, always copy and modify the authenticatedAttributes (or
signedAttrs) then digest that in one go rather than calling the shash
update twice (once for the tag and once for the rest).

(5) For ML-DSA, point ->m to the TBSCertificate instead of digesting it
and using the digest.

Note that whilst ML-DSA does allow for an "external mu", CMS doesn't yet
have that standardised.

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

+50 -19
+2 -2
crypto/asymmetric_keys/pkcs7_parser.c
··· 599 599 } 600 600 601 601 /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */ 602 - sinfo->authattrs = value - (hdrlen - 1); 603 - sinfo->authattrs_len = vlen + (hdrlen - 1); 602 + sinfo->authattrs = value - hdrlen; 603 + sinfo->authattrs_len = vlen + hdrlen; 604 604 return 0; 605 605 } 606 606
+34 -16
crypto/asymmetric_keys/pkcs7_verify.c
··· 30 30 31 31 kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo); 32 32 33 + if (!sinfo->authattrs && sig->algo_takes_data) { 34 + /* There's no intermediate digest and the signature algo 35 + * doesn't want the data prehashing. 36 + */ 37 + sig->m = (void *)pkcs7->data; 38 + sig->m_size = pkcs7->data_len; 39 + sig->m_free = false; 40 + return 0; 41 + } 42 + 33 43 /* The digest was calculated already. */ 34 44 if (sig->m) 35 45 return 0; ··· 58 48 sig->m_size = crypto_shash_digestsize(tfm); 59 49 60 50 ret = -ENOMEM; 61 - sig->m = kmalloc(sig->m_size, GFP_KERNEL); 51 + sig->m = kmalloc(umax(sinfo->authattrs_len, sig->m_size), GFP_KERNEL); 62 52 if (!sig->m) 63 53 goto error_no_desc; 54 + sig->m_free = true; 64 55 65 56 desc = kzalloc(desc_size, GFP_KERNEL); 66 57 if (!desc) ··· 80 69 * digest we just calculated. 81 70 */ 82 71 if (sinfo->authattrs) { 83 - u8 tag; 84 - 85 72 if (!sinfo->msgdigest) { 86 73 pr_warn("Sig %u: No messageDigest\n", sinfo->index); 87 74 ret = -EKEYREJECTED; ··· 105 96 * as the contents of the digest instead. Note that we need to 106 97 * convert the attributes from a CONT.0 into a SET before we 107 98 * hash it. 99 + * 100 + * However, for certain algorithms, such as ML-DSA, the digest 101 + * is integrated into the signing algorithm. In such a case, 102 + * we copy the authattrs, modifying the tag type, and set that 103 + * as the digest. 108 104 */ 109 - memset(sig->m, 0, sig->m_size); 105 + memcpy(sig->m, sinfo->authattrs, sinfo->authattrs_len); 106 + sig->m[0] = ASN1_CONS_BIT | ASN1_SET; 110 107 111 - 112 - ret = crypto_shash_init(desc); 113 - if (ret < 0) 114 - goto error; 115 - tag = ASN1_CONS_BIT | ASN1_SET; 116 - ret = crypto_shash_update(desc, &tag, 1); 117 - if (ret < 0) 118 - goto error; 119 - ret = crypto_shash_finup(desc, sinfo->authattrs, 120 - sinfo->authattrs_len, sig->m); 121 - if (ret < 0) 122 - goto error; 108 + if (sig->algo_takes_data) { 109 + sig->m_size = sinfo->authattrs_len; 110 + ret = 0; 111 + } else { 112 + ret = crypto_shash_digest(desc, sig->m, 113 + sinfo->authattrs_len, 114 + sig->m); 115 + if (ret < 0) 116 + goto error; 117 + } 123 118 pr_devel("AADigest = [%*ph]\n", 8, sig->m); 124 119 } 125 120 ··· 150 137 ret = pkcs7_digest(pkcs7, sinfo); 151 138 if (ret) 152 139 return ret; 140 + if (!sinfo->sig->m_free) { 141 + pr_notice_once("%s: No digest available\n", __func__); 142 + return -EINVAL; /* TODO: MLDSA doesn't necessarily calculate an 143 + * intermediate digest. */ 144 + } 153 145 154 146 *buf = sinfo->sig->m; 155 147 *len = sinfo->sig->m_size;
+2 -1
crypto/asymmetric_keys/signature.c
··· 28 28 for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++) 29 29 kfree(sig->auth_ids[i]); 30 30 kfree(sig->s); 31 - kfree(sig->m); 31 + if (sig->m_free) 32 + kfree(sig->m); 32 33 kfree(sig); 33 34 } 34 35 }
+10
crypto/asymmetric_keys/x509_public_key.c
··· 50 50 51 51 sig->s_size = cert->raw_sig_size; 52 52 53 + if (sig->algo_takes_data) { 54 + /* The signature algorithm does whatever passes for hashing. */ 55 + sig->m = (u8 *)cert->tbs; 56 + sig->m_size = cert->tbs_size; 57 + sig->m_free = false; 58 + goto out; 59 + } 60 + 53 61 /* Allocate the hashing algorithm we're going to need and find out how 54 62 * big the hash operational data will be. 55 63 */ ··· 77 69 sig->m = kmalloc(sig->m_size, GFP_KERNEL); 78 70 if (!sig->m) 79 71 goto error; 72 + sig->m_free = true; 80 73 81 74 desc = kzalloc(desc_size, GFP_KERNEL); 82 75 if (!desc) ··· 93 84 kfree(desc); 94 85 error: 95 86 crypto_free_shash(tfm); 87 + out: 96 88 pr_devel("<==%s() = %d\n", __func__, ret); 97 89 return ret; 98 90 }
+2
include/crypto/public_key.h
··· 46 46 u8 *m; /* Message data to pass to verifier */ 47 47 u32 s_size; /* Number of bytes in signature */ 48 48 u32 m_size; /* Number of bytes in ->m */ 49 + bool m_free; /* T if ->m needs freeing */ 50 + bool algo_takes_data; /* T if public key algo operates on data, not a hash */ 49 51 const char *pkey_algo; 50 52 const char *hash_algo; 51 53 const char *encoding;