Device Unlock Credential Sharing
Description
Device Unlock Credential Sharing occurs when the credentials necessary for unlocking a device are shared across multiple parties and may expose sensitive information. Device unlocking typically activates debug and manufacturer-specific capabilities using sensitive credentials needed for troubleshooting. The risk of credential compromise increases significantly in multi-company supply chains where chip designers, manufacturers, and testers work for different organizations. Each party needs access to unlock credentials, creating greater exposure risks than vertically integrated companies face.
Risk
Shared unlock credentials have severe security implications. Credentials may be leaked to unauthorized parties. Debug interfaces may be accessible to attackers. Protected functionalities may be exposed. Privilege escalation becomes possible. Memory and files may be accessed without authorization. Protection mechanisms may be bypassed. Supply chain attacks become feasible. Intellectual property may be exposed.
Solution
Limit credential sharing to the minimum necessary parties. Maintain utmost secrecy protocols for all shared credentials. Implement part-specific or batch-specific credentials where feasible. Apply strict access control and need-to-know principles. Use cryptographic methods for credential derivation. Implement credential rotation policies. Audit credential usage and access. Consider hardware security modules for credential storage.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Read Memory - Compromised credentials allow unauthorized memory access. |
| Integrity | Scope: Integrity Modify Files - Attackers can modify device configuration and firmware. |
| Access Control | Scope: Access Control Bypass Protection Mechanism - Debug access bypasses security controls. |
| Authorization | Scope: Authorization Gain Privileges - Device unlock enables privileged operations. |
Example Code
Vulnerable Code
// Vulnerable: Single global unlock credential
module vulnerable_device_unlock (
input wire clk,
input wire reset_n,
input wire [127:0] unlock_credential,
input wire unlock_request,
output reg device_unlocked,
output reg debug_enabled
);
// VULNERABLE: Single global credential for all devices
// Same credential used across entire supply chain
parameter GLOBAL_UNLOCK_KEY = 128'h0123456789ABCDEF0123456789ABCDEF;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
device_unlocked <= 1'b0;
debug_enabled <= 1'b0;
end
else if (unlock_request) begin
// VULNERABLE: Check against global key
if (unlock_credential == GLOBAL_UNLOCK_KEY) begin
device_unlocked <= 1'b1;
debug_enabled <= 1'b1;
end
// Problems:
// 1. Key shared with chip designer
// 2. Key shared with foundry
// 3. Key shared with test house
// 4. Key shared with OEM
// 5. Any leak compromises ALL devices
end
end
endmodule
// Vulnerable: Hardcoded unlock credentials
module vulnerable_hardcoded_unlock (
input wire clk,
input wire reset_n,
input wire [63:0] password,
input wire unlock_request,
output reg unlocked
);
// VULNERABLE: Hardcoded passwords shared across organization
parameter PASSWORD_ENGINEERING = 64'h456E67696E656572; // "Engineer"
parameter PASSWORD_PRODUCTION = 64'h50726F64756374; // "Product"
parameter PASSWORD_DEBUG = 64'h4465627567313233; // "Debug123"
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
unlocked <= 1'b0;
end
else if (unlock_request) begin
// VULNERABLE: Any of the shared passwords unlocks device
if (password == PASSWORD_ENGINEERING ||
password == PASSWORD_PRODUCTION ||
password == PASSWORD_DEBUG) begin
unlocked <= 1'b1;
end
// Anyone who knows any password can unlock any device
end
end
endmodule
// Vulnerable: Software with shared unlock credentials
#include <stdint.h>
#include <string.h>
// VULNERABLE: Global unlock key compiled into firmware
// Same key for all devices from this manufacturer
static const uint8_t global_unlock_key[16] = {
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF
};
// VULNERABLE: Shared across supply chain
static const char* shared_passwords[] = {
"DesignerAccess2024", // Chip designer
"FoundryDebug", // Foundry
"TestHouseUnlock", // Test house
"OEMService", // OEM
"FieldDebug123" // Field service
};
bool vulnerable_check_unlock(const uint8_t* credential, size_t len) {
// VULNERABLE: Check against global key
if (len == 16 && memcmp(credential, global_unlock_key, 16) == 0) {
return true;
}
// VULNERABLE: Check against all shared passwords
for (int i = 0; i < sizeof(shared_passwords)/sizeof(shared_passwords[0]); i++) {
if (strcmp((const char*)credential, shared_passwords[i]) == 0) {
return true;
}
}
return false;
}
void vulnerable_unlock_device(const uint8_t* credential, size_t len) {
if (vulnerable_check_unlock(credential, len)) {
// VULNERABLE: Full unlock for any valid credential
enable_jtag();
enable_debug_uart();
disable_secure_boot();
enable_memory_dump();
// Any party with any credential gets full access
}
}
// VULNERABLE: Credential sharing in supply chain
typedef struct {
char company_name[64];
uint8_t unlock_credential[16];
uint32_t access_level;
} supply_chain_credential_t;
supply_chain_credential_t vulnerable_supply_chain[] = {
{"Chip Designer Co", {0x01, 0x23, ...}, ACCESS_FULL},
{"Global Foundry", {0x01, 0x23, ...}, ACCESS_FULL}, // Same key!
{"Test Systems Inc", {0x01, 0x23, ...}, ACCESS_FULL}, // Same key!
{"Acme OEM", {0x01, 0x23, ...}, ACCESS_FULL}, // Same key!
};
// All parties share the same credential
// Leak from any party compromises all
Fixed Code
// Fixed: Device-specific unlock credentials
module secure_device_unlock (
input wire clk,
input wire reset_n,
input wire [127:0] unlock_credential,
input wire [127:0] challenge,
input wire unlock_request,
input wire [63:0] device_id,
output reg device_unlocked,
output reg debug_enabled,
output reg unlock_failed
);
// FIXED: Device-specific key derived from master + device ID
// Master key stored in HSM, never shared directly
wire [127:0] device_specific_key;
reg [127:0] expected_response;
// Key derivation (simplified - use proper KDF in practice)
// In real implementation: HKDF(master_key, device_id)
key_derivation_unit kdf (
.device_id(device_id),
.derived_key(device_specific_key)
);
// Challenge-response authentication
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
device_unlocked <= 1'b0;
debug_enabled <= 1'b0;
unlock_failed <= 1'b0;
end
else if (unlock_request) begin
// FIXED: Verify challenge-response with device-specific key
expected_response <= compute_hmac(device_specific_key, challenge);
if (unlock_credential == expected_response) begin
device_unlocked <= 1'b1;
debug_enabled <= 1'b1;
unlock_failed <= 1'b0;
end
else begin
unlock_failed <= 1'b1;
end
end
end
endmodule
// Fixed: Tiered unlock with different access levels
module secure_tiered_unlock (
input wire clk,
input wire reset_n,
input wire [127:0] credential,
input wire [1:0] requested_level,
input wire unlock_request,
output reg [1:0] current_access_level,
output reg unlock_granted
);
// FIXED: Different credentials for different access levels
// Each level has unique, non-shared credentials
parameter LEVEL_NONE = 2'b00;
parameter LEVEL_BASIC = 2'b01; // Basic diagnostics
parameter LEVEL_ADVANCED = 2'b10; // Advanced debug
parameter LEVEL_FULL = 2'b11; // Full unlock (restricted)
// Per-device credentials stored in OTP
reg [127:0] basic_credential; // From fuse
reg [127:0] advanced_credential; // From fuse
reg [127:0] full_credential; // From secure fuse
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
current_access_level <= LEVEL_NONE;
unlock_granted <= 1'b0;
end
else if (unlock_request) begin
unlock_granted <= 1'b0;
case (requested_level)
LEVEL_BASIC: begin
// FIXED: Basic level - limited exposure
if (credential == basic_credential) begin
current_access_level <= LEVEL_BASIC;
unlock_granted <= 1'b1;
end
end
LEVEL_ADVANCED: begin
// FIXED: Advanced level - more restricted sharing
if (credential == advanced_credential) begin
current_access_level <= LEVEL_ADVANCED;
unlock_granted <= 1'b1;
end
end
LEVEL_FULL: begin
// FIXED: Full level - never shared externally
if (credential == full_credential) begin
current_access_level <= LEVEL_FULL;
unlock_granted <= 1'b1;
end
end
endcase
end
end
endmodule
// Fixed: One-time unlock tokens
module secure_one_time_unlock (
input wire clk,
input wire reset_n,
input wire [255:0] unlock_token,
input wire unlock_request,
output reg device_unlocked,
output reg token_consumed
);
// FIXED: One-time tokens - cannot be reused
reg [255:0] token_hash_storage [0:15];
reg [3:0] token_index;
reg token_valid;
// Check if token matches any unused token
integer i;
always @(*) begin
token_valid = 1'b0;
for (i = 0; i < 16; i = i + 1) begin
if (token_hash_storage[i] == sha256(unlock_token) &&
token_hash_storage[i] != 256'h0) begin
token_valid = 1'b1;
token_index = i;
end
end
end
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
device_unlocked <= 1'b0;
token_consumed <= 1'b0;
end
else if (unlock_request && token_valid) begin
// FIXED: Consume token after use
token_hash_storage[token_index] <= 256'h0;
device_unlocked <= 1'b1;
token_consumed <= 1'b1;
end
end
endmodule
// Fixed: Software with secure credential management
#include <stdint.h>
#include <stdbool.h>
// FIXED: No hardcoded credentials
// All credentials derived from device-specific secrets
typedef struct {
uint8_t device_id[16];
uint8_t derived_key[32];
} device_credentials_t;
// FIXED: Derive device-specific credentials from master + device ID
static bool derive_device_credential(const uint8_t* device_id,
uint8_t* credential_out) {
// In practice: HSM derives key, device only stores derived value
// Key derivation: HKDF(master_key, device_id || "unlock")
uint8_t context[32];
memcpy(context, device_id, 16);
memcpy(context + 16, "unlock_context", 16);
// Derive from device-specific root key
return hkdf_derive(get_device_root_key(), context, 32, credential_out);
}
// FIXED: Challenge-response authentication
typedef struct {
uint8_t challenge[32];
uint8_t response[32];
uint32_t timestamp;
uint32_t nonce;
} unlock_request_t;
bool secure_verify_unlock(const unlock_request_t* request) {
uint8_t device_credential[32];
uint8_t expected_response[32];
// Get device-specific credential
if (!derive_device_credential(get_device_id(), device_credential)) {
return false;
}
// FIXED: Verify timestamp is recent (prevent replay)
if (!verify_timestamp(request->timestamp)) {
log_security_event("Unlock timestamp invalid");
return false;
}
// FIXED: Verify nonce hasn't been used (prevent replay)
if (is_nonce_used(request->nonce)) {
log_security_event("Unlock nonce replay detected");
return false;
}
// Compute expected response
compute_hmac_sha256(device_credential, request->challenge, 32,
expected_response);
// FIXED: Constant-time comparison
if (!secure_compare(request->response, expected_response, 32)) {
log_security_event("Unlock credential mismatch");
return false;
}
// Mark nonce as used
mark_nonce_used(request->nonce);
return true;
}
// FIXED: Tiered access levels with separate credentials
typedef enum {
ACCESS_NONE = 0,
ACCESS_BASIC = 1, // Basic diagnostics - shared with field service
ACCESS_ADVANCED = 2, // Advanced debug - limited sharing
ACCESS_FULL = 3 // Full access - never shared externally
} access_level_t;
typedef struct {
access_level_t level;
uint8_t credential[32];
uint32_t permissions;
} access_tier_t;
static access_tier_t access_tiers[4];
void secure_unlock_device(access_level_t level, const uint8_t* credential) {
// FIXED: Verify credential for specific level only
uint8_t expected[32];
derive_level_credential(level, expected);
if (!secure_compare(credential, expected, 32)) {
log_security_event("Invalid credential for level %d", level);
increment_failure_counter();
return;
}
// FIXED: Grant only permissions for this level
switch (level) {
case ACCESS_BASIC:
// Limited access for field service
enable_basic_diagnostics();
break;
case ACCESS_ADVANCED:
// More access for authorized technicians
enable_advanced_debug();
break;
case ACCESS_FULL:
// Full access - internal use only
enable_jtag();
enable_memory_dump();
break;
default:
break;
}
}
// FIXED: Audit credential usage
void log_credential_usage(access_level_t level, const char* requester) {
audit_entry_t entry = {
.timestamp = get_secure_time(),
.access_level = level,
.device_id = get_device_id(),
.requester_hash = hash_string(requester),
.success = true
};
write_audit_log(&entry);
}
CVE Examples
Credential sharing vulnerabilities have been found in various supply chain scenarios where unlock credentials shared across multiple parties were leaked, allowing unauthorized access to device debug interfaces across entire product lines.
Related CWEs
- CWE-200: Exposure of Sensitive Information to an Unauthorized Actor (parent)
- CWE-1195: Manufacturing and Life Cycle Management Concerns (category)
- CWE-798: Use of Hard-coded Credentials (related)
- CAPEC-560: Use of Known Domain Credentials (attack pattern)
References
- MITRE Corporation. "CWE-1273: Device Unlock Credential Sharing." https://cwe.mitre.org/data/definitions/1273.html
- NIST. "Supply Chain Risk Management Practices"
- GlobalPlatform. "Device Trust Architecture"