[RFC][PATCH v3 9/9] ima: Support non-PKCS#7 modsig types

From: Roberto Sassu
Date: Thu Jul 20 2023 - 11:37:05 EST


From: Roberto Sassu <roberto.sassu@xxxxxxxxxx>

Add support for alternative signature formats through the newly introduced
user asymmetric key signatures. The corresponding API is invoked if the
signature type is not PKEY_ID_PKCS7. If the signature type is
PKEY_ID_PKCS7, nothing changes, the existing API is still invoked.

Signed-off-by: Roberto Sassu <roberto.sassu@xxxxxxxxxx>
---
security/integrity/ima/ima_modsig.c | 79 +++++++++++++++++++++--------
1 file changed, 59 insertions(+), 20 deletions(-)

diff --git a/security/integrity/ima/ima_modsig.c b/security/integrity/ima/ima_modsig.c
index 3e7bee30080..7c96cb2613a 100644
--- a/security/integrity/ima/ima_modsig.c
+++ b/security/integrity/ima/ima_modsig.c
@@ -12,11 +12,14 @@
#include <linux/module_signature.h>
#include <keys/asymmetric-type.h>
#include <crypto/pkcs7.h>
+#include <crypto/uasym_keys_sigs.h>

#include "ima.h"

struct modsig {
struct pkcs7_message *pkcs7_msg;
+ struct uasym_sig_message *uasym_sig;
+ u8 id_type;

enum hash_algo hash_algo;

@@ -28,8 +31,8 @@ struct modsig {
* This is what will go to the measurement list if the template requires
* storing the signature.
*/
- int raw_pkcs7_len;
- u8 raw_pkcs7[];
+ int raw_sig_len;
+ u8 raw_sig[];
};

/*
@@ -57,27 +60,43 @@ int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
buf_len -= marker_len;
sig = (const struct module_signature *)(p - sizeof(*sig));

- rc = mod_check_sig(sig, buf_len, func_tokens[func]);
- if (rc)
- return rc;
+ if (sig->id_type == PKEY_ID_PKCS7) {
+ rc = mod_check_sig(sig, buf_len, func_tokens[func]);
+ if (rc)
+ return rc;
+ } else {
+ /* Same as mod_check_sig() but skipping the id_type check. */
+ if (sig->algo != 0 ||
+ sig->hash != 0 ||
+ sig->signer_len != 0 ||
+ sig->key_id_len != 0 ||
+ sig->__pad[0] != 0 ||
+ sig->__pad[1] != 0 ||
+ sig->__pad[2] != 0)
+ return -EBADMSG;
+ }

sig_len = be32_to_cpu(sig->sig_len);
buf_len -= sig_len + sizeof(*sig);

- /* Allocate sig_len additional bytes to hold the raw PKCS#7 data. */
+ /* Allocate sig_len additional bytes to hold the raw sig data. */
hdr = kzalloc(sizeof(*hdr) + sig_len, GFP_KERNEL);
if (!hdr)
return -ENOMEM;

- hdr->pkcs7_msg = pkcs7_parse_message(buf + buf_len, sig_len);
- if (IS_ERR(hdr->pkcs7_msg)) {
- rc = PTR_ERR(hdr->pkcs7_msg);
+ if (sig->id_type == PKEY_ID_PKCS7)
+ hdr->pkcs7_msg = pkcs7_parse_message(buf + buf_len, sig_len);
+ else
+ hdr->uasym_sig = uasym_sig_parse_message(buf + buf_len, sig_len);
+
+ if (IS_ERR(hdr->pkcs7_msg) || IS_ERR(hdr->uasym_sig)) {
kfree(hdr);
return rc;
}

- memcpy(hdr->raw_pkcs7, buf + buf_len, sig_len);
- hdr->raw_pkcs7_len = sig_len;
+ memcpy(hdr->raw_sig, buf + buf_len, sig_len);
+ hdr->raw_sig_len = sig_len;
+ hdr->id_type = sig->id_type;

/* We don't know the hash algorithm yet. */
hdr->hash_algo = HASH_ALGO__LAST;
@@ -105,21 +124,38 @@ void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size)
* Provide the file contents (minus the appended sig) so that the PKCS7
* code can calculate the file hash.
*/
- size -= modsig->raw_pkcs7_len + strlen(MODULE_SIG_STRING) +
+ size -= modsig->raw_sig_len + strlen(MODULE_SIG_STRING) +
sizeof(struct module_signature);
- rc = pkcs7_supply_detached_data(modsig->pkcs7_msg, buf, size);
+ if (modsig->id_type == PKEY_ID_PKCS7)
+ rc = pkcs7_supply_detached_data(modsig->pkcs7_msg, buf, size);
+ else
+ rc = uasym_sig_supply_detached_data(modsig->uasym_sig, buf,
+ size);
if (rc)
return;

/* Ask the PKCS7 code to calculate the file hash. */
- rc = pkcs7_get_digest(modsig->pkcs7_msg, &modsig->digest,
- &modsig->digest_size, &modsig->hash_algo);
+ if (modsig->id_type == PKEY_ID_PKCS7)
+ rc = pkcs7_get_digest(modsig->pkcs7_msg, &modsig->digest,
+ &modsig->digest_size, &modsig->hash_algo);
+ else
+ rc = uasym_sig_get_digest(modsig->uasym_sig, &modsig->digest,
+ &modsig->digest_size,
+ &modsig->hash_algo);
}

int ima_modsig_verify(struct key *keyring, const struct modsig *modsig)
{
- return verify_pkcs7_message_sig(NULL, 0, modsig->pkcs7_msg, keyring,
- VERIFYING_MODULE_SIGNATURE, NULL, NULL);
+ if (modsig->id_type == PKEY_ID_PKCS7)
+ return verify_pkcs7_message_sig(NULL, 0, modsig->pkcs7_msg,
+ keyring,
+ VERIFYING_MODULE_SIGNATURE,
+ NULL, NULL);
+ else
+ return verify_uasym_sig_message(NULL, 0, modsig->uasym_sig,
+ keyring,
+ VERIFYING_MODULE_SIGNATURE,
+ NULL, NULL);
}

int ima_get_modsig_digest(const struct modsig *modsig, enum hash_algo *algo,
@@ -135,8 +171,8 @@ int ima_get_modsig_digest(const struct modsig *modsig, enum hash_algo *algo,
int ima_get_raw_modsig(const struct modsig *modsig, const void **data,
u32 *data_len)
{
- *data = &modsig->raw_pkcs7;
- *data_len = modsig->raw_pkcs7_len;
+ *data = &modsig->raw_sig;
+ *data_len = modsig->raw_sig_len;

return 0;
}
@@ -146,6 +182,9 @@ void ima_free_modsig(struct modsig *modsig)
if (!modsig)
return;

- pkcs7_free_message(modsig->pkcs7_msg);
+ if (modsig->id_type == PKEY_ID_PKCS7)
+ pkcs7_free_message(modsig->pkcs7_msg);
+ else
+ uasym_sig_free_message(modsig->uasym_sig);
kfree(modsig);
}
--
2.34.1