Vboot Reference: Add a firmware verification benchmark.
The benchmark calculates the time taken to verify a firmware image of various sizes for various combinations of signature algorithm. This is meant to be called through autotest.
Review URL: http://codereview.chromium.org/1127007
diff --git a/tests/Makefile b/tests/Makefile
index 19a0940..98fd3fd 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -11,35 +11,50 @@
LIBS = $(TOP)/utils/kernel_image.o $(TOP)/utils/firmware_image.o \
$(TOP)/utils/file_keys.o $(TOP)/utils/signature_digest.o -lcrypto
-tests: firmware_image_tests verify_firmware_fuzz_driver \
- kernel_image_tests verify_kernel_fuzz_driver \
- sha_tests sha_benchmark rsa_verify_benchmark rsa_padding_test
-
-sha_tests: sha_tests.c
- $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(FIRMWARE_LIBS)
+tests: firmware_image_tests \
+ firmware_verify_benchmark \
+ kernel_image_tests \
+ rsa_padding_test \
+ rsa_verify_benchmark \
+ sha_benchmark \
+ sha_tests \
+ verify_firmware_fuzz_driver \
+ verify_kernel_fuzz_driver
firmware_image_tests: firmware_image_tests.c
$(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) $(FIRMWARE_LIBS)
-verify_firmware_fuzz_driver: verify_firmware_fuzz_driver.c
- $(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) $(FIRMWARE_LIBS)
+firmware_verify_benchmark: firmware_verify_benchmark.c timer_utils.c
+ $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ -lrt $(LIBS) $(FIRMWARE_LIBS)
kernel_image_tests: kernel_image_tests.c
$(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) $(FIRMWARE_LIBS)
-verify_kernel_fuzz_driver: verify_kernel_fuzz_driver.c
- $(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) $(FIRMWARE_LIBS)
-
-sha_benchmark: sha_benchmark.c timer_utils.c $(FIRMWARE_LIBS)
- $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ -lrt
-
rsa_padding_test: rsa_padding_test.c
$(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(LIBS) $(FIRMWARE_LIBS)
rsa_verify_benchmark: rsa_verify_benchmark.c timer_utils.c
$(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ -lrt $(LIBS) $(FIRMWARE_LIBS)
+sha_benchmark: sha_benchmark.c timer_utils.c $(FIRMWARE_LIBS)
+ $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ -lrt
+
+sha_tests: sha_tests.c
+ $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(FIRMWARE_LIBS)
+
+verify_firmware_fuzz_driver: verify_firmware_fuzz_driver.c
+ $(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) $(FIRMWARE_LIBS)
+
+verify_kernel_fuzz_driver: verify_kernel_fuzz_driver.c
+ $(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) $(FIRMWARE_LIBS)
+
clean:
- rm -f sha_tests sha_benchmark rsa_verify_benchmark \
- firmware_image_tests kernel_image_tests rsa_padding_test \
- verify_firmware_fuzz_driver verify_kernel_fuzz_driver
+ rm -f firmware_image_tests \
+ firmware_verify_benchmark \
+ kernel_image_tests \
+ rsa_padding_test \
+ rsa_verify_benchmark \
+ sha_benchmark \
+ sha_tests \
+ verify_firmware_fuzz_driver \
+ verify_kernel_fuzz_driver
diff --git a/tests/firmware_verify_benchmark.c b/tests/firmware_verify_benchmark.c
new file mode 100644
index 0000000..278cb29
--- /dev/null
+++ b/tests/firmware_verify_benchmark.c
@@ -0,0 +1,203 @@
+/* Copyright (c) 2010 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.
+ *
+ * Timing benchmark for verifying a firmware image.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "file_keys.h"
+#include "firmware_image.h"
+#include "padding.h"
+#include "rsa_utility.h"
+#include "timer_utils.h"
+#include "utility.h"
+
+#define FILE_NAME_SIZE 128
+#define NUM_OPERATIONS 100 /* Number of verify operations to time. */
+#define FIRMWARE_SIZE_SMALL 512000
+#define FIRMWARE_SIZE_MEDIUM 1024000
+#define FIRMWARE_SIZE_LARGE 4096000
+
+uint8_t* GenerateTestFirmwareBlob(int algorithm,
+ int firmware_len,
+ const uint8_t* firmware_sign_key,
+ const char* root_key_file,
+ const char* firmware_sign_key_file) {
+ FirmwareImage* image = FirmwareImageNew();
+ uint8_t* firmware_blob = NULL;
+ uint64_t firmware_blob_len = 0;
+
+ Memcpy(image->magic, FIRMWARE_MAGIC, FIRMWARE_MAGIC_SIZE);
+ image->firmware_sign_algorithm = algorithm;
+ image->firmware_sign_key = (uint8_t*) Malloc(
+ RSAProcessedKeySize(image->firmware_sign_algorithm));
+ Memcpy(image->firmware_sign_key, firmware_sign_key,
+ RSAProcessedKeySize(image->firmware_sign_algorithm));
+ image->firmware_key_version = 1;
+
+ /* Update correct header length. */
+ image->header_len = GetFirmwareHeaderLen(image);
+
+ /* Calculate SHA-512 digest on header and populate header_checksum. */
+ CalculateFirmwareHeaderChecksum(image, image->header_checksum);
+
+ /* Populate firmware and preamble with dummy data. */
+ image->firmware_version = 1;
+ image->firmware_len = firmware_len;
+ image->preamble_signature = image->firmware_signature = NULL;
+ Memset(image->preamble, 'P', FIRMWARE_PREAMBLE_SIZE);
+ image->firmware_data = Malloc(image->firmware_len);
+ Memset(image->firmware_data, 'F', image->firmware_len);
+
+ if (!AddFirmwareKeySignature(image, root_key_file)) {
+ fprintf(stderr, "Couldn't create key signature.\n");
+ FirmwareImageFree(image);
+ return NULL;
+ }
+
+ if (!AddFirmwareSignature(image, firmware_sign_key_file)) {
+ fprintf(stderr, "Couldn't create firmware and preamble signature.\n");
+ FirmwareImageFree(image);
+ return NULL;
+ }
+ firmware_blob = GetFirmwareBlob(image, &firmware_blob_len);
+ FirmwareImageFree(image);
+ return firmware_blob;
+}
+
+int SpeedTestAlgorithm(int algorithm) {
+ int i, key_size, error_code = 0;
+ ClockTimerState ct;
+ double msecs;
+ uint64_t len;
+ uint8_t* firmware_sign_key = NULL;
+ uint8_t* root_key_blob = NULL;
+ char firmware_sign_key_file[FILE_NAME_SIZE];
+ char file_name[FILE_NAME_SIZE];
+ char* sha_strings[] = { /* Maps algorithm->SHA algorithm. */
+ "sha1", "sha256", "sha512", /* RSA-1024 */
+ "sha1", "sha256", "sha512", /* RSA-2048 */
+ "sha1", "sha256", "sha512", /* RSA-4096 */
+ "sha1", "sha256", "sha512", /* RSA-8192 */
+ };
+ /* Test for three different firmware sizes. */
+ uint8_t* firmware_blob_small = NULL;
+ uint8_t* firmware_blob_medium = NULL;
+ uint8_t* firmware_blob_large = NULL;
+
+ key_size = siglen_map[algorithm] * 8; /* in bits. */
+ snprintf(firmware_sign_key_file, FILE_NAME_SIZE, "testkeys/key_rsa%d.pem",
+ key_size);
+
+ snprintf(file_name, FILE_NAME_SIZE, "testkeys/key_rsa%d.keyb", key_size);
+ firmware_sign_key = BufferFromFile(file_name, &len);
+ if (!firmware_sign_key) {
+ fprintf(stderr, "Couldn't read pre-processed firmware signing key.\n");
+ error_code = 1;
+ goto cleanup;
+ }
+
+ /* Generate test images. */
+ firmware_blob_small = GenerateTestFirmwareBlob(algorithm,
+ FIRMWARE_SIZE_SMALL,
+ firmware_sign_key,
+ "testkeys/key_rsa8192.pem",
+ firmware_sign_key_file);
+ firmware_blob_medium = GenerateTestFirmwareBlob(algorithm,
+ FIRMWARE_SIZE_MEDIUM,
+ firmware_sign_key,
+ "testkeys/key_rsa8192.pem",
+ firmware_sign_key_file);
+ firmware_blob_large = GenerateTestFirmwareBlob(algorithm,
+ FIRMWARE_SIZE_LARGE,
+ firmware_sign_key,
+ "testkeys/key_rsa8192.pem",
+ firmware_sign_key_file);
+ if (!firmware_blob_small || !firmware_blob_medium || !firmware_blob_large) {
+ fprintf(stderr, "Couldn't generate test firmware images.\n");
+ error_code = 1;
+ goto cleanup;
+ }
+
+ root_key_blob = BufferFromFile("testkeys/key_rsa8192.keyb", &len);
+ if (!root_key_blob) {
+ fprintf(stderr, "Couldn't read pre-processed rootkey.\n");
+ error_code = 1;
+ goto cleanup;
+ }
+
+ /* Small.*/
+ StartTimer(&ct);
+ for (i = 0; i < NUM_OPERATIONS; ++i) {
+ if (VERIFY_FIRMWARE_SUCCESS !=
+ VerifyFirmware(root_key_blob, firmware_blob_small, 0))
+ fprintf(stderr, "Warning: Firmware Verification Failed.\n");
+ }
+ StopTimer(&ct);
+ msecs = (float) GetDurationMsecs(&ct) / NUM_OPERATIONS;
+ fprintf(stderr,
+ "# Firmware (Small, Algo = %s):"
+ "\t%.02f ms/verification\n",
+ algo_strings[algorithm], msecs);
+ fprintf(stdout, "ms_firmware_sm_rsa%d_%s:%.02f\n",
+ key_size,
+ sha_strings[algorithm],
+ msecs);
+
+ /* Medium. */
+ StartTimer(&ct);
+ for (i = 0; i < NUM_OPERATIONS; ++i) {
+ if (VERIFY_FIRMWARE_SUCCESS !=
+ VerifyFirmware(root_key_blob, firmware_blob_medium, 0))
+ fprintf(stderr, "Warning: Firmware Verification Failed.\n");
+ }
+ StopTimer(&ct);
+ msecs = (float) GetDurationMsecs(&ct) / NUM_OPERATIONS;
+ fprintf(stderr,
+ "# Firmware (Medium, Algo = %s):"
+ "\t%.02f ms/verification\n",
+ algo_strings[algorithm], msecs);
+ fprintf(stdout, "ms_firmware_med_rsa%d_%s:%.02f\n",
+ key_size,
+ sha_strings[algorithm],
+ msecs);
+
+
+ /* Large */
+ StartTimer(&ct);
+ for (i = 0; i < NUM_OPERATIONS; ++i) {
+ if (VERIFY_FIRMWARE_SUCCESS !=
+ VerifyFirmware(root_key_blob, firmware_blob_large, 0))
+ fprintf(stderr, "Warning: Firmware Verification Failed.\n");
+ }
+ StopTimer(&ct);
+ msecs = (float) GetDurationMsecs(&ct) / NUM_OPERATIONS;
+ fprintf(stderr,
+ "# Firmware (Large, Algorithm = %s):"
+ "\t%.02f ms/verification\n",
+ algo_strings[algorithm], msecs);
+ fprintf(stdout, "ms_firmware_large_rsa%d_%s:%.02f\n",
+ key_size,
+ sha_strings[algorithm],
+ msecs);
+
+ cleanup:
+ Free(root_key_blob);
+ Free(firmware_blob_large);
+ Free(firmware_blob_medium);
+ Free(firmware_blob_small);
+ return error_code;
+}
+
+
+int main(int argc, char* argv[]) {
+ int i, error_code = 0;
+ for (i = 0; i < kNumAlgorithms; ++i) {
+ if (0 != (error_code = SpeedTestAlgorithm(i)))
+ return error_code;
+ }
+ return 0;
+}