Compare commits

..

18 Commits
v0.9 ... master

Author SHA1 Message Date
Dmitry Kasatkin
3e2a67bdb0 script to build static evmctl version
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@huawei.com>
2015-10-01 22:42:45 +03:00
Dmitry Kasatkin
839a674580 Supply file attributes values on command line
Can be used by Android filesystem image creation tool.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@huawei.com>
2015-09-20 23:28:20 +03:00
Dmitry Kasatkin
e55d286ad6 Use single flag to indicate 'no'flag
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@huawei.com>
2015-09-20 23:15:32 +03:00
Dmitry Kasatkin
28d99354de Use byte range values
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@huawei.com>
2015-09-20 22:22:06 +03:00
Dmitry Kasatkin
ea5ccdf38f Newer kernels requires at least 64 byte keys
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@huawei.com>
2015-09-20 22:22:00 +03:00
Patrick Ohly
b0d13ba557 calc_evm_hmac/hash: avoid fd leak when ioctl fails
When opening the file succeeds but ioctl() then fails, the file must
be closed before returning.

Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
2015-09-09 23:02:01 +03:00
Patrick Ohly
199311e6a5 ima_verify: ignore -n flag
"evmutil ima_verify -n <some file>" disabled using xattrs without enabling
using a signature file, resulting in the use of uninitialized memory in
ima_verify_signature() and thus unpredictable results.

Such a mode of operation makes no sense, so interpret -n as
documented ("print result to stdout instead of setting xattr") and ignore it
during ima_verify. Instead, switch between the two verification modes only
via the global sigfile variable.

Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
2015-09-09 22:50:45 +03:00
Patrick Ohly
453d3db8a5 tpm_pcr_read: close file when returning early
When return from inside the for() loop, the open file was not
closed.

Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
2015-09-09 22:50:35 +03:00
Patrick Ohly
fa0b30b15e add_dir_hash: fix DIR leak in case of failure
When bailing out of the function due to EVP_DigestUpdate()
failing, the DIR resources allocated with opendir() were
not freed.

Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
2015-09-09 22:50:18 +03:00
Dmitry Kasatkin
4b56112c09 Release version 1.0
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@huawei.com>
2015-07-30 21:28:53 +03:00
Mimi Zohar
9c8a67a209 Prompt for the password
Supplying the password on the command line is not safe.  This patch
adds support for prompting the user to enter the password.  At some
point, supplying the pasword on the command line should be deprecated.

Prior to this patch, the password could be specified with a blank in
between the '-p' option and the password.  With this patch, the
password now must be adjacent

Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
2015-07-28 21:42:35 +03:00
Dmitry Kasatkin
96e55082c2 Must use 'const char*'
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@huawei.com>
2015-07-24 22:51:39 +03:00
Mimi Zohar
6a712b3b38 Add support for passing the private key password to sign_hash()
evmctl defines the "--pass | -p" command line option for providing
the private key's password.  The password is then stored in a global
variable accessible by the sign_hash_XXXX() functions.

This patch modifies the arguments to the library sign_hash()
function to include the password, allowing callers to specify the
private key password.

Changelog:
- add library init to call OpenSSL_add_all_algorithms

Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
2015-07-24 22:51:27 +03:00
Dmitry Kasatkin
17f49a1881 Add "ima_clear" command to remove IMA/EVM xattrs
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-10-29 21:38:03 +02:00
Dmitry Kasatkin
4d7d2c71a5 Define common function for recursive scanning
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-10-29 21:31:58 +02:00
Dmitry Kasatkin
92033dc404 Produce immutable EVM signature
'evmctl sign -i <file>' generates immutable EVM signature.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-10-29 13:00:43 +02:00
Dmitry Kasatkin
f805d4d0fe Fix typo
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-10-29 12:33:58 +02:00
Dmitry Kasatkin
8558dc5250 Add recursive hashing
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-10-02 19:22:19 +03:00
8 changed files with 327 additions and 160 deletions

View File

@ -1,3 +1,12 @@
2014-07-30 Dmitry Kasatkin <dmitry.kasatkin@huawei.com>
version 1.0
* Recursive hashing
* Immutable EVM signatures (experimental)
* Command 'ima_clear' to remove xattrs
* Support for passing password to the library
* Support for asking password safely from the user
2014-09-23 Dmitry Kasatkin <d.kasatkin@samsung.com> 2014-09-23 Dmitry Kasatkin <d.kasatkin@samsung.com>
version 0.9 version 0.9

