Sensitive Non-Volatile Information Not Protected During Debug
Description
Sensitive Non-Volatile Information Not Protected During Debug occurs when access to security-sensitive information stored in fuses is not limited during debug operations. Security-sensitive values like root keys, encryption keys, manufacturing data, and OEM information are programmed into fuses. During chip power-on, these values are read from fuses and stored in temporary locations such as registers and local memory. While normally protected with access controls, debug operations can bypass these protections if not properly restricted.
Risk
Unprotected debug access to fuse data has severe security implications. Root keys may be extracted during debug. Encryption keys may be exposed through debug interfaces. Manufacturing secrets may be disclosed. OEM-specific data may be compromised. Secure boot keys may be readable. Device identity credentials may be stolen. Cryptographic material may enable device cloning. Trust anchors may be compromised.
Solution
Disable access to security-sensitive information stored in fuses directly and also reflected from temporary storage locations when in debug mode. Implement debug authentication before allowing any access. Use hardware gates to block sensitive register reads in debug. Clear sensitive registers when entering debug mode. Verify debug protection through security testing. Document which assets are protected during debug.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Read Application Data - Debug operations can expose security-sensitive information from fuses and their temporary storage locations. |
| Access Control | Scope: Access Control Bypass Protection Mechanism - Debug mode may bypass normal access controls protecting sensitive fuse data. |
Example Code
Vulnerable Code
// Vulnerable: Debug mode exposes encryption key
module vulnerable_aes_key_register (
input wire clk,
input wire reset_n,
input wire [127:0] fuse_key, // Key from 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
// Load key from fuses at power-on
key_register <= fuse_key;
end
end
// VULNERABLE: Debug can read key register!
always @(posedge clk) begin
if (debug_read) begin
case (debug_addr)
32'h0000: debug_data <= key_register[31:0]; // Key exposed!
32'h0004: debug_data <= key_register[63:32]; // Key exposed!
32'h0008: debug_data <= key_register[95:64]; // Key exposed!
32'h000C: debug_data <= key_register[127:96]; // Key exposed!
default: debug_data <= 32'h0;
endcase
end
end
// Attacker in debug mode can read full encryption key
endmodule
// Vulnerable: Fuse values readable through debug interface
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]
);
// VULNERABLE: All fuses readable in debug mode
always @(posedge clk) begin
if (debug_mode && debug_fuse_read) begin
// Any fuse can be read - including secrets!
debug_fuse_data <= fuse_array[debug_fuse_addr];
end
end
// Attacker can read:
// - Root keys
// - Device ID
// - Manufacturing data
// - Security configuration
// - OEM secrets
endmodule
// Vulnerable: Temporary key storage exposed
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
);
// Temporary storage for boot key
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
// Load boot key from fuses
boot_key_temp <= boot_key_fuses;
key_loaded <= 1'b1;
end
end
// VULNERABLE: Debug can read temporary key storage
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];
// ... all 256 bits readable
default: mem_data = 32'h0;
endcase
end else begin
mem_data = 32'h0;
end
end
endmodule
// Vulnerable: Firmware exposes fuse data during debug
#define FUSE_BASE_ADDR 0x40010000
#define DEBUG_PORT_ADDR 0x40020000
// VULNERABLE: Debug command reads any fuse
void debug_read_fuse_command(uint8_t fuse_index) {
uint32_t fuse_value = *(volatile uint32_t*)(FUSE_BASE_ADDR + fuse_index * 4);
// Send to debug port - exposes secrets!
*(volatile uint32_t*)DEBUG_PORT_ADDR = fuse_value;
}
// VULNERABLE: Key loaded to memory, readable in debug
uint8_t encryption_key[32];
void load_encryption_key(void) {
// Read key from fuses into RAM
for (int i = 0; i < 32; i++) {
encryption_key[i] = read_fuse(KEY_FUSE_START + i);
}
// Key now in RAM - debug can dump memory!
}
Fixed Code
// Fixed: Debug mode blocks access to encryption key
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 requires authentication
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
);
// Shadow copy for normal operation
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
// Only load key when NOT in debug mode
key_register <= fuse_key;
key_shadow <= fuse_key;
end
else if (debug_mode && !debug_authenticated) begin
// FIXED: Clear key when entering unauthenticated debug
key_shadow <= 128'h0;
end
end
// FIXED: Key NOT readable in debug mode
always @(posedge clk) begin
debug_access_violation <= 1'b0;
if (debug_read) begin
if (debug_addr >= 32'h0000 && debug_addr <= 32'h000F) begin
// FIXED: Key addresses return zeros in debug
if (debug_mode) begin
debug_data <= 32'h0;
debug_access_violation <= 1'b1; // Log attempt
end else begin
// Normal mode still blocked from external debug read
debug_data <= 32'h0;
end
end else begin
// Other registers may be readable
debug_data <= get_non_sensitive_register(debug_addr);
end
end
end
endmodule
// Fixed: Fuse controller with debug protection
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]
);
// Define sensitive fuse ranges
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
// FIXED: Sensitive fuses not readable in debug
debug_fuse_data <= 32'h0;
access_denied <= 1'b1;
end
else if (debug_authenticated) begin
// Non-sensitive fuses readable with authentication
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
// Fixed: Boot key cleared when entering debug
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, // Rising edge when entering 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
// FIXED: Clear key when entering debug mode
boot_key_temp <= 256'h0;
key_valid <= 1'b0;
end
else if (boot_start && !key_loaded && !debug_active) begin
// Only load key when not in debug
boot_key_temp <= boot_key_fuses;
key_loaded <= 1'b1;
key_valid <= 1'b1;
end
end
// FIXED: Debug cannot read key addresses
always @(*) begin
if (mem_read) begin
if (mem_addr[31:8] == 24'h000000) begin
// Key address range - always return 0
mem_data = 32'h0;
end else begin
// Other addresses may be readable
mem_data = normal_memory_read(mem_addr);
end
end else begin
mem_data = 32'h0;
end
end
endmodule
// Fixed: Firmware protects fuse data during debug
#define FUSE_BASE_ADDR 0x40010000
#define DEBUG_PORT_ADDR 0x40020000
// Sensitive fuse ranges
#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);
}
// FIXED: Debug command blocks sensitive fuses
void debug_read_fuse_command(uint8_t fuse_index) {
if (is_sensitive_fuse(fuse_index)) {
// Return zeros for sensitive fuses
*(volatile uint32_t*)DEBUG_PORT_ADDR = 0;
log_security_event("Debug attempt to read sensitive fuse %d", fuse_index);
return;
}
// Non-sensitive fuses may be readable
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;
}
}
// FIXED: Key in secure memory, cleared on debug entry
static uint8_t encryption_key[32] __attribute__((section(".secure_ram")));
void load_encryption_key(void) {
if (is_debug_mode()) {
// Don't load key in debug mode
return;
}
// Read key from fuses into secure RAM
for (int i = 0; i < 32; i++) {
encryption_key[i] = read_fuse(KEY_FUSE_START + i);
}
}
void debug_entry_handler(void) {
// FIXED: Clear all sensitive data when entering debug
secure_memzero(encryption_key, sizeof(encryption_key));
// Clear any other sensitive temporary storage
clear_all_key_material();
}
CVE Examples
Debug access to fuse data vulnerabilities have been found in various SoC designs where encryption keys and other secrets could be extracted through debug interfaces.
Related CWEs
- CWE-1263: Improper Physical Access Control (parent)
- CWE-1207: Debug and Test Problems (category member)
- CWE-1244: Internal Asset Exposed to Unsafe Debug Access Level (related)
References
- 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