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

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 234 additions and 201 deletions

View File

@ -1,3 +1,8 @@
2012-04-02 Dmitry Kasatkin <dmitry.kasatkin@intel.com>
version 0.1.0
* Fully functional version for lastest 3.x kernels
2011-08-24 Dmitry Kasatkin <dmitry.kasatkin@intel.com>
version 0.1

12
README
View File

@ -1,8 +1,17 @@
1. Generate private key
# plain key
openssl genrsa -out privkey_evm.pem 1024
# encrypted key
openssl genrsa -des3 -out privkey_evm.pem 1024
# set password for the key
openssl rsa -in /etc/keys/privkey_evm.pem -out privkey_evm_enc.pem -des3
or
openssl pkcs8 -topk8 -in /etc/keys/privkey_evm.pem -out privkey_evm_enc.pem
2. Generate public key
openssl rsa -pubout -in privkey_evm.pem -out pubkey_evm.pem
@ -34,6 +43,9 @@ find /lib/modules ! -name "*.ko" -type f -uid 0 -exec evmctl sign --imahash '{}'
# security.ima needs to have signature for modules
find /lib/modules -name "*.ko" -type f -uid 0 -exec evmctl sign --imasig '{}' \;
# generate signatures in .sig files
find /lib/modules -name "*.ko" -type f -uid 0 -exec evmctl -n --sigfile ima_sign '{}' \;
8. Label filesystem in fix mode...
ima_fix_dir.sh <dir>

View File

@ -33,7 +33,7 @@ AC_CHECK_HEADERS(openssl/conf.h)
#debug support - yes for a while
PKG_ARG_ENABLE(debug, "yes", DEBUG, [Enable Debug support])
if test $pkg_cv_enable_debug = yes; then
CFLAGS="-g -O1 -Wall -Wstrict-prototypes -pipe"
CFLAGS="$CFLAGS -g -O1 -Wall -Wstrict-prototypes -pipe"
else
CFLAGS="$CFLAGS -Wall -Wstrict-prototypes -pipe -fomit-frame-pointer"
fi

View File