4
README
View File

@ -142,7 +142,7 @@ EVM encrypted key is used for EVM HMAC calculation:
keyctl pipe `keyctl search @u user kmk` > /etc/keys/kmk keyctl pipe `keyctl search @u user kmk` > /etc/keys/kmk
# create the EVM encrypted key # 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 keyctl pipe `keyctl search @u encrypted evm-key` >/etc/keys/evm-key
@ -403,7 +403,7 @@ When using plain RSA public keys in PEM format, use 'evmctl import --rsa' for im
Latest version of keyctl allows to import X509 public key certificates: Latest version of keyctl allows to import X509 public key certificates:
cat /etc/keys/x509_ima.der | keyctl padd asymmetric '' @ima_id cat /etc/keys/x509_ima.der | keyctl padd asymmetric '' $ima_id
FILES FILES

4
build-static.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/sh
gcc -static -o evmctl.static -include config.h src/evmctl.c src/libimaevm.c -lcrypto -lkeyutils -ldl

View File

@ -1,7 +1,7 @@
# autoconf script # autoconf script
AC_PREREQ([2.65]) AC_PREREQ([2.65])
AC_INIT(ima-evm-utils, 0.9, d.kasatkin@samsung.com) AC_INIT(ima-evm-utils, 1.0, dmitry.kasatkin@huawei.com)
AM_INIT_AUTOMAKE AM_INIT_AUTOMAKE
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])

View File

@ -1,5 +1,5 @@
Name: ima-evm-utils Name: ima-evm-utils
Version: 0.9 Version: 1.0
Release: 1%{?dist} Release: 1%{?dist}
Summary: ima-evm-utils - IMA/EVM control utility Summary: ima-evm-utils - IMA/EVM control utility
Group: System/Libraries Group: System/Libraries

View File

