diff options
Diffstat (limited to 'crypto/asymmetric_keys/pkcs7_verify.c')
| -rw-r--r-- | crypto/asymmetric_keys/pkcs7_verify.c | 78 |
1 files changed, 51 insertions, 27 deletions
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index 6d6475e3a9bf..474e2c1ae21b 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c @@ -30,8 +30,18 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo); + if (!sinfo->authattrs && sig->algo_takes_data) { + /* There's no intermediate digest and the signature algo + * doesn't want the data prehashing. + */ + sig->m = (void *)pkcs7->data; + sig->m_size = pkcs7->data_len; + sig->m_free = false; + return 0; + } + /* The digest was calculated already. */ - if (sig->digest) + if (sig->m) return 0; if (!sinfo->sig->hash_algo) @@ -45,12 +55,13 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); - sig->digest_size = crypto_shash_digestsize(tfm); + sig->m_size = crypto_shash_digestsize(tfm); ret = -ENOMEM; - sig->digest = kmalloc(sig->digest_size, GFP_KERNEL); - if (!sig->digest) + sig->m = kmalloc(umax(sinfo->authattrs_len, sig->m_size), GFP_KERNEL); + if (!sig->m) goto error_no_desc; + sig->m_free = true; desc = kzalloc(desc_size, GFP_KERNEL); if (!desc) @@ -59,33 +70,30 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, desc->tfm = tfm; /* Digest the message [RFC2315 9.3] */ - ret = crypto_shash_digest(desc, pkcs7->data, pkcs7->data_len, - sig->digest); + ret = crypto_shash_digest(desc, pkcs7->data, pkcs7->data_len, sig->m); if (ret < 0) goto error; - pr_devel("MsgDigest = [%*ph]\n", 8, sig->digest); + pr_devel("MsgDigest = [%*ph]\n", 8, sig->m); /* However, if there are authenticated attributes, there must be a * message digest attribute amongst them which corresponds to the * digest we just calculated. */ if (sinfo->authattrs) { - u8 tag; - if (!sinfo->msgdigest) { pr_warn("Sig %u: No messageDigest\n", sinfo->index); ret = -EKEYREJECTED; goto error; } - if (sinfo->msgdigest_len != sig->digest_size) { + if (sinfo->msgdigest_len != sig->m_size) { pr_warn("Sig %u: Invalid digest size (%u)\n", sinfo->index, sinfo->msgdigest_len); ret = -EBADMSG; goto error; } - if (memcmp(sig->digest, sinfo->msgdigest, + if (memcmp(sig->m, sinfo->msgdigest, sinfo->msgdigest_len) != 0) { pr_warn("Sig %u: Message digest doesn't match\n", sinfo->index); @@ -97,21 +105,26 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, * as the contents of the digest instead. Note that we need to * convert the attributes from a CONT.0 into a SET before we * hash it. + * + * However, for certain algorithms, such as ML-DSA, the digest + * is integrated into the signing algorithm. In such a case, + * we copy the authattrs, modifying the tag type, and set that + * as the digest. */ - memset(sig->digest, 0, sig->digest_size); - - ret = crypto_shash_init(desc); - if (ret < 0) - goto error; - tag = ASN1_CONS_BIT | ASN1_SET; - ret = crypto_shash_update(desc, &tag, 1); - if (ret < 0) - goto error; - ret = crypto_shash_finup(desc, sinfo->authattrs, - sinfo->authattrs_len, sig->digest); - if (ret < 0) - goto error; - pr_devel("AADigest = [%*ph]\n", 8, sig->digest); + memcpy(sig->m, sinfo->authattrs, sinfo->authattrs_len); + sig->m[0] = ASN1_CONS_BIT | ASN1_SET; + + if (sig->algo_takes_data) { + sig->m_size = sinfo->authattrs_len; + ret = 0; + } else { + ret = crypto_shash_digest(desc, sig->m, + sinfo->authattrs_len, + sig->m); + if (ret < 0) + goto error; + } + pr_devel("AADigest = [%*ph]\n", 8, sig->m); } error: @@ -137,9 +150,14 @@ int pkcs7_get_digest(struct pkcs7_message *pkcs7, const u8 **buf, u32 *len, ret = pkcs7_digest(pkcs7, sinfo); if (ret) return ret; + if (!sinfo->sig->m_free) { + pr_notice_once("%s: No digest available\n", __func__); + return -EINVAL; /* TODO: MLDSA doesn't necessarily calculate an + * intermediate digest. */ + } - *buf = sinfo->sig->digest; - *len = sinfo->sig->digest_size; + *buf = sinfo->sig->m; + *len = sinfo->sig->m_size; i = match_string(hash_algo_name, HASH_ALGO__LAST, sinfo->sig->hash_algo); @@ -407,6 +425,12 @@ int pkcs7_verify(struct pkcs7_message *pkcs7, return -EKEYREJECTED; } if (pkcs7->have_authattrs) { +#ifdef CONFIG_PKCS7_WAIVE_AUTHATTRS_REJECTION_FOR_MLDSA + if (pkcs7->authattrs_rej_waivable) { + pr_warn_once("Waived invalid module sig (has authattrs)\n"); + break; + } +#endif pr_warn("Invalid module sig (has authattrs)\n"); return -EKEYREJECTED; } |
