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

8 Commits
v0.1.0 ... v0.2

Author SHA1 Message Date
76f3496455 evm-utils renamed to ima-evm-utils.
Version set to 0.2.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:53 +03:00
dc36ed86d3 Added RPM and TAR building rules
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:53 +03:00
de89119dbf added command options description
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:53 +03:00
04e3ff3ef5 removed unused parameter
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:53 +03:00
5769fb1833 import functions combined
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:53 +03:00
52960f8b93 updated error handling
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:53 +03:00
e576ac9771 read list of existing extended attributes
getxattr() might return runtime value which does not really exist
on file system. It happens for SMACK LSM. Reading the list of existing
attributes allows to prevent such to happen.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:53 +03:00
d61b9c0be7 added HMAC API error handling
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:53 +03:00
5 changed files with 275 additions and 192 deletions

View File

@ -1,3 +1,12 @@
2012-04-05 Dmitry Kasatkin <dmitry.kasatkin@intel.com>
version 0.2
* added RPM & TAR building makefile rules
* renamed evm-utils to ima-evm-utils
* added command options description
* updated error handling
* refactored redundant code
2012-04-02 Dmitry Kasatkin <dmitry.kasatkin@intel.com>
version 0.1.0

View File

@ -4,3 +4,20 @@ SUBDIRS = src tests
ACLOCAL_AMFLAGS = -I m4
SRCS = $(HOME)/rpmbuild/SOURCES
SPEC = $(PACKAGE_NAME).spec
pkgname = $(PACKAGE_NAME)-$(PACKAGE_VERSION)
tarname = $(pkgname).tar.gz
$(tarname):
git tag -f v$(PACKAGE_VERSION)
git archive --format=tar --prefix=$(pkgname)/ v$(PACKAGE_VERSION) $(FILES) | gzip >$@;
tar: $(tarname)
rpm: $(tarname)
cp $(tarname) $(SRCS)/
rpmbuild -ba --nodeps $(SPEC)
.PHONY: $(tarname)

View File

@ -1,7 +1,7 @@
# autoconf script
AC_PREREQ([2.65])
AC_INIT(evm-utils, 0.1, dmitry.kasatkin@intel.com)
AC_INIT(ima-evm-utils, 0.2, dmitry.kasatkin@intel.com)
AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
@ -47,7 +47,7 @@ fi
AC_CONFIG_FILES([Makefile
src/Makefile
tests/Makefile
evm-utils.spec
ima-evm-utils.spec
])
AC_OUTPUT

View File

