Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Chapter 13: Automotive Security and the Roots of Trust

Over the past decade, the automotive landscape has undergone a profound transformation. The mechanical components that once defined vehicles have progressively given way to their electronic counterparts, giving rise to highly intelligent, software-defined vehicles. Today’s cars are essentially rolling networks of electronic control units (ECUs) managing everything from infotainment to critical road-assist and safety systems. But as we connect these internal networks to the outside world—via Wi-Fi, cellular networks, and V2X (Vehicle-to-Everything) communications—we expose them to an entirely new class of threats.

In this chapter, we are going to look at the automotive threat landscape, why the legacy buses inside your car are incredibly vulnerable, and how we lock down the hardware using Secure Boot.

13.1 The Automotive Threat Landscape

In the old days, vehicle security meant preventing someone from physically tampering with your brake wires, jimmying a lock, or hot-wiring the ignition. Today, the threat is invisible and wireless.

At the heart of almost every modern vehicle’s internal communication is the Controller Area Network (CAN) bus. Developed by Robert Bosch GmbH in the 1980s, the CAN bus is a serial, message-based protocol originally designed to allow microcontrollers to communicate in electrically noisy environments without a central host computer. It is exceptionally reliable for real-time control, but it has a fatal flaw in the modern era: it was never designed with cybersecurity in mind.

The CAN bus inherently lacks modern security mechanisms like encryption and authentication. When an ECU transmits a message—say, the steering wheel telling the wheels to turn—it broadcasts that message unencrypted to the entire bus. Because there is no authentication, any device on the network can read the data, and worse, any device can inject forged messages.

If an attacker gains access to the CAN bus, they can launch several devastating attacks:

  • Eavesdropping and Data Tampering: Without encryption, unauthorized entities can easily intercept and read sensitive data transmitted over the network.
  • Replay Attacks: Because CAN messages lack cryptographic freshness guarantees, an attacker can record a legitimate message (like the command to unlock the doors) and replay it later to trigger the action without authorization.
  • Denial of Service (DoS): An attacker can flood the CAN bus with high-priority fake traffic, overwhelming the network and preventing critical safety messages (like a command to deploy airbags or apply brakes) from reaching their destinations.

WAR STORY: The Jeep Cherokee Hack (Note: The specific details of the 2015 Jeep Cherokee hack mentioned here are drawn from historical context outside of our provided sources, but they perfectly illustrate the vulnerabilities our sources describe). In 2015, cybersecurity researchers Charlie Miller and Chris Valasek famously hacked a Jeep Cherokee while it was driving down the highway. By exploiting a vulnerability in the vehicle’s internet-connected infotainment system, they were able to pivot into the car’s internal CAN bus. Because the CAN bus lacks authentication, they were able to inject raw steering and braking commands, remotely killing the transmission and disabling the brakes.

As our sources note, the successful execution of such cyberattacks carries catastrophic implications, mimicking physical sabotage by incapacitating brakes, unlocking doors, or shutting off the engine entirely. The introduction of Firmware Over-The-Air (FOTA) updates and V2X communication expands this attack surface even further, turning isolated vehicles into globally accessible targets.

13.2 Secure Boot and Hardware Trust Anchors

If an attacker manages to push a malicious FOTA update to your vehicle’s engine control unit, they own the vehicle. To prevent this, we cannot simply rely on software firewalls. We must root our security in immutable silicon. We do this by implementing a Secure Boot process.

When an automotive ECU receives power, the hardware has strict rules about what happens next. In a system with Secure Boot, the processor is physically prevented from executing random code. Instead, it must systematically verify that every piece of software it loads is trusted, authentic, and completely unmodified.

Cryptographic Signatures and the Chain of Trust

Secure Boot relies on cryptographic signatures (specifically public-key cryptography) to verify the authenticity and integrity of firmware images. Here is how the process works:

  1. When the manufacturer creates a firmware update, they compute a cryptographic hash of the file and encrypt that hash using their closely guarded private key. This creates the digital signature.
  2. When the ECU boots up, it computes its own hash of the firmware sitting in its memory.
  3. The ECU then uses the manufacturer’s public key to decrypt the attached digital signature.
  4. If the decrypted hash perfectly matches the newly computed hash, the ECU knows the firmware is authentic and has not been tampered with. The code is allowed to run.

By repeating this process sequentially, the system establishes a chain of trust starting from the lowest-level bootloader, up through the firmware, and finally into the operating system. If an attacker alters even a single byte of the firmware, the hash will change, the signature verification will fail, and the ECU will reject the untrusted update and halt the boot process.

