Hello community, here is the log from the commit of package ima-evm-utils for openSUSE:Factory checked in at 2018-03-20 21:59:04 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ima-evm-utils (Old) and /work/SRC/openSUSE:Factory/.ima-evm-utils.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ima-evm-utils" Tue Mar 20 21:59:04 2018 rev:13 rq:587839 version:1.1 Changes: -------- --- /work/SRC/openSUSE:Factory/ima-evm-utils/ima-evm-utils.changes 2017-11-27 22:18:57.293450564 +0100 +++ /work/SRC/openSUSE:Factory/.ima-evm-utils.new/ima-evm-utils.changes 2018-03-20 21:59:29.147570643 +0100 @@ -1,0 +2,16 @@ +Fri Mar 16 09:23:01 UTC 2018 - [email protected] + +- Update to version 1.1 + * Support the new openssl 1.1 api + * Support for validating multiple pcrs + * Verify the measurement list signature based on the list digest + * Verify the "ima-sig" measurement list using multiple keys + * Fixed parsing the measurement template data field length + * Portable & immutable EVM signatures (new format) + * Multiple fixes that have been lingering in the next branch. Some + are for experimental features that are not yet supported in the + kernel. +- Drop ima-evm-utils-openssl1.patch (not needed any more as IMA got + backward compatible support for openssl 1.1). + +------------------------------------------------------------------- Old: ---- ima-evm-utils-1.0.tar.gz ima-evm-utils-openssl1.patch New: ---- ima-evm-utils-1.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ima-evm-utils.spec ++++++ --- /var/tmp/diff_new_pack.gXbrIK/_old 2018-03-20 21:59:29.875544433 +0100 +++ /var/tmp/diff_new_pack.gXbrIK/_new 2018-03-20 21:59:29.879544289 +0100 @@ -1,7 +1,7 @@ # # spec file for package ima-evm-utils # -# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,15 +19,14 @@ %define sover 0 %define libname libimaevm%{sover} Name: ima-evm-utils -Version: 1.0 +Version: 1.1 Release: 0 Summary: IMA/EVM control utility -License: LGPL-2.1+ +License: LGPL-2.1-or-later Group: System/Base Url: http://sourceforge.net/projects/linux-ima/ Source0: http://downloads.sourceforge.net/project/linux-ima/ima-evm-utils/%{name}-%{version}.tar.gz Patch2: ima-evm-utils-fix-docbook-xsl-directory.patch -Patch3: ima-evm-utils-openssl1.patch BuildRequires: asciidoc BuildRequires: autoconf BuildRequires: automake @@ -76,9 +75,6 @@ %if 0%{?suse_version} >= 1315 %patch2 -p1 %endif -if pkg-config --atleast-version=1.1 openssl; then -%patch3 -p1 -fi %build autoreconf -fiv ++++++ ima-evm-utils-1.0.tar.gz -> ima-evm-utils-1.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ima-evm-utils-1.0/ChangeLog new/ima-evm-utils-1.1/ChangeLog --- old/ima-evm-utils-1.0/ChangeLog 2015-07-30 20:28:53.000000000 +0200 +++ new/ima-evm-utils-1.1/ChangeLog 2018-02-15 14:02:19.000000000 +0100 @@ -1,3 +1,16 @@ +2018-01-28 Mimi Zohar <[email protected]> + + version 1.1 + * Support the new openssl 1.1 api + * Support for validating multiple pcrs + * Verify the measurement list signature based on the list digest + * Verify the "ima-sig" measurement list using multiple keys + * Fixed parsing the measurement template data field length + * Portable & immutable EVM signatures (new format) + * Multiple fixes that have been lingering in the next branch. Some + are for experimental features that are not yet supported in the + kernel. + 2014-07-30 Dmitry Kasatkin <[email protected]> version 1.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ima-evm-utils-1.0/README new/ima-evm-utils-1.1/README --- old/ima-evm-utils-1.0/README 2015-07-30 20:28:53.000000000 +0200 +++ new/ima-evm-utils-1.1/README 2018-02-15 14:02:19.000000000 +0100 @@ -26,12 +26,12 @@ --version help <command> import [--rsa] pubkey keyring - sign [-r] [--imahash | --imasig ] [--key key] [--pass password] file + sign [-r] [--imahash | --imasig ] [--portable] [--key key] [--pass password] file verify file ima_sign [--sigfile] [--key key] [--pass password] file ima_verify file ima_hash file - ima_measurement file + ima_measurement [--key "key1, key2, ..."] [--list] file ima_fix [-t fdsxm] path sign_hash [--key key] [--pass password] hmac [--imahash | --imasig ] file @@ -46,6 +46,7 @@ -f, --sigfile store IMA signature in .sig file instead of xattr --rsa use RSA key type and signing scheme v1 -k, --key path to signing key (default: /etc/keys/{privkey,pubkey}_evm.pem) + -o, --portable generate portable EVM signatures -p, --pass password for encrypted signing key -r, --recursive recurse into directories (sign) -t, --type file types to fix 'fdsxm' (f: file, d: directory, s: block/char/symlink) @@ -95,7 +96,8 @@ filesystem UUID into HMAC and enabled by default. Therefore evmctl also includes fsuuid by default. Providing '--uuid' option without parameter allows to disable usage of fs uuid. Providing '--uuid=UUID' option with parameter allows to use -custom UUID. +custom UUID. Providing the '--portable' option will disable usage of the fs uuid +and also the inode number and generation. Kernel configuration option CONFIG_EVM_EXTRA_SMACK_XATTRS controls whether to include additional SMACK extended attributes into HMAC. They are following: @@ -142,7 +144,7 @@ keyctl pipe `keyctl search @u user kmk` > /etc/keys/kmk # create the EVM encrypted key - keyctl add encrypted evm-key "new user:kmk 32" @u + keyctl add encrypted evm-key "new user:kmk 64" @u keyctl pipe `keyctl search @u encrypted evm-key` >/etc/keys/evm-key diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ima-evm-utils-1.0/build-static.sh new/ima-evm-utils-1.1/build-static.sh --- old/ima-evm-utils-1.0/build-static.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/ima-evm-utils-1.1/build-static.sh 2018-02-15 14:02:19.000000000 +0100 @@ -0,0 +1,4 @@ +#!/bin/sh + +gcc -static -o evmctl.static -include config.h src/evmctl.c src/libimaevm.c -lcrypto -lkeyutils -ldl + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ima-evm-utils-1.0/configure.ac new/ima-evm-utils-1.1/configure.ac --- old/ima-evm-utils-1.0/configure.ac 2015-07-30 20:28:53.000000000 +0200 +++ new/ima-evm-utils-1.1/configure.ac 2018-02-15 14:02:19.000000000 +0100 @@ -1,7 +1,7 @@ # autoconf script AC_PREREQ([2.65]) -AC_INIT(ima-evm-utils, 1.0, [email protected]) +AC_INIT(ima-evm-utils, 1.1, [email protected]) AM_INIT_AUTOMAKE AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ima-evm-utils-1.0/packaging/ima-evm-utils.spec new/ima-evm-utils-1.1/packaging/ima-evm-utils.spec --- old/ima-evm-utils-1.0/packaging/ima-evm-utils.spec 2015-07-30 20:28:53.000000000 +0200 +++ new/ima-evm-utils-1.1/packaging/ima-evm-utils.spec 2018-02-15 14:02:19.000000000 +0100 @@ -1,5 +1,5 @@ Name: ima-evm-utils -Version: 1.0 +Version: 1.1 Release: 1%{?dist} Summary: ima-evm-utils - IMA/EVM control utility Group: System/Libraries diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ima-evm-utils-1.0/src/evmctl.c new/ima-evm-utils-1.1/src/evmctl.c --- old/ima-evm-utils-1.0/src/evmctl.c 2015-07-30 20:28:53.000000000 +0200 +++ new/ima-evm-utils-1.1/src/evmctl.c 2018-02-15 14:02:19.000000000 +0100 @@ -104,15 +104,26 @@ static int digsig; static int sigfile; static char *uuid_str; +static char *ino_str; +static char *uid_str; +static char *gid_str; +static char *mode_str; +static char *generation_str; +static char *caps_str; +static char *ima_str; +static char *selinux_str; static char *search_type; +static int measurement_list; static int recursive; static int msize; static dev_t fs_dev; static bool evm_immutable; +static bool evm_portable; -#define HMAC_FLAG_UUID 0x0001 -#define HMAC_FLAG_UUID_SET 0x0002 -static unsigned long hmac_flags = HMAC_FLAG_UUID; +#define HMAC_FLAG_NO_UUID 0x0001 +#define HMAC_FLAG_CAPS_SET 0x0002 + +static unsigned long hmac_flags; typedef int (*find_cb_t)(const char *path); static int find(const char *path, int dts, find_cb_t func); @@ -200,7 +211,7 @@ return -1; } -static int hex2bin(uint8_t *dst, const char *src, size_t count) +static int hex2bin(void *dst, const char *src, size_t count) { int hi, lo; @@ -214,7 +225,7 @@ if ((hi < 0) || (lo < 0)) return -1; - *dst++ = (hi << 4) | lo; + *(uint8_t *)dst++ = (hi << 4) | lo; } return 0; } @@ -275,7 +286,7 @@ FILE *fp; size_t len; - if (hmac_flags & HMAC_FLAG_UUID_SET) + if (uuid_str) return pack_uuid(uuid_str, uuid); dev = st->st_dev; @@ -305,7 +316,7 @@ struct stat st; int err; uint32_t generation = 0; - EVP_MD_CTX ctx; + EVP_MD_CTX *pctx; unsigned int mdlen; char **xattrname; char xattr_value[1024]; @@ -314,16 +325,33 @@ char uuid[16]; struct h_misc_64 hmac_misc; int hmac_size; +#if OPENSSL_VERSION_NUMBER < 0x10100000 + EVP_MD_CTX ctx; + pctx = &ctx; +#else + pctx = EVP_MD_CTX_new(); +#endif if (lstat(file, &st)) { log_err("Failed to stat: %s\n", file); return -1; } + if (generation_str) + generation = strtoul(generation_str, NULL, 10); + if (ino_str) + st.st_ino = strtoul(ino_str, NULL, 10); + if (uid_str) + st.st_uid = strtoul(uid_str, NULL, 10); + if (gid_str) + st.st_gid = strtoul(gid_str, NULL, 10); + if (mode_str) + st.st_mode = strtoul(mode_str, NULL, 10); + if (!evm_immutable) { - if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) { - /* we cannot at the momement to get generation of special files.. - * kernel API does not support it */ + if ((S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) && !generation_str) { + /* we cannot at the momement to get generation of + special files kernel API does not support it */ int fd = open(file, 0); if (fd < 0) { @@ -332,6 +360,7 @@ } if (ioctl(fd, FS_IOC_GETVERSION, &generation)) { log_err("ioctl() failed\n"); + close(fd); return -1; } close(fd); @@ -345,26 +374,39 @@ return -1; } - err = EVP_DigestInit(&ctx, EVP_sha1()); + err = EVP_DigestInit(pctx, EVP_sha1()); if (!err) { log_err("EVP_DigestInit() failed\n"); return 1; } for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) { - err = lgetxattr(file, *xattrname, xattr_value, sizeof(xattr_value)); - if (err < 0) { - log_info("no xattr: %s\n", *xattrname); - continue; - } - if (!find_xattr(list, list_size, *xattrname)) { - log_info("skipping xattr: %s\n", *xattrname); - continue; + if (!strcmp(*xattrname, XATTR_NAME_SELINUX) && selinux_str) { + strcpy(xattr_value, selinux_str); + err = strlen(selinux_str) + 1; + } else if (!strcmp(*xattrname, XATTR_NAME_IMA) && ima_str) { + hex2bin(xattr_value, ima_str, strlen(ima_str) / 2); + err = strlen(ima_str) / 2; + } else if (!strcmp(*xattrname, XATTR_NAME_CAPS) && (hmac_flags & HMAC_FLAG_CAPS_SET)) { + if (!caps_str) + continue; + strcpy(xattr_value, caps_str); + err = strlen(caps_str); + } else { + err = lgetxattr(file, *xattrname, xattr_value, sizeof(xattr_value)); + if (err < 0) { + log_info("no xattr: %s\n", *xattrname); + continue; + } + if (!find_xattr(list, list_size, *xattrname)) { + log_info("skipping xattr: %s\n", *xattrname); + continue; + } } /*log_debug("name: %s, value: %s, size: %d\n", *xattrname, xattr_value, err);*/ log_info("name: %s, size: %d\n", *xattrname, err); log_debug_dump(xattr_value, err); - err = EVP_DigestUpdate(&ctx, xattr_value, err); + err = EVP_DigestUpdate(pctx, xattr_value, err); if (!err) { log_err("EVP_DigestUpdate() failed\n"); return 1; @@ -384,8 +426,10 @@ struct h_misc *hmac = (struct h_misc *)&hmac_misc; hmac_size = sizeof(*hmac); - hmac->ino = st.st_ino; - hmac->generation = generation; + if (!evm_portable) { + hmac->ino = st.st_ino; + hmac->generation = generation; + } hmac->uid = st.st_uid; hmac->gid = st.st_gid; hmac->mode = st.st_mode; @@ -393,8 +437,10 @@ struct h_misc_64 *hmac = (struct h_misc_64 *)&hmac_misc; hmac_size = sizeof(*hmac); - hmac->ino = st.st_ino; - hmac->generation = generation; + if (!evm_portable) { + hmac->ino = st.st_ino; + hmac->generation = generation; + } hmac->uid = st.st_uid; hmac->gid = st.st_gid; hmac->mode = st.st_mode; @@ -402,8 +448,10 @@ struct h_misc_32 *hmac = (struct h_misc_32 *)&hmac_misc; hmac_size = sizeof(*hmac); - hmac->ino = st.st_ino; - hmac->generation = generation; + if (!evm_portable) { + hmac->ino = st.st_ino; + hmac->generation = generation; + } hmac->uid = st.st_uid; hmac->gid = st.st_gid; hmac->mode = st.st_mode; @@ -412,25 +460,26 @@ log_debug("hmac_misc (%d): ", hmac_size); log_debug_dump(&hmac_misc, hmac_size); - err = EVP_DigestUpdate(&ctx, &hmac_misc, hmac_size); + err = EVP_DigestUpdate(pctx, &hmac_misc, hmac_size); if (!err) { log_err("EVP_DigestUpdate() failed\n"); return 1; } - if (!evm_immutable && (hmac_flags & HMAC_FLAG_UUID)) { + if (!evm_immutable && !evm_portable && + !(hmac_flags & HMAC_FLAG_NO_UUID)) { err = get_uuid(&st, uuid); if (err) return -1; - err = EVP_DigestUpdate(&ctx, (const unsigned char *)uuid, sizeof(uuid)); + err = EVP_DigestUpdate(pctx, (const unsigned char *)uuid, sizeof(uuid)); if (!err) { log_err("EVP_DigestUpdate() failed\n"); return 1; } } - err = EVP_DigestFinal(&ctx, hash, &mdlen); + err = EVP_DigestFinal(pctx, hash, &mdlen); if (!err) { log_err("EVP_DigestFinal() failed\n"); return 1; @@ -455,7 +504,10 @@ /* add header */ len++; - sig[0] = EVM_IMA_XATTR_DIGSIG; + if (evm_portable) + sig[0] = EVM_XATTR_PORTABLE_DIGSIG; + else + sig[0] = EVM_IMA_XATTR_DIGSIG; if (evm_immutable) sig[1] = 3; /* immutable signature version */ @@ -713,12 +765,13 @@ return -1; } - return verify_hash(hash, sizeof(hash), sig + 1, len - 1); + return verify_hash(file, hash, sizeof(hash), sig + 1, len - 1); } static int cmd_verify_evm(struct command *cmd) { char *file = g_argv[optind++]; + int err; if (!file) { log_err("Parameters missing\n"); @@ -726,7 +779,10 @@ return -1; } - return verify_evm(file); + err = verify_evm(file); + if (!err && params.verbose >= LOG_INFO) + log_info("%s: verification is OK\n", file); + return err; } static int verify_ima(const char *file) @@ -734,35 +790,69 @@ unsigned char sig[1024]; int len; - if (xattr) { - len = lgetxattr(file, "security.ima", sig, sizeof(sig)); - if (len < 0) { - log_err("getxattr failed: %s\n", file); - return len; - } - } - if (sigfile) { void *tmp = file2bin(file, "sig", &len); memcpy(sig, tmp, len); free(tmp); + } else { + len = lgetxattr(file, "security.ima", sig, sizeof(sig)); + if (len < 0) { + log_err("getxattr failed: %s\n", file); + return len; + } } - return ima_verify_signature(file, sig, len); + return ima_verify_signature(file, sig, len, NULL, 0); } static int cmd_verify_ima(struct command *cmd) { char *file = g_argv[optind++]; + int err; + errno = 0; if (!file) { log_err("Parameters missing\n"); print_usage(cmd); return -1; } - return verify_ima(file); + err = verify_ima(file); + if (!err && params.verbose >= LOG_INFO) + log_info("%s: verification is OK\n", file); + return err; +} + +static int cmd_convert(struct command *cmd) +{ + char *inkey; + unsigned char _pub[1024], *pub = _pub; + int len, err = 0; + char name[20]; + uint8_t keyid[8]; + RSA *key; + + params.x509 = 0; + + inkey = g_argv[optind++]; + if (!inkey) { + inkey = params.x509 ? "/etc/keys/x509_evm.der" : + "/etc/keys/pubkey_evm.pem"; + } + + key = read_pub_key(inkey, params.x509); + if (!key) + return 1; + + len = key2bin(key, pub); + calc_keyid_v1(keyid, name, pub, len); + + bin2file(inkey, "bin", pub, len); + bin2file(inkey, "keyid", (const unsigned char *)name, strlen(name)); + + RSA_free(key); + return err; } static int cmd_import(struct command *cmd) @@ -837,6 +927,42 @@ return err; } +static int setxattr_ima(const char *file, char *sig_file) +{ + unsigned char *sig; + int len, err; + + if (sig_file) + sig = file2bin(sig_file, NULL, &len); + else + sig = file2bin(file, "sig", &len); + if (!sig) + return 0; + + err = lsetxattr(file, "security.ima", sig, len, 0); + if (err < 0) + log_err("setxattr failed: %s\n", file); + free(sig); + return err; +} + +static int cmd_setxattr_ima(struct command *cmd) +{ + char *file, *sig = NULL; + + if (sigfile) + sig = g_argv[optind++]; + file = g_argv[optind++]; + + if (!file) { + log_err("Parameters missing\n"); + print_usage(cmd); + return -1; + } + + return setxattr_ima(file, sig); +} + #define MAX_KEY_SIZE 128 static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *hash) @@ -844,7 +970,7 @@ struct stat st; int err = -1; uint32_t generation = 0; - HMAC_CTX ctx; + HMAC_CTX *pctx; unsigned int mdlen; char **xattrname; unsigned char xattr_value[1024]; @@ -855,6 +981,12 @@ ssize_t list_size; struct h_misc_64 hmac_misc; int hmac_size; +#if OPENSSL_VERSION_NUMBER < 0x10100000 + HMAC_CTX ctx; + pctx = &ctx; +#else + pctx = HMAC_CTX_new(); +#endif key = file2bin(keyfile, NULL, &keylen); if (!key) { @@ -887,6 +1019,7 @@ } if (ioctl(fd, FS_IOC_GETVERSION, &generation)) { log_err("ioctl() failed\n"); + close(fd); goto out; } close(fd); @@ -900,7 +1033,7 @@ goto out; } - err = !HMAC_Init(&ctx, evmkey, sizeof(evmkey), EVP_sha1()); + err = !HMAC_Init_ex(pctx, evmkey, sizeof(evmkey), EVP_sha1(), NULL); if (err) { log_err("HMAC_Init() failed\n"); goto out; @@ -919,7 +1052,7 @@ /*log_debug("name: %s, value: %s, size: %d\n", *xattrname, xattr_value, err);*/ log_info("name: %s, size: %d\n", *xattrname, err); log_debug_dump(xattr_value, err); - err = !HMAC_Update(&ctx, xattr_value, err); + err = !HMAC_Update(pctx, xattr_value, err); if (err) { log_err("HMAC_Update() failed\n"); goto out_ctx_cleanup; @@ -960,16 +1093,20 @@ log_debug("hmac_misc (%d): ", hmac_size); log_debug_dump(&hmac_misc, hmac_size); - err = !HMAC_Update(&ctx, (const unsigned char *)&hmac_misc, hmac_size); + err = !HMAC_Update(pctx, (const unsigned char *)&hmac_misc, hmac_size); if (err) { log_err("HMAC_Update() failed\n"); goto out_ctx_cleanup; } - err = !HMAC_Final(&ctx, hash, &mdlen); + err = !HMAC_Final(pctx, hash, &mdlen); if (err) log_err("HMAC_Final() failed\n"); out_ctx_cleanup: - HMAC_CTX_cleanup(&ctx); +#if OPENSSL_VERSION_NUMBER < 0x10100000 + HMAC_CTX_cleanup(pctx); +#else + HMAC_CTX_free(pctx); +#endif out: free(key); return err ?: mdlen; @@ -1137,18 +1274,23 @@ return do_cmd(cmd, ima_clear); } -static char *pcrs = "/sys/class/misc/tpm0/device/pcrs"; +static char *pcrs = "/sys/class/tpm/tpm0/device/pcrs"; /* Kernels >= 4.0 */ +static char *misc_pcrs = "/sys/class/misc/tpm0/device/pcrs"; static int tpm_pcr_read(int idx, uint8_t *pcr, int len) { FILE *fp; char *p, pcr_str[7], buf[70]; /* length of the TPM string */ + int result = -1; sprintf(pcr_str, "PCR-%d", idx); fp = fopen(pcrs, "r"); + if (!fp) + fp = fopen(misc_pcrs, "r"); + if (!fp) { - log_err("Unable to open %s\n", pcrs); + log_err("Unable to open %s or %s\n", pcrs, misc_pcrs); return -1; } @@ -1158,11 +1300,12 @@ break; if (!strncmp(p, pcr_str, 6)) { hex2bin(pcr, p + 7, len); - return 0; + result = 0; + break; } } fclose(fp); - return -1; + return result; } #define TCG_EVENT_NAME_LEN_MAX 255 @@ -1197,7 +1340,7 @@ SHA1_Final(pcr, &ctx); } -static int ima_verify_tamplate_hash(struct template_entry *entry) +static int ima_verify_template_hash(struct template_entry *entry) { uint8_t digest[SHA_DIGEST_LENGTH]; @@ -1227,9 +1370,10 @@ int total_len = entry->template_len, digest_len, len, sig_len; uint8_t *digest, *sig = NULL; char *algo, *path; + int err; /* get binary digest */ - field_len = *(uint8_t *)fieldp; + field_len = *(uint32_t *)fieldp; fieldp += sizeof(field_len); total_len -= sizeof(field_len); @@ -1243,7 +1387,7 @@ total_len -= field_len; /* get path */ - field_len = *(uint8_t *)fieldp; + field_len = *(uint32_t *)fieldp; fieldp += sizeof(field_len); total_len -= sizeof(field_len); @@ -1255,7 +1399,7 @@ if (!strcmp(entry->name, "ima-sig")) { /* get signature */ - field_len = *(uint8_t *)fieldp; + field_len = *(uint32_t *)fieldp; fieldp += sizeof(field_len); total_len -= sizeof(field_len); @@ -1270,18 +1414,30 @@ } /* ascii_runtime_measurements */ - log_info("%d ", entry->header.pcr); - log_dump_n(entry->header.digest, sizeof(entry->header.digest)); - log_info(" %s %s", entry->name, algo); - log_dump_n(digest, digest_len); - log_info(" %s", path); + if (params.verbose > LOG_INFO) { + log_info("%d ", entry->header.pcr); + log_dump_n(entry->header.digest, sizeof(entry->header.digest)); + log_info(" %s %s", entry->name, algo); + log_dump_n(digest, digest_len); + log_info(" %s", path); + } if (sig) { - log_info(" "); - log_dump(sig, sig_len); - ima_verify_signature(path, sig, sig_len); - } else - log_info("\n"); + if (params.verbose > LOG_INFO) { + log_info(" "); + log_dump(sig, sig_len); + } + if (measurement_list) + err = ima_verify_signature(path, sig, sig_len, + digest, digest_len); + else + err = ima_verify_signature(path, sig, sig_len, NULL, 0); + if (!err && params.verbose > LOG_INFO) + log_info("%s: verification is OK\n", path); + } else { + if (params.verbose > LOG_INFO) + log_info("\n"); + } if (total_len) log_err("Remain unprocessed data: %d\n", total_len); @@ -1289,12 +1445,16 @@ static int ima_measurement(const char *file) { - uint8_t pcr[SHA_DIGEST_LENGTH] = {0,}; - uint8_t pcr10[SHA_DIGEST_LENGTH]; + uint8_t pcr[NUM_PCRS][SHA_DIGEST_LENGTH] = {{0}}; + uint8_t hwpcr[SHA_DIGEST_LENGTH]; struct template_entry entry = { .template = 0 }; FILE *fp; int err = -1; + bool verify_failed = false; + int i; + errno = 0; + memset(zero, 0, SHA_DIGEST_LENGTH); memset(fox, 0xff, SHA_DIGEST_LENGTH); log_debug("Initial PCR value: "); @@ -1306,8 +1466,13 @@ return -1; } + /* Support multiple public keys */ + if (params.keyfile) + init_public_keys(params.keyfile); + while (fread(&entry.header, sizeof(entry.header), 1, fp)) { - ima_extend_pcr(pcr, entry.header.digest, SHA_DIGEST_LENGTH); + ima_extend_pcr(pcr[entry.header.pcr], entry.header.digest, + SHA_DIGEST_LENGTH); if (!fread(entry.name, entry.header.name_len, 1, fp)) { log_err("Unable to read template name\n"); @@ -1333,7 +1498,7 @@ } if (validate) - ima_verify_tamplate_hash(&entry); + ima_verify_template_hash(&entry); if (!strcmp(entry.name, "ima")) ima_show(&entry); @@ -1341,23 +1506,29 @@ ima_ng_show(&entry); } - tpm_pcr_read(10, pcr10, sizeof(pcr10)); - log_info("PCRAgg: "); - log_dump(pcr, sizeof(pcr)); + for (i = 0; i < NUM_PCRS; i++) { + if (memcmp(pcr[i], zero, SHA_DIGEST_LENGTH) == 0) + continue; - log_info("PCR-10: "); - log_dump(pcr10, sizeof(pcr10)); + log_info("PCRAgg %.2d: ", i); + log_dump(pcr[i], SHA_DIGEST_LENGTH); - if (memcmp(pcr, pcr10, sizeof(pcr))) { - log_err("PCRAgg does not match PCR-10\n"); - goto out; + tpm_pcr_read(i, hwpcr, sizeof(hwpcr)); + log_info("HW PCR-%d: ", i); + log_dump(hwpcr, sizeof(hwpcr)); + + if (memcmp(pcr[i], hwpcr, sizeof(SHA_DIGEST_LENGTH)) != 0) { + log_err("PCRAgg %d does not match HW PCR-%d\n", i, i); + + verify_failed = true; + } } - err = 0; + if (!verify_failed) + err = 0; out: fclose(fp); - return err; } @@ -1450,6 +1621,7 @@ " -f, --sigfile store IMA signature in .sig file instead of xattr\n" " --rsa use RSA key type and signing scheme v1\n" " -k, --key path to signing key (default: /etc/keys/{privkey,pubkey}_evm.pem)\n" + " -o, --portable generate portable EVM signatures\n" " -p, --pass password for encrypted signing key\n" " -r, --recursive recurse into directories (sign)\n" " -t, --type file types to fix 'fdsxm' (f: file, d: directory, s: block/char/symlink)\n" @@ -1460,6 +1632,15 @@ " --smack use extra SMACK xattrs for EVM\n" " --m32 force EVM hmac/signature for 32 bit target system\n" " --m64 force EVM hmac/signature for 64 bit target system\n" + " --ino use custom inode for EVM\n" + " --uid use custom UID for EVM\n" + " --gid use custom GID for EVM\n" + " --mode use custom Mode for EVM\n" + " --generation use custom Generation for EVM(unspecified: from FS, empty: use 0)\n" + " --ima use custom IMA signature for EVM\n" + " --selinux use custom Selinux label for EVM\n" + " --caps use custom Capabilities for EVM(unspecified: from FS, empty: do not use)\n" + " --list measurement list verification\n" " -v increase verbosity level\n" " -h, --help display this help and exit\n" "\n"); @@ -1469,10 +1650,12 @@ {"--version", NULL, 0, ""}, {"help", cmd_help, 0, "<command>"}, {"import", cmd_import, 0, "[--rsa] pubkey keyring", "Import public key into the keyring.\n"}, + {"convert", cmd_convert, 0, "key", "convert public key into the keyring.\n"}, {"sign", cmd_sign_evm, 0, "[-r] [--imahash | --imasig ] [--key key] [--pass [password] file", "Sign file metadata.\n"}, {"verify", cmd_verify_evm, 0, "file", "Verify EVM signature (for debugging).\n"}, {"ima_sign", cmd_sign_ima, 0, "[--sigfile] [--key key] [--pass [password] file", "Make file content signature.\n"}, {"ima_verify", cmd_verify_ima, 0, "file", "Verify IMA signature (for debugging).\n"}, + {"ima_setxattr", cmd_setxattr_ima, 0, "[--sigfile file]", "Set IMA signature from sigfile\n"}, {"ima_hash", cmd_hash_ima, 0, "file", "Make file content hash.\n"}, {"ima_measurement", cmd_ima_measurement, 0, "file", "Verify measurement list (experimental).\n"}, {"ima_fix", cmd_ima_fix, 0, "[-t fdsxm] path", "Recursively fix IMA/EVM xattrs in fix mode.\n"}, @@ -1498,8 +1681,18 @@ {"recursive", 0, 0, 'r'}, {"m32", 0, 0, '3'}, {"m64", 0, 0, '6'}, - {"smack", 0, 0, 256}, - {"version", 0, 0, 257}, + {"portable", 0, 0, 'o'}, + {"smack", 0, 0, 128}, + {"version", 0, 0, 129}, + {"inode", 1, 0, 130}, + {"uid", 1, 0, 131}, + {"gid", 1, 0, 132}, + {"mode", 1, 0, 133}, + {"generation", 1, 0, 134}, + {"ima", 1, 0, 135}, + {"selinux", 1, 0, 136}, + {"caps", 2, 0, 137}, + {"list", 0, 0, 138}, {} }; @@ -1546,7 +1739,7 @@ g_argc = argc; while (1) { - c = getopt_long(argc, argv, "hvnsda:p::fu::k:t:ri", opts, &lind); + c = getopt_long(argc, argv, "hvnsda:op::fu::k:t:ri", opts, &lind); if (c == -1) break; @@ -1580,14 +1773,11 @@ break; case 'f': sigfile = 1; - xattr = 0; break; case 'u': uuid_str = optarg; - if (uuid_str) - hmac_flags |= HMAC_FLAG_UUID_SET; - else - hmac_flags &= ~HMAC_FLAG_UUID; + if (!uuid_str) + hmac_flags |= HMAC_FLAG_NO_UUID; break; case '1': params.x509 = 0; @@ -1596,7 +1786,16 @@ params.keyfile = optarg; break; case 'i': - evm_immutable = true; + if (evm_portable) + log_err("Portable and immutable options are exclusive, ignoring immutable option."); + else + evm_immutable = true; + break; + case 'o': + if (evm_immutable) + log_err("Portable and immutable options are exclusive, ignoring portable option."); + else + evm_portable = true; break; case 't': search_type = optarg; @@ -1610,13 +1809,41 @@ case '6': msize = 64; break; - case 256: + case 128: evm_config_xattrnames = evm_extra_smack_xattrs; break; - case 257: + case 129: printf("evmctl %s\n", VERSION); exit(0); break; + case 130: + ino_str = optarg; + break; + case 131: + uid_str = optarg; + break; + case 132: + gid_str = optarg; + break; + case 133: + mode_str = optarg; + break; + case 134: + generation_str = optarg; + break; + case 135: + ima_str = optarg; + break; + case 136: + selinux_str = optarg; + break; + case 137: + caps_str = optarg; + hmac_flags |= HMAC_FLAG_CAPS_SET; + break; + case 138: + measurement_list = 1; + break; case '?': exit(1); break; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ima-evm-utils-1.0/src/imaevm.h new/ima-evm-utils-1.1/src/imaevm.h --- old/ima-evm-utils-1.0/src/imaevm.h 2015-07-30 20:28:53.000000000 +0200 +++ new/ima-evm-utils-1.1/src/imaevm.h 2018-02-15 14:02:19.000000000 +0100 @@ -82,6 +82,7 @@ EVM_XATTR_HMAC, EVM_IMA_XATTR_DIGSIG, IMA_XATTR_DIGEST_NG, + EVM_XATTR_PORTABLE_DIGSIG, }; struct h_misc { @@ -172,7 +173,7 @@ } __packed; -typedef int (*verify_hash_fn_t)(const unsigned char *hash, int size, unsigned char *sig, int siglen, const char *keyfile); +typedef int (*verify_hash_fn_t)(const char *file, const unsigned char *hash, int size, unsigned char *sig, int siglen, const char *keyfile); struct libevm_params { int verbose; @@ -187,6 +188,9 @@ size_t size; }; +#define NUM_PCRS 20 +#define DEFAULT_PCR 10 + extern const struct RSA_ASN1_template RSA_ASN1_templates[PKEY_HASH__LAST]; extern struct libevm_params params; @@ -202,7 +206,8 @@ int key2bin(RSA *key, unsigned char *pub); int sign_hash(const char *algo, const unsigned char *hash, int size, const char *keyfile, const char *keypass, unsigned char *sig); -int verify_hash(const unsigned char *hash, int size, unsigned char *sig, int siglen); -int ima_verify_signature(const char *file, unsigned char *sig, int siglen); +int verify_hash(const char *file, const unsigned char *hash, int size, unsigned char *sig, int siglen); +int ima_verify_signature(const char *file, unsigned char *sig, int siglen, unsigned char *digest, int digestlen); +void init_public_keys(const char *keyfiles); #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ima-evm-utils-1.0/src/libimaevm.c new/ima-evm-utils-1.1/src/libimaevm.c --- old/ima-evm-utils-1.0/src/libimaevm.c 2015-07-30 20:28:53.000000000 +0200 +++ new/ima-evm-utils-1.1/src/libimaevm.c 2018-02-15 14:02:19.000000000 +0100 @@ -214,6 +214,7 @@ DIR *dir; unsigned long long ino, off; unsigned int type; + int result = 0; dir = opendir(file); if (!dir) { @@ -233,13 +234,14 @@ err |= EVP_DigestUpdate(ctx, &type, sizeof(type)); if (!err) { log_err("EVP_DigestUpdate() failed\n"); - return 1; + result = 1; + break; } } closedir(dir); - return 0; + return result; } static int add_link_hash(const char *path, EVP_MD_CTX *ctx) @@ -269,9 +271,15 @@ { const EVP_MD *md; struct stat st; - EVP_MD_CTX ctx; + 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 /* Need to know the file length */ err = lstat(file, &st); @@ -286,7 +294,7 @@ return 1; } - err = EVP_DigestInit(&ctx, md); + err = EVP_DigestInit(pctx, md); if (!err) { log_err("EVP_DigestInit() failed\n"); return 1; @@ -294,17 +302,17 @@ switch (st.st_mode & S_IFMT) { case S_IFREG: - err = add_file_hash(file, &ctx); + err = add_file_hash(file, pctx); break; case S_IFDIR: - err = add_dir_hash(file, &ctx); + err = add_dir_hash(file, pctx); break; case S_IFLNK: - err = add_link_hash(file, &ctx); + err = add_link_hash(file, pctx); break; case S_IFIFO: case S_IFSOCK: case S_IFCHR: case S_IFBLK: - err = add_dev_hash(&st, &ctx); + err = add_dev_hash(&st, pctx); break; default: log_errno("Unsupported file type"); @@ -314,7 +322,7 @@ if (err) return err; - err = EVP_DigestFinal(&ctx, hash, &mdlen); + err = EVP_DigestFinal(pctx, hash, &mdlen); if (!err) { log_err("EVP_DigestFinal() failed\n"); return 1; @@ -364,7 +372,8 @@ return key; } -int verify_hash_v1(const unsigned char *hash, int size, unsigned char *sig, int siglen, const char *keyfile) +int verify_hash_v1(const char *file, const unsigned char *hash, int size, + unsigned char *sig, int siglen, const char *keyfile) { int err, len; SHA_CTX ctx; @@ -373,7 +382,7 @@ unsigned char sighash[20]; struct signature_hdr *hdr = (struct signature_hdr *)sig; - log_info("hash: "); + log_info("hash-v1: "); log_dump(hash, size); key = read_pub_key(keyfile, 0); @@ -390,24 +399,77 @@ err = RSA_public_decrypt(siglen - sizeof(*hdr) - 2, sig + sizeof(*hdr) + 2, out, key, RSA_PKCS1_PADDING); RSA_free(key); if (err < 0) { - log_err("RSA_public_decrypt() failed: %d\n", err); + log_err("%s: RSA_public_decrypt() failed: %d\n", file, err); return 1; } len = err; if (len != sizeof(sighash) || memcmp(out, sighash, len) != 0) { - log_err("Verification failed: %d\n", err); + log_err("%s: verification failed: %d\n", file, err); return -1; - } else { - /*log_info("Verification is OK\n");*/ - printf("Verification is OK\n"); } return 0; } -int verify_hash_v2(const unsigned char *hash, int size, unsigned char *sig, int siglen, const char *keyfile) +struct public_key_entry { + struct public_key_entry *next; + uint32_t keyid; + char name[9]; + RSA *key; +}; +static struct public_key_entry *public_keys = NULL; + +static RSA *find_keyid(uint32_t keyid) +{ + struct public_key_entry *entry; + + for (entry = public_keys; entry != NULL; entry = entry->next) { + if (entry->keyid == keyid) + return entry->key; + } + return NULL; +} + +void init_public_keys(const char *keyfiles) +{ + struct public_key_entry *entry; + char *tmp_keyfiles; + char *keyfile; + int i = 1; + + tmp_keyfiles = strdup(keyfiles); + + while ((keyfile = strsep(&tmp_keyfiles, ", \t")) != NULL) { + if (!keyfile) + break; + if ((*keyfile == '\0') || (*keyfile == ' ') || + (*keyfile == '\t')) + continue; + + entry = malloc(sizeof(struct public_key_entry)); + if (!entry) { + perror("malloc"); + break; + } + + entry->key = read_pub_key(keyfile, 1); + if (!entry->key) { + free(entry); + continue; + } + + calc_keyid_v2(&entry->keyid, entry->name, entry->key); + sprintf(entry->name, "%x", __be32_to_cpup(&entry->keyid)); + log_info("key %d: %s %s\n", i++, entry->name, keyfile); + entry->next = public_keys; + public_keys = entry; + } +} + +int verify_hash_v2(const char *file, const unsigned char *hash, int size, + unsigned char *sig, int siglen, const char *keyfile) { int err, len; unsigned char out[1024]; @@ -415,17 +477,29 @@ struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig; const struct RSA_ASN1_template *asn1; - log_info("hash: "); - log_dump(hash, size); + if (params.verbose > LOG_INFO) { + log_info("hash: "); + log_dump(hash, size); + } - key = read_pub_key(keyfile, 1); - if (!key) - return 1; + if (public_keys) { + key = find_keyid(hdr->keyid); + if (!key) { + log_err("%s: unknown keyid: %x\n", file, + __be32_to_cpup(&hdr->keyid)); + return -1; + } + } else { + key = read_pub_key(keyfile, 1); + if (!key) + return 1; + } - err = RSA_public_decrypt(siglen - sizeof(*hdr), sig + sizeof(*hdr), out, key, RSA_PKCS1_PADDING); - RSA_free(key); + + err = RSA_public_decrypt(siglen - sizeof(*hdr), sig + sizeof(*hdr), + out, key, RSA_PKCS1_PADDING); if (err < 0) { - log_err("RSA_public_decrypt() failed: %d\n", err); + log_err("%s: RSA_public_decrypt() failed: %d\n", file, err); return 1; } @@ -434,20 +508,17 @@ asn1 = &RSA_ASN1_templates[hdr->hash_algo]; if (len < asn1->size || memcmp(out, asn1->data, asn1->size)) { - log_err("Verification failed: %d\n", err); + log_err("%s: verification failed: %d\n", file, err); return -1; } len -= asn1->size; if (len != size || memcmp(out + asn1->size, hash, len)) { - log_err("Verification failed: %d\n", err); + log_err("%s: verification failed: %d\n", file, err); return -1; } - /*log_info("Verification is OK\n");*/ - printf("Verification is OK\n"); - return 0; } @@ -489,7 +560,8 @@ return -1; } -int verify_hash(const unsigned char *hash, int size, unsigned char *sig, int siglen) +int verify_hash(const char *file, const unsigned char *hash, int size, unsigned char *sig, + int siglen) { const char *key; int x509; @@ -512,10 +584,11 @@ "/etc/keys/x509_evm.der" : "/etc/keys/pubkey_evm.pem"; - return verify_hash(hash, size, sig, siglen, key); + return verify_hash(file, hash, size, sig, siglen, key); } -int ima_verify_signature(const char *file, unsigned char *sig, int siglen) +int ima_verify_signature(const char *file, unsigned char *sig, int siglen, + unsigned char *digest, int digestlen) { unsigned char hash[64]; int hashlen, sig_hash_algo; @@ -533,11 +606,18 @@ /* Use hash algorithm as retrieved from signature */ params.hash_algo = pkey_hash_algo[sig_hash_algo]; + /* + * Validate the signature based on the digest included in the + * measurement list, not by calculating the local file digest. + */ + if (digestlen > 0) + return verify_hash(file, digest, digestlen, sig + 1, siglen - 1); + hashlen = ima_calc_hash(file, hash); if (hashlen <= 1) return hashlen; - return verify_hash(hash, hashlen, sig + 1, siglen - 1); + return verify_hash(file, hash, hashlen, sig + 1, siglen - 1); } /* @@ -547,6 +627,14 @@ { int len, b, offset = 0; struct pubkey_hdr *pkh = (struct pubkey_hdr *)pub; + const BIGNUM *n, *e; + +#if OPENSSL_VERSION_NUMBER < 0x10100000 + n = key->n; + e = key->e; +#else + RSA_get0_key(key, &n, &e, NULL); +#endif /* add key header */ pkh->version = 1; @@ -556,18 +644,18 @@ offset += sizeof(*pkh); - len = BN_num_bytes(key->n); - b = BN_num_bits(key->n); + len = BN_num_bytes(n); + b = BN_num_bits(n); pub[offset++] = b >> 8; pub[offset++] = b & 0xff; - BN_bn2bin(key->n, &pub[offset]); + BN_bn2bin(n, &pub[offset]); offset += len; - len = BN_num_bytes(key->e); - b = BN_num_bits(key->e); + len = BN_num_bytes(e); + b = BN_num_bits(e); pub[offset++] = b >> 8; pub[offset++] = b & 0xff; - BN_bn2bin(key->e, &pub[offset]); + BN_bn2bin(e, &pub[offset]); offset += len; return offset; @@ -585,9 +673,11 @@ log_debug("keyid: "); log_debug_dump(keyid, 8); - id = __be64_to_cpup((__be64 *) keyid); - sprintf(str, "%llX", (unsigned long long)id); - log_info("keyid: %s\n", str); + if (params.verbose > LOG_INFO) { + id = __be64_to_cpup((__be64 *) keyid); + sprintf(str, "%llX", (unsigned long long)id); + log_info("keyid-v1: %s\n", str); + } } void calc_keyid_v2(uint32_t *keyid, char *str, RSA *key) @@ -605,8 +695,10 @@ log_debug("keyid: "); log_debug_dump(keyid, 4); - sprintf(str, "%x", __be32_to_cpup(keyid)); - log_info("keyid: %s\n", str); + if (params.verbose > LOG_INFO) { + sprintf(str, "%x", __be32_to_cpup(keyid)); + log_info("keyid: %s\n", str); + } free(pkey); } @@ -719,7 +811,7 @@ blen = (uint16_t *) (sig + sizeof(*hdr)); *blen = __cpu_to_be16(len << 3); len += sizeof(*hdr) + 2; - log_info("evm/ima signature: %d bytes\n", len); + log_info("evm/ima signature-v1: %d bytes\n", len); out: RSA_free(key); return len;
