Skip to content

Latest commit

Β 

History

History
527 lines (404 loc) Β· 15.6 KB

File metadata and controls

527 lines (404 loc) Β· 15.6 KB

Secure Boot and Chain of Trust

Building Unbreakable Trust from Power-On to Runtime
Understanding how secure boot creates a foundation of trust that protects your entire system


πŸ“‹ Table of Contents


πŸ—οΈ Trust Foundation

Why Trust Matters from the First Instruction

Imagine you're building a house. You wouldn't start with the walls or roofβ€”you'd start with a solid foundation. Secure boot is that foundation for your embedded system's security.

The Trust Problem

When your device powers on, it's in a completely untrusted state. Anyone could have:

  • Replaced the firmware with malicious code
  • Modified the bootloader to skip security checks
  • Tampered with the hardware to bypass protections
  • Intercepted the boot process to inject malicious code

The Solution: Secure Boot

Secure boot ensures that only trusted, verified code can run on your system. It's like having a security guard that checks everyone's ID before they enter a building.


πŸ”— Chain of Trust

Building Trust Step by Step

A chain of trust works like a relay race where each runner must verify the next runner before passing the baton. If any link in the chain is broken, trust is lost.

The Trust Chain Visualization

Power-On β†’ ROM β†’ Bootloader β†’ Kernel β†’ Applications
   ↓         ↓        ↓         ↓         ↓
Untrusted β†’ Trusted β†’ Trusted β†’ Trusted β†’ Trusted
   State     Code     Code      Code      Code

How It Works:

  1. ROM (Read-Only Memory) - Contains the initial trusted code
  2. Bootloader - Verified by ROM before execution
  3. Kernel - Verified by bootloader before execution
  4. Applications - Verified by kernel before execution

Trust Verification Process

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           ROM (Trusted)             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚   Public Key Hash           β”‚    β”‚
β”‚  β”‚   (Hardcoded in ROM)       β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              ↓
        Verify Bootloader
              ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚        Bootloader (Verified)        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚   Digital Signature         β”‚    β”‚
β”‚  β”‚   (Signed by trusted key)   β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              ↓
        Verify Kernel
              ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚          Kernel (Verified)          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚   Digital Signature         β”‚    β”‚
β”‚  β”‚   (Signed by trusted key)   β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸš€ Secure Boot Process

Step-by-Step Boot Verification

Phase 1: Hardware Initialization

When power is applied, the system starts in a completely untrusted state:

// Hardware reset sequence
void hardware_reset() {
    // Clear all registers and memory
    clear_all_registers();
    clear_all_memory();
    
    // Disable all peripherals except essential ones
    disable_non_essential_peripherals();
    
    // Set security mode to highest level
    set_security_mode(SECURITY_MODE_HIGHEST);
    
    // Jump to ROM code
    jump_to_rom();
}

Phase 2: ROM Code Execution

The ROM contains the first trusted code that can't be modified:

// ROM code (immutable, trusted)
void rom_entry_point() {
    // Initialize minimal hardware
    init_minimal_hardware();
    
    // Load bootloader from storage
    uint8_t* bootloader = load_bootloader_from_storage();
    
    // Verify bootloader signature
    if (!verify_bootloader_signature(bootloader)) {
        // Bootloader verification failed
        enter_secure_failure_mode();
        return;
    }
    
    // Calculate bootloader hash
    uint8_t calculated_hash[32];
    calculate_hash(bootloader, BOOTLOADER_SIZE, calculated_hash);
    
    // Compare with trusted hash
    if (!compare_hashes(calculated_hash, TRUSTED_BOOTLOADER_HASH)) {
        // Hash mismatch - bootloader corrupted
        enter_secure_failure_mode();
        return;
    }
    
    // Bootloader is trusted - execute it
    execute_bootloader(bootloader);
}

Phase 3: Bootloader Verification

The bootloader must verify itself and the next component:

// Bootloader verification
typedef struct {
    uint8_t signature[64];      // Digital signature
    uint8_t hash[32];          // Code hash
    uint32_t version;          // Version number
    uint32_t flags;            // Security flags
    uint8_t reserved[16];      // Reserved for future use
} BootloaderHeader;