@ -1,7 +1,7 @@
Name: @PACKAGE_NAME@
Version: @PACKAGE_VERSION@
Release: 1%{?dist}
Summary: evm-utils - IMA/EVM support utilities
Summary: @PACKAGE_NAME@ - IMA/EVM control utility
Group: System/Libraries
License: LGPLv2
#URL:
@ -12,11 +12,10 @@ BuildRequires: autoconf
BuildRequires: automake
BuildRequires: openssl-devel
BuildRequires: libattr-devel
BuildRequires: readline-devel
BuildRequires: keyutils-libs-devel
%description
This library provides EVM support utilities.
This package provide IMA/EVM control utility
%prep
%setup -q
@ -48,6 +47,6 @@ exit 0
%{_libdir}/*
%changelog
* Wed Jul 20 2011 Dmitry Kasatkin <dmitry.kasatkin@intel.com>
- Initial package for MeeGo
* Thu Apr 05 2012 Dmitry Kasatkin <dmitry.kasatkin@intel.com>
- Initial RPM spec file

View File

@ -2,7 +2,7 @@
* evm-utils - IMA/EVM support utilities
*
* Copyright (C) 2011 Nokia Corporation
* Copyright (C) 2011 Intel Corporation
* Copyright (C) 2011, 2012 Intel Corporation
*
* Authors:
* Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
@ -74,7 +74,7 @@
#define log_dump(p, len) do_log_dump(LOG_INFO, p, len)
#define log_info(fmt, args...) do_log(LOG_INFO, fmt, ##args)
#define log_err(fmt, args...) do_log(LOG_ERR, fmt, ##args)
#define log_errno(fmt, args...) do_log(LOG_ERR, fmt ": %s (%d)\n", ##args, strerror(errno), errno)
#define log_errno(fmt, args...) do_log(LOG_ERR, fmt ": errno: %s (%d)\n", ##args, strerror(errno), errno)
#define DATA_SIZE 4096
#define SHA1_HASH_LEN 20
@ -200,7 +200,7 @@ static int bin2file(const char *file, const char *ext, const unsigned char *data
fp = fopen(name, "w");
if (!fp) {
log_errno("Unable to open %s for writing", name);
log_err("Unable to open %s for writing\n", name);
return -1;
}
err = fwrite(data, len, 1, fp);
@ -208,16 +208,16 @@ static int bin2file(const char *file, const char *ext, const unsigned char *data
return err;
}
static char *file2bin(const char *file, int *size)
static unsigned char *file2bin(const char *file, int *size)
{
FILE *fp;
int len;
char *data;
unsigned char *data;
len = get_filesize(file);
fp = fopen(file, "r");
if (!fp) {
log_errno("Unable to open %s", file);
log_err("Unable to open %s\n", file);
return NULL;
}
data = malloc(len);
@ -270,14 +270,14 @@ static int read_key(const char *inkey, unsigned char *pub)
fp = fopen(inkey, "r");
if (!fp) {
log_errno("read key failed from file %s", inkey);
log_err("read key failed from file %s\n", inkey);
return -1;
}
key1 = PEM_read_RSA_PUBKEY(fp, &key, NULL, NULL);
fclose(fp);
if (!key1) {
log_errno("PEM_read_RSA_PUBKEY() failed");
log_err("PEM_read_RSA_PUBKEY() failed\n");
return -1;
}
@ -324,14 +324,14 @@ static int sign_hash(const unsigned char *hash, int size, const char *keyfile, u
fp = fopen(keyfile, "r");
if (!fp) {
log_errno("Unable to open keyfile %s", keyfile);
log_err("Unable to open keyfile %s\n", keyfile);
return -1;
}
key1 = PEM_read_RSAPrivateKey(fp, &key, NULL, keypass);
fclose(fp);
if (!key1) {
log_errno("RSAPrivateKey() failed");
return -1;
log_err("PEM_read_RSAPrivateKey() failed\n");
return 1;
}
/* now create a new hash */
@ -355,8 +355,8 @@ static int sign_hash(const unsigned char *hash, int size, const char *keyfile, u
err = RSA_private_encrypt(sizeof(sighash), sighash, sig + sizeof(*hdr) + 2, key, RSA_PKCS1_PADDING);
RSA_free(key);
if (err < 0) {
log_errno("RSA_private_encrypt() failed: %d", err);
return -1;
log_err("RSA_private_encrypt() failed: %d\n", err);
return 1;
}
len = err;
@ -372,6 +372,18 @@ static int sign_hash(const unsigned char *hash, int size, const char *keyfile, u
return len;
}
static int find_xattr(const char *list, int list_size, const char *xattr)
{
int len;
for (; list_size > 0; len++, list_size -= len, list += len) {
len = strlen(list);
if (!strcmp(list, xattr))
return 1;
}
return 0;
}
static int calc_evm_hash(const char *file, unsigned char *hash)
{
struct stat st;
@ -382,20 +394,22 @@ static int calc_evm_hash(const char *file, unsigned char *hash)
unsigned int mdlen;
char **xattrname;
char xattr_value[1024];
char list[1024];
ssize_t list_size;
fd = open(file, 0);
if (fd < 0) {
log_errno("Unable to open %s", file);
log_err("Unable to open %s\n", file);
return -1;
}
if (fstat(fd, &st)) {
log_errno("fstat() failed");
log_err("fstat() failed\n");
return -1;
}
if (ioctl(fd, EXT34_IOC_GETVERSION, &generation)) {
log_errno("ioctl() failed");
log_err("ioctl() failed\n");
return -1;
}
@ -403,22 +417,32 @@ static int calc_evm_hash(const char *file, unsigned char *hash)
log_info("generation: %u\n", generation);
list_size = llistxattr(file, list, sizeof(list));
if (list_size <= 0) {
log_err("llistxattr() failed\n");
return -1;
}
md = EVP_get_digestbyname("sha1");
if (!md) {
log_errno("EVP_get_digestbyname() failed");
return -1;
log_err("EVP_get_digestbyname() failed\n");
return 1;
}
err = EVP_DigestInit(&ctx, md);
if (!err) {
log_errno("EVP_DigestInit() failed");
return -1;
log_err("EVP_DigestInit() failed\n");
return 1;
}
for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) {
err = getxattr(file, *xattrname, xattr_value, sizeof(xattr_value));
if (err < 0) {
log_info("no attr: %s\n", *xattrname);
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);*/
@ -426,8 +450,8 @@ static int calc_evm_hash(const char *file, unsigned char *hash)
log_debug_dump(xattr_value, err);
err = EVP_DigestUpdate(&ctx, xattr_value, err);
if (!err) {
log_errno("EVP_DigestUpdate() failed");
return -1;
log_err("EVP_DigestUpdate() failed\n");
return 1;
}
}
@ -440,34 +464,36 @@ static int calc_evm_hash(const char *file, unsigned char *hash)
err = EVP_DigestUpdate(&ctx, (const unsigned char *)&hmac_misc, sizeof(hmac_misc));
if (!err) {
log_errno("EVP_DigestUpdate() failed");
return -1;
log_err("EVP_DigestUpdate() failed\n");
return 1;
}
err = EVP_DigestFinal(&ctx, hash, &mdlen);
if (!err) {
log_errno("EVP_DigestFinal() failed");
return -1;
log_err("EVP_DigestFinal() failed\n");
return 1;
}
return 0;
return mdlen;
}
static int sign_evm(const char *file, const char *key)
{
unsigned char hash[20];
unsigned char sig[1024] = "\x03";
int err;
int len, err;
calc_evm_hash(file, hash);
len = calc_evm_hash(file, hash);
if (len <= 1)
return len;
err = sign_hash(hash, sizeof(hash), key, sig + 1);
if (err < 0)
return err;
len = sign_hash(hash, len, key, sig + 1);
if (len <= 1)
return len;
if (xattr) {
err = setxattr(file, "security.evm", sig, err + 1, 0);
err = setxattr(file, "security.evm", sig, len + 1, 0);
if (err < 0) {
log_errno("setxattr failed: %s", file);
log_err("setxattr failed: %s\n", file);
return err;
}
}
@ -487,26 +513,26 @@ static int calc_file_hash(const char *file, uint8_t *hash)
data = malloc(bs);
if (!data) {
log_errno("malloc failed");
log_err("malloc failed\n");
return -1;
}
fp = fopen(file, "r");
if (!fp) {
log_errno("Unable to open %s", file);
log_err("Unable to open %s\n", file);
return -1;
}
md = EVP_get_digestbyname(hash_algo);
if (!md) {
log_errno("EVP_get_digestbyname() failed");
return -1;
log_err("EVP_get_digestbyname() failed\n");
return 1;
}
err = EVP_DigestInit(&ctx, md);
if (!err) {
log_errno("EVP_DigestInit() failed");
return -1;
log_err("EVP_DigestInit() failed\n");
return 1;
}
for (size = get_fdsize(fileno(fp)); size; size -= len) {
@ -514,22 +540,22 @@ static int calc_file_hash(const char *file, uint8_t *hash)
err = fread(data, len, 1, fp);
if (!err) {
if (ferror(fp)) {
log_errno("fread() error\n");
log_err("fread() error\n\n");
return -1;
}
break;
}
err = EVP_DigestUpdate(&ctx, data, len);
if (!err) {
log_errno("EVP_DigestUpdate() failed");
return -1;
log_err("EVP_DigestUpdate() failed\n");
return 1;
}
}
err = EVP_DigestFinal(&ctx, hash, &mdlen);
if (!err) {
log_errno("EVP_DigestFinal() failed");
return -1;
log_err("EVP_DigestFinal() failed\n");
return 1;
}
fclose(fp);
@ -557,20 +583,20 @@ static int calc_dir_hash(const char *file, uint8_t *hash)
dir = opendir(file);
if (!dir) {
log_errno("Unable to open %s", file);
log_err("Unable to open %s\n", file);
return -1;
}
md = EVP_get_digestbyname(hash_algo);
if (!md) {
log_errno("EVP_get_digestbyname() failed");
return -1;
log_err("EVP_get_digestbyname() failed\n");
return 1;
}
err = EVP_DigestInit(&ctx, md);
if (!err) {
log_errno("EVP_DigestInit() failed");
return -1;
log_err("EVP_DigestInit() failed\n");
return 1;
}
while ((de = readdir(dir))) {
@ -594,21 +620,21 @@ static int calc_dir_hash(const char *file, uint8_t *hash)
log_debug("entry: ino: %llu, %s\n", (unsigned long long)ino, cur->de.d_name);
err = EVP_DigestUpdate(&ctx, cur->de.d_name, strlen(cur->de.d_name));
if (!err) {
log_errno("EVP_DigestUpdate() failed");
return -1;
log_err("EVP_DigestUpdate() failed\n");
return 1;
}
err = EVP_DigestUpdate(&ctx, &ino, sizeof(ino));
if (!err) {
log_errno("EVP_DigestUpdate() failed");
return -1;
log_err("EVP_DigestUpdate() failed\n");
return 1;
}
free(cur);
}
err = EVP_DigestFinal(&ctx, hash, &mdlen);
if (!err) {
log_errno("EVP_DigestFinal() failed");
return -1;
log_err("EVP_DigestFinal() failed\n");
return 1;
}
closedir(dir);
@ -619,33 +645,33 @@ static int calc_dir_hash(const char *file, uint8_t *hash)
static int hash_ima(const char *file)
{
unsigned char hash[65] = "\x01"; /* MAX hash size + 1 */
int err;
int len, err;
struct stat st;
/* Need to know the file length */
err = stat(file, &st);
if (err < 0) {
log_errno("stat() failed");
log_err("stat() failed\n");
return err;
}
if (S_ISDIR(st.st_mode))
err = calc_dir_hash(file, hash + 1);
len = calc_dir_hash(file, hash + 1);
else
err = calc_file_hash(file, hash + 1);
if (err < 0)
return err;
len = calc_file_hash(file, hash + 1);
if (len <= 1)
return len;
if (verbose >= LOG_INFO)
log_info("hash: ");
if (!xattr || verbose >= LOG_INFO)
dump(hash, err + 1);
dump(hash, len + 1);
if (xattr) {
err = setxattr(file, "security.ima", hash, err + 1, 0);
err = setxattr(file, "security.ima", hash, len + 1, 0);
if (err < 0) {
log_errno("setxattr failed: %s", file);
log_err("setxattr failed: %s\n", file);
return err;
}
}
@ -660,7 +686,7 @@ static int cmd_hash_ima(struct command *cmd)
if (!file) {
log_err("Parameters missing\n");
print_usage(cmd);
return 1;
return -1;
}
return hash_ima(file);
@ -670,23 +696,23 @@ static int sign_ima(const char *file, const char *key)
{
unsigned char hash[64];
unsigned char sig[1024] = "\x03";
int err;
int len, err;
err = calc_file_hash(file, hash);
if (err < 0)
return err;
len = calc_file_hash(file, hash);
if (len <= 1)
return len;
err = sign_hash(hash, err, key, sig + 1);
if (err < 0)
return err;
len = sign_hash(hash, len, key, sig + 1);
if (len <= 1)
return len;
if (sigfile)
bin2file(file, "sig", sig, err + 1);
bin2file(file, "sig", sig, len + 1);
if (xattr) {
err = setxattr(file, "security.ima", sig, err + 1, 0);
err = setxattr(file, "security.ima", sig, len + 1, 0);
if (err < 0) {
log_errno("setxattr failed: %s", file);
log_err("setxattr failed: %s\n", file);
return err;
}
}
@ -701,7 +727,7 @@ static int cmd_sign_ima(struct command *cmd)
if (!file) {
log_err("Parameters missing\n");
print_usage(cmd);
return 1;
return -1;
}
key = g_argv[optind++];
@ -720,7 +746,13 @@ static int cmd_sign_evm(struct command *cmd)
if (!file) {
log_err("Parameters missing\n");
print_usage(cmd);
return 1;
return -1;
}
if (!digsig && !digest) {
log_err("Parameters missing\n");
print_usage(cmd);
return -1;
}
key = g_argv[optind++];
@ -757,14 +789,14 @@ static int verify_hash(const unsigned char *hash, int size, unsigned char *sig,
fp = fopen(keyfile, "r");
if (!fp) {
log_errno("Unable to open keyfile %s", keyfile);
log_err("Unable to open keyfile %s\n", keyfile);
return -1;
}
key1 = PEM_read_RSA_PUBKEY(fp, &key, NULL, NULL);
fclose(fp);
if (!key1) {
log_errno("PEM_read_RSA_PUBKEY() failed");
return -1;
log_err("PEM_read_RSA_PUBKEY() failed\n");
return 1;
}
SHA1_Init(&ctx);
@ -777,14 +809,14 @@ static int verify_hash(const unsigned char *hash, int size, unsigned char *sig,
err = RSA_public_decrypt(siglen - sizeof(*hdr) - 2, sig + sizeof(*hdr) + 2, out, key, RSA_PKCS1_PADDING);
RSA_free(key);
if (err < 0) {
log_errno("RSA_public_decrypt() failed: %d", err);
return -1;
log_err("RSA_public_decrypt() failed: %d\n", err);
return 1;
}
len = err;
if (len != sizeof(sighash) || memcmp(out, sighash, len) != 0) {
log_errno("Verification failed: %d", err);
log_err("Verification failed: %d\n", err);
return -1;
} else {
/*log_info("Verification is OK\n");*/
@ -798,22 +830,24 @@ static int verify_evm(const char *file, const char *key)
{
unsigned char hash[20];
unsigned char sig[1024];
int err;
int len;
calc_evm_hash(file, hash);
len = calc_evm_hash(file, hash);
if (len <= 1)
return len;
err = getxattr(file, "security.evm", sig, sizeof(sig));
if (err < 0) {
log_errno("getxattr failed");
return err;
len = getxattr(file, "security.evm", sig, sizeof(sig));
if (len < 0) {
log_err("getxattr failed\n");
return len;
}
if (sig[0] != 0x03) {
log_errno("security.evm has not signature");
return err;
log_err("security.evm has not signature\n");
return -1;
}
return verify_hash(hash, sizeof(hash), sig + 1, err - 1, key);
return verify_hash(hash, sizeof(hash), sig + 1, len - 1, key);
}
static int cmd_verify_evm(struct command *cmd)
@ -823,7 +857,7 @@ static int cmd_verify_evm(struct command *cmd)
if (!file) {
log_err("Parameters missing\n");
print_usage(cmd);
return 1;
return -1;
}
key = g_argv[optind++];
@ -863,62 +897,21 @@ static int cmd_convert(struct command *cmd)
return 0;
}
static int cmd_import_bin(struct command *cmd)
{
int len;
char *inkey, *ring = NULL;
char *key, name[20];
key_serial_t id;
uint8_t keyid[8];
inkey = g_argv[optind++];
if (!inkey)
inkey = "/etc/keys/pubkey_evm.bin";
else
ring = g_argv[optind++];
if (!ring)
id = KEY_SPEC_USER_KEYRING;
else
id = atoi(ring);
key = file2bin(inkey, &len);
if (!key)
return -1;
calc_keyid(keyid, name, (unsigned char *)key, len);
log_info("Importing public key %s from file %s into keyring %d\n", name, inkey, id);
id = add_key("user", name, key, len, id);
if (id < 0) {
log_errno("add_key failed");
return -1;
}
log_info("keyid: %d\n", id);
printf("%d\n", id);
free(key);
return 0;
}
static int cmd_import(struct command *cmd)
{
char *inkey, *ring = NULL;
unsigned char key[1024];
unsigned char _key[1024], *key = _key;
int id, len;
char name[20];
uint8_t keyid[8];
if (binkey)
return cmd_import_bin(cmd);
inkey = g_argv[optind++];
if (!inkey)
inkey = "/etc/keys/pubkey_evm.pem";
if (!inkey) {
if (binkey)
inkey = "/etc/keys/pubkey_evm.bin";
else
inkey = "/etc/keys/pubkey_evm.pem";
} else
ring = g_argv[optind++];
if (!ring)
@ -926,9 +919,15 @@ static int cmd_import(struct command *cmd)
else
id = atoi(ring);
if (binkey) {
key = file2bin(inkey, &len);
if (!key)
return -1;
} else {
len = read_key(inkey, key);
if (len < 0)
return -1;
}
calc_keyid(keyid, name, key, len);
@ -936,13 +935,16 @@ static int cmd_import(struct command *cmd)
id = add_key("user", name, key, len, id);
if (id < 0) {
log_errno("add_key failed");
log_err("add_key failed\n");
return -1;
}
log_info("keyid: %d\n", id);
printf("%d\n", id);
if (binkey)
free(key);
return 0;
}
@ -957,18 +959,20 @@ static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *h
unsigned int mdlen;
char **xattrname;
unsigned char xattr_value[1024];
char *key;
unsigned char *key;
int keylen;
unsigned char evmkey[MAX_KEY_SIZE];
char list[1024];
ssize_t list_size;
key = file2bin(keyfile, &keylen);
if (!key) {
log_errno("Unable to read a key: %s\n", keyfile);
log_err("Unable to read a key: %s\n\n", keyfile);
return -1;
}
if (keylen > sizeof(evmkey)) {
log_errno("key is too long\n");
log_err("key is too long\n");
return -1;
}
@ -978,17 +982,17 @@ static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *h
fd = open(file, 0);
if (fd < 0) {
log_errno("Unable to open %s", file);
log_err("Unable to open %s\n", file);
return -1;
}
if (fstat(fd, &st)) {
log_errno("fstat() failed");
log_err("fstat() failed\n");
return -1;
}
if (ioctl(fd, EXT34_IOC_GETVERSION, &generation)) {
log_errno("ioctl() failed");
log_err("ioctl() failed\n");
return -1;
}
@ -996,18 +1000,36 @@ static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *h
log_info("generation: %u\n", generation);
HMAC_Init(&ctx, evmkey, sizeof(evmkey), EVP_sha1());
list_size = llistxattr(file, list, sizeof(list));
if (list_size <= 0) {
log_err("llistxattr() failed\n");
return -1;
}
err = HMAC_Init(&ctx, evmkey, sizeof(evmkey), EVP_sha1());
if (!err) {
log_err("HMAC_Init() failed\n");
return 1;
}
for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) {
err = getxattr(file, *xattrname, xattr_value, sizeof(xattr_value));
if (err < 0) {
log_info("no attr: %s\n", *xattrname);
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);
HMAC_Update(&ctx, xattr_value, err);
err = HMAC_Update(&ctx, xattr_value, err);
if (!err) {
log_err("HMAC_Update() failed\n");
return 1;
}
}
memset(&hmac_misc, 0, sizeof(hmac_misc));
@ -1017,32 +1039,41 @@ static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *h
hmac_misc.gid = st.st_gid;
hmac_misc.mode = st.st_mode;
HMAC_Update(&ctx, (const unsigned char *)&hmac_misc, sizeof(hmac_misc));
HMAC_Final(&ctx, hash, &mdlen);
err = HMAC_Update(&ctx, (const unsigned char *)&hmac_misc, sizeof(hmac_misc));
if (!err) {
log_err("HMAC_Update() failed\n");
return 1;
}
err = HMAC_Final(&ctx, hash, &mdlen);
if (!err) {
log_err("HMAC_Final() failed\n");
return 1;
}
HMAC_CTX_cleanup(&ctx);
free(key);
return 0;
return mdlen;
}
static int hmac_evm(const char *file, const char *key)
{
unsigned char hash[20];
unsigned char sig[1024] = "\x02";
int err;
int len, err;
calc_evm_hmac(file, key, hash);
len = calc_evm_hmac(file, key, hash);
if (len <= 1)
return len;
log_info("hmac: ");
log_dump(hash, sizeof(hash));
memcpy(sig + 1, hash, sizeof(hash));
err = sizeof(hash);
log_dump(hash, len);
memcpy(sig + 1, hash, len);
if (xattr) {
err = setxattr(file, "security.evm", sig, err + 1, 0);
err = setxattr(file, "security.evm", sig, len + 1, 0);
if (err < 0) {
log_errno("setxattr failed: %s", file);
log_err("setxattr failed: %s\n", file);
return err;
}
}
@ -1058,7 +1089,13 @@ static int cmd_hmac_evm(struct command *cmd)
if (!file) {
log_err("Parameters missing\n");
print_usage(cmd);
return 1;
return -1;
}
if (!digsig && !digest) {
log_err("Parameters missing\n");
print_usage(cmd);
return -1;
}
key = g_argv[optind++];
@ -1090,8 +1127,7 @@ static void print_full_usage(struct command *cmd)
if (cmd->name)
printf("usage: %s %s\n", cmd->name, cmd->arg ? cmd->arg : "");
if (cmd->msg)
printf("description:\n%s", cmd->msg);
printf("%s", cmd->msg);
}
static int print_command_usage(struct command *cmds, char *command)
@ -1105,18 +1141,20 @@ static int print_command_usage(struct command *cmds, char *command)
}
}
printf("invalid command: %s\n", command);
return 1;
return -1;
}
static void print_all_usage(struct command *cmds)
{
struct command *cmd;
printf("commands:\n");
for (cmd = cmds; cmd->name; cmd++) {
if (cmd->arg)
printf("%s %s\n", cmd->name, cmd->arg);
printf(" %s %s\n", cmd->name, cmd->arg);
else if (cmd->msg)
printf("%s", cmd->msg);
printf(" %s", cmd->msg);
}
}
@ -1143,26 +1181,40 @@ static int cmd_help(struct command *cmd)
static void usage(void)
{
printf("Usage: evmctl <command> [parameters..]\n");
printf("Usage: evmctl [-v] <command> [OPTIONS]\n");
print_all_usage(cmds);
printf(
"\n"
" -a, --hashalgo sha1 (default), sha224, sha256, sha384, sha512\n"
" -s, --imasig also make IMA signature\n"
" -d, --imahash also make IMA hash\n"
" -f, --sigfile store IMA signature in .sig file instead of xattr\n"
" -b, --bin signing key is in binary format\n"
" -p, --pass password for encrypted signing key\n"
" -n print result to stdout instead of setting xattr\n"
" -v increase verbosity level\n"
" -h, --help display this help and exit\n"
"\n");
}
struct command cmds[] = {
{"help", cmd_help, 0, "<command>"},
{"import", cmd_import, 0, "[--bin] inkey keyring", "Import public key (PEM/bin) into the keyring.\n"},
{"import", cmd_import, 0, "[--bin] pubkey keyring", "Import public key (PEM/bin) into the keyring.\n"},
{"convert", cmd_convert, 0, "inkey outkey", "Convert PEM public key into IMA/EVM kernel friendly format.\n"},
{"sign", cmd_sign_evm, 0, "[--imahash | --imasig ] file [key]", "Sign file metadata.\n"},
{"sign", cmd_sign_evm, 0, "[--imahash | --imasig ] [--pass password] file [key]", "Sign file metadata.\n"},
{"verify", cmd_verify_evm, 0, "file", "Verify EVM signature (for debugging).\n"},
{"ima_sign", cmd_sign_ima, 0, "[--sigfile] file [key]", "Sign file content.\n"},
{"ima_hash", cmd_hash_ima, 0, "file", "Hash file content.\n"},
{"hmac", cmd_hmac_evm, 0, "[--imahash | --imasig ] file [key]", "Sign file metadata with HMAC (for debugging).\n"},
{"ima_sign", cmd_sign_ima, 0, "[--sigfile] [--pass password] file [key]", "Make file content signature.\n"},
{"ima_hash", cmd_hash_ima, 0, "file", "Make file content hash.\n"},
#ifdef DEBUG
{"hmac", cmd_hmac_evm, 0, "[--imahash | --imasig ] file [key]", "Sign file metadata with HMAC using symmetric key (for testing purpose).\n"},
#endif
{0, 0, 0, NULL}
};
static struct option opts[] = {
{"help", 0, 0, 'h'},
{"inkey", 1, 0, 'k'},
{"imasig", 0, 0, 's'},
{"imahash", 0, 0, 'd'},
{"hashalgo", 1, 0, 'a'},
@ -1181,7 +1233,7 @@ int main(int argc, char *argv[])
g_argc = argc;
while (1) {
c = getopt_long(argc, argv, "hk:vnsda:bp:f", opts, &lind);
c = getopt_long(argc, argv, "hvnsda:bp:f", opts, &lind);
if (c == -1)
break;
@ -1190,9 +1242,6 @@ int main(int argc, char *argv[])
usage();
exit(0);
break;
case 'k':
printf("inkey: %s\n", optarg);
break;
case 'v':
verbose++;
break;
@ -1234,8 +1283,17 @@ int main(int argc, char *argv[])
else
err = call_command(cmds, argv[optind++]);
if (err)
log_err("error: %s\n", ERR_error_string(ERR_get_error(), NULL));
if (err) {
unsigned long err;
if (errno)
log_err("errno: %s (%d)\n", strerror(errno), errno);
for (;;) {
err = ERR_get_error();
if (!err)
break;
log_err("%s\n", ERR_error_string(err, NULL));
}
}
ERR_free_strings();
EVP_cleanup();