summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2010-06-17 14:45:22 -0700
committerRandall Spangler <rspangler@chromium.org>2010-06-17 14:45:22 -0700
commit620c38cf34eadcd222535b01fb71c5e9fbc1cb80 (patch)
tree55c883fd01447b0ffdf6c121f4b7c6817cbc53b0 /firmware
parentd52030f340d14f8039360a39ec6a938d31e083d0 (diff)
downloadvboot-620c38cf34eadcd222535b01fb71c5e9fbc1cb80.tar.gz
Remove unused files, and tidy the directory structure of the remaining ones.
Review URL: http://codereview.chromium.org/2815011
Diffstat (limited to 'firmware')
-rw-r--r--firmware/Makefile51
-rw-r--r--firmware/README6
-rw-r--r--firmware/include/boot_device.h26
-rw-r--r--firmware/include/gbb_header.h48
-rw-r--r--firmware/include/load_firmware_fw.h86
-rw-r--r--firmware/include/load_kernel_fw.h66
-rw-r--r--firmware/include/rollback_index.h66
-rw-r--r--firmware/include/sysincludes.h28
-rw-r--r--firmware/include/tlcl.h114
-rw-r--r--firmware/include/utility.h69
-rw-r--r--firmware/lib/cgptlib/cgptlib.c148
-rw-r--r--firmware/lib/cgptlib/cgptlib_internal.c348
-rwxr-xr-xfirmware/lib/cgptlib/crc32.c108
-rw-r--r--firmware/lib/cgptlib/include/cgptlib.h115
-rw-r--r--firmware/lib/cgptlib/include/cgptlib_internal.h115
-rw-r--r--firmware/lib/cgptlib/include/crc32.h12
-rw-r--r--firmware/lib/cgptlib/include/gpt.h104
-rw-r--r--firmware/lib/cryptolib/README3
-rw-r--r--firmware/lib/cryptolib/include/cryptolib.h15
-rw-r--r--firmware/lib/cryptolib/include/padding.h40
-rw-r--r--firmware/lib/cryptolib/include/rsa.h92
-rw-r--r--firmware/lib/cryptolib/include/sha.h128
-rw-r--r--firmware/lib/cryptolib/padding.c246
-rw-r--r--firmware/lib/cryptolib/rsa.c187
-rw-r--r--firmware/lib/cryptolib/rsa_utility.c134
-rw-r--r--firmware/lib/cryptolib/sha1.c287
-rw-r--r--firmware/lib/cryptolib/sha2.c623
-rw-r--r--firmware/lib/cryptolib/sha_utility.c87
-rw-r--r--firmware/lib/include/stateful_util.h62
-rw-r--r--firmware/lib/include/tss_constants.h79
-rw-r--r--firmware/lib/include/vboot_common.h110
-rw-r--r--firmware/lib/include/vboot_kernel.h25
-rw-r--r--firmware/lib/include/vboot_struct.h124
-rw-r--r--firmware/lib/rollback_index.c362
-rw-r--r--firmware/lib/stateful_util.c65
-rw-r--r--firmware/lib/vboot_common.c341
-rw-r--r--firmware/lib/vboot_firmware.c209
-rw-r--r--firmware/lib/vboot_kernel.c379
-rw-r--r--firmware/linktest/main.c70
-rw-r--r--firmware/stub/boot_device_stub.c17
-rw-r--r--firmware/stub/load_firmware_stub.c104
-rw-r--r--firmware/stub/tlcl.c38
-rw-r--r--firmware/stub/utility_stub.c72
43 files changed, 5409 insertions, 0 deletions
diff --git a/firmware/Makefile b/firmware/Makefile
new file mode 100644
index 00000000..07e113a0
--- /dev/null
+++ b/firmware/Makefile
@@ -0,0 +1,51 @@
+# 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.
+
+FWTOP := $(shell pwd)
+LIBDIR = $(FWTOP)/lib
+STUBDIR = $(FWTOP)/stub
+TESTDIR = $(FWTOP)/linktest
+BUILD_ROOT := ${BUILD}/$(shell basename ${FWTOP})
+
+INCLUDES = \
+ -I$(FWTOP)/include \
+ -I$(LIBDIR)/include \
+ -I$(LIBDIR)/cgptlib/include \
+ -I$(LIBDIR)/cryptolib/include
+
+
+# find ./lib -iname '*.c' | sort
+LIB_SRCS = \
+ ./lib/cgptlib/cgptlib.c \
+ ./lib/cgptlib/cgptlib_internal.c \
+ ./lib/cgptlib/crc32.c \
+ ./lib/cryptolib/padding.c \
+ ./lib/cryptolib/rsa.c \
+ ./lib/cryptolib/rsa_utility.c \
+ ./lib/cryptolib/sha1.c \
+ ./lib/cryptolib/sha2.c \
+ ./lib/cryptolib/sha_utility.c \
+ ./lib/rollback_index.c \
+ ./lib/stateful_util.c \
+ ./lib/vboot_common.c \
+ ./lib/vboot_firmware.c \
+ ./lib/vboot_kernel.c
+
+STUB_SRCS = \
+ ./stub/boot_device_stub.c \
+ ./stub/load_firmware_stub.c \
+ ./stub/tlcl.c \
+ ./stub/utility_stub.c
+
+ALL_SRCS = ${LIB_SRCS} ${STUB_SRCS}
+
+test : $(FWLIB)
+ $(CC) $(CFLAGS) $(INCLUDES) -o $(BUILD_ROOT)/a.out \
+ $(TESTDIR)/main.c $(FWLIB)
+
+include ../common.mk
+
+$(FWLIB) : $(ALL_OBJS)
+ rm -f $@
+ ar qc $@ $^
diff --git a/firmware/README b/firmware/README
new file mode 100644
index 00000000..2b0bff50
--- /dev/null
+++ b/firmware/README
@@ -0,0 +1,6 @@
+
+lib/ is stuff that the BIOS needs to link with.
+
+stub/ is stuff to be implemented by the BIOS.
+
+include/ describes the interfaces between the two parts.
diff --git a/firmware/include/boot_device.h b/firmware/include/boot_device.h
new file mode 100644
index 00000000..10303ca4
--- /dev/null
+++ b/firmware/include/boot_device.h
@@ -0,0 +1,26 @@
+/* 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 raw sector access to current boot device. */
+
+#ifndef VBOOT_REFERENCE_BOOT_DEVICE_H_
+#define VBOOT_REFERENCE_BOOT_DEVICE_H_
+
+#include "sysincludes.h"
+
+int BootDeviceReadLBA(uint64_t lba_start, uint64_t lba_count, void *buffer);
+/* Reads lba_count LBA sectors, starting at sector lba_start, from the current
+ * boot device, into the buffer.
+ *
+ * Returns 0 if successful or 1 if error. */
+
+int BootDeviceWriteLBA(uint64_t lba_start, uint64_t lba_count,
+ const void *buffer);
+/* Writes lba_count LBA sectors, starting at sector lba_start, to the current
+ * boot device, from the buffer.
+ *
+ * Returns 0 if successful or 1 if error. */
+
+#endif /* VBOOT_REFERENCE_BOOT_DEVICE_H_ */
diff --git a/firmware/include/gbb_header.h b/firmware/include/gbb_header.h
new file mode 100644
index 00000000..18bb64b7
--- /dev/null
+++ b/firmware/include/gbb_header.h
@@ -0,0 +1,48 @@
+/* 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 of Google Binary Block (GBB)
+ */
+
+#ifndef VBOOT_REFERENCE_GBB_HEADER_H_
+#define VBOOT_REFERENCE_GBB_HEADER_H_
+
+#include "sysincludes.h"
+
+#define GBB_HEADER_SIZE (0x80)
+
+#define GBB_SIGNATURE "$GBB"
+#define GBB_SIGNATURE_SIZE (4)
+
+#define GBB_MAJOR_VER (0x01)
+#define GBB_MINOR_VER (0x00)
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+typedef struct GoogleBinaryBlockHeader {
+ uint8_t signature[GBB_SIGNATURE_SIZE]; // GBB_SIGNATURE "$GBB"
+ uint16_t major_version; // see GBB_MAJOR_VER
+ uint16_t minor_version; // see GBB_MINOR_VER
+ uint32_t header_size; // size of GBB header in bytes
+ uint32_t reserved;
+
+ uint32_t hwid_offset; // HWID offset from header
+ uint32_t hwid_size; // HWID size in bytes
+ uint32_t rootkey_offset; // Root Key offset from header
+ uint32_t rootkey_size; // Root Key size in bytes
+ uint32_t bmpfv_offset; // BMP FV offset from header
+ uint32_t bmpfv_size; // BMP FV size in bytes
+ uint32_t recovery_key_offset; // Recovery Key offset from header
+ uint32_t recovery_key_size; // Recovery Key size in bytes
+
+ uint8_t pad[80]; // to match GBB_HEADER_SIZE
+} GoogleBinaryBlockHeader;
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* VBOOT_REFERENCE_GBB_HEADER_H_ */
diff --git a/firmware/include/load_firmware_fw.h b/firmware/include/load_firmware_fw.h
new file mode 100644
index 00000000..8ba67cf7
--- /dev/null
+++ b/firmware/include/load_firmware_fw.h
@@ -0,0 +1,86 @@
+/* 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)
+ */
+
+#ifndef VBOOT_REFERENCE_LOAD_FIRMWARE_FW_H_
+#define VBOOT_REFERENCE_LOAD_FIRMWARE_FW_H_
+
+#include "sysincludes.h"
+
+/* Recommended size of kernel_sign_key_blob in bytes, for
+ * implementations which must preallocate a transfer buffer between
+ * boot phases */
+#define LOAD_FIRMWARE_KEY_BLOB_REC_SIZE 2104
+
+/* Return codes for LoadFirmware() */
+#define LOAD_FIRMWARE_SUCCESS 0 /* Success */
+#define LOAD_FIRMWARE_RECOVERY 1 /* Reboot to recovery mode */
+
+typedef struct LoadFirmwareParams {
+ /* Inputs to LoadFirmware() */
+ void *firmware_root_key_blob; /* Key used to sign firmware header */
+ void *verification_block_0; /* Key block + preamble for firmware 0 */
+ void *verification_block_1; /* Key block + preamble for firmware 1 */
+ uint64_t verification_size_0; /* Verification block 0 size in bytes */
+ uint64_t verification_size_1; /* Verification block 1 size in bytes */
+ void *kernel_sign_key_blob; /* Destination buffer for key to use
+ * when loading kernel. Pass this
+ * data to LoadKernel() in
+ * LoadKernelParams.header_sign_key_blob. */
+ uint64_t kernel_sign_key_size; /* Size of kernel signing key blob
+ * buffer, in bytes. On output, this
+ * will contain the actual key blob
+ * size placed into the buffer. */
+
+ /* Outputs from LoadFirmware(); valid only if LoadFirmware() returns
+ * LOAD_FIRMWARE_SUCCESS. */
+ uint64_t firmware_index; /* Firmware index to run. */
+
+ /* Internal data for LoadFirmware() / UpdateFirmwareBodyHash(). */
+ void* load_firmware_internal;
+
+ /* Internal data for caller / GetFirmwareBody(). */
+ void* caller_internal;
+
+} LoadFirmwareParams;
+
+
+/* Functions provided by PEI to LoadFirmware() */
+
+/* Get the firmware body data for [firmware_index], which is either
+ * 0 (the first firmware image) or 1 (the second firmware image).
+ *
+ * This function must call UpdateFirmwareBodyHash() before returning,
+ * to update the secure hash for the firmware image. For best
+ * performance, the reader should call this function periodically
+ * during the read, so that updating the hash can be pipelined with
+ * the read. If the reader cannot update the hash during the read
+ * process, it should call UpdateFirmwareBodyHash() on the entire
+ * firmeware data after the read, before returning.
+ *
+ * Returns 0 if successful or non-zero if error. */
+int GetFirmwareBody(LoadFirmwareParams* params, uint64_t firmware_index);
+
+
+/* Functions provided by verified boot library to PEI */
+
+/* Attempts to load the rewritable firmware.
+ *
+ * Returns LOAD_FIRMWARE_SUCCESS if successful, error code on failure. */
+int LoadFirmware(LoadFirmwareParams* params);
+
+
+/* Update the data hash for the current firmware image, extending it
+ * by [size] bytes stored in [*data]. This function must only be
+ * called inside GetFirmwareBody(). */
+void UpdateFirmwareBodyHash(LoadFirmwareParams* params,
+ uint8_t* data, uint64_t size);
+
+
+
+
+#endif /* VBOOT_REFERENCE_LOAD_FIRMWARE_FW_H_ */
diff --git a/firmware/include/load_kernel_fw.h b/firmware/include/load_kernel_fw.h
new file mode 100644
index 00000000..4f86b403
--- /dev/null
+++ b/firmware/include/load_kernel_fw.h
@@ -0,0 +1,66 @@
+/* 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 kernel.
+ * (Firmware Portion)
+ */
+
+#ifndef VBOOT_REFERENCE_LOAD_KERNEL_FW_H_
+#define VBOOT_REFERENCE_LOAD_KERNEL_FW_H_
+
+#include "sysincludes.h"
+
+/* Interface provided by verified boot library to BDS */
+
+/* Return codes for LoadKernel() */
+#define LOAD_KERNEL_SUCCESS 0 /* Success; good kernel found on device */
+#define LOAD_KERNEL_NOT_FOUND 1 /* No kernel found on device */
+#define LOAD_KERNEL_INVALID 2 /* Only invalid kernels found on device */
+#define LOAD_KERNEL_RECOVERY 3 /* Internal error; reboot to recovery mode */
+
+/* Boot flags for LoadKernel().boot_flags */
+#define BOOT_FLAG_DEVELOPER UINT64_C(0x01) /* Developer switch is on */
+#define BOOT_FLAG_RECOVERY UINT64_C(0x02) /* In recovery mode */
+#define BOOT_FLAG_SKIP_ADDR_CHECK UINT64_C(0x04) /* Skip check of kernel
+ * buffer address */
+
+typedef struct LoadKernelParams {
+ /* Inputs to LoadKernel() */
+ void *header_sign_key_blob; /* Key blob used to sign the kernel header */
+ uint64_t bytes_per_lba; /* Bytes per lba sector on current device */
+ uint64_t ending_lba; /* Last addressable lba sector on current
+ * device */
+ void *kernel_buffer; /* Destination buffer for kernel
+ * (normally at 0x100000) */
+ uint64_t kernel_buffer_size; /* Size of kernel buffer in bytes */
+ uint64_t boot_flags; /* Boot flags */
+
+ /* Outputs from LoadKernel(); valid only if LoadKernel() returns
+ * LOAD_KERNEL_SUCCESS */
+ uint64_t partition_number; /* Partition number to boot on current device
+ * (1...M) */
+ uint64_t bootloader_address; /* Address of bootloader image in RAM */
+ uint64_t bootloader_size; /* Size of bootloader image in bytes */
+} LoadKernelParams;
+
+int LoadKernel(LoadKernelParams* params);
+/* Attempts to load the kernel from the current device.
+ *
+ * Returns LOAD_KERNEL_SUCCESS if successful, error code on failure. */
+
+
+typedef struct KernelBootloaderOptions {
+ /* The bootloader is loaded using the EFI LoadImage() and StartImage()
+ * calls. Pass this struct via loaded_image->load_options. */
+ uint64_t drive_number; /* Drive number of boot device (0...N) */
+ uint64_t partition_number; /* Partition number, as returned from
+ * LoadKernel() in
+ * LoadKernelParams.partition_number */
+ uint64_t original_address; /* Absolute bootloader start adddress,
+ * as returned from LoadKernel() in
+ * LoadKernelParams.bootloader_start */
+} KernelBootloaderOptions;
+
+
+#endif /* VBOOT_REFERENCE_LOAD_KERNEL_FW_H_ */
diff --git a/firmware/include/rollback_index.h b/firmware/include/rollback_index.h
new file mode 100644
index 00000000..c359b4bb
--- /dev/null
+++ b/firmware/include/rollback_index.h
@@ -0,0 +1,66 @@
+/* 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.
+ */
+
+#ifndef VBOOT_REFERENCE_ROLLBACK_INDEX_H_
+#define VBOOT_REFERENCE_ROLLBACK_INDEX_H_
+
+#include "sysincludes.h"
+
+/* TODO: global variables won't work in the boot stub, since it runs
+ directly out of ROM. */
+extern uint16_t g_firmware_key_version;
+extern uint16_t g_firmware_version;
+extern uint16_t g_kernel_key_version;
+extern uint16_t g_kernel_version;
+
+/* Rollback version types. */
+#define FIRMWARE_VERSIONS 0
+#define KERNEL_VERSIONS 1
+
+/* Initialization mode */
+#define RO_RECOVERY_MODE 0
+#define RO_NORMAL_MODE 1
+#define RW_NORMAL_MODE 2
+
+/* TPM NVRAM location indices. */
+#define FIRMWARE_VERSIONS_NV_INDEX 0x1001
+#define KERNEL_VERSIONS_NV_INDEX 0x1002
+#define TPM_IS_INITIALIZED_NV_INDEX 0x1003
+#define KERNEL_VERSIONS_BACKUP_NV_INDEX 0x1004
+#define KERNEL_MUST_USE_BACKUP_NV_INDEX 0x1005
+#define DEVELOPER_MODE_NV_INDEX 0x1006
+
+/* Unique ID to detect kernel space redefinition */
+#define KERNEL_SPACE_UID "GRWL" /* unique ID with secret meaning */
+#define KERNEL_SPACE_UID_SIZE (sizeof(KERNEL_SPACE_UID) - 1)
+#define KERNEL_SPACE_INIT_DATA ((uint8_t*) "\0\0\0\0" KERNEL_SPACE_UID)
+#define KERNEL_SPACE_SIZE (sizeof(uint32_t) + KERNEL_SPACE_UID_SIZE)
+
+/* All functions return TPM_SUCCESS (zero) if successful, non-zero if error */
+
+/* SetupTPM is called on boot and on starting the RW firmware, passing the
+ * appripriate MODE and DEVELOPER_FLAG parameters. MODE can be one of
+ * RO_RECOVERY_MODE, RO_NORMAL_MODE, RW_NORMAL_MODE. DEVELOPER_FLAG is 1 when
+ * the developer switch is ON, 0 otherwise.
+ *
+ * If SetupTPM returns TPM_SUCCESS, the caller may proceed. If it returns
+ * TPM_E_MUST_REBOOT, the caller must reboot in the current mode. For all
+ * other return values, the caller must reboot in recovery mode.
+ *
+ * This function has many side effects on the TPM state. In particular, when
+ * called with mode = RECOVERY_MODE, it locks the firmware versions before
+ * returning. In all other cases, the caller is responsible for locking the
+ * firmware versions once it decides it doesn't need to update them.
+ */
+uint32_t SetupTPM(int mode, int developer_flag);
+uint32_t GetStoredVersions(int type, uint16_t* key_version, uint16_t* version);
+uint32_t WriteStoredVersions(int type, uint16_t key_version, uint16_t version);
+uint32_t LockFirmwareVersions(void);
+uint32_t LockKernelVersionsByLockingPP(void);
+
+#endif /* VBOOT_REFERENCE_ROLLBACK_INDEX_H_ */
diff --git a/firmware/include/sysincludes.h b/firmware/include/sysincludes.h
new file mode 100644
index 00000000..758e5820
--- /dev/null
+++ b/firmware/include/sysincludes.h
@@ -0,0 +1,28 @@
+/* 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.
+ */
+
+/* System includes for vboot reference library. This is the ONLY
+ * place in firmware/ where system headers may be included via
+ * #include <...>, so that there's only one place that needs to be
+ * fixed up for platforms which don't have all the system includes.
+ *
+ * Files in firmware/stub may still include system headers, because
+ * they're local implementations and will be ported to each system
+ * anyway. */
+
+#ifndef VBOOT_REFERENCE_SYSINCLUDES_H_
+#define VBOOT_REFERENCE_SYSINCLUDES_H_
+
+#include <inttypes.h> /* For PRIu64 */
+#include <stdint.h>
+#include <stdlib.h>
+
+#if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN)
+#include <byteswap.h>
+#include <memory.h>
+#endif
+
+
+#endif /* VBOOT_REFERENCE_SYSINCLUDES_H_ */
diff --git a/firmware/include/tlcl.h b/firmware/include/tlcl.h
new file mode 100644
index 00000000..82947f63
--- /dev/null
+++ b/firmware/include/tlcl.h
@@ -0,0 +1,114 @@
+/* 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.
+ */
+
+/* TPM Lightweight Command Library.
+ *
+ * A low-level library for interfacing to TPM hardware or an emulator.
+ */
+
+/* FIXME(gauravsh):
+ * NOTE: This file is copied over from
+ * src/platform/tpm_lite/src/tlcl/tlcl.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.
+ *
+ * FURTHER NOTE: The subset of TPM error codes relevant to verified boot
+ * (TPM_SUCCESS, etc.) are in tss_constants.h. A full list of TPM error codes
+ * are in /usr/include/tss/tpm_error.h, from the trousers package.
+ */
+
+#ifndef TPM_LITE_TLCL_H_
+#define TPM_LITE_TLCL_H_
+
+#include "sysincludes.h"
+
+/* Call this first.
+ */
+void TlclLibInit(void);
+
+/* Sends a TPM_Startup(ST_CLEAR). Note that this is a no-op for the emulator,
+ * because it runs this command during initialization. The TPM error code is
+ * returned (0 for success).
+ */
+uint32_t TlclStartup(void);
+
+/* Run the self test. Note---this is synchronous. To run this in parallel
+ * with other firmware, use ContinueSelfTest. The TPM error code is returned.
+ */
+uint32_t TlclSelftestfull(void);
+
+/* Runs the self test in the background. The TPM error code is returned.
+ */
+uint32_t TlclContinueSelfTest(void);
+
+/* Defines a space with permission [perm]. [index] is the index for the space,
+ * [size] the usable data size. The TPM error code is returned.
+ */
+uint32_t TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size);
+
+/* Writes [length] bytes of [data] to space at [index]. The TPM error code is
+ * returned.
+ */
+uint32_t TlclWrite(uint32_t index, uint8_t *data, uint32_t length);
+
+/* Reads [length] bytes from space at [index] into [data]. The TPM error code
+ * is returned.
+ */
+uint32_t TlclRead(uint32_t index, uint8_t *data, uint32_t length);
+
+/* Write-locks space at [index]. The TPM error code is returned.
+ */
+uint32_t TlclWriteLock(uint32_t index);
+
+/* Read-locks space at [index]. The TPM error code is returned.
+ */
+uint32_t TlclReadLock(uint32_t index);
+
+/* Asserts physical presence in software. The TPM error code is returned.
+ */
+uint32_t TlclAssertPhysicalPresence(void);
+
+/* Turns off physical presence and locks it off until next reboot. The TPM
+ * error code is returned.
+ */
+uint32_t TlclLockPhysicalPresence(void);
+
+/* Sets the nvLocked bit. The TPM error code is returned.
+ */
+uint32_t TlclSetNvLocked(void);
+
+/* Returns 1 if the TPM is owned, 0 otherwise.
+ */
+int TlclIsOwned(void);
+
+/* Issues a ForceClear. The TPM error code is returned.
+ */
+uint32_t TlclForceClear(void);
+
+/* Issues a SetEnable. The TPM error code is returned.
+ */
+uint32_t TlclSetEnable(void);
+
+/* Issues a SetDeactivated. Pass 0 to activate. Returns result code.
+ */
+uint32_t TlclSetDeactivated(uint8_t flag);
+
+/* Gets flags of interest. (Add more here as needed.) The TPM error code is
+ * returned.
+ */
+uint32_t TlclGetFlags(uint8_t* disable, uint8_t* deactivated);
+
+/* Sets the bGlobalLock flag, which only a reboot can clear. The TPM error
+ * code is returned.
+ */
+uint32_t TlclSetGlobalLock(void);
+
+/* Gets the permission bits for the NVRAM space with |index|.
+ */
+uint32_t TlclGetPermissions(uint32_t index, uint32_t* permissions);
+
+#endif /* TPM_LITE_TLCL_H_ */
diff --git a/firmware/include/utility.h b/firmware/include/utility.h
new file mode 100644
index 00000000..4cfb076b
--- /dev/null
+++ b/firmware/include/utility.h
@@ -0,0 +1,69 @@
+/* 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_REFERENCE_UTILITY_H_
+#define VBOOT_REFERENCE_UTILITY_H_
+
+#include "sysincludes.h"
+
+/* Outputs an error message and quits. */
+void error(const char *format, ...);
+
+/* Outputs debug/warning messages. */
+void debug(const char *format, ...);
+
+#define assert(expr) do { if (!(expr)) { \
+ error("assert fail: %s at %s:%d\n", \
+ #expr, __FILE__, __LINE__); }} while(0)
+
+/* Combine [msw] and [lsw] uint16s to a uint32_t with its [msw] and
+ * [lsw] forming the most and least signficant 16-bit words.
+ */
+#define CombineUint16Pair(msw,lsw) (((msw) << 16) | \
+ (((lsw)) & 0xFFFF))
+/* Return the minimum of (a) or (b). */
+#define Min(a, b) (((a) < (b)) ? (a) : (b))
+
+/* Allocate [size] bytes and return a pointer to the allocated memory. Abort
+ * on error.
+ */
+void* Malloc(size_t size);
+
+/* Free memory pointed by [ptr] previously allocated by Malloc(). */
+void Free(void* ptr);
+
+/* Compare [n] bytes in [src1] and [src2]
+ * Returns an integer less than, equal to, or greater than zero if the first [n]
+ * bytes of [src1] is found, respectively, to be less than, to match, or be
+ * greater than the first n bytes of [src2]. */
+int Memcmp(const void* src1, const void* src2, size_t n);
+
+/* Copy [n] bytes from [src] to [dest]. */
+void* Memcpy(void* dest, const void* src, size_t n);
+
+/* Set [n] bytes starting at [s] to [c]. */
+void* Memset(void *dest, const uint8_t c, size_t n);
+
+/* Compare [n] bytes starting at [s1] with [s2] and return 0 if they match,
+ * 1 if they don't. Time taken to perform the comparison is only dependent on
+ * [n] and not on the relationship of the match between [s1] and [s2].
+ */
+int SafeMemcmp(const void* s1, const void* s2, size_t n);
+
+/* Ensure that only our stub implementations are used, not standard C */
+#ifndef _STUB_IMPLEMENTATION_
+#define malloc _do_not_use_standard_malloc
+#define free _do_not_use_standard_free
+#define memcmp _do_not_use_standard_memcmp
+#define memcpy _do_not_use_standard_memcpy
+#define memset _do_not_use_standard_memset
+#endif
+
+
+#endif /* VBOOT_REFERENCE_UTILITY_H_ */
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*) &current_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;
+}
diff --git a/firmware/linktest/main.c b/firmware/linktest/main.c
new file mode 100644
index 00000000..e6659a99
--- /dev/null
+++ b/firmware/linktest/main.c
@@ -0,0 +1,70 @@
+
+#include "cgptlib.h"
+#include "load_firmware_fw.h"
+#include "load_kernel_fw.h"
+#include "rollback_index.h"
+#include "tlcl.h"
+#include "vboot_common.h"
+#include "vboot_kernel.h"
+
+int main(void)
+{
+ uint16_t x, y;
+
+ /* cgptlib.h */
+ GptInit(0);
+ GptNextKernelEntry(0, 0, 0);
+ GptUpdateKernelEntry(0, 0);
+
+ /* load_firmware_fw.h */
+ UpdateFirmwareBodyHash(0, 0, 0);
+ LoadFirmware(0);
+
+ /* load_kernel_fw.h */
+ LoadKernel(0);
+
+ /* rollback_index.h */
+ SetupTPM(0, 0);
+ GetStoredVersions(0, &x, &y);
+ WriteStoredVersions(0, 0, 0);
+ LockFirmwareVersions();
+ LockKernelVersionsByLockingPP();
+
+ /* tlcl.h */
+ TlclLibInit();
+ TlclStartup();
+ TlclSelftestfull();
+ TlclContinueSelfTest();
+ TlclDefineSpace(0, 0, 0);
+ TlclWrite(0, 0, 0);
+ TlclRead(0, 0, 0);
+ TlclWriteLock(0);
+ TlclReadLock(0);
+ TlclAssertPhysicalPresence();
+ TlclSetNvLocked();
+ TlclIsOwned();
+ TlclForceClear();
+ TlclSetEnable();
+ TlclSetDeactivated(0);
+ TlclGetFlags(0, 0);
+
+ /* vboot_common.h */
+ OffsetOf(0, 0);
+ GetPublicKeyData(0);
+ GetPublicKeyDataC(0);
+ GetSignatureData(0);
+ GetSignatureDataC(0);
+ VerifyMemberInside(0, 0, 0, 0, 0, 0);
+ VerifyPublicKeyInside(0, 0, 0);
+ VerifySignatureInside(0, 0, 0);
+ PublicKeyInit(0, 0, 0);
+ PublicKeyCopy(0, 0);
+ PublicKeyToRSA(0);
+ VerifyData(0, 0, 0);
+ VerifyDigest(0, 0, 0);
+ KeyBlockVerify(0, 0, 0);
+ VerifyFirmwarePreamble2(0, 0, 0);
+ VerifyKernelPreamble2(0, 0, 0);
+
+ return 0;
+}
diff --git a/firmware/stub/boot_device_stub.c b/firmware/stub/boot_device_stub.c
new file mode 100644
index 00000000..c7bb86f5
--- /dev/null
+++ b/firmware/stub/boot_device_stub.c
@@ -0,0 +1,17 @@
+/* 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 boot device functions.
+ */
+
+#include "boot_device.h"
+
+int BootDeviceReadLBA(uint64_t lba_start, uint64_t lba_count, void *buffer) {
+ return 1;
+}
+
+int BootDeviceWriteLBA(uint64_t lba_start, uint64_t lba_count,
+ const void *buffer) {
+ return 1;
+}
diff --git a/firmware/stub/load_firmware_stub.c b/firmware/stub/load_firmware_stub.c
new file mode 100644
index 00000000..9453856a
--- /dev/null
+++ b/firmware/stub/load_firmware_stub.c
@@ -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.
+ *
+ * TEMPORARY stub for calling LoadFirmware() which looks like the old
+ * VerifyFirmwareDriver_f() call.
+ * (Firmware portion)
+ */
+
+#include "load_firmware_fw.h"
+#include "utility.h"
+
+#define BOOT_FIRMWARE_A_CONTINUE 1
+#define BOOT_FIRMWARE_B_CONTINUE 2
+#define BOOT_FIRMWARE_RECOVERY_CONTINUE 3
+
+typedef struct CallerInternal {
+ uint8_t *firmwareA;
+ uint64_t firmwareA_size;
+ uint8_t *firmwareB;
+ uint64_t firmwareB_size;
+} CallerInternal;
+
+int GetFirmwareBody(LoadFirmwareParams* params, uint64_t index) {
+
+ CallerInternal* ci = (CallerInternal*)params->caller_internal;
+ uint8_t *fw;
+ uint64_t size;
+
+ /* In a real implementation, GetFirmwareBody() should be what reads
+ * and decompresses the firmware volume. In this temporary hack, we
+ * just pass the pointer which we got from
+ * VerifyFirmwareDriver_Stub(). */
+ switch(index) {
+ case 0:
+ size = ci->firmwareA_size;
+ fw = ci->firmwareA;
+ case 1:
+ size = ci->firmwareB_size;
+ fw = ci->firmwareB;
+ default:
+ /* Anything else is invalid */
+ return 1;
+ }
+
+ /* Need to call UpdateFirmwareBodyHash() with the firmware volume
+ * data. In this temporary hack, the FV is already decompressed, so
+ * we pass in the entire volume at once. In a real implementation,
+ * you should call this as the FV is being decompressed. */
+ UpdateFirmwareBodyHash(params, fw, size);
+
+ /* Success */
+ return 0;
+}
+
+
+/* Where you're currently calling VerifyFirmwareDriver_f(), call this
+ * function instead. Because you still need to read in both firmware
+ * volumes, this call will still be slow. Once we reach feature
+ * complete, you should modify your code to call LoadImage()
+ * directly. */
+int VerifyFirmwareDriver_stub(uint8_t* root_key_blob,
+ uint8_t* verification_headerA,
+ uint8_t* firmwareA,
+ uint8_t* verification_headerB,
+ uint8_t* firmwareB) {
+
+ int rv;
+
+ CallerInternal ci;
+
+ /* Copy the firmware volume pointers to our global variables. */
+ ci.firmwareA = firmwareA;
+ ci.firmwareB = firmwareB;
+
+ /* TODO: YOU NEED TO PASS IN THE FIRMWARE VOLUME SIZES SOMEHOW */
+ ci.firmwareA_size = 0;
+ ci.firmwareB_size = 0;
+
+ /* Set up the params for LoadFirmware() */
+ LoadFirmwareParams p;
+ p.caller_internal = &ci;
+ p.firmware_root_key_blob = root_key_blob;
+ p.verification_block_0 = verification_headerA;
+ p.verification_block_1 = verification_headerB;
+
+ /* Allocate a key blob buffer */
+ p.kernel_sign_key_blob = Malloc(LOAD_FIRMWARE_KEY_BLOB_REC_SIZE);
+ p.kernel_sign_key_size = LOAD_FIRMWARE_KEY_BLOB_REC_SIZE;
+
+ /* Call LoadFirmware() */
+ rv = LoadFirmware(&p);
+ if (LOAD_FIRMWARE_SUCCESS == rv) {
+ /* TODO: YOU NEED TO KEEP TRACK OF p.kernel_sign_key_blob AND
+ * p.kernel_sign_key_size SO YOU CAN PASS THEM TO LoadKernel(). */
+
+ return (0 == p.firmware_index ? BOOT_FIRMWARE_A_CONTINUE :
+ BOOT_FIRMWARE_B_CONTINUE);
+
+ } else {
+ /* Error */
+ return BOOT_FIRMWARE_RECOVERY_CONTINUE;
+ }
+}
diff --git a/firmware/stub/tlcl.c b/firmware/stub/tlcl.c
new file mode 100644
index 00000000..23f0f09a
--- /dev/null
+++ b/firmware/stub/tlcl.c
@@ -0,0 +1,38 @@
+/* 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 TPM Lite Library.
+ */
+
+#include "tss_constants.h"
+
+void TlclLibInit(void) { return; }
+uint32_t TlclStartup(void) { return TPM_SUCCESS; }
+uint32_t TlclSelftestfull(void) { return TPM_SUCCESS; }
+uint32_t TlclContinueSelfTest(void) { return TPM_SUCCESS; }
+uint32_t TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size) {
+ return TPM_SUCCESS;
+}
+uint32_t TlclWrite(uint32_t index, uint8_t *data, uint32_t length) {
+ return TPM_SUCCESS;
+}
+uint32_t TlclRead(uint32_t index, uint8_t *data, uint32_t length) {
+ return TPM_SUCCESS;
+}
+uint32_t TlclWriteLock(uint32_t index) { return TPM_SUCCESS; }
+uint32_t TlclReadLock(uint32_t index) { return TPM_SUCCESS; }
+uint32_t TlclAssertPhysicalPresence(void) { return TPM_SUCCESS; }
+uint32_t TlclLockPhysicalPresence(void) { return TPM_SUCCESS; }
+uint32_t TlclSetNvLocked(void) { return TPM_SUCCESS; }
+int TlclIsOwned(void) { return TPM_SUCCESS; }
+uint32_t TlclForceClear(void) { return TPM_SUCCESS; }
+uint32_t TlclSetEnable(void) { return TPM_SUCCESS; }
+uint32_t TlclSetDeactivated(int deactivated) { return TPM_SUCCESS; }
+uint32_t TlclSetGlobalLock(void) { return TPM_SUCCESS; }
+uint32_t TlclGetFlags(uint8_t* disable, uint8_t* deactivated) {
+ return TPM_SUCCESS;
+}
+uint32_t TlclGetPermissions(uint32_t index, uint32_t* permissions) {
+ return TPM_SUCCESS;
+}
diff --git a/firmware/stub/utility_stub.c b/firmware/stub/utility_stub.c
new file mode 100644
index 00000000..a41e3a3d
--- /dev/null
+++ b/firmware/stub/utility_stub.c
@@ -0,0 +1,72 @@
+/* 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.
+ */
+
+#define _STUB_IMPLEMENTATION_
+#include "utility.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void error(const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ fprintf(stderr, "ERROR: ");
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ exit(1);
+}
+
+void debug(const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ fprintf(stderr, "WARNING: ");
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+}
+
+void* Malloc(size_t size) {
+ void* p = malloc(size);
+ if (!p) {
+ /* Fatal Error. We must abort. */
+ abort();
+ }
+ return p;
+}
+
+void Free(void* ptr) {
+ free(ptr);
+}
+
+int Memcmp(const void* src1, const void* src2, size_t n) {
+ return memcmp(src1, src2, n);
+}
+
+void* Memcpy(void* dest, const void* src, size_t n) {
+ return memcpy(dest, src, n);
+}
+
+void* Memset(void* dest, const uint8_t c, size_t n) {
+ while (n--) {
+ *((uint8_t*)dest++) = c;
+ }
+ return dest;
+}
+
+int SafeMemcmp(const void* s1, const void* s2, size_t n) {
+ int match = 0;
+ const unsigned char* us1 = s1;
+ const unsigned char* us2 = s2;
+ while (n--) {
+ if (*us1++ != *us2++)
+ match = 1;
+ }
+
+ return match;
+}