bool verify_bootloader_integrity(uint8_t* bootloader) {
    BootloaderHeader* header = (BootloaderHeader*)bootloader;
    
    // Step 1: Verify signature using ROM public key
    uint8_t* code_start = bootloader + sizeof(BootloaderHeader);
    uint32_t code_size = BOOTLOADER_SIZE - sizeof(BootloaderHeader);
    
    if (!verify_signature(header->signature, 
                         code_start, 
                         code_size, 
                         ROM_PUBLIC_KEY)) {
        return false; // Signature verification failed
    }
    
    // Step 2: Verify code hash
    uint8_t calculated_hash[32];
    calculate_hash(code_start, code_size, calculated_hash);
    
    if (memcmp(calculated_hash, header->hash, 32) != 0) {
        return false; // Hash mismatch
    }
    
    // Step 3: Check version compatibility
    if (header->version < MIN_SUPPORTED_VERSION) {
        return false; // Version too old
    }
    
    // Step 4: Check security flags
    if (header->flags & FLAG_DEBUG_ENABLED) {
        return false; // Debug mode not allowed
    }
    
    return true; // All checks passed
}

Phase 4: Kernel Verification

The bootloader verifies the kernel before loading it:

// Kernel verification process
bool verify_kernel(uint8_t* kernel_image) {
    KernelHeader* header = (KernelHeader*)kernel_image;
    
    // Verify kernel signature
    if (!verify_signature(header->signature, 
                         kernel_image + sizeof(KernelHeader),
                         header->code_size,
                         BOOTLOADER_PUBLIC_KEY)) {
        return false;
    }
    
    // Verify kernel hash
    uint8_t calculated_hash[32];
    calculate_hash(kernel_image + sizeof(KernelHeader),
                  header->code_size,
                  calculated_hash);
    
    if (memcmp(calculated_hash, header->hash, 32) != 0) {
        return false;
    }
    
    // Check kernel security attributes
    if (!verify_kernel_security_attributes(header)) {
        return false;
    }
    
    return true;
}

πŸ› οΈ Implementation Details

Building Your Secure Boot System

1. Cryptographic Primitives

You'll need several cryptographic functions:

// Cryptographic function prototypes
typedef struct {
    uint8_t modulus[256];      // RSA modulus
    uint8_t exponent[4];       // RSA exponent
} RSAPublicKey;

// Hash calculation (SHA-256)
void calculate_sha256(const uint8_t* data, 
                     uint32_t length, 
                     uint8_t* hash);

// RSA signature verification
bool verify_rsa_signature(const uint8_t* signature,
                         const uint8_t* data,
                         uint32_t data_length,
                         const RSAPublicKey* public_key);

// HMAC calculation for integrity
void calculate_hmac(const uint8_t* key,
                   uint32_t key_length,
                   const uint8_t* data,
                   uint32_t data_length,
                   uint8_t* hmac);

2. Key Management

Managing cryptographic keys is critical:

// Key storage structure
typedef struct {
    uint8_t key_id[16];        // Unique key identifier
    uint8_t public_key[256];   // Public key data
    uint32_t key_type;         // Key type (RSA, ECC, etc.)
    uint32_t key_size;         // Key size in bits
    uint32_t permissions;      // What this key can verify
    uint8_t reserved[32];      // Reserved for future use
} TrustedKey;

// Key database
typedef struct {
    uint32_t num_keys;         // Number of trusted keys
    TrustedKey keys[MAX_KEYS]; // Array of trusted keys
    uint8_t reserved[64];      // Reserved for future use
} KeyDatabase;

// Find key by ID
TrustedKey* find_trusted_key(const uint8_t* key_id) {
    for (int i = 0; i < key_database.num_keys; i++) {
        if (memcmp(key_database.keys[i].key_id, key_id, 16) == 0) {
            return &key_database.keys[i];
        }
    }
    return NULL; // Key not found
}

3. Secure Storage

Protect keys and sensitive data:

// Secure storage implementation
typedef struct {
    uint8_t data[256];         // Encrypted data
    uint8_t iv[16];            // Initialization vector
    uint8_t tag[16];           // Authentication tag
} EncryptedData;

// Encrypt sensitive data
bool encrypt_secure_data(const uint8_t* plaintext,
                        uint32_t length,
                        const uint8_t* key,
                        EncryptedData* encrypted) {
    
    // Generate random IV
    if (!generate_random_bytes(encrypted->iv, 16)) {
        return false;
    }
    
    // Encrypt data using AES-GCM
    if (!aes_gcm_encrypt(plaintext, length,
                         key, encrypted->iv,
                         encrypted->data, encrypted->tag)) {
        return false;
    }
    
    return true;
}

