8 Commits
v0.3 ... v0.4

Author SHA1 Message Date
5be54eaca4 Update README
README updated.
Module signing info has been removed. Module signing is done now in kernel
source tree and uses appended signatures. No need to create sig files or
set extended attributes. Information about test scripts has been removed.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-10 15:37:40 +03:00
a58cd9f4af Remove test scripts
Test scripts are not used at all.
All needed information is in README.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-10 15:17:42 +03:00
c8b4f34fd4 remove directory entry list sorting
Directory entries list sorting is not needed.
Entries are read always in the same order.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:54 +03:00
c171931236 added ima signature verification support
For debugging puporse it is usefull to have signature verification
functionality. It supports use of xattrs and .sig files.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:54 +03:00
ba07c9d4b1 do not output type prefix for sig files
sig files do not need type prefix as they are contain only signatures.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:54 +03:00
203f058903 added support for kernel module signature
Kernel module signature is appended to the kernel module.
Kernel signature also contains signature length and magic.
Added --modsig parameter to generate kernel module signature.

Signature can be added to the module like: cat module.sig >> module.ko

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:54 +03:00
72ad26c3be disable printing signature when using sigfiles
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:54 +03:00
f41d43026b Remove tag creation
Better to create tag manually when release is done.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:54 +03:00
13 changed files with 164 additions and 206 deletions

View File

@ -1,4 +1,4 @@
SUBDIRS = src tests
SUBDIRS = src
#EXTRA_DIST = LEGAL acinclude.m4 include
@ -11,7 +11,6 @@ pkgname = $(PACKAGE_NAME)-$(PACKAGE_VERSION)
tarname = $(pkgname).tar.gz
$(tarname):
git tag v$(PACKAGE_VERSION)
git archive --format=tar --prefix=$(pkgname)/ v$(PACKAGE_VERSION) $(FILES) | gzip >$@
tar: $(tarname)

89
README
View File

@ -1,52 +1,79 @@
ima-evm-utils - IMA/EVM signing utility
=========================================
1. Generate private key
Contents:
# plain key
openssl genrsa -out privkey_evm.pem 1024
1. Key generation
2. Initialization
3. Signing
# 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
Key generation
--------------
2. Generate public key
Generate private key in plain text format
openssl rsa -pubout -in privkey_evm.pem -out pubkey_evm.pem
$ openssl genrsa -out privkey_evm.pem 1024
3. Copy public (+private if to sign on device) key to the device/qemu /etc/keys
Generate encrypted private key
scp pubkey_evm.pem mad:/etc/keys
$ openssl genrsa -des3 -out privkey_evm.pem 1024
4. Load keys and enable EVM
Make encrypted private key from unencrypted
evm_enable.sh
$ openssl rsa -in /etc/keys/privkey_evm.pem -out privkey_evm_enc.pem -des3
This should be done at early phase, before mounting root filesystem.
Get public key
5. Sign EVM and use hash value for IMA - common case
$ openssl rsa -pubout -in privkey_evm.pem -out pubkey_evm.pem
evmctl sign --imahash test.txt
Copy keys to /etc/keys
6. Sign IMA and EVM - for immutable files and modules
$ cp pubkey_evm.pem /etc/keys
$ scp pubkey_evm.pem target:/etc/keys
evmctl sign --imasig test.txt
7. Sign whole filesystem
Initialization
--------------
evm_sign_all.sh
or
find / \( -fstype rootfs -o -fstype ext3 -o -fstype ext4 \) ! -path "/lib/modules/*" -type f -uid 0 -exec evmctl sign --imahash '{}' \;
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 '{}' \;
IMA/EVM initialization should be normally done from initial RAM file system
before mounting root filesystem.
# generate signatures in .sig files
find /lib/modules -name "*.ko" -type f -uid 0 -exec evmctl -n --sigfile ima_sign '{}' \;
Here is an example script /etc/initramfs-tools/scripts/local-top/ima.sh
8. Label filesystem in fix mode...
# import EVM HMAC key
keyctl clear @u
keyctl add user kmk "testing123" @u
keyctl add encrypted evm-key "load `cat /etc/keys/evm-key`" @u
ima_fix_dir.sh <dir>
# import IMA public key
ima_id=`keyctl newring _ima @u`
evmctl import /etc/keys/pubkey_evm.pem $ima_id
# import EVM public key
evm_id=`keyctl newring _evm @u`
evmctl import /etc/keys/pubkey_evm.pem $evm_id
# enable EVM
echo "1" > /sys/kernel/security/evm
Signing
-------
Sign file with EVM signature and use hash value for IMA - common case
$ evmctl sign --imahash test.txt
Sign file with both IMA and EVM signatures - for immutable files
$ evmctl sign --imasig test.txt
Label whole filesystem with EVM signatures
$ find / \( -fstype rootfs -o -fstype ext4 \) -exec evmctl sign --imahash '{}' \;
Label filesystem in fix mode - kernel sets correct values to IMA and EVM xattrs
$ find / \( -fstype rootfs -o -fstype ext4 \) -exec sh -c "< '{}'" \;

