Fehlender unveränderlicher Root of Trust in der Hardware

Beschreibung

Fehlender unveränderlicher Root of Trust in der Hardware tritt auf, wenn ein System keinen Hardware-basierten Root of Trust implementiert, der unveränderlich oder ordnungsgemäß gegen Modifikation durch nicht vertrauenswürdige Agenten geschützt ist. Ein Root of Trust bildet die Grundlage für alle Sicherheitsoperationen im System und muss inhärent vertrauenswürdig sein. Ohne einen Hardware-basierten unveränderlichen Root of Trust können Angreifer das grundlegende Vertrauensanker des Systems manipulieren oder kompromittieren, wodurch alle darauf aufbauenden Sicherheitsmaßnahmen effektiv untergraben werden.

Risiko

Ein fehlender unveränderlicher Root of Trust ermöglicht verschiedene Angriffe. Angreifer können Firmware mit bösartigen Versionen ersetzen. Boot-Prozesse können manipuliert werden, ohne Erkennung. Kryptografische Schlüssel können ersetzt oder extrahiert werden. Secure-Boot-Ketten werden bedeutungslos ohne echten Hardware-Root. Das gesamte Gerät kann dauerhaft kompromittiert werden.

Lösung

Implementieren Sie einen Hardware-basierten Root of Trust, der nach der Herstellung nicht modifiziert werden kann. Verwenden Sie One-Time-Programmable (OTP)-Speicher für kritische Schlüssel und Konfigurationen. Implementieren Sie Secure-Boot-Ketten, die vom unveränderlichen Root of Trust ausgehen. Verwenden Sie Hardware-Security-Module (HSM) oder Trusted Platform Module (TPM). Verifizieren Sie jede Boot-Stufe gegen Signaturen, die an den Hardware-Root gebunden sind.

Häufige Auswirkungen

AuswirkungDetails
ZugriffskontrolleBereich: Zugriffskontrolle

Angreifer können durch Modifikation des Root of Trust beliebigen Zugriff erlangen.
IntegritätBereich: Integrität

Firmware- und Software-Integrität kann nicht gewährleistet werden.
AuthentifizierungBereich: Authentifizierung

Geräte-Authentizität kann nicht verifiziert werden.

Beispielcode und Lösung

Verwundbarer Code

// VERWUNDBAR: Root of Trust in veränderlichem Speicher gespeichert

module vulnerable_root_of_trust (
    input  wire        clk,
    input  wire        rst_n,

    // Boot-Schlüsselspeicher (VERWUNDBAR: beschreibbar)
    input  wire [255:0] key_write_data,
    input  wire         key_write_en,
    output reg  [255:0] boot_key,

    // Boot-Code-Hash (VERWUNDBAR: beschreibbar)
    input  wire [255:0] hash_write_data,
    input  wire         hash_write_en,
    output reg  [255:0] expected_boot_hash,

    // Sicherheitseinstellungen (VERWUNDBAR: beschreibbar)
    input  wire [31:0]  settings_write_data,
    input  wire         settings_write_en,
    output reg  [31:0]  security_settings,

    // Boot-Verifikation
    input  wire [255:0] actual_boot_hash,
    input  wire         verify_boot,
    output reg          boot_verified
);

    // VERWUNDBAR: Root-of-Trust-Werte in normalen Registern gespeichert
    // Können nach der Erstprovisionierung modifiziert werden

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            boot_key <= 256'h0;
            expected_boot_hash <= 256'h0;
            security_settings <= 32'h0;
        end else begin
            // VERWUNDBAR: Schlüssel kann jederzeit überschrieben werden
            if (key_write_en) begin
                boot_key <= key_write_data;
            end

            // VERWUNDBAR: Erwarteter Hash kann geändert werden
            if (hash_write_en) begin
                expected_boot_hash <= hash_write_data;
            end

            // VERWUNDBAR: Sicherheitseinstellungen modifizierbar
            if (settings_write_en) begin
                security_settings <= settings_write_data;
            end
        end
    end

    // Boot-Verifikation verwendet potenziell kompromittierte Werte
    always @(posedge clk) begin
        if (verify_boot) begin
            // VERWUNDBAR: Vergleicht gegen vom Angreifer modifizierbaren Hash
            boot_verified <= (actual_boot_hash == expected_boot_hash);
        end
    end

    // Angriff:
    // 1. Bösartigen Boot-Code in Flash schreiben
    // 2. expected_boot_hash aktualisieren um zum bösartigen Code zu passen
    // 3. Secure Boot bestanden, bösartiger Code wird ausgeführt

