Sensible nichtflüchtige Informationen nicht während Debug geschützt
Beschreibung
Sensible nichtflüchtige Informationen nicht während Debug geschützt tritt auf, wenn der Zugriff auf sicherheitsrelevante Informationen, die in Fuses gespeichert sind, während Debug-Operationen nicht eingeschränkt wird. Sicherheitsrelevante Werte wie Root-Schlüssel, Verschlüsselungsschlüssel, Fertigungsdaten und OEM-Informationen werden in Fuses programmiert. Beim Einschalten des Chips werden diese Werte aus den Fuses gelesen und in temporären Speicherorten wie Registern und lokalem Speicher abgelegt. Während sie normalerweise durch Zugriffskontrollen geschützt sind, können Debug-Operationen diese Schutzmechanismen umgehen, wenn sie nicht ordnungsgemäß eingeschränkt werden.
Risiko
Ungeschützter Debug-Zugriff auf Fuse-Daten hat schwerwiegende Sicherheitsauswirkungen. Root-Schlüssel können während des Debuggens extrahiert werden. Verschlüsselungsschlüssel können über Debug-Schnittstellen offengelegt werden. Fertigungsgeheimnisse können preisgegeben werden. OEM-spezifische Daten können kompromittiert werden. Secure-Boot-Schlüssel können ausgelesen werden. Geräteidentitäts-Anmeldeinformationen können gestohlen werden. Kryptographisches Material kann das Klonen von Geräten ermöglichen. Vertrauensanker können kompromittiert werden.
Lösung
Deaktivieren Sie den Zugriff auf sicherheitsrelevante Informationen, die in Fuses gespeichert sind, sowohl direkt als auch über temporäre Speicherorte, wenn der Debug-Modus aktiv ist. Implementieren Sie eine Debug-Authentifizierung, bevor Zugriff gewährt wird. Verwenden Sie Hardware-Gates, um das Lesen sensibler Register im Debug zu blockieren. Löschen Sie sensible Register beim Eintritt in den Debug-Modus. Überprüfen Sie den Debug-Schutz durch Sicherheitstests. Dokumentieren Sie, welche Assets während des Debuggens geschützt sind.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Umfang: Vertraulichkeit Anwendungsdaten lesen - Debug-Operationen können sicherheitsrelevante Informationen aus Fuses und deren temporären Speicherorten offenlegen. |
| Zugriffskontrolle | Umfang: Zugriffskontrolle Schutzmechanismus umgehen - Der Debug-Modus kann normale Zugriffskontrollen umgehen, die sensible Fuse-Daten schützen. |
Beispielcode und Lösung
Verwundbarer Code
// VERWUNDBAR: Debug-Modus legt Verschlüsselungsschlüssel offen
module vulnerable_aes_key_register (
input wire clk,
input wire reset_n,
input wire [127:0] fuse_key, // Schlüssel aus Fuses
input wire fuse_valid,
input wire debug_mode,
input wire [31:0] debug_addr,
input wire debug_read,
output reg [127:0] key_register,
output reg [31:0] debug_data
);
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
key_register <= 128'h0;
end
else if (fuse_valid) begin
// Schlüssel aus Fuses beim Einschalten laden
key_register <= fuse_key;
end
end
// VERWUNDBAR: Debug kann Schlüsselregister lesen!
always @(posedge clk) begin
if (debug_read) begin
case (debug_addr)
32'h0000: debug_data <= key_register[31:0]; // Schlüssel offengelegt!
32'h0004: debug_data <= key_register[63:32]; // Schlüssel offengelegt!
32'h0008: debug_data <= key_register[95:64]; // Schlüssel offengelegt!
32'h000C: debug_data <= key_register[127:96]; // Schlüssel offengelegt!
default: debug_data <= 32'h0;
endcase
end
end
// Angreifer im Debug-Modus kann den vollständigen Verschlüsselungsschlüssel lesen
endmodule
// VERWUNDBAR: Fuse-Werte über Debug-Schnittstelle lesbar
module vulnerable_fuse_controller (
input wire clk,
input wire reset_n,
input wire debug_mode,
input wire [7:0] debug_fuse_addr,
input wire debug_fuse_read,
output reg [31:0] debug_fuse_data,
// Fuse-Array
input wire [31:0] fuse_array [0:255]
);
// VERWUNDBAR: Alle Fuses im Debug-Modus lesbar
always @(posedge clk) begin
if (debug_mode && debug_fuse_read) begin
// Jede Fuse kann gelesen werden - einschließlich Geheimnisse!
debug_fuse_data <= fuse_array[debug_fuse_addr];
end
end
// Angreifer kann lesen:
// - Root-Schlüssel
// - Geräte-ID
// - Fertigungsdaten
// - Sicherheitskonfiguration
// - OEM-Geheimnisse
endmodule
// VERWUNDBAR: Temporärer Schlüsselspeicher offengelegt
module vulnerable_boot_key_loader (
input wire clk,
input wire reset_n,
input wire [255:0] boot_key_fuses,
input wire boot_start,
input wire debug_active,
input wire [31:0] mem_addr,
input wire mem_read,
output reg [31:0] mem_data
);
// Temporärer Speicher für Boot-Schlüssel
reg [255:0] boot_key_temp;
reg key_loaded;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
boot_key_temp <= 256'h0;
key_loaded <= 1'b0;
end
else if (boot_start && !key_loaded) begin
// Boot-Schlüssel aus Fuses laden
boot_key_temp <= boot_key_fuses;
key_loaded <= 1'b1;
end
end
// VERWUNDBAR: Debug kann temporären Schlüsselspeicher lesen
always @(*) begin
if (debug_active && mem_read) begin
case (mem_addr[7:0])
8'h00: mem_data = boot_key_temp[31:0];
8'h04: mem_data = boot_key_temp[63:32];
8'h08: mem_data = boot_key_temp[95:64];
8'h0C: mem_data = boot_key_temp[127:96];
// ... alle 256 Bits lesbar
default: mem_data = 32'h0;
endcase
end else begin
mem_data = 32'h0;
end
end
endmodule
// VERWUNDBAR: Firmware legt Fuse-Daten während Debug offen
#define FUSE_BASE_ADDR 0x40010000
#define DEBUG_PORT_ADDR 0x40020000
// VERWUNDBAR: Debug-Befehl liest beliebige Fuse
void debug_read_fuse_command(uint8_t fuse_index) {
uint32_t fuse_value = *(volatile uint32_t*)(FUSE_BASE_ADDR + fuse_index * 4);
// An Debug-Port senden - legt Geheimnisse offen!
*(volatile uint32_t*)DEBUG_PORT_ADDR = fuse_value;
}
// VERWUNDBAR: Schlüssel in Speicher geladen, im Debug lesbar
uint8_t encryption_key[32];
void load_encryption_key(void) {
// Schlüssel aus Fuses in RAM lesen
for (int i = 0; i < 32; i++) {
encryption_key[i] = read_fuse(KEY_FUSE_START + i);
}
// Schlüssel jetzt im RAM - Debug kann Speicher auslesen!
}
Sichere Lösung
// SICHER: Debug-Modus blockiert Zugriff auf Verschlüsselungsschlüssel
module secure_aes_key_register (
input wire clk,
input wire reset_n,
input wire [127:0] fuse_key,
input wire fuse_valid,
input wire debug_mode,
input wire debug_authenticated, // Debug erfordert Authentifizierung
input wire [31:0] debug_addr,
input wire debug_read,
output reg [127:0] key_register,
output reg [31:0] debug_data,
output reg debug_access_violation
);
// Schattenkopie für Normalbetrieb
reg [127:0] key_shadow;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
key_register <= 128'h0;
key_shadow <= 128'h0;
end
else if (fuse_valid && !debug_mode) begin
// Schlüssel nur laden, wenn NICHT im Debug-Modus
key_register <= fuse_key;
key_shadow <= fuse_key;
end
else if (debug_mode && !debug_authenticated) begin
// SICHER: Schlüssel bei unauthentifiziertem Debug löschen
key_shadow <= 128'h0;
end
end
// SICHER: Schlüssel NICHT im Debug-Modus lesbar
always @(posedge clk) begin
debug_access_violation <= 1'b0;
if (debug_read) begin
if (debug_addr >= 32'h0000 && debug_addr <= 32'h000F) begin
// SICHER: Schlüsseladressen geben im Debug Nullen zurück
if (debug_mode) begin
debug_data <= 32'h0;
debug_access_violation <= 1'b1; // Versuch protokollieren
end else begin
// Normalmodus ebenfalls vor externem Debug-Lesen geschützt
debug_data <= 32'h0;
end
end else begin
// Andere Register können lesbar sein
debug_data <= get_non_sensitive_register(debug_addr);
end
end
end
endmodule
// SICHER: Fuse-Controller mit Debug-Schutz
module secure_fuse_controller (
input wire clk,
input wire reset_n,
input wire debug_mode,
input wire debug_authenticated,
input wire [7:0] debug_fuse_addr,
input wire debug_fuse_read,
output reg [31:0] debug_fuse_data,
output reg access_denied,
input wire [31:0] fuse_array [0:255]
);
// Sensible Fuse-Bereiche definieren
parameter KEY_FUSE_START = 8'h00;
parameter KEY_FUSE_END = 8'h1F;
parameter OEM_FUSE_START = 8'h20;
parameter OEM_FUSE_END = 8'h3F;
function is_sensitive_fuse;
input [7:0] addr;
begin
is_sensitive_fuse = (addr >= KEY_FUSE_START && addr <= KEY_FUSE_END) ||
(addr >= OEM_FUSE_START && addr <= OEM_FUSE_END);
end
endfunction
always @(posedge clk) begin
access_denied <= 1'b0;
if (debug_mode && debug_fuse_read) begin
if (is_sensitive_fuse(debug_fuse_addr)) begin
// SICHER: Sensible Fuses im Debug nicht lesbar
debug_fuse_data <= 32'h0;
access_denied <= 1'b1;
end
else if (debug_authenticated) begin
// Nicht-sensible Fuses mit Authentifizierung lesbar
debug_fuse_data <= fuse_array[debug_fuse_addr];
end
else begin
debug_fuse_data <= 32'h0;
access_denied <= 1'b1;
end
end
else begin
debug_fuse_data <= 32'h0;
end
end
endmodule
// SICHER: Boot-Schlüssel wird beim Eintritt in Debug gelöscht
module secure_boot_key_loader (
input wire clk,
input wire reset_n,
input wire [255:0] boot_key_fuses,
input wire boot_start,
input wire debug_active,
input wire debug_entry, // Steigende Flanke beim Eintritt in Debug
input wire [31:0] mem_addr,
input wire mem_read,
output reg [31:0] mem_data,
output reg key_valid
);
reg [255:0] boot_key_temp;
reg key_loaded;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
boot_key_temp <= 256'h0;
key_loaded <= 1'b0;
key_valid <= 1'b0;
end
else if (debug_entry) begin
// SICHER: Schlüssel beim Eintritt in Debug-Modus löschen
boot_key_temp <= 256'h0;
key_valid <= 1'b0;
end
else if (boot_start && !key_loaded && !debug_active) begin
// Schlüssel nur laden, wenn nicht im Debug
boot_key_temp <= boot_key_fuses;
key_loaded <= 1'b1;
key_valid <= 1'b1;
end
end
// SICHER: Debug kann Schlüsseladressen nicht lesen
always @(*) begin
if (mem_read) begin
if (mem_addr[31:8] == 24'h000000) begin
// Schlüsseladressbereich - immer 0 zurückgeben
mem_data = 32'h0;
end else begin
// Andere Adressen können lesbar sein
mem_data = normal_memory_read(mem_addr);
end
end else begin
mem_data = 32'h0;
end
end
endmodule
// SICHER: Firmware schützt Fuse-Daten während Debug
#define FUSE_BASE_ADDR 0x40010000
#define DEBUG_PORT_ADDR 0x40020000
// Sensible Fuse-Bereiche
#define KEY_FUSE_START 0
#define KEY_FUSE_END 31
#define OEM_FUSE_START 32
#define OEM_FUSE_END 63
bool is_sensitive_fuse(uint8_t index) {
return (index >= KEY_FUSE_START && index <= KEY_FUSE_END) ||
(index >= OEM_FUSE_START && index <= OEM_FUSE_END);
}
// SICHER: Debug-Befehl blockiert sensible Fuses
void debug_read_fuse_command(uint8_t fuse_index) {
if (is_sensitive_fuse(fuse_index)) {
// Nullen für sensible Fuses zurückgeben
*(volatile uint32_t*)DEBUG_PORT_ADDR = 0;
log_security_event("Debug-Versuch, sensible Fuse %d zu lesen", fuse_index);
return;
}
// Nicht-sensible Fuses können lesbar sein
if (is_debug_authenticated()) {
uint32_t fuse_value = *(volatile uint32_t*)(FUSE_BASE_ADDR + fuse_index * 4);
*(volatile uint32_t*)DEBUG_PORT_ADDR = fuse_value;
} else {
*(volatile uint32_t*)DEBUG_PORT_ADDR = 0;
}
}
// SICHER: Schlüssel im sicheren Speicher, beim Debug-Eintritt gelöscht
static uint8_t encryption_key[32] __attribute__((section(".secure_ram")));
void load_encryption_key(void) {
if (is_debug_mode()) {
// Schlüssel nicht im Debug-Modus laden
return;
}
// Schlüssel aus Fuses in sicheren RAM lesen
for (int i = 0; i < 32; i++) {
encryption_key[i] = read_fuse(KEY_FUSE_START + i);
}
}
void debug_entry_handler(void) {
// SICHER: Alle sensiblen Daten beim Eintritt in Debug löschen
secure_memzero(encryption_key, sizeof(encryption_key));
// Alle anderen sensiblen temporären Speicher löschen
clear_all_key_material();
}
CVE-Beispiele
Schwachstellen beim Debug-Zugriff auf Fuse-Daten wurden in verschiedenen SoC-Designs gefunden, bei denen Verschlüsselungsschlüssel und andere Geheimnisse über Debug-Schnittstellen extrahiert werden könnten.
Verwandte CWEs
- CWE-1263: Unsachgemäße physische Zugriffskontrolle (übergeordnet)
- CWE-1207: Debug- und Testprobleme (Kategoriemitglied)
- CWE-1244: Internes Asset unsicherem Debug-Zugriffslevel ausgesetzt (verwandt)
Referenzen
- MITRE Corporation. "CWE-1243: Sensitive Non-Volatile Information Not Protected During Debug." https://cwe.mitre.org/data/definitions/1243.html
- REF-1366: HACK@DAC'21 OpenPiton SoC AES Wrapper Code
- REF-1367: Fixed Version of AES Wrapper Implementation