Incorrect Chaining or Granularity of Debug Components

Description

Incorrect Chaining or Granularity of Debug Components occurs when a product's debug components contain incorrect chaining or granularity configurations. Debug infrastructure in chips typically includes Test Access Ports (TAPs), scan cells for internal component observation, and hierarchical tracing hubs. Logic errors during design or synthesis can misconfigure how these debug components interconnect, potentially creating unintended access permissions that bypass security controls. For example, implementing a daisy-chained TAP structure when hierarchical authorization was required grants unauthorized access to internal TAPs that should require separate credentials.

Risk

Incorrect debug component chaining has severe implications. Privilege escalation through debug interfaces. Protection mechanism bypass. Unauthorized code execution. Memory modification via debug. Compromised confidentiality. Authentication bypass. Unauthorized access to internal components. Entire debug hierarchy exposed through single access point. Medium likelihood of exploitation.

Solution

Ensure that debug components are properly chained and their granularity is maintained at different authentication levels. Review debug architecture during design phase. Implement hierarchical TAP structures with separate authentication for sensitive components. Test debug access at various authorization levels in both pre-silicon and post-silicon testing. Use formal verification of debug connectivity. Document intended debug access policies and verify implementation matches.

Common Consequences

ImpactDetails
ConfidentialityScope: Confidentiality

Unauthorized access to internal registers and memory.
IntegrityScope: Integrity

Memory modification through improperly exposed debug.
Access ControlScope: Access Control, Authentication

Debug authentication bypassed through incorrect chaining.
AvailabilityScope: Availability

System disruption through unauthorized debug commands.

Example Code

Vulnerable Code

// Vulnerable: Incorrect TAP chaining - daisy chain where hierarchy needed

module vulnerable_tap_controller (
    input  wire        tck,
    input  wire        tms,
    input  wire        tdi,
    input  wire        trst_n,
    output wire        tdo,

    // Debug access signals
    output wire        cpu_debug_enable,
    output wire        secure_debug_enable,
    output wire        key_debug_enable  // VULNERABLE: Sensitive key access
);

    // VULNERABLE: All TAPs in single daisy chain
    // No separate authentication for sensitive TAPs

    wire cpu_tap_tdo;
    wire secure_tap_tdo;
    wire key_tap_tdo;

    // TAP state machine
    reg [3:0] state;
    reg [7:0] instruction;

    // VULNERABLE: Daisy-chain all TAPs together
    // Once any TAP is accessed, all are accessible

    cpu_tap u_cpu_tap (
        .tck(tck),
        .tms(tms),
        .tdi(tdi),              // Input from top
        .trst_n(trst_n),
        .tdo(cpu_tap_tdo),      // Output to next
        .debug_enable(cpu_debug_enable)
    );

    // VULNERABLE: Secure TAP chained without separate auth
    secure_tap u_secure_tap (
        .tck(tck),
        .tms(tms),
        .tdi(cpu_tap_tdo),      // VULNERABLE: Chained from CPU TAP
        .trst_n(trst_n),
        .tdo(secure_tap_tdo),
        .debug_enable(secure_debug_enable)
    );

    // VULNERABLE: Key TAP also in same chain
    key_tap u_key_tap (
        .tck(tck),
        .tms(tms),
        .tdi(secure_tap_tdo),   // VULNERABLE: Chained without auth
        .trst_n(trst_n),
        .tdo(key_tap_tdo),
        .debug_enable(key_debug_enable)
    );

    assign tdo = key_tap_tdo;   // VULNERABLE: Full chain exposed

    // Attack: Access TDI -> shift through CPU TAP -> reach secure TAP -> reach key TAP
    // No authentication required for sensitive components

endmodule

// Vulnerable: Incorrect granularity - single unlock for all
module vulnerable_debug_unlock (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [63:0] unlock_key,
    input  wire        unlock_request,
    output reg         all_debug_enabled  // VULNERABLE: Single enable for all
);

    // VULNERABLE: One key unlocks everything
    localparam MASTER_KEY = 64'hDEAD_BEEF_CAFE_BABE;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            all_debug_enabled <= 1'b0;
        end else if (unlock_request) begin
            // VULNERABLE: Single check enables all debug
            if (unlock_key == MASTER_KEY) begin
                all_debug_enabled <= 1'b1;  // Enables CPU, secure, and key debug!
            end
        end
    end

endmodule

// Vulnerable: Missing granularity in scan chain
module vulnerable_scan_controller (
    input  wire        scan_enable,
    input  wire        scan_in,
    output wire        scan_out,

    // Internal registers including sensitive ones
    output wire [127:0] aes_key_shadow,      // VULNERABLE: Key accessible via scan
    output wire [255:0] private_key_shadow   // VULNERABLE: Private key accessible
);

    // VULNERABLE: All registers in single scan chain
    // No separation between sensitive and non-sensitive data

    reg [127:0] aes_key_reg;
    reg [255:0] private_key_reg;
    reg [31:0]  status_reg;
    reg [31:0]  config_reg;

    // VULNERABLE: Single scan chain includes everything
    assign aes_key_shadow = aes_key_reg;
    assign private_key_shadow = private_key_reg;

    // Full scan chain: scan_in -> config -> status -> aes_key -> private_key -> scan_out
    // Attacker can shift out all values including keys

endmodule

Fixed Code

// Fixed: Hierarchical TAP structure with proper authentication

module secure_tap_controller (
    input  wire        tck,
    input  wire        tms,
    input  wire        tdi,
    input  wire        trst_n,
    output wire        tdo,

    // Authentication signals
    input  wire        basic_auth_valid,
    input  wire        secure_auth_valid,
    input  wire        key_auth_valid,

    // Debug access signals
    output wire        cpu_debug_enable,
    output wire        secure_debug_enable,
    output wire        key_debug_enable
);

    // FIXED: Hierarchical TAP structure with separate authentication

    // Level 1: Basic TAP (always accessible for production test)
    wire basic_tap_tdo;
    wire basic_tap_selected;

    // Level 2: CPU debug TAP (requires basic authentication)
    wire cpu_tap_tdo;
    wire cpu_tap_selected;

    // Level 3: Secure TAP (requires enhanced authentication)
    wire secure_tap_tdo;
    wire secure_tap_selected;

    // Level 4: Key TAP (requires highest authentication)
    wire key_tap_tdo;
    wire key_tap_selected;

    // FIXED: TAP router with authentication gating
    tap_router u_router (
        .tck(tck),
        .tms(tms),
        .tdi(tdi),
        .trst_n(trst_n),
        .tdo(tdo),

        // Authentication inputs
        .basic_auth(basic_auth_valid),
        .secure_auth(secure_auth_valid),
        .key_auth(key_auth_valid),

        // TAP selection outputs (authentication-gated)
        .basic_tap_sel(basic_tap_selected),
        .cpu_tap_sel(cpu_tap_selected),
        .secure_tap_sel(secure_tap_selected),
        .key_tap_sel(key_tap_selected),

        // TAP data inputs
        .basic_tap_tdo(basic_tap_tdo),
        .cpu_tap_tdo(cpu_tap_tdo),
        .secure_tap_tdo(secure_tap_tdo),
        .key_tap_tdo(key_tap_tdo)
    );

    // FIXED: Basic TAP - production test
    basic_tap u_basic_tap (
        .tck(tck),
        .tms(tms),
        .tdi(tdi),
        .trst_n(trst_n),
        .selected(basic_tap_selected),
        .tdo(basic_tap_tdo)
    );

    // FIXED: CPU TAP - requires basic authentication
    cpu_tap u_cpu_tap (
        .tck(tck),
        .tms(tms),
        .tdi(tdi),
        .trst_n(trst_n),
        .selected(cpu_tap_selected & basic_auth_valid),  // FIXED: Gated
        .tdo(cpu_tap_tdo),
        .debug_enable(cpu_debug_enable)
    );

    // FIXED: Secure TAP - requires secure authentication
    secure_tap u_secure_tap (
        .tck(tck),
        .tms(tms),
        .tdi(tdi),
        .trst_n(trst_n),
        .selected(secure_tap_selected & secure_auth_valid),  // FIXED: Gated
        .tdo(secure_tap_tdo),
        .debug_enable(secure_debug_enable)
    );

    // FIXED: Key TAP - requires key authentication
    key_tap u_key_tap (
        .tck(tck),
        .tms(tms),
        .tdi(tdi),
        .trst_n(trst_n),
        .selected(key_tap_selected & key_auth_valid),  // FIXED: Gated
        .tdo(key_tap_tdo),
        .debug_enable(key_debug_enable)
    );

endmodule

// Fixed: Granular debug unlock with separate levels
module secure_debug_unlock (
    input  wire        clk,
    input  wire        rst_n,

    // Separate unlock interfaces for each level
    input  wire [63:0] basic_unlock_key,
    input  wire        basic_unlock_request,
    input  wire [127:0] secure_unlock_key,
    input  wire        secure_unlock_request,
    input  wire [255:0] key_unlock_key,
    input  wire        key_unlock_request,

    // Separate enable outputs
    output reg         basic_debug_enabled,
    output reg         secure_debug_enabled,
    output reg         key_debug_enabled
);

    // FIXED: Separate keys for each level (from OTP)
    wire [63:0]  basic_key_otp;
    wire [127:0] secure_key_otp;
    wire [255:0] key_key_otp;

    // FIXED: Rate limiting for unlock attempts
    reg [3:0] basic_fail_count;
    reg [3:0] secure_fail_count;
    reg [3:0] key_fail_count;
    localparam MAX_ATTEMPTS = 4'd5;

    // FIXED: Lockout on too many failures
    wire basic_locked = (basic_fail_count >= MAX_ATTEMPTS);
    wire secure_locked = (secure_fail_count >= MAX_ATTEMPTS);
    wire key_locked = (key_fail_count >= MAX_ATTEMPTS);

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            basic_debug_enabled <= 1'b0;
            secure_debug_enabled <= 1'b0;
            key_debug_enabled <= 1'b0;
            basic_fail_count <= 4'd0;
            secure_fail_count <= 4'd0;
            key_fail_count <= 4'd0;
        end else begin
            // FIXED: Basic level unlock
            if (basic_unlock_request && !basic_locked) begin
                if (basic_unlock_key == basic_key_otp) begin
                    basic_debug_enabled <= 1'b1;
                    basic_fail_count <= 4'd0;
                end else begin
                    basic_fail_count <= basic_fail_count + 1;
                end
            end

            // FIXED: Secure level requires basic first
            if (secure_unlock_request && !secure_locked && basic_debug_enabled) begin
                if (secure_unlock_key == secure_key_otp) begin
                    secure_debug_enabled <= 1'b1;
                    secure_fail_count <= 4'd0;
                end else begin
                    secure_fail_count <= secure_fail_count + 1;
                end
            end

            // FIXED: Key level requires secure first
            if (key_unlock_request && !key_locked && secure_debug_enabled) begin
                if (key_unlock_key == key_key_otp) begin
                    key_debug_enabled <= 1'b1;
                    key_fail_count <= 4'd0;
                end else begin
                    key_fail_count <= key_fail_count + 1;
                end
            end
        end
    end

endmodule

// Fixed: Scan chain with proper granularity
module secure_scan_controller (
    input  wire        scan_enable,
    input  wire        scan_in,
    input  wire        secure_scan_auth,  // FIXED: Separate auth for secure scan
    output wire        scan_out,

    // Non-sensitive scan access
    output wire [31:0] status_shadow,
    output wire [31:0] config_shadow
);

    // FIXED: Separate scan chains for different security levels

    // Public scan chain - general registers
    wire public_scan_out;

    // FIXED: Secure registers excluded from scan chain entirely
    // Or use separate authenticated secure scan chain

    reg [31:0] status_reg;
    reg [31:0] config_reg;

    // FIXED: Keys are NOT in any scan chain
    // Keys stored in isolated block without scan capability
    // reg [127:0] aes_key_reg;     // NOT SCANNABLE
    // reg [255:0] private_key_reg; // NOT SCANNABLE

    // FIXED: Only non-sensitive registers in scan chain
    assign status_shadow = status_reg;
    assign config_shadow = config_reg;

    // FIXED: Secure scan only with authentication
    scan_chain #(.WIDTH(64)) u_public_scan (
        .scan_enable(scan_enable),
        .scan_in(scan_in),
        .scan_out(public_scan_out),
        .regs({status_reg, config_reg})
    );

    // FIXED: No scan path to cryptographic keys
    // Keys are isolated in non-scannable block

    assign scan_out = public_scan_out;

endmodule

// Fixed: TAP router with authentication
module tap_router (
    input  wire        tck,
    input  wire        tms,
    input  wire        tdi,
    input  wire        trst_n,
    output reg         tdo,

    input  wire        basic_auth,
    input  wire        secure_auth,
    input  wire        key_auth,

    output reg         basic_tap_sel,
    output reg         cpu_tap_sel,
    output reg         secure_tap_sel,
    output reg         key_tap_sel,

    input  wire        basic_tap_tdo,
    input  wire        cpu_tap_tdo,
    input  wire        secure_tap_tdo,
    input  wire        key_tap_tdo
);

    // FIXED: Route based on IR value AND authentication
    reg [3:0] current_ir;

    always @(*) begin
        // Default: no TAP selected
        basic_tap_sel = 1'b0;
        cpu_tap_sel = 1'b0;
        secure_tap_sel = 1'b0;
        key_tap_sel = 1'b0;
        tdo = 1'b0;

        case (current_ir)
            4'h0: begin  // Basic TAP - always accessible
                basic_tap_sel = 1'b1;
                tdo = basic_tap_tdo;
            end

            4'h1: begin  // CPU TAP - requires basic auth
                if (basic_auth) begin
                    cpu_tap_sel = 1'b1;
                    tdo = cpu_tap_tdo;
                end
                // FIXED: No access without auth
            end

            4'h2: begin  // Secure TAP - requires secure auth
                if (secure_auth) begin
                    secure_tap_sel = 1'b1;
                    tdo = secure_tap_tdo;
                end
            end

            4'h3: begin  // Key TAP - requires key auth
                if (key_auth) begin
                    key_tap_sel = 1'b1;
                    tdo = key_tap_tdo;
                end
            end

            default: begin
                // Invalid IR - no access
            end
        endcase
    end

endmodule

CVE Examples

  • CVE-2021-33097: Debug chain misconfiguration in processor allowed unauthorized access to secure debug features.
  • CVE-2019-11090: JTAG daisy chain exposed secure components without proper authentication.

  • CWE-284: Improper Access Control (parent)
  • CWE-1207: Debug and Test Problems (category)
  • CWE-1295: Debug Messages Revealing Unnecessary Information (related)
  • CWE-1244: Internal Asset Exposed to Unsafe Debug Access (related)

References

  1. MITRE Corporation. "CWE-1296: Incorrect Chaining or Granularity of Debug Components." https://cwe.mitre.org/data/definitions/1296.html
  2. IEEE 1149.1: Standard Test Access Port and Boundary-Scan Architecture
  3. CAPEC-702: Exploiting Incorrect Chaining or Granularity of Hardware Debug Components