Skip to content

OpenSC pkcs11-tool Global Buffer Overflow Vulnerability Report #3682

@HMF2021

Description

@HMF2021

Describe the bug

Vulnerability Basic Information

  • Vulnerability Name: OpenSC pkcs11-tool Key Generation Module Input Validation Flaw Leading to Global Buffer Overflow
  • Vulnerability Type: Buffer Overflow (CWE-120 / CWE-787)
  • Affected Component: OpenSC (especially the pkcs11-tool tool)
  • Affected Versions: OpenSC 0.26.1 and earlier
  • Severity: Medium / High (depending on execution context)
  • Attack Vector: Local / Physical
  • Prerequisites: The attacker must craft a malicious PKCS#11 module to be loaded by the victim, or provide a malicious physical smart card device with customized firmware, and induce the victim to interact with it via pkcs11-tool, thereby triggering the test_kpgen_certwrite logic.

Vulnerability Detailed Description

In OpenSC version 0.26.1, within the file src/tools/pkcs11-tool.c, a global buffer overflow vulnerability exists during key pair generation tests such as -z, --test-ec, and --test-kpgen. This vulnerability is caused by missing input validation.

The root cause lies in the function test_kpgen_certwrite(). After dynamically retrieving the CKA_ID attribute returned by the underlying PKCS#11 token or smart card, the function fails to validate the length of the returned data and directly copies it into a fixed-size global static buffer of only 100 bytes.


Vulnerability Code Analysis

1. Fixed-Size Global Buffer Definition

Code Path: src/tools/pkcs11-tool.c : 444

static CK_BYTE opt_object_id[100], new_object_id[100];

static size_t opt_object_id_len = 0, new_object_id_len = 0;

As shown above, the application defines a static array opt_object_id of only 100 bytes to store IDs generated by the smart card.


2. Retrieval of Variable-Length Data from Hardware (Unsafe Trust of Length)

Code Path: src/tools/pkcs11-tool.c : 8387

// After gen_keypair(), retrieve the CKA_ID of the generated private key (length stored in i)

tmp = getID(session, priv_key, &i);

// ... [only check] ...

if (i == 0) {

    fprintf(stderr, "ERR: newly generated private key has no (or an empty) CKA_ID\n");

    return session;

}

The function getID is a wrapper generated via the VARATTR_METHOD macro, internally invoking the PKCS#11 API C_GetAttributeValue. It dynamically allocates sufficient heap memory based on the length returned by the hardware and stores the length in variable i.

If the underlying token is malicious, it may return excessively large data (e.g., 500, 1000, or more bytes). The current code only checks for i == 0, but performs no upper-bound validation.


3. Triggering the Buffer Overflow

Code Path: src/tools/pkcs11-tool.c : 8392 - 8393

opt_object_id_len = (size_t) i;

memcpy(opt_object_id, tmp, opt_object_id_len); // [!] no bounds checking, overflow occurs

If the returned length exceeds 100 bytes, memcpy will blindly copy all data into opt_object_id, causing an out-of-bounds write.

Since opt_object_id resides in the global .bss segment alongside other global variables, this leads to a classic global buffer overflow, potentially corrupting adjacent global variables, altering program state, or even overwriting function pointers to achieve arbitrary code execution.


Steps to reproduce

Exploitation Scenarios

This vulnerability is not trivial and can be exploited through two realistic attack paths:

Scenario 1: Malicious PKCS#11 Module Injection

This is the most direct and commonly used attack method (also used in our reproduction suite):

  • The attacker develops a malicious PKCS#11 shared library (*.so) implementing APIs such as C_GetAttributeValue.
  • The module is disguised as a legitimate driver for a security device and delivered via social engineering.
  • The victim is tricked into executing commands such as:
pkcs11-tool --module malicious.so -z xxx
  • During execution, the malicious module returns an oversized CKA_ID, triggering the overflow and enabling potential code execution.

Scenario 2: Malicious Hardware Supply Chain Injection

For high-security enterprise environments:

  • The core issue lies in trusting responses from underlying hardware devices.
  • An attacker may compromise the supply chain and distribute smart cards with malicious firmware.
  • During key generation, the device deliberately returns oversized attribute data.
  • When administrators use standard OpenSC tools (e.g., pkcs11-tool -z ...) for card initialization or testing, the malicious payload propagates through the hardware interface and triggers the vulnerability, leading to compromise of the host system.

