10 Commits

Author SHA1 Message Date
1e2934d9a3 version 0.1.0 2012-09-06 14:08:53 +03:00
c13fce4028 remove unused parameter
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:53 +03:00
aa2f6e9b63 Changed time_t timestamp type to uint32_t
time_t is actually long and is different on 32 and 64 bit architectures.
Format of the signatures should not depend on the architecture and should
be the same. Changed timestamp to uint32_t like in GPG.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:53 +03:00
ff071501d0 Added missing CFLAGS
Added missing CFLAGS

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:52 +03:00
f2b486e053 Added signature write to .sig file
To enable module signature verification working on file systems
without extended attributes, or to be able to copy modules by methods,
which does not support extended attribute copying, it is necessary
to store signature in the file. This patch provides command line parameter
for storing signature in .sig file.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:52 +03:00
e3f11d343a Change set_xattr to xattr.
set_xattr changed to xattr.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:52 +03:00
7e89de565e Changed to conform Linux kernel coding style
Changed to conform Linux kernel coding style, except 80 characters
line length limit.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:52 +03:00
e91cb01e9a added password parameter for using encrypted keys
Added password parameter for using encrypted keys.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:52 +03:00
b0966fd243 added openssl initialization and error reporting
Added openssl initialization and error reporting.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:52 +03:00
0b197c4d30 minor fixes
- error message
- command info

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:52 +03:00
4 changed files with 194 additions and 268 deletions

View File

@ -4,20 +4,3 @@ SUBDIRS = src tests
ACLOCAL_AMFLAGS = -I m4 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 # autoconf script
AC_PREREQ([2.65]) AC_PREREQ([2.65])
AC_INIT(ima-evm-utils, 0.1.1, dmitry.kasatkin@intel.com) AC_INIT(evm-utils, 0.1, dmitry.kasatkin@intel.com)
AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
@ -47,7 +47,7 @@ fi
AC_CONFIG_FILES([Makefile AC_CONFIG_FILES([Makefile
src/Makefile src/Makefile
tests/Makefile tests/Makefile
ima-evm-utils.spec evm-utils.spec
]) ])
AC_OUTPUT AC_OUTPUT

View File

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

View File

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