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@xxxxxxxxxxxxxxxxxx> --- README | 2 +- src/evmctl.c | 4 +++ src/imaevm.h | 1 + src/libimaevm.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 76 insertions(+), 6 deletions(-) diff --git a/README b/README index da828cf..1c4bc7a 100644 --- a/README +++ b/README @@ -31,7 +31,7 @@ COMMANDS ima_sign [--sigfile] [--key key] [--pass password] file ima_verify file ima_hash file - ima_measurement file + ima_measurement [--key "key1, key2, ..."] file ima_fix [-t fdsxm] path sign_hash [--key key] [--pass password] hmac [--imahash | --imasig ] file diff --git a/src/evmctl.c b/src/evmctl.c index 746fc09..e0ed93d 100644 --- a/src/evmctl.c +++ b/src/evmctl.c @@ -1419,6 +1419,10 @@ static int ima_measurement(const char *file) return -1; } + /* Support multiple public keys */ + if (params.keyfile) + init_public_keys(params.keyfile); + while (fread(&entry.header, sizeof(entry.header), 1, fp)) { ima_extend_pcr(pcr, entry.header.digest, SHA_DIGEST_LENGTH); diff --git a/src/imaevm.h b/src/imaevm.h index e397743..ea6a7b1 100644 --- a/src/imaevm.h +++ b/src/imaevm.h @@ -205,5 +205,6 @@ 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); 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); +void init_public_keys(const char *keyfiles); #endif diff --git a/src/libimaevm.c b/src/libimaevm.c index a92deed..0ad290a 100644 --- a/src/libimaevm.c +++ b/src/libimaevm.c @@ -408,6 +408,61 @@ int verify_hash_v1(const unsigned char *hash, int size, unsigned char *sig, int return 0; } +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 unsigned char *hash, int size, unsigned char *sig, int siglen, const char *keyfile) { int err, len; @@ -419,12 +474,22 @@ int verify_hash_v2(const unsigned char *hash, int size, unsigned char *sig, int log_info("hash: "); log_dump(hash, size); - key = read_pub_key(keyfile, 1); - if (!key) - return 1; + if (public_keys) { + key = find_keyid(hdr->keyid); + if (!key) { + log_err("Unknown keyid: %x\n", + __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) { log_err("RSA_public_decrypt() failed: %d\n", err); return 1; -- 2.7.4