Hardware Trust Anchors: HSMs and TPMs

For Secure Boot to mean anything, the public keys and the cryptographic verification engine cannot simply sit in standard, modifiable RAM. If they did, an attacker could just overwrite the manufacturer’s public key with their own, allowing them to sign their own malicious firmware.

To solve this, the keys and cryptographic operations must be isolated inside a Hardware Security Module (HSM) or a Trusted Platform Module (TPM).

A TPM is a dedicated, tamper-resistant cryptographic coprocessor integrated directly into the hardware. It acts as the ultimate Hardware Trust Anchor for the system. The TPM provides several highly secure services:

  • Secure Key Storage: The TPM can permanently lock cryptographic keys within its silicon, ensuring they cannot be discovered or extracted by malicious software or even by a sophisticated attacker with physical access to the chip.
  • System Integrity Verification: The TPM provides the isolated cryptographic processing power required by the firmware to execute the Secure Boot signature verifications safely.
  • True Random Number Generation: It uses physical hardware entropy to generate truly random, unpredictable cryptographic keys.

By storing the root keys in an unalterable TPM and enforcing a strict Secure Boot chain, automotive engineers can guarantee that even if an attacker compromises the external cellular connection, they cannot rewrite the underlying physical behavior of the vehicle’s control systems.

13.3 Firmware Over-The-Air (FOTA)

In the old days of the automotive industry, fixing a software bug meant forcing the customer to drive to a dealership so a technician could plug a physical cable into the vehicle and manually flash the Electronic Control Unit (ECU). Today, that model is entirely obsolete.

Borrowing heavily from the mobile phone industry, modern Cyber-Physical Systems (CPS) rely on Firmware Over-The-Air (FOTA) updates. FOTA allows manufacturers to wirelessly push security patches, performance improvements, and entirely new features directly to vehicles or edge devices in the field. It drastically reduces fleet management costs, improves the user experience, and, most importantly, allows manufacturers to rapidly patch zero-day vulnerabilities before attackers can exploit them.

But FOTA introduces a terrifying operational hazard. When you flash an ECU over a wireless network, you are fighting physics. Network connections drop. Flash memory chips degrade. And vehicle batteries die. If a drone or a car loses power when the firmware update is only 50% complete, or if the new firmware contains a fatal bug that immediately causes a HardFault upon booting, a standard microcontroller will be rendered permanently inoperable. You have just created a two-ton, $40,000 brick.

13.3.1 The Dual-Image System (A/B Partitioning)

To survive a failed update, your system must have a guaranteed, autonomous fallback mechanism. In the automotive industry, this is implemented using a dual-image system, commonly referred to as A/B partitioning.

Instead of having a single massive block of Flash memory for your application, you divide the memory into two identical, independent partitions (Partition A and Partition B).

Here is how the lifecycle works:

  1. Normal Operation: The vehicle is currently executing the known-good firmware from the active partition (let’s say, Partition A).
  2. Background Download: When an update is triggered, the FOTA agent downloads the encrypted software package over the cellular network and writes the new firmware directly into the inactive partition (Partition B). Because Partition A is untouched, the vehicle can remain fully operational during the download.
  3. Verification: Once the download is complete, the system verifies the digital signatures and checksums of Partition B to ensure the payload is authentic and uncorrupted.
  4. The Swap: The system sets a persistent flag in a dedicated Flash/EEPROM metadata sector, instructing the bootloader to attempt to boot from Partition B on the next restart.
  5. The Rollback: If Partition B fails to boot, or crashes shortly after booting, the system automatically falls back to the pristine firmware still sitting in Partition A.

13.3.2 The Bootloader Logic: C Code for a Safe Swap

To implement this safely, the logic cannot live in your main application. It must live in an immutable, highly trusted piece of software called the Bootloader. The bootloader executes the moment power is applied. It inspects a small “Boot Record” in memory, decides which partition to boot, and configures a hardware Watchdog Timer.

If the new firmware doesn’t successfully boot and disable the watchdog in time, the watchdog resets the CPU, and the bootloader catches the failure.

Here is the bare-metal C logic for a bulletproof A/B partition swap:

#include <stdint.h>

// Memory map definitions
#define PARTITION_A_ADDR 0x08010000
#define PARTITION_B_ADDR 0x08080000
#define BOOT_RECORD_ADDR 0x0800F000 // Safe sector for metadata

// Hardware Watchdog (WDT) Registers
#define WDT_KICK_REG     (*(volatile uint32_t*) 0x40003000)
#define WDT_ENABLE_REG   (*(volatile uint32_t*) 0x40003004)

// The metadata structure stored in non-volatile Flash/EEPROM
typedef struct {
    uint8_t active_partition; // 0 = Partition A, 1 = Partition B
    uint8_t pending_update;   // 1 if a new update is waiting to be tested
    uint8_t update_success;   // 1 if the new update booted successfully
    uint8_t padding;
} boot_record_t;

// Pointer to our persistent boot record
#define BOOT_RECORD ((volatile boot_record_t*) BOOT_RECORD_ADDR)

// Function pointer type for branching to the application
typedef void (*app_main_t)(void);

void bootloader_main(void) {
    uint32_t target_address;

    // 1. Check if we are testing a new FOTA update
    if (BOOT_RECORD->pending_update == 1) {
        
        // Did the update crash on the last attempt?
        if (BOOT_RECORD->update_success == 0) {
            // THE ROLLBACK: The system reset before the new firmware 
            // could mark itself as successful. The update is bad!
            // We gracefully fall back to the known-good active partition.
            clear_pending_update_flag(); // Revert metadata in Flash
            
            target_address = (BOOT_RECORD->active_partition == 0) ? 
                              PARTITION_A_ADDR : PARTITION_B_ADDR;
        } else {
            // First time trying the new update! 
            // Attempt to boot the inactive partition.
            target_address = (BOOT_RECORD->active_partition == 0) ? 
                              PARTITION_B_ADDR : PARTITION_A_ADDR;
            
            // 2. Start the Hardware Watchdog. 
            // If the new firmware freezes or HardFaults, the WDT will reset 
            // the CPU in 5 seconds, triggering the rollback logic above.
            WDT_ENABLE_REG = 1; 
        }
    } else {
        // Normal boot: load the established active partition
        target_address = (BOOT_RECORD->active_partition == 0) ? 
                          PARTITION_A_ADDR : PARTITION_B_ADDR;
    }

    // 3. Vector away to the chosen firmware application
    // (In ARM Cortex-M, we load the stack pointer, then jump to the reset vector)
    uint32_t app_stack = *((volatile uint32_t*) target_address);
    app_main_t app_entry = (app_main_t) *((volatile uint32_t*) (target_address + 4));

    __asm__ volatile ("msr msp, %0" : : "r" (app_stack)); // Set Stack Pointer
    app_entry(); // Jump to the application
}

13.3.3 The Application Logic: Committing the Update

The bootloader code above relies on the fact that BOOT_RECORD->update_success defaults to 0 when the new firmware is downloaded. The bootloader arms a ticking time bomb (the hardware watchdog) before jumping to the new firmware.

If the new firmware loses power halfway through its boot sequence, or if a networking bug traps it in an infinite loop, the watchdog timer will expire, the silicon will reset, and the bootloader will execute the if (BOOT_RECORD->update_success == 0) rollback condition, instantly reverting the vehicle to a safe operational state.

To finalize the update and prevent the rollback, the new firmware must “commit” the update by writing to the flash metadata and kicking the watchdog. This should only happen after the new firmware has successfully brought up the RTOS, initialized the CAN bus, and passed its own internal sanity checks:

void new_firmware_main(void) {
    // 1. Initialize hardware, RTOS, and network stacks
    system_init();
    
    // 2. Run self-diagnostics to ensure we aren't a broken update
    if (run_sanity_checks() == SYSTEM_OK) {
        
        // 3. COMMIT THE UPDATE!
        // We survived the boot process. Write to the non-volatile boot record 
        // to tell the bootloader we are stable.
        flash_unlock();
        BOOT_RECORD->update_success = 1;
        BOOT_RECORD->active_partition = (BOOT_RECORD->active_partition == 0) ? 1 : 0;
        BOOT_RECORD->pending_update = 0;
        flash_lock();
        
        // 4. Disable or service the Watchdog Timer 
        WDT_KICK_REG = 1;
    } else {
        // If sanity checks fail, we purposefully let the watchdog reset us 
        // so the bootloader handles the rollback.
        while(1); 
    }
    
    // ... proceed to normal super-loop ...
}

By enforcing this strict handshake between the bootloader, the application, and the hardware watchdog, your CPS can survive catastrophic network drops and corrupted deployments. The system will always autonomously recover, ensuring that even if an update completely fails, the physical equipment remains secure and functional.