endmodule

// VERWUNDBAR: Fuse-Controller ohne Sperrmechanismus
module vulnerable_fuse_controller (
    input  wire        clk,
    input  wire        rst_n,

    // Fuse-Programmierungsschnittstelle
    input  wire [7:0]  fuse_addr,
    input  wire [31:0] fuse_data,
    input  wire        fuse_program,

    // Fuse-Leseschnittstelle
    output reg  [31:0] fuse_read_data
);

    // Fuse-Speicher (simuliert)
    reg [31:0] fuses [0:255];

    // VERWUNDBAR: Kein Sperrmechanismus
    // Fuses können nach der Erstprovisionierung umprogrammiert werden

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            // Fuses initialisieren
        end else if (fuse_program) begin
            // VERWUNDBAR: Erlaubt immer Programmierung
            fuses[fuse_addr] <= fuse_data;
        end
    end

    always @(*) begin
        fuse_read_data = fuses[fuse_addr];
    end

    // Angriff: Sicherheits-Fuses umprogrammieren um Schutz zu umgehen

endmodule
// VERWUNDBAR: Software verwendet veränderlichen Trust-Store

#include <stdint.h>
#include <stdbool.h>
#include <string.h>

// VERWUNDBAR: Root of Trust in normalem RAM
typedef struct {
    uint8_t root_key[32];
    uint8_t expected_hash[32];
    uint32_t security_flags;
} root_of_trust_t;

// VERWUNDBAR: In normalem Speicher gespeichert
static root_of_trust_t rot_store;

// VERWUNDBAR: Kann jederzeit modifiziert werden
void vulnerable_set_root_key(const uint8_t* key) {
    memcpy(rot_store.root_key, key, 32);
}

void vulnerable_set_expected_hash(const uint8_t* hash) {
    memcpy(rot_store.expected_hash, hash, 32);
}

bool vulnerable_verify_boot(const uint8_t* firmware, size_t size) {
    uint8_t computed_hash[32];

    sha256(firmware, size, computed_hash);

    // VERWUNDBAR: Vergleicht gegen modifizierbaren Hash
    return memcmp(computed_hash, rot_store.expected_hash, 32) == 0;
}

// Angriff: rot_store.expected_hash vor der Verifikation modifizieren
// Jede Firmware besteht die Verifikation

Sichere Lösung

// SICHER: Unveränderlicher Root of Trust mit Hardware-Schutz

module secure_root_of_trust (
    input  wire        clk,
    input  wire        rst_n,

    // Boot-Schlüsselspeicher (OTP - One-Time Programmable)
    input  wire [255:0] key_write_data,
    input  wire         key_write_en,
    input  wire         provisioning_mode,   // SICHER: Nur während Provisionierung
    output wire [255:0] boot_key,

    // Boot-Code-Hash (OTP)
    input  wire [255:0] hash_write_data,
    input  wire         hash_write_en,
    output wire [255:0] expected_boot_hash,

    // Sicherheitseinstellungen (OTP mit Sperre)
    input  wire [31:0]  settings_write_data,
    input  wire         settings_write_en,
    output wire [31:0]  security_settings,

    // Sperrstatus
    output reg          rot_locked,
    output reg          write_denied,

    // Boot-Verifikation
    input  wire [255:0] actual_boot_hash,
    input  wire         verify_boot,
    output reg          boot_verified
);

    // SICHER: OTP-Fuse-Speicher (simuliert als Register die nur gesetzt, nicht gelöscht werden können)
    reg [255:0] key_fuses;
    reg [255:0] hash_fuses;
    reg [31:0]  settings_fuses;
    reg         lock_fuse;  // SICHER: Sperrbit

    // SICHER: Schlüsselprovisionierung nur wenn entsperrt und im Provisionierungsmodus
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            key_fuses <= 256'h0;
            write_denied <= 1'b0;
        end else if (key_write_en) begin
            write_denied <= 1'b0;

            // SICHER: Schreiben nur im Provisionierungsmodus und vor Sperre erlauben
            if (provisioning_mode && !lock_fuse) begin
                // SICHER: OTP-Verhalten - kann nur Bits setzen, nicht löschen
                key_fuses <= key_fuses | key_write_data;
            end else begin
                write_denied <= 1'b1;
            end
        end
    end

    // SICHER: Hash-Provisionierung mit gleichem Schutz
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            hash_fuses <= 256'h0;
        end else if (hash_write_en && provisioning_mode && !lock_fuse) begin
            hash_fuses <= hash_fuses | hash_write_data;
        end
    end

    // SICHER: Einstellungs-Provisionierung
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            settings_fuses <= 32'h0;
        end else if (settings_write_en && provisioning_mode && !lock_fuse) begin
            settings_fuses <= settings_fuses | settings_write_data;
        end
    end

    // SICHER: Sperr-Fuse - einmal gesetzt, kann nicht gelöscht werden
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            lock_fuse <= 1'b0;
        end else if (settings_write_en && settings_write_data[31] && provisioning_mode) begin
            // SICHER: Sperrbit kann nur gesetzt, nie gelöscht werden
            lock_fuse <= 1'b1;
        end
    end

    // SICHER: Ausgabe von unveränderlichen Fuses
    assign boot_key = key_fuses;
    assign expected_boot_hash = hash_fuses;
    assign security_settings = settings_fuses;
    assign rot_locked = lock_fuse;

    // SICHER: Boot-Verifikation gegen unveränderlichen Hash
    always @(posedge clk) begin
        if (verify_boot) begin
            // Vergleicht gegen Hardware-geschützten Hash
            boot_verified <= (actual_boot_hash == hash_fuses);
        end
    end

endmodule

// SICHER: Sicherer Fuse-Controller mit Sperre
module secure_fuse_controller (
    input  wire        clk,
    input  wire        rst_n,

    // Fuse-Programmierungsschnittstelle
    input  wire [7:0]  fuse_addr,
    input  wire [31:0] fuse_data,
    input  wire        fuse_program,
    input  wire        provisioning_mode,

    // Fuse-Leseschnittstelle
    output reg  [31:0] fuse_read_data,
    output reg         program_denied,

    // Sperrstatus
    output wire        fuses_locked
);

    reg [31:0] fuses [0:255];
    reg [255:0] fuse_programmed;  // Verfolgen welche Fuses programmiert wurden
    reg global_lock;

    // SICHER: Sperradresse
    localparam LOCK_FUSE_ADDR = 8'hFF;

    // SICHER: Fuse-Programmierung mit Einschränkungen
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            global_lock <= 1'b0;
            program_denied <= 1'b0;
        end else if (fuse_program) begin
            program_denied <= 1'b0;

            // SICHER: Prüfen ob gesperrt oder nicht im Provisionierungsmodus
            if (global_lock || !provisioning_mode) begin
                program_denied <= 1'b1;
            end
            // SICHER: Prüfen ob bereits programmiert (OTP)
            else if (fuse_programmed[fuse_addr]) begin
                program_denied <= 1'b1;
            end
            else begin
                // SICHER: Fuse programmieren (OTP - nur einmal)
                fuses[fuse_addr] <= fuse_data;
                fuse_programmed[fuse_addr] <= 1'b1;

                // SICHER: Auf Sperr-Fuse prüfen
                if (fuse_addr == LOCK_FUSE_ADDR && fuse_data[0]) begin
                    global_lock <= 1'b1;
                end
            end
        end
    end

    assign fuses_locked = global_lock;

    always @(*) begin
        fuse_read_data = fuses[fuse_addr];
    end

endmodule
// SICHER: Unveränderliche Root-of-Trust-Implementierung

