/* 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 #include #include #include "cryptolib.h" #include "file_keys.h" #include "kernel_image.h" #include "test_common.h" #include "timer_utils.h" #include "utility.h" #define FILE_NAME_SIZE 128 #define NUM_OPERATIONS 30 /* Number of verify operations to time. * We use a smaller number here (30 vs. 100) * since there are many more cases to consider * (one for each combination of firmware and kernel * signature algorithm. */ #define KERNEL_SIZE_SMALL 512000 #define KERNEL_SIZE_MEDIUM 1024000 #define KERNEL_SIZE_LARGE 4096000 const uint64_t g_kernel_sizes_to_test[] = { KERNEL_SIZE_SMALL, KERNEL_SIZE_MEDIUM, KERNEL_SIZE_LARGE }; const char* g_kernel_size_labels[] = { "small", "medium", "large" }; #define NUM_SIZES_TO_TEST (sizeof(g_kernel_sizes_to_test) / \ sizeof(g_kernel_sizes_to_test[0])) int SpeedTestAlgorithm(int firmware_sign_algorithm, int kernel_sign_algorithm) { int i, j, error_code = 0; int firmware_key_size, kernel_key_size; ClockTimerState ct; double msecs; uint64_t len; uint8_t* kernel_sign_key = NULL; uint8_t* firmware_key_blob = NULL; char firmware_sign_key_file[FILE_NAME_SIZE]; char kernel_sign_key_file[FILE_NAME_SIZE]; char file_name[FILE_NAME_SIZE]; /* Temp to hold a constructed file name */ 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 */ }; uint8_t* kernel_blobs[NUM_SIZES_TO_TEST]; for (i = 0; i < NUM_SIZES_TO_TEST; ++i) kernel_blobs[i] = NULL; /* Get all needed test keys. */ firmware_key_size = siglen_map[firmware_sign_algorithm] * 8; /* in bits. */ kernel_key_size = siglen_map[kernel_sign_algorithm] * 8; /* in bits. */ snprintf(firmware_sign_key_file, FILE_NAME_SIZE, "testkeys/key_rsa%d.pem", firmware_key_size); snprintf(kernel_sign_key_file, FILE_NAME_SIZE, "testkeys/key_rsa%d.pem", kernel_key_size); snprintf(file_name, FILE_NAME_SIZE, "testkeys/key_rsa%d.keyb", kernel_key_size); kernel_sign_key = BufferFromFile(file_name, &len); if (!kernel_sign_key) { VBDEBUG(("Couldn't read pre-processed public kernel signing key.\n")); error_code = 1; goto cleanup; } /* Generate test images. */ for (i = 0; i < NUM_SIZES_TO_TEST; ++i) { kernel_blobs[i] = GenerateTestKernelBlob(firmware_sign_algorithm, kernel_sign_algorithm, kernel_sign_key, 1, /* kernel key version. */ 1, /* kernel version. */ g_kernel_sizes_to_test[i], firmware_sign_key_file, kernel_sign_key_file); if (!kernel_blobs[i]) { VBDEBUG(("Couldn't generate test firmware images.\n")); error_code = 1; goto cleanup; } } /* Get pre-processed key used for verification. */ snprintf(file_name, FILE_NAME_SIZE, "testkeys/key_rsa%d.keyb", firmware_key_size); firmware_key_blob = BufferFromFile(file_name, &len); if (!firmware_key_blob) { VBDEBUG(("Couldn't read pre-processed firmware public key.\n")); error_code = 1; goto cleanup; } /* Now run the timing tests. */ for (i = 0; i < NUM_SIZES_TO_TEST; ++i) { StartTimer(&ct); for (j = 0; j < NUM_OPERATIONS; ++j) { if (VERIFY_KERNEL_SUCCESS != VerifyKernel(firmware_key_blob, kernel_blobs[i], 0)) VBDEBUG(("Warning: Kernel Verification Failed.\n")); } StopTimer(&ct); msecs = (float) GetDurationMsecs(&ct) / NUM_OPERATIONS; fprintf(stderr, "# Kernel (%s, Algo = %s / %s):" "\t%.02f ms/verification\n", g_kernel_size_labels[i], algo_strings[firmware_sign_algorithm], algo_strings[kernel_sign_algorithm], msecs); fprintf(stdout, "ms_kernel_%s_rsa%d_%s_rsa%d_%s:%.02f\n", g_kernel_size_labels[i], firmware_key_size, sha_strings[firmware_sign_algorithm], kernel_key_size, sha_strings[kernel_sign_algorithm], msecs); } cleanup: for (i = 0; i < NUM_SIZES_TO_TEST; ++i) Free(kernel_blobs[i]); Free(firmware_key_blob); Free(kernel_sign_key); return error_code; } int main(int argc, char* argv[]) { int i, j, error_code = 0; for (i = 0; i < kNumAlgorithms; ++i) { /* Firmware Signing Algorithm. */ for (j = 0; j < kNumAlgorithms; ++j) { /* Kernel Signing Algorithm. */ /* Only measure if the kernel signing algorithm is weaker or equal to * the firmware signing algorithm. */ if (siglen_map[j] > siglen_map[i]) continue; if (siglen_map[j] == siglen_map[i] && hash_size_map[j] > hash_size_map[i]) continue; if (0 != (error_code = SpeedTestAlgorithm(i, j))) return error_code; } } return 0; }