@ -45,17 +45,19 @@
#include <attr/xattr.h>
#include <dirent.h>
#include <openssl/sha.h>
#include <openssl/sha.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/hmac.h>
#include <openssl/engine.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#define USE_FPRINTF
#ifdef USE_FPRINTF
#define do_log(level, fmt, args...) if (level <= verbose) fprintf(stderr, fmt, ##args)
#define do_log_dump(level, p, len) if (level <= verbose) do_dump(stderr, p, len)
#define do_log(level, fmt, args...) ({ if (level <= verbose) fprintf(stderr, fmt, ##args); })
#define do_log_dump(level, p, len) ({ if (level <= verbose) do_dump(stderr, p, len); })
#else
#define do_log(level, fmt, args...) syslog(level, fmt, ##args)
#define do_log_dump(p, len)
@ -105,25 +107,23 @@ enum digest_algo {
};
struct pubkey_hdr {
uint8_t version; /* key format version */
time_t timestamp; /* key made, always 0 for now */
uint8_t algo;
uint8_t nmpi;
char mpi[0];
uint8_t version; /* key format version */
uint32_t timestamp; /* key made, always 0 for now */
uint8_t algo;
uint8_t nmpi;
char mpi[0];
} __attribute__ ((packed));
struct signature_hdr {
uint8_t version; /* signature format version */
time_t timestamp; /* signature made */
uint8_t algo;
uint8_t hash;
uint8_t keyid[8];
uint8_t nmpi;
char mpi[0];
uint8_t version; /* signature format version */
uint32_t timestamp; /* signature made */
uint8_t algo;
uint8_t hash;
uint8_t keyid[8];
uint8_t nmpi;
char mpi[0];
} __attribute__ ((packed));
static char *evm_config_xattrnames[] = {
"security.selinux",
"security.SMACK64",
@ -133,34 +133,35 @@ static char *evm_config_xattrnames[] = {
};
struct command {
char *name;
int (*func)(struct command *cmd);
int cmd;
char *arg;
char *msg; /* extra info message */
char *name;
int (*func)(struct command *cmd);
int cmd;
char *arg;
char *msg; /* extra info message */
};
static int verbose = LOG_INFO - 1;
static int g_argc;
static char **g_argv;
static int set_xattr = 1;
static int digest = 0;
static int digsig = 0;
static char *hash_algo = "sha1";
static int binkey = 0;
static int verbose = LOG_INFO - 1;
static int g_argc;
static char **g_argv;
static int xattr = 1;
static int digest;
static int digsig;
static char *hash_algo = "sha1";
static int binkey;
static char *keypass;
static int sigfile;
extern struct command cmds[];
struct command cmds[];
static void print_usage(struct command *cmd);
static void do_dump(FILE *fp, const void *ptr, int len)
{
int i;
uint8_t *data = (uint8_t *)ptr;
int i;
uint8_t *data = (uint8_t *) ptr;
for (i = 0; i < len; i++) {
fprintf(fp, "%02x", data[i]);
}
fprintf(fp, "\n");
for (i = 0; i < len; i++)
fprintf(fp, "%02x", data[i]);
fprintf(fp, "\n");
}
static void dump(const void *ptr, int len)
@ -173,7 +174,7 @@ static inline int get_filesize(const char *filename)
struct stat stats;
/* Need to know the file length */
stat(filename, &stats);
return (int) stats.st_size;
return (int)stats.st_size;
}
static inline int get_fdsize(int fd)
@ -181,7 +182,7 @@ static inline int get_fdsize(int fd)
struct stat stats;
/* Need to know the file length */
fstat(fd, &stats);
return (int) stats.st_size;
return (int)stats.st_size;
}
static int bin2file(const char *file, const char *ext, const unsigned char *data, int len)
@ -244,7 +245,6 @@ static int key2bin(RSA *key, unsigned char *pub)
offset += sizeof(*pkh);
// MPIs
len = BN_num_bytes(key->n);
b = BN_num_bits(key->n);
pub[offset++] = b >> 8;
@ -288,7 +288,6 @@ static int read_key(const char *inkey, unsigned char *pub)
return len;
}
static void calc_keyid(uint8_t *keyid, char *str, const unsigned char *pkey, int len)
{
uint8_t sha1[SHA_DIGEST_LENGTH];
@ -298,12 +297,12 @@ static void calc_keyid(uint8_t *keyid, char *str, const unsigned char *pkey, int
log_debug_dump(pkey, len);
SHA1(pkey, len, sha1);
//sha1[12 - 19] is exactly keyid from gpg file
/* sha1[12 - 19] is exactly keyid from gpg file */
memcpy(keyid, sha1 + 12, 8);
log_debug("keyid:\n");
log_debug_dump(keyid, 8);
id = __be64_to_cpup((__be64 *)keyid);
id = __be64_to_cpup((__be64 *) keyid);
sprintf(str, "%llX", (unsigned long long)id);
log_info("keyid: %s\n", str);
}
@ -328,7 +327,7 @@ static int sign_hash(const unsigned char *hash, int size, const char *keyfile, u
log_errno("Unable to open keyfile %s", keyfile);
return -1;
}
key1 = PEM_read_RSAPrivateKey(fp, &key, NULL, NULL);
key1 = PEM_read_RSAPrivateKey(fp, &key, NULL, keypass);
fclose(fp);
if (!key1) {
log_errno("RSAPrivateKey() failed");
@ -337,7 +336,7 @@ static int sign_hash(const unsigned char *hash, int size, const char *keyfile, u
/* now create a new hash */
hdr->version = 1;
time(&hdr->timestamp);
hdr->timestamp = time(NULL);
hdr->algo = PUBKEY_ALGO_RSA;
hdr->hash = DIGEST_ALGO_SHA1;
@ -363,17 +362,17 @@ static int sign_hash(const unsigned char *hash, int size, const char *keyfile, u
len = err;
/* we add bit length of the signature to make it gnupg compatible */
blen = (uint16_t *)(sig + sizeof(*hdr));
blen = (uint16_t *) (sig + sizeof(*hdr));
*blen = __cpu_to_be16(len << 3);
len += sizeof(*hdr) + 2;
log_info("evm/ima signature: %d bytes\n", len);
if (!set_xattr || verbose >= LOG_INFO)
if (!xattr || verbose >= LOG_INFO)
dump(sig, len);
return len;
}
static int calc_evm_hash(const char *file, const char *keyfile, unsigned char *hash)
static int calc_evm_hash(const char *file, unsigned char *hash)
{
struct stat st;
int fd, err;
@ -404,8 +403,6 @@ static int calc_evm_hash(const char *file, const char *keyfile, unsigned char *h
log_info("generation: %u\n", generation);
OpenSSL_add_all_digests();
md = EVP_get_digestbyname("sha1");
if (!md) {
log_errno("EVP_get_digestbyname() failed");
@ -424,7 +421,7 @@ static int calc_evm_hash(const char *file, const char *keyfile, unsigned char *h
log_info("no attr: %s\n", *xattrname);
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_debug_dump(xattr_value, err);
err = EVP_DigestUpdate(&ctx, xattr_value, err);
@ -441,7 +438,7 @@ static int calc_evm_hash(const char *file, const char *keyfile, unsigned char *h
hmac_misc.gid = st.st_gid;
hmac_misc.mode = st.st_mode;
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) {
log_errno("EVP_DigestUpdate() failed");
return -1;
@ -461,13 +458,13 @@ static int sign_evm(const char *file, const char *key)
unsigned char sig[1024] = "\x03";
int err;
calc_evm_hash(file, key, hash);
calc_evm_hash(file, hash);
err = sign_hash(hash, sizeof(hash), key, sig + 1);
if (err < 0)
return err;
if (set_xattr) {
if (xattr) {
err = setxattr(file, "security.evm", sig, err + 1, 0);
if (err < 0) {
log_errno("setxattr failed: %s", file);
@ -482,7 +479,7 @@ static int calc_file_hash(const char *file, uint8_t *hash)
{
EVP_MD_CTX ctx;
const EVP_MD *md;
uint8_t *data;
uint8_t *data;
int err, size, bs = DATA_SIZE;
size_t len;
unsigned int mdlen;
@ -500,8 +497,6 @@ static int calc_file_hash(const char *file, uint8_t *hash)
return -1;
}
OpenSSL_add_all_digests();
md = EVP_get_digestbyname(hash_algo);
if (!md) {
log_errno("EVP_get_digestbyname() failed");
@ -566,8 +561,6 @@ static int calc_dir_hash(const char *file, uint8_t *hash)
return -1;
}
OpenSSL_add_all_digests();
md = EVP_get_digestbyname(hash_algo);
if (!md) {
log_errno("EVP_get_digestbyname() failed");
@ -581,7 +574,7 @@ static int calc_dir_hash(const char *file, uint8_t *hash)
}
while ((de = readdir(dir))) {
//printf("entry: ino: %lu, %s\n", de->d_ino, de->d_name);
/*log_debug("entry: ino: %lu, %s\n", de->d_ino, de->d_name);*/
for (prev = NULL, pos = head; pos; prev = pos, pos = pos->next) {
if (de->d_ino < pos->de.d_ino)
break;
@ -598,7 +591,7 @@ static int calc_dir_hash(const char *file, uint8_t *hash)
for (cur = head; cur; cur = pos) {
pos = cur->next;
ino = cur->de.d_ino;
log_debug("entry: ino: %llu, %s\n", 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));
if (!err) {
log_errno("EVP_DigestUpdate() failed");
@ -625,14 +618,16 @@ 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
unsigned char hash[65] = "\x01"; /* MAX hash size + 1 */
int err;
struct stat st;
/* Need to know the file length */
err = stat(file, &st);
if (err < 0)
if (err < 0) {
log_errno("stat() failed");
return err;
}
if (S_ISDIR(st.st_mode))
err = calc_dir_hash(file, hash + 1);
@ -644,10 +639,10 @@ static int hash_ima(const char *file)
if (verbose >= LOG_INFO)
log_info("hash: ");
if (!set_xattr || verbose >= LOG_INFO)
if (!xattr || verbose >= LOG_INFO)
dump(hash, err + 1);
if (set_xattr) {
if (xattr) {
err = setxattr(file, "security.ima", hash, err + 1, 0);
if (err < 0) {
log_errno("setxattr failed: %s", file);
@ -685,7 +680,10 @@ static int sign_ima(const char *file, const char *key)
if (err < 0)
return err;
if (set_xattr) {
if (sigfile)
bin2file(file, "sig", sig, err + 1);
if (xattr) {
err = setxattr(file, "security.ima", sig, err + 1, 0);
if (err < 0) {
log_errno("setxattr failed: %s", file);
@ -789,7 +787,7 @@ static int verify_hash(const unsigned char *hash, int size, unsigned char *sig,
log_errno("Verification failed: %d", err);
return -1;
} else {
//log_info("Verification is OK\n");
/*log_info("Verification is OK\n");*/
printf("Verification is OK\n");
}
@ -802,7 +800,7 @@ static int verify_evm(const char *file, const char *key)
unsigned char sig[1024];
int err;
calc_evm_hash(file, key, hash);
calc_evm_hash(file, hash);
err = getxattr(file, "security.evm", sig, sizeof(sig));
if (err < 0) {
@ -876,11 +874,11 @@ static int cmd_import_bin(struct command *cmd)
inkey = g_argv[optind++];
if (!inkey)
inkey = "/etc/keys/pubkey_evm.bin";
else
ring = g_argv[optind++];
else
ring = g_argv[optind++];
if (!ring)
id = KEY_SPEC_USER_KEYRING;
if (!ring)
id = KEY_SPEC_USER_KEYRING;
else
id = atoi(ring);
@ -890,7 +888,7 @@ static int cmd_import_bin(struct command *cmd)
calc_keyid(keyid, name, (unsigned char *)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);
if (id < 0) {
@ -920,11 +918,11 @@ static int cmd_import(struct command *cmd)
inkey = g_argv[optind++];
if (!inkey)
inkey = "/etc/keys/pubkey_evm.pem";
else
ring = g_argv[optind++];
else
ring = g_argv[optind++];
if (!ring)
id = KEY_SPEC_USER_KEYRING;
if (!ring)
id = KEY_SPEC_USER_KEYRING;
else
id = atoi(ring);
@ -934,7 +932,7 @@ static int cmd_import(struct command *cmd)
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);
if (id < 0) {
@ -1006,7 +1004,7 @@ static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *h
log_info("no attr: %s\n", *xattrname);
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_debug_dump(xattr_value, err);
HMAC_Update(&ctx, xattr_value, err);
@ -1019,7 +1017,7 @@ 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_Update(&ctx, (const unsigned char *)&hmac_misc, sizeof(hmac_misc));
HMAC_Final(&ctx, hash, &mdlen);
HMAC_CTX_cleanup(&ctx);
@ -1041,7 +1039,7 @@ static int hmac_evm(const char *file, const char *key)
memcpy(sig + 1, hash, sizeof(hash));
err = sizeof(hash);
if (set_xattr) {
if (xattr) {
err = setxattr(file, "security.evm", sig, err + 1, 0);
if (err < 0) {
log_errno("setxattr failed: %s", file);
@ -1098,7 +1096,7 @@ static void print_full_usage(struct command *cmd)
static int print_command_usage(struct command *cmds, char *command)
{
struct command *cmd;
struct command *cmd;
for (cmd = cmds; cmd->name; cmd++) {
if (strcmp(cmd->name, command) == 0) {
@ -1107,12 +1105,12 @@ 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;
struct command *cmd;
for (cmd = cmds; cmd->name; cmd++) {
if (cmd->arg)
@ -1124,7 +1122,7 @@ static void print_all_usage(struct command *cmds)
static int call_command(struct command *cmds, char *command)
{
struct command *cmd;
struct command *cmd;
for (cmd = cmds; cmd->name; cmd++) {
if (strcasecmp(cmd->name, command) == 0)
@ -1152,23 +1150,25 @@ static void usage(void)
struct command cmds[] = {
{"help", cmd_help, 0, "<command>"},
{"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" },
{"sign", cmd_sign_evm, 0, "[--imahash | --imasig ] file [key]", "Sign file metadata.\n" },
{"verify", cmd_verify_evm, 0, "file", "Verify EVM.\n" },
{"ima_sign", cmd_sign_ima, 0, "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" },
{"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"},
{"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"},
{"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"},
{0, 0, 0, NULL}
};
static struct option opts[] = {
static struct option opts[] = {
{"help", 0, 0, 'h'},
{"inkey", 1, 0, 'k'},
{"imasig", 0, 0, 's'},
{"imahash", 0, 0, 'd'},
{"hashalgo", 1, 0, 'a'},
{"bin", 0, 0, 'b'},
{"pass", 1, 0, 'p'},
{"sigfile", 0, 0, 'f'},
{}
};
@ -1181,7 +1181,7 @@ int main(int argc, char *argv[])
g_argc = argc;
while (1) {
c = getopt_long(argc, argv, "hk:vnsda:b", opts, &lind);
c = getopt_long(argc, argv, "hk:vnsda:bp:f", opts, &lind);
if (c == -1)
break;
@ -1203,7 +1203,8 @@ int main(int argc, char *argv[])
digsig = 1;
break;
case 'n':
set_xattr = 0; // do not set Extended Attributes... just print signature
/* do not set Extended Attributes... just print signature */
xattr = 0;
break;
case 'a':
hash_algo = optarg;
@ -1211,6 +1212,12 @@ int main(int argc, char *argv[])
case 'b':
binkey = 1;
break;
case 'p':
keypass = optarg;
break;
case 'f':
sigfile = 1;
break;
case '?':
exit(1);
break;
@ -1219,10 +1226,19 @@ int main(int argc, char *argv[])
}
}
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
if (argv[optind] == NULL)
usage();
else
err = call_command(cmds, argv[optind++]);
if (err)
log_err("error: %s\n", ERR_error_string(ERR_get_error(), NULL));
ERR_free_strings();
EVP_cleanup();
return err;
}