@ -54,6 +54,7 @@
#include <getopt.h> #include <getopt.h>
#include <keyutils.h> #include <keyutils.h>
#include <ctype.h> #include <ctype.h>
#include <termios.h>
#include <openssl/sha.h> #include <openssl/sha.h>
#include <openssl/pem.h> #include <openssl/pem.h>
@ -103,14 +104,24 @@ static int digest;
static int digsig; static int digsig;
static int sigfile; static int sigfile;
static char *uuid_str; 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 char *search_type;
static int recursive; static int recursive;
static int msize; static int msize;
static dev_t fs_dev; static dev_t fs_dev;
static bool evm_immutable;
#define HMAC_FLAG_UUID 0x0001 #define HMAC_FLAG_NO_UUID 0x0001
#define HMAC_FLAG_UUID_SET 0x0002 #define HMAC_FLAG_CAPS_SET 0x0002
static unsigned long hmac_flags = HMAC_FLAG_UUID;
static unsigned long hmac_flags;
typedef int (*find_cb_t)(const char *path); typedef int (*find_cb_t)(const char *path);
static int find(const char *path, int dts, find_cb_t func); static int find(const char *path, int dts, find_cb_t func);
@ -198,7 +209,7 @@ static int hex_to_bin(char ch)
return -1; 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; int hi, lo;
@ -212,7 +223,7 @@ static int hex2bin(uint8_t *dst, const char *src, size_t count)
if ((hi < 0) || (lo < 0)) if ((hi < 0) || (lo < 0))
return -1; return -1;
*dst++ = (hi << 4) | lo; *(uint8_t *)dst++ = (hi << 4) | lo;
} }
return 0; return 0;
} }
@ -273,7 +284,7 @@ static int get_uuid(struct stat *st, char *uuid)
FILE *fp; FILE *fp;
size_t len; size_t len;
if (hmac_flags & HMAC_FLAG_UUID_SET) if (uuid_str)
return pack_uuid(uuid_str, uuid); return pack_uuid(uuid_str, uuid);
dev = st->st_dev; dev = st->st_dev;
@ -318,9 +329,21 @@ static int calc_evm_hash(const char *file, unsigned char *hash)
return -1; return -1;
} }
if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) { if (generation_str)
/* we cannot at the momement to get generation of special files.. generation = strtoul(generation_str, NULL, 10);
* kernel API does not support it */ 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)) && !generation_str) {
/* we cannot at the momement to get generation of
special files kernel API does not support it */
int fd = open(file, 0); int fd = open(file, 0);
if (fd < 0) { if (fd < 0) {
@ -329,12 +352,13 @@ static int calc_evm_hash(const char *file, unsigned char *hash)
} }
if (ioctl(fd, FS_IOC_GETVERSION, &generation)) { if (ioctl(fd, FS_IOC_GETVERSION, &generation)) {
log_err("ioctl() failed\n"); log_err("ioctl() failed\n");
close(fd);
return -1; return -1;
} }
close(fd); close(fd);
} }
log_info("generation: %u\n", generation); log_info("generation: %u\n", generation);
}
list_size = llistxattr(file, list, sizeof(list)); list_size = llistxattr(file, list, sizeof(list));
if (list_size < 0) { if (list_size < 0) {
@ -349,6 +373,18 @@ static int calc_evm_hash(const char *file, unsigned char *hash)
} }
for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) { for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) {
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)); err = lgetxattr(file, *xattrname, xattr_value, sizeof(xattr_value));
if (err < 0) { if (err < 0) {
log_info("no xattr: %s\n", *xattrname); log_info("no xattr: %s\n", *xattrname);
@ -358,6 +394,7 @@ static int calc_evm_hash(const char *file, unsigned char *hash)
log_info("skipping xattr: %s\n", *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);
@ -370,7 +407,14 @@ static int calc_evm_hash(const char *file, unsigned char *hash)
memset(&hmac_misc, 0, sizeof(hmac_misc)); memset(&hmac_misc, 0, sizeof(hmac_misc));
if (msize == 0) { if (evm_immutable) {
struct h_misc_digsig *hmac = (struct h_misc_digsig *)&hmac_misc;
hmac_size = sizeof(*hmac);
hmac->uid = st.st_uid;
hmac->gid = st.st_gid;
hmac->mode = st.st_mode;
} else if (msize == 0) {
struct h_misc *hmac = (struct h_misc *)&hmac_misc; struct h_misc *hmac = (struct h_misc *)&hmac_misc;
hmac_size = sizeof(*hmac); hmac_size = sizeof(*hmac);
@ -408,7 +452,7 @@ static int calc_evm_hash(const char *file, unsigned char *hash)
return 1; return 1;
} }
if (hmac_flags & HMAC_FLAG_UUID) { if (!evm_immutable && !(hmac_flags & HMAC_FLAG_NO_UUID)) {
err = get_uuid(&st, uuid); err = get_uuid(&st, uuid);
if (err) if (err)
return -1; return -1;
@ -439,7 +483,7 @@ static int sign_evm(const char *file, const char *key)
if (len <= 1) if (len <= 1)
return len; return len;
len = sign_hash("sha1", hash, len, key, sig + 1); len = sign_hash("sha1", hash, len, key, NULL, sig + 1);
if (len <= 1) if (len <= 1)
return len; return len;
@ -447,6 +491,9 @@ static int sign_evm(const char *file, const char *key)
len++; len++;
sig[0] = EVM_IMA_XATTR_DIGSIG; sig[0] = EVM_IMA_XATTR_DIGSIG;
if (evm_immutable)
sig[1] = 3; /* immutable signature version */
if (sigdump || params.verbose >= LOG_INFO) if (sigdump || params.verbose >= LOG_INFO)
dump(sig, len); dump(sig, len);
@ -499,19 +546,6 @@ static int hash_ima(const char *file)
return 0; return 0;
} }
static int cmd_hash_ima(struct command *cmd)
{
char *file = g_argv[optind++];
if (!file) {
log_err("Parameters missing\n");
print_usage(cmd);
return -1;
}
return hash_ima(file);
}
static int sign_ima(const char *file, const char *key) static int sign_ima(const char *file, const char *key)
{ {
unsigned char hash[64]; unsigned char hash[64];
@ -522,7 +556,7 @@ static int sign_ima(const char *file, const char *key)
if (len <= 1) if (len <= 1)
return len; return len;
len = sign_hash(params.hash_algo, hash, len, key, sig + 1); len = sign_hash(params.hash_algo, hash, len, key, NULL, sig + 1);
if (len <= 1) if (len <= 1)
return len; return len;
@ -577,9 +611,39 @@ static int get_file_type(const char *path, const char *search_type)
return dts; return dts;
} }
static int do_cmd(struct command *cmd, find_cb_t func)
{
char *path = g_argv[optind++];
int err, dts = REG_MASK; /* only regular files by default */
if (!path) {
log_err("Parameters missing\n");
print_usage(cmd);
return -1;
}
if (recursive) {
if (search_type) {
dts = get_file_type(path, search_type);
if (dts < 0)
return dts;
}
err = find(path, dts, func);
} else {
err = func(path);
}
return err;
}
static int cmd_hash_ima(struct command *cmd)
{
return do_cmd(cmd, hash_ima);
}
static int sign_ima_file(const char *file) static int sign_ima_file(const char *file)
{ {
char *key; const char *key;
key = params.keyfile ? : "/etc/keys/privkey_evm.pem"; key = params.keyfile ? : "/etc/keys/privkey_evm.pem";
@ -588,32 +652,13 @@ static int sign_ima_file(const char *file)
static int cmd_sign_ima(struct command *cmd) static int cmd_sign_ima(struct command *cmd)
{ {
char *file = g_argv[optind++]; return do_cmd(cmd, sign_ima_file);
int err, dts = REG_MASK; /* only regular files by default */
if (!file) {
log_err("Parameters missing\n");
print_usage(cmd);
return -1;
}
if (recursive) {
if (search_type) {
dts = get_file_type(file, search_type);
if (dts < 0)
return dts;
}
err = find(file, dts, sign_ima_file);
} else {
err = sign_ima_file(file);
}
return err;
} }
static int cmd_sign_hash(struct command *cmd) static int cmd_sign_hash(struct command *cmd)
{ {
char *key, *token, *line = NULL; const char *key;
char *token, *line = NULL;
int hashlen = 0; int hashlen = 0;
size_t line_len; size_t line_len;
ssize_t len; ssize_t len;
@ -635,7 +680,7 @@ static int cmd_sign_hash(struct command *cmd)
hex2bin(hash, line, hashlen); hex2bin(hash, line, hashlen);
siglen = sign_hash(params.hash_algo, hash, hashlen/2, siglen = sign_hash(params.hash_algo, hash, hashlen/2,
key, sig + 1); key, NULL, sig + 1);
if (siglen <= 1) if (siglen <= 1)
return siglen; return siglen;
@ -656,7 +701,7 @@ static int cmd_sign_hash(struct command *cmd)
static int sign_evm_path(const char *file) static int sign_evm_path(const char *file)
{ {
char *key; const char *key;
int err; int err;
key = params.keyfile ? : "/etc/keys/privkey_evm.pem"; key = params.keyfile ? : "/etc/keys/privkey_evm.pem";
@ -678,27 +723,7 @@ static int sign_evm_path(const char *file)
static int cmd_sign_evm(struct command *cmd) static int cmd_sign_evm(struct command *cmd)
{ {
char *path = g_argv[optind++]; return do_cmd(cmd, sign_evm_path);
int err, dts = REG_MASK; /* only regular files by default */
if (!path) {
log_err("Parameters missing\n");
print_usage(cmd);
return -1;
}
if (recursive) {
if (search_type) {
dts = get_file_type(path, search_type);
if (dts < 0)
return dts;
}
err = find(path, dts, sign_evm_path);
} else {
err = sign_evm_path(path);
}
return err;
} }
static int verify_evm(const char *file) static int verify_evm(const char *file)
@ -743,19 +768,17 @@ static int verify_ima(const char *file)
unsigned char sig[1024]; unsigned char sig[1024];
int len; 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) { if (sigfile) {
void *tmp = file2bin(file, "sig", &len); void *tmp = file2bin(file, "sig", &len);
memcpy(sig, tmp, len); memcpy(sig, tmp, len);
free(tmp); 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);
@ -774,6 +797,38 @@ static int cmd_verify_ima(struct command *cmd)
return verify_ima(file); return verify_ima(file);
} }
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) static int cmd_import(struct command *cmd)
{ {
char *inkey, *ring = NULL; char *inkey, *ring = NULL;
@ -896,6 +951,7 @@ static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *h
} }
if (ioctl(fd, FS_IOC_GETVERSION, &generation)) { if (ioctl(fd, FS_IOC_GETVERSION, &generation)) {
log_err("ioctl() failed\n"); log_err("ioctl() failed\n");
close(fd);
goto out; goto out;
} }
close(fd); close(fd);
@ -1012,7 +1068,7 @@ static int hmac_evm(const char *file, const char *key)
static int cmd_hmac_evm(struct command *cmd) static int cmd_hmac_evm(struct command *cmd)
{ {
char *key, *file = g_argv[optind++]; const char *key, *file = g_argv[optind++];
int err; int err;
if (!file) { if (!file) {
@ -1129,36 +1185,30 @@ static int find(const char *path, int dts, find_cb_t func)
static int cmd_ima_fix(struct command *cmd) static int cmd_ima_fix(struct command *cmd)
{ {
char *path = g_argv[optind++]; return do_cmd(cmd, ima_fix);
int err, dts = REG_MASK; /* only regular files by default */
if (!path) {
log_err("Parameters missing\n");
print_usage(cmd);
return -1;
} }
if (recursive) { static int ima_clear(const char *path)
if (search_type) { {
dts = get_file_type(path, search_type); log_info("%s\n", path);
if (dts < 0) lremovexattr(path, "security.ima");
return dts; lremovexattr(path, "security.evm");
}
err = find(path, dts, ima_fix); return 0;
} else {
err = ima_fix(path);
} }
return err; static int cmd_ima_clear(struct command *cmd)
{
return do_cmd(cmd, ima_clear);
} }
static char *pcrs = "/sys/class/misc/tpm0/device/pcrs"; static char *pcrs = "/sys/class/misc/tpm0/device/pcrs";
static int tpm_pcr_read(int idx, uint8_t *pcr, int len) static int tpm_pcr_read(int idx, uint8_t *pcr, int len)
{ {
FILE *fp; FILE *fp;
char *p, pcr_str[7], buf[70]; /* length of the TPM string */ char *p, pcr_str[7], buf[70]; /* length of the TPM string */
int result = -1;
sprintf(pcr_str, "PCR-%d", idx); sprintf(pcr_str, "PCR-%d", idx);
@ -1174,11 +1224,12 @@ static int tpm_pcr_read(int idx, uint8_t *pcr, int len)
break; break;
if (!strncmp(p, pcr_str, 6)) { if (!strncmp(p, pcr_str, 6)) {
hex2bin(pcr, p + 7, len); hex2bin(pcr, p + 7, len);
return 0; result = 0;
break;
} }
} }
fclose(fp); fclose(fp);
return -1; return result;
} }
#define TCG_EVENT_NAME_LEN_MAX 255 #define TCG_EVENT_NAME_LEN_MAX 255
@ -1476,6 +1527,14 @@ static void usage(void)
" --smack use extra SMACK xattrs for EVM\n" " --smack use extra SMACK xattrs for EVM\n"
" --m32 force EVM hmac/signature for 32 bit target system\n" " --m32 force EVM hmac/signature for 32 bit target system\n"
" --m64 force EVM hmac/signature for 64 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"
" -v increase verbosity level\n" " -v increase verbosity level\n"
" -h, --help display this help and exit\n" " -h, --help display this help and exit\n"
"\n"); "\n");
@ -1485,14 +1544,16 @@ struct command cmds[] = {
{"--version", NULL, 0, ""}, {"--version", NULL, 0, ""},
{"help", cmd_help, 0, "<command>"}, {"help", cmd_help, 0, "<command>"},
{"import", cmd_import, 0, "[--rsa] pubkey keyring", "Import public key into the keyring.\n"}, {"import", cmd_import, 0, "[--rsa] pubkey keyring", "Import public key into the keyring.\n"},
{"sign", cmd_sign_evm, 0, "[-r] [--imahash | --imasig ] [--key key] [--pass password] file", "Sign file metadata.\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"}, {"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_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_verify", cmd_verify_ima, 0, "file", "Verify IMA signature (for debugging).\n"},
{"ima_hash", cmd_hash_ima, 0, "file", "Make file content hash.\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_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"}, {"ima_fix", cmd_ima_fix, 0, "[-t fdsxm] path", "Recursively fix IMA/EVM xattrs in fix mode.\n"},
{"sign_hash", cmd_sign_hash, 0, "[--key key] [--pass password]", "Sign hashes from shaXsum output.\n"}, {"ima_clear", cmd_ima_clear, 0, "[-t fdsxm] path", "Recursively remove IMA/EVM xattrs.\n"},
{"sign_hash", cmd_sign_hash, 0, "[--key key] [--pass [password]", "Sign hashes from shaXsum output.\n"},
#ifdef DEBUG #ifdef DEBUG
{"hmac", cmd_hmac_evm, 0, "[--imahash | --imasig ] file", "Sign file metadata with HMAC using symmetric key (for testing purpose).\n"}, {"hmac", cmd_hmac_evm, 0, "[--imahash | --imasig ] file", "Sign file metadata with HMAC using symmetric key (for testing purpose).\n"},
#endif #endif
@ -1504,7 +1565,7 @@ static struct option opts[] = {
{"imasig", 0, 0, 's'}, {"imasig", 0, 0, 's'},
{"imahash", 0, 0, 'd'}, {"imahash", 0, 0, 'd'},
{"hashalgo", 1, 0, 'a'}, {"hashalgo", 1, 0, 'a'},
{"pass", 1, 0, 'p'}, {"pass", 2, 0, 'p'},
{"sigfile", 0, 0, 'f'}, {"sigfile", 0, 0, 'f'},
{"uuid", 2, 0, 'u'}, {"uuid", 2, 0, 'u'},
{"rsa", 0, 0, '1'}, {"rsa", 0, 0, '1'},
@ -1513,12 +1574,54 @@ static struct option opts[] = {
{"recursive", 0, 0, 'r'}, {"recursive", 0, 0, 'r'},
{"m32", 0, 0, '3'}, {"m32", 0, 0, '3'},
{"m64", 0, 0, '6'}, {"m64", 0, 0, '6'},
{"smack", 0, 0, 256}, {"smack", 0, 0, 128},
{"version", 0, 0, 257}, {"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},
{} {}
}; };
static char *get_password(void)
{
struct termios flags, tmp_flags;
char *password, *pwd;
int passlen = 64;
password = malloc(passlen);
if (!password) {
perror("malloc");
return NULL;
}
tcgetattr(fileno(stdin), &flags);
tmp_flags = flags;
tmp_flags.c_lflag &= ~ECHO;
tmp_flags.c_lflag |= ECHONL;
if (tcsetattr(fileno(stdin), TCSANOW, &tmp_flags) != 0) {
perror("tcsetattr");
return NULL;
}
printf("PEM password: ");
pwd = fgets(password, passlen, stdin);
/* restore terminal */
if (tcsetattr(fileno(stdin), TCSANOW, &flags) != 0) {
perror("tcsetattr");
return NULL;
}
return pwd;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int err = 0, c, lind; int err = 0, c, lind;
@ -1527,7 +1630,7 @@ int main(int argc, char *argv[])
g_argc = argc; g_argc = argc;
while (1) { while (1) {
c = getopt_long(argc, argv, "hvnsda:p:fu::k:t:r", opts, &lind); c = getopt_long(argc, argv, "hvnsda:p::fu::k:t:ri", opts, &lind);
if (c == -1) if (c == -1)
break; break;
@ -1554,18 +1657,18 @@ int main(int argc, char *argv[])
params.hash_algo = optarg; params.hash_algo = optarg;
break; break;
case 'p': case 'p':
if (optarg)
params.keypass = optarg; params.keypass = optarg;
else
params.keypass = get_password();
break; break;
case 'f': case 'f':
sigfile = 1; sigfile = 1;
xattr = 0;
break; break;
case 'u': case 'u':
uuid_str = optarg; uuid_str = optarg;
if (uuid_str) if (!uuid_str)
hmac_flags |= HMAC_FLAG_UUID_SET; hmac_flags |= HMAC_FLAG_NO_UUID;
else
hmac_flags &= ~HMAC_FLAG_UUID;
break; break;
case '1': case '1':
params.x509 = 0; params.x509 = 0;
@ -1573,6 +1676,9 @@ int main(int argc, char *argv[])
case 'k': case 'k':
params.keyfile = optarg; params.keyfile = optarg;
break; break;
case 'i':
evm_immutable = true;
break;
case 't': case 't':
search_type = optarg; search_type = optarg;
break; break;
@ -1585,13 +1691,38 @@ int main(int argc, char *argv[])
case '6': case '6':
msize = 64; msize = 64;
break; break;
case 256: case 128:
evm_config_xattrnames = evm_extra_smack_xattrs; evm_config_xattrnames = evm_extra_smack_xattrs;
break; break;
case 257: case 129:
printf("evmctl %s\n", VERSION); printf("evmctl %s\n", VERSION);
exit(0); exit(0);
break; 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 '?': case '?':
exit(1); exit(1);
break; break;
@ -1600,9 +1731,6 @@ int main(int argc, char *argv[])
} }
} }
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
if (argv[optind] == NULL) if (argv[optind] == NULL)
usage(); usage();
else else
@ -1623,6 +1751,6 @@ int main(int argc, char *argv[])
ERR_free_strings(); ERR_free_strings();
EVP_cleanup(); EVP_cleanup();
BIO_free(NULL);
return err; return err;
} }

View File

@ -108,6 +108,12 @@ struct h_misc_64 {
unsigned short mode; unsigned short mode;
}; };
struct h_misc_digsig {
uid_t uid;
gid_t gid;
unsigned short mode;
};
enum pubkey_algo { enum pubkey_algo {
PUBKEY_ALGO_RSA, PUBKEY_ALGO_RSA,
PUBKEY_ALGO_MAX, PUBKEY_ALGO_MAX,
@ -172,8 +178,8 @@ struct libevm_params {
int verbose; int verbose;
int x509; int x509;
const char *hash_algo; const char *hash_algo;
char *keyfile; const char *keyfile;
char *keypass; const char *keypass;
}; };
struct RSA_ASN1_template { struct RSA_ASN1_template {
@ -195,7 +201,7 @@ void calc_keyid_v1(uint8_t *keyid, char *str, const unsigned char *pkey, int len
void calc_keyid_v2(uint32_t *keyid, char *str, RSA *key); void calc_keyid_v2(uint32_t *keyid, char *str, RSA *key);
int key2bin(RSA *key, unsigned char *pub); int key2bin(RSA *key, unsigned char *pub);
int sign_hash(const char *algo, const unsigned char *hash, int size, const char *keyfile, unsigned char *sig); 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 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 ima_verify_signature(const char *file, unsigned char *sig, int siglen);

View File

@ -53,6 +53,7 @@
#include <openssl/pem.h> #include <openssl/pem.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/x509.h> #include <openssl/x509.h>
#include <openssl/err.h>
#include "imaevm.h" #include "imaevm.h"
@ -130,6 +131,8 @@ struct libevm_params params = {
.hash_algo = "sha1", .hash_algo = "sha1",
}; };
static void __attribute__ ((constructor)) libinit(void);
void do_dump(FILE *fp, const void *ptr, int len, bool cr) void do_dump(FILE *fp, const void *ptr, int len, bool cr)
{ {
int i; int i;
@ -211,6 +214,7 @@ static int add_dir_hash(const char *file, EVP_MD_CTX *ctx)
DIR *dir; DIR *dir;
unsigned long long ino, off; unsigned long long ino, off;
unsigned int type; unsigned int type;
int result = 0;
dir = opendir(file); dir = opendir(file);
if (!dir) { if (!dir) {
@ -230,13 +234,14 @@ static int add_dir_hash(const char *file, EVP_MD_CTX *ctx)
err |= EVP_DigestUpdate(ctx, &type, sizeof(type)); err |= EVP_DigestUpdate(ctx, &type, sizeof(type));
if (!err) { if (!err) {
log_err("EVP_DigestUpdate() failed\n"); log_err("EVP_DigestUpdate() failed\n");
return 1; result = 1;
break;
} }
} }
closedir(dir); closedir(dir);
return 0; return result;
} }
static int add_link_hash(const char *path, EVP_MD_CTX *ctx) static int add_link_hash(const char *path, EVP_MD_CTX *ctx)
@ -370,7 +375,7 @@ int verify_hash_v1(const unsigned char *hash, int size, unsigned char *sig, int
unsigned char sighash[20]; unsigned char sighash[20];
struct signature_hdr *hdr = (struct signature_hdr *)sig; struct signature_hdr *hdr = (struct signature_hdr *)sig;
log_info("hash: "); log_info("hash-v1: ");
log_dump(hash, size); log_dump(hash, size);
key = read_pub_key(keyfile, 0); key = read_pub_key(keyfile, 0);
@ -488,7 +493,7 @@ static int get_hash_algo_from_sig(unsigned char *sig)
int verify_hash(const unsigned char *hash, int size, unsigned char *sig, int siglen) int verify_hash(const unsigned char *hash, int size, unsigned char *sig, int siglen)
{ {
char *key; const char *key;
int x509; int x509;
verify_hash_fn_t verify_hash; verify_hash_fn_t verify_hash;
@ -584,7 +589,7 @@ void calc_keyid_v1(uint8_t *keyid, char *str, const unsigned char *pkey, int len
id = __be64_to_cpup((__be64 *) keyid); id = __be64_to_cpup((__be64 *) keyid);
sprintf(str, "%llX", (unsigned long long)id); sprintf(str, "%llX", (unsigned long long)id);
log_info("keyid: %s\n", str); log_info("keyid-v1: %s\n", str);
} }
void calc_keyid_v2(uint32_t *keyid, char *str, RSA *key) void calc_keyid_v2(uint32_t *keyid, char *str, RSA *key)
@ -608,7 +613,7 @@ void calc_keyid_v2(uint32_t *keyid, char *str, RSA *key)
free(pkey); free(pkey);
} }
static RSA *read_priv_key(const char *keyfile, char *keypass) static RSA *read_priv_key(const char *keyfile, const char *keypass)
{ {
FILE *fp; FILE *fp;
RSA *key; RSA *key;
@ -618,9 +623,14 @@ static RSA *read_priv_key(const char *keyfile, char *keypass)
log_err("Failed to open keyfile: %s\n", keyfile); log_err("Failed to open keyfile: %s\n", keyfile);
return NULL; return NULL;
} }
key = PEM_read_RSAPrivateKey(fp, NULL, NULL, keypass); ERR_load_crypto_strings();
if (!key) key = PEM_read_RSAPrivateKey(fp, NULL, NULL, (void *)keypass);
log_err("PEM_read_RSAPrivateKey() failed\n"); if (!key) {
char str[256];
ERR_error_string(ERR_get_error(), str);
log_err("PEM_read_RSAPrivateKey() failed: %s\n", str);
}
fclose(fp); fclose(fp);
return key; return key;
@ -711,7 +721,7 @@ int sign_hash_v1(const char *hashalgo, const unsigned char *hash, int size, cons
blen = (uint16_t *) (sig + sizeof(*hdr)); blen = (uint16_t *) (sig + sizeof(*hdr));
*blen = __cpu_to_be16(len << 3); *blen = __cpu_to_be16(len << 3);
len += sizeof(*hdr) + 2; len += sizeof(*hdr) + 2;
log_info("evm/ima signature: %d bytes\n", len); log_info("evm/ima signature-v1: %d bytes\n", len);
out: out:
RSA_free(key); RSA_free(key);
return len; return len;
@ -786,8 +796,18 @@ out:
return len; return len;
} }
int sign_hash(const char *hashalgo, const unsigned char *hash, int size, const char *keyfile, unsigned char *sig)
int sign_hash(const char *hashalgo, const unsigned char *hash, int size, const char *keyfile, const char *keypass, unsigned char *sig)
{ {
if (keypass)
params.keypass = keypass;
return params.x509 ? sign_hash_v2(hashalgo, hash, size, keyfile, sig) : return params.x509 ? sign_hash_v2(hashalgo, hash, size, keyfile, sig) :
sign_hash_v1(hashalgo, hash, size, keyfile, sig); sign_hash_v1(hashalgo, hash, size, keyfile, sig);
} }
static void libinit()
{
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
}