Heiko Schäfer discovered a new security issue in the Yubico yubihsm_pkcs11.so driver library, which we disclosed together to Yubico. The YubiHSM PKCS#11 client-side library is designed to interact with Yubico HSM2 hardware security modules. Due to flaws in the memory handling, the library code accidentally returns 8192 bytes of previously used process memory under some circumstances. This impacts the memory confidentiality of the calling program for some usages.

This article will describe the issue.

Consulting

I’m a freelance Security Consultant and currently available for new projects. If you are looking for assistance to secure your projects or organization, contact me.

Memory Handling Issue in C_GetAttributeValue

The C_GetAttributeValue() function in yubihsm_pkcs11.c can be used to query X.509 certificate attributes of particular types. However, some codepaths have problematic memory handling.

Consider client software that retrieves the certificate attribute CKA_SERIAL_NUMBER with the C_GetAttributeValue call from a regular, non-malicious YubiHSM2 device via the PKCS#11 API interface.

Internally, the PKCS#11 functions will establish a session with the YubiHSM2 device and then attempt to handle and parse the received object information. This happens via the following code positions:

CK_DEFINE_FUNCTION(CK_RV, C_GetAttributeValue)[...]

yubihsm_pkcs11.c L2018

CK_RV populate_template(int type, void *object, CK_ATTRIBUTE_PTR pTemplate, [..])

util_pkcs11.c L5065

Note that populate_template() reserves a local stack buffer CK_BYTE tmp[8192]; without explicit data initialization and passes its size as the len parameter to subsequent function calls in

CK_ULONG len = sizeof(tmp);

util_pkcs11.c L5072 This will become relevant later.

The particular security issue is associated with opaque attributes, which are handled via

static CK_RV get_attribute([...])

util_pkcs11.c L1969

static CK_RV get_attribute_opaque(CK_ATTRIBUTE_TYPE type, [...] )

util_pkcs11.c L1030

In get_attribute_opaque(), some function paths overwrite the length parameter - which is passed as a reference - to the actual length of the field for the specific attribute they fetched. However, for at least three specific field types, this does not happen:

   case CKA_SUBJECT:
   case CKA_ISSUER:
   case CKA_SERIAL_NUMBER:
break;

util_pkcs11.c L1105-L1108

As a result, code flows hitting the quoted code lines in get_attribute_opaque() will return to the parent function without writing data into the tmp buffer, without changing the length parameter away from the maximum value, and without returning an error code. By convention, this appears like a successful operation which produced 8192 bytes of new output, although in reality the tmp buffer was not written to at all.

This constellation leads to a problematic memcpy() call which leaks the uninitialized memory contents of tmp into the output:

memcpy(pTemplate[i].pValue, tmp, len);

util_pkcs11.c L5095

Typically, the content of uninitialized stack memory variables will contain memory from stack frames which previously occupied the relevant memory region. Copying data from this memory region will likely contain stack variables and other stack-related information (stack canaries, pointers) from previous function calls.

The leaked data will then get returned to the PKCS#11 caller. Since the caller requested some specific certificate information, but instead gets data from an information leak, this represents a security issue. Additionally, since the problematic library function indicates no errors, this information may be passed on by the caller towards other components and trust spheres, depending on the specific behavior of the program.

Programs that use the YubiHSM are likely to handle secrets, possibly including secret key material, or sensitive plaintext. The sensitive key material may include the PIN secret used to secure the HSM communication. Because of this bug, a program that uses yubihsm_pkcs11.so may inadvertently return such information instead of the requested X.509 certificate attributes.

Since the vulnerable component is a flexible library, it is unclear which programs call into the problematic function, and under which circumstances. Additionally, the relevant memory accesses are undefined behavior (UB) in C and may depend on the compiler and system environment. If you have more information about specific integrating applications and their confirmed security impacts, please contact us.

Initial Debugging

To confirm that this data actually leaks from the tmp variable on the stack, we used a modified yubihsm_pkcs11.so library which specifically marks the memory in question with ASCII ‘A’ characters. During initial debugging, this allowed a straightforward identification of the problematic memory in returned data:

CK_BYTE tmp[8192];
+ // mark potentially leaked bytes
+ memset(tmp, 0x41, sizeof(tmp));

PoC

In order to confirm the issue and help Yubico reproduce it, we crafted a proof-of-concept (PoC). The PoC consists of a short dummy program written in C that triggers the issue: pkcs11-memleak.c.

