1
0
mirror of https://git.code.sf.net/p/linux-ima/ima-evm-utils synced 2025-07-04 06:25:15 +02:00

9 Commits
v0.9 ... v1.0

Author SHA1 Message Date
4b56112c09 Release version 1.0
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@huawei.com>
2015-07-30 21:28:53 +03:00
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
96e55082c2 Must use 'const char*'
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@huawei.com>
2015-07-24 22:51:39 +03:00
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
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
4d7d2c71a5 Define common function for recursive scanning
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-10-29 21:31:58 +02:00
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
f805d4d0fe Fix typo
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-10-29 12:33:58 +02:00
8558dc5250 Add recursive hashing
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-10-02 19:22:19 +03:00
7 changed files with 176 additions and 121 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

2
README
View File

@ -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

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>
@ -107,6 +108,7 @@ 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_UUID 0x0001
#define HMAC_FLAG_UUID_SET 0x0002 #define HMAC_FLAG_UUID_SET 0x0002
@ -318,6 +320,7 @@ static int calc_evm_hash(const char *file, unsigned char *hash)
return -1; return -1;
} }
if (!evm_immutable) {
if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) { if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) {
/* we cannot at the momement to get generation of special files.. /* we cannot at the momement to get generation of special files..
* kernel API does not support it */ * kernel API does not support it */
@ -333,8 +336,8 @@ static int calc_evm_hash(const char *file, unsigned char *hash)
} }
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) {
@ -370,7 +373,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 +418,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_UUID)) {
err = get_uuid(&st, uuid); err = get_uuid(&st, uuid);
if (err) if (err)
return -1; return -1;
@ -439,7 +449,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 +457,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 +512,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 +522,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 +577,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 +618,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 +646,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 +667,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 +689,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)
@ -1012,7 +1003,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,29 +1120,22 @@ 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) {
if (search_type) {
dts = get_file_type(path, search_type);
if (dts < 0)
return dts;
}
err = find(path, dts, ima_fix);
} else {
err = ima_fix(path);
}
return err;
} }
static int ima_clear(const char *path)
{
log_info("%s\n", path);
lremovexattr(path, "security.ima");
lremovexattr(path, "security.evm");
return 0;
}
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";
@ -1485,14 +1469,15 @@ 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"}, {"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 +1489,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'},
@ -1519,6 +1504,40 @@ static struct option opts[] = {
}; };
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 +1546,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,7 +1573,10 @@ 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;
@ -1573,6 +1595,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;
@ -1600,9 +1625,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 +1645,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;
@ -488,7 +491,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;
@ -608,7 +611,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 +621,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;
@ -786,8 +794,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();
}