Generation of Incorrect Security Tokens
Description
Generation of Incorrect Security Tokens occurs when a system implements security tokens to differentiate allowed and disallowed actions but generates these tokens incorrectly. In System-on-Chip (SoC) designs, security tokens differentiate and identify actions from various agents representing actions like "read," "write," "program," "reset," "fetch," and "compute." Each agent receives a unique token based on trust level or privileges. When tokens are generated incorrectly, the same token may be assigned to different agents or different tokens assigned to the same agent, breaking the security model.
Risk
Incorrect security token generation has severe security implications. Privilege escalation becomes possible. Unauthorized access may be granted. Denial of service can occur. Multiple agents may receive identical tokens. Trusted and untrusted agents may be confused. Access control is completely bypassed. Protected resources become exposed. Entire security architecture can be compromised.
Solution
Review token generation logic for design inconsistencies and common weaknesses during security reviews. Test security-token definitions in both pre-silicon and post-silicon testing phases. Implement unique token assignment verification. Ensure token generation is deterministic and reproducible. Document all token assignments and validate consistency. Use formal verification for token generation logic.
Common Consequences
| Impact | Details |
|---|---|
| Access Control | Scope: Access Control Bypass Protection Mechanism - Incorrect tokens allow unauthorized actions. |
| Confidentiality | Scope: Confidentiality Read Memory - Unauthorized agents may gain read access. |
| Integrity | Scope: Integrity Modify Memory - Unauthorized agents may gain write access. |
| Availability | Scope: Availability DoS - Conflicting tokens may cause system failures. |
Example Code
Vulnerable Code
// Vulnerable: Token generation with conflict
module vulnerable_token_generator (
input wire clk,
input wire reset_n,
input wire [3:0] agent_id,
input wire request_token,
output reg [7:0] security_token,
output reg token_valid
);
// VULNERABLE: Flawed token generation logic
// Multiple agents can receive the same token
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
security_token <= 8'h00;
token_valid <= 1'b0;
end
else if (request_token) begin
// VULNERABLE: Token based only on lower 2 bits of agent_id
// Agents 0, 4, 8, 12 all get the same token
// Agents 1, 5, 9, 13 all get the same token
// etc.
case (agent_id[1:0])
2'b00: security_token <= 8'h01; // Token 1
2'b01: security_token <= 8'h02; // Token 2
2'b10: security_token <= 8'h03; // Token 3
2'b11: security_token <= 8'h04; // Token 4
endcase
token_valid <= 1'b1;
// Problem: Agent 0 (trusted CPU) gets token 1
// Agent 4 (untrusted DMA) also gets token 1
// Both can access same protected resources!
end
end
endmodule
// Vulnerable: AES key access with token collision
module vulnerable_aes_access (
input wire clk,
input wire reset_n,
input wire [7:0] token,
input wire [7:0] reg_addr,
input wire read_request,
output reg [31:0] read_data,
output reg access_granted
);
reg [127:0] aes_key;
// Token assignments (vulnerable):
// Token 1 = Crypto controller (trusted) - should access key
// Token 1 = DMA controller (untrusted) - same token!
parameter TRUSTED_CRYPTO = 8'h01;
// VULNERABLE: Both agents have token 0x01
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
access_granted <= 1'b0;
end
else if (read_request) begin
if (reg_addr == 8'h00) begin // AES key register
// VULNERABLE: Check only against token value
if (token == TRUSTED_CRYPTO) begin
// Both trusted and untrusted get access!
read_data <= aes_key[31:0];
access_granted <= 1'b1;
end
else begin
access_granted <= 1'b0;
end
end
end
end
endmodule
// Vulnerable: Software token assignment with collision
#include <stdint.h>
#define MAX_AGENTS 16
typedef struct {
uint8_t agent_id;
uint8_t security_token;
const char* name;
} agent_info_t;
// VULNERABLE: Token assignment function
uint8_t vulnerable_generate_token(uint8_t agent_id) {
// VULNERABLE: Only uses lower 3 bits
// Agents 0 and 8 get the same token
// Agents 1 and 9 get the same token
// etc.
return (agent_id & 0x07) + 1;
}
// VULNERABLE: Token table with collisions
agent_info_t vulnerable_agent_table[] = {
{0, 1, "Secure CPU"}, // Token 1
{1, 2, "Crypto Engine"}, // Token 2
{2, 3, "Boot ROM"}, // Token 3
{3, 4, "User App"}, // Token 4
// ... later additions
{8, 1, "DMA Controller"}, // VULNERABLE: Same token as Secure CPU!
{9, 2, "Debug Agent"}, // VULNERABLE: Same token as Crypto Engine!
};
bool vulnerable_check_access(uint8_t token, uint32_t resource) {
// Only checks token value, not agent identity
if (resource == RESOURCE_AES_KEY) {
return (token == 1 || token == 2); // Tokens 1 and 2 allowed
}
return false;
// Problem: DMA (token 1) and Debug (token 2) can access AES key!
}
Fixed Code
// Fixed: Unique token generation
module secure_token_generator (
input wire clk,
input wire reset_n,
input wire [3:0] agent_id,
input wire request_token,
output reg [7:0] security_token,
output reg token_valid,
output reg token_conflict
);
// Token assignment table (verified unique)
reg [7:0] token_table [0:15];
// Track assigned tokens
reg [255:0] token_assigned;
// Initialize unique tokens
initial begin
// Each agent gets unique token
token_table[0] = 8'h01; // Secure CPU
token_table[1] = 8'h02; // Crypto Engine
token_table[2] = 8'h03; // Boot ROM
token_table[3] = 8'h04; // User Application
token_table[4] = 8'h10; // DMA Controller (different!)
token_table[5] = 8'h20; // Debug Agent (different!)
token_table[6] = 8'h30; // Test Interface
token_table[7] = 8'h40; // External Host
token_table[8] = 8'h50; // GPU
token_table[9] = 8'h60; // DSP
token_table[10] = 8'h70; // Network Controller
token_table[11] = 8'h80; // Storage Controller
token_table[12] = 8'h90; // USB Controller
token_table[13] = 8'hA0; // Audio Controller
token_table[14] = 8'hB0; // Video Controller
token_table[15] = 8'hC0; // Reserved
token_assigned = 256'h0;
end
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
security_token <= 8'h00;
token_valid <= 1'b0;
token_conflict <= 1'b0;
end
else if (request_token) begin
token_conflict <= 1'b0;
// FIXED: Use full agent_id for lookup
security_token <= token_table[agent_id];
// FIXED: Verify no token collision
if (token_assigned[token_table[agent_id]]) begin
// Token already assigned to another agent!
token_conflict <= 1'b1;
token_valid <= 1'b0;
end
else begin
token_assigned[token_table[agent_id]] <= 1'b1;
token_valid <= 1'b1;
end
end
end
endmodule
// Fixed: AES access with verified tokens
module secure_aes_access (
input wire clk,
input wire reset_n,
input wire [3:0] agent_id,
input wire [7:0] token,
input wire [7:0] reg_addr,
input wire read_request,
output reg [31:0] read_data,
output reg access_granted,
output reg token_mismatch
);
reg [127:0] aes_key;
// Expected token table
reg [7:0] expected_token [0:15];
// Access policy for AES key
reg [15:0] aes_access_policy;
initial begin
// Set expected tokens (must match token generator)
expected_token[0] = 8'h01; // Secure CPU
expected_token[1] = 8'h02; // Crypto Engine
expected_token[4] = 8'h10; // DMA Controller
expected_token[5] = 8'h20; // Debug Agent
// Only agents 0 and 1 can access AES key
aes_access_policy = 16'b0000_0000_0000_0011;
end
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
access_granted <= 1'b0;
token_mismatch <= 1'b0;
end
else if (read_request) begin
token_mismatch <= 1'b0;
access_granted <= 1'b0;
// FIXED: Verify token matches expected for agent
if (token != expected_token[agent_id]) begin
// Token doesn't match agent - possible spoofing
token_mismatch <= 1'b1;
end
else if (reg_addr == 8'h00) begin // AES key register
// FIXED: Check agent permission, not just token
if (aes_access_policy[agent_id]) begin
read_data <= aes_key[31:0];
access_granted <= 1'b1;
end
end
end
end
endmodule
// Fixed: Token verification module
module token_verification (
input wire clk,
input wire reset_n,
input wire verify_enable,
output reg verification_passed,
output reg [3:0] conflict_agent_a,
output reg [3:0] conflict_agent_b
);
reg [7:0] token_table [0:15];
integer i, j;
reg conflict_found;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
verification_passed <= 1'b0;
conflict_found <= 1'b0;
end
else if (verify_enable) begin
conflict_found <= 1'b0;
// FIXED: Check all token pairs for uniqueness
for (i = 0; i < 15; i = i + 1) begin
for (j = i + 1; j < 16; j = j + 1) begin
if (token_table[i] == token_table[j]) begin
conflict_found <= 1'b1;
conflict_agent_a <= i[3:0];
conflict_agent_b <= j[3:0];
end
end
end
verification_passed <= !conflict_found;
end
end
endmodule
// Fixed: Software token generation with uniqueness verification
#include <stdint.h>
#include <stdbool.h>
#define MAX_AGENTS 16
#define INVALID_TOKEN 0x00
typedef struct {
uint8_t agent_id;
uint8_t security_token;
const char* name;
bool is_trusted;
} secure_agent_info_t;
// FIXED: Verified unique token table
static const secure_agent_info_t secure_agent_table[] = {
{0, 0x01, "Secure CPU", true},
{1, 0x02, "Crypto Engine", true},
{2, 0x03, "Boot ROM", true},
{3, 0x04, "User Application", false},
{4, 0x10, "DMA Controller", false}, // FIXED: Unique token
{5, 0x20, "Debug Agent", false}, // FIXED: Unique token
{6, 0x30, "Test Interface", false},
{7, 0x40, "External Host", false},
{8, 0x50, "GPU", false}, // FIXED: Unique token
{9, 0x60, "DSP", false}, // FIXED: Unique token
{10, 0x70, "Network", false},
{11, 0x80, "Storage", false},
{12, 0x90, "USB", false},
{13, 0xA0, "Audio", false},
{14, 0xB0, "Video", false},
{15, 0xC0, "Reserved", false},
};
// FIXED: Verify token uniqueness at startup
bool verify_token_uniqueness(void) {
uint8_t token_count[256] = {0};
for (int i = 0; i < MAX_AGENTS; i++) {
uint8_t token = secure_agent_table[i].security_token;
if (token == INVALID_TOKEN) {
log_error("Agent %d has invalid token", i);
return false;
}
if (token_count[token] > 0) {
log_error("Token collision: token 0x%02X assigned multiple times", token);
return false;
}
token_count[token]++;
}
log_info("Token uniqueness verified for all %d agents", MAX_AGENTS);
return true;
}
// FIXED: Get token for agent with validation
uint8_t secure_get_token(uint8_t agent_id) {
if (agent_id >= MAX_AGENTS) {
return INVALID_TOKEN;
}
return secure_agent_table[agent_id].security_token;
}
// FIXED: Verify token belongs to claimed agent
bool verify_token_ownership(uint8_t agent_id, uint8_t presented_token) {
if (agent_id >= MAX_AGENTS) {
return false;
}
return (secure_agent_table[agent_id].security_token == presented_token);
}
// FIXED: Access check with agent and token verification
bool secure_check_access(uint8_t agent_id, uint8_t token, uint32_t resource) {
// Verify token matches agent
if (!verify_token_ownership(agent_id, token)) {
log_security_event("Token mismatch for agent %d", agent_id);
return false;
}
// Check resource access based on agent identity (not just token)
if (resource == RESOURCE_AES_KEY) {
// Only trusted agents can access AES key
return secure_agent_table[agent_id].is_trusted;
}
return false;
}
CVE Examples
Token generation vulnerabilities have been found in various SoC designs where multiple agents were incorrectly assigned the same security token, allowing untrusted components to access protected resources.
Related CWEs
- CWE-284: Improper Access Control (parent)
- CWE-1294: Insecure Security Identifier Mechanism (parent)
- CWE-1259: Improper Restriction of Security Token Assignment (related)
- CAPEC-121: Exploit Non-Production Interfaces (attack pattern)
- CAPEC-633: Token Impersonation (attack pattern)
- CAPEC-681: Exploitation of Improperly Controlled Hardware Security Identifiers (attack pattern)
References
- MITRE Corporation. "CWE-1270: Generation of Incorrect Security Tokens." https://cwe.mitre.org/data/definitions/1270.html
- ARM. "AMBA AXI Security Extensions"
- RISC-V. "World-Guard Security Specification"