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

30 Commits
v0.9 ... v1.1

Author SHA1 Message Date
c860e0d9bb ima-evm-utils: Release version 1.1
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
2018-02-15 08:02:19 -05:00
360655f059 Support different levels of output for "ima_measurement"
Instead of always displaying the entire measurement list, the default
behavior is just to return an error.  Verbose (-v) displays the key ids
used in validating the measurement list, the PCR aggregate and TPM PCR
values.  Verbose+ (-v -v) also displays the measurement list.

Signed-of-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
2018-02-06 07:50:31 -05:00
057efc397d Include the file name in "ima_measurement" verification result
When displaying the measurement list, include the filename in the result.

Signed-of-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
2018-02-06 07:50:01 -05:00
c2ef2aabe2 ima-evm-utils: sysfs pathname change
Commit 313d21e "tpm: device class for tpm" moved the TPM sysfs location
from /sys/class/misc/tpmX/device/ to /sys/class/tpm/tpmX/device/.

Mimi Zohar <zohar@linux.vnet.ibm.com>
2018-01-29 14:24:03 -05:00
81010f0d87 ima-evm-utils: Add backward compatible support for openssl 1.1
Openssl 1.1 is really annoying in that it made certain objects opaque
and added accessors for the necessary componenets, but these accessors
often don't exist in 1.0 and before, so there's no way to create clean
code that will compile with both 1.0 and 1.1; instead you have to
compiled with both code bases to make sure everything is working).

The other problem is that since the structures are opaque, their size
isn't known, so having a structure declared as a variable is no longer
possible.

This change switches all uses of EVP_MD_CTX to be pointers initialised
with the correct EVP_MD_CTX_new() (not available in 1.0), does the
same for HMAC_CTX, and uses the 1.1 only primitve RSA_get0_key() to
extract the public modulus and exponent from an RSA key.

Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Tested-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
2018-01-28 13:47:54 -05:00
6921833477 ima-evm-utils: add support for validating multiple pcrs
The IMA measurement list may contain records for different PCRs.  This
patch walks the measurement list, calculating a PCR aggregate value for
each PCR.

Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
2018-01-28 10:02:18 -05:00
1a69e42ac1 ima-evm-utils: verify the measurement list signature based on the list digest
Instead of verifying file signatures included in the measurement list,
by calculating the local file hash, verify the file signature based on the
digest contained in the measurement list.

This patch defines a new option named "--list".

Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
2018-01-28 09:57:34 -05:00
9c79b7de72 ima-evm-utils: support verifying the measurement list using multiple keys
On a running system, different software packages might be signed by
different parties.  Support verifying signatures in the measurement
list using multiple public keys(eg.  -k "key1, key2, ...").

Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
2018-01-28 09:57:34 -05:00
838b08b449 ima-evm-utils: fix spelling error
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
2018-01-28 09:57:34 -05:00
ba92e44719 ima-evm-utils: fix "ima_measurement" template fields length
The template data field length is uint32_t, not uint8_t.

Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
2018-01-28 08:37:08 -05:00
4928548d9d Add support for portable EVM format
Add a --portable argument that generates EVM signatures without using
the inode number and generation or fs UUID.

Signed-off-by: Matthew Garrett <mjg59@google.com>
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>

Changelog:
- immutable and portable flags are exclusive, prevent enabling both.
2017-11-16 15:02:40 -05:00
233dedffe9 Write out .sig file as security.ima xattr
To write the .sig file as security.ima xattr using setfattr first
requires converting the .sig file from binary to ascii-hex.  Although
this conversion can be done using hexdump, it is unnecessary when
calling setxattr.  This patch defines a new command called
"ima_setxattr", which calls lsetxattr() to write the .sig file as
the security.ima xattr.

Changelog:
- remove unnecessary copy
- fixed --sigfile option

Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
2016-03-06 07:55:04 -05:00
3e2a67bdb0 script to build static evmctl version
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@huawei.com>
2015-10-01 22:42:45 +03:00
839a674580 Supply file attributes values on command line
Can be used by Android filesystem image creation tool.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@huawei.com>
2015-09-20 23:28:20 +03:00
e55d286ad6 Use single flag to indicate 'no'flag
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@huawei.com>
2015-09-20 23:15:32 +03:00
28d99354de Use byte range values
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@huawei.com>
2015-09-20 22:22:06 +03:00
ea5ccdf38f Newer kernels requires at least 64 byte keys
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@huawei.com>
2015-09-20 22:22:00 +03:00
b0d13ba557 calc_evm_hmac/hash: avoid fd leak when ioctl fails
When opening the file succeeds but ioctl() then fails, the file must
be closed before returning.

Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
2015-09-09 23:02:01 +03:00
199311e6a5 ima_verify: ignore -n flag
"evmutil ima_verify -n <some file>" disabled using xattrs without enabling
using a signature file, resulting in the use of uninitialized memory in
ima_verify_signature() and thus unpredictable results.

Such a mode of operation makes no sense, so interpret -n as
documented ("print result to stdout instead of setting xattr") and ignore it
during ima_verify. Instead, switch between the two verification modes only
via the global sigfile variable.

Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
2015-09-09 22:50:45 +03:00
453d3db8a5 tpm_pcr_read: close file when returning early
When return from inside the for() loop, the open file was not
closed.

Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
2015-09-09 22:50:35 +03:00
fa0b30b15e add_dir_hash: fix DIR leak in case of failure
When bailing out of the function due to EVP_DigestUpdate()
failing, the DIR resources allocated with opendir() were
not freed.

Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
2015-09-09 22:50:18 +03:00
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
8 changed files with 658 additions and 260 deletions

View File

@ -1,3 +1,25 @@
2018-01-28 Mimi Zohar <zohar@us.ibm.com>
version 1.1
* Support the new openssl 1.1 api
* Support for validating multiple pcrs
* Verify the measurement list signature based on the list digest
* Verify the "ima-sig" measurement list using multiple keys
* Fixed parsing the measurement template data field length
* Portable & immutable EVM signatures (new format)
* Multiple fixes that have been lingering in the next branch. Some
are for experimental features that are not yet supported in the
kernel.
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

12
README
View File

@ -26,12 +26,12 @@ COMMANDS
--version --version
help <command> help <command>
import [--rsa] pubkey keyring import [--rsa] pubkey keyring
sign [-r] [--imahash | --imasig ] [--key key] [--pass password] file sign [-r] [--imahash | --imasig ] [--portable] [--key key] [--pass password] file
verify file verify file
ima_sign [--sigfile] [--key key] [--pass password] file ima_sign [--sigfile] [--key key] [--pass password] file
ima_verify file ima_verify file
ima_hash file ima_hash file
ima_measurement file ima_measurement [--key "key1, key2, ..."] [--list] file
ima_fix [-t fdsxm] path ima_fix [-t fdsxm] path
sign_hash [--key key] [--pass password] sign_hash [--key key] [--pass password]
hmac [--imahash | --imasig ] file hmac [--imahash | --imasig ] file
@ -46,6 +46,7 @@ OPTIONS
-f, --sigfile store IMA signature in .sig file instead of xattr -f, --sigfile store IMA signature in .sig file instead of xattr
--rsa use RSA key type and signing scheme v1 --rsa use RSA key type and signing scheme v1
-k, --key path to signing key (default: /etc/keys/{privkey,pubkey}_evm.pem) -k, --key path to signing key (default: /etc/keys/{privkey,pubkey}_evm.pem)
-o, --portable generate portable EVM signatures
-p, --pass password for encrypted signing key -p, --pass password for encrypted signing key
-r, --recursive recurse into directories (sign) -r, --recursive recurse into directories (sign)
-t, --type file types to fix 'fdsxm' (f: file, d: directory, s: block/char/symlink) -t, --type file types to fix 'fdsxm' (f: file, d: directory, s: block/char/symlink)
@ -95,7 +96,8 @@ Kernel configuration option CONFIG_EVM_ATTR_FSUUID controls whether to include
filesystem UUID into HMAC and enabled by default. Therefore evmctl also includes filesystem UUID into HMAC and enabled by default. Therefore evmctl also includes
fsuuid by default. Providing '--uuid' option without parameter allows to disable fsuuid by default. Providing '--uuid' option without parameter allows to disable
usage of fs uuid. Providing '--uuid=UUID' option with parameter allows to use usage of fs uuid. Providing '--uuid=UUID' option with parameter allows to use
custom UUID. custom UUID. Providing the '--portable' option will disable usage of the fs uuid
and also the inode number and generation.
Kernel configuration option CONFIG_EVM_EXTRA_SMACK_XATTRS controls whether to Kernel configuration option CONFIG_EVM_EXTRA_SMACK_XATTRS controls whether to
include additional SMACK extended attributes into HMAC. They are following: include additional SMACK extended attributes into HMAC. They are following:
@ -142,7 +144,7 @@ EVM encrypted key is used for EVM HMAC calculation:
keyctl pipe `keyctl search @u user kmk` > /etc/keys/kmk keyctl pipe `keyctl search @u user kmk` > /etc/keys/kmk
# create the EVM encrypted key # create the EVM encrypted key
keyctl add encrypted evm-key "new user:kmk 32" @u keyctl add encrypted evm-key "new user:kmk 64" @u
keyctl pipe `keyctl search @u encrypted evm-key` >/etc/keys/evm-key keyctl pipe `keyctl search @u encrypted evm-key` >/etc/keys/evm-key
@ -403,7 +405,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

4
build-static.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/sh
gcc -static -o evmctl.static -include config.h src/evmctl.c src/libimaevm.c -lcrypto -lkeyutils -ldl

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.1, zohar@linux.vnet.ibm.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.1
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

File diff suppressed because it is too large Load Diff

View File

@ -82,6 +82,7 @@ enum evm_ima_xattr_type {
EVM_XATTR_HMAC, EVM_XATTR_HMAC,
EVM_IMA_XATTR_DIGSIG, EVM_IMA_XATTR_DIGSIG,
IMA_XATTR_DIGEST_NG, IMA_XATTR_DIGEST_NG,
EVM_XATTR_PORTABLE_DIGSIG,
}; };
struct h_misc { struct h_misc {
@ -108,6 +109,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,
@ -166,14 +173,14 @@ struct signature_v2_hdr {
} __packed; } __packed;
typedef int (*verify_hash_fn_t)(const unsigned char *hash, int size, unsigned char *sig, int siglen, const char *keyfile); typedef int (*verify_hash_fn_t)(const char *file, const unsigned char *hash, int size, unsigned char *sig, int siglen, const char *keyfile);
struct libevm_params { 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 {
@ -181,6 +188,9 @@ struct RSA_ASN1_template {
size_t size; size_t size;
}; };
#define NUM_PCRS 20
#define DEFAULT_PCR 10
extern const struct RSA_ASN1_template RSA_ASN1_templates[PKEY_HASH__LAST]; extern const struct RSA_ASN1_template RSA_ASN1_templates[PKEY_HASH__LAST];
extern struct libevm_params params; extern struct libevm_params params;
@ -195,8 +205,9 @@ 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 char *file, 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, unsigned char *digest, int digestlen);
void init_public_keys(const char *keyfiles);
#endif #endif

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;
@ -211,6 +214,7 @@ static int add_dir_hash(const char *file, EVP_MD_CTX *ctx)
DIR *dir; DIR *dir;
unsigned long long ino, off; unsigned long long ino, off;
unsigned int type; unsigned int type;
int result = 0;
dir = opendir(file); dir = opendir(file);
if (!dir) { if (!dir) {
@ -230,13 +234,14 @@ static int add_dir_hash(const char *file, EVP_MD_CTX *ctx)
err |= EVP_DigestUpdate(ctx, &type, sizeof(type)); err |= EVP_DigestUpdate(ctx, &type, sizeof(type));
if (!err) { if (!err) {
log_err("EVP_DigestUpdate() failed\n"); log_err("EVP_DigestUpdate() failed\n");
return 1; result = 1;
break;
} }
} }
closedir(dir); closedir(dir);
return 0; return result;
} }
static int add_link_hash(const char *path, EVP_MD_CTX *ctx) static int add_link_hash(const char *path, EVP_MD_CTX *ctx)
@ -266,9 +271,15 @@ int ima_calc_hash(const char *file, uint8_t *hash)
{ {
const EVP_MD *md; const EVP_MD *md;
struct stat st; struct stat st;
EVP_MD_CTX ctx; EVP_MD_CTX *pctx;
unsigned int mdlen; unsigned int mdlen;
int err; int err;
#if OPENSSL_VERSION_NUMBER < 0x10100000
EVP_MD_CTX ctx;
pctx = &ctx;
#else
pctx = EVP_MD_CTX_new();
#endif
/* Need to know the file length */ /* Need to know the file length */
err = lstat(file, &st); err = lstat(file, &st);
@ -283,7 +294,7 @@ int ima_calc_hash(const char *file, uint8_t *hash)
return 1; return 1;
} }
err = EVP_DigestInit(&ctx, md); err = EVP_DigestInit(pctx, md);
if (!err) { if (!err) {
log_err("EVP_DigestInit() failed\n"); log_err("EVP_DigestInit() failed\n");
return 1; return 1;
@ -291,17 +302,17 @@ int ima_calc_hash(const char *file, uint8_t *hash)
switch (st.st_mode & S_IFMT) { switch (st.st_mode & S_IFMT) {
case S_IFREG: case S_IFREG:
err = add_file_hash(file, &ctx); err = add_file_hash(file, pctx);
break; break;
case S_IFDIR: case S_IFDIR:
err = add_dir_hash(file, &ctx); err = add_dir_hash(file, pctx);
break; break;
case S_IFLNK: case S_IFLNK:
err = add_link_hash(file, &ctx); err = add_link_hash(file, pctx);
break; break;
case S_IFIFO: case S_IFSOCK: case S_IFIFO: case S_IFSOCK:
case S_IFCHR: case S_IFBLK: case S_IFCHR: case S_IFBLK:
err = add_dev_hash(&st, &ctx); err = add_dev_hash(&st, pctx);
break; break;
default: default:
log_errno("Unsupported file type"); log_errno("Unsupported file type");
@ -311,7 +322,7 @@ int ima_calc_hash(const char *file, uint8_t *hash)
if (err) if (err)
return err; return err;
err = EVP_DigestFinal(&ctx, hash, &mdlen); err = EVP_DigestFinal(pctx, hash, &mdlen);
if (!err) { if (!err) {
log_err("EVP_DigestFinal() failed\n"); log_err("EVP_DigestFinal() failed\n");
return 1; return 1;
@ -361,7 +372,8 @@ out:
return key; return key;
} }
int verify_hash_v1(const unsigned char *hash, int size, unsigned char *sig, int siglen, const char *keyfile) int verify_hash_v1(const char *file, const unsigned char *hash, int size,
unsigned char *sig, int siglen, const char *keyfile)
{ {
int err, len; int err, len;
SHA_CTX ctx; SHA_CTX ctx;
@ -370,7 +382,7 @@ int verify_hash_v1(const unsigned char *hash, int size, unsigned char *sig, int
unsigned char sighash[20]; unsigned char sighash[20];
struct signature_hdr *hdr = (struct signature_hdr *)sig; struct signature_hdr *hdr = (struct signature_hdr *)sig;
log_info("hash: "); log_info("hash-v1: ");
log_dump(hash, size); log_dump(hash, size);
key = read_pub_key(keyfile, 0); key = read_pub_key(keyfile, 0);
@ -387,24 +399,77 @@ int verify_hash_v1(const unsigned char *hash, int size, unsigned char *sig, int
err = RSA_public_decrypt(siglen - sizeof(*hdr) - 2, sig + sizeof(*hdr) + 2, out, key, RSA_PKCS1_PADDING); err = RSA_public_decrypt(siglen - sizeof(*hdr) - 2, sig + sizeof(*hdr) + 2, out, key, RSA_PKCS1_PADDING);
RSA_free(key); RSA_free(key);
if (err < 0) { if (err < 0) {
log_err("RSA_public_decrypt() failed: %d\n", err); log_err("%s: RSA_public_decrypt() failed: %d\n", file, err);
return 1; return 1;
} }
len = err; len = err;
if (len != sizeof(sighash) || memcmp(out, sighash, len) != 0) { if (len != sizeof(sighash) || memcmp(out, sighash, len) != 0) {
log_err("Verification failed: %d\n", err); log_err("%s: verification failed: %d\n", file, err);
return -1; return -1;
} else {
/*log_info("Verification is OK\n");*/
printf("Verification is OK\n");
} }
return 0; return 0;
} }
int verify_hash_v2(const unsigned char *hash, int size, unsigned char *sig, int siglen, const char *keyfile) struct public_key_entry {
struct public_key_entry *next;
uint32_t keyid;
char name[9];
RSA *key;
};
static struct public_key_entry *public_keys = NULL;
static RSA *find_keyid(uint32_t keyid)
{
struct public_key_entry *entry;
for (entry = public_keys; entry != NULL; entry = entry->next) {
if (entry->keyid == keyid)
return entry->key;
}
return NULL;
}
void init_public_keys(const char *keyfiles)
{
struct public_key_entry *entry;
char *tmp_keyfiles;
char *keyfile;
int i = 1;
tmp_keyfiles = strdup(keyfiles);
while ((keyfile = strsep(&tmp_keyfiles, ", \t")) != NULL) {
if (!keyfile)
break;
if ((*keyfile == '\0') || (*keyfile == ' ') ||
(*keyfile == '\t'))
continue;
entry = malloc(sizeof(struct public_key_entry));
if (!entry) {
perror("malloc");
break;
}
entry->key = read_pub_key(keyfile, 1);
if (!entry->key) {
free(entry);
continue;
}
calc_keyid_v2(&entry->keyid, entry->name, entry->key);
sprintf(entry->name, "%x", __be32_to_cpup(&entry->keyid));
log_info("key %d: %s %s\n", i++, entry->name, keyfile);
entry->next = public_keys;
public_keys = entry;
}
}
int verify_hash_v2(const char *file, const unsigned char *hash, int size,
unsigned char *sig, int siglen, const char *keyfile)
{ {
int err, len; int err, len;
unsigned char out[1024]; unsigned char out[1024];
@ -412,17 +477,29 @@ int verify_hash_v2(const unsigned char *hash, int size, unsigned char *sig, int
struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig; struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
const struct RSA_ASN1_template *asn1; const struct RSA_ASN1_template *asn1;
log_info("hash: "); if (params.verbose > LOG_INFO) {
log_dump(hash, size); log_info("hash: ");
log_dump(hash, size);
}
key = read_pub_key(keyfile, 1); if (public_keys) {
if (!key) key = find_keyid(hdr->keyid);
return 1; if (!key) {
log_err("%s: unknown keyid: %x\n", file,
__be32_to_cpup(&hdr->keyid));
return -1;
}
} else {
key = read_pub_key(keyfile, 1);
if (!key)
return 1;
}
err = RSA_public_decrypt(siglen - sizeof(*hdr), sig + sizeof(*hdr), out, key, RSA_PKCS1_PADDING);
RSA_free(key); err = RSA_public_decrypt(siglen - sizeof(*hdr), sig + sizeof(*hdr),
out, key, RSA_PKCS1_PADDING);
if (err < 0) { if (err < 0) {
log_err("RSA_public_decrypt() failed: %d\n", err); log_err("%s: RSA_public_decrypt() failed: %d\n", file, err);
return 1; return 1;
} }
@ -431,20 +508,17 @@ int verify_hash_v2(const unsigned char *hash, int size, unsigned char *sig, int
asn1 = &RSA_ASN1_templates[hdr->hash_algo]; asn1 = &RSA_ASN1_templates[hdr->hash_algo];
if (len < asn1->size || memcmp(out, asn1->data, asn1->size)) { if (len < asn1->size || memcmp(out, asn1->data, asn1->size)) {
log_err("Verification failed: %d\n", err); log_err("%s: verification failed: %d\n", file, err);
return -1; return -1;
} }
len -= asn1->size; len -= asn1->size;
if (len != size || memcmp(out + asn1->size, hash, len)) { if (len != size || memcmp(out + asn1->size, hash, len)) {
log_err("Verification failed: %d\n", err); log_err("%s: verification failed: %d\n", file, err);
return -1; return -1;
} }
/*log_info("Verification is OK\n");*/
printf("Verification is OK\n");
return 0; return 0;
} }
@ -486,9 +560,10 @@ static int get_hash_algo_from_sig(unsigned char *sig)
return -1; return -1;
} }
int verify_hash(const unsigned char *hash, int size, unsigned char *sig, int siglen) int verify_hash(const char *file, 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;
@ -509,10 +584,11 @@ int verify_hash(const unsigned char *hash, int size, unsigned char *sig, int sig
"/etc/keys/x509_evm.der" : "/etc/keys/x509_evm.der" :
"/etc/keys/pubkey_evm.pem"; "/etc/keys/pubkey_evm.pem";
return verify_hash(hash, size, sig, siglen, key); return verify_hash(file, hash, size, sig, siglen, key);
} }
int ima_verify_signature(const char *file, unsigned char *sig, int siglen) int ima_verify_signature(const char *file, unsigned char *sig, int siglen,
unsigned char *digest, int digestlen)
{ {
unsigned char hash[64]; unsigned char hash[64];
int hashlen, sig_hash_algo; int hashlen, sig_hash_algo;
@ -530,11 +606,18 @@ int ima_verify_signature(const char *file, unsigned char *sig, int siglen)
/* Use hash algorithm as retrieved from signature */ /* Use hash algorithm as retrieved from signature */
params.hash_algo = pkey_hash_algo[sig_hash_algo]; params.hash_algo = pkey_hash_algo[sig_hash_algo];
/*
* Validate the signature based on the digest included in the
* measurement list, not by calculating the local file digest.
*/
if (digestlen > 0)
return verify_hash(file, digest, digestlen, sig + 1, siglen - 1);
hashlen = ima_calc_hash(file, hash); hashlen = ima_calc_hash(file, hash);
if (hashlen <= 1) if (hashlen <= 1)
return hashlen; return hashlen;
return verify_hash(hash, hashlen, sig + 1, siglen - 1); return verify_hash(file, hash, hashlen, sig + 1, siglen - 1);
} }
/* /*
@ -544,6 +627,14 @@ int key2bin(RSA *key, unsigned char *pub)
{ {
int len, b, offset = 0; int len, b, offset = 0;
struct pubkey_hdr *pkh = (struct pubkey_hdr *)pub; struct pubkey_hdr *pkh = (struct pubkey_hdr *)pub;
const BIGNUM *n, *e;
#if OPENSSL_VERSION_NUMBER < 0x10100000
n = key->n;
e = key->e;
#else
RSA_get0_key(key, &n, &e, NULL);
#endif
/* add key header */ /* add key header */
pkh->version = 1; pkh->version = 1;
@ -553,18 +644,18 @@ int key2bin(RSA *key, unsigned char *pub)
offset += sizeof(*pkh); offset += sizeof(*pkh);
len = BN_num_bytes(key->n); len = BN_num_bytes(n);
b = BN_num_bits(key->n); b = BN_num_bits(n);
pub[offset++] = b >> 8; pub[offset++] = b >> 8;
pub[offset++] = b & 0xff; pub[offset++] = b & 0xff;
BN_bn2bin(key->n, &pub[offset]); BN_bn2bin(n, &pub[offset]);
offset += len; offset += len;
len = BN_num_bytes(key->e); len = BN_num_bytes(e);
b = BN_num_bits(key->e); b = BN_num_bits(e);
pub[offset++] = b >> 8; pub[offset++] = b >> 8;
pub[offset++] = b & 0xff; pub[offset++] = b & 0xff;
BN_bn2bin(key->e, &pub[offset]); BN_bn2bin(e, &pub[offset]);
offset += len; offset += len;
return offset; return offset;
@ -582,9 +673,11 @@ void calc_keyid_v1(uint8_t *keyid, char *str, const unsigned char *pkey, int len
log_debug("keyid: "); log_debug("keyid: ");
log_debug_dump(keyid, 8); log_debug_dump(keyid, 8);
id = __be64_to_cpup((__be64 *) keyid); if (params.verbose > LOG_INFO) {
sprintf(str, "%llX", (unsigned long long)id); id = __be64_to_cpup((__be64 *) keyid);
log_info("keyid: %s\n", str); sprintf(str, "%llX", (unsigned long long)id);
log_info("keyid-v1: %s\n", str);
}
} }
void calc_keyid_v2(uint32_t *keyid, char *str, RSA *key) void calc_keyid_v2(uint32_t *keyid, char *str, RSA *key)
@ -602,13 +695,15 @@ void calc_keyid_v2(uint32_t *keyid, char *str, RSA *key)
log_debug("keyid: "); log_debug("keyid: ");
log_debug_dump(keyid, 4); log_debug_dump(keyid, 4);
sprintf(str, "%x", __be32_to_cpup(keyid)); if (params.verbose > LOG_INFO) {
log_info("keyid: %s\n", str); sprintf(str, "%x", __be32_to_cpup(keyid));
log_info("keyid: %s\n", str);
}
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 +713,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;
@ -711,7 +811,7 @@ int sign_hash_v1(const char *hashalgo, const unsigned char *hash, int size, cons
blen = (uint16_t *) (sig + sizeof(*hdr)); blen = (uint16_t *) (sig + sizeof(*hdr));
*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-v1: %d bytes\n", len);
out: out:
RSA_free(key); RSA_free(key);
return len; return len;
@ -786,8 +886,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();
}