Veränderbare Attestierungs- oder Messdaten

Beschreibung

Veränderbare Attestierungs- oder Messdaten treten auf, wenn Attestierungs- oder Messregister, die in sicheren Boot-Prozessen verwendet werden, von Angreifern modifiziert werden können, wodurch sie die Integritätsmessungen des Boot-Ablaufs fälschen können. Während des sicheren/verifizierten Boots eines SoC berechnen Systeme kryptographische Hashes von Code-Binärdateien und erweitern diese sequenziell. Diese endgültigen Hash-Werte — gespeichert in Registern für spätere Attestierung — können gelesen werden, um Manipulationen zu erkennen. Die Schwachstelle tritt auf, wenn diese Register keinen angemessenen Schutz haben, was es Angreifern ermöglicht, beliebige Hash-Werte zu schreiben und Boot-Integritätsaussagen zu fälschen.

Risiko

Veränderbare Attestierungsdaten haben schwerwiegende Sicherheitsauswirkungen. Boot-Integrität kann vorgetäuscht werden. Messketten können gefälscht werden. Attestierungsberichte werden unzuverlässig. Bösartiger Boot bleibt unerkannt. Vertrauensverifizierung wird umgangen. Remote-Attestierung wird kompromittiert. TPM-ähnliche Garantien gehen verloren. Secure Boot kann überwunden werden.

Lösung

Speichern Sie Messdaten in Registern mit Nur-Lese-Zugriffsschutz. Stellen Sie Unveränderlichkeit gegen direkte oder indirekte Modifikation sicher. Implementieren Sie angemessene Zugriffskontrollen, die Modifikation durch nicht vertrauenswürdige Agenten verhindern. Verwenden Sie Nur-Erweiterungsoperationen für Messungen. Sperren Sie Messregister nach Abschluss des Boots. Überprüfen Sie den Schutz der Messregister in Sicherheitsaudits.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitBereich: Vertraulichkeit

Anwendungsdaten lesen - Falsche Attestierung ermöglicht unbefugten Zugriff.
IntegritätBereich: Integrität

Speicher modifizieren - Messdaten können gefälscht werden.
ZugriffskontrolleBereich: Zugriffskontrolle

Schutzmechanismus umgehen - Attestierungsverifizierung wird umgangen.

Beispielcode und Lösung

Verwundbarer Code

// VERWUNDBAR: Messregister ohne Schreibschutz

module vulnerable_measurement_engine (
    input wire clk,
    input wire reset_n,
    input wire [255:0] hash_input,
    input wire extend_command,
    input wire [7:0] pcr_select,
    input wire [255:0] direct_write_data,
    input wire direct_write_enable,
    input wire [3:0] requester_id,
    output reg [255:0] pcr_read_data,
    output reg measurement_done
);

    // Platform Configuration Registers (PCRs)
    reg [255:0] pcr [0:23];

    // VERWUNDBAR: PCRs können direkt geschrieben werden
    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            // PCRs auf Null initialisieren
            integer i;
            for (i = 0; i < 24; i = i + 1) begin
                pcr[i] <= 256'h0;
            end
            measurement_done <= 1'b0;
        end
        else begin
            measurement_done <= 1'b0;

            if (extend_command) begin
                // Normale Erweiterungsoperation: PCR = Hash(PCR || neue_Daten)
                pcr[pcr_select] <= sha256({pcr[pcr_select], hash_input});
                measurement_done <= 1'b1;
            end

            // VERWUNDBAR: Direktes Schreiben in PCRs erlaubt
            if (direct_write_enable) begin
                // Jeder Anfragende kann beliebige Werte schreiben!
                pcr[pcr_select] <= direct_write_data;

                // Angreifer kann:
                // 1. PCR auf erwarteten "guten" Wert setzen
                // 2. Bösartige Boot-Komponenten verstecken
                // 3. Attestierung mit kompromittiertem System bestehen
            end
        end
    end

    // PCR-Wert lesen
    always @(*) begin
        pcr_read_data = pcr[pcr_select];
    end

endmodule

// VERWUNDBAR: Attestierungsbericht aus veränderbarer Quelle
module vulnerable_attestation (
    input wire clk,
    input wire reset_n,
    input wire generate_report,
    input wire [7:0] pcr_mask,
    output reg [2047:0] attestation_report,
    output reg report_valid
);

    // VERWUNDBAR: Messregister können modifiziert werden
    reg [255:0] measurements [0:7];

    // VERWUNDBAR: Jeder kann Messungen aktualisieren
    input wire [255:0] measurement_update;
    input wire [2:0] measurement_select;
    input wire update_measurement;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            report_valid <= 1'b0;
        end
        else begin
            // VERWUNDBAR: Keine Zugriffskontrolle bei Messungsaktualisierungen
            if (update_measurement) begin
                measurements[measurement_select] <= measurement_update;
            end

            if (generate_report) begin
                // Bericht aus veränderbaren Messungen erstellen
                // Bericht ist nicht vertrauenswürdig!
                attestation_report <= {measurements[0], measurements[1],
                                       measurements[2], measurements[3],
                                       measurements[4], measurements[5],
                                       measurements[6], measurements[7]};
                report_valid <= 1'b1;
            end
        end
    end

endmodule
// VERWUNDBAR: Software mit veränderbarem Messungsspeicher

#include <stdint.h>

// VERWUNDBAR: Messungen in beschreibbarem Speicher gespeichert
static uint8_t pcr_values[24][32];  // In .bss - beschreibbar

// VERWUNDBAR: Direkte PCR-Schreibfunktion
void vulnerable_pcr_write(uint8_t pcr_index, const uint8_t* value) {
    // VERWUNDBAR: Keine Zugriffskontrolle
    // Jeder Code kann beliebige Werte in PCRs schreiben
    if (pcr_index < 24) {
        memcpy(pcr_values[pcr_index], value, 32);
    }
}

// VERWUNDBAR: Erweiterungsfunktion, die umgangen werden kann
void vulnerable_pcr_extend(uint8_t pcr_index, const uint8_t* data, size_t len) {
    if (pcr_index >= 24) return;

    // Normale Erweiterung: neuer_Wert = SHA256(alter_Wert || Daten)
    uint8_t buffer[64];
    memcpy(buffer, pcr_values[pcr_index], 32);
    memcpy(buffer + 32, data, len > 32 ? 32 : len);

    sha256(buffer, 64, pcr_values[pcr_index]);

    // Problem: Angreifer kann vulnerable_pcr_write() direkt aufrufen
    // um PCR auf beliebigen Wert zu setzen und die Erweiterungskette zu umgehen
}

// VERWUNDBAR: Attestierung mit veränderbaren PCRs
bool vulnerable_generate_attestation(uint8_t* report, size_t* report_len) {
    // PCR-Werte zitieren (die möglicherweise manipuliert wurden)
    for (int i = 0; i < 24; i++) {
        memcpy(report + i * 32, pcr_values[i], 32);
    }

    // Mit Attestierungsschlüssel signieren
    sign_report(report, 24 * 32);

    *report_len = 24 * 32 + 64;  // PCRs + Signatur
    return true;

    // Bericht ist signiert, aber PCR-Werte sind nicht vertrauenswürdig
}

Sichere Lösung

// SICHER: Messregister mit Schreibschutz

module secure_measurement_engine (
    input wire clk,
    input wire reset_n,
    input wire [255:0] hash_input,
    input wire extend_command,
    input wire [7:0] pcr_select,
    input wire [3:0] requester_id,
    input wire boot_complete,
    output reg [255:0] pcr_read_data,
    output reg measurement_done,
    output reg access_denied,
    output reg pcrs_locked
);

    // Platform Configuration Registers (PCRs)
    reg [255:0] pcr [0:23];

    // SICHER: PCR-Sperrstatus - einmal gesperrt, nicht mehr änderbar
    reg [23:0] pcr_lock;

    // SICHER: Vertrauenswürdige Anfragende für verschiedene PCRs
    parameter SECURE_BOOT_ROM = 4'd0;
    parameter SECURE_BOOT_LOADER = 4'd1;
    parameter OS_KERNEL = 4'd2;

    // PCR-Zuweisungen
    // PCR 0-3: Boot-ROM-Messungen (nur ROM)
    // PCR 4-7: Bootloader-Messungen (nur Bootloader)
    // PCR 8-15: OS-Messungen (nur Kernel)
    // PCR 16-23: Anwendungsmessungen (verschiedene)

    function automatic is_pcr_writable;
        input [7:0] pcr_idx;
        input [3:0] requester;
        begin
            is_pcr_writable = 1'b0;

            // PCR-Bereich und Anfragenden prüfen
            if (pcr_idx < 4 && requester == SECURE_BOOT_ROM) begin
                is_pcr_writable = 1'b1;
            end
            else if (pcr_idx >= 4 && pcr_idx < 8 && requester == SECURE_BOOT_LOADER) begin
                is_pcr_writable = 1'b1;
            end
            else if (pcr_idx >= 8 && pcr_idx < 16 && requester == OS_KERNEL) begin
                is_pcr_writable = 1'b1;
            end
            // PCR 16-23 haben flexiblere Richtlinien
        end
    endfunction

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            integer i;
            for (i = 0; i < 24; i = i + 1) begin
                pcr[i] <= 256'h0;
            end
            pcr_lock <= 24'h0;
            measurement_done <= 1'b0;
            access_denied <= 1'b0;
            pcrs_locked <= 1'b0;
        end
        else begin
            measurement_done <= 1'b0;
            access_denied <= 1'b0;

            // SICHER: PCRs nach dem Boot sperren
            if (boot_complete) begin
                pcr_lock <= 24'hFFFFFF;  // Alle PCRs sperren
                pcrs_locked <= 1'b1;
            end

            if (extend_command) begin
                // SICHER: Prüfen, ob PCR gesperrt ist
                if (pcr_lock[pcr_select]) begin
                    access_denied <= 1'b1;
                end
                // SICHER: Autorisierung des Anfragenden prüfen
                else if (!is_pcr_writable(pcr_select, requester_id)) begin
                    access_denied <= 1'b1;
                end
                else begin
                    // SICHER: Nur Erweiterungsoperation - kein direktes Schreiben
                    pcr[pcr_select] <= sha256({pcr[pcr_select], hash_input});
                    measurement_done <= 1'b1;
                end
            end

            // SICHER: Keine direkte Schreibschnittstelle
            // PCRs können nur durch Erweiterungsoperation modifiziert werden
        end
    end

    // PCR-Wert lesen (immer erlaubt)
    always @(*) begin
        pcr_read_data = pcr[pcr_select];
    end

endmodule

// SICHER: Sichere Attestierung mit geschützten Messungen
module secure_attestation (
    input wire clk,
    input wire reset_n,
    input wire generate_report,
    input wire [23:0] pcr_mask,
    input wire [255:0] nonce,
    input wire [3:0] requester_id,
    output reg [2047:0] attestation_report,
    output reg report_valid,
    output reg report_signed
);

    // SICHER: Messungen von geschützter PCR-Engine
    wire [255:0] pcr_values [0:23];
    wire pcrs_locked;

    secure_measurement_engine pcr_engine (
        // ... Verbindungen ...
        .pcrs_locked(pcrs_locked)
    );

    // SICHER: Attestierungsschlüssel in Hardware
    wire [255:0] attestation_private_key;  // Aus sicherem Schlüsselspeicher

    // Zustandsautomat für Attestierung
    reg [2:0] attest_state;
    parameter IDLE = 3'd0;
    parameter COLLECT = 3'd1;
    parameter HASH = 3'd2;
    parameter SIGN = 3'd3;
    parameter DONE = 3'd4;

    reg [7:0] pcr_index;
    reg [2047:0] report_buffer;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            report_valid <= 1'b0;
            report_signed <= 1'b0;
            attest_state <= IDLE;
        end
        else begin
            case (attest_state)
                IDLE: begin
                    report_valid <= 1'b0;
                    report_signed <= 1'b0;

                    if (generate_report) begin
                        // SICHER: Bericht nur erstellen, wenn PCRs gesperrt sind
                        if (pcrs_locked) begin
                            attest_state <= COLLECT;
                            pcr_index <= 8'h0;
                            report_buffer <= {nonce, 1792'h0};  // Nonce einschließen
                        end
                    end
                end

                COLLECT: begin
                    // SICHER: PCR-Werte von geschützter Engine sammeln
                    if (pcr_mask[pcr_index]) begin
                        // Diesen PCR in Bericht aufnehmen
                        report_buffer <= {report_buffer, pcr_values[pcr_index]};
                    end

                    pcr_index <= pcr_index + 1;
                    if (pcr_index >= 23) begin
                        attest_state <= HASH;
                    end
                end

                HASH: begin
                    // Bericht zum Signieren hashen
                    attest_state <= SIGN;
                end

                SIGN: begin
                    // SICHER: Mit geschütztem Attestierungsschlüssel signieren
                    // Signatur beweist, dass der Bericht von diesem Gerät stammt
                    attestation_report <= sign_ecdsa(report_buffer,
                                                     attestation_private_key);
                    report_signed <= 1'b1;
                    attest_state <= DONE;
                end

                DONE: begin
                    report_valid <= 1'b1;
                    attest_state <= IDLE;
                end
            endcase
        end
    end

endmodule
// SICHER: Software mit geschütztem Messungsspeicher

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

// SICHER: PCR-Operationen gehen über ein hardware-basiertes TPM-ähnliches Modul
#define TPM_PCR_EXTEND_REG 0x50001000
#define TPM_PCR_READ_REG   0x50001004
#define TPM_PCR_SELECT_REG 0x50001008
#define TPM_STATUS_REG     0x5000100C
#define TPM_PCR_LOCKED_BIT 0x01

// SICHER: PCRs sind in Hardware, Software hat nur Erweiterungsschnittstelle
static bool pcr_extend(uint8_t pcr_index, const uint8_t* data, size_t len) {
    volatile uint32_t* pcr_select = (volatile uint32_t*)TPM_PCR_SELECT_REG;
    volatile uint32_t* status = (volatile uint32_t*)TPM_STATUS_REG;
    volatile uint32_t* extend_reg = (volatile uint32_t*)TPM_PCR_EXTEND_REG;

    if (pcr_index >= 24) {
        return false;
    }

    // Prüfen, ob PCRs gesperrt sind
    if (*status & TPM_PCR_LOCKED_BIT) {
        log_error("PCRs sind gesperrt");
        return false;
    }

    // PCR auswählen
    *pcr_select = pcr_index;

    // SICHER: Nur Erweiterungsoperation verfügbar - kein direktes Schreiben
    // Hardware führt aus: PCR = SHA256(PCR || Daten)
    for (size_t i = 0; i < len; i += 4) {
        uint32_t word;
        memcpy(&word, data + i, 4);
        *extend_reg = word;
    }

    // Auf Abschluss der Operation warten
    while (!(*status & TPM_EXTEND_COMPLETE_BIT)) {
        // Warten
    }

    return true;
}

// SICHER: PCR aus Hardware lesen
static bool pcr_read(uint8_t pcr_index, uint8_t* value) {
    volatile uint32_t* pcr_select = (volatile uint32_t*)TPM_PCR_SELECT_REG;
    volatile uint32_t* read_reg = (volatile uint32_t*)TPM_PCR_READ_REG;

    if (pcr_index >= 24) {
        return false;
    }

    *pcr_select = pcr_index;

    // 32 Bytes (256 Bits) lesen
    for (int i = 0; i < 8; i++) {
        uint32_t word = read_reg[i];
        memcpy(value + i * 4, &word, 4);
    }

    return true;
}

// SICHER: Keine direkte PCR-Schreibfunktion
// void pcr_write(...) - EXISTIERT NICHT

// SICHER: Attestierung mit hardware-geschützten PCRs
bool secure_generate_attestation(const uint8_t* nonce, size_t nonce_len,
                                 uint8_t* report, size_t* report_len) {
    attestation_request_t req;
    attestation_response_t resp;

    // Anfrage mit Nonce erstellen (für Aktualität)
    memcpy(req.nonce, nonce, nonce_len);
    req.pcr_mask = 0x00FFFFFF;  // Alle 24 PCRs

    // SICHER: Attestierung von Hardware-TPM anfordern
    // Hardware liest PCRs und signiert mit geschütztem Schlüssel
    if (!tpm_generate_quote(&req, &resp)) {
        return false;
    }

    // SICHER: Überprüfen, dass Signatur von diesem TPM stammt
    if (!verify_quote_signature(&resp)) {
        log_error("Quote-Signaturverifizierung fehlgeschlagen");
        return false;
    }

    memcpy(report, resp.quote, resp.quote_len);
    *report_len = resp.quote_len;

    return true;
}

// SICHER: PCRs nach dem Boot sperren
void finalize_measurements(void) {
    volatile uint32_t* tpm_ctrl = (volatile uint32_t*)TPM_CONTROL_REG;

    // Alle PCRs sperren - kann ohne Reset nicht entsperrt werden
    *tpm_ctrl |= TPM_LOCK_PCRS;

    // Sperre verifizieren
    volatile uint32_t* status = (volatile uint32_t*)TPM_STATUS_REG;
    if (!(*status & TPM_PCR_LOCKED_BIT)) {
        log_error("PCR-Sperrung fehlgeschlagen");
        secure_halt();
    }
}

CVE-Beispiele

Schwachstellen bei veränderbaren Attestierungen wurden in TPM-ähnlichen Implementierungen gefunden, bei denen PCR-Register direkt geschrieben statt nur erweitert werden könnten, was es Angreifern ermöglichte, Attestierungsberichte zu fälschen.


Verwandte CWEs

  • CWE-284: Unsachgemäße Zugriffskontrolle (übergeordnet)
  • CWE-1196: Sicherheitsfluss-Probleme (Kategorie)
  • CWE-1282: Als unveränderlich angenommene Daten werden in beschreibbarem Speicher gespeichert (verwandt)
  • CAPEC-680: Ausnutzung unsachgemäß kontrollierter Register (Angriffsmuster)

Referenzen

  1. MITRE Corporation. "CWE-1283: Mutable Attestation or Measurement Reporting Data." https://cwe.mitre.org/data/definitions/1283.html
  2. TCG. "TPM 2.0 Library Specification"
  3. Intel. "PCIe Device Measurement Requirements"