Skip to content

Support secret-key concatenation for hybrid ECDH/ML-KEM derivation #264

Closed

Description

@amnagmv

We're evaluating wolfPKCS11 for a hybrid key agreement using P-256 and ML-KEM-768. Our application uses the concatenation construction described in ETSI TS 103 744, clause 8.2.3:

IKM = PSK || Z_ECDH || Z_MLKEM

The PSK is optional. Each contribution is 32 bytes, so the combined input is 64 bytes without a PSK or 96 bytes with one. We then use HKDF-SHA-256 to derive the protocol keys.

We would like to keep the agreement contributions and combined input in sensitive, non-extractable PKCS#11 objects. The missing step in our tests is concatenating those objects before calling native HKDF.

Our test environment uses:

  • Linux in Docker, with the software backend.
  • wolfPKCS11 v2.2.0-stable, commit dbf5bd4.
  • wolfSSL 5.9.4, commit 3c5eead44904df64e6a5a1f4ebdce377d35a849a.
  • wolfPKCS11 configured with --enable-pkcs11v32 --enable-mlkem --enable-hkdf --enable-pbkdf2.

Separate native C tests passed for P-256 ECDH, ML-KEM-768 encapsulation/decapsulation, and HKDF-SHA-256 deriving a protected AES-256 key. These are component tests; we have not completed the full hybrid schedule.

To reproduce the concatenation result:

  1. Initialize a fresh token and log in to a read/write session.
  2. Import a 32-byte zero-filled test value as a CKK_GENERIC_SECRET, with CKA_SENSITIVE = CK_TRUE, CKA_EXTRACTABLE = CK_FALSE, and CKA_DERIVE = CK_TRUE.
  3. Obtain a second 32-byte CKK_GENERIC_SECRET from ML-KEM-768, with the same protection and derivation attributes.
  4. Call C_DeriveKey with CKM_CONCATENATE_BASE_AND_KEY (0x00000360). Pass the second object's handle as the mechanism parameter and request a 64-byte generic secret with the same protection attributes.

The call returns:

CKR_MECHANISM_INVALID (0x00000070)

We also checked the default branch's mechanism registry and derivation dispatch, but could not find this mechanism. The runtime result above is from the released version.

Would you consider adding CKM_CONCATENATE_BASE_AND_KEY? We'd expect it to create the ordered concatenation as another protected secret object, following PKCS#11's applicable attribute rules, so it can serve as the base key for CKM_HKDF_DERIVE.

The related CKM_CONCATENATE_BASE_AND_DATA and CKM_CONCATENATE_DATA_AND_BASE mechanisms would also be useful, although joining secret-key objects is our immediate requirement.

If an existing supported operation can produce the same concatenated input without exporting the contributions through the application API, we'd appreciate guidance on that path.

Activity

  1. Frauschi commented on Nov 2, 2026

    @Frauschi
    Member

    Hi @amnagmv,

    Thank you very much for this issue report and feature request. I am Tobias and a member of the wolfSSL team. As this feature is only a tiny change and it overlapped with some fixes I had intended anyway for the library, I went ahead and implemented it. Please see PR #279 for it.

    It would be awesome if you could test the implementation on your end to validate it works as intended for your use case. Thanks already!

  2. added a commit that references this issue on Nov 2, 2026
    ea18833
  3. amnagmv commented on Nov 2, 2026

    @amnagmv
    Author

    Thanks, @Frauschi. We tested PR #279 at 1a2f20a18c8597f84f5b3b1a19367f79f077ffb7 with wolfSSL 5.9.4 and the same configure options as our original report.

    Our v2.2.0 control reproduces CKR_MECHANISM_INVALID (0x70), while your branch succeeds on the original call.

    We also exercised real P-256 ECDH and ML-KEM-768, constructed protected 64-byte and 96-byte IKM (without and with a 32-byte PSK), and used native HKDF-SHA-256 to derive protected AES-256/HMAC keys. Protection attributes, denied value reads, encryption/MAC use and tamper rejection passed. Known-answer HMAC checks also matched for both input constructions.

    This resolves the original blocker in our probe. Thanks for implementing this.

  4. added a commit that references this issue on Nov 2, 2026
    f5370f6
  5. added a commit that references this issue on Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions