Move sign hash functions to library
This patch enables package managers, such as rpm, to include IMA signatures in packages. To do this, sign_hash and some helper functions were moved from evmctl to libimaevm. These functions used global variables that belong to evmctl, sigdump and keypass. The variable sigdump is a flag that file signatures should be printed to stdout, so the signature dump is now handled by functions that call sign_hash. The variable keypass is a passphrase for an encrypted key, so it was added to 'struct libevm_params'. v2: Uses 'struct libevm_params' to minimize sign_hash parameters v3: Export single sign_hash function that selects _v1 or _v2 internally based on params.x509. Moved parameter checks and explicitly return -1 for failures. Signed-off-by: Fionnuala Gunter <fin@linux.vnet.ibm.com> Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
This commit is contained in:
parent
29adc34d35
commit
8f04d131ac
250
src/evmctl.c
250
src/evmctl.c
@ -52,7 +52,6 @@
|
|||||||
#include <attr/xattr.h>
|
#include <attr/xattr.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <keyutils.h>
|
#include <keyutils.h>
|
||||||
#include <asm/byteorder.h>
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
@ -88,9 +87,7 @@ static bool check_xattr;
|
|||||||
static int sigdump;
|
static int sigdump;
|
||||||
static int digest;
|
static int digest;
|
||||||
static int digsig;
|
static int digsig;
|
||||||
static char *keypass;
|
|
||||||
static int sigfile;
|
static int sigfile;
|
||||||
static int x509 = 1;
|
|
||||||
static char *uuid_str;
|
static char *uuid_str;
|
||||||
static char *search_type;
|
static char *search_type;
|
||||||
static int recursive;
|
static int recursive;
|
||||||
@ -110,10 +107,6 @@ static int find(const char *path, int dts, find_cb_t func);
|
|||||||
#define CHR_MASK (1 << DT_CHR)
|
#define CHR_MASK (1 << DT_CHR)
|
||||||
#define BLK_MASK (1 << DT_BLK)
|
#define BLK_MASK (1 << DT_BLK)
|
||||||
|
|
||||||
typedef int (*sign_hash_fn_t)(const char *algo, const unsigned char *hash, int size, const char *keyfile, unsigned char *sig);
|
|
||||||
|
|
||||||
static sign_hash_fn_t sign_hash;
|
|
||||||
|
|
||||||
struct command cmds[];
|
struct command cmds[];
|
||||||
static void print_usage(struct command *cmd);
|
static void print_usage(struct command *cmd);
|
||||||
|
|
||||||
@ -169,215 +162,6 @@ static unsigned char *file2bin(const char *file, const char *ext, int *size)
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Create binary key representation suitable for kernel
|
|
||||||
*/
|
|
||||||
static int key2bin(RSA *key, unsigned char *pub)
|
|
||||||
{
|
|
||||||
int len, b, offset = 0;
|
|
||||||
struct pubkey_hdr *pkh = (struct pubkey_hdr *)pub;
|
|
||||||
|
|
||||||
/* add key header */
|
|
||||||
pkh->version = 1;
|
|
||||||
pkh->timestamp = 0; /* PEM has no timestamp?? */
|
|
||||||
pkh->algo = PUBKEY_ALGO_RSA;
|
|
||||||
pkh->nmpi = 2;
|
|
||||||
|
|
||||||
offset += sizeof(*pkh);
|
|
||||||
|
|
||||||
len = BN_num_bytes(key->n);
|
|
||||||
b = BN_num_bits(key->n);
|
|
||||||
pub[offset++] = b >> 8;
|
|
||||||
pub[offset++] = b & 0xff;
|
|
||||||
BN_bn2bin(key->n, &pub[offset]);
|
|
||||||
offset += len;
|
|
||||||
|
|
||||||
len = BN_num_bytes(key->e);
|
|
||||||
b = BN_num_bits(key->e);
|
|
||||||
pub[offset++] = b >> 8;
|
|
||||||
pub[offset++] = b & 0xff;
|
|
||||||
BN_bn2bin(key->e, &pub[offset]);
|
|
||||||
offset += len;
|
|
||||||
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void calc_keyid_v1(uint8_t *keyid, char *str, const unsigned char *pkey, int len)
|
|
||||||
{
|
|
||||||
uint8_t sha1[SHA_DIGEST_LENGTH];
|
|
||||||
uint64_t id;
|
|
||||||
|
|
||||||
SHA1(pkey, len, sha1);
|
|
||||||
|
|
||||||
/* sha1[12 - 19] is exactly keyid from gpg file */
|
|
||||||
memcpy(keyid, sha1 + 12, 8);
|
|
||||||
log_debug("keyid: ");
|
|
||||||
log_debug_dump(keyid, 8);
|
|
||||||
|
|
||||||
id = __be64_to_cpup((__be64 *) keyid);
|
|
||||||
sprintf(str, "%llX", (unsigned long long)id);
|
|
||||||
log_info("keyid: %s\n", str);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void calc_keyid_v2(uint32_t *keyid, char *str, RSA *key)
|
|
||||||
{
|
|
||||||
uint8_t sha1[SHA_DIGEST_LENGTH];
|
|
||||||
unsigned char *pkey = NULL;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
len = i2d_RSAPublicKey(key, &pkey);
|
|
||||||
|
|
||||||
SHA1(pkey, len, sha1);
|
|
||||||
|
|
||||||
/* sha1[12 - 19] is exactly keyid from gpg file */
|
|
||||||
memcpy(keyid, sha1 + 16, 4);
|
|
||||||
log_debug("keyid: ");
|
|
||||||
log_debug_dump(keyid, 4);
|
|
||||||
|
|
||||||
sprintf(str, "%x", __be32_to_cpup(keyid));
|
|
||||||
log_info("keyid: %s\n", str);
|
|
||||||
|
|
||||||
free(pkey);
|
|
||||||
}
|
|
||||||
|
|
||||||
static RSA *read_priv_key(const char *keyfile)
|
|
||||||
{
|
|
||||||
FILE *fp;
|
|
||||||
RSA *key;
|
|
||||||
|
|
||||||
fp = fopen(keyfile, "r");
|
|
||||||
if (!fp) {
|
|
||||||
log_err("Unable to open keyfile %s\n", keyfile);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
key = PEM_read_RSAPrivateKey(fp, NULL, NULL, keypass);
|
|
||||||
if (!key)
|
|
||||||
log_err("PEM_read_RSAPrivateKey() failed\n");
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_hash_algo_v1(const char *algo)
|
|
||||||
{
|
|
||||||
|
|
||||||
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;
|
|
||||||
char name[20];
|
|
||||||
unsigned char sighash[20];
|
|
||||||
struct signature_hdr *hdr = (struct signature_hdr *)sig;
|
|
||||||
uint16_t *blen;
|
|
||||||
|
|
||||||
log_info("hash: ");
|
|
||||||
log_dump(hash, size);
|
|
||||||
|
|
||||||
key = read_priv_key(keyfile);
|
|
||||||
if (!key)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* now create a new hash */
|
|
||||||
hdr->version = (uint8_t) DIGSIG_VERSION_1;
|
|
||||||
hdr->timestamp = time(NULL);
|
|
||||||
hdr->algo = PUBKEY_ALGO_RSA;
|
|
||||||
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);
|
|
||||||
|
|
||||||
hdr->nmpi = 1;
|
|
||||||
|
|
||||||
SHA1_Init(&ctx);
|
|
||||||
SHA1_Update(&ctx, hash, size);
|
|
||||||
SHA1_Update(&ctx, hdr, sizeof(*hdr));
|
|
||||||
SHA1_Final(sighash, &ctx);
|
|
||||||
log_info("sighash: ");
|
|
||||||
log_dump(sighash, sizeof(sighash));
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we add bit length of the signature to make it gnupg compatible */
|
|
||||||
blen = (uint16_t *) (sig + sizeof(*hdr));
|
|
||||||
*blen = __cpu_to_be16(len << 3);
|
|
||||||
len += sizeof(*hdr) + 2;
|
|
||||||
log_info("evm/ima signature: %d bytes\n", len);
|
|
||||||
if (sigdump || params.verbose >= LOG_INFO)
|
|
||||||
dump(sig, len);
|
|
||||||
out:
|
|
||||||
RSA_free(key);
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = -1;
|
|
||||||
RSA *key;
|
|
||||||
char name[20];
|
|
||||||
unsigned char *buf;
|
|
||||||
const struct RSA_ASN1_template *asn1;
|
|
||||||
|
|
||||||
log_info("hash: ");
|
|
||||||
log_dump(hash, size);
|
|
||||||
|
|
||||||
key = read_priv_key(keyfile);
|
|
||||||
if (!key)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
hdr->version = (uint8_t) DIGSIG_VERSION_2;
|
|
||||||
hdr->hash_algo = get_hash_algo(algo);
|
|
||||||
|
|
||||||
calc_keyid_v2(&hdr->keyid, name, key);
|
|
||||||
|
|
||||||
asn1 = &RSA_ASN1_templates[hdr->hash_algo];
|
|
||||||
|
|
||||||
buf = malloc(size + asn1->size);
|
|
||||||
if (!buf)
|
|
||||||
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);
|
|
||||||
if (len < 0) {
|
|
||||||
log_err("RSA_private_encrypt() failed: %d\n", len);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we add bit length of the signature to make it gnupg compatible */
|
|
||||||
hdr->sig_size = __cpu_to_be16(len);
|
|
||||||
len += sizeof(*hdr);
|
|
||||||
log_info("evm/ima signature: %d bytes\n", len);
|
|
||||||
if (sigdump || params.verbose >= LOG_INFO)
|
|
||||||
dump(sig, len);
|
|
||||||
out:
|
|
||||||
if (buf)
|
|
||||||
free(buf);
|
|
||||||
RSA_free(key);
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int find_xattr(const char *list, int list_size, const char *xattr)
|
static int find_xattr(const char *list, int list_size, const char *xattr)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
@ -642,9 +426,15 @@ static int sign_evm(const char *file, const char *key)
|
|||||||
if (len <= 1)
|
if (len <= 1)
|
||||||
return len;
|
return len;
|
||||||
|
|
||||||
|
/* add header */
|
||||||
|
len++;
|
||||||
|
sig[0] = EVM_IMA_XATTR_DIGSIG;
|
||||||
|
|
||||||
|
if (sigdump || params.verbose >= LOG_INFO)
|
||||||
|
dump(sig, len);
|
||||||
|
|
||||||
if (xattr) {
|
if (xattr) {
|
||||||
sig[0] = EVM_IMA_XATTR_DIGSIG;
|
err = lsetxattr(file, "security.evm", sig, len, 0);
|
||||||
err = lsetxattr(file, "security.evm", sig, len + 1, 0);
|
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
log_err("setxattr failed: %s\n", file);
|
log_err("setxattr failed: %s\n", file);
|
||||||
return err;
|
return err;
|
||||||
@ -723,6 +513,9 @@ static int sign_ima(const char *file, const char *key)
|
|||||||
len++;
|
len++;
|
||||||
sig[0] = EVM_IMA_XATTR_DIGSIG;
|
sig[0] = EVM_IMA_XATTR_DIGSIG;
|
||||||
|
|
||||||
|
if (sigdump || params.verbose >= LOG_INFO)
|
||||||
|
dump(sig, len);
|
||||||
|
|
||||||
if (sigfile)
|
if (sigfile)
|
||||||
bin2file(file, "sig", sig, len);
|
bin2file(file, "sig", sig, len);
|
||||||
|
|
||||||
@ -975,8 +768,8 @@ static int cmd_import(struct command *cmd)
|
|||||||
|
|
||||||
inkey = g_argv[optind++];
|
inkey = g_argv[optind++];
|
||||||
if (!inkey) {
|
if (!inkey) {
|
||||||
inkey = x509 ? "/etc/keys/x509_evm.der" :
|
inkey = params.x509 ? "/etc/keys/x509_evm.der" :
|
||||||
"/etc/keys/pubkey_evm.pem";
|
"/etc/keys/pubkey_evm.pem";
|
||||||
} else
|
} else
|
||||||
ring = g_argv[optind++];
|
ring = g_argv[optind++];
|
||||||
|
|
||||||
@ -1004,11 +797,11 @@ static int cmd_import(struct command *cmd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
key = read_pub_key(inkey, x509);
|
key = read_pub_key(inkey, params.x509);
|
||||||
if (!key)
|
if (!key)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (x509) {
|
if (params.x509) {
|
||||||
pub = file2bin(inkey, NULL, &len);
|
pub = file2bin(inkey, NULL, &len);
|
||||||
if (!pub)
|
if (!pub)
|
||||||
goto out;
|
goto out;
|
||||||
@ -1020,7 +813,7 @@ static int cmd_import(struct command *cmd)
|
|||||||
|
|
||||||
log_info("Importing public key %s from file %s into keyring %d\n", name, inkey, id);
|
log_info("Importing public key %s from file %s into keyring %d\n", name, inkey, id);
|
||||||
|
|
||||||
id = add_key(x509 ? "asymmetric" : "user", x509 ? NULL : name, pub, len, id);
|
id = add_key(params.x509 ? "asymmetric" : "user", params.x509 ? NULL : name, pub, len, id);
|
||||||
if (id < 0) {
|
if (id < 0) {
|
||||||
log_err("add_key failed\n");
|
log_err("add_key failed\n");
|
||||||
err = id;
|
err = id;
|
||||||
@ -1028,7 +821,7 @@ static int cmd_import(struct command *cmd)
|
|||||||
log_info("keyid: %d\n", id);
|
log_info("keyid: %d\n", id);
|
||||||
printf("%d\n", id);
|
printf("%d\n", id);
|
||||||
}
|
}
|
||||||
if (x509)
|
if (params.x509)
|
||||||
free(pub);
|
free(pub);
|
||||||
out:
|
out:
|
||||||
RSA_free(key);
|
RSA_free(key);
|
||||||
@ -1734,7 +1527,7 @@ int main(int argc, char *argv[])
|
|||||||
params.hash_algo = optarg;
|
params.hash_algo = optarg;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
keypass = optarg;
|
params.keypass = optarg;
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
sigfile = 1;
|
sigfile = 1;
|
||||||
@ -1748,7 +1541,7 @@ int main(int argc, char *argv[])
|
|||||||
hmac_flags &= ~HMAC_FLAG_UUID;
|
hmac_flags &= ~HMAC_FLAG_UUID;
|
||||||
break;
|
break;
|
||||||
case '1':
|
case '1':
|
||||||
x509 = 0;
|
params.x509 = 0;
|
||||||
break;
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
params.keyfile = optarg;
|
params.keyfile = optarg;
|
||||||
@ -1773,11 +1566,6 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x509)
|
|
||||||
sign_hash = sign_hash_v2;
|
|
||||||
else
|
|
||||||
sign_hash = sign_hash_v1;
|
|
||||||
|
|
||||||
OpenSSL_add_all_algorithms();
|
OpenSSL_add_all_algorithms();
|
||||||
ERR_load_crypto_strings();
|
ERR_load_crypto_strings();
|
||||||
|
|
||||||
|
@ -170,8 +170,10 @@ typedef int (*verify_hash_fn_t)(const unsigned char *hash, int size, unsigned ch
|
|||||||
|
|
||||||
struct libevm_params {
|
struct libevm_params {
|
||||||
int verbose;
|
int verbose;
|
||||||
|
int x509;
|
||||||
const char *hash_algo;
|
const char *hash_algo;
|
||||||
char *keyfile;
|
char *keyfile;
|
||||||
|
char *keypass;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RSA_ASN1_template {
|
struct RSA_ASN1_template {
|
||||||
@ -189,6 +191,11 @@ int ima_calc_hash(const char *file, uint8_t *hash);
|
|||||||
int get_hash_algo(const char *algo);
|
int get_hash_algo(const char *algo);
|
||||||
RSA *read_pub_key(const char *keyfile, int x509);
|
RSA *read_pub_key(const char *keyfile, int x509);
|
||||||
|
|
||||||
|
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);
|
||||||
|
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 verify_hash(const unsigned char *hash, int size, unsigned char *sig, int siglen);
|
int verify_hash(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);
|
||||||
|
|
||||||
|
258
src/libimaevm.c
258
src/libimaevm.c
@ -44,6 +44,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <asm/byteorder.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -125,6 +126,7 @@ const struct RSA_ASN1_template RSA_ASN1_templates[PKEY_HASH__LAST] = {
|
|||||||
|
|
||||||
struct libevm_params params = {
|
struct libevm_params params = {
|
||||||
.verbose = LOG_INFO - 1,
|
.verbose = LOG_INFO - 1,
|
||||||
|
.x509 = 1,
|
||||||
.hash_algo = "sha1",
|
.hash_algo = "sha1",
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -533,3 +535,259 @@ int ima_verify_signature(const char *file, unsigned char *sig, int siglen)
|
|||||||
|
|
||||||
return verify_hash(hash, hashlen, sig + 1, siglen - 1);
|
return verify_hash(hash, hashlen, sig + 1, siglen - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create binary key representation suitable for kernel
|
||||||
|
*/
|
||||||
|
int key2bin(RSA *key, unsigned char *pub)
|
||||||
|
{
|
||||||
|
int len, b, offset = 0;
|
||||||
|
struct pubkey_hdr *pkh = (struct pubkey_hdr *)pub;
|
||||||
|
|
||||||
|
/* add key header */
|
||||||
|
pkh->version = 1;
|
||||||
|
pkh->timestamp = 0; /* PEM has no timestamp?? */
|
||||||
|
pkh->algo = PUBKEY_ALGO_RSA;
|
||||||
|
pkh->nmpi = 2;
|
||||||
|
|
||||||
|
offset += sizeof(*pkh);
|
||||||
|
|
||||||
|
len = BN_num_bytes(key->n);
|
||||||
|
b = BN_num_bits(key->n);
|
||||||
|
pub[offset++] = b >> 8;
|
||||||
|
pub[offset++] = b & 0xff;
|
||||||
|
BN_bn2bin(key->n, &pub[offset]);
|
||||||
|
offset += len;
|
||||||
|
|
||||||
|
len = BN_num_bytes(key->e);
|
||||||
|
b = BN_num_bits(key->e);
|
||||||
|
pub[offset++] = b >> 8;
|
||||||
|
pub[offset++] = b & 0xff;
|
||||||
|
BN_bn2bin(key->e, &pub[offset]);
|
||||||
|
offset += len;
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_keyid_v1(uint8_t *keyid, char *str, const unsigned char *pkey, int len)
|
||||||
|
{
|
||||||
|
uint8_t sha1[SHA_DIGEST_LENGTH];
|
||||||
|
uint64_t id;
|
||||||
|
|
||||||
|
SHA1(pkey, len, sha1);
|
||||||
|
|
||||||
|
/* sha1[12 - 19] is exactly keyid from gpg file */
|
||||||
|
memcpy(keyid, sha1 + 12, 8);
|
||||||
|
log_debug("keyid: ");
|
||||||
|
log_debug_dump(keyid, 8);
|
||||||
|
|
||||||
|
id = __be64_to_cpup((__be64 *) keyid);
|
||||||
|
sprintf(str, "%llX", (unsigned long long)id);
|
||||||
|
log_info("keyid: %s\n", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_keyid_v2(uint32_t *keyid, char *str, RSA *key)
|
||||||
|
{
|
||||||
|
uint8_t sha1[SHA_DIGEST_LENGTH];
|
||||||
|
unsigned char *pkey = NULL;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = i2d_RSAPublicKey(key, &pkey);
|
||||||
|
|
||||||
|
SHA1(pkey, len, sha1);
|
||||||
|
|
||||||
|
/* sha1[12 - 19] is exactly keyid from gpg file */
|
||||||
|
memcpy(keyid, sha1 + 16, 4);
|
||||||
|
log_debug("keyid: ");
|
||||||
|
log_debug_dump(keyid, 4);
|
||||||
|
|
||||||
|
sprintf(str, "%x", __be32_to_cpup(keyid));
|
||||||
|
log_info("keyid: %s\n", str);
|
||||||
|
|
||||||
|
free(pkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
static RSA *read_priv_key(const char *keyfile, char *keypass)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
RSA *key;
|
||||||
|
|
||||||
|
fp = fopen(keyfile, "r");
|
||||||
|
if (!fp) {
|
||||||
|
log_err("Unable to open keyfile %s\n", keyfile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
key = PEM_read_RSAPrivateKey(fp, NULL, NULL, keypass);
|
||||||
|
if (!key)
|
||||||
|
log_err("PEM_read_RSAPrivateKey() failed\n");
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_hash_algo_v1(const char *algo)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!strcmp(algo, "sha1"))
|
||||||
|
return DIGEST_ALGO_SHA1;
|
||||||
|
else if (!strcmp(algo, "sha256"))
|
||||||
|
return DIGEST_ALGO_SHA256;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
char name[20];
|
||||||
|
unsigned char sighash[20];
|
||||||
|
struct signature_hdr *hdr;
|
||||||
|
uint16_t *blen;
|
||||||
|
|
||||||
|
if (!hash) {
|
||||||
|
log_err("sign_hash_v1: hash is null\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size < 0) {
|
||||||
|
log_err("sign_hash_v1: size is negative: %d\n", size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hashalgo) {
|
||||||
|
log_err("sign_hash_v1: hashalgo is null\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sig) {
|
||||||
|
log_err("sign_hash_v1: sig is null\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("hash: ");
|
||||||
|
log_dump(hash, size);
|
||||||
|
|
||||||
|
key = read_priv_key(keyfile, params.keypass);
|
||||||
|
if (!key) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdr = (struct signature_hdr *)sig;
|
||||||
|
|
||||||
|
/* now create a new hash */
|
||||||
|
hdr->version = (uint8_t) DIGSIG_VERSION_1;
|
||||||
|
hdr->timestamp = time(NULL);
|
||||||
|
hdr->algo = PUBKEY_ALGO_RSA;
|
||||||
|
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);
|
||||||
|
|
||||||
|
hdr->nmpi = 1;
|
||||||
|
|
||||||
|
SHA1_Init(&ctx);
|
||||||
|
SHA1_Update(&ctx, hash, size);
|
||||||
|
SHA1_Update(&ctx, hdr, sizeof(*hdr));
|
||||||
|
SHA1_Final(sighash, &ctx);
|
||||||
|
log_info("sighash: ");
|
||||||
|
log_dump(sighash, sizeof(sighash));
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we add bit length of the signature to make it gnupg compatible */
|
||||||
|
blen = (uint16_t *) (sig + sizeof(*hdr));
|
||||||
|
*blen = __cpu_to_be16(len << 3);
|
||||||
|
len += sizeof(*hdr) + 2;
|
||||||
|
log_info("evm/ima signature: %d bytes\n", len);
|
||||||
|
out:
|
||||||
|
RSA_free(key);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sign_hash_v2(const char *algo, const unsigned char *hash, int size, const char *keyfile, unsigned char *sig)
|
||||||
|
{
|
||||||
|
struct signature_v2_hdr *hdr;
|
||||||
|
int len = -1;
|
||||||
|
RSA *key;
|
||||||
|
char name[20];
|
||||||
|
unsigned char *buf;
|
||||||
|
const struct RSA_ASN1_template *asn1;
|
||||||
|
|
||||||
|
if (!hash) {
|
||||||
|
log_err("sign_hash_v2: hash is null\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size < 0) {
|
||||||
|
log_err("sign_hash_v2: size is negative: %d\n", size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sig) {
|
||||||
|
log_err("sign_hash_v2: sig is null\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!algo) {
|
||||||
|
log_err("sign_hash_v2: algo is null\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("hash: ");
|
||||||
|
log_dump(hash, size);
|
||||||
|
|
||||||
|
key = read_priv_key(keyfile, params.keypass);
|
||||||
|
if (!key)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
hdr = (struct signature_v2_hdr *)sig;
|
||||||
|
hdr->version = (uint8_t) DIGSIG_VERSION_2;
|
||||||
|
|
||||||
|
hdr->hash_algo = get_hash_algo(algo);
|
||||||
|
|
||||||
|
calc_keyid_v2(&hdr->keyid, name, key);
|
||||||
|
|
||||||
|
asn1 = &RSA_ASN1_templates[hdr->hash_algo];
|
||||||
|
|
||||||
|
buf = malloc(size + asn1->size);
|
||||||
|
if (!buf)
|
||||||
|
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);
|
||||||
|
if (len < 0) {
|
||||||
|
log_err("RSA_private_encrypt() failed: %d\n", len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we add bit length of the signature to make it gnupg compatible */
|
||||||
|
hdr->sig_size = __cpu_to_be16(len);
|
||||||
|
len += sizeof(*hdr);
|
||||||
|
log_info("evm/ima signature: %d bytes\n", len);
|
||||||
|
out:
|
||||||
|
if (buf)
|
||||||
|
free(buf);
|
||||||
|
RSA_free(key);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sign_hash(const char *hashalgo, const unsigned char *hash, int size, const char *keyfile, unsigned char *sig)
|
||||||
|
{
|
||||||
|
return params.x509 ? sign_hash_v2(hashalgo, hash, size, keyfile, sig) :
|
||||||
|
sign_hash_v1(hashalgo, hash, size, keyfile, sig);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user