/* Copyright 2014 The ChromiumOS Authors * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Tests for firmware image library. */ #include #include #include #include "2common.h" #include "2rsa.h" #include "2sysincludes.h" #include "common/tests.h" #include "host_common.h" #include "host_common21.h" #include "host_key21.h" #include "host_signature21.h" #include "util_misc.h" static const uint8_t test_data[] = "This is some test data to sign."; static const uint32_t test_size = sizeof(test_data); static void test_unpack_key(const struct vb21_packed_key *key) { struct vb2_public_key pubk; struct vb21_packed_key *key2; uint32_t size = key->c.total_size; /* Make a copy of the key for testing */ key2 = (struct vb21_packed_key *)malloc(size); memcpy(key2, key, size); TEST_SUCC(vb21_unpack_key(&pubk, (uint8_t *)key2, size), "vb21_unpack_key() ok"); memcpy(key2, key, size); key2->key_offset += 4; TEST_EQ(vb21_unpack_key(&pubk, (uint8_t *)key2, size), VB2_ERROR_COMMON_MEMBER_SIZE, "vb21_unpack_key() buffer too small"); memcpy(key2, key, size); key2->c.fixed_size += size; TEST_EQ(vb21_unpack_key(&pubk, (uint8_t *)key2, size), VB2_ERROR_COMMON_FIXED_SIZE, "vb21_unpack_key() buffer too small for desc"); memcpy(key2, key, size); key2->c.desc_size = 0; TEST_SUCC(vb21_unpack_key(&pubk, (uint8_t *)key2, size), "vb21_unpack_key() no desc"); TEST_EQ(strcmp(pubk.desc, ""), 0, " empty desc string"); memcpy(key2, key, size); key2->c.magic++; TEST_EQ(vb21_unpack_key(&pubk, (uint8_t *)key2, size), VB2_ERROR_UNPACK_KEY_MAGIC, "vb21_unpack_key() bad magic"); memcpy(key2, key, size); key2->c.struct_version_major++; TEST_EQ(vb21_unpack_key(&pubk, (uint8_t *)key2, size), VB2_ERROR_UNPACK_KEY_STRUCT_VERSION, "vb21_unpack_key() bad major version"); /* * Minor version changes are ok. Note that this test assumes that the * source key struct version is the highest actually known to the * reader. If the reader does know about minor version + 1 and that * adds fields, this test will likely fail. But at that point, we * should have already added a test for minor version compatibility to * handle both old and new struct versions, so someone will have * noticed this comment. */ memcpy(key2, key, size); key2->c.struct_version_minor++; TEST_SUCC(vb21_unpack_key(&pubk, (uint8_t *)key2, size), "vb21_unpack_key() minor version change ok"); memcpy(key2, key, size); key2->sig_alg = VB2_SIG_INVALID; TEST_EQ(vb21_unpack_key(&pubk, (uint8_t *)key2, size), VB2_ERROR_UNPACK_KEY_SIG_ALGORITHM, "vb21_unpack_key() bad sig algorithm"); memcpy(key2, key, size); key2->hash_alg = VB2_HASH_INVALID; TEST_EQ(vb21_unpack_key(&pubk, (uint8_t *)key2, size), VB2_ERROR_UNPACK_KEY_HASH_ALGORITHM, "vb21_unpack_key() bad hash algorithm"); memcpy(key2, key, size); key2->key_size -= 4; TEST_EQ(vb21_unpack_key(&pubk, (uint8_t *)key2, size), VB2_ERROR_UNPACK_KEY_SIZE, "vb21_unpack_key() invalid size"); memcpy(key2, key, size); key2->key_offset--; TEST_EQ(vb21_unpack_key(&pubk, (uint8_t *)key2, size), VB2_ERROR_COMMON_MEMBER_UNALIGNED, "vb21_unpack_key() unaligned data"); memcpy(key2, key, size); *(uint32_t *)((uint8_t *)key2 + key2->key_offset) /= 2; TEST_EQ(vb21_unpack_key(&pubk, (uint8_t *)key2, size), VB2_ERROR_UNPACK_KEY_ARRAY_SIZE, "vb21_unpack_key() invalid key array size"); free(key2); } static void test_verify_signature(const struct vb21_signature *sig) { struct vb21_signature *sig2; uint8_t *buf2; uint32_t size; /* Make a copy of the signature */ size = sig->c.total_size; buf2 = malloc(size); sig2 = (struct vb21_signature *)buf2; memcpy(buf2, sig, size); TEST_SUCC(vb21_verify_signature(sig2, size), "verify_sig ok"); sig2->c.magic = VB21_MAGIC_PACKED_KEY; TEST_EQ(vb21_verify_signature(sig2, size), VB2_ERROR_SIG_MAGIC, "verify_sig magic"); memcpy(buf2, sig, size); sig2->c.total_size += 4; TEST_EQ(vb21_verify_signature(sig2, size), VB2_ERROR_COMMON_TOTAL_SIZE, "verify_sig common header"); memcpy(buf2, sig, size); sig2->c.struct_version_minor++; TEST_SUCC(vb21_verify_signature(sig2, size), "verify_sig minor ver"); sig2->c.struct_version_major++; TEST_EQ(vb21_verify_signature(sig2, size), VB2_ERROR_SIG_VERSION, "verify_sig major ver"); memcpy(buf2, sig, size); sig2->c.fixed_size -= 4; sig2->c.desc_size += 4; TEST_EQ(vb21_verify_signature(sig2, size), VB2_ERROR_SIG_HEADER_SIZE, "verify_sig header size"); memcpy(buf2, sig, size); sig2->sig_size += 4; TEST_EQ(vb21_verify_signature(sig2, size), VB2_ERROR_COMMON_MEMBER_SIZE, "verify_sig sig size"); memcpy(buf2, sig, size); sig2->sig_alg = VB2_SIG_INVALID; TEST_EQ(vb21_verify_signature(sig2, size), VB2_ERROR_SIG_ALGORITHM, "verify_sig sig alg"); memcpy(buf2, sig, size); sig2->sig_alg = (sig2->sig_alg == VB2_SIG_NONE ? VB2_SIG_RSA1024 : VB2_SIG_NONE); TEST_EQ(vb21_verify_signature(sig2, size), VB2_ERROR_SIG_SIZE, "verify_sig sig size"); free(buf2); } static void test_verify_data(const struct vb2_public_key *pubk_orig, const struct vb21_signature *sig) { uint8_t workbuf[VB2_VERIFY_DATA_WORKBUF_BYTES] __attribute__((aligned(VB2_WORKBUF_ALIGN))); struct vb2_workbuf wb; struct vb2_public_key pubk; struct vb21_signature *sig2; uint8_t *buf2; uint32_t size; vb2_workbuf_init(&wb, workbuf, sizeof(workbuf)); pubk = *pubk_orig; /* Allocate signature copy for tests */ size = sig->c.total_size; buf2 = malloc(size); sig2 = (struct vb21_signature *)buf2; memcpy(buf2, sig, size); pubk.sig_alg = VB2_SIG_INVALID; TEST_EQ(vb21_verify_data(test_data, test_size, sig2, &pubk, &wb), VB2_ERROR_VDATA_ALGORITHM, "vb21_verify_data() bad sig alg"); pubk = *pubk_orig; memcpy(buf2, sig, size); pubk.hash_alg = VB2_HASH_INVALID; TEST_EQ(vb21_verify_data(test_data, test_size, sig2, &pubk, &wb), VB2_ERROR_VDATA_DIGEST_SIZE, "vb21_verify_data() bad hash alg"); pubk = *pubk_orig; vb2_workbuf_init(&wb, workbuf, 4); memcpy(buf2, sig, size); TEST_EQ(vb21_verify_data(test_data, test_size, sig2, &pubk, &wb), VB2_ERROR_VDATA_WORKBUF_DIGEST, "vb21_verify_data() workbuf too small"); vb2_workbuf_init(&wb, workbuf, sizeof(workbuf)); memcpy(buf2, sig, size); TEST_EQ(vb21_verify_data(test_data, test_size, sig2, &pubk, &wb), 0, "vb21_verify_data() ok"); memcpy(buf2, sig, size); sig2->sig_size -= 16; TEST_EQ(vb21_verify_data(test_data, test_size, sig2, &pubk, &wb), VB2_ERROR_VDATA_SIG_SIZE, "vb21_verify_data() wrong sig size"); memcpy(buf2, sig, size); TEST_EQ(vb21_verify_data(test_data, test_size - 1, sig2, &pubk, &wb), VB2_ERROR_VDATA_SIZE, "vb21_verify_data() wrong data size"); memcpy(buf2, sig, size); sig2->hash_alg = (sig2->hash_alg == VB2_HASH_SHA1 ? VB2_HASH_SHA256 : VB2_HASH_SHA1); TEST_EQ(vb21_verify_data(test_data, test_size, sig2, &pubk, &wb), VB2_ERROR_VDATA_ALGORITHM_MISMATCH, "vb21_verify_data() alg mismatch"); memcpy(buf2, sig, size); buf2[sig2->sig_offset] ^= 0x5A; TEST_EQ(vb21_verify_data(test_data, test_size, sig2, &pubk, &wb), VB2_ERROR_RSA_PADDING, "vb21_verify_data() wrong sig"); free(buf2); } static int test_algorithm(int key_algorithm, const char *keys_dir) { char filename[1024]; enum vb2_signature_algorithm sig_alg = vb2_crypto_to_signature(key_algorithm); enum vb2_hash_algorithm hash_alg = vb2_crypto_to_hash(key_algorithm); struct vb2_private_key *prik = NULL; struct vb21_signature *sig2 = NULL; struct vb2_public_key *pubk; uint8_t *pubk_buf = 0; uint8_t *keyb_data = 0; uint32_t keyb_size; struct vb21_packed_key *key2 = NULL; printf("***Testing algorithm: %s\n", vb2_get_crypto_algorithm_name(key_algorithm)); snprintf(filename, sizeof(filename), "%s/key_%s.pem", keys_dir, vb2_get_crypto_algorithm_file(key_algorithm)); TEST_SUCC(vb2_private_key_read_pem(&prik, filename), "Read private key"); prik->hash_alg = hash_alg; prik->sig_alg = sig_alg; vb2_private_key_set_desc(prik, "private key"); /* Create the public key */ TEST_SUCC(vb2_public_key_alloc(&pubk, sig_alg), "Allocate public key"); /* Extract the keyb blob */ TEST_SUCC(vb_keyb_from_rsa(prik->rsa_private_key, &keyb_data, &keyb_size), "Extract public key"); /* * Copy the keyb blob to the public key's buffer, because that's * where vb2_unpack_key_data() and vb2_public_key_pack() expect * to find it. */ pubk_buf = vb2_public_key_packed_data(pubk); memcpy(pubk_buf, keyb_data, keyb_size); /* Fill in the internal struct pointers */ TEST_SUCC(vb2_unpack_key_data(pubk, pubk_buf, keyb_size), "unpack public key blob"); pubk->hash_alg = hash_alg; vb2_public_key_set_desc(pubk, "public key"); TEST_SUCC(vb21_public_key_pack(&key2, pubk), "Pack public key"); /* Calculate good signatures */ TEST_SUCC(vb21_sign_data(&sig2, test_data, test_size, prik, ""), "Make test signature"); test_unpack_key(key2); test_verify_data(pubk, sig2); test_verify_signature(sig2); free(keyb_data); free(key2); free(sig2); vb2_free_private_key(prik); vb2_public_key_free(pubk); return 0; } /* Test only the algorithms we use */ const int key_algs[] = { VB2_ALG_RSA2048_SHA256, VB2_ALG_RSA4096_SHA256, VB2_ALG_RSA8192_SHA512, }; int main(int argc, char *argv[]) { if (argc == 2) { int i; for (i = 0; i < ARRAY_SIZE(key_algs); i++) { if (test_algorithm(key_algs[i], argv[1])) return 1; } } else if (argc == 3 && !strcasecmp(argv[2], "--all")) { /* Test all the algorithms */ int alg; for (alg = 0; alg < VB2_ALG_COUNT; alg++) { if (test_algorithm(alg, argv[1])) return 1; } } else { fprintf(stderr, "Usage: %s [--all]", argv[0]); return -1; } return gTestSuccess ? 0 : 255; }