1
0
mirror of https://git.code.sf.net/p/linux-ima/ima-evm-utils synced 2025-07-16 04:00:43 +02:00

Sign an fs-verity file digest

Sign fs-verity file digests provided in the format as produced by
"fsverity digest".  The output is of the same format as the input,
but with the file signature appended.  Use setfattr to write the
signature as security.ima xattr.

fsverity digest format: <algo>:<hash> <pathname>
output format: <algo>:<hash> <pathname> <signature>

Instead of directly signing the fsverity hash, to disambiguate the
original IMA signatures from the fs-verity signatures stored in the
security.ima xattr a new signature format version 3 (sigv3) was
defined as the hash of the xattr type (enum evm_ima_xattr_type),
the hash algorithm (enum hash_algo), and the hash.

Example:
fsverity digest <pathname> | evmctl sign_hash --veritysig \
 --key <pem encoded private key>

Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
This commit is contained in:
Mimi Zohar
2021-11-24 08:35:20 -05:00
parent acb19d1894
commit fc46af121e
4 changed files with 186 additions and 18 deletions

View File

@ -497,6 +497,92 @@ err:
return ret;
}
#define HASH_MAX_DIGESTSIZE 64 /* kernel HASH_MAX_DIGESTSIZE is 64 bytes */
struct ima_file_id {
__u8 hash_type; /* xattr type [enum evm_ima_xattr_type] */
__u8 hash_algorithm; /* Digest algorithm [enum hash_algo] */
__u8 hash[HASH_MAX_DIGESTSIZE];
} __packed;
/*
* Calculate the signature format version 3 hash based on the portion
* of the ima_file_id structure used, not the entire structure.
*
* On success, return the hash length, otherwise for openssl errors
* return 1, other errors return -EINVAL.
*/
int calc_hash_sigv3(enum evm_ima_xattr_type type, const char *algo,
const unsigned char *in_hash, unsigned char *out_hash)
{
struct ima_file_id file_id = { .hash_type = IMA_VERITY_DIGSIG };
uint8_t *data = (uint8_t *) &file_id;
const EVP_MD *md;
EVP_MD_CTX *pctx;
unsigned int mdlen;
int err;
#if OPENSSL_VERSION_NUMBER < 0x10100000
EVP_MD_CTX ctx;
pctx = &ctx;
#else
pctx = EVP_MD_CTX_new();
#endif
int hash_algo;
int hash_size;
unsigned int unused;
if (type != IMA_VERITY_DIGSIG) {
log_err("Only fsverity supports signature format v3 (sigv3)\n");
return -EINVAL;
}
if ((hash_algo = imaevm_get_hash_algo(algo)) < 0) {
log_err("Hash algorithm %s not supported\n", algo);
return -EINVAL;
}
file_id.hash_algorithm = hash_algo;
md = EVP_get_digestbyname(algo);
if (!md) {
log_err("EVP_get_digestbyname(%s) failed\n", algo);
err = 1;
goto err;
}
hash_size = EVP_MD_size(md);
memcpy(file_id.hash, in_hash, hash_size);
err = EVP_DigestInit(pctx, md);
if (!err) {
log_err("EVP_DigestInit() failed\n");
err = 1;
goto err;
}
unused = HASH_MAX_DIGESTSIZE - hash_size;
if (!EVP_DigestUpdate(pctx, data, sizeof(file_id) - unused)) {
log_err("EVP_DigestUpdate() failed\n");
err = 1;
goto err;
}
err = EVP_DigestFinal(pctx, out_hash, &mdlen);
if (!err) {
log_err("EVP_DigestFinal() failed\n");
err = 1;
goto err;
}
err = mdlen;
err:
if (err == 1)
output_openssl_errors();
#if OPENSSL_VERSION_NUMBER >= 0x10100000
EVP_MD_CTX_free(pctx);
#endif
return err;
}
int imaevm_get_hash_algo(const char *algo)
{
int i;