Sensible Informationen vor Debug-/Energiezustandsübergang nicht geloscht

Beschreibung

Sensible Informationen vor Debug-/Energiezustandsübergang nicht geloscht tritt auf, wenn ein Produkt sensible Informationen während Energie- oder Debug-Zustandsübergangen nicht loscht, wodurch Daten zuganglich bleiben, wenn sie aufgrund geänderter Zugriffseinschränkungen nicht mehr verfügbar sein sollten. Gerate arbeiten über mehrere Energiezustände (Normal, Niedrigenergie, Ruhezustand, Tiefschlaf) und Debug-Bedingungen. Beim Übergang zwischen Zuständen können Informationen, die im vorherigen Zustand zuganglich waren, im Speicher verbleiben. Wenn diese sensiblen Daten nicht vor dem Übergang entfernt werden, können sie an unbefugte Akteure im neuen Zustand gelangen.

Risiko

Nicht geloschte sensible Informationen haben schwerwiegende Sicherheitsauswirkungen. Kryptografische Schlüssel können über Zustände hinweg durchsickern. Authentifizierungsdaten können freigelegt werden. Debug-Zugriff kann Geheimnisse offenlegen. Versteckte Geratefunktionen können entsperrt werden. Vertrauliche Daten können kompromittiert werden. Sicherheitsgrenzen können verletzt werden. Angreifer können Zustandsübergange ausnutzen. Informationsoffenlegung ermöglicht weitere Angriffe.

Lösung

Entfernen Sie während Zustandsübergangen Informationen, die im nächsten Zustand nicht benötigt werden, bevor der Übergang abgeschlossen wird. Implementieren Sie automatisches Loschen sensibler Register und Speicher während Energieübergängen. Loschen Sie kryptografische Schlüssel vor dem Eintritt in den Debug-Modus. Entwerfen Sie Zustandsmaschinen, die das Loschen von Daten erzwingen. Verifizieren Sie das Loschen durch Tests. Wenden Sie diese Minderung sowohl während der Architektur-/Design- als auch der Implementierungsphase an.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitUmfang: Vertraulichkeit

Speicher lesen - Sensible Daten bleiben nach Zustandsübergang zuganglich.
ZugriffskontrolleUmfang: Zugriffskontrolle

Schutzmechanismus umgehen - Angreifer können über Zustandsübergange auf Daten zugreifen.
AuthentifizierungUmfang: Authentifizierung

Berechtigungen erlangen - Anmeldedaten können aus dem vorherigen Zustand wiederhergestellt werden.

Beispielcode und Lösung

Verwundbarer Code

// VERWUNDBAR: Zustandsübergang ohne Loschen sensibler Daten

module vulnerable_power_controller (
    input wire clk,
    input wire reset_n,
    input wire [1:0] power_request,
    output reg [1:0] current_state,
    // Sensible Daten
    input wire [127:0] encryption_key,
    output reg [127:0] key_register
);

    // Energiezustände
    parameter ACTIVE = 2'b00;
    parameter IDLE = 2'b01;
    parameter SLEEP = 2'b10;
    parameter DEBUG = 2'b11;

    // VERWUNDBAR: Schlüssel bleibt im Register über Zustandsübergange hinweg
    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            current_state <= ACTIVE;
            key_register <= 128'h0;
        end
        else begin
            case (current_state)
                ACTIVE: begin
                    // Schlüssel im aktiven Zustand laden
                    key_register <= encryption_key;

                    if (power_request == SLEEP) begin
                        // VERWUNDBAR: Übergang in Schlafmodus ohne Schlüssel zu loschen
                        current_state <= SLEEP;
                    end
                    else if (power_request == DEBUG) begin
                        // VERWUNDBAR: Übergang in Debug-Modus ohne Schlüssel zu loschen
                        current_state <= DEBUG;
                        // Schlüssel ist im Debug-Zustand noch zuganglich!
                    end
                end

                SLEEP: begin
                    // VERWUNDBAR: Schlüssel noch im Schlafzustand vorhanden
                    // Angreifer kann Speicher untersuchen während Gerat schlaft

                    if (power_request == ACTIVE) begin
                        current_state <= ACTIVE;
                    end
                end

                DEBUG: begin
                    // VERWUNDBAR: Vollständiger Schlüssel im Debug-Zustand sichtbar
                    // Debug-Schnittstelle kann key_register lesen

                    if (power_request == ACTIVE) begin
                        current_state <= ACTIVE;
                    end
                end
            endcase
        end
    end

endmodule

// VERWUNDBAR: Debug-Modus legt sensible Informationen offen
module vulnerable_debug_access (
    input wire clk,
    input wire reset_n,
    input wire debug_enable,
    input wire [7:0] debug_addr,
    output reg [31:0] debug_data,
    // Interner sensibler Zustand
    input wire [255:0] private_key,
    input wire [127:0] session_key,
    input wire [63:0] user_credentials
);

    // VERWUNDBAR: Gesamter interner Zustand im Debug-Modus zuganglich
    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            debug_data <= 32'h0;
        end
        else if (debug_enable) begin
            // VERWUNDBAR: Kein Loschen sensibler Daten vor Debug
            case (debug_addr)
                8'h00: debug_data <= private_key[31:0];
                8'h01: debug_data <= private_key[63:32];
                8'h02: debug_data <= private_key[95:64];
                // ... vollständiger privater Schlüssel zuganglich
                8'h10: debug_data <= session_key[31:0];
                8'h14: debug_data <= user_credentials[31:0];
            endcase
        end
    end

endmodule
// VERWUNDBAR: Software-Zustandsübergang ohne Loschen

#include <stdint.h>

typedef struct {
    uint8_t aes_key[32];
    uint8_t private_key[256];
    uint8_t user_password[64];
    uint8_t session_token[32];
} sensitive_data_t;

static sensitive_data_t secrets;

// VERWUNDBAR: Schlafmodus ohne Loschen von Geheimnissen
void vulnerable_enter_sleep(void) {
    // Zustand für Wiederaufnahme speichern
    save_cpu_context();

    // VERWUNDBAR: Geheimnisse bleiben im Speicher während Schlafmodus
    // RAM kann für Angreifer zuganglich sein

    // Schlafmodus betreten
    enter_low_power_mode();

    // Beim Aufwachen sind Geheimnisse noch vorhanden
}

// VERWUNDBAR: Debug-Modus ohne Loschen von Geheimnissen
void vulnerable_enter_debug(void) {
    // VERWUNDBAR: Kein Loschen vor Debug

    // Debug-Schnittstelle aktivieren
    enable_jtag();
    enable_debug_uart();

    // Debugger kann jetzt auf gesamten Speicher einschließlich Geheimnissen zugreifen!
}

// VERWUNDBAR: TPM-Spezifikationsverletzung
void vulnerable_tpm_power_transition(void) {
    // VERWUNDBAR: Erforderliche Flags gemäß TPM-Spezifikation nicht gesetzt
    // Fehlgeschlagene Autorisierungsversuche werden nach Stromverlust nicht aufgezeichnet

    // Niedrigenergiemodus betreten
    tpm_enter_idle();

    // Stromverlust tritt auf...

    // Bei Wiederaufnahme wird der Autorisierungsfehlzahler zurückgesetzt
    // Angreifer erhält unbegrenzte Passwortversuche!
}

Sichere Lösung

// SICHER: Zustandsübergang mit Loschen sensibler Daten

module secure_power_controller (
    input wire clk,
    input wire reset_n,
    input wire [1:0] power_request,
    output reg [1:0] current_state,
    input wire [127:0] encryption_key,
    output reg [127:0] key_register,
    output reg key_valid,
    output reg transition_complete
);

    // Energiezustände
    parameter ACTIVE = 2'b00;
    parameter IDLE = 2'b01;
    parameter SLEEP = 2'b10;
    parameter DEBUG = 2'b11;

    // Zustandsübergangsphasen
    reg [1:0] transition_phase;
    parameter PHASE_IDLE = 2'b00;
    parameter PHASE_CLEARING = 2'b01;
    parameter PHASE_TRANSITION = 2'b10;
    parameter PHASE_COMPLETE = 2'b11;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            current_state <= ACTIVE;
            key_register <= 128'h0;
            key_valid <= 1'b0;
            transition_phase <= PHASE_IDLE;
            transition_complete <= 1'b0;
        end
        else begin
            case (current_state)
                ACTIVE: begin
                    transition_complete <= 1'b0;

                    // Schlüssel im aktiven Zustand laden
                    key_register <= encryption_key;
                    key_valid <= 1'b1;

                    if (power_request == SLEEP || power_request == DEBUG) begin
                        // SICHER: Loschphase vor Übergang betreten
                        transition_phase <= PHASE_CLEARING;
                    end
                end
            endcase

            // SICHER: Loschphase
            if (transition_phase == PHASE_CLEARING) begin
                // Alle sensiblen Daten loschen
                key_register <= 128'h0;
                key_valid <= 1'b0;
                transition_phase <= PHASE_TRANSITION;
            end

            // Übergang nach abgeschlossenem Loschen
            if (transition_phase == PHASE_TRANSITION) begin
                current_state <= power_request;
                transition_phase <= PHASE_COMPLETE;
                transition_complete <= 1'b1;
            end

            if (transition_phase == PHASE_COMPLETE) begin
                transition_phase <= PHASE_IDLE;
            end
        end
    end

endmodule

// SICHER: Debug-Modus mit Schutz sensibler Daten
module secure_debug_access (
    input wire clk,
    input wire reset_n,
    input wire debug_request,
    input wire debug_authenticated,
    input wire [7:0] debug_addr,
    output reg [31:0] debug_data,
    output reg debug_enabled,
    // Interner sensibler Zustand
    input wire [255:0] private_key,
    input wire [127:0] session_key,
    input wire [63:0] user_credentials
);

    // SICHER: Geloschte Kopien für Debug-Zugriff
    reg [255:0] cleared_private_key;
    reg [127:0] cleared_session_key;
    reg [63:0] cleared_credentials;
    reg sensitive_cleared;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            debug_data <= 32'h0;
            debug_enabled <= 1'b0;
            sensitive_cleared <= 1'b0;
            cleared_private_key <= 256'h0;
            cleared_session_key <= 128'h0;
            cleared_credentials <= 64'h0;
        end
        else begin
            if (debug_request && debug_authenticated) begin
                // SICHER: Sensible Daten VOR Aktivierung des Debug loschen
                if (!sensitive_cleared) begin
                    cleared_private_key <= 256'h0;
                    cleared_session_key <= 128'h0;
                    cleared_credentials <= 64'h0;
                    sensitive_cleared <= 1'b1;
                end
                else begin
                    debug_enabled <= 1'b1;
                end
            end

            if (debug_enabled) begin
                case (debug_addr)
                    // SICHER: Nur geloschte/bereinigte Daten bereitstellen
                    8'h00: debug_data <= 32'hDEADBEEF;  // Indikator
                    8'h10: debug_data <= 32'hDEADBEEF;  // Keine echten Daten
                    default: debug_data <= 32'h0;
                endcase
            end

            // Debug-Modus verlassen
            if (!debug_request) begin
                debug_enabled <= 1'b0;
                sensitive_cleared <= 1'b0;
            end
        end
    end

endmodule

// SICHER: Energiezustandsmaschine mit obligatorischem Loschen
module secure_power_fsm (
    input wire clk,
    input wire reset_n,
    input wire [1:0] requested_state,
    input wire transition_request,
    output reg [1:0] current_state,
    output reg clearing_in_progress,
    output reg transition_complete,
    // Schnittstelle für sensible Daten
    output reg clear_keys,
    output reg clear_session,
    output reg clear_cache,
    input wire keys_cleared,
    input wire session_cleared,
    input wire cache_cleared
);

    parameter ACTIVE = 2'b00;
    parameter SLEEP = 2'b01;
    parameter HIBERNATE = 2'b10;
    parameter DEBUG = 2'b11;

    reg [2:0] fsm_state;
    parameter FSM_IDLE = 3'd0;
    parameter FSM_START_CLEAR = 3'd1;
    parameter FSM_WAIT_CLEAR = 3'd2;
    parameter FSM_VERIFY_CLEAR = 3'd3;
    parameter FSM_TRANSITION = 3'd4;
    parameter FSM_COMPLETE = 3'd5;

    reg [1:0] pending_state;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            current_state <= ACTIVE;
            fsm_state <= FSM_IDLE;
            clearing_in_progress <= 1'b0;
            transition_complete <= 1'b0;
            clear_keys <= 1'b0;
            clear_session <= 1'b0;
            clear_cache <= 1'b0;
        end
        else begin
            case (fsm_state)
                FSM_IDLE: begin
                    transition_complete <= 1'b0;
                    if (transition_request && requested_state != current_state) begin
                        pending_state <= requested_state;
                        fsm_state <= FSM_START_CLEAR;
                    end
                end

                FSM_START_CLEAR: begin
                    // SICHER: Loschen aller sensiblen Daten einleiten
                    clearing_in_progress <= 1'b1;
                    clear_keys <= 1'b1;
                    clear_session <= 1'b1;
                    clear_cache <= 1'b1;
                    fsm_state <= FSM_WAIT_CLEAR;
                end

                FSM_WAIT_CLEAR: begin
                    // SICHER: Auf Abschluss aller Loschvorgange warten
                    if (keys_cleared && session_cleared && cache_cleared) begin
                        clear_keys <= 1'b0;
                        clear_session <= 1'b0;
                        clear_cache <= 1'b0;
                        fsm_state <= FSM_VERIFY_CLEAR;
                    end
                end

                FSM_VERIFY_CLEAR: begin
                    // SICHER: Verifizieren dass Loschen erfolgreich war
                    // Zusätzliche Verifizierung könnte hier hinzugefugt werden
                    fsm_state <= FSM_TRANSITION;
                end

                FSM_TRANSITION: begin
                    // SICHER: Nur nach verifiziertem Loschen ubergehen
                    current_state <= pending_state;
                    clearing_in_progress <= 1'b0;
                    fsm_state <= FSM_COMPLETE;
                end

                FSM_COMPLETE: begin
                    transition_complete <= 1'b1;
                    fsm_state <= FSM_IDLE;
                end
            endcase
        end
    end