#include <stdint.h>
#include <stdbool.h>
#include <string.h>

// SICHER: Hardware-Adressen für OTP-Fuses
#define OTP_ROOT_KEY_ADDR    0x10000000
#define OTP_HASH_ADDR        0x10000020
#define OTP_SETTINGS_ADDR    0x10000040
#define OTP_LOCK_ADDR        0x100000FF

// SICHER: Aus Hardware-OTP lesen (kann nicht durch Software modifiziert werden)
static inline void read_otp(uint32_t addr, uint8_t* data, size_t len) {
    volatile uint8_t* otp = (volatile uint8_t*)addr;
    for (size_t i = 0; i < len; i++) {
        data[i] = otp[i];
    }
}

// SICHER: Prüfen ob OTP gesperrt ist
static inline bool is_otp_locked(void) {
    volatile uint32_t* lock = (volatile uint32_t*)OTP_LOCK_ADDR;
    return (*lock & 1) != 0;
}

// SICHER: Sichere Boot-Verifikation mit Hardware-OTP
bool secure_verify_boot(const uint8_t* firmware, size_t size) {
    uint8_t expected_hash[32];
    uint8_t computed_hash[32];

    // SICHER: Erwarteten Hash aus Hardware-OTP lesen (unveränderlich)
    read_otp(OTP_HASH_ADDR, expected_hash, 32);

    // Hash der Firmware berechnen
    sha256(firmware, size, computed_hash);

    // SICHER: Gegen Hardware-geschützten Hash vergleichen
    // Software kann expected_hash nicht modifizieren
    return secure_compare(computed_hash, expected_hash, 32) == 0;
}

// SICHER: Provisionierung nur einmal erlaubt
bool provision_root_of_trust(const uint8_t* key, const uint8_t* hash) {
    // SICHER: Prüfen ob bereits gesperrt
    if (is_otp_locked()) {
        return false;  // Kann nicht provisionieren - bereits gesperrt
    }

    // SICHER: OTP programmieren (Hardware stellt einmalige Programmierung sicher)
    // Dies erfordert spezielles Provisionierungsmodus-Signal von Hardware
    if (!program_otp(OTP_ROOT_KEY_ADDR, key, 32)) {
        return false;
    }

    if (!program_otp(OTP_HASH_ADDR, hash, 32)) {
        return false;
    }

    // SICHER: OTP nach Provisionierung sperren
    uint32_t lock_value = 1;
    if (!program_otp(OTP_LOCK_ADDR, (uint8_t*)&lock_value, 4)) {
        return false;
    }

    return true;
}

Ausgenutzt in der Praxis

UEFI-Firmware-Rootkits

Angreifer haben Firmware-Rootkits entwickelt, die auf Systemen ohne Hardware-Root-of-Trust persistieren. Der Hacking-Team-Leak enthüllte UEFI-Rootkits, die Betriebssystem-Neuinstallationen überleben.

Spectre/Meltdown und Hardware-Trust

Die Spectre- und Meltdown-Schwachstellen zeigten, wie Hardware-Vertrauen selbst auf CPU-Ebene kompromittiert werden kann, wenn spekulative Ausführung nicht ordnungsgemäß isoliert ist.


Tools zum Testen und Ausnutzen

  • CHIPSEC - Plattform-Sicherheitsbewertungs-Framework.

  • UEFITool - UEFI-Firmware-Analyse-Tool.

  • Binwalk - Firmware-Analyse-Tool.


CVE-Beispiele

  • CVE-2020-0069 - MediaTek-Bootrom-Schwachstelle ermöglicht Secure-Boot-Umgehung.

  • CVE-2019-11478 - Intel-Boot-Guard-Konfigurationsschwachstelle.


Referenzen

  1. MITRE Corporation. "CWE-1326: Missing Immutable Root of Trust in Hardware." https://cwe.mitre.org/data/definitions/1326.html

  2. NIST. "Hardware Security Guidelines." https://csrc.nist.gov/

  3. TCG. "Trusted Platform Module Specification." https://trustedcomputinggroup.org/