[PATCH v2 ima-evm-utils 3/3] Verify an fs-verity file digest based signature

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



ima-evm-utils does not attempt to calculate or even read the fs-verity
file hash, but can verify the fs-verity signature based on the fsverity
file hash, both contained in the measurement list record.

For the time being only fs-verity supports signature format v3 (sigv3).
To differentiate between the existing IMA and fs-verity file signatures,
modify the verify_hash() 'sig' argument to be a pointer to the entire
xattr, including the xattr type.

Example:
evmctl ima_measurement --key <DER encoded public key> \
 --verify-sig /sys/kernel/security/ima/binary_runtime_measurements

Signed-off-by: Mimi Zohar <zohar@xxxxxxxxxxxxx>
---
 src/evmctl.c    | 11 +++++++++--
 src/libimaevm.c | 50 +++++++++++++++++++++++++++++++++++++------------
 2 files changed, 47 insertions(+), 14 deletions(-)

diff --git a/src/evmctl.c b/src/evmctl.c
index 9152b0a5c7c2..593eed80f96a 100644
--- a/src/evmctl.c
+++ b/src/evmctl.c
@@ -909,7 +909,7 @@ static int verify_evm(const char *file)
 		return mdlen;
 	assert(mdlen <= sizeof(hash));
 
-	return verify_hash(file, hash, mdlen, sig + 1, len - 1);
+	return verify_hash(file, hash, mdlen, sig, len);
 }
 
 static int cmd_verify_evm(struct command *cmd)
@@ -1572,7 +1572,8 @@ void ima_ng_show(struct template_entry *entry)
 	fieldp += field_len;
 	total_len -= field_len;
 
-	if (!strcmp(entry->name, "ima-sig")) {
+	if (!strcmp(entry->name, "ima-sig") ||
+	    !strcmp(entry->name, "ima-sigv2")) {
 		/* get signature */
 		field_len = *(uint32_t *)fieldp;
 		fieldp += sizeof(field_len);
@@ -1618,11 +1619,17 @@ void ima_ng_show(struct template_entry *entry)
 			log_info(" ");
 			log_dump(sig, sig_len);
 		}
+
+		/*
+		 * Either verify the signature against the hash contained in
+		 * the measurement list or calculate the hash.
+		 */
 		if (verify_list_sig)
 			err = ima_verify_signature(path, sig, sig_len,
 						   digest, digest_len);
 		else
 			err = ima_verify_signature(path, sig, sig_len, NULL, 0);
+
 		if (!err && imaevm_params.verbose > LOG_INFO)
 			log_info("%s: verification is OK\n", path);
 	} else {
diff --git a/src/libimaevm.c b/src/libimaevm.c
index 7c2ed5fb0556..8a37551132d6 100644
--- a/src/libimaevm.c
+++ b/src/libimaevm.c
@@ -534,11 +534,21 @@ int calc_hash_sigv3(enum evm_ima_xattr_type type, const char *algo,
 		return -EINVAL;
 	}
 
-	if ((hash_algo = imaevm_get_hash_algo(algo)) < 0) {
-		log_err("Hash algorithm %s not supported\n", algo);
-		return -EINVAL;
+	/*
+	 * Calculating the hash is based on the fsverity hash algorithm,
+	 * while verifying the signature is based on the hash algorithm
+	 * contained in the signature header.
+	 */
+	if (algo) {
+		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;
+	} else {
+		algo = imaevm_params.hash_algo;
+		file_id.hash_algorithm = imaevm_get_hash_algo(algo);
 	}
-	file_id.hash_algorithm = hash_algo;
 
 	md = EVP_get_digestbyname(algo);
 	if (!md) {
@@ -622,7 +632,7 @@ int imaevm_hash_algo_from_sig(unsigned char *sig)
 		default:
 			return -1;
 		}
-	} else if (sig[0] == DIGSIG_VERSION_2) {
+	} else if (sig[0] == DIGSIG_VERSION_2 || sig[0] == DIGSIG_VERSION_3) {
 		hashalgo = ((struct signature_v2_hdr *)sig)->hash_algo;
 		if (hashalgo >= PKEY_HASH__LAST)
 			return -1;
@@ -634,8 +644,11 @@ int imaevm_hash_algo_from_sig(unsigned char *sig)
 int verify_hash(const char *file, const unsigned char *hash, int size, unsigned char *sig,
 		int siglen)
 {
+	unsigned char sigv3_hash[MAX_DIGEST_SIZE];
+	int ret;
+
 	/* Get signature type from sig header */
-	if (sig[0] == DIGSIG_VERSION_1) {
+	if (sig[1] == DIGSIG_VERSION_1) {
 		const char *key = NULL;
 
 		/* Read pubkey from RSA key */
@@ -643,9 +656,17 @@ int verify_hash(const char *file, const unsigned char *hash, int size, unsigned
 			key = "/etc/keys/pubkey_evm.pem";
 		else
 			key = imaevm_params.keyfile;
-		return verify_hash_v1(file, hash, size, sig, siglen, key);
-	} else if (sig[0] == DIGSIG_VERSION_2) {
-		return verify_hash_v2(file, hash, size, sig, siglen);
+		return verify_hash_v1(file, hash, size, sig + 1, siglen - 1,
+				      key);
+	} else if (sig[1] == DIGSIG_VERSION_2) {
+		return verify_hash_v2(file, hash, size, sig + 1, siglen - 1);
+	} else if (sig[1] == DIGSIG_VERSION_3) {
+		ret = calc_hash_sigv3(sig[0], NULL, hash, sigv3_hash);
+		if (ret < 0)
+			return ret;
+
+		return verify_hash_v2(file, sigv3_hash, size, sig + 1,
+				      siglen - 1);
 	} else
 		return -1;
 }
@@ -656,11 +677,16 @@ int ima_verify_signature(const char *file, unsigned char *sig, int siglen,
 	unsigned char hash[MAX_DIGEST_SIZE];
 	int hashlen, sig_hash_algo;
 
-	if (sig[0] != EVM_IMA_XATTR_DIGSIG) {
+	if ((sig[0] != EVM_IMA_XATTR_DIGSIG) && (sig[0] != IMA_VERITY_DIGSIG)) {
 		log_err("%s: xattr ima has no signature\n", file);
 		return -1;
 	}
 
+	if (!digest && sig[0] == IMA_VERITY_DIGSIG) {
+		log_err("%s: calculating the fs-verity digest is not supported\n", file);
+		return -1;
+	}
+
 	sig_hash_algo = imaevm_hash_algo_from_sig(sig + 1);
 	if (sig_hash_algo < 0) {
 		log_err("%s: Invalid signature\n", file);
@@ -674,14 +700,14 @@ int ima_verify_signature(const char *file, unsigned char *sig, int siglen,
 	 * measurement list, not by calculating the local file digest.
 	 */
 	if (digestlen > 0)
-	    return verify_hash(file, digest, digestlen, sig + 1, siglen - 1);
+		return verify_hash(file, digest, digestlen, sig, siglen);
 
 	hashlen = ima_calc_hash(file, hash);
 	if (hashlen <= 1)
 		return hashlen;
 	assert(hashlen <= sizeof(hash));
 
-	return verify_hash(file, hash, hashlen, sig + 1, siglen - 1);
+	return verify_hash(file, hash, hashlen, sig, siglen);
 }
 
 /*
-- 
2.27.0




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux Kernel]     [Linux Kernel Hardening]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux