|
|
|
@ -1,26 +1,26 @@
|
|
|
|
|
/*
|
|
|
|
|
* evm-utils - IMA/EVM support utilities
|
|
|
|
|
* ima-evm-utils - IMA/EVM support utilities
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2011 Nokia Corporation
|
|
|
|
|
* Copyright (C) 2011,2012,2013 Intel Corporation
|
|
|
|
|
* Copyright (C) 2013 Samsung Electronics
|
|
|
|
|
*
|
|
|
|
|
* Authors:
|
|
|
|
|
* Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
|
|
|
|
|
* <dmitry.kasatkin@intel.com>
|
|
|
|
|
* <d.kasatkin@samsung.com>
|
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Lesser General Public License
|
|
|
|
|
* version 2.1 as published by the Free Software Foundation.
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* version 2 as published by the Free Software Foundation.
|
|
|
|
|
*
|
|
|
|
|
* This library is distributed in the hope that it will be useful, but
|
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
|
|
|
* 02110-1301 USA
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*
|
|
|
|
|
* File: evmctl.c
|
|
|
|
|
* IMA/EVM control program
|
|
|
|
@ -108,6 +108,11 @@ enum digest_algo {
|
|
|
|
|
DIGEST_ALGO_MAX
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum digsig_version {
|
|
|
|
|
DIGSIG_VERSION_1 = 1,
|
|
|
|
|
DIGSIG_VERSION_2
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct pubkey_hdr {
|
|
|
|
|
uint8_t version; /* key format version */
|
|
|
|
|
uint32_t timestamp; /* key made, always 0 for now */
|
|
|
|
@ -244,12 +249,14 @@ static int xattr = 1;
|
|
|
|
|
static int sigdump;
|
|
|
|
|
static int digest;
|
|
|
|
|
static int digsig;
|
|
|
|
|
static char *hash_algo = "sha1";
|
|
|
|
|
static const char *hash_algo = "sha1";
|
|
|
|
|
static int user_hash_algo;
|
|
|
|
|
static char *keypass;
|
|
|
|
|
static int sigfile;
|
|
|
|
|
static int modsig;
|
|
|
|
|
static char *uuid_str;
|
|
|
|
|
static int x509;
|
|
|
|
|
static int user_sig_type;
|
|
|
|
|
static char *keyfile;
|
|
|
|
|
|
|
|
|
|
typedef int (*sign_hash_fn_t)(const char *algo, const unsigned char *hash, int size, const char *keyfile, unsigned char *sig);
|
|
|
|
@ -476,9 +483,20 @@ static RSA *read_priv_key(const char *keyfile)
|
|
|
|
|
return key;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int sign_hash_v1(const char *algo, const unsigned char *hash, int size, const char *keyfile, unsigned char *sig)
|
|
|
|
|
int get_hash_algo_v1(const char *algo)
|
|
|
|
|
{
|
|
|
|
|
int err, len;
|
|
|
|
|
|
|
|
|
|
if (!strcmp(algo, "sha1"))
|
|
|
|
|
return DIGEST_ALGO_SHA1;
|
|
|
|
|
else if (!strcmp(algo, "sha256"))
|
|
|
|
|
return DIGEST_ALGO_SHA256;
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int sign_hash_v1(const char *hashalgo, const unsigned char *hash, int size, const char *keyfile, unsigned char *sig)
|
|
|
|
|
{
|
|
|
|
|
int len = -1, hashalgo_idx;
|
|
|
|
|
SHA_CTX ctx;
|
|
|
|
|
unsigned char pub[1024];
|
|
|
|
|
RSA *key;
|
|
|
|
@ -495,10 +513,16 @@ static int sign_hash_v1(const char *algo, const unsigned char *hash, int size, c
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
/* now create a new hash */
|
|
|
|
|
hdr->version = 1;
|
|
|
|
|
hdr->version = (uint8_t) DIGSIG_VERSION_1;
|
|
|
|
|
hdr->timestamp = time(NULL);
|
|
|
|
|
hdr->algo = PUBKEY_ALGO_RSA;
|
|
|
|
|
hdr->hash = DIGEST_ALGO_SHA1;
|
|
|
|
|
hashalgo_idx = get_hash_algo_v1(hashalgo);
|
|
|
|
|
if (hashalgo_idx < 0) {
|
|
|
|
|
log_err("Signature version 1 does not support hash algo %s\n",
|
|
|
|
|
hashalgo);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
hdr->hash = (uint8_t) hashalgo_idx;
|
|
|
|
|
|
|
|
|
|
len = key2bin(key, pub);
|
|
|
|
|
calc_keyid_v1(hdr->keyid, name, pub, len);
|
|
|
|
@ -512,15 +536,12 @@ static int sign_hash_v1(const char *algo, const unsigned char *hash, int size, c
|
|
|
|
|
log_info("sighash: ");
|
|
|
|
|
log_dump(sighash, sizeof(sighash));
|
|
|
|
|
|
|
|
|
|
err = RSA_private_encrypt(sizeof(sighash), sighash, sig + sizeof(*hdr) + 2, key, RSA_PKCS1_PADDING);
|
|
|
|
|
RSA_free(key);
|
|
|
|
|
if (err < 0) {
|
|
|
|
|
log_err("RSA_private_encrypt() failed: %d\n", err);
|
|
|
|
|
return 1;
|
|
|
|
|
len = RSA_private_encrypt(sizeof(sighash), sighash, sig + sizeof(*hdr) + 2, key, RSA_PKCS1_PADDING);
|
|
|
|
|
if (len < 0) {
|
|
|
|
|
log_err("RSA_private_encrypt() failed: %d\n", len);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
len = err;
|
|
|
|
|
|
|
|
|
|
/* we add bit length of the signature to make it gnupg compatible */
|
|
|
|
|
blen = (uint16_t *) (sig + sizeof(*hdr));
|
|
|
|
|
*blen = __cpu_to_be16(len << 3);
|
|
|
|
@ -528,7 +549,8 @@ static int sign_hash_v1(const char *algo, const unsigned char *hash, int size, c
|
|
|
|
|
log_info("evm/ima signature: %d bytes\n", len);
|
|
|
|
|
if (sigdump || verbose >= LOG_INFO)
|
|
|
|
|
dump(sig, len);
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
RSA_free(key);
|
|
|
|
|
return len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -546,7 +568,7 @@ uint8_t get_hash_algo(const char *algo)
|
|
|
|
|
static int sign_hash_v2(const char *algo, const unsigned char *hash, int size, const char *keyfile, unsigned char *sig)
|
|
|
|
|
{
|
|
|
|
|
struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
|
|
|
|
|
int len;
|
|
|
|
|
int len = -1;
|
|
|
|
|
RSA *key;
|
|
|
|
|
char name[20];
|
|
|
|
|
unsigned char *buf;
|
|
|
|
@ -559,7 +581,7 @@ static int sign_hash_v2(const char *algo, const unsigned char *hash, int size, c
|
|
|
|
|
if (!key)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
hdr->version = 2;
|
|
|
|
|
hdr->version = (uint8_t) DIGSIG_VERSION_2;
|
|
|
|
|
hdr->hash_algo = get_hash_algo(algo);
|
|
|
|
|
|
|
|
|
|
calc_keyid_v2(&hdr->keyid, name, key);
|
|
|
|
@ -568,16 +590,15 @@ static int sign_hash_v2(const char *algo, const unsigned char *hash, int size, c
|
|
|
|
|
|
|
|
|
|
buf = malloc(size + asn1->size);
|
|
|
|
|
if (!buf)
|
|
|
|
|
return -1;
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
memcpy(buf, asn1->data, asn1->size);
|
|
|
|
|
memcpy(buf + asn1->size, hash, size);
|
|
|
|
|
len = RSA_private_encrypt(size + asn1->size, buf, hdr->sig,
|
|
|
|
|
key, RSA_PKCS1_PADDING);
|
|
|
|
|
RSA_free(key);
|
|
|
|
|
if (len < 0) {
|
|
|
|
|
log_err("RSA_private_encrypt() failed: %d\n", len);
|
|
|
|
|
return -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* we add bit length of the signature to make it gnupg compatible */
|
|
|
|
@ -586,7 +607,10 @@ static int sign_hash_v2(const char *algo, const unsigned char *hash, int size, c
|
|
|
|
|
log_info("evm/ima signature: %d bytes\n", len);
|
|
|
|
|
if (sigdump || verbose >= LOG_INFO)
|
|
|
|
|
dump(sig, len);
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
if (buf)
|
|
|
|
|
free(buf);
|
|
|
|
|
RSA_free(key);
|
|
|
|
|
return len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -612,10 +636,16 @@ static int hex_to_bin(char ch)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void pack_uuid(const char *uuid_str, char *to)
|
|
|
|
|
static int pack_uuid(const char *uuid_str, char *uuid)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
char *to = uuid;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 16; ++i) {
|
|
|
|
|
if (!uuid_str[0] || !uuid_str[1]) {
|
|
|
|
|
log_err("wrong UUID format\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
*to++ = (hex_to_bin(*uuid_str) << 4) |
|
|
|
|
|
(hex_to_bin(*(uuid_str + 1)));
|
|
|
|
|
uuid_str += 2;
|
|
|
|
@ -624,10 +654,17 @@ static void pack_uuid(const char *uuid_str, char *to)
|
|
|
|
|
case 5:
|
|
|
|
|
case 7:
|
|
|
|
|
case 9:
|
|
|
|
|
if (*uuid_str != '-') {
|
|
|
|
|
log_err("wrong UUID format\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
uuid_str++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
log_info("uuid: ");
|
|
|
|
|
log_dump(uuid, 16);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int get_uuid(struct stat *st, char *uuid)
|
|
|
|
@ -638,10 +675,8 @@ static int get_uuid(struct stat *st, char *uuid)
|
|
|
|
|
FILE *fp;
|
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
|
|
if (uuid_str[0] != '-') {
|
|
|
|
|
pack_uuid(uuid_str, uuid);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (uuid_str[0] != '-')
|
|
|
|
|
return pack_uuid(uuid_str, uuid);
|
|
|
|
|
|
|
|
|
|
dev = st->st_dev;
|
|
|
|
|
major = (dev & 0xfff00) >> 8;
|
|
|
|
@ -663,12 +698,7 @@ static int get_uuid(struct stat *st, char *uuid)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pack_uuid(_uuid, uuid);
|
|
|
|
|
|
|
|
|
|
log_info("uuid: ");
|
|
|
|
|
log_dump(uuid, 16);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
return pack_uuid(_uuid, uuid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int calc_evm_hash(const char *file, unsigned char *hash)
|
|
|
|
@ -1020,7 +1050,7 @@ static int sign_ima(const char *file, const char *key)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sigfile)
|
|
|
|
|
bin2file(file, "sig", sig + 1, len - 1);
|
|
|
|
|
bin2file(file, "sig", sig, len);
|
|
|
|
|
|
|
|
|
|
if (xattr) {
|
|
|
|
|
err = setxattr(file, "security.ima", sig, len, 0);
|
|
|
|
@ -1060,12 +1090,6 @@ static int cmd_sign_evm(struct command *cmd)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!digsig && !digest) {
|
|
|
|
|
log_err("Parameters missing\n");
|
|
|
|
|
print_usage(cmd);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
key = keyfile ? : "/etc/keys/privkey_evm.pem";
|
|
|
|
|
|
|
|
|
|
if (digsig) {
|
|
|
|
@ -1141,7 +1165,7 @@ static int verify_hash_v2(const unsigned char *hash, int size, unsigned char *si
|
|
|
|
|
if (!key)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
err = RSA_public_decrypt(siglen - sizeof(*hdr) - 2, sig + sizeof(*hdr) + 2, out, key, RSA_PKCS1_PADDING);
|
|
|
|
|
err = RSA_public_decrypt(siglen - sizeof(*hdr), sig + sizeof(*hdr), out, key, RSA_PKCS1_PADDING);
|
|
|
|
|
RSA_free(key);
|
|
|
|
|
if (err < 0) {
|
|
|
|
|
log_err("RSA_public_decrypt() failed: %d\n", err);
|
|
|
|
@ -1211,15 +1235,40 @@ static int cmd_verify_evm(struct command *cmd)
|
|
|
|
|
return verify_evm(file, key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int verify_ima(const char *file, const char *key)
|
|
|
|
|
static int get_hash_algo_from_sig(unsigned char *sig)
|
|
|
|
|
{
|
|
|
|
|
unsigned char hash[20];
|
|
|
|
|
unsigned char sig[1024];
|
|
|
|
|
int len;
|
|
|
|
|
uint8_t hashalgo;
|
|
|
|
|
|
|
|
|
|
len = calc_hash(file, hash);
|
|
|
|
|
if (len <= 1)
|
|
|
|
|
return len;
|
|
|
|
|
if (sig[0] == 1) {
|
|
|
|
|
hashalgo = ((struct signature_hdr *)sig)->hash;
|
|
|
|
|
|
|
|
|
|
if (hashalgo >= DIGEST_ALGO_MAX)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
switch (hashalgo) {
|
|
|
|
|
case DIGEST_ALGO_SHA1:
|
|
|
|
|
return PKEY_HASH_SHA1;
|
|
|
|
|
case DIGEST_ALGO_SHA256:
|
|
|
|
|
return PKEY_HASH_SHA256;
|
|
|
|
|
default:
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
} else if (sig[0] == 2) {
|
|
|
|
|
hashalgo = ((struct signature_v2_hdr *)sig)->hash_algo;
|
|
|
|
|
if (hashalgo >= PKEY_HASH__LAST)
|
|
|
|
|
return -1;
|
|
|
|
|
return hashalgo;
|
|
|
|
|
} else
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int verify_ima(const char *file)
|
|
|
|
|
{
|
|
|
|
|
unsigned char hash[64];
|
|
|
|
|
unsigned char sig[1024];
|
|
|
|
|
int len, hashlen;
|
|
|
|
|
int sig_hash_algo;
|
|
|
|
|
char *key;
|
|
|
|
|
|
|
|
|
|
if (xattr) {
|
|
|
|
|
len = getxattr(file, "security.ima", sig, sizeof(sig));
|
|
|
|
@ -1241,12 +1290,44 @@ static int verify_ima(const char *file, const char *key)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return verify_hash(hash, sizeof(hash), sig + 1, len - 1, key);
|
|
|
|
|
/* If user specified an hash algo on command line, let it override */
|
|
|
|
|
if (!user_hash_algo) {
|
|
|
|
|
sig_hash_algo = get_hash_algo_from_sig(sig + 1);
|
|
|
|
|
if (sig_hash_algo < 0) {
|
|
|
|
|
log_err("Invalid signature\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Use hash algorithm as retrieved from signature */
|
|
|
|
|
hash_algo = pkey_hash_algo[sig_hash_algo];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hashlen = calc_hash(file, hash);
|
|
|
|
|
if (hashlen <= 1)
|
|
|
|
|
return hashlen;
|
|
|
|
|
|
|
|
|
|
/* Get signature type from sig header if user did not enforce it */
|
|
|
|
|
if (!user_sig_type) {
|
|
|
|
|
if (sig[1] == DIGSIG_VERSION_1)
|
|
|
|
|
verify_hash = verify_hash_v1;
|
|
|
|
|
else if (sig[1] == DIGSIG_VERSION_2) {
|
|
|
|
|
verify_hash = verify_hash_v2;
|
|
|
|
|
/* Read pubkey from x509 cert */
|
|
|
|
|
x509 = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Determine what key to use for verification*/
|
|
|
|
|
key = keyfile ? : x509 ?
|
|
|
|
|
"/etc/keys/x509_evm.der" :
|
|
|
|
|
"/etc/keys/pubkey_evm.pem";
|
|
|
|
|
|
|
|
|
|
return verify_hash(hash, hashlen, sig + 1, len - 1, key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int cmd_verify_ima(struct command *cmd)
|
|
|
|
|
{
|
|
|
|
|
char *key, *file = g_argv[optind++];
|
|
|
|
|
char *file = g_argv[optind++];
|
|
|
|
|
|
|
|
|
|
if (!file) {
|
|
|
|
|
log_err("Parameters missing\n");
|
|
|
|
@ -1254,21 +1335,17 @@ static int cmd_verify_ima(struct command *cmd)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
key = keyfile ? : x509 ?
|
|
|
|
|
"/etc/keys/x509_evm.der" :
|
|
|
|
|
"/etc/keys/pubkey_evm.pem";
|
|
|
|
|
|
|
|
|
|
return verify_ima(file, key);
|
|
|
|
|
return verify_ima(file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int cmd_import(struct command *cmd)
|
|
|
|
|
{
|
|
|
|
|
char *inkey, *ring = NULL;
|
|
|
|
|
unsigned char _pub[1024], *pub = _pub;
|
|
|
|
|
int id, len, err = -1;
|
|
|
|
|
int id, len, err = 0;
|
|
|
|
|
char name[20];
|
|
|
|
|
uint8_t keyid[8];
|
|
|
|
|
RSA *key = NULL;
|
|
|
|
|
RSA *key;
|
|
|
|
|
|
|
|
|
|
inkey = g_argv[optind++];
|
|
|
|
|
if (!inkey) {
|
|
|
|
@ -1284,7 +1361,7 @@ static int cmd_import(struct command *cmd)
|
|
|
|
|
|
|
|
|
|
key = read_pub_key(inkey);
|
|
|
|
|
if (!key)
|
|
|
|
|
goto out;
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (x509) {
|
|
|
|
|
pub = file2bin(inkey, NULL, &len);
|
|
|
|
@ -1301,19 +1378,15 @@ static int cmd_import(struct command *cmd)
|
|
|
|
|
id = add_key(x509 ? "asymmetric" : "user", x509 ? NULL : name, pub, len, id);
|
|
|
|
|
if (id < 0) {
|
|
|
|
|
log_err("add_key failed\n");
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = id;
|
|
|
|
|
} else {
|
|
|
|
|
log_info("keyid: %d\n", id);
|
|
|
|
|
printf("%d\n", id);
|
|
|
|
|
|
|
|
|
|
err = 0;
|
|
|
|
|
out:
|
|
|
|
|
if (key)
|
|
|
|
|
RSA_free(key);
|
|
|
|
|
}
|
|
|
|
|
if (x509)
|
|
|
|
|
free(pub);
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
RSA_free(key);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1322,7 +1395,7 @@ out:
|
|
|
|
|
static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *hash)
|
|
|
|
|
{
|
|
|
|
|
struct stat st;
|
|
|
|
|
int fd, err;
|
|
|
|
|
int fd, err = -1;
|
|
|
|
|
uint32_t generation;
|
|
|
|
|
HMAC_CTX ctx;
|
|
|
|
|
unsigned int mdlen;
|
|
|
|
@ -1342,7 +1415,7 @@ static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *h
|
|
|
|
|
|
|
|
|
|
if (keylen > sizeof(evmkey)) {
|
|
|
|
|
log_err("key is too long\n");
|
|
|
|
|
return -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* EVM key is 128 bytes */
|
|
|
|
@ -1352,17 +1425,17 @@ static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *h
|
|
|
|
|
fd = open(file, 0);
|
|
|
|
|
if (fd < 0) {
|
|
|
|
|
log_err("Unable to open %s\n", file);
|
|
|
|
|
return -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fstat(fd, &st)) {
|
|
|
|
|
log_err("fstat() failed\n");
|
|
|
|
|
return -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ioctl(fd, EXT34_IOC_GETVERSION, &generation)) {
|
|
|
|
|
log_err("ioctl() failed\n");
|
|
|
|
|
return -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
@ -1372,13 +1445,13 @@ static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *h
|
|
|
|
|
list_size = llistxattr(file, list, sizeof(list));
|
|
|
|
|
if (list_size <= 0) {
|
|
|
|
|
log_err("llistxattr() failed\n");
|
|
|
|
|
return -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = HMAC_Init(&ctx, evmkey, sizeof(evmkey), EVP_sha1());
|
|
|
|
|
if (!err) {
|
|
|
|
|
err = !HMAC_Init(&ctx, evmkey, sizeof(evmkey), EVP_sha1());
|
|
|
|
|
if (err) {
|
|
|
|
|
log_err("HMAC_Init() failed\n");
|
|
|
|
|
return 1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) {
|
|
|
|
@ -1394,10 +1467,10 @@ static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *h
|
|
|
|
|
/*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 = HMAC_Update(&ctx, xattr_value, err);
|
|
|
|
|
if (!err) {
|
|
|
|
|
err = !HMAC_Update(&ctx, xattr_value, err);
|
|
|
|
|
if (err) {
|
|
|
|
|
log_err("HMAC_Update() failed\n");
|
|
|
|
|
return 1;
|
|
|
|
|
goto out_ctx_cleanup;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1408,21 +1481,19 @@ 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;
|
|
|
|
|
|
|
|
|
|
err = HMAC_Update(&ctx, (const unsigned char *)&hmac_misc, sizeof(hmac_misc));
|
|
|
|
|
if (!err) {
|
|
|
|
|
err = !HMAC_Update(&ctx, (const unsigned char *)&hmac_misc, sizeof(hmac_misc));
|
|
|
|
|
if (err) {
|
|
|
|
|
log_err("HMAC_Update() failed\n");
|
|
|
|
|
return 1;
|
|
|
|
|
goto out_ctx_cleanup;
|
|
|
|
|
}
|
|
|
|
|
err = HMAC_Final(&ctx, hash, &mdlen);
|
|
|
|
|
if (!err) {
|
|
|
|
|
err = !HMAC_Final(&ctx, hash, &mdlen);
|
|
|
|
|
if (err)
|
|
|
|
|
log_err("HMAC_Final() failed\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
out_ctx_cleanup:
|
|
|
|
|
HMAC_CTX_cleanup(&ctx);
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
free(key);
|
|
|
|
|
|
|
|
|
|
return mdlen;
|
|
|
|
|
return err ?: mdlen;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int hmac_evm(const char *file, const char *key)
|
|
|
|
@ -1461,12 +1532,6 @@ static int cmd_hmac_evm(struct command *cmd)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!digsig && !digest) {
|
|
|
|
|
log_err("Parameters missing\n");
|
|
|
|
|
print_usage(cmd);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
key = keyfile ? : "/etc/keys/privkey_evm.pem";
|
|
|
|
|
|
|
|
|
|
if (digsig) {
|
|
|
|
@ -1562,6 +1627,7 @@ static void usage(void)
|
|
|
|
|
" -x, --x509 signing key is in x509 DER format (signing v2 for using asymmetric keys)\n"
|
|
|
|
|
" -k, --key path to signing key (default keys are /etc/keys/{privkey,pubkey}_evm.pem)\n"
|
|
|
|
|
" -p, --pass password for encrypted signing key\n"
|
|
|
|
|
" -u, --uuid use file system UUID in HMAC calculation (EVM v2)\n"
|
|
|
|
|
" -n print result to stdout instead of setting xattr\n"
|
|
|
|
|
" -v increase verbosity level\n"
|
|
|
|
|
" -h, --help display this help and exit\n"
|
|
|
|
@ -1590,7 +1656,7 @@ static struct option opts[] = {
|
|
|
|
|
{"pass", 1, 0, 'p'},
|
|
|
|
|
{"sigfile", 0, 0, 'f'},
|
|
|
|
|
{"modsig", 0, 0, 'm'},
|
|
|
|
|
{"uuid", 1, 0, 'u'},
|
|
|
|
|
{"uuid", 2, 0, 'u'},
|
|
|
|
|
{"x509", 0, 0, 'x'},
|
|
|
|
|
{"key", 1, 0, 'k'},
|
|
|
|
|
{}
|
|
|
|
@ -1608,7 +1674,7 @@ int main(int argc, char *argv[])
|
|
|
|
|
verify_hash = verify_hash_v1;
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
c = getopt_long(argc, argv, "hvnsda:p:fu:xk:", opts, &lind);
|
|
|
|
|
c = getopt_long(argc, argv, "hvnsda:p:fu::xk:", opts, &lind);
|
|
|
|
|
if (c == -1)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
@ -1633,6 +1699,7 @@ int main(int argc, char *argv[])
|
|
|
|
|
break;
|
|
|
|
|
case 'a':
|
|
|
|
|
hash_algo = optarg;
|
|
|
|
|
user_hash_algo = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 'p':
|
|
|
|
|
keypass = optarg;
|
|
|
|
@ -1646,12 +1713,13 @@ int main(int argc, char *argv[])
|
|
|
|
|
xattr = 0;
|
|
|
|
|
break;
|
|
|
|
|
case 'u':
|
|
|
|
|
uuid_str = optarg;
|
|
|
|
|
uuid_str = optarg ?: "-";
|
|
|
|
|
break;
|
|
|
|
|
case 'x':
|
|
|
|
|
x509 = 1;
|
|
|
|
|
sign_hash = sign_hash_v2;
|
|
|
|
|
verify_hash = verify_hash_v2;
|
|
|
|
|
user_sig_type = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 'k':
|
|
|
|
|
keyfile = optarg;
|
|
|
|
|