diff --git a/Makefile b/Makefile index 48403e8..807c9fb 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ CFLAGS = -Wall -Werror -Wextra -ggdb --std=c99 LDFLAGS = -fwhole-program sbsign_objs = sbsign.o idc.o image.o -sbverify_objs = sbverify.o image.o +sbverify_objs = sbverify.o idc.o image.o libs = -lbfd -lcrypto ccan_objs = lib/ccan/libccan.a diff --git a/idc.c b/idc.c index a578ee9..0e49b66 100644 --- a/idc.c +++ b/idc.c @@ -17,6 +17,7 @@ * USA. */ #include +#include #include #include #include @@ -132,6 +133,17 @@ const char obsolete[] = { 0x00, 0x65, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e }; +const char *sha256_str(const uint8_t *hash) +{ + static char s[SHA256_DIGEST_LENGTH * 2 + 1]; + int i; + + for (i = 0; i < SHA256_DIGEST_LENGTH; i++) + snprintf(s + i * 2, 3, "%02x", hash[i]); + + return s; +} + int IDC_set(PKCS7 *p7, PKCS7_SIGNER_INFO *si, struct image *image) { uint8_t *buf, *tmp, sha[SHA256_DIGEST_LENGTH]; @@ -205,4 +217,40 @@ int IDC_set(PKCS7 *p7, PKCS7_SIGNER_INFO *si, struct image *image) return 0; } +int IDC_check_hash(struct image *image, PKCS7 *p7) +{ + unsigned char sha[SHA256_DIGEST_LENGTH]; + const unsigned char *buf; + ASN1_STRING *str; + IDC *idc; + image_hash_sha256(image, sha); + + /* extract the idc from the signed PKCS7 'other' data */ + str = p7->d.sign->contents->d.other->value.asn1_string; + buf = ASN1_STRING_data(str); + idc = d2i_IDC(NULL, &buf, ASN1_STRING_length(str)); + + /* check hash algorithm sanity */ + if (OBJ_cmp(idc->digest->alg->algorithm, OBJ_nid2obj(NID_sha256))) { + fprintf(stderr, "Invalid algorithm type\n"); + return -1; + } + + str = idc->digest->digest; + if (ASN1_STRING_length(str) != sizeof(sha)) { + fprintf(stderr, "Invalid algorithm length\n"); + return -1; + } + + /* check hash against the one we calculated from the image */ + buf = ASN1_STRING_data(str); + if (memcmp(buf, sha, sizeof(sha))) { + fprintf(stderr, "Hash doesn't match image\n"); + fprintf(stderr, " got: %s\n", sha256_str(buf)); + fprintf(stderr, " expecting: %s\n", sha256_str(sha)); + return -1; + } + + return 0; +} diff --git a/idc.h b/idc.h index 9d35530..ecd6b97 100644 --- a/idc.h +++ b/idc.h @@ -24,6 +24,7 @@ #include int IDC_set(PKCS7 *p7, PKCS7_SIGNER_INFO *si, struct image *image); +int IDC_check_hash(struct image *image, PKCS7 *p7); #endif /* IDC_H */ diff --git a/sbverify.c b/sbverify.c index c72888f..90e18cd 100644 --- a/sbverify.c +++ b/sbverify.c @@ -20,17 +20,25 @@ #include #include +#include + #include "image.h" +#include "idc.h" #include #include #include #include +enum verify_status { + VERIFY_FAIL = 0, + VERIFY_OK = 1, +}; int main(int argc, char **argv) { struct cert_table_header *header; + enum verify_status status; struct image *image; uint8_t *idcbuf, tmp; const uint8_t *buf; @@ -38,6 +46,8 @@ int main(int argc, char **argv) BIO *idcbio; PKCS7 *p7; + status = VERIFY_FAIL; + if (argc != 2) { fprintf(stderr, "usage: %s \n", argv[0]); return EXIT_FAILURE; @@ -45,11 +55,12 @@ int main(int argc, char **argv) image = image_load(argv[1]); image_pecoff_parse(image); + image_find_regions(image); if (!image->data_dir_sigtable->addr || !image->data_dir_sigtable->size) { fprintf(stderr, "No signature table present\n"); - return EXIT_FAILURE; + goto out; } header = image->buf + image->data_dir_sigtable->addr; @@ -59,6 +70,10 @@ int main(int argc, char **argv) buf = (void *)(header + 1); p7 = d2i_PKCS7(NULL, &buf, header->size); + rc = IDC_check_hash(image, p7); + if (rc) + goto out; + idcbuf = p7->d.sign->contents->d.other->value.asn1_string->data; /* we don't include the type and length data in the hash */ @@ -81,9 +96,17 @@ int main(int argc, char **argv) if (!rc) { printf("PKCS7 verification failed\n"); ERR_print_errors_fp(stderr); - } else { - printf("Signature verification OK\n"); + goto out; } - return rc ? EXIT_SUCCESS : EXIT_FAILURE; + status = VERIFY_OK; + +out: + talloc_free(image); + if (status == VERIFY_OK) + printf("Signature verification OK\n"); + else + printf("Signature verification failed\n"); + + return status == VERIFY_OK ? EXIT_SUCCESS : EXIT_FAILURE; }