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:
parent
b929aaa655
commit
4e89b9a1ee
4 changed files with 77 additions and 5 deletions
2
Makefile
2
Makefile
|
@ -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
48
idc.c
|
@ -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
1
idc.h
|
@ -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 */
|
||||||
|
|
||||||
|
|
31
sbverify.c
31
sbverify.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue