@@ -891,7 +891,6 @@ static int cmd_import(struct command *cmd)
int id, len, err = 0;
char name[20];
uint8_t keyid[8];
- RSA *key;
inkey = g_argv[optind++];
if (!inkey) {
@@ -925,18 +924,26 @@ static int cmd_import(struct command *cmd)
}
}
- key = read_pub_key(inkey, params.x509);
- if (!key)
- return 1;
-
if (params.x509) {
+ EVP_PKEY *pkey = read_pub_pkey(inkey, params.x509);
+
+ if (!pkey)
+ return 1;
pub = file2bin(inkey, NULL, &len);
- if (!pub)
- goto out;
- calc_keyid_v2((uint32_t *)keyid, name, key);
+ if (!pub) {
+ EVP_PKEY_free(pkey);
+ return 1;
+ }
+ calc_keyid_v2((uint32_t *)keyid, name, pkey);
+ EVP_PKEY_free(pkey);
} else {
+ RSA *key = read_pub_key(inkey, params.x509);
+
+ if (!key)
+ return 1;
len = key2bin(key, pub);
calc_keyid_v1(keyid, name, pub, len);
+ RSA_free(key);
}
log_info("Importing public key %s from file %s into keyring %d\n", name, inkey, id);
@@ -951,8 +958,6 @@ static int cmd_import(struct command *cmd)
}
if (params.x509)
free(pub);
-out:
- RSA_free(key);
return err;
}
@@ -219,7 +219,7 @@ RSA *read_pub_key(const char *keyfile, int x509);
EVP_PKEY *read_pub_pkey(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);
+void calc_keyid_v2(uint32_t *keyid, char *str, EVP_PKEY *key);
int key2bin(RSA *key, unsigned char *pub);
int sign_hash(const char *algo, const unsigned char *hash, int size, const char *keyfile, const char *keypass, unsigned char *sig);
@@ -452,11 +452,11 @@ struct public_key_entry {
struct public_key_entry *next;
uint32_t keyid;
char name[9];
- RSA *key;
+ EVP_PKEY *key;
};
static struct public_key_entry *public_keys = NULL;
-static RSA *find_keyid(uint32_t keyid)
+static EVP_PKEY *find_keyid(uint32_t keyid)
{
struct public_key_entry *entry;
@@ -489,7 +489,7 @@ void init_public_keys(const char *keyfiles)
break;
}
- entry->key = read_pub_key(keyfile, 1);
+ entry->key = read_pub_pkey(keyfile, 1);
if (!entry->key) {
free(entry);
continue;
@@ -506,11 +506,11 @@ void init_public_keys(const char *keyfiles)
int verify_hash_v2(const char *file, const unsigned char *hash, int size,
unsigned char *sig, int siglen, const char *keyfile)
{
- int err, len;
- unsigned char out[1024];
- RSA *key;
+ int err;
+ EVP_PKEY *pkey;
struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
- const struct RSA_ASN1_template *asn1;
+ EVP_PKEY_CTX *ctx;
+ const EVP_MD *md;
if (params.verbose > LOG_INFO) {
log_info("hash: ");
@@ -518,45 +518,39 @@ int verify_hash_v2(const char *file, const unsigned char *hash, int size,
}
if (public_keys) {
- key = find_keyid(hdr->keyid);
- if (!key) {
+ pkey = find_keyid(hdr->keyid);
+ if (!pkey) {
log_err("%s: unknown keyid: %x\n", file,
__be32_to_cpup(&hdr->keyid));
return -1;
}
} else {
- key = read_pub_key(keyfile, 1);
- if (!key)
+ pkey = read_pub_pkey(keyfile, 1);
+ if (!pkey)
return 1;
}
+ if (!(ctx = EVP_PKEY_CTX_new(pkey, NULL)))
+ goto err;
+ if (!EVP_PKEY_verify_init(ctx))
+ goto err;
+ if (!(md = EVP_get_digestbyname(params.hash_algo)))
+ goto err;
+ if (!EVP_PKEY_CTX_set_signature_md(ctx, md))
+ goto err;
+ err = EVP_PKEY_verify(ctx, sig + sizeof(*hdr),
+ siglen - sizeof(*hdr), hash, size);
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(pkey);
- err = RSA_public_decrypt(siglen - sizeof(*hdr), sig + sizeof(*hdr),
- out, key, RSA_PKCS1_PADDING);
- if (err < 0) {
- log_err("%s: RSA_public_decrypt() failed: %d\n", file, err);
- return 1;
- }
-
- len = err;
-
- asn1 = &RSA_ASN1_templates[hdr->hash_algo];
-
- if (len < asn1->size || memcmp(out, asn1->data, asn1->size)) {
- log_err("%s: verification failed: %d (asn1 mismatch)\n",
- file, err);
- return -1;
- }
-
- len -= asn1->size;
-
- if (len != size || memcmp(out + asn1->size, hash, len)) {
- log_err("%s: verification failed: %d (digest mismatch)\n",
- file, err);
- return -1;
- }
-
- return 0;
+ return err != 1;
+err:
+#ifdef USE_FPRINTF
+ ERR_print_errors_fp(stderr);
+#endif
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(pkey);
+ return -1;
}
int get_hash_algo(const char *algo)
@@ -731,16 +725,25 @@ void calc_keyid_v1(uint8_t *keyid, char *str, const unsigned char *pkey, int len
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, EVP_PKEY *key)
{
+ X509_PUBKEY *pk = NULL;
uint8_t sha1[SHA_DIGEST_LENGTH];
- unsigned char *pkey = NULL;
+ const unsigned char *pkey = NULL;
int len;
- len = i2d_RSAPublicKey(key, &pkey);
-
+ /* This is more general than i2d_PublicKey() */
+ if (!X509_PUBKEY_set(&pk, key) ||
+ !X509_PUBKEY_get0_param(NULL, &pkey, &len, NULL, pk) ||
+ len <= 0) {
+#ifdef USE_FPRINTF
+ ERR_print_errors_fp(stderr);
+#endif
+ /* Produce invalid keyid in case of error. */
+ *keyid = 0;
+ return;
+ }
SHA1(pkey, len, sha1);
-
/* sha1[12 - 19] is exactly keyid from gpg file */
memcpy(keyid, sha1 + 16, 4);
log_debug("keyid: ");
@@ -750,7 +753,7 @@ void calc_keyid_v2(uint32_t *keyid, char *str, RSA *key)
if (params.verbose > LOG_INFO)
log_info("keyid: %s\n", str);
- free(pkey);
+ X509_PUBKEY_free(pk);
}
static EVP_PKEY *read_priv_pkey(const char *keyfile, const char *keypass)
@@ -889,14 +892,16 @@ out:
return len;
}
+/* @sig is assumed to be of MAX_SIGNATURE_SIZE size */
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;
+ EVP_PKEY *pkey;
char name[20];
- unsigned char *buf;
- const struct RSA_ASN1_template *asn1;
+ EVP_PKEY_CTX *ctx = NULL;
+ const EVP_MD *md;
+ size_t sigsize;
if (!hash) {
log_err("sign_hash_v2: hash is null\n");
@@ -921,8 +926,8 @@ int sign_hash_v2(const char *algo, const unsigned char *hash, int size, const ch
log_info("hash: ");
log_dump(hash, size);
- key = read_priv_key(keyfile, params.keypass);
- if (!key)
+ pkey = read_priv_pkey(keyfile, params.keypass);
+ if (!pkey)
return -1;
hdr = (struct signature_v2_hdr *)sig;
@@ -930,32 +935,36 @@ int sign_hash_v2(const char *algo, const unsigned char *hash, int size, const ch
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;
- }
+ calc_keyid_v2(&hdr->keyid, name, pkey);
+
+ if (!(ctx = EVP_PKEY_CTX_new(pkey, NULL)))
+ goto err;
+ if (!EVP_PKEY_sign_init(ctx))
+ goto err;
+ if (!(md = EVP_get_digestbyname(params.hash_algo)))
+ goto err;
+ if (!EVP_PKEY_CTX_set_signature_md(ctx, md))
+ goto err;
+ sigsize = MAX_SIGNATURE_SIZE - sizeof(struct signature_v2_hdr);
+ if (!EVP_PKEY_sign(ctx, hdr->sig, &sigsize, hash, size))
+ goto err;
+ len = (int)sigsize;
/* 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);
+
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(pkey);
return len;
+err:
+#ifdef USE_FPRINTF
+ ERR_print_errors_fp(stderr);
+#endif
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(pkey);
+ return -1;
}
Convert sign_v2 and related to using more generic EVP_PKEY API instead of RSA API. This enables more signatures to work out of the box. Signed-off-by: Vitaly Chikunov <vt@altlinux.org> --- src/evmctl.c | 25 ++++++---- src/imaevm.h | 2 +- src/libimaevm.c | 145 ++++++++++++++++++++++++++++++-------------------------- 3 files changed, 93 insertions(+), 79 deletions(-)