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)
@ -106,16 +108,15 @@ enum digest_algo {
struct pubkey_hdr {
uint8_t version; /* key format version */
time_t timestamp; /* key made, always 0 for now */
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 */
uint32_t timestamp; /* signature made */
uint8_t algo;
uint8_t hash;
uint8_t keyid[8];
@ -123,7 +124,6 @@ struct signature_hdr {
char mpi[0];
} __attribute__ ((packed));
static char *evm_config_xattrnames[] = {
"security.selinux",
"security.SMACK64",
@ -143,13 +143,15 @@ struct command {
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 int xattr = 1;
static int digest;
static int digsig;
static char *hash_algo = "sha1";
static int binkey = 0;
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)
@ -157,9 +159,8 @@ static void do_dump(FILE *fp, const void *ptr, int len)
int i;
uint8_t *data = (uint8_t *) ptr;
for (i = 0; i < len; i++) {
for (i = 0; i < len; i++)
fprintf(fp, "%02x", data[i]);
}
fprintf(fp, "\n");
}
@ -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,7 +297,7 @@ 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);
@ -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;
@ -367,13 +366,13 @@ static int sign_hash(const unsigned char *hash, int size, const char *keyfile, u
*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);
@ -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);
@ -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) {
@ -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);
@ -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);
@ -1155,8 +1153,8 @@ struct command cmds[] = {
{"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" },
{"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}
@ -1169,6 +1167,8 @@ static struct option opts[] = {
{"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;
}