ASan Report and Reproduction Result

In the provided reproduction suite, the malicious module returns a 200-byte CKA_ID. Running the test triggers the following AddressSanitizer report:

=================================================================

==38127==ERROR: AddressSanitizer: global-buffer-overflow on address 0x55e211f35904 at pc 0x7f303c447e93 bp 0x7ffc1d09cf50 sp 0x7ffc1d09c6f8

WRITE of size 200 at 0x55e211f35904 thread T0

    #0 0x7f303c447e92 in __interceptor_memcpy ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:899

    #1 0x55e211eeb169 in test_kpgen_certwrite /mnt/c/Users/ZHEFOX/Desktop/testcase/OpenSC-0.26.1/src/tools/pkcs11-tool.c:8393

    #2 0x55e211eb316a in main /mnt/c/Users/ZHEFOX/Desktop/testcase/OpenSC-0.26.1/src/tools/pkcs11-tool.c:1557

...

0x55e211f35904 is located 0 bytes after global variable 'opt_object_id' defined in 'pkcs11-tool.c:444:17' (0x55e211f358a0) of size 100

0x55e211f35904 is located 60 bytes before global variable 'new_object_id' defined in 'pkcs11-tool.c:444:37' (0x55e211f35940) of size 100

SUMMARY: AddressSanitizer: global-buffer-overflow

Verification Steps

  1. Download the <font style="color:rgb(5, 8, 44);">Reproduce2</font> archive from the submission materials.
  2. Execute the provided script:
./reproduce.sh
  1. The script compiles mock_pkcs11.c into mock_pkcs11.so and loads it into an ASan-instrumented pkcs11-tool.
  2. If a segmentation fault or the above AddressSanitizer error appears, the vulnerability has been successfully reproduced.

Fix Recommendations

This issue stems from improper trust in data returned from lower-level PKCS#11 interfaces (potentially malicious hardware or software modules).

Add Explicit Bounds Checking

Modify pkcs11-tool.c:8387 as follows:

tmp = getID(session, priv_key, &i);

if (i == 0) {

    fprintf(stderr, "ERR: newly generated private key has no (or an empty) CKA_ID\n");

    return session;

}

// Fix: enforce strict upper bound

if (i > sizeof(opt_object_id)) {

    fprintf(stderr, "ERR: returned CKA_ID length (%lu) strictly exceeds maximum supported buffer size (%zu)\n",

            (unsigned long)i, sizeof(opt_object_id));

    free(tmp);

    return session;

}

opt_object_id_len = (size_t) i;

memcpy(opt_object_id, tmp, opt_object_id_len);

Additional Recommendations

  • Audit all usages of C_GetAttributeValue where returned lengths are used in memory copy operations.
  • Ensure all buffer operations include strict upper-bound validation.
  • Avoid implicit trust in hardware or external module responses.

Reproduction Package

All reproduction materials are included in the Reproduce2 directory.

Expected behavior

pkcs11-tool should validate the length of the CKA_ID attribute returned by the PKCS#11 token or module before copying it into the fixed-size global buffer opt_object_id. If the returned CKA_ID length exceeds the capacity of the destination buffer, the tool should reject the value, report an error, release the allocated memory, and terminate the current operation safely without performing an out-of-bounds write.

Actual behavior

In test_kpgen_certwrite(), after retrieving the CKA_ID of the generated private key, pkcs11-tool only checks whether the returned length is zero, but does not enforce an upper-bound check. The returned length is directly assigned to opt_object_id_len and then used in memcpy(opt_object_id, tmp, opt_object_id_len). When a malicious PKCS#11 module or smart card returns an oversized CKA_ID, the copy operation writes beyond the 100-byte global buffer opt_object_id, triggering a global buffer overflow. In our reproduction, a 200-byte CKA_ID causes AddressSanitizer to report a global-buffer-overflow at src/tools/pkcs11-tool.c:8393.

OpenSC version

OpenSC 0.26.1 and earlier

Operating system

Ubuntu 22.04

Smart card model or security token

No response

Application used with smart card

No response

Logs and debug output

Checklist

  • I am using a supported OpenSC version
  • I have searched existing issues to avoid duplicates

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions