sbverify: Add check for image hash

Add a check to match the calculated image's hash against the one found
in the PKCS7 IndirectDataContext

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
This commit is contained in:
Jeremy Kerr 2012-05-12 21:21:20 -07:00
parent b929aaa655
commit 4e89b9a1ee
4 changed files with 77 additions and 5 deletions

View file

@ -5,7 +5,7 @@ CFLAGS = -Wall -Werror -Wextra -ggdb --std=c99
LDFLAGS = -fwhole-program LDFLAGS = -fwhole-program
sbsign_objs = sbsign.o idc.o image.o 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 libs = -lbfd -lcrypto
ccan_objs = lib/ccan/libccan.a ccan_objs = lib/ccan/libccan.a

48
idc.c
View file

@ -17,6 +17,7 @@
* USA. * USA.
*/ */
#include <stdint.h> #include <stdint.h>
#include <string.h>
#include <openssl/asn1t.h> #include <openssl/asn1t.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/err.h> #include <openssl/err.h>
@ -132,6 +133,17 @@ const char obsolete[] = {
0x00, 0x65, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e 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) int IDC_set(PKCS7 *p7, PKCS7_SIGNER_INFO *si, struct image *image)
{ {
uint8_t *buf, *tmp, sha[SHA256_DIGEST_LENGTH]; 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; 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;
}

1
idc.h
View file

@ -24,6 +24,7 @@
#include <openssl/pkcs7.h> #include <openssl/pkcs7.h>
int IDC_set(PKCS7 *p7, PKCS7_SIGNER_INFO *si, struct image *image); int IDC_set(PKCS7 *p7, PKCS7_SIGNER_INFO *si, struct image *image);
int IDC_check_hash(struct image *image, PKCS7 *p7);
#endif /* IDC_H */ #endif /* IDC_H */

View file

@ -20,17 +20,25 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <ccan/talloc/talloc.h>
#include "image.h" #include "image.h"
#include "idc.h"
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/bio.h> #include <openssl/bio.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/pkcs7.h> #include <openssl/pkcs7.h>
enum verify_status {
VERIFY_FAIL = 0,
VERIFY_OK = 1,
};
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct cert_table_header *header; struct cert_table_header *header;
enum verify_status status;
struct image *image; struct image *image;
uint8_t *idcbuf, tmp; uint8_t *idcbuf, tmp;
const uint8_t *buf; const uint8_t *buf;
@ -38,6 +46,8 @@ int main(int argc, char **argv)
BIO *idcbio; BIO *idcbio;
PKCS7 *p7; PKCS7 *p7;
status = VERIFY_FAIL;
if (argc != 2) { if (argc != 2) {
fprintf(stderr, "usage: %s <boot-image>\n", argv[0]); fprintf(stderr, "usage: %s <boot-image>\n", argv[0]);
return EXIT_FAILURE; return EXIT_FAILURE;
@ -45,11 +55,12 @@ int main(int argc, char **argv)
image = image_load(argv[1]); image = image_load(argv[1]);
image_pecoff_parse(image); image_pecoff_parse(image);
image_find_regions(image);
if (!image->data_dir_sigtable->addr if (!image->data_dir_sigtable->addr
|| !image->data_dir_sigtable->size) { || !image->data_dir_sigtable->size) {
fprintf(stderr, "No signature table present\n"); fprintf(stderr, "No signature table present\n");
return EXIT_FAILURE; goto out;
} }
header = image->buf + image->data_dir_sigtable->addr; header = image->buf + image->data_dir_sigtable->addr;
@ -59,6 +70,10 @@ int main(int argc, char **argv)
buf = (void *)(header + 1); buf = (void *)(header + 1);
p7 = d2i_PKCS7(NULL, &buf, header->size); 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; idcbuf = p7->d.sign->contents->d.other->value.asn1_string->data;
/* we don't include the type and length data in the hash */ /* we don't include the type and length data in the hash */
@ -81,9 +96,17 @@ int main(int argc, char **argv)
if (!rc) { if (!rc) {
printf("PKCS7 verification failed\n"); printf("PKCS7 verification failed\n");
ERR_print_errors_fp(stderr); ERR_print_errors_fp(stderr);
} else { goto out;
printf("Signature verification OK\n");
} }
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;
} }