// Decrypt sensitive data
bool decrypt_secure_data(const EncryptedData* encrypted,
                        const uint8_t* key,
                        uint8_t* plaintext,
                        uint32_t* length) {
    
    // Decrypt using AES-GCM
    if (!aes_gcm_decrypt(encrypted->data, encrypted->tag,
                         key, encrypted->iv,
                         plaintext, length)) {
        return false;
    }
    
    return true;
}

πŸš€ Advanced Features

Beyond Basic Secure Boot

1. Rollback Protection

Prevent attackers from downgrading to vulnerable versions:

// Version management
typedef struct {
    uint32_t major_version;    // Major version number
    uint32_t minor_version;    // Minor version number
    uint32_t patch_version;    // Patch version number
    uint32_t build_number;     // Build number
} VersionInfo;

// Check for rollback attempts
bool check_version_rollback(const VersionInfo* new_version) {
    VersionInfo current_version = get_current_version();
    
    // Compare version numbers
    if (new_version->major_version < current_version.major_version) {
        return false; // Major version rollback
    }
    
    if (new_version->major_version == current_version.major_version) {
        if (new_version->minor_version < current_version.minor_version) {
            return false; // Minor version rollback
        }
        
        if (new_version->minor_version == current_version.minor_version) {
            if (new_version->patch_version < current_version.patch_version) {
                return false; // Patch version rollback
            }
        }
    }
    
    return true; // No rollback detected
}

2. Secure Update Process

Ensure updates maintain security:

// Update verification
typedef struct {
    uint8_t signature[64];     // Update signature
    uint8_t hash[32];          // Update hash
    VersionInfo version;       // Update version
    uint32_t update_size;      // Size of update
    uint8_t update_type;       // Type of update
    uint8_t reserved[15];      // Reserved
} UpdateHeader;

bool verify_update_package(const uint8_t* update_data) {
    UpdateHeader* header = (UpdateHeader*)update_data;
    
    // Verify update signature
    if (!verify_signature(header->signature,
                         update_data + sizeof(UpdateHeader),
                         header->update_size,
                         UPDATE_SIGNING_KEY)) {
        return false;
    }
    
    // Check for rollback
    if (!check_version_rollback(&header->version)) {
        return false;
    }
    
    // Verify update hash
    uint8_t calculated_hash[32];
    calculate_hash(update_data + sizeof(UpdateHeader),
                  header->update_size,
                  calculated_hash);
    
    if (memcmp(calculated_hash, header->hash, 32) != 0) {
        return false;
    }
    
    return true;
}

3. Secure Recovery Mode

Provide recovery options while maintaining security:

// Recovery mode handling
typedef enum {
    RECOVERY_MODE_NONE,
    RECOVERY_MODE_UPDATE,
    RECOVERY_MODE_FACTORY_RESET,
    RECOVERY_MODE_DEBUG
} RecoveryMode;

bool enter_recovery_mode(RecoveryMode mode) {
    // Check if recovery mode is allowed
    if (!is_recovery_mode_allowed(mode)) {
        return false;
    }
    
    // Verify recovery mode request
    if (!verify_recovery_request(mode)) {
        return false;
    }
    
    // Set recovery mode
    set_recovery_mode(mode);
    
    // Reboot into recovery mode
    system_reboot();
    
    return true;
}

🎯 Key Takeaways

Fundamental Principles

  1. Trust starts at power-on - Every component must be verified
  2. Chain of trust is unbreakable - One broken link breaks everything
  3. Cryptographic verification - Use strong crypto for all verifications
  4. Secure key management - Protect your keys as much as your code
  5. Rollback protection - Prevent downgrade attacks

Implementation Checklist

  • ROM code contains trusted public keys
  • Bootloader is cryptographically signed
  • Kernel verification implemented
  • Application verification implemented
  • Key management system in place
  • Rollback protection enabled
  • Secure update process implemented
  • Recovery mode security implemented
  • Tamper detection enabled
  • Security testing completed

Common Pitfalls

  1. Weak cryptography - Use industry-standard algorithms
  2. Key exposure - Never expose private keys
  3. No rollback protection - Attackers can downgrade to vulnerable versions
  4. Insufficient verification - Verify everything, trust nothing
  5. No recovery plan - Plan for secure recovery scenarios

πŸ“š Additional Resources

  • "Trusted Platform Module (TPM) Summary" by NIST - TPM specifications
  • "Secure Boot Implementation Guide" by ARM - ARM secure boot guide
  • "UEFI Secure Boot" by UEFI Forum - UEFI secure boot specification

Next Topic: TPM 2.0 Basics β†’ Cryptographic Foundations