Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c7c8bb23 authored by Dmitry Kasatkin's avatar Dmitry Kasatkin Committed by Mimi Zohar
Browse files

ima: provide support for arbitrary hash algorithms



In preparation of supporting more hash algorithms with larger hash sizes
needed for signature verification, this patch replaces the 20 byte sized
digest, with a more flexible structure.  The new structure includes the
hash algorithm, digest size, and digest.

Changelog:
- recalculate filedata hash for the measurement list, if the signature
  hash digest size is greater than 20 bytes.
- use generic HASH_ALGO_
- make ima_calc_file_hash static
- scripts lindent and checkpatch fixes

Signed-off-by: default avatarDmitry Kasatkin <d.kasatkin@samsung.com>
Signed-off-by: default avatarMimi Zohar <zohar@linux.vnet.ibm.com>
parent 3fe78ca2
Loading
Loading
Loading
Loading
+0 −2
Original line number Original line Diff line number Diff line
@@ -21,8 +21,6 @@ struct x509_certificate {
	char		*authority;		/* Authority key fingerprint as hex */
	char		*authority;		/* Authority key fingerprint as hex */
	struct tm	valid_from;
	struct tm	valid_from;
	struct tm	valid_to;
	struct tm	valid_to;
	enum pkey_algo	pkey_algo : 8;		/* Public key algorithm */
	enum hash_algo sig_hash_algo : 8;	/* Signature hash algorithm */
	const void	*tbs;			/* Signed data */
	const void	*tbs;			/* Signed data */
	unsigned	tbs_size;		/* Size of signed data */
	unsigned	tbs_size;		/* Size of signed data */
	unsigned	raw_sig_size;		/* Size of sigature */
	unsigned	raw_sig_size;		/* Size of sigature */
+2 −1
Original line number Original line Diff line number Diff line
@@ -213,7 +213,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
		 cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1,
		 cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1,
		 cert->valid_to.tm_mday, cert->valid_to.tm_hour,
		 cert->valid_to.tm_mday, cert->valid_to.tm_hour,
		 cert->valid_to.tm_min,  cert->valid_to.tm_sec);
		 cert->valid_to.tm_min,  cert->valid_to.tm_sec);
	pr_devel("Cert Signature: %s\n",
	pr_devel("Cert Signature: %s + %s\n",
		 pkey_algo_name[cert->sig.pkey_algo],
		 hash_algo_name[cert->sig.pkey_hash_algo]);
		 hash_algo_name[cert->sig.pkey_hash_algo]);


	if (!cert->fingerprint) {
	if (!cert->fingerprint) {
+1 −0
Original line number Original line Diff line number Diff line
@@ -9,6 +9,7 @@ config IMA
	select CRYPTO_HMAC
	select CRYPTO_HMAC
	select CRYPTO_MD5
	select CRYPTO_MD5
	select CRYPTO_SHA1
	select CRYPTO_SHA1
	select CRYPTO_HASH_INFO
	select TCG_TPM if HAS_IOMEM && !UML
	select TCG_TPM if HAS_IOMEM && !UML
	select TCG_TIS if TCG_TPM && X86
	select TCG_TIS if TCG_TPM && X86
	select TCG_IBMVTPM if TCG_TPM && PPC64
	select TCG_IBMVTPM if TCG_TPM && PPC64
+4 −3
Original line number Original line Diff line number Diff line
@@ -39,7 +39,7 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
/* set during initialization */
/* set during initialization */
extern int ima_initialized;
extern int ima_initialized;
extern int ima_used_chip;
extern int ima_used_chip;
extern char *ima_hash;
extern int ima_hash_algo;
extern int ima_appraise;
extern int ima_appraise;


/* IMA inode template definition */
/* IMA inode template definition */
@@ -70,8 +70,9 @@ void ima_fs_cleanup(void);
int ima_inode_alloc(struct inode *inode);
int ima_inode_alloc(struct inode *inode);
int ima_add_template_entry(struct ima_template_entry *entry, int violation,
int ima_add_template_entry(struct ima_template_entry *entry, int violation,
			   const char *op, struct inode *inode);
			   const char *op, struct inode *inode);
int ima_calc_file_hash(struct file *file, char *digest);
int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash);
int ima_calc_buffer_hash(const void *data, int len, char *digest);
int ima_calc_buffer_hash(const void *data, int len,
			 struct ima_digest_data *hash);
int ima_calc_boot_aggregate(char *digest);
int ima_calc_boot_aggregate(char *digest);
void ima_add_violation(struct inode *inode, const unsigned char *filename,
void ima_add_violation(struct inode *inode, const unsigned char *filename,
		       const char *op, const char *cause);
		       const char *op, const char *cause);
+24 −8
Original line number Original line Diff line number Diff line
@@ -44,6 +44,7 @@ int ima_store_template(struct ima_template_entry *entry,
	const char *op = "add_template_measure";
	const char *op = "add_template_measure";
	const char *audit_cause = "hashing_error";
	const char *audit_cause = "hashing_error";
	int result;
	int result;
	struct ima_digest_data hash;


	memset(entry->digest, 0, sizeof(entry->digest));
	memset(entry->digest, 0, sizeof(entry->digest));
	entry->template_name = IMA_TEMPLATE_NAME;
	entry->template_name = IMA_TEMPLATE_NAME;
@@ -51,14 +52,14 @@ int ima_store_template(struct ima_template_entry *entry,


	if (!violation) {
	if (!violation) {
		result = ima_calc_buffer_hash(&entry->template,
		result = ima_calc_buffer_hash(&entry->template,
						entry->template_len,
					      entry->template_len, &hash);
						entry->digest);
		if (result < 0) {
		if (result < 0) {
			integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
			integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
					    entry->template_name, op,
					    entry->template_name, op,
					    audit_cause, result, 0);
					    audit_cause, result, 0);
			return result;
			return result;
		}
		}
		memcpy(entry->digest, hash.digest, hash.length);
	}
	}
	result = ima_add_template_entry(entry, violation, op, inode);
	result = ima_add_template_entry(entry, violation, op, inode);
	return result;
	return result;
@@ -147,8 +148,9 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
	if (!(iint->flags & IMA_COLLECTED)) {
	if (!(iint->flags & IMA_COLLECTED)) {
		u64 i_version = file_inode(file)->i_version;
		u64 i_version = file_inode(file)->i_version;


		iint->ima_xattr.type = IMA_XATTR_DIGEST;
		/* use default hash algorithm */
		result = ima_calc_file_hash(file, iint->ima_xattr.digest);
		iint->ima_hash.algo = ima_hash_algo;
		result = ima_calc_file_hash(file, &iint->ima_hash);
		if (!result) {
		if (!result) {
			iint->version = i_version;
			iint->version = i_version;
			iint->flags |= IMA_COLLECTED;
			iint->flags |= IMA_COLLECTED;
@@ -196,7 +198,21 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
		return;
		return;
	}
	}
	memset(&entry->template, 0, sizeof(entry->template));
	memset(&entry->template, 0, sizeof(entry->template));
	memcpy(entry->template.digest, iint->ima_xattr.digest, IMA_DIGEST_SIZE);
	if (iint->ima_hash.algo != ima_hash_algo) {
		struct ima_digest_data hash;

		hash.algo = ima_hash_algo;
		result = ima_calc_file_hash(file, &hash);
		if (result)
			integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
					    filename, "collect_data", "failed",
					    result, 0);
		else
			memcpy(entry->template.digest, hash.digest,
			       hash.length);
	} else
		memcpy(entry->template.digest, iint->ima_hash.digest,
		       iint->ima_hash.length);
	strcpy(entry->template.file_name,
	strcpy(entry->template.file_name,
	       (strlen(filename) > IMA_EVENT_NAME_LEN_MAX) ?
	       (strlen(filename) > IMA_EVENT_NAME_LEN_MAX) ?
	       file->f_dentry->d_name.name : filename);
	       file->f_dentry->d_name.name : filename);
@@ -212,14 +228,14 @@ void ima_audit_measurement(struct integrity_iint_cache *iint,
			   const unsigned char *filename)
			   const unsigned char *filename)
{
{
	struct audit_buffer *ab;
	struct audit_buffer *ab;
	char hash[(IMA_DIGEST_SIZE * 2) + 1];
	char hash[(iint->ima_hash.length * 2) + 1];
	int i;
	int i;


	if (iint->flags & IMA_AUDITED)
	if (iint->flags & IMA_AUDITED)
		return;
		return;


	for (i = 0; i < IMA_DIGEST_SIZE; i++)
	for (i = 0; i < iint->ima_hash.length; i++)
		hex_byte_pack(hash + (i * 2), iint->ima_xattr.digest[i]);
		hex_byte_pack(hash + (i * 2), iint->ima_hash.digest[i]);
	hash[i * 2] = '\0';
	hash[i * 2] = '\0';


	ab = audit_log_start(current->audit_context, GFP_KERNEL,
	ab = audit_log_start(current->audit_context, GFP_KERNEL,
Loading