123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- /* Copyright (c) 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * Unit tests
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "bdb.h"
- #include "host.h"
- #define TEST_EQ(got, want) test_eq(got, want, #got, #want, __LINE__)
- void test_eq(int got, int want, const char *gotstr, const char *wantstr,
- int line)
- {
- if (got == want)
- return;
- fprintf(stderr, "Fail(%d): %s != %s\n"
- "got: 0x%08x (%d)\n"
- "wanted: 0x%08x (%d)\n",
- line, gotstr, wantstr, got, got, want, want);
- exit(1);
- }
- void check_header_tests(void)
- {
- struct bdb_header sgood = {
- .struct_magic = BDB_HEADER_MAGIC,
- .struct_major_version = BDB_HEADER_VERSION_MAJOR,
- .struct_minor_version = BDB_HEADER_VERSION_MINOR,
- .struct_size = sizeof(struct bdb_header),
- .bdb_load_address = -1,
- .bdb_size = 1024,
- .signed_size = 512,
- .oem_area_0_size = 256,
- };
- const size_t ssize = sgood.struct_size;
- struct bdb_header s;
- s = sgood;
- TEST_EQ(bdb_check_header(&s, ssize), BDB_SUCCESS);
- TEST_EQ(bdb_check_header(&s, ssize - 1), BDB_ERROR_BUF_SIZE);
- s = sgood;
- s.struct_size++;
- TEST_EQ(bdb_check_header(&s, ssize), BDB_ERROR_BUF_SIZE);
- s = sgood;
- s.struct_size--;
- TEST_EQ(bdb_check_header(&s, ssize), BDB_ERROR_STRUCT_SIZE);
- s = sgood;
- s.struct_magic++;
- TEST_EQ(bdb_check_header(&s, ssize), BDB_ERROR_STRUCT_MAGIC);
- s = sgood;
- s.struct_major_version++;
- TEST_EQ(bdb_check_header(&s, ssize), BDB_ERROR_STRUCT_VERSION);
- s = sgood;
- s.oem_area_0_size++;
- TEST_EQ(bdb_check_header(&s, ssize), BDB_ERROR_OEM_AREA_SIZE);
- s = sgood;
- s.bdb_size = ssize - 1;
- TEST_EQ(bdb_check_header(&s, ssize), BDB_ERROR_BDB_SIZE);
- }
- void check_key_tests(void)
- {
- struct bdb_key sgood = {
- .struct_magic = BDB_KEY_MAGIC,
- .struct_major_version = BDB_KEY_VERSION_MAJOR,
- .struct_minor_version = BDB_KEY_VERSION_MINOR,
- .struct_size = (sizeof(struct bdb_key) +
- BDB_RSA4096_KEY_DATA_SIZE),
- .hash_alg = BDB_HASH_ALG_SHA256,
- .sig_alg = BDB_SIG_ALG_RSA4096,
- .key_version = 1,
- .description = "Test key",
- };
- const size_t ssize = sgood.struct_size;
- struct bdb_key s;
- s = sgood;
- TEST_EQ(bdb_check_key(&s, ssize), BDB_SUCCESS);
- TEST_EQ(bdb_check_key(&s, ssize - 1), BDB_ERROR_BUF_SIZE);
- s = sgood;
- s.struct_size++;
- TEST_EQ(bdb_check_key(&s, ssize), BDB_ERROR_BUF_SIZE);
- s = sgood;
- s.struct_size--;
- TEST_EQ(bdb_check_key(&s, ssize), BDB_ERROR_STRUCT_SIZE);
- s = sgood;
- s.struct_magic++;
- TEST_EQ(bdb_check_key(&s, ssize), BDB_ERROR_STRUCT_MAGIC);
- s = sgood;
- s.struct_major_version++;
- TEST_EQ(bdb_check_key(&s, ssize), BDB_ERROR_STRUCT_VERSION);
- /* Description must contain a null */
- s = sgood;
- memset(s.description, 'x', sizeof(s.description));
- TEST_EQ(bdb_check_key(&s, ssize), BDB_ERROR_DESCRIPTION);
- /* Data AFTER the null is explicitly allowed, though */
- s = sgood;
- s.description[100] = 'x';
- TEST_EQ(bdb_check_key(&s, ssize), BDB_SUCCESS);
- /* Limited algorithm choices at present */
- s = sgood;
- s.hash_alg = BDB_HASH_ALG_INVALID;
- TEST_EQ(bdb_check_key(&s, ssize), BDB_ERROR_HASH_ALG);
- /* This works because ECDSA521 signatures are smaller than RSA4096 */
- s = sgood;
- s.sig_alg = BDB_SIG_ALG_ECSDSA521;
- TEST_EQ(bdb_check_key(&s, ssize), BDB_SUCCESS);
- s = sgood;
- s.sig_alg = BDB_SIG_ALG_INVALID;
- TEST_EQ(bdb_check_key(&s, ssize), BDB_ERROR_SIG_ALG);
- }
- void check_sig_tests(void)
- {
- struct bdb_sig sgood = {
- .struct_magic = BDB_SIG_MAGIC,
- .struct_major_version = BDB_SIG_VERSION_MAJOR,
- .struct_minor_version = BDB_SIG_VERSION_MINOR,
- .struct_size = sizeof(struct bdb_sig) + BDB_RSA4096_SIG_SIZE,
- .hash_alg = BDB_HASH_ALG_SHA256,
- .sig_alg = BDB_SIG_ALG_RSA4096,
- .signed_size = 123,
- .description = "Test sig",
- };
- const size_t ssize = sgood.struct_size;
- struct bdb_sig s;
- s = sgood;
- TEST_EQ(bdb_check_sig(&s, ssize), BDB_SUCCESS);
- TEST_EQ(bdb_check_sig(&s, ssize - 1), BDB_ERROR_BUF_SIZE);
- s = sgood;
- s.struct_size++;
- TEST_EQ(bdb_check_sig(&s, ssize), BDB_ERROR_BUF_SIZE);
- s = sgood;
- s.struct_size--;
- TEST_EQ(bdb_check_sig(&s, ssize), BDB_ERROR_STRUCT_SIZE);
- s = sgood;
- s.struct_magic++;
- TEST_EQ(bdb_check_sig(&s, ssize), BDB_ERROR_STRUCT_MAGIC);
- s = sgood;
- s.struct_major_version++;
- TEST_EQ(bdb_check_sig(&s, ssize), BDB_ERROR_STRUCT_VERSION);
- /* Description must contain a null */
- s = sgood;
- memset(s.description, 'x', sizeof(s.description));
- TEST_EQ(bdb_check_sig(&s, ssize), BDB_ERROR_DESCRIPTION);
- /* Data AFTER the null is explicitly allowed, though */
- s = sgood;
- s.description[100] = 'x';
- TEST_EQ(bdb_check_sig(&s, ssize), BDB_SUCCESS);
- /* Limited algorithm choices at present */
- s = sgood;
- s.hash_alg = BDB_HASH_ALG_INVALID;
- TEST_EQ(bdb_check_sig(&s, ssize), BDB_ERROR_HASH_ALG);
- /* This works because ECDSA521 signatures are smaller than RSA4096 */
- s = sgood;
- s.sig_alg = BDB_SIG_ALG_ECSDSA521;
- TEST_EQ(bdb_check_sig(&s, ssize), BDB_SUCCESS);
- s = sgood;
- s.sig_alg = BDB_SIG_ALG_INVALID;
- TEST_EQ(bdb_check_sig(&s, ssize), BDB_ERROR_SIG_ALG);
- }
- void check_data_tests(void)
- {
- struct bdb_data sgood = {
- .struct_magic = BDB_DATA_MAGIC,
- .struct_major_version = BDB_DATA_VERSION_MAJOR,
- .struct_minor_version = BDB_DATA_VERSION_MINOR,
- .struct_size = sizeof(struct bdb_data),
- .data_version = 1,
- .oem_area_1_size = 256,
- .num_hashes = 3,
- .hash_entry_size = sizeof(struct bdb_hash),
- .signed_size = 2048,
- .description = "Test data",
- };
- const size_t ssize = sgood.signed_size;
- struct bdb_data s;
- s = sgood;
- TEST_EQ(bdb_check_data(&s, ssize), BDB_SUCCESS);
- TEST_EQ(bdb_check_data(&s, ssize - 1), BDB_ERROR_BUF_SIZE);
- s = sgood;
- s.struct_size--;
- TEST_EQ(bdb_check_data(&s, ssize), BDB_ERROR_STRUCT_SIZE);
- s = sgood;
- s.struct_magic++;
- TEST_EQ(bdb_check_data(&s, ssize), BDB_ERROR_STRUCT_MAGIC);
- s = sgood;
- s.struct_major_version++;
- TEST_EQ(bdb_check_data(&s, ssize), BDB_ERROR_STRUCT_VERSION);
- /* Description must contain a null */
- s = sgood;
- memset(s.description, 'x', sizeof(s.description));
- TEST_EQ(bdb_check_data(&s, ssize), BDB_ERROR_DESCRIPTION);
- /* Data AFTER the null is explicitly allowed, though */
- s = sgood;
- s.description[100] = 'x';
- TEST_EQ(bdb_check_data(&s, ssize), BDB_SUCCESS);
- s = sgood;
- s.hash_entry_size--;
- TEST_EQ(bdb_check_data(&s, ssize), BDB_ERROR_HASH_ENTRY_SIZE);
- s = sgood;
- s.oem_area_1_size++;
- TEST_EQ(bdb_check_data(&s, ssize), BDB_ERROR_OEM_AREA_SIZE);
- /* Check exact size needed */
- s = sgood;
- s.signed_size = sizeof(s) + s.num_hashes * sizeof(struct bdb_hash) +
- s.oem_area_1_size;
- TEST_EQ(bdb_check_data(&s, ssize), BDB_SUCCESS);
- s.signed_size--;
- TEST_EQ(bdb_check_data(&s, ssize), BDB_ERROR_SIGNED_SIZE);
- /*
- * TODO: Verify wraparound check works. That can only be tested on a
- * platform where size_t is uint32_t, because otherwise a 32-bit
- * oem_area_1_size can't cause wraparound.
- */
- }
- /**
- * Test bdb_verify() and bdb_create()
- */
- void check_bdb_verify(void)
- {
- uint8_t oem_area_0[32] = "Some OEM area.";
- uint8_t oem_area_1[64] = "Some other OEM area.";
- struct bdb_hash hash[2] = {
- {
- .offset = 0x10000,
- .size = 0x18000,
- .partition = 1,
- .type = BDB_DATA_SP_RW,
- .load_address = 0x100000,
- .digest = {0x11, 0x11, 0x11, 0x10},
- },
- {
- .offset = 0x28000,
- .size = 0x20000,
- .partition = 1,
- .type = BDB_DATA_AP_RW,
- .load_address = 0x200000,
- .digest = {0x22, 0x22, 0x22, 0x20},
- },
- };
- struct bdb_create_params p = {
- .bdb_load_address = 0x11223344,
- .oem_area_0 = oem_area_0,
- .oem_area_0_size = sizeof(oem_area_0),
- .oem_area_1 = oem_area_1,
- .oem_area_1_size = sizeof(oem_area_1),
- .header_sig_description = "The header sig",
- .data_sig_description = "The data sig",
- .data_description = "Test BDB data",
- .data_version = 3,
- .hash = hash,
- .num_hashes = 2,
- };
- uint8_t bdbkey_digest[BDB_SHA256_DIGEST_SIZE];
- struct bdb_header *hgood, *h;
- size_t hsize;
- /* Load keys */
- p.bdbkey = bdb_create_key("testkeys/bdbkey.keyb", 100, "BDB key");
- p.subkey = bdb_create_key("testkeys/subkey.keyb", 200, "Subkey");
- p.private_bdbkey = read_pem("testkeys/bdbkey.pem");
- p.private_subkey = read_pem("testkeys/subkey.pem");
- if (!p.bdbkey || !p.subkey || !p.private_bdbkey || !p.private_subkey) {
- fprintf(stderr, "Unable to load test keys\n");
- exit(2);
- }
- bdb_sha256(bdbkey_digest, p.bdbkey, p.bdbkey->struct_size);
- /* Create the test BDB */
- hgood = bdb_create(&p);
- if (!hgood) {
- fprintf(stderr, "Unable to create test BDB\n");
- exit(2);
- }
- hsize = hgood->bdb_size;
- /* Allocate a copy we can mangle */
- h = calloc(hsize, 1);
- /* As created, it should pass */
- memcpy(h, hgood, hsize);
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_SUCCESS);
- /* Mangle each component in turn */
- memcpy(h, hgood, hsize);
- h->struct_magic++;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_HEADER);
- memcpy(h, hgood, hsize);
- ((struct bdb_key *)bdb_get_bdbkey(h))->struct_magic++;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_BDBKEY);
- memcpy(h, hgood, hsize);
- ((struct bdb_key *)bdb_get_bdbkey(h))->key_version++;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_GOOD_OTHER_THAN_KEY);
- memcpy(h, hgood, hsize);
- h->oem_area_0_size += hsize;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_OEM_AREA_0);
- memcpy(h, hgood, hsize);
- ((struct bdb_key *)bdb_get_subkey(h))->struct_magic++;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_SUBKEY);
- memcpy(h, hgood, hsize);
- ((struct bdb_key *)bdb_get_subkey(h))->struct_size += 4;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_BDB_SIGNED_SIZE);
- memcpy(h, hgood, hsize);
- ((struct bdb_sig *)bdb_get_header_sig(h))->struct_magic++;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_HEADER_SIG);
- memcpy(h, hgood, hsize);
- ((struct bdb_sig *)bdb_get_header_sig(h))->signed_size--;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_HEADER_SIG);
- memcpy(h, hgood, hsize);
- ((struct bdb_sig *)bdb_get_header_sig(h))->sig_data[0] ^= 0x42;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_HEADER_SIG);
- /* Also make sure the header sig really covers all the fields */
- memcpy(h, hgood, hsize);
- ((struct bdb_key *)bdb_get_subkey(h))->key_version++;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_HEADER_SIG);
- memcpy(h, hgood, hsize);
- ((uint8_t *)bdb_get_oem_area_0(h))[0] ^= 0x42;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_HEADER_SIG);
- memcpy(h, hgood, hsize);
- ((uint8_t *)bdb_get_oem_area_0(h))[p.oem_area_0_size - 1] ^= 0x24;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_HEADER_SIG);
- /* Check data header */
- memcpy(h, hgood, hsize);
- ((struct bdb_data *)bdb_get_data(h))->struct_magic++;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA);
- memcpy(h, hgood, hsize);
- ((struct bdb_sig *)bdb_get_data_sig(h))->struct_magic++;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA_SIG);
- memcpy(h, hgood, hsize);
- ((struct bdb_sig *)bdb_get_data_sig(h))->signed_size--;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA_SIG);
- memcpy(h, hgood, hsize);
- ((struct bdb_sig *)bdb_get_data_sig(h))->sig_data[0] ^= 0x42;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA_SIG);
- /* Also make sure the data sig really covers all the fields */
- memcpy(h, hgood, hsize);
- ((struct bdb_data *)bdb_get_data(h))->data_version--;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA_SIG);
- memcpy(h, hgood, hsize);
- ((uint8_t *)bdb_get_oem_area_1(h))[0] ^= 0x42;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA_SIG);
- memcpy(h, hgood, hsize);
- ((uint8_t *)bdb_get_oem_area_1(h))[p.oem_area_1_size - 1] ^= 0x24;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA_SIG);
- memcpy(h, hgood, hsize);
- ((struct bdb_hash *)bdb_get_hash(h, BDB_DATA_SP_RW))->offset++;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA_SIG);
- memcpy(h, hgood, hsize);
- ((struct bdb_hash *)bdb_get_hash(h, BDB_DATA_AP_RW))->digest[0] ^= 0x96;
- TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA_SIG);
- /*
- * This is also a convenient place to test that all the parameters we
- * fed into bdb_create() also worked. That also tests all the
- * bdb_get_*() functions.
- */
- memcpy(h, hgood, hsize);
- TEST_EQ(h->bdb_load_address, p.bdb_load_address);
- TEST_EQ(strcmp(bdb_get_bdbkey(h)->description,
- p.bdbkey->description), 0);
- TEST_EQ(bdb_get_bdbkey(h)->key_version, p.bdbkey->key_version);
- TEST_EQ(h->oem_area_0_size, p.oem_area_0_size);
- TEST_EQ(memcmp(bdb_get_oem_area_0(h), oem_area_0, sizeof(oem_area_0)),
- 0);
- TEST_EQ(strcmp(bdb_get_subkey(h)->description, p.subkey->description),
- 0);
- TEST_EQ(bdb_get_subkey(h)->key_version, p.subkey->key_version);
- TEST_EQ(strcmp(bdb_get_header_sig(h)->description,
- p.header_sig_description), 0);
- TEST_EQ(strcmp(bdb_get_data(h)->description, p.data_description), 0);
- TEST_EQ(bdb_get_data(h)->data_version, p.data_version);
- TEST_EQ(bdb_get_data(h)->num_hashes, p.num_hashes);
- TEST_EQ(bdb_get_data(h)->oem_area_1_size, p.oem_area_1_size);
- TEST_EQ(memcmp(bdb_get_oem_area_1(h), oem_area_1, sizeof(oem_area_1)),
- 0);
- TEST_EQ(strcmp(bdb_get_data_sig(h)->description,
- p.data_sig_description), 0);
- /* Test getting hash entries */
- memcpy(h, hgood, hsize);
- TEST_EQ(bdb_get_hash(h, BDB_DATA_SP_RW)->offset, hash[0].offset);
- TEST_EQ(bdb_get_hash(h, BDB_DATA_AP_RW)->offset, hash[1].offset);
- /* And a non-existent one */
- TEST_EQ(bdb_get_hash(h, BDB_DATA_MCU)!=NULL, 0);
- /*
- * TODO: Verify wraparound checks works. That can only be tested on a
- * platform where size_t is uint32_t, because otherwise a 32-bit
- * oem_area_1_size can't cause wraparound.
- */
- /* Free keys and buffers */
- free(p.bdbkey);
- free(p.subkey);
- RSA_free(p.private_bdbkey);
- RSA_free(p.private_subkey);
- free(hgood);
- free(h);
- }
- /*****************************************************************************/
- int main(void)
- {
- printf("Running tests...\n");
- check_header_tests();
- check_key_tests();
- check_sig_tests();
- check_data_tests();
- check_bdb_verify();
- printf("All tests passed!\n");
- return 0;
- }
|