diff options
Diffstat (limited to 'firmware/lib')
28 files changed, 4548 insertions, 0 deletions
diff --git a/firmware/lib/cgptlib/cgptlib.c b/firmware/lib/cgptlib/cgptlib.c new file mode 100644 index 00000000..4856311a --- /dev/null +++ b/firmware/lib/cgptlib/cgptlib.c @@ -0,0 +1,148 @@ +/* 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. + */ + +#include "cgptlib.h" +#include "cgptlib_internal.h" +#include "crc32.h" +#include "gpt.h" +#include "utility.h" + +/* global types to compare against */ +const Guid guid_unused = GPT_ENT_TYPE_UNUSED; +const Guid guid_chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL; + + +int GptInit(GptData *gpt) { + int retval; + + gpt->modified = 0; + gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND; + gpt->current_priority = 999; + + retval = GptSanityCheck(gpt); + if (GPT_SUCCESS != retval) + return retval; + + GptRepair(gpt); + return GPT_SUCCESS; +} + + +int GptNextKernelEntry(GptData* gpt, uint64_t* start_sector, uint64_t* size) { + GptHeader* header = (GptHeader*)gpt->primary_header; + GptEntry* entries = (GptEntry*)gpt->primary_entries; + GptEntry* e; + int new_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND; + int new_prio = 0; + int i; + + /* If we already found a kernel, continue the scan at the current + * kernel's prioity, in case there is another kernel with the same + * priority. */ + if (gpt->current_kernel != CGPT_KERNEL_ENTRY_NOT_FOUND) { + for (i = gpt->current_kernel + 1; i < header->number_of_entries; i++) { + e = entries + i; + if (!IsKernelEntry(e)) + continue; + if (!(GetEntrySuccessful(e) || GetEntryTries(e))) + continue; + if (GetEntryPriority(e) == gpt->current_priority) { + gpt->current_kernel = i; + *start_sector = e->starting_lba; + *size = e->ending_lba - e->starting_lba + 1; + return GPT_SUCCESS; + } + } + } + + /* We're still here, so scan for the remaining kernel with the + * highest priority less than the previous attempt. */ + for (i = 0, e = entries; i < header->number_of_entries; i++, e++) { + int current_prio = GetEntryPriority(e); + if (!IsKernelEntry(e)) + continue; + if (!(GetEntrySuccessful(e) || GetEntryTries(e))) + continue; + if (current_prio >= gpt->current_priority) + continue; /* Already returned this kernel in a previous call */ + if (current_prio > new_prio) { + new_kernel = i; + new_prio = current_prio; + } + } + + /* Save what we found. Note that if we didn't find a new kernel, + * new_prio will still be -1, so future calls to this function will + * also fail. */ + gpt->current_kernel = new_kernel; + gpt->current_priority = new_prio; + + if (CGPT_KERNEL_ENTRY_NOT_FOUND == new_kernel) + return GPT_ERROR_NO_VALID_KERNEL; + + e = entries + new_kernel; + *start_sector = e->starting_lba; + *size = e->ending_lba - e->starting_lba + 1; + return GPT_SUCCESS; +} + + +int GptUpdateKernelEntry(GptData* gpt, uint32_t update_type) { + GptHeader* header = (GptHeader*)gpt->primary_header; + GptEntry* entries = (GptEntry*)gpt->primary_entries; + GptEntry* e = entries + gpt->current_kernel; + uint64_t previous_attr = e->attributes; + + if (gpt->current_kernel == CGPT_KERNEL_ENTRY_NOT_FOUND) + return GPT_ERROR_INVALID_UPDATE_TYPE; + if (!IsKernelEntry(e)) + return GPT_ERROR_INVALID_UPDATE_TYPE; + + switch (update_type) { + case GPT_UPDATE_ENTRY_TRY: { + /* Used up a try */ + int tries; + if (GetEntrySuccessful(e)) + return GPT_SUCCESS; /* Successfully booted this partition, so + * tries field is ignored. */ + tries = GetEntryTries(e); + if (tries > 1) { + /* Still have tries left */ + SetEntryTries(e, tries - 1); + break; + } + /* Out of tries, so drop through and mark partition bad. */ + } + case GPT_UPDATE_ENTRY_BAD: { + /* Giving up on this partition entirely. */ + e->attributes &= ~(CGPT_ATTRIBUTE_SUCCESSFUL_MASK | + CGPT_ATTRIBUTE_TRIES_MASK | + CGPT_ATTRIBUTE_PRIORITY_MASK); + break; + } + default: + return GPT_ERROR_INVALID_UPDATE_TYPE; + } + + /* If no change to attributes, we're done */ + if (e->attributes == previous_attr) + return GPT_SUCCESS; + + /* Update the CRCs */ + header->entries_crc32 = Crc32((const uint8_t *)entries, + header->size_of_entry * + header->number_of_entries); + header->header_crc32 = HeaderCrc(header); + gpt->modified |= GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1; + + /* Use the repair function to update the other copy of the GPT. + * This is a tad inefficient, but is much faster than the disk I/O + * to update the GPT on disk so it doesn't matter. */ + gpt->valid_headers = MASK_PRIMARY; + gpt->valid_entries = MASK_PRIMARY; + GptRepair(gpt); + + return GPT_SUCCESS; +} diff --git a/firmware/lib/cgptlib/cgptlib_internal.c b/firmware/lib/cgptlib/cgptlib_internal.c new file mode 100644 index 00000000..7faf3832 --- /dev/null +++ b/firmware/lib/cgptlib/cgptlib_internal.c @@ -0,0 +1,348 @@ +/* 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. + */ + +#include "cgptlib.h" +#include "cgptlib_internal.h" +#include "crc32.h" +#include "gpt.h" +#include "utility.h" + + +int CheckParameters(GptData *gpt) { + /* Currently, we only support 512-byte sector. In the future, we may support + * larger sector. */ + if (gpt->sector_bytes != 512) + return GPT_ERROR_INVALID_SECTOR_SIZE; + + /* The sector number of a drive should be reasonable. If the given value is + * too small to contain basic GPT structure (PMBR + Headers + Entries), + * the value is wrong. */ + if (gpt->drive_sectors < (1 + 2 * (1 + GPT_ENTRIES_SECTORS))) + return GPT_ERROR_INVALID_SECTOR_NUMBER; + + return GPT_SUCCESS; +} + + +uint32_t HeaderCrc(GptHeader* h) { + uint32_t crc32, original_crc32; + + /* Original CRC is calculated with the CRC field 0. */ + original_crc32 = h->header_crc32; + h->header_crc32 = 0; + crc32 = Crc32((const uint8_t *)h, h->size); + h->header_crc32 = original_crc32; + + return crc32; +} + + +int CheckHeader(GptHeader *h, int is_secondary, uint64_t drive_sectors) { + if (!h) + return 1; + + /* Make sure we're looking at a header of reasonable size before + * attempting to calculate CRC. */ + if (Memcmp(h->signature, GPT_HEADER_SIGNATURE, GPT_HEADER_SIGNATURE_SIZE)) + return 1; + if (h->revision != GPT_HEADER_REVISION) + return 1; + if (h->size < MIN_SIZE_OF_HEADER || h->size > MAX_SIZE_OF_HEADER) + return 1; + + /* Check CRC before looking at remaining fields */ + if (HeaderCrc(h) != h->header_crc32) + return 1; + + /* Reserved fields must be zero. */ + if (h->reserved_zero) + return 1; + + /* Could check that padding is zero, but that doesn't matter to us. */ + + /* If entry size is different than our struct, we won't be able to + * parse it. Technically, any size 2^N where N>=7 is valid. */ + if (h->size_of_entry != sizeof(GptEntry)) + return 1; + if ((h->number_of_entries < MIN_NUMBER_OF_ENTRIES) || + (h->number_of_entries > MAX_NUMBER_OF_ENTRIES) || + (h->number_of_entries * h->size_of_entry != TOTAL_ENTRIES_SIZE)) + return 1; + + /* Check locations for the header and its entries. The primary + * immediately follows the PMBR, and is followed by its entries. + * The secondary is at the end of the drive, preceded by its + * entries. */ + if (is_secondary) { + if (h->my_lba != drive_sectors - 1) + return 1; + if (h->entries_lba != h->my_lba - GPT_ENTRIES_SECTORS) + return 1; + } else { + if (h->my_lba != 1) + return 1; + if (h->entries_lba != h->my_lba + 1) + return 1; + } + + /* FirstUsableLBA must be after the end of the primary GPT table + * array. LastUsableLBA must be before the start of the secondary + * GPT table array. FirstUsableLBA <= LastUsableLBA. */ + if (h->first_usable_lba < 2 + GPT_ENTRIES_SECTORS) + return 1; + if (h->last_usable_lba >= drive_sectors - 1 - GPT_ENTRIES_SECTORS) + return 1; + if (h->first_usable_lba > h->last_usable_lba) + return 1; + + /* Success */ + return 0; +} + + +/* Return non-zero if the entry is unused, 0 if it is used. */ +int IsUnusedEntry(const GptEntry* e) { + static Guid zero = {{{0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0}}}}; + return !Memcmp(&zero, (const uint8_t*)(&e->type), sizeof(zero)); +} + +/* Returns non-zero if the entry is a Chrome OS kernel partition, else 0. */ +int IsKernelEntry(const GptEntry* e) { + static Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL; + return !Memcmp(&e->type, &chromeos_kernel, sizeof(Guid)); +} + + +int CheckEntries(GptEntry* entries, GptHeader* h, uint64_t drive_sectors) { + + GptEntry* entry; + uint32_t crc32; + int i; + + /* Check CRC before examining entries. */ + crc32 = Crc32((const uint8_t *)entries, + h->size_of_entry * h->number_of_entries); + if (crc32 != h->entries_crc32) + return 1; + + /* Check all entries. */ + for (i = 0, entry = entries; i < h->number_of_entries; i++, entry++) { + GptEntry* e2; + int i2; + + if (IsUnusedEntry(entry)) + continue; + + /* Entry must be in valid region. */ + if ((entry->starting_lba < h->first_usable_lba) || + (entry->ending_lba > h->last_usable_lba) || + (entry->ending_lba < entry->starting_lba)) + return 1; + + /* Entry must not overlap other entries. */ + for (i2 = 0, e2 = entries; i2 < h->number_of_entries; i2++, e2++) { + if (i2 == i || IsUnusedEntry(e2)) + continue; + + if ((entry->starting_lba >= e2->starting_lba) && + (entry->starting_lba <= e2->ending_lba)) + return 1; + if ((entry->ending_lba >= e2->starting_lba) && + (entry->ending_lba <= e2->ending_lba)) + return 1; + } + } + + /* Success */ + return 0; +} + + +/* Returns 0 if the GptHeaders are the same for all fields which don't + * differ between the primary and secondary headers - that is, all + * fields other than: + * + * my_lba + * alternate_lba + * entries_lba */ +int HeaderFieldsSame(GptHeader *h1, GptHeader *h2) { + if (Memcmp(h1->signature, h2->signature, sizeof(h1->signature))) + return 1; + if (h1->revision != h2->revision) + return 1; + if (h1->size != h2->size) + return 1; + if (h1->reserved_zero != h2->reserved_zero) + return 1; + if (h1->first_usable_lba != h2->first_usable_lba) + return 1; + if (h1->last_usable_lba != h2->last_usable_lba) + return 1; + if (Memcmp(&h1->disk_uuid, &h2->disk_uuid, sizeof(Guid))) + return 1; + if (h1->number_of_entries != h2->number_of_entries) + return 1; + if (h1->size_of_entry != h2->size_of_entry) + return 1; + if (h1->entries_crc32 != h2->entries_crc32) + return 1; + + return 0; +} + + +int GptSanityCheck(GptData *gpt) { + int retval; + GptHeader* header1 = (GptHeader*)(gpt->primary_header); + GptHeader* header2 = (GptHeader*)(gpt->secondary_header); + GptEntry* entries1 = (GptEntry*)(gpt->primary_entries); + GptEntry* entries2 = (GptEntry*)(gpt->secondary_entries); + GptHeader* goodhdr = NULL; + + gpt->valid_headers = 0; + gpt->valid_entries = 0; + + retval = CheckParameters(gpt); + if (retval != GPT_SUCCESS) + return retval; + + /* Check both headers; we need at least one valid header. */ + if (0 == CheckHeader(header1, 0, gpt->drive_sectors)) { + gpt->valid_headers |= MASK_PRIMARY; + goodhdr = header1; + } + if (0 == CheckHeader(header2, 1, gpt->drive_sectors)) { + gpt->valid_headers |= MASK_SECONDARY; + if (!goodhdr) + goodhdr = header2; + } + + if (!gpt->valid_headers) + return GPT_ERROR_INVALID_HEADERS; + + /* Checks if entries are valid. + * + * Note that we use the same header in both checks. This way we'll + * catch the case where (header1,entries1) and (header2,entries2) + * are both valid, but (entries1 != entries2). */ + if (0 == CheckEntries(entries1, goodhdr, gpt->drive_sectors)) + gpt->valid_entries |= MASK_PRIMARY; + if (0 == CheckEntries(entries2, goodhdr, gpt->drive_sectors)) + gpt->valid_entries |= MASK_SECONDARY; + + /* If both headers are good but neither entries were good, check the + * entries with the secondary header. */ + if (MASK_BOTH == gpt->valid_headers && !gpt->valid_entries) { + if (0 == CheckEntries(entries1, header2, gpt->drive_sectors)) + gpt->valid_entries |= MASK_PRIMARY; + if (0 == CheckEntries(entries2, header2, gpt->drive_sectors)) + gpt->valid_entries |= MASK_SECONDARY; + if (gpt->valid_entries) { + /* Sure enough, header2 had a good CRC for one of the entries. Mark + * header1 invalid, so we'll update its entries CRC. */ + gpt->valid_headers &= ~MASK_PRIMARY; + goodhdr = header2; + } + } + + if (!gpt->valid_entries) + return GPT_ERROR_INVALID_ENTRIES; + + /* Now that we've determined which header contains a good CRC for + * the entries, make sure the headers are otherwise identical. */ + if (MASK_BOTH == gpt->valid_headers && + 0 != HeaderFieldsSame(header1, header2)) + gpt->valid_headers &= ~MASK_SECONDARY; + + return GPT_SUCCESS; +} + + +void GptRepair(GptData *gpt) { + GptHeader* header1 = (GptHeader*)(gpt->primary_header); + GptHeader* header2 = (GptHeader*)(gpt->secondary_header); + GptEntry* entries1 = (GptEntry*)(gpt->primary_entries); + GptEntry* entries2 = (GptEntry*)(gpt->secondary_entries); + int entries_size; + + /* Need at least one good header and one good set of entries. */ + if (MASK_NONE == gpt->valid_headers || MASK_NONE == gpt->valid_entries) + return; + + /* Repair headers if necessary */ + if (MASK_PRIMARY == gpt->valid_headers) { + /* Primary is good, secondary is bad */ + Memcpy(header2, header1, sizeof(GptHeader)); + header2->my_lba = gpt->drive_sectors - 1; + header2->alternate_lba = 1; + header2->entries_lba = header2->my_lba - GPT_ENTRIES_SECTORS; + header2->header_crc32 = HeaderCrc(header2); + gpt->modified |= GPT_MODIFIED_HEADER2; + } + else if (MASK_SECONDARY == gpt->valid_headers) { + /* Secondary is good, primary is bad */ + Memcpy(header1, header2, sizeof(GptHeader)); + header1->my_lba = 1; + header1->alternate_lba = gpt->drive_sectors - 1; + header1->entries_lba = header1->my_lba + 1; + header1->header_crc32 = HeaderCrc(header1); + gpt->modified |= GPT_MODIFIED_HEADER1; + } + gpt->valid_headers = MASK_BOTH; + + /* Repair entries if necessary */ + entries_size = header1->size_of_entry * header1->number_of_entries; + if (MASK_PRIMARY == gpt->valid_entries) { + /* Primary is good, secondary is bad */ + Memcpy(entries2, entries1, entries_size); + gpt->modified |= GPT_MODIFIED_ENTRIES2; + } + else if (MASK_SECONDARY == gpt->valid_entries) { + /* Secondary is good, primary is bad */ + Memcpy(entries1, entries2, entries_size); + gpt->modified |= GPT_MODIFIED_ENTRIES1; + } + gpt->valid_entries = MASK_BOTH; +} + + +int GetEntrySuccessful(const GptEntry* e) { + return (e->attributes & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >> + CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET; +} + + +int GetEntryPriority(const GptEntry* e) { + return (e->attributes & CGPT_ATTRIBUTE_PRIORITY_MASK) >> + CGPT_ATTRIBUTE_PRIORITY_OFFSET; +} + + +int GetEntryTries(const GptEntry* e) { + return (e->attributes & CGPT_ATTRIBUTE_TRIES_MASK) >> + CGPT_ATTRIBUTE_TRIES_OFFSET; +} + + +void SetEntrySuccessful(GptEntry* e, int successful) { + if (successful) + e->attributes |= CGPT_ATTRIBUTE_SUCCESSFUL_MASK; + else + e->attributes &= ~CGPT_ATTRIBUTE_SUCCESSFUL_MASK; +} + + +void SetEntryPriority(GptEntry* e, int priority) { + e->attributes &= ~CGPT_ATTRIBUTE_PRIORITY_MASK; + e->attributes |= ((uint64_t)priority << CGPT_ATTRIBUTE_PRIORITY_OFFSET) & + CGPT_ATTRIBUTE_PRIORITY_MASK; +} + + +void SetEntryTries(GptEntry* e, int tries) { + e->attributes &= ~CGPT_ATTRIBUTE_TRIES_MASK; + e->attributes |= ((uint64_t)tries << CGPT_ATTRIBUTE_TRIES_OFFSET) & + CGPT_ATTRIBUTE_TRIES_MASK; +} diff --git a/firmware/lib/cgptlib/crc32.c b/firmware/lib/cgptlib/crc32.c new file mode 100755 index 00000000..9dacd178 --- /dev/null +++ b/firmware/lib/cgptlib/crc32.c @@ -0,0 +1,108 @@ +/* CRC32 implementation by Gary S. Brown. See license claim below. */ + +/* ============================================================= */ +/* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */ +/* code or tables extracted from it, as desired without restriction. */ +/* */ +/* First, the polynomial itself and its table of feedback terms. The */ +/* polynomial is */ +/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ +/* */ +/* Note that we take it "backwards" and put the highest-order term in */ +/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +/* the MSB being 1. */ +/* */ +/* Note that the usual hardware shift register implementation, which */ +/* is what we're using (we're merely optimizing it by doing eight-bit */ +/* chunks at a time) shifts bits into the lowest-order term. In our */ +/* implementation, that means shifting towards the right. Why do we */ +/* do it this way? Because the calculated CRC must be transmitted in */ +/* order from highest-order term to lowest-order term. UARTs transmit */ +/* characters in order from LSB to MSB. By storing the CRC this way, */ +/* we hand it to the UART in the order low-byte to high-byte; the UART */ +/* sends each low-bit to hight-bit; and the result is transmission bit */ +/* by bit from highest- to lowest-order term without requiring any bit */ +/* shuffling on our part. Reception works similarly. */ +/* */ +/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +/* */ +/* The table can be generated at runtime if desired; code to do so */ +/* is shown later. It might not be obvious, but the feedback */ +/* terms simply represent the results of eight shift/xor opera- */ +/* tions for all combinations of data and CRC register values. */ +/* */ +/* The values must be right-shifted by eight bits by the "updcrc" */ +/* logic; the shift must be unsigned (bring in zeroes). On some */ +/* hardware you could probably optimize the shift in assembler by */ +/* using byte-swap instructions. */ +/* polynomial $edb88320 */ +/* */ +/* -------------------------------------------------------------------- */ +#include "crc32.h" + +static uint32_t crc32_tab[] = { + 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U, + 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U, + 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U, + 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU, + 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U, + 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U, + 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U, + 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU, + 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U, + 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU, + 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U, + 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U, + 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U, + 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU, + 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU, + 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U, + 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU, + 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U, + 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U, + 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U, + 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU, + 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U, + 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U, + 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU, + 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U, + 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U, + 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U, + 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U, + 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U, + 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU, + 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU, + 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U, + 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U, + 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU, + 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU, + 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U, + 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU, + 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U, + 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU, + 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U, + 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU, + 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U, + 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U, + 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU, + 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U, + 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U, + 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U, + 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U, + 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U, + 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U, + 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU, + 0x2d02ef8dU +}; + +/* Returns a 32-bit CRC of the contents of the buffer. */ +uint32_t Crc32(const void *buffer, uint32_t len) { + uint8_t *byte = (uint8_t*)buffer; + uint32_t i; + uint32_t value = ~0U; + + for (i = 0; i < len; ++i) + value = crc32_tab[(value ^ byte[i]) & 0xff] ^ (value >> 8); + return value ^ ~0U; +} diff --git a/firmware/lib/cgptlib/include/cgptlib.h b/firmware/lib/cgptlib/include/cgptlib.h new file mode 100644 index 00000000..4eadc817 --- /dev/null +++ b/firmware/lib/cgptlib/include/cgptlib.h @@ -0,0 +1,115 @@ +/* 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. + */ + +#ifndef VBOOT_REFERENCE_CGPTLIB_H_ +#define VBOOT_REFERENCE_CGPTLIB_H_ + +#include "sysincludes.h" + +enum { + GPT_SUCCESS = 0, + GPT_ERROR_NO_VALID_KERNEL, + GPT_ERROR_INVALID_HEADERS, + GPT_ERROR_INVALID_ENTRIES, + GPT_ERROR_INVALID_SECTOR_SIZE, + GPT_ERROR_INVALID_SECTOR_NUMBER, + GPT_ERROR_INVALID_UPDATE_TYPE, +}; + +/* Bit masks for GptData.modified field. */ +#define GPT_MODIFIED_HEADER1 0x01 +#define GPT_MODIFIED_HEADER2 0x02 +#define GPT_MODIFIED_ENTRIES1 0x04 +#define GPT_MODIFIED_ENTRIES2 0x08 + +#define TOTAL_ENTRIES_SIZE 16384 /* Size of GptData.primary_entries + * and secondary_entries: 128 + * bytes/entry * 128 entries. */ + +/* The 'update_type' of GptUpdateKernelEntry() + * We expose TRY and BAD only because those are what verified boot needs. + * For more precise control on GPT attribute bits, please refer to + * gpt_internal.h */ +enum { + GPT_UPDATE_ENTRY_TRY = 1, + /* System will be trying to boot the currently selected kernel partition. + * Update its try count if necessary. */ + GPT_UPDATE_ENTRY_BAD = 2, + /* The currently selected kernel partition failed validation. Mark entry as + * invalid. */ +}; + +typedef struct { + /* Fill in the following fields before calling GptInit() */ + uint8_t *primary_header; /* GPT primary header, from sector 1 of disk + * (size: 512 bytes) */ + uint8_t *secondary_header; /* GPT secondary header, from last sector of + * disk (size: 512 bytes) */ + uint8_t *primary_entries; /* primary GPT table, follows primary header + * (size: 16 KB) */ + uint8_t *secondary_entries; /* secondary GPT table, precedes secondary + * header (size: 16 KB) */ + uint32_t sector_bytes; /* Size of a LBA sector, in bytes */ + uint64_t drive_sectors; /* Size of drive in LBA sectors, in sectors */ + + /* Outputs */ + uint8_t modified; /* Which inputs have been modified? + * 0x01 = header1 + * 0x02 = header2 + * 0x04 = table1 + * 0x08 = table2 */ + int current_kernel; /* the current chromeos kernel index in partition table. + * -1 means not found on drive. */ + + /* Internal variables */ + uint32_t valid_headers, valid_entries; + int current_priority; +} GptData; + +int GptInit(GptData* gpt); +/* Initializes the GPT data structure's internal state. The following fields + * must be filled before calling this function: + * + * primary_header + * secondary_header + * primary_entries + * secondary_entries + * sector_bytes + * drive_sectors + * + * On return the modified field may be set, if the GPT data has been modified + * and should be written to disk. + * + * Returns GPT_SUCCESS if successful, non-zero if error: + * GPT_ERROR_INVALID_HEADERS, both partition table headers are invalid, enters + * recovery mode, + * GPT_ERROR_INVALID_ENTRIES, both partition table entries are invalid, enters + * recovery mode, + * GPT_ERROR_INVALID_SECTOR_SIZE, size of a sector is not supported, + * GPT_ERROR_INVALID_SECTOR_NUMBER, number of sectors in drive is invalid (too + * small) */ + +int GptNextKernelEntry(GptData* gpt, uint64_t* start_sector, uint64_t* size); +/* Provides the location of the next kernel partition, in order of decreasing + * priority. On return the start_sector parameter contains the LBA sector + * for the start of the kernel partition, and the size parameter contains the + * size of the kernel partition in LBA sectors. gpt.current_kernel contains + * the partition index of the current chromeos kernel partition. + * + * Returns GPT_SUCCESS if successful, else + * GPT_ERROR_NO_VALID_KERNEL, no avaliable kernel, enters recovery mode */ + +int GptUpdateKernelEntry(GptData* gpt, uint32_t update_type); +/* Updates the kernel entry with the specified index, using the specified type + * of update (GPT_UPDATE_ENTRY_*). + * + * On return the modified field may be set, if the GPT data has been modified + * and should be written to disk. + * + * Returns GPT_SUCCESS if successful, else + * GPT_ERROR_INVALID_UPDATE_TYPE, invalid 'update_type' is given. + */ + +#endif /* VBOOT_REFERENCE_CGPTLIB_H_ */ diff --git a/firmware/lib/cgptlib/include/cgptlib_internal.h b/firmware/lib/cgptlib/include/cgptlib_internal.h new file mode 100644 index 00000000..f4a4d199 --- /dev/null +++ b/firmware/lib/cgptlib/include/cgptlib_internal.h @@ -0,0 +1,115 @@ +/* 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. + */ + +#ifndef VBOOT_REFERENCE_CGPTLIB_INTERNAL_H_ +#define VBOOT_REFERENCE_CGPTLIB_INTERNAL_H_ + +#include "sysincludes.h" +#include "cgptlib.h" +#include "gpt.h" + +/* If gpt->current_kernel is this value, means either: + * 1. an initial value before scanning GPT entries, + * 2. after scanning, no any valid kernel is found. + */ +#define CGPT_KERNEL_ENTRY_NOT_FOUND (-1) + +/* Bit definitions and masks for GPT attributes. + * + * 63-61 -- (reserved) + * 60 -- read-only + * 59-57 -- (reserved) + * 56 -- success + * 55-52 -- tries + * 51-48 -- priority + * 47-2 -- UEFI: reserved for future use + * 1 -- UEFI: partition is not mapped + * 0 -- UEFI: partition is required + */ +#define CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET 56 +#define CGPT_ATTRIBUTE_MAX_SUCCESSFUL (1ULL) +#define CGPT_ATTRIBUTE_SUCCESSFUL_MASK (CGPT_ATTRIBUTE_MAX_SUCCESSFUL << \ + CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET) + +#define CGPT_ATTRIBUTE_TRIES_OFFSET 52 +#define CGPT_ATTRIBUTE_MAX_TRIES (15ULL) +#define CGPT_ATTRIBUTE_TRIES_MASK (CGPT_ATTRIBUTE_MAX_TRIES << \ + CGPT_ATTRIBUTE_TRIES_OFFSET) + +#define CGPT_ATTRIBUTE_PRIORITY_OFFSET 48 +#define CGPT_ATTRIBUTE_MAX_PRIORITY (15ULL) +#define CGPT_ATTRIBUTE_PRIORITY_MASK (CGPT_ATTRIBUTE_MAX_PRIORITY << \ + CGPT_ATTRIBUTE_PRIORITY_OFFSET) + +/* Defines ChromeOS-specific limitation on GPT */ +#define MIN_SIZE_OF_HEADER 92 +#define MAX_SIZE_OF_HEADER 512 +#define MIN_SIZE_OF_ENTRY 128 +#define MAX_SIZE_OF_ENTRY 512 +#define SIZE_OF_ENTRY_MULTIPLE 8 +#define MIN_NUMBER_OF_ENTRIES 32 +#define MAX_NUMBER_OF_ENTRIES 512 + +/* Defines GPT sizes */ +#define GPT_PMBR_SECTOR 1 /* size (in sectors) of PMBR */ +#define GPT_HEADER_SECTOR 1 +#define GPT_ENTRIES_SECTORS 32 /* assume sector size if 512 bytes, then + * (TOTAL_ENTRIES_SIZE / 512) = 32 */ + +/* alias name of index in internal array for primary and secondary header and + * entries. */ +enum { + PRIMARY = 0, + SECONDARY = 1, + MASK_NONE = 0, + MASK_PRIMARY = 1, + MASK_SECONDARY = 2, + MASK_BOTH = 3, +}; + +/* Verify GptData parameters are sane. */ +int CheckParameters(GptData* gpt); + +/* Check header fields. + * + * Returns 0 if header is valid, 1 if invalid. */ +int CheckHeader(GptHeader* h, int is_secondary, uint64_t drive_sectors); + +/* Calculate and return the header CRC. */ +uint32_t HeaderCrc(GptHeader* h); + +/* Check entries. + * + * Returns 0 if entries are valid, 1 if invalid. */ +int CheckEntries(GptEntry* entries, GptHeader* h, uint64_t drive_sectors); + +/* Check GptData, headers, entries. + * + * If successful, sets gpt->valid_headers and gpt->valid_entries and returns + * GPT_SUCCESS. + * + * On error, returns a GPT_ERROR_* return code. */ +int GptSanityCheck(GptData* gpt); + +/* Repairs GPT data by copying from one set of valid headers/entries to the + * other. Assumes GptSanityCheck() has been run to determine which headers + * and/or entries are already valid. */ +void GptRepair(GptData* gpt); + +/* Getters and setters for partition attribute fields. */ +int GetEntrySuccessful(const GptEntry* e); +int GetEntryPriority(const GptEntry* e); +int GetEntryTries(const GptEntry* e); +void SetEntrySuccessful(GptEntry* e, int successful); +void SetEntryPriority(GptEntry* e, int priority); +void SetEntryTries(GptEntry* e, int tries); + +/* Return 1 if the entry is unused, 0 if it is used. */ +int IsUnusedEntry(const GptEntry* e); + +/* Returns 1 if the entry is a Chrome OS kernel partition, else 0. */ +int IsKernelEntry(const GptEntry* e); + +#endif /* VBOOT_REFERENCE_CGPTLIB_INTERNAL_H_ */ diff --git a/firmware/lib/cgptlib/include/crc32.h b/firmware/lib/cgptlib/include/crc32.h new file mode 100644 index 00000000..23361138 --- /dev/null +++ b/firmware/lib/cgptlib/include/crc32.h @@ -0,0 +1,12 @@ +/* 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. + */ +#ifndef VBOOT_REFERENCE_GPT_CRC32_H_ +#define VBOOT_REFERENCE_GPT_CRC32_H_ + +#include "sysincludes.h" + +uint32_t Crc32(const void *buffer, uint32_t len); + +#endif /* VBOOT_REFERENCE_GPT_CRC32_H_ */ diff --git a/firmware/lib/cgptlib/include/gpt.h b/firmware/lib/cgptlib/include/gpt.h new file mode 100644 index 00000000..a65317fb --- /dev/null +++ b/firmware/lib/cgptlib/include/gpt.h @@ -0,0 +1,104 @@ +/* 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. + * + * Defines EFI related structure. See more details in EFI 2.3 spec. + * + * To download EFI standard, please visit UEFI homepage: + * http://www.uefi.org/ + */ +#ifndef VBOOT_REFERENCE_CGPTLIB_GPT_H_ +#define VBOOT_REFERENCE_CGPTLIB_GPT_H_ + +#include "sysincludes.h" + +#define GPT_HEADER_SIGNATURE "EFI PART" +#define GPT_HEADER_SIGNATURE_SIZE sizeof(GPT_HEADER_SIGNATURE) +#define GPT_HEADER_REVISION 0x00010000 + +/* The first 3 numbers should be stored in network-endian format + * according to the GUID RFC. The UEFI spec appendix A claims they + * should be stored in little-endian format. But they need to be + * _displayed_ in network-endian format, which is also how they're + * documented in the specs. + * + * Since what we have here are little-endian constants, they're + * byte-swapped from the normal display order. */ +#define GPT_ENT_TYPE_UNUSED \ + {{{0x00000000,0x0000,0x0000,0x00,0x00,{0x00,0x00,0x00,0x00,0x00,0x00}}}} +#define GPT_ENT_TYPE_EFI \ + {{{0xc12a7328,0xf81f,0x11d2,0xba,0x4b,{0x00,0xa0,0xc9,0x3e,0xc9,0x3b}}}} +#define GPT_ENT_TYPE_CHROMEOS_KERNEL \ + {{{0xfe3a2a5d,0x4f32,0x41a7,0xb7,0x25,{0xac,0xcc,0x32,0x85,0xa3,0x09}}}} +#define GPT_ENT_TYPE_CHROMEOS_ROOTFS \ + {{{0x3cb8e202,0x3b7e,0x47dd,0x8a,0x3c,{0x7f,0xf2,0xa1,0x3c,0xfc,0xec}}}} +#define GPT_ENT_TYPE_CHROMEOS_RESERVED \ + {{{0x2e0a753d,0x9e48,0x43b0,0x83,0x37,{0xb1,0x51,0x92,0xcb,0x1b,0x5e}}}} +#define GPT_ENT_TYPE_LINUX_DATA \ + {{{0xebd0a0a2,0xb9e5,0x4433,0x87,0xc0,{0x68,0xb6,0xb7,0x26,0x99,0xc7}}}} + + +#define UUID_NODE_LEN 6 +#define GUID_SIZE 16 + +/* GUID definition. + * Defined in appendix A of EFI standard. + */ +typedef struct { + union { + struct { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_high_and_version; + uint8_t clock_seq_high_and_reserved; + uint8_t clock_seq_low; + uint8_t node[UUID_NODE_LEN]; + } Uuid; + uint8_t raw[GUID_SIZE]; + } u; +} __attribute__((packed)) Guid; + +/* Some constant values */ +extern const Guid guid_unused; +extern const Guid guid_chromeos_kernel; + +/* GPT header defines how many partitions exist on a drive and sectors managed. + * For every drive device, there are 2 headers, primary and secondary. + * Most of fields are duplicated except my_lba and entries_lba. + * + * You may find more details in chapter 5 of EFI standard. + */ +typedef struct { + char signature[8]; + uint32_t revision; + uint32_t size; + uint32_t header_crc32; + uint32_t reserved_zero; + uint64_t my_lba; + uint64_t alternate_lba; + uint64_t first_usable_lba; + uint64_t last_usable_lba; + Guid disk_uuid; + uint64_t entries_lba; + uint32_t number_of_entries; + uint32_t size_of_entry; + uint32_t entries_crc32; + uint8_t reserved_padding[]; /* entire sector reserved for header */ +} __attribute__((packed)) GptHeader; + +/* GPT partition entry defines the starting and ending LBAs of a partition. + * It also contains the unique GUID, type, and attribute bits. + * + * You may find more details in chapter 5 of EFI standard. + */ +typedef struct { + Guid type; + Guid unique; + uint64_t starting_lba; + uint64_t ending_lba; + uint64_t attributes; + uint16_t name[36]; /* UTF-16 encoded partition name */ + uint8_t reserved[]; /* nothing, really */ +} __attribute__((packed)) GptEntry; + +#endif /* VBOOT_REFERENCE_CGPTLIB_GPT_H_ */ diff --git a/firmware/lib/cryptolib/README b/firmware/lib/cryptolib/README new file mode 100644 index 00000000..e576bb7b --- /dev/null +++ b/firmware/lib/cryptolib/README @@ -0,0 +1,3 @@ +This contains the implementation for the crypto library. This includes +implementations for SHA1, SHA256, SHA512, and RSA signature verification +(for PKCS #1 v1.5 signatures). diff --git a/firmware/lib/cryptolib/include/cryptolib.h b/firmware/lib/cryptolib/include/cryptolib.h new file mode 100644 index 00000000..b65a71db --- /dev/null +++ b/firmware/lib/cryptolib/include/cryptolib.h @@ -0,0 +1,15 @@ +/* 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. + * + * Firmware Cryptolib includes. + */ + +#ifndef VBOOT_REFERENCE_CRYPTOLIB_H_ +#define VBOOT_REFERENCE_CRYPTOLIB_H_ + +#include "padding.h" +#include "rsa.h" +#include "sha.h" + +#endif /* VBOOT_REFERENCE_CRYPTOLIB_H_ */ diff --git a/firmware/lib/cryptolib/include/padding.h b/firmware/lib/cryptolib/include/padding.h new file mode 100644 index 00000000..59b8dc39 --- /dev/null +++ b/firmware/lib/cryptolib/include/padding.h @@ -0,0 +1,40 @@ +/* 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. + */ + +#ifndef VBOOT_REFERENCE_PADDING_H_ +#define VBOOT_REFERENCE_PADDING_H_ + +#ifndef VBOOT_REFERENCE_CRYPTOLIB_H_ +#error "Do not include this file directly. Use cryptolib.h instead." +#endif + +#include "sysincludes.h" + +extern const uint8_t paddingRSA1024_SHA1[]; +extern const uint8_t paddingRSA1024_SHA256[]; +extern const uint8_t paddingRSA1024_SHA512[]; +extern const uint8_t paddingRSA2048_SHA1[]; +extern const uint8_t paddingRSA2048_SHA256[]; +extern const uint8_t paddingRSA2048_SHA512[]; +extern const uint8_t paddingRSA4096_SHA1[]; +extern const uint8_t paddingRSA4096_SHA256[]; +extern const uint8_t paddingRSA4096_SHA512[]; +extern const uint8_t paddingRSA8192_SHA1[]; +extern const uint8_t paddingRSA8192_SHA256[]; +extern const uint8_t paddingRSA8192_SHA512[]; + +extern const int kNumAlgorithms; + +extern const int digestinfo_size_map[]; +extern const int siglen_map[]; +extern const uint8_t* padding_map[]; +extern const int padding_size_map[]; +extern const int hash_type_map[]; +extern const int hash_size_map[]; +extern const int hash_blocksize_map[]; +extern const uint8_t* hash_digestinfo_map[]; +extern const char* algo_strings[]; + +#endif /* VBOOT_REFERENCE_PADDING_H_ */ diff --git a/firmware/lib/cryptolib/include/rsa.h b/firmware/lib/cryptolib/include/rsa.h new file mode 100644 index 00000000..2d3ee955 --- /dev/null +++ b/firmware/lib/cryptolib/include/rsa.h @@ -0,0 +1,92 @@ +/* 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. + */ + +#ifndef VBOOT_REFERENCE_RSA_H_ +#define VBOOT_REFERENCE_RSA_H_ + +#ifndef VBOOT_REFERENCE_CRYPTOLIB_H_ +#error "Do not include this file directly. Use cryptolib.h instead." +#endif + +#include "sysincludes.h" + +#define RSA1024NUMBYTES 128 /* 1024 bit key length */ +#define RSA2048NUMBYTES 256 /* 2048 bit key length */ +#define RSA4096NUMBYTES 512 /* 4096 bit key length */ +#define RSA8192NUMBYTES 1024 /* 8192 bit key length */ + +#define RSA1024NUMWORDS (RSA1024NUMBYTES / sizeof(uint32_t)) +#define RSA2048NUMWORDS (RSA2048NUMBYTES / sizeof(uint32_t)) +#define RSA4096NUMWORDS (RSA4096NUMBYTES / sizeof(uint32_t)) +#define RSA8192NUMWORDS (RSA8192NUMBYTES / sizeof(uint32_t)) + +typedef struct RSAPublicKey { + uint32_t len; /* Length of n[] in number of uint32_t */ + uint32_t n0inv; /* -1 / n[0] mod 2^32 */ + uint32_t* n; /* modulus as little endian array */ + uint32_t* rr; /* R^2 as little endian array */ + int algorithm; /* Algorithm to use when verifying binaries with the key */ +} RSAPublicKey; + +/* Verify a RSA PKCS1.5 signature [sig] of [sig_type] and length [sig_len] + * against an expected [hash] using [key]. Returns 0 on failure, 1 on success. + */ +int RSAVerify(const RSAPublicKey *key, + const uint8_t* sig, + const int sig_len, + const uint8_t sig_type, + const uint8_t* hash); + +/* Perform RSA signature verification on [buf] of length [len] against expected + * signature [sig] using signature algorithm [algorithm]. The public key used + * for verification can either be in the form of a pre-process key blob + * [key_blob] or RSAPublicKey structure [key]. One of [key_blob] or [key] must + * be non-NULL, and the other NULL or the function will fail. + * + * Returns 1 on verification success, 0 on verification failure or invalid + * arguments. + * + * Note: This function is for use in the firmware and assumes all pointers point + * to areas in the memory of the right size. + * + */ +int RSAVerifyBinary_f(const uint8_t* key_blob, + const RSAPublicKey* key, + const uint8_t* buf, + uint64_t len, + const uint8_t* sig, + int algorithm); + +/* Version of RSAVerifyBinary_f() where instead of the raw binary blob + * of data, its digest is passed as the argument. */ +int RSAVerifyBinaryWithDigest_f(const uint8_t* key_blob, + const RSAPublicKey* key, + const uint8_t* digest, + const uint8_t* sig, + int algorithm); + + +/* ----Some additional utility functions for RSA.---- */ + +/* Returns the size of a pre-processed RSA public key in bytes with algorithm + * [algorithm]. */ +int RSAProcessedKeySize(int algorithm); + +/* Allocate a new RSAPublicKey structure and initialize its pointer fields to + * NULL */ +RSAPublicKey* RSAPublicKeyNew(void); + +/* Deep free the contents of [key]. */ +void RSAPublicKeyFree(RSAPublicKey* key); + +/* Create a RSAPublic key structure from binary blob [buf] of length + * [len]. + * + * Caller owns the returned key and must free it. + */ +RSAPublicKey* RSAPublicKeyFromBuf(const uint8_t* buf, int len); + + +#endif /* VBOOT_REFERENCE_RSA_H_ */ diff --git a/firmware/lib/cryptolib/include/sha.h b/firmware/lib/cryptolib/include/sha.h new file mode 100644 index 00000000..46e417d9 --- /dev/null +++ b/firmware/lib/cryptolib/include/sha.h @@ -0,0 +1,128 @@ +/* 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. + */ + +/* SHA-1, 256 and 512 functions. */ + +#ifndef VBOOT_REFERENCE_SHA_H_ +#define VBOOT_REFERENCE_SHA_H_ + +#ifndef VBOOT_REFERENCE_CRYPTOLIB_H_ +#error "Do not include this file directly. Use cryptolib.h instead." +#endif + +#include "sysincludes.h" + +#define SHA1_DIGEST_SIZE 20 +#define SHA1_BLOCK_SIZE 64 + +#define SHA256_DIGEST_SIZE 32 +#define SHA256_BLOCK_SIZE 64 + +#define SHA512_DIGEST_SIZE 64 +#define SHA512_BLOCK_SIZE 128 + +typedef struct SHA1_CTX { + uint64_t count; + uint32_t state[5]; +#if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN) + union { + uint8_t b[64]; + uint32_t w[16]; + } buf; +#else + uint8_t buf[64]; +#endif +} SHA1_CTX; + +typedef struct { + uint32_t h[8]; + uint32_t tot_len; + uint32_t len; + uint8_t block[2 * SHA256_BLOCK_SIZE]; + uint8_t buf[SHA256_DIGEST_SIZE]; /* Used for storing the final digest. */ +} SHA256_CTX; + +typedef struct { + uint64_t h[8]; + uint32_t tot_len; + uint32_t len; + uint8_t block[2 * SHA512_BLOCK_SIZE]; + uint8_t buf[SHA512_DIGEST_SIZE]; /* Used for storing the final digest. */ +} SHA512_CTX; + + +void SHA1_init(SHA1_CTX* ctx); +void SHA1_update(SHA1_CTX* ctx, const uint8_t* data, uint64_t len); +uint8_t* SHA1_final(SHA1_CTX* ctx); + +void SHA256_init(SHA256_CTX* ctx); +void SHA256_update(SHA256_CTX* ctx, const uint8_t* data, uint64_t len); +uint8_t* SHA256_final(SHA256_CTX* ctx); + +void SHA512_init(SHA512_CTX* ctx); +void SHA512_update(SHA512_CTX* ctx, const uint8_t* data, uint64_t len); +uint8_t* SHA512_final(SHA512_CTX* ctx); + +/* Convenience function for SHA-1. Computes hash on [data] of length [len]. + * and stores it into [digest]. [digest] should be pre-allocated to + * SHA1_DIGEST_SIZE bytes. + */ +uint8_t* SHA1(const uint8_t* data, uint64_t len, uint8_t* digest); + +/* Convenience function for SHA-256. Computes hash on [data] of length [len]. + * and stores it into [digest]. [digest] should be pre-allocated to + * SHA256_DIGEST_SIZE bytes. + */ +uint8_t* SHA256(const uint8_t* data, uint64_t len, uint8_t* digest); + +/* Convenience function for SHA-512. Computes hash on [data] of length [len]. + * and stores it into [digest]. [digest] should be pre-allocated to + * SHA512_DIGEST_SIZE bytes. + */ +uint8_t* SHA512(const uint8_t* data, uint64_t len, uint8_t* digest); + + +/*---- Utility functions/wrappers for message digests. */ + +#define SHA1_DIGEST_ALGORITHM 0 +#define SHA256_DIGEST_ALGORITHM 1 +#define SHA512_DIGEST_ALGORITHM 2 + +/* A generic digest context structure which can be used to represent + * the SHA*_CTX for multiple digest algorithms. + */ +typedef struct DigestContext { + SHA1_CTX* sha1_ctx; + SHA256_CTX* sha256_ctx; + SHA512_CTX* sha512_ctx; + int algorithm; /* Hashing algorithm to use. */ +} DigestContext; + +/* Wrappers for message digest algorithms. These are useful when the hashing + * operation is being done in parallel with something else. DigestContext tracks + * and stores the state of any digest algorithm (one at any given time). + */ + +/* Initialize a digest context for use with signature algorithm [algorithm]. */ +void DigestInit(DigestContext* ctx, int sig_algorithm); +void DigestUpdate(DigestContext* ctx, const uint8_t* data, uint64_t len); + +/* Caller owns the returned digest and must free it. */ +uint8_t* DigestFinal(DigestContext* ctx); + +/* Returns the appropriate digest for the data in [input_file] + * based on the signature [algorithm]. + * Caller owns the returned digest and must free it. + */ +uint8_t* DigestFile(char* input_file, int sig_algorithm); + +/* Returns the appropriate digest of [buf] of length + * [len] based on the signature [algorithm]. + * Caller owns the returned digest and must free it. + */ +uint8_t* DigestBuf(const uint8_t* buf, uint64_t len, int sig_algorithm); + + +#endif /* VBOOT_REFERENCE_SHA_H_ */ diff --git a/firmware/lib/cryptolib/padding.c b/firmware/lib/cryptolib/padding.c new file mode 100644 index 00000000..14d94458 --- /dev/null +++ b/firmware/lib/cryptolib/padding.c @@ -0,0 +1,246 @@ +/* + * DO NOT MODIFY THIS FILE DIRECTLY. + * + * This file is automatically generated by genpadding.sh and contains padding + * arrays corresponding to various combinations of algorithms for RSA signatures. + */ + +#include "cryptolib.h" + + +/* + * PKCS 1.5 padding (from the RSA PKCS#1 v2.1 standard) + * + * Depending on the RSA key size and hash function, the padding is calculated + * as follows: + * + * 0x00 || 0x01 || PS || 0x00 || T + * + * T: DER Encoded DigestInfo value which depends on the hash function used. + * + * SHA-1: (0x)30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14 || H. + * SHA-256: (0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || H. + * SHA-512: (0x)30 51 30 0d 06 09 60 86 48 01 65 03 04 02 03 05 00 04 40 || H. + * + * Length(T) = 35 octets for SHA-1 + * Length(T) = 51 octets for SHA-256 + * Length(T) = 83 octets for SHA-512 + * + * PS: octet string consisting of {Length(RSA Key) - Length(T) - 3} 0xFF + * + */ + + +/* Algorithm Type 0 */ +const uint8_t paddingRSA1024_SHA1[RSA1024NUMBYTES - SHA1_DIGEST_SIZE] = { +0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14 +}; + +/* Algorithm Type 1 */ +const uint8_t paddingRSA1024_SHA256[RSA1024NUMBYTES - SHA256_DIGEST_SIZE] = { +0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20 +}; + +/* Algorithm Type 2 */ +const uint8_t paddingRSA1024_SHA512[RSA1024NUMBYTES - SHA512_DIGEST_SIZE] = { +0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40 +}; + +/* Algorithm Type 3 */ +const uint8_t paddingRSA2048_SHA1[RSA2048NUMBYTES - SHA1_DIGEST_SIZE] = { +0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14 +}; + +/* Algorithm Type 4 */ +const uint8_t paddingRSA2048_SHA256[RSA2048NUMBYTES - SHA256_DIGEST_SIZE] = { +0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20 +}; + +/* Algorithm Type 5 */ +const uint8_t paddingRSA2048_SHA512[RSA2048NUMBYTES - SHA512_DIGEST_SIZE] = { +0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40 +}; + +/* Algorithm Type 6 */ +const uint8_t paddingRSA4096_SHA1[RSA4096NUMBYTES - SHA1_DIGEST_SIZE] = { +0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14 +}; + +/* Algorithm Type 7 */ +const uint8_t paddingRSA4096_SHA256[RSA4096NUMBYTES - SHA256_DIGEST_SIZE] = { +0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20 +}; + +/* Algorithm Type 8 */ +const uint8_t paddingRSA4096_SHA512[RSA4096NUMBYTES - SHA512_DIGEST_SIZE] = { +0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40 +}; + +/* Algorithm Type 9 */ +const uint8_t paddingRSA8192_SHA1[RSA8192NUMBYTES - SHA1_DIGEST_SIZE] = { +0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14 +}; + +/* Algorithm Type 10 */ +const uint8_t paddingRSA8192_SHA256[RSA8192NUMBYTES - SHA256_DIGEST_SIZE] = { +0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20 +}; + +/* Algorithm Type 11 */ +const uint8_t paddingRSA8192_SHA512[RSA8192NUMBYTES - SHA512_DIGEST_SIZE] = { +0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40 +}; + +const int kNumAlgorithms = 12; +#define NUMALGORITHMS 12 + +#define SHA1_DIGESTINFO_LEN 15 +#define SHA256_DIGESTINFO_LEN 19 +#define SHA512_DIGESTINFO_LEN 19 +const uint8_t SHA1_digestinfo[] = { +0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14 +}; + +const uint8_t SHA256_digestinfo[] = { +0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20 +}; + +const uint8_t SHA512_digestinfo[] = { +0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40 +}; + +const int digestinfo_size_map[] = { +SHA1_DIGESTINFO_LEN, +SHA256_DIGESTINFO_LEN, +SHA512_DIGESTINFO_LEN, +SHA1_DIGESTINFO_LEN, +SHA256_DIGESTINFO_LEN, +SHA512_DIGESTINFO_LEN, +SHA1_DIGESTINFO_LEN, +SHA256_DIGESTINFO_LEN, +SHA512_DIGESTINFO_LEN, +SHA1_DIGESTINFO_LEN, +SHA256_DIGESTINFO_LEN, +SHA512_DIGESTINFO_LEN, +}; + +const int siglen_map[NUMALGORITHMS] = { +RSA1024NUMBYTES, +RSA1024NUMBYTES, +RSA1024NUMBYTES, +RSA2048NUMBYTES, +RSA2048NUMBYTES, +RSA2048NUMBYTES, +RSA4096NUMBYTES, +RSA4096NUMBYTES, +RSA4096NUMBYTES, +RSA8192NUMBYTES, +RSA8192NUMBYTES, +RSA8192NUMBYTES, +}; + +const uint8_t* padding_map[NUMALGORITHMS] = { +paddingRSA1024_SHA1, +paddingRSA1024_SHA256, +paddingRSA1024_SHA512, +paddingRSA2048_SHA1, +paddingRSA2048_SHA256, +paddingRSA2048_SHA512, +paddingRSA4096_SHA1, +paddingRSA4096_SHA256, +paddingRSA4096_SHA512, +paddingRSA8192_SHA1, +paddingRSA8192_SHA256, +paddingRSA8192_SHA512, +}; + +const int padding_size_map[NUMALGORITHMS] = { +RSA1024NUMBYTES - SHA1_DIGEST_SIZE, +RSA1024NUMBYTES - SHA256_DIGEST_SIZE, +RSA1024NUMBYTES - SHA512_DIGEST_SIZE, +RSA2048NUMBYTES - SHA1_DIGEST_SIZE, +RSA2048NUMBYTES - SHA256_DIGEST_SIZE, +RSA2048NUMBYTES - SHA512_DIGEST_SIZE, +RSA4096NUMBYTES - SHA1_DIGEST_SIZE, +RSA4096NUMBYTES - SHA256_DIGEST_SIZE, +RSA4096NUMBYTES - SHA512_DIGEST_SIZE, +RSA8192NUMBYTES - SHA1_DIGEST_SIZE, +RSA8192NUMBYTES - SHA256_DIGEST_SIZE, +RSA8192NUMBYTES - SHA512_DIGEST_SIZE, +}; + +const int hash_type_map[] = { +SHA1_DIGEST_ALGORITHM, +SHA256_DIGEST_ALGORITHM, +SHA512_DIGEST_ALGORITHM, +SHA1_DIGEST_ALGORITHM, +SHA256_DIGEST_ALGORITHM, +SHA512_DIGEST_ALGORITHM, +SHA1_DIGEST_ALGORITHM, +SHA256_DIGEST_ALGORITHM, +SHA512_DIGEST_ALGORITHM, +SHA1_DIGEST_ALGORITHM, +SHA256_DIGEST_ALGORITHM, +SHA512_DIGEST_ALGORITHM, +}; + +const int hash_size_map[NUMALGORITHMS] = { +SHA1_DIGEST_SIZE, +SHA256_DIGEST_SIZE, +SHA512_DIGEST_SIZE, +SHA1_DIGEST_SIZE, +SHA256_DIGEST_SIZE, +SHA512_DIGEST_SIZE, +SHA1_DIGEST_SIZE, +SHA256_DIGEST_SIZE, +SHA512_DIGEST_SIZE, +SHA1_DIGEST_SIZE, +SHA256_DIGEST_SIZE, +SHA512_DIGEST_SIZE, +}; + +const int hash_blocksize_map[NUMALGORITHMS] = { +SHA1_BLOCK_SIZE, +SHA256_BLOCK_SIZE, +SHA512_BLOCK_SIZE, +SHA1_BLOCK_SIZE, +SHA256_BLOCK_SIZE, +SHA512_BLOCK_SIZE, +SHA1_BLOCK_SIZE, +SHA256_BLOCK_SIZE, +SHA512_BLOCK_SIZE, +SHA1_BLOCK_SIZE, +SHA256_BLOCK_SIZE, +SHA512_BLOCK_SIZE, +}; + +const uint8_t* hash_digestinfo_map[NUMALGORITHMS] = { +SHA1_digestinfo, +SHA256_digestinfo, +SHA512_digestinfo, +SHA1_digestinfo, +SHA256_digestinfo, +SHA512_digestinfo, +SHA1_digestinfo, +SHA256_digestinfo, +SHA512_digestinfo, +SHA1_digestinfo, +SHA256_digestinfo, +SHA512_digestinfo, +}; + +const char* algo_strings[NUMALGORITHMS] = { +"RSA1024 SHA1", +"RSA1024 SHA256", +"RSA1024 SHA512", +"RSA2048 SHA1", +"RSA2048 SHA256", +"RSA2048 SHA512", +"RSA4096 SHA1", +"RSA4096 SHA256", +"RSA4096 SHA512", +"RSA8192 SHA1", +"RSA8192 SHA256", +"RSA8192 SHA512", +}; + diff --git a/firmware/lib/cryptolib/rsa.c b/firmware/lib/cryptolib/rsa.c new file mode 100644 index 00000000..bfc64469 --- /dev/null +++ b/firmware/lib/cryptolib/rsa.c @@ -0,0 +1,187 @@ +/* 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. + */ + +/* Implementation of RSA signature verification which uses a pre-processed + * key for computation. The code extends Android's RSA verification code to + * support multiple RSA key lengths and hash digest algorithms. + */ + +#include "cryptolib.h" +#include "utility.h" + +/* a[] -= mod */ +static void subM(const RSAPublicKey *key, uint32_t *a) { + int64_t A = 0; + int i; + for (i = 0; i < key->len; ++i) { + A += (uint64_t)a[i] - key->n[i]; + a[i] = (uint32_t)A; + A >>= 32; + } +} + +/* return a[] >= mod */ +static int geM(const RSAPublicKey *key, uint32_t *a) { + int i; + for (i = key->len; i;) { + --i; + if (a[i] < key->n[i]) return 0; + if (a[i] > key->n[i]) return 1; + } + return 1; /* equal */ + } + +/* montgomery c[] += a * b[] / R % mod */ +static void montMulAdd(const RSAPublicKey *key, + uint32_t* c, + const uint32_t a, + const uint32_t* b) { + uint64_t A = (uint64_t)a * b[0] + c[0]; + uint32_t d0 = (uint32_t)A * key->n0inv; + uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A; + int i; + + for (i = 1; i < key->len; ++i) { + A = (A >> 32) + (uint64_t)a * b[i] + c[i]; + B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A; + c[i - 1] = (uint32_t)B; + } + + A = (A >> 32) + (B >> 32); + + c[i - 1] = (uint32_t)A; + + if (A >> 32) { + subM(key, c); + } +} + +/* montgomery c[] = a[] * b[] / R % mod */ +static void montMul(const RSAPublicKey *key, + uint32_t* c, + uint32_t* a, + uint32_t* b) { + int i; + for (i = 0; i < key->len; ++i) { + c[i] = 0; + } + for (i = 0; i < key->len; ++i) { + montMulAdd(key, c, a[i], b); + } +} + +/* In-place public exponentiation. (65537} + * Input and output big-endian byte array in inout. + */ +static void modpowF4(const RSAPublicKey *key, + uint8_t* inout) { + uint32_t* a = (uint32_t*) Malloc(key->len * sizeof(uint32_t)); + uint32_t* aR = (uint32_t*) Malloc(key->len * sizeof(uint32_t)); + uint32_t* aaR = (uint32_t*) Malloc(key->len * sizeof(uint32_t)); + + uint32_t* aaa = aaR; /* Re-use location. */ + int i; + + /* Convert from big endian byte array to little endian word array. */ + for (i = 0; i < key->len; ++i) { + uint32_t tmp = + (inout[((key->len - 1 - i) * 4) + 0] << 24) | + (inout[((key->len - 1 - i) * 4) + 1] << 16) | + (inout[((key->len - 1 - i) * 4) + 2] << 8) | + (inout[((key->len - 1 - i) * 4) + 3] << 0); + a[i] = tmp; + } + + montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M */ + for (i = 0; i < 16; i+=2) { + montMul(key, aaR, aR, aR); /* aaR = aR * aR / R mod M */ + montMul(key, aR, aaR, aaR); /* aR = aaR * aaR / R mod M */ + } + montMul(key, aaa, aR, a); /* aaa = aR * a / R mod M */ + + + /* Make sure aaa < mod; aaa is at most 1x mod too large. */ + if (geM(key, aaa)) { + subM(key, aaa); + } + + /* Convert to bigendian byte array */ + for (i = key->len - 1; i >= 0; --i) { + uint32_t tmp = aaa[i]; + *inout++ = tmp >> 24; + *inout++ = tmp >> 16; + *inout++ = tmp >> 8; + *inout++ = tmp >> 0; + } + + Free(a); + Free(aR); + Free(aaR); +} + +/* Verify a RSA PKCS1.5 signature against an expected hash. + * Returns 0 on failure, 1 on success. + */ +int RSAVerify(const RSAPublicKey *key, + const uint8_t *sig, + const int sig_len, + const uint8_t sig_type, + const uint8_t *hash) { + int i; + uint8_t* buf; + const uint8_t* padding; + int success = 1; + + if (sig_len != (key->len * sizeof(uint32_t))) { + debug("Signature is of incorrect length!\n"); + return 0; + } + + if (sig_type >= kNumAlgorithms) { + debug("Invalid signature type!\n"); + return 0; + } + + if (key->len != siglen_map[sig_type] / sizeof(uint32_t)) { + debug("Wrong key passed in!\n"); + return 0; + } + + buf = (uint8_t*) Malloc(sig_len); + Memcpy(buf, sig, sig_len); + + modpowF4(key, buf); + + /* Determine padding to use depending on the signature type. */ + padding = padding_map[sig_type]; + + /* Check pkcs1.5 padding bytes. */ + for (i = 0; i < padding_size_map[sig_type]; ++i) { + if (buf[i] != padding[i]) { +#ifndef NDEBUG +/* TODO(gauravsh): Replace with a macro call for logging. */ + debug("Padding: Expecting = %02x Got = %02x\n", padding[i], + buf[i]); +#endif + success = 0; + } + } + + /* Check if digest matches. */ + for (; i < sig_len; ++i) { + if (buf[i] != *hash++) { +#ifndef NDEBUG +/* TODO(gauravsh): Replace with a macro call for logging. */ + debug("Digest: Expecting = %02x Got = %02x\n", padding[i], + buf[i]); +#endif + success = 0; + } + } + + Free(buf); + + return success; +} diff --git a/firmware/lib/cryptolib/rsa_utility.c b/firmware/lib/cryptolib/rsa_utility.c new file mode 100644 index 00000000..f15b97ee --- /dev/null +++ b/firmware/lib/cryptolib/rsa_utility.c @@ -0,0 +1,134 @@ +/* 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. + * + * Implementation of RSA utility functions. + */ + +#include "cryptolib.h" +#include "stateful_util.h" +#include "utility.h" + +int RSAProcessedKeySize(int algorithm) { + int key_len = siglen_map[algorithm]; /* Key length in + * bytes. */ + /* Total size needed by a RSAPublicKey structure is = + * 2 * key_len bytes for the n and rr arrays + * + sizeof len + sizeof n0inv. + */ + return (2 * key_len + sizeof(uint32_t) + sizeof(uint32_t)); +} + +RSAPublicKey* RSAPublicKeyNew(void) { + RSAPublicKey* key = (RSAPublicKey*) Malloc(sizeof(RSAPublicKey)); + key->n = NULL; + key->rr = NULL; + return key; +} + +void RSAPublicKeyFree(RSAPublicKey* key) { + if (key) { + Free(key->n); + Free(key->rr); + Free(key); + } +} + +RSAPublicKey* RSAPublicKeyFromBuf(const uint8_t* buf, int len) { + RSAPublicKey* key = RSAPublicKeyNew(); + MemcpyState st; + int key_len; + + st.remaining_buf = (uint8_t*) buf; + st.remaining_len = len; + st.overrun = 0; + + StatefulMemcpy(&st, &key->len, sizeof(key->len)); + key_len = key->len * sizeof(uint32_t); /* key length in bytes. */ + + /* Sanity Check the key length. */ + if (RSA1024NUMBYTES != key_len && + RSA2048NUMBYTES != key_len && + RSA4096NUMBYTES != key_len && + RSA8192NUMBYTES != key_len) { + RSAPublicKeyFree(key); + return NULL; + } + + key->n = (uint32_t*) Malloc(key_len); + key->rr = (uint32_t*) Malloc(key_len); + + StatefulMemcpy(&st, &key->n0inv, sizeof(key->n0inv)); + StatefulMemcpy(&st, key->n, key_len); + StatefulMemcpy(&st, key->rr, key_len); + if (st.overrun || st.remaining_len != 0) { /* Underrun or overrun. */ + RSAPublicKeyFree(key); + return NULL; + } + + return key; +} + +int RSAVerifyBinary_f(const uint8_t* key_blob, + const RSAPublicKey* key, + const uint8_t* buf, + uint64_t len, + const uint8_t* sig, + int algorithm) { + RSAPublicKey* verification_key = NULL; + uint8_t* digest = NULL; + int key_size; + int sig_size; + int success; + + if (algorithm >= kNumAlgorithms) + return 0; /* Invalid algorithm. */ + key_size = RSAProcessedKeySize(algorithm); + sig_size = siglen_map[algorithm]; + + if (key_blob && !key) + verification_key = RSAPublicKeyFromBuf(key_blob, key_size); + else if (!key_blob && key) + verification_key = (RSAPublicKey*) key; /* Supress const warning. */ + else + return 0; /* Both can't be NULL or non-NULL. */ + + digest = DigestBuf(buf, len, algorithm); + success = RSAVerify(verification_key, sig, sig_size, algorithm, digest); + + Free(digest); + if (!key) + RSAPublicKeyFree(verification_key); /* Only free if we allocated it. */ + return success; +} + +/* Version of RSAVerifyBinary_f() where instead of the raw binary blob + * of data, its digest is passed as the argument. */ +int RSAVerifyBinaryWithDigest_f(const uint8_t* key_blob, + const RSAPublicKey* key, + const uint8_t* digest, + const uint8_t* sig, + int algorithm) { + RSAPublicKey* verification_key = NULL; + int key_size; + int sig_size; + int success; + + if (algorithm >= kNumAlgorithms) + return 0; /* Invalid algorithm. */ + key_size = RSAProcessedKeySize(algorithm); + sig_size = siglen_map[algorithm]; + + if (key_blob && !key) + verification_key = RSAPublicKeyFromBuf(key_blob, key_size); + else if (!key_blob && key) + verification_key = (RSAPublicKey*) key; /* Supress const warning. */ + else + return 0; /* Both can't be NULL or non-NULL. */ + + success = RSAVerify(verification_key, sig, sig_size, algorithm, digest); + + if (!key) + RSAPublicKeyFree(verification_key); /* Only free if we allocated it. */ + return success; +} diff --git a/firmware/lib/cryptolib/sha1.c b/firmware/lib/cryptolib/sha1.c new file mode 100644 index 00000000..70653ba7 --- /dev/null +++ b/firmware/lib/cryptolib/sha1.c @@ -0,0 +1,287 @@ +/* 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. + * + * SHA-1 implementation largely based on libmincrypt in the the Android + * Open Source Project (platorm/system/core.git/libmincrypt/sha.c + */ + +#include "cryptolib.h" +#include "utility.h" + + +/* Some machines lack byteswap.h and endian.h. These have to use the + * slower code, even if they're little-endian. + */ + +#if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN) + +/* This version is about 28% faster than the generic version below, + * but assumes little-endianness. + */ +static uint32_t ror27(uint32_t val) { + return (val >> 27) | (val << 5); +} +static uint32_t ror2(uint32_t val) { + return (val >> 2) | (val << 30); +} +static uint32_t ror31(uint32_t val) { + return (val >> 31) | (val << 1); +} + +static void SHA1_Transform(SHA1_CTX* ctx) { + uint32_t W[80]; + register uint32_t A, B, C, D, E; + int t; + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + +#define SHA_F1(A,B,C,D,E,t) \ + E += ror27(A) + \ + (W[t] = bswap_32(ctx->buf.w[t])) + \ + (D^(B&(C^D))) + 0x5A827999; \ + B = ror2(B); + + for (t = 0; t < 15; t += 5) { + SHA_F1(A,B,C,D,E,t + 0); + SHA_F1(E,A,B,C,D,t + 1); + SHA_F1(D,E,A,B,C,t + 2); + SHA_F1(C,D,E,A,B,t + 3); + SHA_F1(B,C,D,E,A,t + 4); + } + SHA_F1(A,B,C,D,E,t + 0); /* 16th one, t == 15 */ + +#undef SHA_F1 + +#define SHA_F1(A,B,C,D,E,t) \ + E += ror27(A) + \ + (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \ + (D^(B&(C^D))) + 0x5A827999; \ + B = ror2(B); + + SHA_F1(E,A,B,C,D,t + 1); + SHA_F1(D,E,A,B,C,t + 2); + SHA_F1(C,D,E,A,B,t + 3); + SHA_F1(B,C,D,E,A,t + 4); + +#undef SHA_F1 + +#define SHA_F2(A,B,C,D,E,t) \ + E += ror27(A) + \ + (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \ + (B^C^D) + 0x6ED9EBA1; \ + B = ror2(B); + + for (t = 20; t < 40; t += 5) { + SHA_F2(A,B,C,D,E,t + 0); + SHA_F2(E,A,B,C,D,t + 1); + SHA_F2(D,E,A,B,C,t + 2); + SHA_F2(C,D,E,A,B,t + 3); + SHA_F2(B,C,D,E,A,t + 4); + } + +#undef SHA_F2 + +#define SHA_F3(A,B,C,D,E,t) \ + E += ror27(A) + \ + (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \ + ((B&C)|(D&(B|C))) + 0x8F1BBCDC; \ + B = ror2(B); + + for (; t < 60; t += 5) { + SHA_F3(A,B,C,D,E,t + 0); + SHA_F3(E,A,B,C,D,t + 1); + SHA_F3(D,E,A,B,C,t + 2); + SHA_F3(C,D,E,A,B,t + 3); + SHA_F3(B,C,D,E,A,t + 4); + } + +#undef SHA_F3 + +#define SHA_F4(A,B,C,D,E,t) \ + E += ror27(A) + \ + (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \ + (B^C^D) + 0xCA62C1D6; \ + B = ror2(B); + + for (; t < 80; t += 5) { + SHA_F4(A,B,C,D,E,t + 0); + SHA_F4(E,A,B,C,D,t + 1); + SHA_F4(D,E,A,B,C,t + 2); + SHA_F4(C,D,E,A,B,t + 3); + SHA_F4(B,C,D,E,A,t + 4); + } + +#undef SHA_F4 + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; +} + +void SHA1_update(SHA1_CTX* ctx, const uint8_t* data, uint64_t len) { + int i = ctx->count % sizeof(ctx->buf); + const uint8_t* p = (const uint8_t*)data; + + ctx->count += len; + + while (len > sizeof(ctx->buf) - i) { + Memcpy(&ctx->buf.b[i], p, sizeof(ctx->buf) - i); + len -= sizeof(ctx->buf) - i; + p += sizeof(ctx->buf) - i; + SHA1_Transform(ctx); + i = 0; + } + + while (len--) { + ctx->buf.b[i++] = *p++; + if (i == sizeof(ctx->buf)) { + SHA1_Transform(ctx); + i = 0; + } + } +} + + +uint8_t* SHA1_final(SHA1_CTX* ctx) { + uint64_t cnt = ctx->count * 8; + int i; + + SHA1_update(ctx, (uint8_t*)"\x80", 1); + while ((ctx->count % sizeof(ctx->buf)) != (sizeof(ctx->buf) - 8)) { + SHA1_update(ctx, (uint8_t*)"\0", 1); + } + for (i = 0; i < 8; ++i) { + uint8_t tmp = cnt >> ((7 - i) * 8); + SHA1_update(ctx, &tmp, 1); + } + + for (i = 0; i < 5; i++) { + ctx->buf.w[i] = bswap_32(ctx->state[i]); + } + + return ctx->buf.b; +} + +#else /* #if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN) */ + +#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +static void SHA1_transform(SHA1_CTX *ctx) { + uint32_t W[80]; + uint32_t A, B, C, D, E; + uint8_t *p = ctx->buf; + int t; + + for(t = 0; t < 16; ++t) { + uint32_t tmp = *p++ << 24; + tmp |= *p++ << 16; + tmp |= *p++ << 8; + tmp |= *p++; + W[t] = tmp; + } + + for(; t < 80; t++) { + W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); + } + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + + for(t = 0; t < 80; t++) { + uint32_t tmp = rol(5,A) + E + W[t]; + + if (t < 20) + tmp += (D^(B&(C^D))) + 0x5A827999; + else if ( t < 40) + tmp += (B^C^D) + 0x6ED9EBA1; + else if ( t < 60) + tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC; + else + tmp += (B^C^D) + 0xCA62C1D6; + + E = D; + D = C; + C = rol(30,B); + B = A; + A = tmp; + } + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; +} + +void SHA1_update(SHA1_CTX *ctx, const uint8_t *data, uint64_t len) { + int i = ctx->count % sizeof(ctx->buf); + const uint8_t* p = (const uint8_t*) data; + + ctx->count += len; + + while (len--) { + ctx->buf[i++] = *p++; + if (i == sizeof(ctx->buf)) { + SHA1_transform(ctx); + i = 0; + } + } +} +uint8_t* SHA1_final(SHA1_CTX *ctx) { + uint8_t *p = ctx->buf; + uint64_t cnt = ctx->count * 8; + int i; + + SHA1_update(ctx, (uint8_t*)"\x80", 1); + while ((ctx->count % sizeof(ctx->buf)) != (sizeof(ctx->buf) - 8)) { + SHA1_update(ctx, (uint8_t*)"\0", 1); + } + for (i = 0; i < 8; ++i) { + uint8_t tmp = cnt >> ((7 - i) * 8); + SHA1_update(ctx, &tmp, 1); + } + + for (i = 0; i < 5; i++) { + uint32_t tmp = ctx->state[i]; + *p++ = tmp >> 24; + *p++ = tmp >> 16; + *p++ = tmp >> 8; + *p++ = tmp >> 0; + } + + return ctx->buf; +} + +#endif /* endianness */ + +void SHA1_init(SHA1_CTX* ctx) { + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; + ctx->count = 0; +} + +uint8_t* SHA1(const uint8_t *data, uint64_t len, uint8_t *digest) { + const uint8_t *p; + int i; + SHA1_CTX ctx; + SHA1_init(&ctx); + SHA1_update(&ctx, data, len); + p = SHA1_final(&ctx); + for (i = 0; i < SHA1_DIGEST_SIZE; ++i) { + digest[i] = *p++; + } + return digest; +} diff --git a/firmware/lib/cryptolib/sha2.c b/firmware/lib/cryptolib/sha2.c new file mode 100644 index 00000000..e7f78885 --- /dev/null +++ b/firmware/lib/cryptolib/sha2.c @@ -0,0 +1,623 @@ +/* SHA-256 and SHA-512 implementation based on code by Oliver Gay + * <olivier.gay@a3.epfl.ch> under a BSD-style license. See below. + */ + +/* + * FIPS 180-2 SHA-224/256/384/512 implementation + * Last update: 02/02/2007 + * Issue date: 04/30/2005 + * + * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cryptolib.h" +#include "utility.h" + +#define SHFR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) +#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) +#define CH(x, y, z) ((x & y) ^ (~x & z)) +#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) + +#define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3)) +#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10)) + +#define SHA512_F1(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39)) +#define SHA512_F2(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41)) +#define SHA512_F3(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHFR(x, 7)) +#define SHA512_F4(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHFR(x, 6)) + +#define UNPACK32(x, str) \ + { \ + *((str) + 3) = (uint8_t) ((x) ); \ + *((str) + 2) = (uint8_t) ((x) >> 8); \ + *((str) + 1) = (uint8_t) ((x) >> 16); \ + *((str) + 0) = (uint8_t) ((x) >> 24); \ + } + +#define PACK32(str, x) \ + { \ + *(x) = ((uint32_t) *((str) + 3) ) \ + | ((uint32_t) *((str) + 2) << 8) \ + | ((uint32_t) *((str) + 1) << 16) \ + | ((uint32_t) *((str) + 0) << 24); \ + } + +#define UNPACK64(x, str) \ + { \ + *((str) + 7) = (uint8_t) ((x) ); \ + *((str) + 6) = (uint8_t) ((x) >> 8); \ + *((str) + 5) = (uint8_t) ((x) >> 16); \ + *((str) + 4) = (uint8_t) ((x) >> 24); \ + *((str) + 3) = (uint8_t) ((x) >> 32); \ + *((str) + 2) = (uint8_t) ((x) >> 40); \ + *((str) + 1) = (uint8_t) ((x) >> 48); \ + *((str) + 0) = (uint8_t) ((x) >> 56); \ + } + +#define PACK64(str, x) \ + { \ + *(x) = ((uint64_t) *((str) + 7) ) \ + | ((uint64_t) *((str) + 6) << 8) \ + | ((uint64_t) *((str) + 5) << 16) \ + | ((uint64_t) *((str) + 4) << 24) \ + | ((uint64_t) *((str) + 3) << 32) \ + | ((uint64_t) *((str) + 2) << 40) \ + | ((uint64_t) *((str) + 1) << 48) \ + | ((uint64_t) *((str) + 0) << 56); \ + } + +/* Macros used for loops unrolling */ + +#define SHA256_SCR(i) \ + { \ + w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \ + + SHA256_F3(w[i - 15]) + w[i - 16]; \ + } + +#define SHA512_SCR(i) \ + { \ + w[i] = SHA512_F4(w[i - 2]) + w[i - 7] \ + + SHA512_F3(w[i - 15]) + w[i - 16]; \ + } + +#define SHA256_EXP(a, b, c, d, e, f, g, h, j) \ + { \ + t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \ + + sha256_k[j] + w[j]; \ + t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ + wv[d] += t1; \ + wv[h] = t1 + t2; \ + } + +#define SHA512_EXP(a, b, c, d, e, f, g ,h, j) \ + { \ + t1 = wv[h] + SHA512_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \ + + sha512_k[j] + w[j]; \ + t2 = SHA512_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ + wv[d] += t1; \ + wv[h] = t1 + t2; \ + } + +uint32_t sha256_h0[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + +uint64_t sha512_h0[8] = { + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL}; + +uint32_t sha256_k[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + +uint64_t sha512_k[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL}; + + +/* SHA-256 implementation */ +void SHA256_init(SHA256_CTX *ctx) { +#ifndef UNROLL_LOOPS + int i; + for (i = 0; i < 8; i++) { + ctx->h[i] = sha256_h0[i]; + } +#else + ctx->h[0] = sha256_h0[0]; ctx->h[1] = sha256_h0[1]; + ctx->h[2] = sha256_h0[2]; ctx->h[3] = sha256_h0[3]; + ctx->h[4] = sha256_h0[4]; ctx->h[5] = sha256_h0[5]; + ctx->h[6] = sha256_h0[6]; ctx->h[7] = sha256_h0[7]; +#endif /* !UNROLL_LOOPS */ + + ctx->len = 0; + ctx->tot_len = 0; +} + + +static void SHA256_transform(SHA256_CTX* ctx, const uint8_t* message, + unsigned int block_nb) { + uint32_t w[64]; + uint32_t wv[8]; + uint32_t t1, t2; + const unsigned char *sub_block; + int i; + +#ifndef UNROLL_LOOPS + int j; +#endif + + for (i = 0; i < (int) block_nb; i++) { + sub_block = message + (i << 6); + +#ifndef UNROLL_LOOPS + for (j = 0; j < 16; j++) { + PACK32(&sub_block[j << 2], &w[j]); + } + + for (j = 16; j < 64; j++) { + SHA256_SCR(j); + } + + for (j = 0; j < 8; j++) { + wv[j] = ctx->h[j]; + } + + for (j = 0; j < 64; j++) { + t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + + sha256_k[j] + w[j]; + t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); + wv[7] = wv[6]; + wv[6] = wv[5]; + wv[5] = wv[4]; + wv[4] = wv[3] + t1; + wv[3] = wv[2]; + wv[2] = wv[1]; + wv[1] = wv[0]; + wv[0] = t1 + t2; + } + + for (j = 0; j < 8; j++) { + ctx->h[j] += wv[j]; + } +#else + PACK32(&sub_block[ 0], &w[ 0]); PACK32(&sub_block[ 4], &w[ 1]); + PACK32(&sub_block[ 8], &w[ 2]); PACK32(&sub_block[12], &w[ 3]); + PACK32(&sub_block[16], &w[ 4]); PACK32(&sub_block[20], &w[ 5]); + PACK32(&sub_block[24], &w[ 6]); PACK32(&sub_block[28], &w[ 7]); + PACK32(&sub_block[32], &w[ 8]); PACK32(&sub_block[36], &w[ 9]); + PACK32(&sub_block[40], &w[10]); PACK32(&sub_block[44], &w[11]); + PACK32(&sub_block[48], &w[12]); PACK32(&sub_block[52], &w[13]); + PACK32(&sub_block[56], &w[14]); PACK32(&sub_block[60], &w[15]); + + SHA256_SCR(16); SHA256_SCR(17); SHA256_SCR(18); SHA256_SCR(19); + SHA256_SCR(20); SHA256_SCR(21); SHA256_SCR(22); SHA256_SCR(23); + SHA256_SCR(24); SHA256_SCR(25); SHA256_SCR(26); SHA256_SCR(27); + SHA256_SCR(28); SHA256_SCR(29); SHA256_SCR(30); SHA256_SCR(31); + SHA256_SCR(32); SHA256_SCR(33); SHA256_SCR(34); SHA256_SCR(35); + SHA256_SCR(36); SHA256_SCR(37); SHA256_SCR(38); SHA256_SCR(39); + SHA256_SCR(40); SHA256_SCR(41); SHA256_SCR(42); SHA256_SCR(43); + SHA256_SCR(44); SHA256_SCR(45); SHA256_SCR(46); SHA256_SCR(47); + SHA256_SCR(48); SHA256_SCR(49); SHA256_SCR(50); SHA256_SCR(51); + SHA256_SCR(52); SHA256_SCR(53); SHA256_SCR(54); SHA256_SCR(55); + SHA256_SCR(56); SHA256_SCR(57); SHA256_SCR(58); SHA256_SCR(59); + SHA256_SCR(60); SHA256_SCR(61); SHA256_SCR(62); SHA256_SCR(63); + + wv[0] = ctx->h[0]; wv[1] = ctx->h[1]; + wv[2] = ctx->h[2]; wv[3] = ctx->h[3]; + wv[4] = ctx->h[4]; wv[5] = ctx->h[5]; + wv[6] = ctx->h[6]; wv[7] = ctx->h[7]; + + SHA256_EXP(0,1,2,3,4,5,6,7, 0); SHA256_EXP(7,0,1,2,3,4,5,6, 1); + SHA256_EXP(6,7,0,1,2,3,4,5, 2); SHA256_EXP(5,6,7,0,1,2,3,4, 3); + SHA256_EXP(4,5,6,7,0,1,2,3, 4); SHA256_EXP(3,4,5,6,7,0,1,2, 5); + SHA256_EXP(2,3,4,5,6,7,0,1, 6); SHA256_EXP(1,2,3,4,5,6,7,0, 7); + SHA256_EXP(0,1,2,3,4,5,6,7, 8); SHA256_EXP(7,0,1,2,3,4,5,6, 9); + SHA256_EXP(6,7,0,1,2,3,4,5,10); SHA256_EXP(5,6,7,0,1,2,3,4,11); + SHA256_EXP(4,5,6,7,0,1,2,3,12); SHA256_EXP(3,4,5,6,7,0,1,2,13); + SHA256_EXP(2,3,4,5,6,7,0,1,14); SHA256_EXP(1,2,3,4,5,6,7,0,15); + SHA256_EXP(0,1,2,3,4,5,6,7,16); SHA256_EXP(7,0,1,2,3,4,5,6,17); + SHA256_EXP(6,7,0,1,2,3,4,5,18); SHA256_EXP(5,6,7,0,1,2,3,4,19); + SHA256_EXP(4,5,6,7,0,1,2,3,20); SHA256_EXP(3,4,5,6,7,0,1,2,21); + SHA256_EXP(2,3,4,5,6,7,0,1,22); SHA256_EXP(1,2,3,4,5,6,7,0,23); + SHA256_EXP(0,1,2,3,4,5,6,7,24); SHA256_EXP(7,0,1,2,3,4,5,6,25); + SHA256_EXP(6,7,0,1,2,3,4,5,26); SHA256_EXP(5,6,7,0,1,2,3,4,27); + SHA256_EXP(4,5,6,7,0,1,2,3,28); SHA256_EXP(3,4,5,6,7,0,1,2,29); + SHA256_EXP(2,3,4,5,6,7,0,1,30); SHA256_EXP(1,2,3,4,5,6,7,0,31); + SHA256_EXP(0,1,2,3,4,5,6,7,32); SHA256_EXP(7,0,1,2,3,4,5,6,33); + SHA256_EXP(6,7,0,1,2,3,4,5,34); SHA256_EXP(5,6,7,0,1,2,3,4,35); + SHA256_EXP(4,5,6,7,0,1,2,3,36); SHA256_EXP(3,4,5,6,7,0,1,2,37); + SHA256_EXP(2,3,4,5,6,7,0,1,38); SHA256_EXP(1,2,3,4,5,6,7,0,39); + SHA256_EXP(0,1,2,3,4,5,6,7,40); SHA256_EXP(7,0,1,2,3,4,5,6,41); + SHA256_EXP(6,7,0,1,2,3,4,5,42); SHA256_EXP(5,6,7,0,1,2,3,4,43); + SHA256_EXP(4,5,6,7,0,1,2,3,44); SHA256_EXP(3,4,5,6,7,0,1,2,45); + SHA256_EXP(2,3,4,5,6,7,0,1,46); SHA256_EXP(1,2,3,4,5,6,7,0,47); + SHA256_EXP(0,1,2,3,4,5,6,7,48); SHA256_EXP(7,0,1,2,3,4,5,6,49); + SHA256_EXP(6,7,0,1,2,3,4,5,50); SHA256_EXP(5,6,7,0,1,2,3,4,51); + SHA256_EXP(4,5,6,7,0,1,2,3,52); SHA256_EXP(3,4,5,6,7,0,1,2,53); + SHA256_EXP(2,3,4,5,6,7,0,1,54); SHA256_EXP(1,2,3,4,5,6,7,0,55); + SHA256_EXP(0,1,2,3,4,5,6,7,56); SHA256_EXP(7,0,1,2,3,4,5,6,57); + SHA256_EXP(6,7,0,1,2,3,4,5,58); SHA256_EXP(5,6,7,0,1,2,3,4,59); + SHA256_EXP(4,5,6,7,0,1,2,3,60); SHA256_EXP(3,4,5,6,7,0,1,2,61); + SHA256_EXP(2,3,4,5,6,7,0,1,62); SHA256_EXP(1,2,3,4,5,6,7,0,63); + + ctx->h[0] += wv[0]; ctx->h[1] += wv[1]; + ctx->h[2] += wv[2]; ctx->h[3] += wv[3]; + ctx->h[4] += wv[4]; ctx->h[5] += wv[5]; + ctx->h[6] += wv[6]; ctx->h[7] += wv[7]; +#endif /* !UNROLL_LOOPS */ + } +} + + + +void SHA256_update(SHA256_CTX* ctx, const uint8_t* data, uint64_t len) { + unsigned int block_nb; + unsigned int new_len, rem_len, tmp_len; + const uint8_t *shifted_data; + + tmp_len = SHA256_BLOCK_SIZE - ctx->len; + rem_len = len < tmp_len ? len : tmp_len; + + Memcpy(&ctx->block[ctx->len], data, rem_len); + + if (ctx->len + len < SHA256_BLOCK_SIZE) { + ctx->len += len; + return; + } + + new_len = len - rem_len; + block_nb = new_len / SHA256_BLOCK_SIZE; + + shifted_data = data + rem_len; + + SHA256_transform(ctx, ctx->block, 1); + SHA256_transform(ctx, shifted_data, block_nb); + + rem_len = new_len % SHA256_BLOCK_SIZE; + + Memcpy(ctx->block, &shifted_data[block_nb << 6], + rem_len); + + ctx->len = rem_len; + ctx->tot_len += (block_nb + 1) << 6; +} + +uint8_t* SHA256_final(SHA256_CTX* ctx) { + unsigned int block_nb; + unsigned int pm_len; + unsigned int len_b; +#ifndef UNROLL_LOOPS + int i; +#endif + + block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) + < (ctx->len % SHA256_BLOCK_SIZE))); + + len_b = (ctx->tot_len + ctx->len) << 3; + pm_len = block_nb << 6; + + Memset(ctx->block + ctx->len, 0, pm_len - ctx->len); + ctx->block[ctx->len] = 0x80; + UNPACK32(len_b, ctx->block + pm_len - 4); + + SHA256_transform(ctx, ctx->block, block_nb); + +#ifndef UNROLL_LOOPS + for (i = 0 ; i < 8; i++) { + UNPACK32(ctx->h[i], &ctx->buf[i << 2]); + } +#else + UNPACK32(ctx->h[0], &ctx->buf[ 0]); + UNPACK32(ctx->h[1], &ctx->buf[ 4]); + UNPACK32(ctx->h[2], &ctx->buf[ 8]); + UNPACK32(ctx->h[3], &ctx->buf[12]); + UNPACK32(ctx->h[4], &ctx->buf[16]); + UNPACK32(ctx->h[5], &ctx->buf[20]); + UNPACK32(ctx->h[6], &ctx->buf[24]); + UNPACK32(ctx->h[7], &ctx->buf[28]); +#endif /* !UNROLL_LOOPS */ + + return ctx->buf; +} + + +/* SHA-512 implementation */ + +void SHA512_init(SHA512_CTX *ctx) { +#ifndef UNROLL_LOOPS + int i; + for (i = 0; i < 8; i++) { + ctx->h[i] = sha512_h0[i]; + } +#else + ctx->h[0] = sha512_h0[0]; ctx->h[1] = sha512_h0[1]; + ctx->h[2] = sha512_h0[2]; ctx->h[3] = sha512_h0[3]; + ctx->h[4] = sha512_h0[4]; ctx->h[5] = sha512_h0[5]; + ctx->h[6] = sha512_h0[6]; ctx->h[7] = sha512_h0[7]; +#endif /* !UNROLL_LOOPS */ + + ctx->len = 0; + ctx->tot_len = 0; +} + + +static void SHA512_transform(SHA512_CTX* ctx, const uint8_t* message, + unsigned int block_nb) +{ + uint64_t w[80]; + uint64_t wv[8]; + uint64_t t1, t2; + const uint8_t *sub_block; + int i, j; + + for (i = 0; i < (int) block_nb; i++) { + sub_block = message + (i << 7); + +#ifndef UNROLL_LOOPS + for (j = 0; j < 16; j++) { + PACK64(&sub_block[j << 3], &w[j]); + } + + for (j = 16; j < 80; j++) { + SHA512_SCR(j); + } + + for (j = 0; j < 8; j++) { + wv[j] = ctx->h[j]; + } + + for (j = 0; j < 80; j++) { + t1 = wv[7] + SHA512_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + + sha512_k[j] + w[j]; + t2 = SHA512_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); + wv[7] = wv[6]; + wv[6] = wv[5]; + wv[5] = wv[4]; + wv[4] = wv[3] + t1; + wv[3] = wv[2]; + wv[2] = wv[1]; + wv[1] = wv[0]; + wv[0] = t1 + t2; + } + + for (j = 0; j < 8; j++) { + ctx->h[j] += wv[j]; + } +#else + PACK64(&sub_block[ 0], &w[ 0]); PACK64(&sub_block[ 8], &w[ 1]); + PACK64(&sub_block[ 16], &w[ 2]); PACK64(&sub_block[ 24], &w[ 3]); + PACK64(&sub_block[ 32], &w[ 4]); PACK64(&sub_block[ 40], &w[ 5]); + PACK64(&sub_block[ 48], &w[ 6]); PACK64(&sub_block[ 56], &w[ 7]); + PACK64(&sub_block[ 64], &w[ 8]); PACK64(&sub_block[ 72], &w[ 9]); + PACK64(&sub_block[ 80], &w[10]); PACK64(&sub_block[ 88], &w[11]); + PACK64(&sub_block[ 96], &w[12]); PACK64(&sub_block[104], &w[13]); + PACK64(&sub_block[112], &w[14]); PACK64(&sub_block[120], &w[15]); + + SHA512_SCR(16); SHA512_SCR(17); SHA512_SCR(18); SHA512_SCR(19); + SHA512_SCR(20); SHA512_SCR(21); SHA512_SCR(22); SHA512_SCR(23); + SHA512_SCR(24); SHA512_SCR(25); SHA512_SCR(26); SHA512_SCR(27); + SHA512_SCR(28); SHA512_SCR(29); SHA512_SCR(30); SHA512_SCR(31); + SHA512_SCR(32); SHA512_SCR(33); SHA512_SCR(34); SHA512_SCR(35); + SHA512_SCR(36); SHA512_SCR(37); SHA512_SCR(38); SHA512_SCR(39); + SHA512_SCR(40); SHA512_SCR(41); SHA512_SCR(42); SHA512_SCR(43); + SHA512_SCR(44); SHA512_SCR(45); SHA512_SCR(46); SHA512_SCR(47); + SHA512_SCR(48); SHA512_SCR(49); SHA512_SCR(50); SHA512_SCR(51); + SHA512_SCR(52); SHA512_SCR(53); SHA512_SCR(54); SHA512_SCR(55); + SHA512_SCR(56); SHA512_SCR(57); SHA512_SCR(58); SHA512_SCR(59); + SHA512_SCR(60); SHA512_SCR(61); SHA512_SCR(62); SHA512_SCR(63); + SHA512_SCR(64); SHA512_SCR(65); SHA512_SCR(66); SHA512_SCR(67); + SHA512_SCR(68); SHA512_SCR(69); SHA512_SCR(70); SHA512_SCR(71); + SHA512_SCR(72); SHA512_SCR(73); SHA512_SCR(74); SHA512_SCR(75); + SHA512_SCR(76); SHA512_SCR(77); SHA512_SCR(78); SHA512_SCR(79); + + wv[0] = ctx->h[0]; wv[1] = ctx->h[1]; + wv[2] = ctx->h[2]; wv[3] = ctx->h[3]; + wv[4] = ctx->h[4]; wv[5] = ctx->h[5]; + wv[6] = ctx->h[6]; wv[7] = ctx->h[7]; + + j = 0; + + do { + SHA512_EXP(0,1,2,3,4,5,6,7,j); j++; + SHA512_EXP(7,0,1,2,3,4,5,6,j); j++; + SHA512_EXP(6,7,0,1,2,3,4,5,j); j++; + SHA512_EXP(5,6,7,0,1,2,3,4,j); j++; + SHA512_EXP(4,5,6,7,0,1,2,3,j); j++; + SHA512_EXP(3,4,5,6,7,0,1,2,j); j++; + SHA512_EXP(2,3,4,5,6,7,0,1,j); j++; + SHA512_EXP(1,2,3,4,5,6,7,0,j); j++; + } while (j < 80); + + ctx->h[0] += wv[0]; ctx->h[1] += wv[1]; + ctx->h[2] += wv[2]; ctx->h[3] += wv[3]; + ctx->h[4] += wv[4]; ctx->h[5] += wv[5]; + ctx->h[6] += wv[6]; ctx->h[7] += wv[7]; +#endif /* !UNROLL_LOOPS */ + } +} + + +void SHA512_update(SHA512_CTX* ctx, const uint8_t* data, + uint64_t len) { + unsigned int block_nb; + unsigned int new_len, rem_len, tmp_len; + const uint8_t* shifted_data; + + tmp_len = SHA512_BLOCK_SIZE - ctx->len; + rem_len = len < tmp_len ? len : tmp_len; + + Memcpy(&ctx->block[ctx->len], data, rem_len); + + if (ctx->len + len < SHA512_BLOCK_SIZE) { + ctx->len += len; + return; + } + + new_len = len - rem_len; + block_nb = new_len / SHA512_BLOCK_SIZE; + + shifted_data = data + rem_len; + + SHA512_transform(ctx, ctx->block, 1); + SHA512_transform(ctx, shifted_data, block_nb); + + rem_len = new_len % SHA512_BLOCK_SIZE; + + Memcpy(ctx->block, &shifted_data[block_nb << 7], + rem_len); + + ctx->len = rem_len; + ctx->tot_len += (block_nb + 1) << 7; +} + +uint8_t* SHA512_final(SHA512_CTX* ctx) +{ + unsigned int block_nb; + unsigned int pm_len; + unsigned int len_b; + +#ifndef UNROLL_LOOPS + int i; +#endif + + block_nb = 1 + ((SHA512_BLOCK_SIZE - 17) + < (ctx->len % SHA512_BLOCK_SIZE)); + + len_b = (ctx->tot_len + ctx->len) << 3; + pm_len = block_nb << 7; + + Memset(ctx->block + ctx->len, 0, pm_len - ctx->len); + ctx->block[ctx->len] = 0x80; + UNPACK32(len_b, ctx->block + pm_len - 4); + + SHA512_transform(ctx, ctx->block, block_nb); + +#ifndef UNROLL_LOOPS + for (i = 0 ; i < 8; i++) { + UNPACK64(ctx->h[i], &ctx->buf[i << 3]); + } +#else + UNPACK64(ctx->h[0], &ctx->buf[ 0]); + UNPACK64(ctx->h[1], &ctx->buf[ 8]); + UNPACK64(ctx->h[2], &ctx->buf[16]); + UNPACK64(ctx->h[3], &ctx->buf[24]); + UNPACK64(ctx->h[4], &ctx->buf[32]); + UNPACK64(ctx->h[5], &ctx->buf[40]); + UNPACK64(ctx->h[6], &ctx->buf[48]); + UNPACK64(ctx->h[7], &ctx->buf[56]); +#endif /* !UNROLL_LOOPS */ + + return ctx->buf; +} + + + +/* Convenient functions. */ +uint8_t* SHA256(const uint8_t* data, uint64_t len, uint8_t* digest) { + const uint8_t* p; + int i; + SHA256_CTX ctx; + SHA256_init(&ctx); + SHA256_update(&ctx, data, len); + p = SHA256_final(&ctx); + for (i = 0; i < SHA256_DIGEST_SIZE; ++i) { + digest[i] = *p++; + } + return digest; +} + + +uint8_t* SHA512(const uint8_t* data, uint64_t len, uint8_t* digest) { + const uint8_t* p; + int i; + SHA512_CTX ctx; + SHA512_init(&ctx); + SHA512_update(&ctx, data, len); + p = SHA512_final(&ctx); + for (i = 0; i < SHA512_DIGEST_SIZE; ++i) { + digest[i] = *p++; + } + return digest; +} diff --git a/firmware/lib/cryptolib/sha_utility.c b/firmware/lib/cryptolib/sha_utility.c new file mode 100644 index 00000000..4e266f7c --- /dev/null +++ b/firmware/lib/cryptolib/sha_utility.c @@ -0,0 +1,87 @@ +/* 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. + * + * Utility functions for message digest functions. + */ + +#include "cryptolib.h" +#include "utility.h" + +void DigestInit(DigestContext* ctx, int sig_algorithm) { + ctx->algorithm = hash_type_map[sig_algorithm]; + switch(ctx->algorithm) { + case SHA1_DIGEST_ALGORITHM: + ctx->sha1_ctx = (SHA1_CTX*) Malloc(sizeof(SHA1_CTX)); + SHA1_init(ctx->sha1_ctx); + break; + case SHA256_DIGEST_ALGORITHM: + ctx->sha256_ctx = (SHA256_CTX*) Malloc(sizeof(SHA256_CTX)); + SHA256_init(ctx->sha256_ctx); + break; + case SHA512_DIGEST_ALGORITHM: + ctx->sha512_ctx = (SHA512_CTX*) Malloc(sizeof(SHA512_CTX)); + SHA512_init(ctx->sha512_ctx); + break; + }; +} + +void DigestUpdate(DigestContext* ctx, const uint8_t* data, uint64_t len) { + switch(ctx->algorithm) { + case SHA1_DIGEST_ALGORITHM: + SHA1_update(ctx->sha1_ctx, data, len); + break; + case SHA256_DIGEST_ALGORITHM: + SHA256_update(ctx->sha256_ctx, data, len); + break; + case SHA512_DIGEST_ALGORITHM: + SHA512_update(ctx->sha512_ctx, data, len); + break; + }; +} + +uint8_t* DigestFinal(DigestContext* ctx) { + uint8_t* digest = NULL; + switch(ctx->algorithm) { + case SHA1_DIGEST_ALGORITHM: + digest = (uint8_t*) Malloc(SHA1_DIGEST_SIZE); + Memcpy(digest, SHA1_final(ctx->sha1_ctx), SHA1_DIGEST_SIZE); + Free(ctx->sha1_ctx); + break; + case SHA256_DIGEST_ALGORITHM: + digest = (uint8_t*) Malloc(SHA256_DIGEST_SIZE); + Memcpy(digest, SHA256_final(ctx->sha256_ctx), SHA256_DIGEST_SIZE); + Free(ctx->sha256_ctx); + break; + case SHA512_DIGEST_ALGORITHM: + digest = (uint8_t*) Malloc(SHA512_DIGEST_SIZE); + Memcpy(digest, SHA512_final(ctx->sha512_ctx), SHA512_DIGEST_SIZE); + Free(ctx->sha512_ctx); + break; + }; + return digest; +} + +uint8_t* DigestBuf(const uint8_t* buf, uint64_t len, int sig_algorithm) { + uint8_t* digest = (uint8_t*) Malloc(SHA512_DIGEST_SIZE); /* Use the max. */ + /* Define an array mapping [sig_algorithm] to function pointers to the + * SHA{1|256|512} functions. + */ + typedef uint8_t* (*Hash_ptr) (const uint8_t*, uint64_t, uint8_t*); + Hash_ptr hash[] = { + SHA1, /* RSA 1024 */ + SHA256, + SHA512, + SHA1, /* RSA 2048 */ + SHA256, + SHA512, + SHA1, /* RSA 4096 */ + SHA256, + SHA512, + SHA1, /* RSA 8192 */ + SHA256, + SHA512, + }; + /* Call the appropriate hash function. */ + return hash[sig_algorithm](buf, len, digest); +} diff --git a/firmware/lib/include/stateful_util.h b/firmware/lib/include/stateful_util.h new file mode 100644 index 00000000..e782ed88 --- /dev/null +++ b/firmware/lib/include/stateful_util.h @@ -0,0 +1,62 @@ +/* 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. + */ + +/* Helper functions/wrappers for memory allocations, manipulation and + * comparison. + */ + +#ifndef VBOOT_FIRMWARE_LIB_UTILITY_H_ +#define VBOOT_FIRMWARE_LIB_UTILITY_H_ + +#include "sysincludes.h" + +/* Track remaining data to be read in a buffer. */ +typedef struct MemcpyState { + void* remaining_buf; + uint64_t remaining_len; /* Remaining length of the buffer. */ + uint8_t overrun; /* Flag set to 1 when an overrun occurs. */ +} MemcpyState; + +/* Skip [len] bytes only if there's enough data to skip according + * to [state]. + * On success, return a meaningless but non-NULL pointer and updates [state]. + * On failure, return NULL, set remaining_len in state to -1. + * + * Useful for iterating through a binary blob to populate a struct. After the + * first failure (buffer overrun), successive calls will always fail. + */ +void* StatefulSkip(MemcpyState* state, uint64_t len); + +/* Copy [len] bytes into [dst] only if there's enough data to read according + * to [state]. + * On success, return [dst] and update [state]. + * On failure, return NULL, set remaining len in state to -1. + * + * Useful for iterating through a binary blob to populate a struct. After the + * first failure (buffer overrun), successive calls will always fail. + */ +void* StatefulMemcpy(MemcpyState* state, void* dst, uint64_t len); + +/* Like StatefulMemcpy() but copies in the opposite direction, populating + * data from [src] into the buffer encapsulated in state [state]. + * On success, return [src] and update [state]. + * On failure, return NULL, set remaining_len in state to -1. + * + * Useful for iterating through a structure to populate a binary blob. After the + * first failure (buffer overrun), successive calls will always fail. + */ +const void* StatefulMemcpy_r(MemcpyState* state, const void* src, uint64_t len); + +/* Like StatefulMemcpy_r() but fills a portion of the encapsulated buffer with + * a constant value. + * On success, return a meaningless but non-NULL pointer and updates [state]. + * On failure, return NULL, set remaining_len in state to -1. + * + * After the first failure (buffer overrun), successive calls will always fail. + */ +const void* StatefulMemset_r(MemcpyState* state, const uint8_t val, + uint64_t len); + +#endif /* VBOOT_FIRMWARE_LIB_UTILITY_H_ */ diff --git a/firmware/lib/include/tss_constants.h b/firmware/lib/include/tss_constants.h new file mode 100644 index 00000000..a2371485 --- /dev/null +++ b/firmware/lib/include/tss_constants.h @@ -0,0 +1,79 @@ +/* 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. + * + * Some TPM constants and type definitions for standalone compilation for use in + * the firmware + */ + +/* FIXME(gauravsh): + * NOTE: This file is copied over from + * src/platform/tpm_lite/src/tlcl/tss_constants.h + * Ideally, we want to directly include it without having two maintain + * duplicate copies in sync. But in the current model, this is hard + * to do without breaking standalone compilation. + * Eventually tpm_lite should be moved into vboot_reference. + */ + +#ifndef TPM_LITE_TSS_CONSTANTS_H_ +#define TPM_LITE_TSS_CONSTANTS_H_ + +#include "sysincludes.h" + +#define TPM_MAX_COMMAND_SIZE 4096 +#define TPM_LARGE_ENOUGH_COMMAND_SIZE 256 /* saves space in the firmware */ + +#define TPM_SUCCESS ((uint32_t)0x00000000) +#define TPM_E_BADINDEX ((uint32_t)0x00000002) +#define TPM_E_MAXNVWRITES ((uint32_t)0x00000048) +#define TPM_E_ALREADY_INITIALIZED ((uint32_t)0x00005000) /* vboot local */ +#define TPM_E_INTERNAL_INCONSISTENCY ((uint32_t)0x00005001) /* vboot local */ +#define TPM_E_MUST_REBOOT ((uint32_t)0x00005002) /* vboot local */ + +#define TPM_NV_INDEX0 ((uint32_t)0x00000000) +#define TPM_NV_INDEX_LOCK ((uint32_t)0xffffffff) +#define TPM_NV_PER_WRITE_STCLEAR (((uint32_t)1)<<14) +#define TPM_NV_PER_PPWRITE (((uint32_t)1)<<0) +#define TPM_NV_PER_GLOBALLOCK (((uint32_t)1)<<15) + +typedef uint8_t TSS_BOOL; +typedef uint16_t TPM_STRUCTURE_TAG; + +typedef struct tdTPM_WRITE_INFO { + uint32_t nvIndex; + uint32_t offset; + uint32_t dataSize; +} TPM_WRITE_INFO; + +typedef struct tdTPM_PERMANENT_FLAGS +{ + TPM_STRUCTURE_TAG tag; + TSS_BOOL disable; + TSS_BOOL ownership; + TSS_BOOL deactivated; + TSS_BOOL readPubek; + TSS_BOOL disableOwnerClear; + TSS_BOOL allowMaintenance; + TSS_BOOL physicalPresenceLifetimeLock; + TSS_BOOL physicalPresenceHWEnable; + TSS_BOOL physicalPresenceCMDEnable; + TSS_BOOL CEKPUsed; + TSS_BOOL TPMpost; + TSS_BOOL TPMpostLock; + TSS_BOOL FIPS; + TSS_BOOL Operator; + TSS_BOOL enableRevokeEK; + TSS_BOOL nvLocked; + TSS_BOOL readSRKPub; + TSS_BOOL tpmEstablished; + TSS_BOOL maintenanceDone; + TSS_BOOL disableFullDALogicInfo; +} TPM_PERMANENT_FLAGS; + +#define TPM_ALL_LOCALITIES (TPM_LOC_ZERO | TPM_LOC_ONE | TPM_LOC_TWO \ + | TPM_LOC_THREE | TPM_LOC_FOUR) /* 0x1f */ + +#define TPM_ENCAUTH_SIZE 20 +#define TPM_PUBEK_SIZE 256 + +#endif /* TPM_LITE_TSS_CONSTANTS_H_ */ diff --git a/firmware/lib/include/vboot_common.h b/firmware/lib/include/vboot_common.h new file mode 100644 index 00000000..b7998a7a --- /dev/null +++ b/firmware/lib/include/vboot_common.h @@ -0,0 +1,110 @@ +/* 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. + * + * Common functions between firmware and kernel verified boot. + */ + +#ifndef VBOOT_REFERENCE_VBOOT_COMMON_H_ +#define VBOOT_REFERENCE_VBOOT_COMMON_H_ + +#include "cryptolib.h" +#include "vboot_struct.h" + +/* Error Codes for all common functions. */ +enum { + VBOOT_SUCCESS = 0, + VBOOT_KEY_BLOCK_INVALID, /* Key block internal structure is + * invalid, or not a key block */ + VBOOT_KEY_BLOCK_SIGNATURE, /* Key block signature check failed */ + VBOOT_KEY_BLOCK_HASH, /* Key block hash check failed */ + VBOOT_PUBLIC_KEY_INVALID, /* Invalid public key passed to a + * signature verficiation function. */ + VBOOT_PREAMBLE_INVALID, /* Preamble internal structure is + * invalid */ + VBOOT_PREAMBLE_SIGNATURE, /* Preamble signature check failed */ + VBOOT_ERROR_MAX, +}; +extern char* kVbootErrors[VBOOT_ERROR_MAX]; + + +/* Return offset of ptr from base. */ +uint64_t OffsetOf(const void* base, const void* ptr); + + +/* Helper functions to get data pointed to by a public key or signature. */ +uint8_t* GetPublicKeyData(VbPublicKey* key); +const uint8_t* GetPublicKeyDataC(const VbPublicKey* key); +uint8_t* GetSignatureData(VbSignature* sig); +const uint8_t* GetSignatureDataC(const VbSignature* sig); + + +/* Helper functions to verify the data pointed to by a subfield is inside + * the parent data. Returns 0 if inside, 1 if error. */ +int VerifyMemberInside(const void* parent, uint64_t parent_size, + const void* member, uint64_t member_size, + uint64_t member_data_offset, + uint64_t member_data_size); + +int VerifyPublicKeyInside(const void* parent, uint64_t parent_size, + const VbPublicKey* key); + +int VerifySignatureInside(const void* parent, uint64_t parent_size, + const VbSignature* sig); + + +/* Initialize a public key to refer to [key_data]. */ +void PublicKeyInit(VbPublicKey* key, uint8_t* key_data, uint64_t key_size); + + +/* Copy a public key from [src] to [dest]. + * + * Returns 0 if success, non-zero if error. */ +int PublicKeyCopy(VbPublicKey* dest, const VbPublicKey* src); + + +/* Converts a public key to RsaPublicKey format. The returned key must + * be freed using RSAPublicKeyFree(). + * + * Returns NULL if error. */ +RSAPublicKey* PublicKeyToRSA(const VbPublicKey* key); + + +/* Verifies [data] matches signature [sig] using [key]. */ +int VerifyData(const uint8_t* data, const VbSignature* sig, + const RSAPublicKey* key); + + +/* Verifies a secure hash digest from DigestBuf() or DigestFinal(), + * using [key]. */ +int VerifyDigest(const uint8_t* digest, const VbSignature *sig, + const RSAPublicKey* key); + + +/* Checks the sanity of a key block of size [size] bytes, using public + * key [key]. If [key]==NULL, uses only the block checksum to verify + * the key block. Header fields are also checked for sanity. Does not + * verify key index or key block flags. */ +int KeyBlockVerify(const VbKeyBlockHeader* block, uint64_t size, + const VbPublicKey *key); + + +/* Checks the sanity of a firmware preamble of size [size] bytes, + * using public key [key]. + * + * Returns VBOOT_SUCCESS if successful. */ +int VerifyFirmwarePreamble2(const VbFirmwarePreambleHeader* preamble, + uint64_t size, const RSAPublicKey* key); + + +/* Checks the sanity of a kernel preamble of size [size] bytes, + * using public key [key]. + * + * Returns VBOOT_SUCCESS if successful. */ +int VerifyKernelPreamble2(const VbKernelPreambleHeader* preamble, + uint64_t size, const RSAPublicKey* key); + + + + +#endif /* VBOOT_REFERENCE_VBOOT_COMMON_H_ */ diff --git a/firmware/lib/include/vboot_kernel.h b/firmware/lib/include/vboot_kernel.h new file mode 100644 index 00000000..9cb7f028 --- /dev/null +++ b/firmware/lib/include/vboot_kernel.h @@ -0,0 +1,25 @@ +/* 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. + * + * Data structure and API definitions for a verified boot kernel image. + * (Firmware Portion) + */ + +#ifndef VBOOT_REFERENCE_VBOOT_KERNEL_H_ +#define VBOOT_REFERENCE_VBOOT_KERNEL_H_ + +#include "cgptlib.h" + +/* Allocates and reads GPT data from the drive. The sector_bytes and + * drive_sectors fields should be filled on input. The primary and + * secondary header and entries are filled on output. + * + * Returns 0 if successful, 1 if error. */ +int AllocAndReadGptData(GptData* gptdata); + +/* Writes any changes for the GPT data back to the drive, then frees the + * buffers. */ +int WriteAndFreeGptData(GptData* gptdata); + +#endif /* VBOOT_REFERENCE_VBOOT_KERNEL_H_ */ diff --git a/firmware/lib/include/vboot_struct.h b/firmware/lib/include/vboot_struct.h new file mode 100644 index 00000000..a60615c2 --- /dev/null +++ b/firmware/lib/include/vboot_struct.h @@ -0,0 +1,124 @@ +/* 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. + * + * Data structure definitions for verified boot, for on-disk / in-eeprom + * data. + */ + +#ifndef VBOOT_REFERENCE_VBOOT_STRUCT_H_ +#define VBOOT_REFERENCE_VBOOT_STRUCT_H_ + +#include "sysincludes.h" + + +/* Public key data */ +typedef struct VbPublicKey { + uint64_t key_offset; /* Offset of key data from start of this struct */ + uint64_t key_size; /* Size of key data in bytes (NOT strength of key + * in bits) */ + uint64_t algorithm; /* Signature algorithm used by the key */ + uint64_t key_version; /* Key version */ +} __attribute__((packed)) VbPublicKey; + + +/* Signature data (a secure hash, possibly signed) */ +typedef struct VbSignature { + uint64_t sig_offset; /* Offset of signature data from start of this + * struct */ + uint64_t sig_size; /* Size of signature data in bytes */ + uint64_t data_size; /* Size of the data block which was signed in bytes */ +} __attribute__((packed)) VbSignature; + + +#define KEY_BLOCK_MAGIC "CHROMEOS" +#define KEY_BLOCK_MAGIC_SIZE 8 + +#define KEY_BLOCK_HEADER_VERSION_MAJOR 2 +#define KEY_BLOCK_HEADER_VERSION_MINOR 1 + +/* Flags for key_block_flags */ +/* The following flags set where the key is valid */ +#define KEY_BLOCK_FLAG_DEVELOPER_0 UINT64_C(0x01) /* Developer switch off */ +#define KEY_BLOCK_FLAG_DEVELOPER_1 UINT64_C(0x02) /* Developer switch on */ +#define KEY_BLOCK_FLAG_RECOVERY_0 UINT64_C(0x04) /* Not recovery mode */ +#define KEY_BLOCK_FLAG_RECOVERY_1 UINT64_C(0x08) /* Recovery mode */ + +/* Key block, containing the public key used to sign some other chunk + * of data. */ +typedef struct VbKeyBlockHeader { + uint8_t magic[KEY_BLOCK_MAGIC_SIZE]; /* Magic number */ + uint32_t header_version_major; /* Version of this header format */ + uint32_t header_version_minor; /* Version of this header format */ + uint64_t key_block_size; /* Length of this entire key block, + * including keys, signatures, and + * padding, in bytes */ + VbSignature key_block_signature; /* Signature for this key block + * (header + data pointed to by data_key) + * For use with signed data keys*/ + VbSignature key_block_checksum; /* SHA-512 checksum for this key block + * (header + data pointed to by data_key) + * For use with unsigned data keys */ + uint64_t key_block_flags; /* Flags for key (KEY_BLOCK_FLAG_*) */ + VbPublicKey data_key; /* Key to verify the chunk of data */ +} __attribute__((packed)) VbKeyBlockHeader; +/* This should be followed by: + * 1) The data_key key data, pointed to by data_key.key_offset. + * 2) The checksum data for (VBKeyBlockHeader + data_key data), pointed to + * by key_block_checksum.sig_offset. + * 3) The signature data for (VBKeyBlockHeader + data_key data), pointed to + * by key_block_signature.sig_offset. */ + + +#define FIRMWARE_PREAMBLE_HEADER_VERSION_MAJOR 2 +#define FIRMWARE_PREAMBLE_HEADER_VERSION_MINOR 0 + +/* Preamble block for rewritable firmware */ +typedef struct VbFirmwarePreambleHeader { + uint64_t preamble_size; /* Size of this preamble, including keys, + * signatures, and padding, in bytes */ + VbSignature preamble_signature; /* Signature for this preamble + * (header + kernel subkey + + * body signature) */ + uint32_t header_version_major; /* Version of this header format */ + uint32_t header_version_minor; /* Version of this header format */ + + uint64_t firmware_version; /* Firmware version */ + VbPublicKey kernel_subkey; /* Key to verify kernel key block */ + VbSignature body_signature; /* Signature for the firmware body */ +} __attribute__((packed)) VbFirmwarePreambleHeader; +/* This should be followed by: + * 1) The kernel_subkey key data, pointed to by kernel_subkey.key_offset. + * 2) The signature data for the firmware body, pointed to by + * body_signature.sig_offset. + * 3) The signature data for (VBFirmwarePreambleHeader + kernel_subkey data + * + body signature data), pointed to by + * preamble_signature.sig_offset. */ + + +#define KERNEL_PREAMBLE_HEADER_VERSION_MAJOR 2 +#define KERNEL_PREAMBLE_HEADER_VERSION_MINOR 0 + +/* Preamble block for kernel */ +typedef struct VbKernelPreambleHeader { + uint64_t preamble_size; /* Size of this preamble, including keys, + * signatures, and padding, in bytes */ + VbSignature preamble_signature; /* Signature for this preamble + * (header + body signature) */ + uint32_t header_version_major; /* Version of this header format */ + uint32_t header_version_minor; /* Version of this header format */ + + uint64_t kernel_version; /* Kernel version */ + uint64_t body_load_address; /* Load address for kernel body */ + uint64_t bootloader_address; /* Address of bootloader, after body is + * loaded at body_load_address */ + uint64_t bootloader_size; /* Size of bootloader in bytes */ + VbSignature body_signature; /* Signature for the kernel body */ +} __attribute__((packed)) VbKernelPreambleHeader; +/* This should be followed by: + * 2) The signature data for the kernel body, pointed to by + * body_signature.sig_offset. + * 3) The signature data for (VBFirmwarePreambleHeader + body signature + * data), pointed to by preamble_signature.sig_offset. */ + +#endif /* VBOOT_REFERENCE_VBOOT_STRUCT_H_ */ diff --git a/firmware/lib/rollback_index.c b/firmware/lib/rollback_index.c new file mode 100644 index 00000000..cb86e89e --- /dev/null +++ b/firmware/lib/rollback_index.c @@ -0,0 +1,362 @@ +/* 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 querying, manipulating and locking rollback indices + * stored in the TPM NVRAM. + */ + +#include "rollback_index.h" + +#include "tlcl.h" +#include "tss_constants.h" +#include "utility.h" + +uint16_t g_firmware_key_version = 0; +uint16_t g_firmware_version = 0; +uint16_t g_kernel_key_version = 0; +uint16_t g_kernel_version = 0; + +#define RETURN_ON_FAILURE(tpm_command) do { \ + uint32_t result; \ + if ((result = (tpm_command)) != TPM_SUCCESS) { \ + return result; \ + } \ + } while (0) + +static uint32_t InitializeKernelVersionsSpaces(void) { + RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_VERSIONS_NV_INDEX, + TPM_NV_PER_PPWRITE, KERNEL_SPACE_SIZE)); + RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_NV_INDEX, KERNEL_SPACE_INIT_DATA, + KERNEL_SPACE_SIZE)); + return TPM_SUCCESS; +} + +/* When the return value is TPM_SUCCESS, this function sets *|initialized| to 1 + * if the spaces have been fully initialized, to 0 if not. Otherwise + * *|initialized| is not changed. + */ +static uint32_t GetSpacesInitialized(int* initialized) { + uint32_t space_holder; + uint32_t result; + result = TlclRead(TPM_IS_INITIALIZED_NV_INDEX, + (uint8_t*) &space_holder, sizeof(space_holder)); + switch (result) { + case TPM_SUCCESS: + *initialized = 1; + break; + case TPM_E_BADINDEX: + *initialized = 0; + result = TPM_SUCCESS; + break; + } + return result; +} + +/* Creates the NVRAM spaces, and sets their initial values as needed. + */ +static uint32_t InitializeSpaces(void) { + uint32_t zero = 0; + uint32_t firmware_perm = TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE; + + debug("Initializing spaces\n"); + + RETURN_ON_FAILURE(TlclSetNvLocked()); + + RETURN_ON_FAILURE(TlclDefineSpace(FIRMWARE_VERSIONS_NV_INDEX, + firmware_perm, sizeof(uint32_t))); + RETURN_ON_FAILURE(TlclWrite(FIRMWARE_VERSIONS_NV_INDEX, + (uint8_t*) &zero, sizeof(uint32_t))); + + RETURN_ON_FAILURE(InitializeKernelVersionsSpaces()); + + /* The space KERNEL_VERSIONS_BACKUP_NV_INDEX is used to protect the kernel + * versions. The content of space KERNEL_MUST_USE_BACKUP determines whether + * only the backup value should be trusted. + */ + RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_VERSIONS_BACKUP_NV_INDEX, + firmware_perm, sizeof(uint32_t))); + RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_BACKUP_NV_INDEX, + (uint8_t*) &zero, sizeof(uint32_t))); + RETURN_ON_FAILURE(TlclDefineSpace(KERNEL_MUST_USE_BACKUP_NV_INDEX, + firmware_perm, sizeof(uint32_t))); + RETURN_ON_FAILURE(TlclWrite(KERNEL_MUST_USE_BACKUP_NV_INDEX, + (uint8_t*) &zero, sizeof(uint32_t))); + RETURN_ON_FAILURE(TlclDefineSpace(DEVELOPER_MODE_NV_INDEX, + firmware_perm, sizeof(uint32_t))); + RETURN_ON_FAILURE(TlclWrite(DEVELOPER_MODE_NV_INDEX, + (uint8_t*) &zero, sizeof(uint32_t))); + + /* The space TPM_IS_INITIALIZED_NV_INDEX is used to indicate that the TPM + * initialization has completed. Without it we cannot be sure that the last + * space to be created was also initialized (power could have been lost right + * after its creation). + */ + RETURN_ON_FAILURE(TlclDefineSpace(TPM_IS_INITIALIZED_NV_INDEX, + firmware_perm, sizeof(uint32_t))); + return TPM_SUCCESS; +} + +static uint32_t SetDistrustKernelSpaceAtNextBoot(uint32_t distrust) { + uint32_t must_use_backup; + RETURN_ON_FAILURE(TlclRead(KERNEL_MUST_USE_BACKUP_NV_INDEX, + (uint8_t*) &must_use_backup, sizeof(uint32_t))); + if (must_use_backup != distrust) { + RETURN_ON_FAILURE(TlclWrite(KERNEL_MUST_USE_BACKUP_NV_INDEX, + (uint8_t*) &distrust, sizeof(uint32_t))); + } + return TPM_SUCCESS; +} + +static uint32_t GetTPMRollbackIndices(int type) { + uint32_t firmware_versions; + uint32_t kernel_versions; + + /* We perform the reads, making sure they succeed. A failure means that the + * rollback index locations are missing or somehow messed up. We let the + * caller deal with that. + */ + switch (type) { + case FIRMWARE_VERSIONS: + RETURN_ON_FAILURE(TlclRead(FIRMWARE_VERSIONS_NV_INDEX, + (uint8_t*) &firmware_versions, + sizeof(firmware_versions))); + g_firmware_key_version = firmware_versions >> 16; + g_firmware_version = firmware_versions && 0xffff; + break; + case KERNEL_VERSIONS: + RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX, + (uint8_t*) &kernel_versions, + sizeof(kernel_versions))); + g_kernel_key_version = kernel_versions >> 16; + g_kernel_version = kernel_versions && 0xffff; + break; + } + + return TPM_SUCCESS; +} + +/* Checks if the kernel version space has been mucked with. If it has, + * reconstructs it using the backup value. + */ +uint32_t RecoverKernelSpace(void) { + uint32_t perms = 0; + uint8_t buffer[KERNEL_SPACE_SIZE]; + int read_OK = 0; + int perms_OK = 0; + uint32_t backup_combined_versions; + uint32_t must_use_backup; + + RETURN_ON_FAILURE(TlclRead(KERNEL_MUST_USE_BACKUP_NV_INDEX, + (uint8_t*) &must_use_backup, sizeof(uint32_t))); + /* must_use_backup is true if the previous boot entered recovery mode. */ + + read_OK = TlclRead(KERNEL_VERSIONS_NV_INDEX, (uint8_t*) &buffer, + KERNEL_SPACE_SIZE) == TPM_SUCCESS; + if (read_OK) { + RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_VERSIONS_NV_INDEX, &perms)); + perms_OK = perms == TPM_NV_PER_PPWRITE; + } + if (!must_use_backup && read_OK && perms_OK && + !Memcmp(buffer + sizeof(uint32_t), KERNEL_SPACE_UID, + KERNEL_SPACE_UID_SIZE)) { + /* Everything is fine. This is the normal, frequent path. */ + return TPM_SUCCESS; + } + + /* Either we detected that something went wrong, or we cannot trust the + * PP-protected kernel space. Attempts to fix. It is not always necessary + * to redefine the space, but we might as well, since this path should be + * taken quite seldom (after recovery mode and after an attack). + */ + RETURN_ON_FAILURE(InitializeKernelVersionsSpaces()); + RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_BACKUP_NV_INDEX, + (uint8_t*) &backup_combined_versions, + sizeof(uint32_t))); + RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_NV_INDEX, + (uint8_t*) &backup_combined_versions, + sizeof(uint32_t))); + if (must_use_backup) { + uint32_t zero = 0; + RETURN_ON_FAILURE(TlclWrite(KERNEL_MUST_USE_BACKUP_NV_INDEX, + (uint8_t*) &zero, 0)); + + } + return TPM_SUCCESS; +} + +static uint32_t BackupKernelSpace(void) { + uint32_t kernel_versions; + uint32_t backup_versions; + RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_NV_INDEX, + (uint8_t*) &kernel_versions, sizeof(uint32_t))); + RETURN_ON_FAILURE(TlclRead(KERNEL_VERSIONS_BACKUP_NV_INDEX, + (uint8_t*) &backup_versions, sizeof(uint32_t))); + if (kernel_versions == backup_versions) { + return TPM_SUCCESS; + } else if (kernel_versions < backup_versions) { + /* This cannot happen. We're screwed. */ + return TPM_E_INTERNAL_INCONSISTENCY; + } + RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_BACKUP_NV_INDEX, + (uint8_t*) &kernel_versions, sizeof(uint32_t))); + return TPM_SUCCESS; +} + +/* Checks for transitions between protected mode to developer mode. When going + * into developer mode, clear the TPM. + */ +static uint32_t CheckDeveloperModeTransition(uint32_t current_developer) { + uint32_t past_developer; + int must_clear; + RETURN_ON_FAILURE(TlclRead(DEVELOPER_MODE_NV_INDEX, + (uint8_t*) &past_developer, + sizeof(past_developer))); + must_clear = current_developer != past_developer; + if (must_clear) { + RETURN_ON_FAILURE(TlclForceClear()); + } + if (past_developer != current_developer) { + /* (Unauthorized) writes to the TPM succeed even when the TPM is disabled + * and deactivated. + */ + RETURN_ON_FAILURE(TlclWrite(DEVELOPER_MODE_NV_INDEX, + (uint8_t*) ¤t_developer, + sizeof(current_developer))); + } + return must_clear ? TPM_E_MUST_REBOOT : TPM_SUCCESS; +} + +static uint32_t SetupTPM_(int mode, int developer_flag) { + uint8_t disable; + uint8_t deactivated; + TlclLibInit(); + RETURN_ON_FAILURE(TlclStartup()); + RETURN_ON_FAILURE(TlclContinueSelfTest()); + RETURN_ON_FAILURE(TlclAssertPhysicalPresence()); + /* Checks that the TPM is enabled and activated. */ + RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated)); + if (disable || deactivated) { + RETURN_ON_FAILURE(TlclSetEnable()); + RETURN_ON_FAILURE(TlclSetDeactivated(0)); + return TPM_E_MUST_REBOOT; + } + /* We expect this to fail the first time we run on a device, because the TPM + * has not been initialized yet. + */ + if (RecoverKernelSpace() != TPM_SUCCESS) { + int initialized = 0; + RETURN_ON_FAILURE(GetSpacesInitialized(&initialized)); + if (initialized) { + return TPM_E_ALREADY_INITIALIZED; + } else { + RETURN_ON_FAILURE(InitializeSpaces()); + RETURN_ON_FAILURE(RecoverKernelSpace()); + } + } + RETURN_ON_FAILURE(BackupKernelSpace()); + RETURN_ON_FAILURE(SetDistrustKernelSpaceAtNextBoot(mode == RO_RECOVERY_MODE)); + RETURN_ON_FAILURE(GetTPMRollbackIndices(FIRMWARE_VERSIONS)); + RETURN_ON_FAILURE(GetTPMRollbackIndices(KERNEL_VERSIONS)); + + RETURN_ON_FAILURE(CheckDeveloperModeTransition(developer_flag)); + + /* As a courtesy (I hope) to the caller, lock the firmware versions if we are + * in recovery mode. The normal mode may need to update the firmware + * versions, so they cannot be locked here. + */ + if (mode == RO_RECOVERY_MODE) { + RETURN_ON_FAILURE(LockFirmwareVersions()); + } + return TPM_SUCCESS; +} + +/* SetupTPM starts the TPM and establishes the root of trust for the + * anti-rollback mechanism. SetupTPM can fail for three reasons. 1 A bug. 2 a + * TPM hardware failure. 3 An unexpected TPM state due to some attack. In + * general we cannot easily distinguish the kind of failure, so our strategy is + * to reboot in recovery mode in all cases. The recovery mode calls SetupTPM + * again, which executes (almost) the same sequence of operations. There is a + * good chance that, if recovery mode was entered because of a TPM failure, the + * failure will repeat itself. (In general this is impossible to guarantee + * because we have no way of creating the exact TPM initial state at the + * previous boot.) In recovery mode, we ignore the failure and continue, thus + * giving the recovery kernel a chance to fix things (that's why we don't set + * bGlobalLock). The choice is between a knowingly insecure device and a + * bricked device. + * + * As a side note, observe that we go through considerable hoops to avoid using + * the STCLEAR permissions for the index spaces. We do this to avoid writing + * to the TPM flashram at every reboot or wake-up, because of concerns about + * the durability of the NVRAM. + */ +uint32_t SetupTPM(int mode, int developer_flag) { + switch (mode) { + case RO_RECOVERY_MODE: + case RO_NORMAL_MODE: { + uint32_t result = SetupTPM_(mode, developer_flag); + if (result == TPM_E_MAXNVWRITES) { + /* ForceClears and reboots */ + RETURN_ON_FAILURE(TlclForceClear()); + return TPM_E_MUST_REBOOT; + } else if (mode == RO_NORMAL_MODE) { + return result; + } else { + /* In recovery mode we want to keep going even if there are errors. */ + return TPM_SUCCESS; + } + } + case RW_NORMAL_MODE: + /* There are no TPM writes here, so no need to check for write limit errors. + */ + RETURN_ON_FAILURE(GetTPMRollbackIndices(KERNEL_VERSIONS)); + default: + return TPM_E_INTERNAL_INCONSISTENCY; + } +} + +uint32_t GetStoredVersions(int type, uint16_t* key_version, uint16_t* version) { + /* TODO: should verify that SetupTPM() has been called. + * + * Note that SetupTPM() does hardware setup AND sets global variables. When + * we get down into kernel verification, the hardware setup persists, but we + * lose the global variables. + */ + switch (type) { + case FIRMWARE_VERSIONS: + *key_version = g_firmware_key_version; + *version = g_firmware_version; + break; + case KERNEL_VERSIONS: + *key_version = g_kernel_key_version; + *version = g_kernel_version; + break; + } + + return TPM_SUCCESS; +} + +uint32_t WriteStoredVersions(int type, uint16_t key_version, uint16_t version) { + uint32_t combined_version = (key_version << 16) & version; + switch (type) { + case FIRMWARE_VERSIONS: + RETURN_ON_FAILURE(TlclWrite(FIRMWARE_VERSIONS_NV_INDEX, + (uint8_t*) &combined_version, + sizeof(uint32_t))); + break; + + case KERNEL_VERSIONS: + RETURN_ON_FAILURE(TlclWrite(KERNEL_VERSIONS_NV_INDEX, + (uint8_t*) &combined_version, + sizeof(uint32_t))); + } + return TPM_SUCCESS; +} + +uint32_t LockFirmwareVersions() { + return TlclSetGlobalLock(); +} + +uint32_t LockKernelVersionsByLockingPP() { + return TlclLockPhysicalPresence(); +} diff --git a/firmware/lib/stateful_util.c b/firmware/lib/stateful_util.c new file mode 100644 index 00000000..137ea77a --- /dev/null +++ b/firmware/lib/stateful_util.c @@ -0,0 +1,65 @@ +/* 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. + * + * Stub implementations of utility functions which call their linux-specific + * equivalents. + */ + +#include "stateful_util.h" + +#include "utility.h" + +void* StatefulSkip(MemcpyState* state, uint64_t len) { + if (state->overrun) + return NULL; + if (len > state->remaining_len) { + state->overrun = 1; + return NULL; + } + state->remaining_buf += len; + state->remaining_len -= len; + return state; // have to return something non-NULL +} + +void* StatefulMemcpy(MemcpyState* state, void* dst, + uint64_t len) { + if (state->overrun) + return NULL; + if (len > state->remaining_len) { + state->overrun = 1; + return NULL; + } + Memcpy(dst, state->remaining_buf, len); + state->remaining_buf += len; + state->remaining_len -= len; + return dst; +} + +const void* StatefulMemcpy_r(MemcpyState* state, const void* src, + uint64_t len) { + if (state->overrun) + return NULL; + if (len > state->remaining_len) { + state->overrun = 1; + return NULL; + } + Memcpy(state->remaining_buf, src, len); + state->remaining_buf += len; + state->remaining_len -= len; + return src; +} + +const void* StatefulMemset_r(MemcpyState* state, const uint8_t val, + uint64_t len) { + if (state->overrun) + return NULL; + if (len > state->remaining_len) { + state->overrun = 1; + return NULL; + } + Memset(state->remaining_buf, val, len); + state->remaining_buf += len; + state->remaining_len -= len; + return state; // have to return something non-NULL +} diff --git a/firmware/lib/vboot_common.c b/firmware/lib/vboot_common.c new file mode 100644 index 00000000..f76eed45 --- /dev/null +++ b/firmware/lib/vboot_common.c @@ -0,0 +1,341 @@ +/* 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. + * + * Common functions between firmware and kernel verified boot. + * (Firmware portion) + */ + + +#include "vboot_common.h" +#include "utility.h" + + +char* kVbootErrors[VBOOT_ERROR_MAX] = { + "Success.", + "Key block invalid.", + "Key block signature failed.", + "Key block hash failed.", + "Public key invalid.", + "Preamble invalid.", + "Preamble signature check failed.", +}; + + +uint64_t OffsetOf(const void *base, const void *ptr) { + return (uint64_t)(size_t)ptr - (uint64_t)(size_t)base; +} + + +/* Helper functions to get data pointed to by a public key or signature. */ +uint8_t* GetPublicKeyData(VbPublicKey* key) { + return (uint8_t*)key + key->key_offset; +} + +const uint8_t* GetPublicKeyDataC(const VbPublicKey* key) { + return (const uint8_t*)key + key->key_offset; +} + +uint8_t* GetSignatureData(VbSignature* sig) { + return (uint8_t*)sig + sig->sig_offset; +} + +const uint8_t* GetSignatureDataC(const VbSignature* sig) { + return (const uint8_t*)sig + sig->sig_offset; +} + + +/* Helper functions to verify the data pointed to by a subfield is inside + * the parent data. Returns 0 if inside, 1 if error. */ +int VerifyMemberInside(const void* parent, uint64_t parent_size, + const void* member, uint64_t member_size, + uint64_t member_data_offset, + uint64_t member_data_size) { + uint64_t end = OffsetOf(parent, member); + + if (end > parent_size) + return 1; + + if (end + member_size > parent_size) + return 1; + + end += member_data_offset; + if (end > parent_size) + return 1; + if (end + member_data_size > parent_size) + return 1; + + return 0; +} + + +int VerifyPublicKeyInside(const void* parent, uint64_t parent_size, + const VbPublicKey* key) { + return VerifyMemberInside(parent, parent_size, + key, sizeof(VbPublicKey), + key->key_offset, key->key_size); +} + + +int VerifySignatureInside(const void* parent, uint64_t parent_size, + const VbSignature* sig) { + return VerifyMemberInside(parent, parent_size, + sig, sizeof(VbSignature), + sig->sig_offset, sig->sig_size); +} + + +void PublicKeyInit(VbPublicKey* key, uint8_t* key_data, uint64_t key_size) { + key->key_offset = OffsetOf(key, key_data); + key->key_size = key_size; + key->algorithm = kNumAlgorithms; /* Key not present yet */ + key->key_version = 0; +} + + +int PublicKeyCopy(VbPublicKey* dest, const VbPublicKey* src) { + if (dest->key_size < src->key_size) + return 1; + + dest->key_size = src->key_size; + dest->algorithm = src->algorithm; + dest->key_version = src->key_version; + Memcpy(GetPublicKeyData(dest), GetPublicKeyDataC(src), src->key_size); + return 0; +} + + +RSAPublicKey* PublicKeyToRSA(const VbPublicKey* key) { + RSAPublicKey *rsa; + + if (kNumAlgorithms <= key->algorithm) { + debug("Invalid algorithm.\n"); + return NULL; + } + if (RSAProcessedKeySize(key->algorithm) != key->key_size) { + debug("Wrong key size for algorithm\n"); + return NULL; + } + + rsa = RSAPublicKeyFromBuf(GetPublicKeyDataC(key), key->key_size); + if (!rsa) + return NULL; + + rsa->algorithm = key->algorithm; + return rsa; +} + + +int VerifyData(const uint8_t* data, const VbSignature *sig, + const RSAPublicKey* key) { + + if (sig->sig_size != siglen_map[key->algorithm]) { + debug("Wrong signature size for algorithm.\n"); + return 1; + } + + if (!RSAVerifyBinary_f(NULL, key, data, sig->data_size, + GetSignatureDataC(sig), key->algorithm)) + return 1; + + return 0; +} + + +int VerifyDigest(const uint8_t* digest, const VbSignature *sig, + const RSAPublicKey* key) { + + if (sig->sig_size != siglen_map[key->algorithm]) { + debug("Wrong signature size for algorithm.\n"); + return 1; + } + + if (!RSAVerifyBinaryWithDigest_f(NULL, key, digest, + GetSignatureDataC(sig), key->algorithm)) + return 1; + + return 0; +} + + +int KeyBlockVerify(const VbKeyBlockHeader* block, uint64_t size, + const VbPublicKey *key) { + + const VbSignature* sig; + + /* Sanity checks before attempting signature of data */ + if (SafeMemcmp(block->magic, KEY_BLOCK_MAGIC, KEY_BLOCK_MAGIC_SIZE)) { + debug("Not a valid verified boot key block.\n"); + return VBOOT_KEY_BLOCK_INVALID; + } + if (block->header_version_major != KEY_BLOCK_HEADER_VERSION_MAJOR) { + debug("Incompatible key block header version.\n"); + return VBOOT_KEY_BLOCK_INVALID; + } + if (size < block->key_block_size) { + debug("Not enough data for key block.\n"); + return VBOOT_KEY_BLOCK_INVALID; + } + + /* Check signature or hash, depending on whether we have a key. */ + if (key) { + /* Check signature */ + RSAPublicKey* rsa; + int rv; + + sig = &block->key_block_signature; + + if (VerifySignatureInside(block, block->key_block_size, sig)) { + debug("Key block signature off end of block\n"); + return VBOOT_KEY_BLOCK_INVALID; + } + + if (!((rsa = PublicKeyToRSA(key)))) { + debug("Invalid public key\n"); + return VBOOT_PUBLIC_KEY_INVALID; + } + rv = VerifyData((const uint8_t*)block, sig, rsa); + RSAPublicKeyFree(rsa); + if (rv) + return VBOOT_KEY_BLOCK_SIGNATURE; + + } else { + /* Check hash */ + uint8_t* header_checksum = NULL; + int rv; + + sig = &block->key_block_checksum; + + if (VerifySignatureInside(block, block->key_block_size, sig)) { + debug("Key block hash off end of block\n"); + return VBOOT_KEY_BLOCK_INVALID; + } + if (sig->sig_size != SHA512_DIGEST_SIZE) { + debug("Wrong hash size for key block.\n"); + return VBOOT_KEY_BLOCK_INVALID; + } + + header_checksum = DigestBuf((const uint8_t*)block, sig->data_size, + SHA512_DIGEST_ALGORITHM); + rv = SafeMemcmp(header_checksum, GetSignatureDataC(sig), + SHA512_DIGEST_SIZE); + Free(header_checksum); + if (rv) { + debug("Invalid key block hash.\n"); + return VBOOT_KEY_BLOCK_HASH; + } + } + + /* Verify we signed enough data */ + if (sig->data_size < sizeof(VbKeyBlockHeader)) { + debug("Didn't sign enough data\n"); + return VBOOT_KEY_BLOCK_INVALID; + } + + /* Verify data key is inside the block and inside signed data */ + if (VerifyPublicKeyInside(block, block->key_block_size, &block->data_key)) { + debug("Data key off end of key block\n"); + return VBOOT_KEY_BLOCK_INVALID; + } + if (VerifyPublicKeyInside(block, sig->data_size, &block->data_key)) { + debug("Data key off end of signed data\n"); + return VBOOT_KEY_BLOCK_INVALID; + } + + /* Success */ + return VBOOT_SUCCESS; +} + + +int VerifyFirmwarePreamble2(const VbFirmwarePreambleHeader* preamble, + uint64_t size, const RSAPublicKey* key) { + + const VbSignature* sig = &preamble->preamble_signature; + + /* Sanity checks before attempting signature of data */ + if (preamble->header_version_major != + FIRMWARE_PREAMBLE_HEADER_VERSION_MAJOR) { + debug("Incompatible firmware preamble header version.\n"); + return VBOOT_PREAMBLE_INVALID; + } + if (size < preamble->preamble_size) { + debug("Not enough data for preamble.\n"); + return VBOOT_PREAMBLE_INVALID; + } + + /* Check signature */ + if (VerifySignatureInside(preamble, preamble->preamble_size, sig)) { + debug("Preamble signature off end of preamble\n"); + return VBOOT_PREAMBLE_INVALID; + } + if (VerifyData((const uint8_t*)preamble, sig, key)) { + debug("Preamble signature validation failed\n"); + return VBOOT_PREAMBLE_SIGNATURE; + } + + /* Verify we signed enough data */ + if (sig->data_size < sizeof(VbFirmwarePreambleHeader)) { + debug("Didn't sign enough data\n"); + return VBOOT_PREAMBLE_INVALID; + } + + /* Verify body signature is inside the block */ + if (VerifySignatureInside(preamble, preamble->preamble_size, + &preamble->body_signature)) { + debug("Firmware body signature off end of preamble\n"); + return VBOOT_PREAMBLE_INVALID; + } + + /* Verify kernel subkey is inside the block */ + if (VerifyPublicKeyInside(preamble, preamble->preamble_size, + &preamble->kernel_subkey)) { + debug("Kernel subkey off end of preamble\n"); + return VBOOT_PREAMBLE_INVALID; + } + + /* Success */ + return VBOOT_SUCCESS; +} + + +int VerifyKernelPreamble2(const VbKernelPreambleHeader* preamble, + uint64_t size, const RSAPublicKey* key) { + + const VbSignature* sig = &preamble->preamble_signature; + + /* Sanity checks before attempting signature of data */ + if (preamble->header_version_major != KERNEL_PREAMBLE_HEADER_VERSION_MAJOR) { + debug("Incompatible kernel preamble header version.\n"); + return VBOOT_PREAMBLE_INVALID; + } + if (size < preamble->preamble_size) { + debug("Not enough data for preamble.\n"); + return VBOOT_PREAMBLE_INVALID; + } + + /* Check signature */ + if (VerifySignatureInside(preamble, preamble->preamble_size, sig)) { + debug("Preamble signature off end of preamble\n"); + return VBOOT_PREAMBLE_INVALID; + } + if (VerifyData((const uint8_t*)preamble, sig, key)) { + debug("Preamble signature validation failed\n"); + return VBOOT_PREAMBLE_SIGNATURE; + } + + /* Verify we signed enough data */ + if (sig->data_size < sizeof(VbKernelPreambleHeader)) { + debug("Didn't sign enough data\n"); + return VBOOT_PREAMBLE_INVALID; + } + + /* Verify body signature is inside the block */ + if (VerifySignatureInside(preamble, preamble->preamble_size, + &preamble->body_signature)) { + debug("Kernel body signature off end of preamble\n"); + return VBOOT_PREAMBLE_INVALID; + } + + /* Success */ + return VBOOT_SUCCESS; +} diff --git a/firmware/lib/vboot_firmware.c b/firmware/lib/vboot_firmware.c new file mode 100644 index 00000000..88d6bb64 --- /dev/null +++ b/firmware/lib/vboot_firmware.c @@ -0,0 +1,209 @@ +/* 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. + * + * High-level firmware API for loading and verifying rewritable firmware. + * (Firmware portion) + */ + +#include "load_firmware_fw.h" +#include "rollback_index.h" +#include "utility.h" +#include "vboot_common.h" + +/* Static variables for UpdateFirmwareBodyHash(). It's less than + * optimal to have static variables in a library, but in UEFI the + * caller is deep inside a different firmware stack and doesn't have a + * good way to pass the params struct back to us. */ +typedef struct VbLoadFirmwareInternal { + DigestContext body_digest_context; + uint64_t body_size_accum; +} VbLoadFirmwareInternal; + + +void UpdateFirmwareBodyHash(LoadFirmwareParams* params, + uint8_t* data, uint64_t size) { + VbLoadFirmwareInternal* lfi = + (VbLoadFirmwareInternal*)params->load_firmware_internal; + + DigestUpdate(&lfi->body_digest_context, data, size); + lfi->body_size_accum += size; +} + + +int LoadFirmware(LoadFirmwareParams* params) { + + VbPublicKey* root_key = (VbPublicKey*)params->firmware_root_key_blob; + VbLoadFirmwareInternal* lfi; + + uint16_t tpm_key_version = 0; + uint16_t tpm_fw_version = 0; + uint64_t lowest_key_version = 0xFFFF; + uint64_t lowest_fw_version = 0xFFFF; + int good_index = -1; + int index; + + /* Clear output params in case we fail */ + params->firmware_index = 0; + params->kernel_sign_key_blob = NULL; + params->kernel_sign_key_size = 0; + + /* Must have a root key */ + if (!root_key) + return LOAD_FIRMWARE_RECOVERY; + + /* Initialize the TPM and read rollback indices. */ + /* TODO: fix SetupTPM parameter */ + if (0 != SetupTPM(0, 0) ) + return LOAD_FIRMWARE_RECOVERY; + if (0 != GetStoredVersions(FIRMWARE_VERSIONS, + &tpm_key_version, &tpm_fw_version)) + return LOAD_FIRMWARE_RECOVERY; + + /* Allocate our internal data */ + lfi = (VbLoadFirmwareInternal*)Malloc(sizeof(VbLoadFirmwareInternal)); + if (!lfi) + return LOAD_FIRMWARE_RECOVERY; + params->load_firmware_internal = lfi; + + /* Loop over indices */ + for (index = 0; index < 2; index++) { + VbKeyBlockHeader* key_block; + uint64_t vblock_size; + VbFirmwarePreambleHeader* preamble; + RSAPublicKey* data_key; + uint64_t key_version; + uint8_t* body_digest; + + /* Verify the key block */ + if (0 == index) { + key_block = (VbKeyBlockHeader*)params->verification_block_0; + vblock_size = params->verification_size_0; + } else { + key_block = (VbKeyBlockHeader*)params->verification_block_1; + vblock_size = params->verification_size_1; + } + if ((0 != KeyBlockVerify(key_block, vblock_size, root_key))) + continue; + + /* Check for rollback of key version. */ + key_version = key_block->data_key.key_version; + if (key_version < tpm_key_version) + continue; + + /* Get the key for preamble/data verification from the key block. */ + data_key = PublicKeyToRSA(&key_block->data_key); + if (!data_key) + continue; + + /* Verify the preamble, which follows the key block. */ + preamble = (VbFirmwarePreambleHeader*)((uint8_t*)key_block + + key_block->key_block_size); + if ((0 != VerifyFirmwarePreamble2(preamble, + vblock_size - key_block->key_block_size, + data_key))) { + RSAPublicKeyFree(data_key); + continue; + } + + /* Check for rollback of firmware version. */ + if (key_version == tpm_key_version && + preamble->firmware_version < tpm_fw_version) { + RSAPublicKeyFree(data_key); + continue; + } + + /* Check for lowest key version from a valid header. */ + if (lowest_key_version > key_version) { + lowest_key_version = key_version; + lowest_fw_version = preamble->firmware_version; + } + else if (lowest_key_version == key_version && + lowest_fw_version > preamble->firmware_version) { + lowest_fw_version = preamble->firmware_version; + } + + /* If we already have good firmware, no need to read another one; + * we only needed to look at the versions to check for + * rollback. */ + if (-1 != good_index) + continue; + + /* Read the firmware data */ + DigestInit(&lfi->body_digest_context, data_key->algorithm); + lfi->body_size_accum = 0; + if ((0 != GetFirmwareBody(params, index)) || + (lfi->body_size_accum != preamble->body_signature.data_size)) { + RSAPublicKeyFree(data_key); + continue; + } + + /* Verify firmware data */ + body_digest = DigestFinal(&lfi->body_digest_context); + if (0 != VerifyDigest(body_digest, &preamble->body_signature, data_key)) { + RSAPublicKeyFree(data_key); + Free(body_digest); + continue; + } + + /* Done with the digest and data key, so can free them now */ + RSAPublicKeyFree(data_key); + Free(body_digest); + + /* If we're still here, the firmware is valid. */ + if (-1 == good_index) { + VbPublicKey *kdest = (VbPublicKey*)params->kernel_sign_key_blob; + + /* Copy the kernel sign key blob into the destination buffer */ + PublicKeyInit(kdest, (uint8_t*)(kdest + 1), + (params->kernel_sign_key_size - sizeof(VbPublicKey))); + + if (0 != PublicKeyCopy(kdest, &preamble->kernel_subkey)) + continue; /* The firmware signature was good, but the public + * key was bigger that the caller can handle. */ + + /* Save the key size we actually used */ + params->kernel_sign_key_size = kdest->key_offset + kdest->key_size; + + /* Save the good index, now that we're sure we can actually use + * this firmware. That's the one we'll boot. */ + good_index = index; + params->firmware_index = index; + + /* If the good firmware's key version is the same as the tpm, + * then the TPM doesn't need updating; we can stop now. + * Otherwise, we'll check all the other headers to see if they + * contain a newer key. */ + if (key_version == tpm_key_version && + preamble->firmware_version == tpm_fw_version) + break; + } + } + + /* Free internal data */ + Free(lfi); + params->load_firmware_internal = NULL; + + /* Handle finding good firmware */ + if (good_index >= 0) { + + /* Update TPM if necessary */ + if ((lowest_key_version > tpm_key_version) || + (lowest_key_version == tpm_key_version && + lowest_fw_version > tpm_fw_version)) { + if (0 != WriteStoredVersions(FIRMWARE_VERSIONS, + lowest_key_version, + lowest_fw_version)) + return LOAD_FIRMWARE_RECOVERY; + } + + /* Lock Firmware TPM rollback indices from further writes. In + * this design, this is done by setting the globalLock bit, which + * is cleared only by TPM_Init at reboot. */ + if (0 != LockFirmwareVersions()) + return LOAD_FIRMWARE_RECOVERY; + } + + /* If we're still here, no good firmware, so go to recovery mode. */ + return LOAD_FIRMWARE_RECOVERY; +} diff --git a/firmware/lib/vboot_kernel.c b/firmware/lib/vboot_kernel.c new file mode 100644 index 00000000..1440eb44 --- /dev/null +++ b/firmware/lib/vboot_kernel.c @@ -0,0 +1,379 @@ +/* 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 loading a kernel from disk. + * (Firmware portion) + */ + +#include "vboot_kernel.h" + +#include "boot_device.h" +#include "cgptlib.h" +#include "load_kernel_fw.h" +#include "rollback_index.h" +#include "utility.h" +#include "vboot_common.h" + + +#define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */ + + +/* Allocates and reads GPT data from the drive. The sector_bytes and + * drive_sectors fields should be filled on input. The primary and + * secondary header and entries are filled on output. + * + * Returns 0 if successful, 1 if error. */ +int AllocAndReadGptData(GptData* gptdata) { + + uint64_t entries_sectors = TOTAL_ENTRIES_SIZE / gptdata->sector_bytes; + + /* No data to be written yet */ + gptdata->modified = 0; + + /* Allocate all buffers */ + gptdata->primary_header = (uint8_t*)Malloc(gptdata->sector_bytes); + gptdata->secondary_header = (uint8_t*)Malloc(gptdata->sector_bytes); + gptdata->primary_entries = (uint8_t*)Malloc(TOTAL_ENTRIES_SIZE); + gptdata->secondary_entries = (uint8_t*)Malloc(TOTAL_ENTRIES_SIZE); + + if (gptdata->primary_header == NULL || gptdata->secondary_header == NULL || + gptdata->primary_entries == NULL || gptdata->secondary_entries == NULL) + return 1; + + /* Read data from the drive, skipping the protective MBR */ + if (0 != BootDeviceReadLBA(1, 1, gptdata->primary_header)) + return 1; + if (0 != BootDeviceReadLBA(2, entries_sectors, gptdata->primary_entries)) + return 1; + if (0 != BootDeviceReadLBA(gptdata->drive_sectors - entries_sectors - 1, + entries_sectors, gptdata->secondary_entries)) + return 1; + if (0 != BootDeviceReadLBA(gptdata->drive_sectors - 1, + 1, gptdata->secondary_header)) + return 1; + + return 0; +} + + +/* Writes any changes for the GPT data back to the drive, then frees + * the buffers. + * + * Returns 0 if successful, 1 if error. */ +int WriteAndFreeGptData(GptData* gptdata) { + + uint64_t entries_sectors = TOTAL_ENTRIES_SIZE / gptdata->sector_bytes; + + if (gptdata->primary_header) { + if (gptdata->modified & GPT_MODIFIED_HEADER1) { + if (0 != BootDeviceWriteLBA(1, 1, gptdata->primary_header)) + return 1; + } + Free(gptdata->primary_header); + } + + if (gptdata->primary_entries) { + if (gptdata->modified & GPT_MODIFIED_ENTRIES1) { + if (0 != BootDeviceWriteLBA(2, entries_sectors, + gptdata->primary_entries)) + return 1; + } + Free(gptdata->primary_entries); + } + + if (gptdata->secondary_entries) { + if (gptdata->modified & GPT_MODIFIED_ENTRIES2) { + if (0 != BootDeviceWriteLBA(gptdata->drive_sectors - entries_sectors - 1, + entries_sectors, gptdata->secondary_entries)) + return 1; + } + Free(gptdata->secondary_entries); + } + + if (gptdata->secondary_header) { + if (gptdata->modified & GPT_MODIFIED_HEADER2) { + if (0 != BootDeviceWriteLBA(gptdata->drive_sectors - 1, 1, + gptdata->secondary_header)) + return 1; + } + Free(gptdata->secondary_header); + } + + /* Success */ + return 0; +} + + +int LoadKernel(LoadKernelParams* params) { + + VbPublicKey* kernel_subkey = (VbPublicKey*)params->header_sign_key_blob; + + GptData gpt; + uint64_t part_start, part_size; + uint64_t blba = params->bytes_per_lba; + uint64_t kbuf_sectors = KBUF_SIZE / blba; + uint8_t* kbuf = NULL; + int found_partitions = 0; + int good_partition = -1; + uint16_t tpm_key_version = 0; + uint16_t tpm_kernel_version = 0; + uint64_t lowest_key_version = 0xFFFF; + uint64_t lowest_kernel_version = 0xFFFF; + int is_dev = ((BOOT_FLAG_DEVELOPER & params->boot_flags) && + !(BOOT_FLAG_RECOVERY & params->boot_flags)); + int is_normal = (!(BOOT_FLAG_DEVELOPER & params->boot_flags) && + !(BOOT_FLAG_RECOVERY & params->boot_flags)); + + /* Clear output params in case we fail */ + params->partition_number = 0; + params->bootloader_address = 0; + params->bootloader_size = 0; + + if (is_normal) { + /* Read current kernel key index from TPM. Assumes TPM is already + * initialized. */ + if (0 != GetStoredVersions(KERNEL_VERSIONS, + &tpm_key_version, + &tpm_kernel_version)) { + debug("Unable to get stored version from TPM\n"); + return LOAD_KERNEL_RECOVERY; + } + } else if (is_dev) { + /* In developer mode, we ignore the kernel subkey, and just use + * the SHA-512 hash to verify the key block. */ + kernel_subkey = NULL; + } + + do { + /* Read GPT data */ + gpt.sector_bytes = blba; + gpt.drive_sectors = params->ending_lba + 1; + if (0 != AllocAndReadGptData(&gpt)) { + debug("Unable to read GPT data\n"); + break; + } + + /* Initialize GPT library */ + if (GPT_SUCCESS != GptInit(&gpt)) { + debug("Error parsing GPT\n"); + break; + } + + /* Allocate kernel header buffers */ + kbuf = (uint8_t*)Malloc(KBUF_SIZE); + if (!kbuf) + break; + + /* Loop over candidate kernel partitions */ + while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { + VbKeyBlockHeader* key_block; + VbKernelPreambleHeader* preamble; + RSAPublicKey* data_key; + uint64_t key_version; + uint64_t body_offset; + + debug("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n", + part_start, part_size); + + /* Found at least one kernel partition. */ + found_partitions++; + + /* Read the first part of the kernel partition */ + if (part_size < kbuf_sectors) + continue; + if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) + continue; + + /* Verify the key block */ + key_block = (VbKeyBlockHeader*)kbuf; + if ((0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey))) { + debug("Verifying key block failed.\n"); + continue; + } + + /* Check the key block flags against the current boot mode */ + if (!(key_block->key_block_flags && + ((BOOT_FLAG_DEVELOPER & params->boot_flags) ? + KEY_BLOCK_FLAG_DEVELOPER_1 : KEY_BLOCK_FLAG_DEVELOPER_0))) { + debug("Developer flag mismatch.\n"); + continue; + } + if (!(key_block->key_block_flags && + ((BOOT_FLAG_RECOVERY & params->boot_flags) ? + KEY_BLOCK_FLAG_RECOVERY_1 : KEY_BLOCK_FLAG_RECOVERY_0))) { + debug("Recovery flag mismatch.\n"); + continue; + } + + /* Check for rollback of key version. Note this is implicitly + * skipped in recovery and developer modes because those set + * key_version=0 above. */ + key_version = key_block->data_key.key_version; + if (key_version < tpm_key_version) { + debug("Key version too old.\n"); + continue; + } + + /* Get the key for preamble/data verification from the key block */ + data_key = PublicKeyToRSA(&key_block->data_key); + if (!data_key) + continue; + + /* Verify the preamble, which follows the key block */ + preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size); + if ((0 != VerifyKernelPreamble2(preamble, + KBUF_SIZE - key_block->key_block_size, + data_key))) { + debug("Preamble verification failed.\n"); + RSAPublicKeyFree(data_key); + continue; + } + + /* Check for rollback of kernel version. Note this is implicitly + * skipped in recovery and developer modes because those set + * key_version=0 and kernel_version=0 above. */ + if (key_version == tpm_key_version && + preamble->kernel_version < tpm_kernel_version) { + debug("Kernel version too low.\n"); + RSAPublicKeyFree(data_key); + continue; + } + + debug("Kernel preamble is good.\n"); + + /* Check for lowest key version from a valid header. */ + if (lowest_key_version > key_version) { + lowest_key_version = key_version; + lowest_kernel_version = preamble->kernel_version; + } + else if (lowest_key_version == key_version && + lowest_kernel_version > preamble->kernel_version) { + lowest_kernel_version = preamble->kernel_version; + } + + /* If we already have a good kernel, no need to read another + * one; we only needed to look at the versions to check for + * rollback. */ + if (-1 != good_partition) + continue; + + /* Verify body load address matches what we expect */ + if ((preamble->body_load_address != (size_t)params->kernel_buffer) && + !(params->boot_flags & BOOT_FLAG_SKIP_ADDR_CHECK)) { + debug("Wrong body load address.\n"); + RSAPublicKeyFree(data_key); + continue; + } + + /* Verify kernel body starts at a multiple of the sector size. */ + body_offset = key_block->key_block_size + preamble->preamble_size; + if (0 != body_offset % blba) { + debug("Kernel body not at multiple of sector size.\n"); + RSAPublicKeyFree(data_key); + continue; + } + + /* Verify kernel body fits in the partition */ + if (body_offset + preamble->body_signature.data_size > + part_size * blba) { + debug("Kernel body doesn't fit in partition.\n"); + RSAPublicKeyFree(data_key); + continue; + } + + /* Read the kernel data */ + if (0 != BootDeviceReadLBA( + part_start + (body_offset / blba), + (preamble->body_signature.data_size + blba - 1) / blba, + params->kernel_buffer)) { + debug("Unable to read kernel data.\n"); + RSAPublicKeyFree(data_key); + continue; + } + + /* Verify kernel data */ + if (0 != VerifyData((const uint8_t*)params->kernel_buffer, + &preamble->body_signature, data_key)) { + debug("Kernel data verification failed.\n"); + RSAPublicKeyFree(data_key); + continue; + } + + /* Done with the kernel signing key, so can free it now */ + RSAPublicKeyFree(data_key); + + /* If we're still here, the kernel is valid. */ + /* Save the first good partition we find; that's the one we'll boot */ + debug("Partiton is good.\n"); + good_partition = gpt.current_kernel; + params->partition_number = gpt.current_kernel; + params->bootloader_address = preamble->bootloader_address; + params->bootloader_size = preamble->bootloader_size; + /* If we're in developer or recovery mode, there's no rollback + * protection, so we can stop at the first valid kernel. */ + if (!is_normal) + break; + + /* Otherwise, we're in normal boot mode, so we do care about the + * key index in the TPM. If the good partition's key version is + * the same as the tpm, then the TPM doesn't need updating; we + * can stop now. Otherwise, we'll check all the other headers + * to see if they contain a newer key. */ + if (key_version == tpm_key_version && + preamble->kernel_version == tpm_kernel_version) + break; + } /* while(GptNextKernelEntry) */ + } while(0); + + /* Free kernel buffer */ + if (kbuf) + Free(kbuf); + + /* Write and free GPT data */ + WriteAndFreeGptData(&gpt); + + /* Handle finding a good partition */ + if (good_partition >= 0) { + + /* See if we need to update the TPM */ + if (is_normal) { + /* We only update the TPM in normal boot mode. In developer + * mode, the kernel is self-signed by the developer, so we can't + * trust the key version and wouldn't want to roll the TPM + * forward. In recovery mode, the TPM stays PP-unlocked, so + * anything we write gets blown away by the firmware when we go + * back to normal mode. */ + if ((lowest_key_version > tpm_key_version) || + (lowest_key_version == tpm_key_version && + lowest_kernel_version > tpm_kernel_version)) { + if (0 != WriteStoredVersions(KERNEL_VERSIONS, + lowest_key_version, + lowest_kernel_version)) + return LOAD_KERNEL_RECOVERY; + } + } + + if (!(BOOT_FLAG_RECOVERY & params->boot_flags)) { + /* We can lock the TPM now, since we've decided which kernel we + * like. If we don't find a good kernel, we leave the TPM + * unlocked so we can try again on the next boot device. If no + * kernels are good, we'll reboot to recovery mode, so it's ok to + * leave the TPM unlocked in that case too. + * + * If we're already in recovery mode, we need to leave PP unlocked, + * so don't lock the kernel versions. */ + if (0 != LockKernelVersionsByLockingPP()) + return LOAD_KERNEL_RECOVERY; + } + + /* Success! */ + return LOAD_KERNEL_SUCCESS; + } + + // Handle error cases + if (found_partitions) + return LOAD_KERNEL_INVALID; + else + return LOAD_KERNEL_NOT_FOUND; +} |