View File

@ -46,7 +46,6 @@ fi
AC_CONFIG_FILES([Makefile
src/Makefile
tests/Makefile
ima-evm-utils.spec
])
AC_OUTPUT

View File

@ -144,12 +144,14 @@ static int verbose = LOG_INFO - 1;
static int g_argc;
static char **g_argv;
static int xattr = 1;
static int sigdump;
static int digest;
static int digsig;
static char *hash_algo = "sha1";
static int binkey;
static char *keypass;
static int sigfile;
static int modsig;
struct command cmds[];
static void print_usage(struct command *cmd);
@ -208,16 +210,24 @@ static int bin2file(const char *file, const char *ext, const unsigned char *data
return err;
}
static unsigned char *file2bin(const char *file, int *size)
static unsigned char *file2bin(const char *file, const char *ext, int *size)
{
FILE *fp;
int len;
unsigned char *data;
char name[strlen(file) + (ext ? strlen(ext) : 0) + 2];
len = get_filesize(file);
fp = fopen(file, "r");
if (ext)
sprintf(name, "%s.%s", file, ext);
else
sprintf(name, "%s", file);
log_info("Reading to %s\n", name);
len = get_filesize(name);
fp = fopen(name, "r");
if (!fp) {
log_err("Unable to open %s\n", file);
log_err("Unable to open %s\n", name);
return NULL;
}
data = malloc(len);
@ -366,7 +376,7 @@ 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 (!xattr || verbose >= LOG_INFO)
if (sigdump || verbose >= LOG_INFO)
dump(sig, len);
return len;
@ -536,18 +546,13 @@ static int add_file_hash(const char *file, EVP_MD_CTX *ctx)
return 0;
}
struct dirent_list {
struct dirent_list *next;
struct dirent de;
};
static int add_dir_hash(const char *file, EVP_MD_CTX *ctx)
{
int err;
struct dirent *de;
DIR *dir;
struct dirent_list *head = NULL, *pos, *prev, *cur;
uint64_t ino;
unsigned long long ino, off;
unsigned int type;
dir = opendir(file);
if (!dir) {
@ -556,40 +561,19 @@ static int add_dir_hash(const char *file, EVP_MD_CTX *ctx)
}
while ((de = readdir(dir))) {
/*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;
}
cur = malloc(sizeof(*cur));
cur->de = *de;
cur->next = pos;
if (!head || !prev)
head = cur;
else
prev->next = cur;
}
for (cur = head; cur; cur = pos) {
pos = cur->next;
ino = cur->de.d_ino;
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));
ino = de->d_ino;
off = de->d_off;
type = de->d_type;
log_debug("entry: %s, ino: %llu, type: %u, off: %llu, reclen: %hu\n",
de->d_name, ino, type, off, de->d_reclen);
err = EVP_DigestUpdate(ctx, de->d_name, strlen(de->d_name));
/*err |= EVP_DigestUpdate(ctx, &off, sizeof(off));*/
err |= EVP_DigestUpdate(ctx, &ino, sizeof(ino));
err |= EVP_DigestUpdate(ctx, &type, sizeof(type));
if (!err) {
log_err("EVP_DigestUpdate() failed\n");
return 1;
}
err = EVP_DigestUpdate(ctx, &ino, sizeof(ino));
if (!err) {
log_err("EVP_DigestUpdate() failed\n");
return 1;
}
err = EVP_DigestUpdate(ctx, &cur->de.d_type, sizeof(cur->de.d_type));
if (!err) {
log_err("EVP_DigestUpdate() failed\n");
return 1;
}
free(cur);
}
closedir(dir);
@ -689,7 +673,7 @@ static int hash_ima(const char *file)
if (verbose >= LOG_INFO)
log_info("hash: ");
if (!xattr || verbose >= LOG_INFO)
if (sigdump || verbose >= LOG_INFO)
dump(hash, len + 1);
if (xattr) {
@ -720,6 +704,7 @@ static int sign_ima(const char *file, const char *key)
{
unsigned char hash[64];
unsigned char sig[1024] = "\x03";
char magic[] = "This Is A Crypto Signed Module";
int len, err;
len = calc_hash(file, hash);
@ -730,11 +715,24 @@ static int sign_ima(const char *file, const char *key)
if (len <= 1)
return len;
/* add header */
len++;
if (modsig) {
/* add signature length */
*(uint16_t *)(sig + len) = __cpu_to_be16(len - 1);
len += sizeof(uint16_t);
memcpy(sig + len, magic, sizeof(magic) - 1);
len += sizeof(magic) - 1;
bin2file(file, "sig", sig + 1, len - 1);
return 0;
}
if (sigfile)
bin2file(file, "sig", sig, len + 1);
bin2file(file, "sig", sig + 1, len - 1);
if (xattr) {
err = setxattr(file, "security.ima", sig, len + 1, 0);
err = setxattr(file, "security.ima", sig, len, 0);
if (err < 0) {
log_err("setxattr failed: %s\n", file);
return err;
@ -891,6 +889,56 @@ static int cmd_verify_evm(struct command *cmd)
return verify_evm(file, key);
}
static int verify_ima(const char *file, const char *key)
{
unsigned char hash[20];
unsigned char sig[1024];
int len;
len = calc_hash(file, hash);
if (len <= 1)
return len;
if (xattr) {
len = getxattr(file, "security.ima", sig, sizeof(sig));
if (len < 0) {
log_err("getxattr failed\n");
return len;
}
}
if (sigfile) {
void *tmp;
tmp = file2bin(file, "sig", &len);
memcpy(sig, tmp, len);
free(tmp);
}
if (sig[0] != 0x03) {
log_err("security.ima has no signature\n");
return -1;
}
return verify_hash(hash, sizeof(hash), sig + 1, len - 1, key);
}
static int cmd_verify_ima(struct command *cmd)
{
char *key, *file = g_argv[optind++];
if (!file) {
log_err("Parameters missing\n");
print_usage(cmd);
return -1;
}
key = g_argv[optind++];
if (!key)
key = "/etc/keys/pubkey_evm.pem";
return verify_ima(file, key);
}
static int cmd_convert(struct command *cmd)
{
char *inkey, *outkey = NULL;
@ -944,7 +992,7 @@ static int cmd_import(struct command *cmd)
id = atoi(ring);
if (binkey) {
key = file2bin(inkey, &len);
key = file2bin(inkey, NULL, &len);
if (!key)
return -1;
} else {
@ -989,7 +1037,7 @@ static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *h
char list[1024];
ssize_t list_size;
key = file2bin(keyfile, &keylen);
key = file2bin(keyfile, NULL, &keylen);
if (!key) {
log_err("Unable to read a key: %s\n\n", keyfile);
return -1;
@ -1215,6 +1263,7 @@ static void usage(void)
" -s, --imasig also make IMA signature\n"
" -d, --imahash also make IMA hash\n"
" -f, --sigfile store IMA signature in .sig file instead of xattr\n"
" -m, --modsig store module signature in .sig file instead of xattr\n"
" -b, --bin signing key is in binary format\n"
" -p, --pass password for encrypted signing key\n"
" -n print result to stdout instead of setting xattr\n"
@ -1229,7 +1278,8 @@ struct command cmds[] = {
{"convert", cmd_convert, 0, "inkey outkey", "Convert PEM public key into IMA/EVM kernel friendly format.\n"},
{"sign", cmd_sign_evm, 0, "[--imahash | --imasig ] [--pass password] 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] [--pass password] file [key]", "Make file content signature.\n"},
{"ima_sign", cmd_sign_ima, 0, "[--sigfile | --modsig] [--pass password] file [key]", "Make file content signature.\n"},
{"ima_verify", cmd_verify_ima, 0, "file [key]", "Verify IMA signature (for debugging).\n"},
{"ima_hash", cmd_hash_ima, 0, "file", "Make file content hash.\n"},
#ifdef DEBUG
{"hmac", cmd_hmac_evm, 0, "[--imahash | --imasig ] file [key]", "Sign file metadata with HMAC using symmetric key (for testing purpose).\n"},
@ -1245,6 +1295,7 @@ static struct option opts[] = {
{"bin", 0, 0, 'b'},
{"pass", 1, 0, 'p'},
{"sigfile", 0, 0, 'f'},
{"modsig", 0, 0, 'm'},
{}
};
@ -1278,6 +1329,7 @@ int main(int argc, char *argv[])
case 'n':
/* do not set Extended Attributes... just print signature */
xattr = 0;
sigdump = 1;
break;
case 'a':
hash_algo = optarg;
@ -1290,6 +1342,11 @@ int main(int argc, char *argv[])
break;
case 'f':
sigfile = 1;
xattr = 0;
break;
case 'm':
modsig = 1;
xattr = 0;
break;
case '?':
exit(1);

View File

@ -1,7 +0,0 @@
pkglibexec_PROGRAMS = openclose
openclose_SOURCES = openclose.c
dist_pkglibexec_SCRIPTS = evm_enable.sh evm_genkey.sh evm_sign_all.sh evm_sign_modules.sh \
ima_fix_dir.sh evm_hmac_all.sh evm_hmac_modules.sh

View File

@ -1,25 +0,0 @@
#!/bin/sh
# import EVM HMAC key
keyctl clear @u
keyctl add user kmk "testing123" @u
keyctl add encrypted evm-key "load `cat /etc/keys/evm-key`" @u
# import Moule public key
mod_id=`keyctl newring _module @u`
evmctl import /etc/keys/pubkey_evm.pem $mod_id
# import IMA public key
ima_id=`keyctl newring _ima @u`
evmctl import /etc/keys/pubkey_evm.pem $ima_id
# import EVM public key
evm_id=`keyctl newring _evm @u`
evmctl import /etc/keys/pubkey_evm.pem $evm_id
# enable EVM
echo "1" > /sys/kernel/security/evm
# enable module checking
echo "1" > /sys/kernel/security/ima/module_check

View File

@ -1,8 +0,0 @@
#!/bin/sh
keyctl add user kmk "testing123" @u
key=`keyctl add encrypted evm-key "new user:kmk 32" @u`
keyctl print $key >/etc/keys/evm-key
keyctl list @u

View File

@ -1,14 +0,0 @@
#!/bin/sh
verbose=""
if [ "$1" = "-v" ] ; then
verbose="-v"
shift 1
fi
dir=${1:-/}
echo "Label: $dir"
find $dir \( -fstype rootfs -o -fstype ext3 -o -fstype ext4 \) \( -type f -o -type d \) -exec evmctl hmac --imahash $verbose '{}' \;

View File

@ -1,14 +0,0 @@
#!/bin/sh
verbose=""
if [ "$1" = "-v" ] ; then
verbose="-v"
shift 1
fi
dir=${1:-/lib/modules}
echo "HMAC modules: $dir"
find $dir -name "*.ko" -type f -exec evmctl hmac --imasig $verbose '{}' \;

View File

@ -1,14 +0,0 @@
#!/bin/sh
verbose=""
if [ "$1" = "-v" ] ; then
verbose="-v"
shift 1
fi
dir=${1:-/}
echo "Label: $dir"
find $dir \( -fstype rootfs -o -fstype ext3 -o -fstype ext4 \) -type f -exec evmctl sign --imahash $verbose '{}' \;

View File

@ -1,14 +0,0 @@
#!/bin/sh
verbose=""
if [ "$1" = "-v" ] ; then
verbose="-v"
shift 1
fi
dir=${1:-/lib/modules}
echo "Signing modules: $dir"
find $dir -name "*.ko" -type f -exec evmctl sign --imasig $verbose '{}' \;

View File

@ -1,8 +0,0 @@
#!/bin/sh
dir=${1:-/}
echo "Fixing dir: $dir"
find $dir \( -fstype rootfs -o -fstype ext3 -o -fstype ext4 \) -type f -exec openclose '{}' \;

View File

@ -1,20 +0,0 @@
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int fd;
fd = open(argv[1], O_RDONLY);
if (fd < 0) {
perror("open()");
exit(1);
}
close(fd);
return 0;
}