mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-10-20 22:41:53 +02:00
Add 0x0026a custom AES-128-CMAC secure bootloader, Week 11a notebook, and README links
This commit is contained in:
1 parent
b85aaf72d6
commit
bec685d573
33 files changed
+3451
No files matched your search
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* @file aes_cmac.h
|
||||
* @brief AES-128-CMAC authentication tag helpers backed by Mbed TLS.
|
||||
* @author Kevin Thomas
|
||||
* @date 2026
|
||||
*
|
||||
* MIT License
|
||||
* Copyright (c) 2026 Kevin Thomas
|
||||
*/
|
||||
|
||||
#ifndef AES_CMAC_H
|
||||
#define AES_CMAC_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/** @brief AES block size in bytes. */
|
||||
#define AES_BLOCK_SIZE 16U
|
||||
|
||||
/**
|
||||
* @brief Compute an AES-128-CMAC tag over a memory region.
|
||||
* @param key Pointer to the 16-byte AES-128 key.
|
||||
* @param data Pointer to the message bytes, which may live in XIP flash.
|
||||
* @param len Message length in bytes.
|
||||
* @param tag Output buffer that receives the 16-byte CMAC tag.
|
||||
* @return int Zero on success, non-zero when the cipher is unavailable.
|
||||
*/
|
||||
int aes128_cmac(const uint8_t *key, const uint8_t *data, size_t len,
|
||||
uint8_t *tag);
|
||||
|
||||
/**
|
||||
* @brief Compare two CMAC tags without short-circuiting on the first byte.
|
||||
* @param a Pointer to the first tag.
|
||||
* @param b Pointer to the second tag.
|
||||
* @return bool True when the tags are byte-for-byte identical.
|
||||
*/
|
||||
bool cmac_tags_equal(const uint8_t *a, const uint8_t *b);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @file boot.h
|
||||
* @brief Secure boot console and application handoff helpers.
|
||||
* @author Kevin Thomas
|
||||
* @date 2026
|
||||
*
|
||||
* MIT License
|
||||
* Copyright (c) 2026 Kevin Thomas
|
||||
*/
|
||||
|
||||
#ifndef BOOT_H
|
||||
#define BOOT_H
|
||||
|
||||
#include "manifest.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Bring up the debug console and print the boot banner.
|
||||
* @param void No parameters.
|
||||
* @return void No return value.
|
||||
*/
|
||||
void boot_init(void);
|
||||
|
||||
/**
|
||||
* @brief Print a boot failure reason and idle forever.
|
||||
* @param reason Null-terminated message describing the failure.
|
||||
* @return void Does not return.
|
||||
*/
|
||||
void boot_halt(const char *reason);
|
||||
|
||||
/**
|
||||
* @brief Announce the verified image and jump to its reset vector.
|
||||
* @param manifest Pointer to the validated manifest.
|
||||
* @return void Does not return.
|
||||
*/
|
||||
void boot_launch(const fw_manifest_t *manifest);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BOOT_H
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @file flash_layout.h
|
||||
* @brief Flash partition map shared by the bootloader and the host signer.
|
||||
* @author Kevin Thomas
|
||||
* @date 2026
|
||||
*
|
||||
* MIT License
|
||||
* Copyright (c) 2026 Kevin Thomas
|
||||
*/
|
||||
|
||||
#ifndef FLASH_LAYOUT_H
|
||||
#define FLASH_LAYOUT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** @brief Absolute base address of the bootloader image in XIP flash. */
|
||||
#define BOOTLOADER_BASE 0x10000000U
|
||||
|
||||
/** @brief Absolute address of the one-sector firmware manifest. */
|
||||
#define FW_MANIFEST_BASE 0x1001F000U
|
||||
|
||||
/** @brief Size in bytes of the flash sector holding the manifest. */
|
||||
#define FW_MANIFEST_SECTOR_SIZE 4096U
|
||||
|
||||
/** @brief Absolute base address where the signed application runs. */
|
||||
#define APP_BASE 0x10020000U
|
||||
|
||||
/** @brief Total XIP flash size in bytes on the RP2350 Pico 2 board. */
|
||||
#define FLASH_TOTAL_SIZE 0x200000U
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @file image.h
|
||||
* @brief Control transfer into a freshly verified Cortex-M application.
|
||||
* @author Kevin Thomas
|
||||
* @date 2026
|
||||
*
|
||||
* MIT License
|
||||
* Copyright (c) 2026 Kevin Thomas
|
||||
*/
|
||||
|
||||
#ifndef IMAGE_H
|
||||
#define IMAGE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Jump to an application whose vector table starts at a base address.
|
||||
* @param vector_base Base address of the application vector table.
|
||||
* @return void Does not return to the caller.
|
||||
*/
|
||||
void image_start(uint32_t vector_base);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @file manifest.h
|
||||
* @brief Firmware manifest stored in the flash sector before the application.
|
||||
* @author Kevin Thomas
|
||||
* @date 2026
|
||||
*
|
||||
* MIT License
|
||||
* Copyright (c) 2026 Kevin Thomas
|
||||
*/
|
||||
|
||||
#ifndef MANIFEST_H
|
||||
#define MANIFEST_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/** @brief Little-endian magic at the head of a valid manifest ("WFLB"). */
|
||||
#define FW_MANIFEST_MAGIC 0x424C4657U
|
||||
|
||||
/** @brief Current manifest structure revision. */
|
||||
#define FW_MANIFEST_VERSION 1U
|
||||
|
||||
/** @brief Length in bytes of an AES-128-CMAC authentication tag. */
|
||||
#define FW_TAG_SIZE 16U
|
||||
|
||||
#pragma pack(push, 1)
|
||||
/** @brief Fixed-layout record describing the signed application image. */
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
uint32_t app_base;
|
||||
uint32_t app_size;
|
||||
uint8_t tag[FW_TAG_SIZE];
|
||||
} fw_manifest_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
/**
|
||||
* @brief Copy the manifest out of its fixed flash address.
|
||||
* @param out Pointer to the manifest structure to populate.
|
||||
* @return void No return value.
|
||||
*/
|
||||
void manifest_read(fw_manifest_t *out);
|
||||
|
||||
/**
|
||||
* @brief Report whether a manifest carries the expected magic and version.
|
||||
* @param manifest Pointer to the manifest to inspect.
|
||||
* @return bool True when the magic and version both match.
|
||||
*/
|
||||
bool manifest_is_valid(const fw_manifest_t *manifest);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @file verify.h
|
||||
* @brief Firmware authenticity verification for the secure bootloader.
|
||||
* @author Kevin Thomas
|
||||
* @date 2026
|
||||
*
|
||||
* MIT License
|
||||
* Copyright (c) 2026 Kevin Thomas
|
||||
*/
|
||||
|
||||
#ifndef VERIFY_H
|
||||
#define VERIFY_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "manifest.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Recompute the CMAC over the application and compare it to the tag.
|
||||
* @param manifest Pointer to the validated manifest.
|
||||
* @return bool True when the tag matches, false otherwise.
|
||||
*/
|
||||
bool verify_manifest(const fw_manifest_t *manifest);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // VERIFY_H
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @file aes_cmac.c
|
||||
* @brief AES-128-CMAC primitives implemented on top of the SDK Mbed TLS.
|
||||
* @author Kevin Thomas
|
||||
* @date 2026
|
||||
*
|
||||
* MIT License
|
||||
* Copyright (c) 2026 Kevin Thomas
|
||||
*/
|
||||
|
||||
#include "mbedtls/cmac.h"
|
||||
#include "mbedtls/cipher.h"
|
||||
#include "aes_cmac.h"
|
||||
|
||||
int aes128_cmac(const uint8_t *key, const uint8_t *data, size_t len,
|
||||
uint8_t *tag) {
|
||||
const mbedtls_cipher_info_t *info;
|
||||
info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB);
|
||||
if (info == NULL) return -1;
|
||||
return mbedtls_cipher_cmac(info, key, 128, data, len, tag);
|
||||
}
|
||||
|
||||
bool cmac_tags_equal(const uint8_t *a, const uint8_t *b) {
|
||||
uint8_t diff = 0;
|
||||
for (size_t i = 0; i < AES_BLOCK_SIZE; i++) {
|
||||
diff |= (uint8_t)(a[i] ^ b[i]);
|
||||
}
|
||||
return diff == 0;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @file boot.c
|
||||
* @brief Secure boot console and application handoff helpers.
|
||||
* @author Kevin Thomas
|
||||
* @date 2026
|
||||
*
|
||||
* MIT License
|
||||
* Copyright (c) 2026 Kevin Thomas
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "boot.h"
|
||||
#include "image.h"
|
||||
|
||||
void boot_init(void) {
|
||||
stdio_init_all();
|
||||
sleep_ms(2000);
|
||||
printf("\n=== 0x0026a secure bootloader ===\n");
|
||||
}
|
||||
|
||||
void boot_halt(const char *reason) {
|
||||
printf("BOOT FAILED: %s\n", reason);
|
||||
while (true) {
|
||||
sleep_ms(500);
|
||||
}
|
||||
}
|
||||
|
||||
void boot_launch(const fw_manifest_t *manifest) {
|
||||
printf("signature valid, entering app at 0x%08lx\n",
|
||||
(unsigned long)manifest->app_base);
|
||||
image_start(manifest->app_base);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @file image.c
|
||||
* @brief Loads the application stack pointer and branches to its reset vector.
|
||||
* @author Kevin Thomas
|
||||
* @date 2026
|
||||
*
|
||||
* MIT License
|
||||
* Copyright (c) 2026 Kevin Thomas
|
||||
*/
|
||||
|
||||
#include "image.h"
|
||||
|
||||
/** @brief Application reset handler signature. */
|
||||
typedef void (*image_entry_t)(void);
|
||||
|
||||
/**
|
||||
* @brief Mask interrupts and point VTOR at the incoming image.
|
||||
* @param base Vector table base address written to the VTOR register.
|
||||
* @return void No return value.
|
||||
*/
|
||||
static void halt_irq_and_rebase(uint32_t base) {
|
||||
__asm volatile ("cpsid i" ::: "memory");
|
||||
*(volatile uint32_t *)0xE000ED08U = base;
|
||||
}
|
||||
|
||||
void image_start(uint32_t vector_base) {
|
||||
uint32_t *vectors = (uint32_t *)vector_base;
|
||||
image_entry_t entry = (image_entry_t)vectors[1];
|
||||
halt_irq_and_rebase(vector_base);
|
||||
__asm volatile ("msr msp, %0" :: "r" (vectors[0]) : "memory");
|
||||
__asm volatile ("dsb\n\tisb" ::: "memory");
|
||||
entry();
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @file main.c
|
||||
* @brief Secure bootloader entry point (verify AES-128-CMAC, then boot).
|
||||
* @author Kevin Thomas
|
||||
* @date 2026
|
||||
*
|
||||
* MIT License
|
||||
* Copyright (c) 2026 Kevin Thomas
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* This file is deliberately thin: it only sequences the secure boot steps.
|
||||
* The console setup, halt reporting, and application handoff live in boot.c;
|
||||
* the CMAC verification (and its key) live in verify.c; the manifest lives in
|
||||
* manifest.c; and the raw reset-vector jump lives in image.c.
|
||||
*
|
||||
* Flash map (2 MiB, RP2350 Pico 2):
|
||||
* 0x10000000 bootloader image (this program)
|
||||
* 0x1001F000 one-sector firmware manifest (magic, size, CMAC tag)
|
||||
* 0x10020000 signed application image
|
||||
*/
|
||||
|
||||
#include "manifest.h"
|
||||
#include "boot.h"
|
||||
#include "verify.h"
|
||||
|
||||
int main(void) {
|
||||
fw_manifest_t manifest;
|
||||
boot_init();
|
||||
manifest_read(&manifest);
|
||||
if (!manifest_is_valid(&manifest)) boot_halt("manifest invalid");
|
||||
if (!verify_manifest(&manifest)) boot_halt("firmware signature invalid");
|
||||
boot_launch(&manifest);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @file manifest.c
|
||||
* @brief Reads and validates the firmware manifest from XIP flash.
|
||||
* @author Kevin Thomas
|
||||
* @date 2026
|
||||
*
|
||||
* MIT License
|
||||
* Copyright (c) 2026 Kevin Thomas
|
||||
*/
|
||||
|
||||
#include "flash_layout.h"
|
||||
#include "manifest.h"
|
||||
|
||||
void manifest_read(fw_manifest_t *out) {
|
||||
const fw_manifest_t *src = (const fw_manifest_t *)FW_MANIFEST_BASE;
|
||||
*out = *src;
|
||||
}
|
||||
|
||||
bool manifest_is_valid(const fw_manifest_t *manifest) {
|
||||
if (manifest->magic != FW_MANIFEST_MAGIC) return false;
|
||||
if (manifest->version != FW_MANIFEST_VERSION) return false;
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @file verify.c
|
||||
* @brief Firmware authenticity verification for the secure bootloader.
|
||||
* @author Kevin Thomas
|
||||
* @date 2026
|
||||
*
|
||||
* MIT License
|
||||
* Copyright (c) 2026 Kevin Thomas
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "flash_layout.h"
|
||||
#include "verify.h"
|
||||
#include "aes_cmac.h"
|
||||
|
||||
/** @brief AES-128 key that authenticates the application image. */
|
||||
static const uint8_t fw_key[FW_TAG_SIZE] = {
|
||||
0x49, 0x72, 0x6F, 0x6E, 0x4E, 0x65, 0x74, 0x42,
|
||||
0x6F, 0x6F, 0x74, 0x4B, 0x65, 0x79, 0x21, 0x21
|
||||
};
|
||||
|
||||
bool verify_manifest(const fw_manifest_t *manifest) {
|
||||
const uint8_t *base = (const uint8_t *)manifest->app_base;
|
||||
uint8_t computed[FW_TAG_SIZE];
|
||||
int rc = aes128_cmac(fw_key, base, manifest->app_size, computed);
|
||||
if (rc != 0) return false;
|
||||
return cmac_tags_equal(computed, manifest->tag);
|
||||
}
|
||||
Reference in new issue
Block a user