From 1aca4fc9bd0f01659d2d676c194619cf4b5782b3 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Tue, 28 Apr 2026 14:39:35 +0000 Subject: [PATCH] tests/wolfssl-interoperability: add multi-call HMAC regression test The existing HMAC test runs against the token-wide session opened by wc_Pkcs11Token_Open, so every Pkcs11OpenSession returns the same handle and Update/Final share a session even when the dispatcher opens and closes one per call. That masks the bug where C_SignFinal on a fresh session returns CKR_OPERATION_NOT_INITIALIZED (WC_HW_E) because C_SignInit ran on a different session. The new test temporarily clears the token-wide handle (and userPin / userPinLogin to suppress per-open Login/Logout that would corrupt the slot's login state for subsequent tests) so each cryptocb dispatch genuinely opens a fresh PKCS#11 session, then restores. Uses a 32-byte key (wolfPKCS11 enforces ulMinKeySize=32 for CKM_SHA256_HMAC) and lets the dispatcher create the key inline on the same per-dispatch session as the sign operation. Compares the device-routed digest against a software reference. Also fix a pre-existing stack-use-after-scope on token->userPin caught by AddressSanitizer: wc_Pkcs11Token_Init stashes the userPin pointer on the token, and wc_Pkcs11Token_Final zeros memory through that pointer at main shutdown, but user_pin_l was a stack array in init_token whose storage was gone the moment init_token returned. Promote it to static. --- .../wolfssl-interoperability/pkcs11_interop.c | 90 ++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/tests/wolfssl-interoperability/pkcs11_interop.c b/tests/wolfssl-interoperability/pkcs11_interop.c index b08dfbfb..8cff984f 100644 --- a/tests/wolfssl-interoperability/pkcs11_interop.c +++ b/tests/wolfssl-interoperability/pkcs11_interop.c @@ -176,7 +176,8 @@ static int init_token(const char* module_path, Pkcs11Dev* dev, Pkcs11Token* token, CK_SLOT_ID* slot_id) { CK_UTF8CHAR so_pin[] = "password123456"; - CK_UTF8CHAR user_pin_l[] = "interop-user"; + /* Static: token->userPin retains the pointer past init_token. */ + static CK_UTF8CHAR user_pin_l[] = "interop-user"; static const char token_label_text[] = "wolfPKCS11-Interop"; CK_UTF8CHAR label[32]; CK_RV rv; @@ -409,6 +410,84 @@ static int test_hmac_sha256(Pkcs11Token* token, int dev_id) return ret; } +/* Multi-call HMAC must run on the same PKCS#11 session; the default + * token-wide session masks the bug, so clear it for this test. */ +static int test_hmac_sha256_per_call_session(Pkcs11Token* token, int dev_id) +{ + /* wolfPKCS11 enforces ulMinKeySize=32 for CKM_SHA256_HMAC. */ + static const byte key[32] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + }; + static const byte msg[] = "wolfPKCS11 multi-call HMAC dispatch"; + CK_SESSION_HANDLE saved_handle = token->handle; + CK_UTF8CHAR_PTR saved_userPin = token->userPin; + byte saved_userPinLogin = token->userPinLogin; + Hmac hmac; + Hmac swHmac; + byte digest[WC_SHA256_DIGEST_SIZE]; + byte ref[WC_SHA256_DIGEST_SIZE]; + int hmacInited = 0; + int swInited = 0; + int ret; + + ret = wc_HmacInit(&swHmac, NULL, INVALID_DEVID); + if (ret != 0) + return ret; + swInited = 1; + ret = wc_HmacSetKey(&swHmac, WC_SHA256, key, (word32)sizeof(key)); + if (ret == 0) + ret = wc_HmacUpdate(&swHmac, msg, (word32)(sizeof(msg) - 1)); + if (ret == 0) + ret = wc_HmacFinal(&swHmac, ref); + if (ret != 0) + goto done; + + /* Force per-dispatch sessions; skip Login/Logout (slot already + * logged in) so subsequent tests aren't affected. */ + token->handle = CK_INVALID_HANDLE; + token->userPin = NULL; + token->userPinLogin = 0; + + ret = wc_HmacInit(&hmac, NULL, dev_id); + if (ret != 0) + goto restore; + hmacInited = 1; + + ret = wc_HmacSetKey(&hmac, WC_SHA256, key, (word32)sizeof(key)); + if (ret != 0) + goto restore; + + ret = wc_HmacUpdate(&hmac, msg, (word32)(sizeof(msg) - 1)); + if (ret != 0) + goto restore; + + ret = wc_HmacFinal(&hmac, digest); + if (ret != 0) + goto restore; + + if (compare_bytes(digest, ref, sizeof(digest)) != 0) { + dump_buffer("hmac", digest, sizeof(digest)); + dump_buffer("hmac-ref", ref, sizeof(ref)); + ret = WC_HW_E; + } + +restore: + /* Free Hmac before restore so cleanup runs without triggering + * Logout via the now-restored userPin. */ + if (hmacInited) + wc_HmacFree(&hmac); + token->handle = saved_handle; + token->userPin = saved_userPin; + token->userPinLogin = saved_userPinLogin; +done: + if (swInited) + wc_HmacFree(&swHmac); + return ret; +} + #ifdef WOLFSSL_SHA224 static int test_sha224_digest(int dev_id) { @@ -1117,6 +1196,15 @@ int main(int argc, char** argv) printf("HMAC-SHA256 test_passed!\n"); } + ret = test_hmac_sha256_per_call_session(&token, dev_id); + if (ret != 0) { + fprintf(stderr, "HMAC-SHA256 per-call session test failed: %d (%s)\n", + ret, error_to_string(ret)); + failures++; + } else { + printf("HMAC-SHA256 per-call session test_passed!\n"); + } + #ifdef WOLFSSL_SHA224 ret = test_sha224_digest(dev_id); if (ret != 0) {