1
0
mirror of https://git.code.sf.net/p/linux-ima/ima-evm-utils synced 2025-07-04 06:25:15 +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> 2011-08-24 Dmitry Kasatkin <dmitry.kasatkin@intel.com>
version 0.1 version 0.1

12
README
View File

@ -1,8 +1,17 @@
1. Generate private key 1. Generate private key
# plain key
openssl genrsa -out privkey_evm.pem 1024 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 2. Generate public key
openssl rsa -pubout -in privkey_evm.pem -out pubkey_evm.pem 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 # security.ima needs to have signature for modules
find /lib/modules -name "*.ko" -type f -uid 0 -exec evmctl sign --imasig '{}' \; 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... 8. Label filesystem in fix mode...
ima_fix_dir.sh <dir> ima_fix_dir.sh <dir>

View File

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

View File

@ -45,17 +45,19 @@
#include <attr/xattr.h> #include <attr/xattr.h>
#include <dirent.h> #include <dirent.h>
#include <openssl/sha.h>
#include <openssl/sha.h> #include <openssl/sha.h>
#include <openssl/rsa.h> #include <openssl/rsa.h>
#include <openssl/pem.h> #include <openssl/pem.h>
#include <openssl/hmac.h> #include <openssl/hmac.h>
#include <openssl/engine.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#define USE_FPRINTF #define USE_FPRINTF
#ifdef USE_FPRINTF #ifdef USE_FPRINTF
#define do_log(level, fmt, args...) if (level <= verbose) fprintf(stderr, fmt, ##args) #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_dump(level, p, len) ({ if (level <= verbose) do_dump(stderr, p, len); })
#else #else
#define do_log(level, fmt, args...) syslog(level, fmt, ##args) #define do_log(level, fmt, args...) syslog(level, fmt, ##args)
#define do_log_dump(p, len) #define do_log_dump(p, len)
@ -106,16 +108,15 @@ enum digest_algo {
struct pubkey_hdr { struct pubkey_hdr {
uint8_t version; /* key format version */ 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 algo;
uint8_t nmpi; uint8_t nmpi;
char mpi[0]; char mpi[0];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct signature_hdr { struct signature_hdr {
uint8_t version; /* signature format version */ uint8_t version; /* signature format version */
time_t timestamp; /* signature made */ uint32_t timestamp; /* signature made */
uint8_t algo; uint8_t algo;
uint8_t hash; uint8_t hash;
uint8_t keyid[8]; uint8_t keyid[8];
@ -123,7 +124,6 @@ struct signature_hdr {
char mpi[0]; char mpi[0];
} __attribute__ ((packed)); } __attribute__ ((packed));
static char *evm_config_xattrnames[] = { static char *evm_config_xattrnames[] = {
"security.selinux", "security.selinux",
"security.SMACK64", "security.SMACK64",
@ -143,13 +143,15 @@ struct command {
static int verbose = LOG_INFO - 1; static int verbose = LOG_INFO - 1;
static int g_argc; static int g_argc;
static char **g_argv; static char **g_argv;
static int set_xattr = 1; static int xattr = 1;
static int digest = 0; static int digest;
static int digsig = 0; static int digsig;
static char *hash_algo = "sha1"; 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 print_usage(struct command *cmd);
static void do_dump(FILE *fp, const void *ptr, int len) 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; int i;
uint8_t *data = (uint8_t *) ptr; 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, "%02x", data[i]);
}
fprintf(fp, "\n"); fprintf(fp, "\n");
} }
@ -244,7 +245,6 @@ static int key2bin(RSA *key, unsigned char *pub)
offset += sizeof(*pkh); offset += sizeof(*pkh);
// MPIs
len = BN_num_bytes(key->n); len = BN_num_bytes(key->n);
b = BN_num_bits(key->n); b = BN_num_bits(key->n);
pub[offset++] = b >> 8; pub[offset++] = b >> 8;
@ -288,7 +288,6 @@ static int read_key(const char *inkey, unsigned char *pub)
return len; return len;
} }
static void calc_keyid(uint8_t *keyid, char *str, const unsigned char *pkey, int len) static void calc_keyid(uint8_t *keyid, char *str, const unsigned char *pkey, int len)
{ {
uint8_t sha1[SHA_DIGEST_LENGTH]; 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); log_debug_dump(pkey, len);
SHA1(pkey, len, sha1); 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); memcpy(keyid, sha1 + 12, 8);
log_debug("keyid:\n"); log_debug("keyid:\n");
log_debug_dump(keyid, 8); 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); log_errno("Unable to open keyfile %s", keyfile);
return -1; return -1;
} }
key1 = PEM_read_RSAPrivateKey(fp, &key, NULL, NULL); key1 = PEM_read_RSAPrivateKey(fp, &key, NULL, keypass);
fclose(fp); fclose(fp);
if (!key1) { if (!key1) {
log_errno("RSAPrivateKey() failed"); 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 */ /* now create a new hash */
hdr->version = 1; hdr->version = 1;
time(&hdr->timestamp); hdr->timestamp = time(NULL);
hdr->algo = PUBKEY_ALGO_RSA; hdr->algo = PUBKEY_ALGO_RSA;
hdr->hash = DIGEST_ALGO_SHA1; 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); *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: %d bytes\n", len);
if (!set_xattr || verbose >= LOG_INFO) if (!xattr || verbose >= LOG_INFO)
dump(sig, len); dump(sig, len);
return 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; struct stat st;
int fd, err; 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); log_info("generation: %u\n", generation);
OpenSSL_add_all_digests();
md = EVP_get_digestbyname("sha1"); md = EVP_get_digestbyname("sha1");
if (!md) { if (!md) {
log_errno("EVP_get_digestbyname() failed"); 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); log_info("no attr: %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 = EVP_DigestUpdate(&ctx, 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"; unsigned char sig[1024] = "\x03";
int err; int err;
calc_evm_hash(file, key, hash); calc_evm_hash(file, hash);
err = sign_hash(hash, sizeof(hash), key, sig + 1); err = sign_hash(hash, sizeof(hash), key, sig + 1);
if (err < 0) if (err < 0)
return err; return err;
if (set_xattr) { if (xattr) {
err = setxattr(file, "security.evm", sig, err + 1, 0); err = setxattr(file, "security.evm", sig, err + 1, 0);
if (err < 0) { if (err < 0) {
log_errno("setxattr failed: %s", file); log_errno("setxattr failed: %s", file);
@ -500,8 +497,6 @@ static int calc_file_hash(const char *file, uint8_t *hash)
return -1; return -1;
} }
OpenSSL_add_all_digests();
md = EVP_get_digestbyname(hash_algo); md = EVP_get_digestbyname(hash_algo);
if (!md) { if (!md) {
log_errno("EVP_get_digestbyname() failed"); log_errno("EVP_get_digestbyname() failed");
@ -566,8 +561,6 @@ static int calc_dir_hash(const char *file, uint8_t *hash)
return -1; return -1;
} }
OpenSSL_add_all_digests();
md = EVP_get_digestbyname(hash_algo); md = EVP_get_digestbyname(hash_algo);
if (!md) { if (!md) {
log_errno("EVP_get_digestbyname() failed"); 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))) { 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) { for (prev = NULL, pos = head; pos; prev = pos, pos = pos->next) {
if (de->d_ino < pos->de.d_ino) if (de->d_ino < pos->de.d_ino)
break; break;
@ -598,7 +591,7 @@ static int calc_dir_hash(const char *file, uint8_t *hash)
for (cur = head; cur; cur = pos) { for (cur = head; cur; cur = pos) {
pos = cur->next; pos = cur->next;
ino = cur->de.d_ino; 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)); err = EVP_DigestUpdate(&ctx, cur->de.d_name, strlen(cur->de.d_name));
if (!err) { if (!err) {
log_errno("EVP_DigestUpdate() failed"); 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) 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; 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_errno("stat() failed");
return err; return err;
}
if (S_ISDIR(st.st_mode)) if (S_ISDIR(st.st_mode))
err = calc_dir_hash(file, hash + 1); err = calc_dir_hash(file, hash + 1);
@ -644,10 +639,10 @@ static int hash_ima(const char *file)
if (verbose >= LOG_INFO) if (verbose >= LOG_INFO)
log_info("hash: "); log_info("hash: ");
if (!set_xattr || verbose >= LOG_INFO) if (!xattr || verbose >= LOG_INFO)
dump(hash, err + 1); dump(hash, err + 1);
if (set_xattr) { if (xattr) {
err = setxattr(file, "security.ima", hash, err + 1, 0); err = setxattr(file, "security.ima", hash, err + 1, 0);
if (err < 0) { if (err < 0) {
log_errno("setxattr failed: %s", file); log_errno("setxattr failed: %s", file);
@ -685,7 +680,10 @@ static int sign_ima(const char *file, const char *key)
if (err < 0) if (err < 0)
return err; return err;
if (set_xattr) { if (sigfile)
bin2file(file, "sig", sig, err + 1);
if (xattr) {
err = setxattr(file, "security.ima", sig, err + 1, 0); err = setxattr(file, "security.ima", sig, err + 1, 0);
if (err < 0) { if (err < 0) {
log_errno("setxattr failed: %s", file); 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); log_errno("Verification failed: %d", err);
return -1; return -1;
} else { } else {
//log_info("Verification is OK\n"); /*log_info("Verification is OK\n");*/
printf("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]; unsigned char sig[1024];
int err; int err;
calc_evm_hash(file, key, hash); calc_evm_hash(file, hash);
err = getxattr(file, "security.evm", sig, sizeof(sig)); err = getxattr(file, "security.evm", sig, sizeof(sig));
if (err < 0) { 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); log_info("no attr: %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);
HMAC_Update(&ctx, 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)); memcpy(sig + 1, hash, sizeof(hash));
err = sizeof(hash); err = sizeof(hash);
if (set_xattr) { if (xattr) {
err = setxattr(file, "security.evm", sig, err + 1, 0); err = setxattr(file, "security.evm", sig, err + 1, 0);
if (err < 0) { if (err < 0) {
log_errno("setxattr failed: %s", file); 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"}, {"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 ] 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.\n" }, {"verify", cmd_verify_evm, 0, "file", "Verify EVM signature (for debugging).\n"},
{"ima_sign", cmd_sign_ima, 0, "file [key]", "Sign file content.\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"}, {"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"}, {"hmac", cmd_hmac_evm, 0, "[--imahash | --imasig ] file [key]", "Sign file metadata with HMAC (for debugging).\n"},
{0, 0, 0, NULL} {0, 0, 0, NULL}
@ -1169,6 +1167,8 @@ static struct option opts[] = {
{"imahash", 0, 0, 'd'}, {"imahash", 0, 0, 'd'},
{"hashalgo", 1, 0, 'a'}, {"hashalgo", 1, 0, 'a'},
{"bin", 0, 0, 'b'}, {"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; g_argc = argc;
while (1) { 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) if (c == -1)
break; break;
@ -1203,7 +1203,8 @@ int main(int argc, char *argv[])
digsig = 1; digsig = 1;
break; break;
case 'n': case 'n':
set_xattr = 0; // do not set Extended Attributes... just print signature /* do not set Extended Attributes... just print signature */
xattr = 0;
break; break;
case 'a': case 'a':
hash_algo = optarg; hash_algo = optarg;
@ -1211,6 +1212,12 @@ int main(int argc, char *argv[])
case 'b': case 'b':
binkey = 1; binkey = 1;
break; break;
case 'p':
keypass = optarg;
break;
case 'f':
sigfile = 1;
break;
case '?': case '?':
exit(1); exit(1);
break; break;
@ -1219,10 +1226,19 @@ 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
err = call_command(cmds, argv[optind++]); 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; return err;
} }