/* Copyright (c) 2013 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. * * Tests for firmware image library. */ #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "cryptolib.h" #include "file_keys.h" #include "host_common.h" #include "test_common.h" #include "vboot_common.h" static void VerifyPublicKeyToRSA(const VbPublicKey *orig_key) { RSAPublicKey *rsa; VbPublicKey *key = PublicKeyAlloc(orig_key->key_size, 0, 0); PublicKeyCopy(key, orig_key); key->algorithm = kNumAlgorithms; TEST_EQ((size_t)PublicKeyToRSA(key), 0, "PublicKeyToRSA() invalid algorithm"); PublicKeyCopy(key, orig_key); key->key_size -= 1; TEST_EQ((size_t)PublicKeyToRSA(key), 0, "PublicKeyToRSA() invalid size"); rsa = PublicKeyToRSA(orig_key); TEST_NEQ((size_t)rsa, 0, "PublicKeyToRSA() ok"); if (rsa) { TEST_EQ((int)rsa->algorithm, (int)key->algorithm, "PublicKeyToRSA() algorithm"); RSAPublicKeyFree(rsa); } } static void VerifyDataTest(const VbPublicKey *public_key, const VbPrivateKey *private_key) { const uint8_t test_data[] = "This is some test data to sign."; const uint64_t test_size = sizeof(test_data); VbSignature *sig; RSAPublicKey *rsa; sig = CalculateSignature(test_data, test_size, private_key); TEST_PTR_NEQ(sig, 0, "VerifyData() calculate signature"); rsa = PublicKeyToRSA(public_key); TEST_PTR_NEQ(rsa, 0, "VerifyData() calculate rsa"); if (!sig || !rsa) return; TEST_EQ(VerifyData(test_data, test_size, sig, rsa), 0, "VerifyData() ok"); sig->sig_size -= 16; TEST_EQ(VerifyData(test_data, test_size, sig, rsa), 1, "VerifyData() wrong sig size"); sig->sig_size += 16; TEST_EQ(VerifyData(test_data, test_size - 1, sig, rsa), 1, "VerifyData() input buffer too small"); GetSignatureData(sig)[0] ^= 0x5A; TEST_EQ(VerifyData(test_data, test_size, sig, rsa), 1, "VerifyData() wrong sig"); RSAPublicKeyFree(rsa); free(sig); } static void VerifyDigestTest(const VbPublicKey *public_key, const VbPrivateKey *private_key) { const uint8_t test_data[] = "This is some other test data to sign."; VbSignature *sig; RSAPublicKey *rsa; uint8_t *digest; sig = CalculateSignature(test_data, sizeof(test_data), private_key); rsa = PublicKeyToRSA(public_key); digest = DigestBuf(test_data, sizeof(test_data), (int)public_key->algorithm); TEST_NEQ(sig && rsa && digest, 0, "VerifyData() prerequisites"); if (!sig || !rsa || !digest) return; TEST_EQ(VerifyDigest(digest, sig, rsa), 0, "VerifyDigest() ok"); GetSignatureData(sig)[0] ^= 0x5A; TEST_EQ(VerifyDigest(digest, sig, rsa), 1, "VerifyDigest() wrong sig"); sig->sig_size = 1; TEST_EQ(VerifyDigest(digest, sig, rsa), 1, "VerifyDigest() sig size"); RSAPublicKeyFree(rsa); free(sig); VbExFree(digest); } static void ReSignKernelPreamble(VbKernelPreambleHeader *h, const VbPrivateKey *key) { VbSignature *sig = CalculateSignature((const uint8_t *)h, h->preamble_signature.data_size, key); SignatureCopy(&h->preamble_signature, sig); free(sig); } static void VerifyKernelPreambleTest(const VbPublicKey *public_key, const VbPrivateKey *private_key) { VbKernelPreambleHeader *hdr; VbKernelPreambleHeader *h; RSAPublicKey *rsa; unsigned hsize; /* Create a dummy signature */ VbSignature *body_sig = SignatureAlloc(56, 78); rsa = PublicKeyToRSA(public_key); hdr = CreateKernelPreamble(0x1234, 0x100000, 0x300000, 0x4000, body_sig, 0, 0, 0, 0, private_key); TEST_NEQ(hdr && rsa, 0, "VerifyKernelPreamble() prerequisites"); if (!hdr) return; hsize = (unsigned) hdr->preamble_size; h = (VbKernelPreambleHeader *)malloc(hsize + 16384); TEST_EQ(VerifyKernelPreamble(hdr, hsize, rsa), 0, "VerifyKernelPreamble() ok using key"); TEST_NEQ(VerifyKernelPreamble(hdr, hsize - 1, rsa), 0, "VerifyKernelPreamble() size--"); TEST_NEQ(VerifyKernelPreamble(hdr, 4, rsa), 0, "VerifyKernelPreamble() size tiny"); TEST_EQ(VerifyKernelPreamble(hdr, hsize + 1, rsa), 0, "VerifyKernelPreamble() size++"); /* Care about major version but not minor */ Memcpy(h, hdr, hsize); h->header_version_major++; ReSignKernelPreamble(h, private_key); TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0, "VerifyKernelPreamble() major++"); Memcpy(h, hdr, hsize); h->header_version_major--; ReSignKernelPreamble(h, private_key); TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0, "VerifyKernelPreamble() major--"); Memcpy(h, hdr, hsize); h->header_version_minor++; ReSignKernelPreamble(h, private_key); TEST_EQ(VerifyKernelPreamble(h, hsize, rsa), 0, "VerifyKernelPreamble() minor++"); Memcpy(h, hdr, hsize); h->header_version_minor--; ReSignKernelPreamble(h, private_key); TEST_EQ(VerifyKernelPreamble(h, hsize, rsa), 0, "VerifyKernelPreamble() minor--"); /* Check signature */ Memcpy(h, hdr, hsize); h->preamble_signature.sig_offset = hsize; ReSignKernelPreamble(h, private_key); TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0, "VerifyKernelPreamble() sig off end"); Memcpy(h, hdr, hsize); h->preamble_signature.sig_size--; ReSignKernelPreamble(h, private_key); TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0, "VerifyKernelPreamble() sig too small"); Memcpy(h, hdr, hsize); GetSignatureData(&h->body_signature)[0] ^= 0x34; TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0, "VerifyKernelPreamble() sig mismatch"); /* Check that we signed header and body sig */ Memcpy(h, hdr, hsize); h->preamble_signature.data_size = 4; h->body_signature.sig_offset = 0; h->body_signature.sig_size = 0; ReSignKernelPreamble(h, private_key); TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0, "VerifyKernelPreamble() didn't sign header"); Memcpy(h, hdr, hsize); h->body_signature.sig_offset = hsize; ReSignKernelPreamble(h, private_key); TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0, "VerifyKernelPreamble() body sig off end"); /* TODO: verify parser can support a bigger header. */ free(h); RSAPublicKeyFree(rsa); free(hdr); } int test_algorithm(int key_algorithm, const char *keys_dir) { char filename[1024]; int rsa_len = siglen_map[key_algorithm] * 8; VbPrivateKey *private_key = NULL; VbPublicKey *public_key = NULL; printf("***Testing algorithm: %s\n", algo_strings[key_algorithm]); sprintf(filename, "%s/key_rsa%d.pem", keys_dir, rsa_len); private_key = PrivateKeyReadPem(filename, key_algorithm); if (!private_key) { fprintf(stderr, "Error reading private_key: %s\n", filename); return 1; } sprintf(filename, "%s/key_rsa%d.keyb", keys_dir, rsa_len); public_key = PublicKeyReadKeyb(filename, key_algorithm, 1); if (!public_key) { fprintf(stderr, "Error reading public_key: %s\n", filename); return 1; } VerifyPublicKeyToRSA(public_key); VerifyDataTest(public_key, private_key); VerifyDigestTest(public_key, private_key); VerifyKernelPreambleTest(public_key, private_key); if (public_key) free(public_key); if (private_key) free(private_key); return 0; } /* * Test only the algorithms we use: * 4 (rsa2048 sha256) * 7 (rsa4096 sha256) * 11 (rsa8192 sha512) */ const int key_algs[] = {4, 7, 11}; 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 < kNumAlgorithms; alg++) { if (test_algorithm(alg, argv[1])) return 1; } } else { fprintf(stderr, "Usage: %s <keys_dir> [--all]", argv[0]); return -1; } if (vboot_api_stub_check_memory()) return 255; return gTestSuccess ? 0 : 255; }