Course contentsShow
← Rust
Lesson 1506 of 1,91012. Unsafe Rust and Low-Level AccessFree lesson

Firmware Image Validation

You will implement code to verify the signature of firmware updates before execution.

In this lesson, you will learn how to implement a secure cryptographic verification gate that prevents unauthorized firmware from executing on your embedded target.

Establishing a Trust Anchor

When a device boots, it must distinguish between legitimate firmware and malicious code. Before jumping to the entry point of a new image, the bootloader performs an integrity check. We achieve this by verifying a digital signature (such as Ed25519) attached to the image, using a public key hardcoded into the device's read-only memory (ROM).

Because we are operating in a no_std environment without an OS, we must handle the raw binary buffer directly.

Implementing the Verification Gate

The core logic involves mapping the firmware image in memory, isolating the signature, and invoking a verified cryptographic crate (like ed25519-dalek configured for no_std).

// A simplified validation function for firmware in flash
fn verify_firmware_image(image_base: *const u8, size: usize) -> bool {
    // 1. Separate the signature from the payload
    let (signature, payload) = split_image(image_base, size);
    
    // 2. Load the public key from immutable storage
    let public_key = get_hardcoded_public_key();
    
    // 3. Perform cryptographic verification
    // We treat the memory as a slice, which is unsafe due to pointer alignment
    let firmware_slice = unsafe { core::slice::from_raw_parts(payload, size - SIGNATURE_SIZE) };
    
    match public_key.verify(firmware_slice, signature) {
        Ok(_) => true,
        Err(_) => false,
    }
}

Critical Security Considerations

When implementing this, keep two low-level constraints in mind:

  1. Memory Mapping: Ensure your image_base pointer resides in a valid, non-mutable flash region. Accessing this via a slice requires strict adherence to memory safety; if the image is being written to simultaneously (e.g., via DMA), you must ensure the verification occurs on a stable memory snapshot to prevent "Time-of-Check to Time-of-Use" (TOCTOU) vulnerabilities.
  2. Panic Safety: In a bootloader, a panic during verification must not lead to a default "jump to code" behavior. Ensure your panic_handler puts the system into a secure, locked state—such as blinking an error LED or entering an infinite loop—rather than resetting the processor and potentially retrying an unverified image.

Key Takeaway: Firmware validation treats the binary as an untrusted slice of data, relying on an immutable, ROM-resident public key to cryptographically sign off on the image before the CPU ever attempts to execute its instructions.