/* 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. * * Functions for verifying a verified boot kernel image. * (Firmware portion) */ #include "kernel_image_fw.h" #include "cryptolib.h" #include "rollback_index.h" #include "stateful_util.h" #include "utility.h" /* Macro to determine the size of a field structure in the KernelImage * structure. */ #define FIELD_LEN(field) (sizeof(((KernelImage*)0)->field)) char* kVerifyKernelErrors[VERIFY_KERNEL_MAX] = { "Success.", "Invalid Image.", "Kernel Key Signature Failed.", "Invalid Kernel Verification Algorithm.", "Preamble Signature Failed.", "Kernel Signature Failed.", "Wrong Kernel Magic.", }; inline uint64_t GetKernelPreambleLen(int algorithm) { return (FIELD_LEN(kernel_version) + FIELD_LEN(kernel_len) + FIELD_LEN(bootloader_offset) + FIELD_LEN(bootloader_size) + FIELD_LEN(padded_header_size) + siglen_map[algorithm]); } uint64_t GetVblockHeaderSize(const uint8_t* vkernel_blob) { uint64_t len = 0; uint16_t firmware_sign_algorithm; uint16_t kernel_sign_algorithm; int algorithms_offset = (FIELD_LEN(magic) + FIELD_LEN(header_version) + FIELD_LEN(header_len)); if (SafeMemcmp(vkernel_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) { debug("Not a valid verified boot kernel blob.\n"); return 0; } Memcpy(&firmware_sign_algorithm, vkernel_blob + algorithms_offset, sizeof(firmware_sign_algorithm)); Memcpy(&kernel_sign_algorithm, vkernel_blob + algorithms_offset + FIELD_LEN(kernel_sign_algorithm), sizeof(kernel_sign_algorithm)); if (firmware_sign_algorithm >= kNumAlgorithms) { debug("Invalid firmware signing algorithm.\n"); return 0; } if (kernel_sign_algorithm >= kNumAlgorithms) { debug("Invalid kernel signing algorithm.\n"); return 0; } len = algorithms_offset; /* magic, header length and version. */ len += (FIELD_LEN(firmware_sign_algorithm) + FIELD_LEN(kernel_sign_algorithm) + FIELD_LEN(kernel_key_version) + RSAProcessedKeySize(kernel_sign_algorithm) + /* kernel_sign_key */ FIELD_LEN(header_checksum) + siglen_map[firmware_sign_algorithm] + /* kernel_key_signature */ GetKernelPreambleLen(kernel_sign_algorithm) + siglen_map[kernel_sign_algorithm]); /* preamble_signature */ return len; } int VerifyKernelKeyHeader(const uint8_t* firmware_key_blob, const uint8_t* header_blob, const int dev_mode, int* firmware_algorithm, int* kernel_algorithm, int* kernel_header_len) { int kernel_sign_key_len; int firmware_sign_key_len; uint16_t header_version, header_len; uint16_t firmware_sign_algorithm, kernel_sign_algorithm; uint8_t* header_checksum = NULL; /* Base Offset for the header_checksum field. Actual offset is * this + kernel_sign_key_len. */ int base_header_checksum_offset = (FIELD_LEN(header_version) + FIELD_LEN(header_len) + FIELD_LEN(firmware_sign_algorithm) + FIELD_LEN(kernel_sign_algorithm) + FIELD_LEN(kernel_key_version)); Memcpy(&header_version, header_blob, sizeof(header_version)); Memcpy(&header_len, header_blob + FIELD_LEN(header_version), sizeof(header_len)); Memcpy(&firmware_sign_algorithm, header_blob + (FIELD_LEN(header_version) + FIELD_LEN(header_len)), sizeof(firmware_sign_algorithm)); Memcpy(&kernel_sign_algorithm, header_blob + (FIELD_LEN(header_version) + FIELD_LEN(header_len) + FIELD_LEN(firmware_sign_algorithm)), sizeof(kernel_sign_algorithm)); /* TODO(gauravsh): Make this return two different error types depending * on whether the firmware or kernel signing algorithm is invalid. */ if (firmware_sign_algorithm >= kNumAlgorithms) return VERIFY_KERNEL_INVALID_ALGORITHM; if (kernel_sign_algorithm >= kNumAlgorithms) return VERIFY_KERNEL_INVALID_ALGORITHM; *firmware_algorithm = (int) firmware_sign_algorithm; *kernel_algorithm = (int) kernel_sign_algorithm; kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm); firmware_sign_key_len = RSAProcessedKeySize(firmware_sign_algorithm); /* Verify if header len is correct? */ if (header_len != (base_header_checksum_offset + kernel_sign_key_len + FIELD_LEN(header_checksum))) { debug("VerifyKernelKeyHeader: Header length mismatch\n"); return VERIFY_KERNEL_INVALID_IMAGE; } *kernel_header_len = (int) header_len; /* Verify if the hash of the header is correct. */ header_checksum = DigestBuf(header_blob, header_len - FIELD_LEN(header_checksum), SHA512_DIGEST_ALGORITHM); if (SafeMemcmp(header_checksum, header_blob + (base_header_checksum_offset + kernel_sign_key_len), FIELD_LEN(header_checksum))) { Free(header_checksum); debug("VerifyKernelKeyHeader: Invalid header hash\n"); return VERIFY_KERNEL_INVALID_IMAGE; } Free(header_checksum); /* Verify kernel key signature unless we are in dev mode. */ if (!dev_mode) { if (!RSAVerifyBinary_f(firmware_key_blob, NULL, /* Key to use */ header_blob, /* Data to verify */ header_len, /* Length of data */ header_blob + header_len, /* Expected Signature */ firmware_sign_algorithm)) return VERIFY_KERNEL_KEY_SIGNATURE_FAILED; } return 0; } int VerifyKernelPreamble(RSAPublicKey* kernel_sign_key, const uint8_t* preamble_blob, int algorithm, uint64_t* kernel_len) { int preamble_len = GetKernelPreambleLen(algorithm); if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use */ preamble_blob, /* Data to verify */ preamble_len, /* Length of data */ preamble_blob + preamble_len, /* Expected Signature */ algorithm)) return VERIFY_KERNEL_PREAMBLE_SIGNATURE_FAILED; Memcpy(kernel_len, preamble_blob + FIELD_LEN(kernel_version), FIELD_LEN(kernel_len)); return 0; } int VerifyKernelData(RSAPublicKey* kernel_sign_key, const uint8_t* kernel_signature, const uint8_t* kernel_data, uint64_t kernel_len, int algorithm) { if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use */ kernel_data, /* Data to verify */ kernel_len, /* Length of data */ kernel_signature, /* Expected Signature */ algorithm)) return VERIFY_KERNEL_SIGNATURE_FAILED; return 0; } int VerifyKernelHeader(const uint8_t* firmware_key_blob, const uint8_t* kernel_header_blob, uint64_t kernel_header_blob_len, const int dev_mode, KernelImage* image, RSAPublicKey** kernel_sign_key) { int error_code; int firmware_sign_algorithm; /* Firmware signing key algorithm. */ int kernel_sign_algorithm; /* Kernel signing key algorithm. */ int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len, header_len; uint64_t kernel_len; const uint8_t* header_ptr = NULL; /* Pointer to key header. */ const uint8_t* preamble_ptr = NULL; /* Pointer to start of preamble. */ MemcpyState st; /* Note: All the offset calculations are based on struct KernelImage which * is defined in include/kernel_image_fw.h. */ st.remaining_buf = (void *)kernel_header_blob; st.remaining_len = kernel_header_blob_len; st.overrun = 0; /* Clear destination image struct */ Memset(image, 0, sizeof(KernelImage)); /* Read and compare magic bytes. */ StatefulMemcpy(&st, &image->magic, KERNEL_MAGIC_SIZE); if (SafeMemcmp(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) { return VERIFY_KERNEL_WRONG_MAGIC; } StatefulMemcpy(&st, &image->header_version, FIELD_LEN(header_version)); StatefulMemcpy(&st, &image->header_len, FIELD_LEN(header_len)); StatefulMemcpy(&st, &image->firmware_sign_algorithm, FIELD_LEN(firmware_sign_algorithm)); StatefulMemcpy(&st, &image->kernel_sign_algorithm, FIELD_LEN(kernel_sign_algorithm)); header_ptr = kernel_header_blob + KERNEL_MAGIC_SIZE; /* Only continue if header verification succeeds. */ if ((error_code = VerifyKernelKeyHeader(firmware_key_blob, header_ptr, dev_mode, &firmware_sign_algorithm, &kernel_sign_algorithm, &header_len))) { debug("VerifyKernelHeader: Kernel Key Header verification failed.\n"); return error_code; /* AKA jump to recovery. */ } /* Read pre-processed public half of the kernel signing key. */ kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm); StatefulMemcpy(&st, &image->kernel_key_version, FIELD_LEN(kernel_key_version)); image->kernel_sign_key = (uint8_t*)st.remaining_buf; StatefulSkip(&st, kernel_sign_key_len); StatefulMemcpy(&st, image->header_checksum, FIELD_LEN(header_checksum)); /* Parse signing key into RSAPublicKey structure since it is * required multiple times. */ *kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key, kernel_sign_key_len); kernel_signature_len = siglen_map[kernel_sign_algorithm]; kernel_key_signature_len = siglen_map[firmware_sign_algorithm]; image->kernel_key_signature = (uint8_t*)st.remaining_buf; StatefulSkip(&st, kernel_key_signature_len); /* Only continue if preamble verification succeeds. */ /* TODO: should pass the remaining len into VerifyKernelPreamble() */ preamble_ptr = (const uint8_t*)st.remaining_buf; if ((error_code = VerifyKernelPreamble(*kernel_sign_key, preamble_ptr, kernel_sign_algorithm, &kernel_len))) { RSAPublicKeyFree(*kernel_sign_key); *kernel_sign_key = NULL; return error_code; /* AKA jump to recovery. */ } /* Copy preamble fields */ StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version)); StatefulMemcpy(&st, &image->kernel_len, FIELD_LEN(kernel_len)); StatefulMemcpy(&st, &image->bootloader_offset, FIELD_LEN(bootloader_offset)); StatefulMemcpy(&st, &image->bootloader_size, FIELD_LEN(bootloader_size)); StatefulMemcpy(&st, &image->padded_header_size, FIELD_LEN(padded_header_size)); image->kernel_signature = (uint8_t*)st.remaining_buf; StatefulSkip(&st, kernel_signature_len); image->preamble_signature = (uint8_t*)st.remaining_buf; return 0; } int VerifyKernel(const uint8_t* firmware_key_blob, const uint8_t* kernel_blob, const int dev_mode) { int error_code; int firmware_sign_algorithm; /* Firmware signing key algorithm. */ int kernel_sign_algorithm; /* Kernel Signing key algorithm. */ RSAPublicKey* kernel_sign_key; int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len, header_len; uint64_t kernel_len; const uint8_t* header_ptr; /* Pointer to header. */ const uint8_t* kernel_sign_key_ptr; /* Pointer to signing key. */ const uint8_t* preamble_ptr; /* Pointer to kernel preamble block. */ const uint8_t* kernel_ptr; /* Pointer to kernel signature/data. */ const uint8_t* kernel_signature; /* Note: All the offset calculations are based on struct FirmwareImage which * is defined in include/firmware_image.h. */ /* Compare magic bytes. */ if (SafeMemcmp(kernel_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) { debug("VerifyKernel: Kernel magic bytes not found.\n"); return VERIFY_KERNEL_WRONG_MAGIC; } header_ptr = kernel_blob + KERNEL_MAGIC_SIZE; /* Only continue if header verification succeeds. */ if ((error_code = VerifyKernelKeyHeader(firmware_key_blob, header_ptr, dev_mode, &firmware_sign_algorithm, &kernel_sign_algorithm, &header_len))) { debug("VerifyKernel: Kernel header verification failed.\n"); return error_code; /* AKA jump to recovery. */ } /* Parse signing key into RSAPublicKey structure since it is required multiple * times. */ kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm); kernel_sign_key_ptr = header_ptr + (FIELD_LEN(header_version) + FIELD_LEN(header_len) + FIELD_LEN(firmware_sign_algorithm) + FIELD_LEN(kernel_sign_algorithm) + FIELD_LEN(kernel_key_version)); kernel_sign_key = RSAPublicKeyFromBuf(kernel_sign_key_ptr, kernel_sign_key_len); kernel_signature_len = siglen_map[kernel_sign_algorithm]; kernel_key_signature_len = siglen_map[firmware_sign_algorithm]; /* Only continue if preamble verification succeeds. */ preamble_ptr = (header_ptr + header_len + kernel_key_signature_len); if ((error_code = VerifyKernelPreamble(kernel_sign_key, preamble_ptr, kernel_sign_algorithm, &kernel_len))) { debug("VerifyKernel: Kernel preamble verification failed.\n"); RSAPublicKeyFree(kernel_sign_key); return error_code; /* AKA jump to recovery. */ } /* Only continue if kernel data verification succeeds. */ kernel_ptr = (preamble_ptr + GetKernelPreambleLen(kernel_sign_algorithm) + kernel_signature_len); /* preamble signature. */ kernel_signature = kernel_ptr - 2 * kernel_signature_len; /* end of kernel * preamble. */ if ((error_code = VerifyKernelData(kernel_sign_key, /* Verification key */ kernel_signature, /* kernel signature */ kernel_ptr, /* Start of kernel data */ kernel_len, /* Length of kernel data. */ kernel_sign_algorithm))) { RSAPublicKeyFree(kernel_sign_key); return error_code; /* AKA jump to recovery. */ } RSAPublicKeyFree(kernel_sign_key); return 0; /* Success! */ } uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob) { uint8_t* kernel_ptr; uint16_t kernel_key_version; uint16_t kernel_version; uint16_t firmware_sign_algorithm; uint16_t kernel_sign_algorithm; int kernel_key_signature_len; int kernel_sign_key_len; kernel_ptr = kernel_blob + (FIELD_LEN(magic) + FIELD_LEN(header_version) + FIELD_LEN(header_len)); Memcpy(&firmware_sign_algorithm, kernel_ptr, sizeof(firmware_sign_algorithm)); kernel_ptr += FIELD_LEN(firmware_sign_algorithm); Memcpy(&kernel_sign_algorithm, kernel_ptr, sizeof(kernel_sign_algorithm)); kernel_ptr += FIELD_LEN(kernel_sign_algorithm); Memcpy(&kernel_key_version, kernel_ptr, sizeof(kernel_key_version)); if (firmware_sign_algorithm >= kNumAlgorithms) return 0; if (kernel_sign_algorithm >= kNumAlgorithms) return 0; kernel_key_signature_len = siglen_map[firmware_sign_algorithm]; kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm); kernel_ptr += (FIELD_LEN(kernel_key_version) + kernel_sign_key_len + FIELD_LEN(header_checksum) + kernel_key_signature_len); Memcpy(&kernel_version, kernel_ptr, sizeof(kernel_version)); return CombineUint16Pair(kernel_key_version, kernel_version); }