WARNING: use the provided PoC code at your own risk, and only on non-production HSM devices.

Please see the code comments for setup details and explanations. The special put_dummy_secrets_on_stack() function may be of particular interest to understand the leaked output and attack conditions.

Code History

Note: this section has been updated to include new information.

By our understanding, this issue was introduced via a combination of two commits:

  1. This commit on Sep 8, 2020 (released with version 2.0.3)
  2. This commit merged on Jan 1, 2023 (released with version 2.4.0)

Commit 1) introduces the weak tmp buffer initialization, and commit 2) introduces problematic code paths and makes the issue reachable.

Patch

The main patch improves the problematic code paths in get_attribute_opaque():

    case CKA_SUBJECT:
    case CKA_ISSUER:
    case CKA_SERIAL_NUMBER:
+      *((CK_BYTE_PTR *) value) = NULL;
+      *length = 0;
      break;

d56f8567d4fe807dc097febbac7bb4e02ca9dea3

A second patch improves the buffer initialization:

-  CK_BYTE tmp[8192];
+  CK_BYTE tmp[8192] = {0};

util_pkcs11.c R5179

Additional references:

Security Implications

CVSS Score

The described security issue affects the confidentiality of program memory. Due to the characteristics of the flaw, we think that program memory integrity and program availability is not impacted.

As with other memory- and library-related vulnerabilities, it is difficult to say generally what the sensitive information in memory is going to be, and how the leaked information will be processed or exposed by the caller. As a result, the practical worst-case impact will likely be very target-dependent.

ID CVSS 3.1 Score Parameters
CVE-2023-39908 stack information leak 4.4 (Medium) AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:N/A:N

The listed scoring maps the impact on a network-enabled integrating program which allows a remote user to trigger the affected functionality and obtain secrets after some form of authentication as a high-privileged user. Other integrating programs that use the PKCS#11 driver may have different impacts. For example, if a lower-privileged user can trigger the issue, PR: L would turn this into a 5.3 CVSS base score (calculator).

Coordinated Disclosure

As outlined in the timeline, the first ~60 days out of the overall 90 days of disclosure did not see a lot of activity or feedback from the vendor side. This follows a pattern seen with previous coordinated disclosures to Yubico, which also had significant delays between reporting and technical discussion & assessment coordination with the vendor. We recommend focusing on a quicker initial handling for future disclosures to reduce the time pressure on coordination tasks. We want to positively mention that Yubico has provided security patches and an advisory on the disclosure date for this disclosure, which is an improvement over the previous issue.

Credits and Commercial Work

During work on integration of YubiHSM2 into an OpenPGP project, Heiko Schäfer found the memory safety issue. Christian Reitter assisted with triage, issue analysis, coordinated disclosure and report writeup. In references to this issue, please credit “Heiko Schäfer and Christian Reitter”.

Heiko Schäfer is available for commercial work with a focus on OpenPGP and Rust:

Relevant Sources

Variant Source Likely Affected Fix References
Yubico upstream GitHub 2.4.0 SDK 2023.08, 2.4.1 YSA-2023-01 advisory, CVE-2023-39908
Fedora package rpm package 2.4.0-1 2.4.1-1, commit bugzilla #2232340

We originally reproduced the issue with yubihsm-shell-2.4.0-1.fc38.x86_64 under Fedora. It appears that earlier versions before 2.4.0 do not contain the problematic code path, see here.

Detailed Timeline

Date Information
2023-05-18 Disclosure of issue to Yubico, including proof-of-concept code
2023-05-24 Response by Yubico, confirms recept of disclosure
2023-06-21 Request to Yubico for a status update and severity assessment
2023-07-17 Status update request to Yubico after lack of response
2023-07-17 Response by Yubico with technical details and CVSS scoring
2023-07-21 Message to Yubico, discussing proposed CVSS scoring & CVE
2023-07-25 Response by Yubico, discussing proposed CVSS scoring
2023-07-31 Message to Yubico, discussing proposed CVSS scoring & CVE
2023-08-02 Response by Yubico, outlining CVE assignment and disclosure date plans
2023-08-04 Response by Yubico, disclosure date plans
2023-08-05 Message to Yubico, acknowledgment
2023-08-14 Yubico publishes YSA-2023-01 and patch release
2023-08-14 Publication of this article
2023-08-16 Original end date of 90-day coordinated disclosure period
2023-08-23 Update of this article, revising version information, adding patch details

Bug Bounty

At the time of the disclosure, the vendor did not offer a bug bounty.