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
| Auswirkung | Details |
|---|---|
| Zugriffskontrolle | Bereich: Zugriffskontrolle Angreifer können durch Modifikation des Root of Trust beliebigen Zugriff erlangen. |
| Integrität | Bereich: Integrität Firmware- und Software-Integrität kann nicht gewährleistet werden. |
| Authentifizierung | Bereich: 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
-
MITRE Corporation. "CWE-1326: Missing Immutable Root of Trust in Hardware." https://cwe.mitre.org/data/definitions/1326.html
-
NIST. "Hardware Security Guidelines." https://csrc.nist.gov/
-
TCG. "Trusted Platform Module Specification." https://trustedcomputinggroup.org/