endmodule
// SICHER: Software-Zustandsübergang mit ordnungsgemäßem Loschen

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

typedef struct {
    uint8_t aes_key[32];
    uint8_t private_key[256];
    uint8_t user_password[64];
    uint8_t session_token[32];
} sensitive_data_t;

static sensitive_data_t secrets;

// SICHER: Sicheres Speicherloschen das nicht wegoptimiert wird
static void secure_clear(volatile void* ptr, size_t size) {
    volatile uint8_t* p = (volatile uint8_t*)ptr;
    while (size--) {
        *p++ = 0;
    }
    __asm__ volatile("" ::: "memory");
}

// SICHER: Schlafmodus mit ordnungsgemäßem Loschen
void secure_enter_sleep(void) {
    // SICHER: Sensible Daten vor Schlafmodus loschen
    secure_clear(&secrets.aes_key, sizeof(secrets.aes_key));
    secure_clear(&secrets.private_key, sizeof(secrets.private_key));
    secure_clear(&secrets.session_token, sizeof(secrets.session_token));
    // Hinweis: Benutzerpasswort behalten falls für Wiederaufnahme-Authentifizierung benötigt

    // SICHER: Hardware-Schlüsselregister loschen
    clear_hardware_key_registers();

    // SICHER: Caches loschen
    flush_and_invalidate_cache();

    // Minimalen Zustand für Wiederaufnahme speichern
    save_cpu_context();

    // Jetzt sicher in Schlafmodus zu wechseln
    enter_low_power_mode();
}

// SICHER: Debug-Modus mit Schutz sensibler Daten
void secure_enter_debug(void) {
    // SICHER: ALLE sensiblen Daten vor Aktivierung des Debug loschen
    secure_clear(&secrets, sizeof(secrets));

    // SICHER: Hardware-Sicherheitszustand loschen
    clear_hardware_key_registers();
    clear_secure_memory_regions();
    zeroize_crypto_state();

    // SICHER: Loschen verifizieren
    if (!verify_sensitive_data_cleared()) {
        log_error("Loschen sensibler Daten fehlgeschlagen");
        secure_halt();
        return;
    }

    // Jetzt sicher Debug zu aktivieren
    enable_jtag();
    enable_debug_uart();
}

// SICHER: TPM-konformer Energieübergang
void secure_tpm_power_transition(void) {
    // SICHER: Erforderliche Flags gemäß TPM-Spezifikation setzen
    tpm_set_state_save_flag();

    // SICHER: Autorisierungsfehlzahler speichern
    save_auth_failure_counter();

    // Niedrigenergiemodus betreten
    tpm_enter_idle();

    // Bei Wiederaufnahme wird Zahler wiederhergestellt
    // Brute-Force-Angriffe bleiben begrenzt
}

// SICHER: Wiederaufnahme aus Schlafmodus mit Verifizierung
void secure_resume_from_sleep(void) {
    // Verifizieren dass wir im erwarteten Zustand sind
    if (!verify_sleep_state()) {
        secure_halt();
        return;
    }

    // SICHER: Verifizieren dass sensible Daten geloscht wurden
    if (!verify_secrets_zero(&secrets.aes_key, sizeof(secrets.aes_key))) {
        log_error("AES-Schlüssel nicht während Schlafmodus geloscht");
        secure_halt();
        return;
    }

    // CPU-Kontext wiederherstellen
    restore_cpu_context();

    // Erneut authentifizieren vor Wiederherstellung von Geheimnissen
    if (!authenticate_user()) {
        secure_halt();
        return;
    }

    // Jetzt sicher Geheimnisse aus sicherem Speicher neu zu laden
    reload_secrets_from_secure_storage();
}

CVE-Beispiele

  • CVE-2020-12926: Produktsoftware setzte erforderliche Flags gemäß TPM-Spezifikationen nicht, was verhinderte, dass fehlgeschlagene Autorisierungsversuche nach Stromverlust aufgezeichnet wurden, wodurch Brute-Force-Angriffe ermöglicht wurden.

Verwandte CWEs

  • CWE-226: Sensible Informationen in Ressource vor Wiederverwendung nicht entfernt (ubergeordnet)
  • CWE-200: Offenlegung sensibler Informationen an unbefugten Akteur (verwandt)
  • CWE-1207: Debug- und Testprobleme (Kategorie)
  • CWE-1258: Offenlegung sensibler Systeminformationen durch nicht geloschte Debug-Informationen (verwandt)

Referenzen

  1. MITRE Corporation. "CWE-1272: Sensitive Information Uncleared Before Debug/Power State Transition." https://cwe.mitre.org/data/definitions/1272.html
  2. TCG. "TPM 2.0 Library Specification"
  3. ARM. "TrustZone Power Management"