From de0cae0bcefdaf78eb60690d078d258237587a93 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Wed, 16 Sep 2026 18:04:45 -0700 Subject: [PATCH 1/2] F-13254 - Reject inconsistent class in C_GenerateKey templates --- src/crypto.c | 29 ++++++ tests/generate_key_class_test.c | 152 ++++++++++++++++++++++++++++++++ tests/include.am | 6 ++ 3 files changed, 187 insertions(+) create mode 100644 tests/generate_key_class_test.c diff --git a/src/crypto.c b/src/crypto.c index 61182614..0d7c6438 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -7448,6 +7448,35 @@ CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession, break; } + if (rv == CKR_OK) { + int idx; + + /* C_GenerateKey always yields a secret key of the mechanism-implied + * type. Reject a template that names a different class or key type + * rather than letting it override the generated object. Every + * occurrence is checked because a later duplicate would otherwise be + * applied by SetAttributeValue. The count is bounded to int as + * elsewhere so a caller-supplied length cannot drive an over-read. */ + for (idx = 0; idx < (int)ulCount && rv == CKR_OK; idx++) { + CK_ATTRIBUTE* attr = &pTemplate[idx]; + + if (attr->type == CKA_CLASS) { + if (attr->pValue == NULL || + attr->ulValueLen != sizeof(CK_OBJECT_CLASS)) + rv = CKR_ATTRIBUTE_VALUE_INVALID; + else if (*(CK_OBJECT_CLASS*)attr->pValue != CKO_SECRET_KEY) + rv = CKR_TEMPLATE_INCONSISTENT; + } + else if (attr->type == CKA_KEY_TYPE) { + if (attr->pValue == NULL || + attr->ulValueLen != sizeof(CK_KEY_TYPE)) + rv = CKR_ATTRIBUTE_VALUE_INVALID; + else if (*(CK_KEY_TYPE*)attr->pValue != keyType) + rv = CKR_TEMPLATE_INCONSISTENT; + } + } + } + if (rv == CKR_OK) { CK_ATTRIBUTE *lenAttr = NULL; diff --git a/tests/generate_key_class_test.c b/tests/generate_key_class_test.c new file mode 100644 index 00000000..76620a6c --- /dev/null +++ b/tests/generate_key_class_test.c @@ -0,0 +1,152 @@ +/* generate_key_class_test.c + * + * Copyright (C) 2006-2025 wolfSSL Inc. + * + * This file is part of wolfPKCS11. + * + * wolfPKCS11 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfPKCS11 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + * C_GenerateKey must reject a template whose CKA_CLASS or CKA_KEY_TYPE is + * inconsistent with the generation mechanism. + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include +#include + +#ifndef WOLFSSL_USER_SETTINGS + #include +#endif +#include +#include + +#ifndef WOLFPKCS11_USER_SETTINGS + #include +#endif +#include + +#ifndef HAVE_PKCS11_STATIC +#include +#endif + +#include "testdata.h" +#include "pkcs11_test_util.h" + +#define TEST_DIR "./store/generate_key_class_test" + +#ifndef NO_AES +static int run_test(void) +{ + CK_RV rv; + CK_SESSION_HANDLE session = 0; + CK_OBJECT_HANDLE key = CK_INVALID_HANDLE; + CK_MECHANISM mech = { CKM_AES_KEY_GEN, NULL, 0 }; + CK_ULONG valueLen = 16; + CK_OBJECT_CLASS dataClass = CKO_DATA; + CK_OBJECT_CLASS secretClass = CKO_SECRET_KEY; + CK_KEY_TYPE rsaType = CKK_RSA; + CK_KEY_TYPE aesType = CKK_AES; + CK_BBOOL ckFalse = CK_FALSE; + CK_ATTRIBUTE badClass[] = { + { CKA_VALUE_LEN, &valueLen, sizeof(valueLen) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, + { CKA_CLASS, &dataClass, sizeof(dataClass) }, + }; + CK_ATTRIBUTE badKeyType[] = { + { CKA_VALUE_LEN, &valueLen, sizeof(valueLen) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, + { CKA_KEY_TYPE, &rsaType, sizeof(rsaType) }, + }; + CK_ATTRIBUTE goodTmpl[] = { + { CKA_VALUE_LEN, &valueLen, sizeof(valueLen) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, + { CKA_CLASS, &secretClass, sizeof(secretClass) }, + { CKA_KEY_TYPE, &aesType, sizeof(aesType) }, + }; + CK_ATTRIBUTE minimalTmpl[] = { + { CKA_VALUE_LEN, &valueLen, sizeof(valueLen) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, + }; + CK_ATTRIBUTE dupClass[] = { + { CKA_VALUE_LEN, &valueLen, sizeof(valueLen) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, + { CKA_CLASS, &secretClass, sizeof(secretClass) }, + { CKA_CLASS, &dataClass, sizeof(dataClass) }, + }; + + rv = pkcs11_load(); + CHECK_RV(rv, "load library", CKR_OK); + if (rv != CKR_OK) + return -1; + + rv = pkcs11_open_session(&session); + CHECK_RV(rv, "open session", CKR_OK); + if (rv != CKR_OK) + goto out; + + rv = funcList->C_GenerateKey(session, &mech, badClass, + sizeof(badClass) / sizeof(*badClass), &key); + CHECK_RV(rv, "C_GenerateKey(inconsistent CKA_CLASS)", + CKR_TEMPLATE_INCONSISTENT); + + rv = funcList->C_GenerateKey(session, &mech, badKeyType, + sizeof(badKeyType) / sizeof(*badKeyType), + &key); + CHECK_RV(rv, "C_GenerateKey(inconsistent CKA_KEY_TYPE)", + CKR_TEMPLATE_INCONSISTENT); + + rv = funcList->C_GenerateKey(session, &mech, goodTmpl, + sizeof(goodTmpl) / sizeof(*goodTmpl), &key); + CHECK_RV(rv, "C_GenerateKey(consistent class and type)", CKR_OK); + + rv = funcList->C_GenerateKey(session, &mech, minimalTmpl, + sizeof(minimalTmpl) / sizeof(*minimalTmpl), + &key); + CHECK_RV(rv, "C_GenerateKey(no class in template)", CKR_OK); + + rv = funcList->C_GenerateKey(session, &mech, dupClass, + sizeof(dupClass) / sizeof(*dupClass), &key); + CHECK_RV(rv, "C_GenerateKey(duplicate inconsistent CKA_CLASS)", + CKR_TEMPLATE_INCONSISTENT); + +out: + if (session != 0) + funcList->C_CloseSession(session); + funcList->C_Finalize(NULL); + pkcs11_unload(); + return 0; +} +#endif /* !NO_AES */ + +int main(int argc, char* argv[]) +{ + (void)argc; + (void)argv; + +#ifndef WOLFPKCS11_NO_ENV + XSETENV("WOLFPKCS11_TOKEN_PATH", TEST_DIR, 1); +#endif + + printf("=== wolfPKCS11 C_GenerateKey class consistency test ===\n"); +#ifndef NO_AES + run_test(); +#else + printf("AES not compiled in!\n"); +#endif + return pkcs11_test_summary(); +} diff --git a/tests/include.am b/tests/include.am index 5af7cbba..15e87611 100644 --- a/tests/include.am +++ b/tests/include.am @@ -250,6 +250,10 @@ noinst_PROGRAMS += tests/hbs_persistence_test tests_hbs_persistence_test_SOURCES = tests/hbs_persistence_test.c tests_hbs_persistence_test_LDADD = +check_PROGRAMS += tests/generate_key_class_test +noinst_PROGRAMS += tests/generate_key_class_test +tests_generate_key_class_test_SOURCES = tests/generate_key_class_test.c +tests_generate_key_class_test_LDADD = if BUILD_STATIC tests_pkcs11test_LDADD += src/libwolfpkcs11.la tests_pkcs11mtt_LDADD += src/libwolfpkcs11.la @@ -301,6 +305,7 @@ tests_logout_token_key_zero_test_LDADD += src/libwolfpkcs11.la tests_tpm_decode_bounds_test_LDADD += src/libwolfpkcs11.la tests_concurrent_destroy_object_test_LDADD += src/libwolfpkcs11.la tests_hbs_persistence_test_LDADD += src/libwolfpkcs11.la +tests_generate_key_class_test_LDADD += src/libwolfpkcs11.la else tests_object_id_uniqueness_test_LDADD += src/libwolfpkcs11.la tests_empty_pin_store_test_LDADD += src/libwolfpkcs11.la @@ -344,6 +349,7 @@ tests_logout_token_key_zero_test_LDADD += src/libwolfpkcs11.la tests_tpm_decode_bounds_test_LDADD += src/libwolfpkcs11.la tests_concurrent_destroy_object_test_LDADD += src/libwolfpkcs11.la tests_hbs_persistence_test_LDADD += src/libwolfpkcs11.la +tests_generate_key_class_test_LDADD += src/libwolfpkcs11.la endif EXTRA_DIST += tests/unit.h \ From 93db94a06c9ea47a8e96466b60c356fe88585e93 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Wed, 16 Sep 2026 18:32:25 -0700 Subject: [PATCH 2/2] F-13255 - Reject inconsistent class in C_GenerateKeyPair templates --- src/crypto.c | 80 ++++++++++++++ tests/generate_keypair_class_test.c | 166 ++++++++++++++++++++++++++++ tests/include.am | 6 + 3 files changed, 252 insertions(+) create mode 100644 tests/generate_keypair_class_test.c diff --git a/src/crypto.c b/src/crypto.c index 0d7c6438..d2a63e38 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -7834,6 +7834,38 @@ CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession, * type of operation. * CKR_OK on success. */ +/* Reject a key-pair template whose CKA_CLASS or CKA_KEY_TYPE, in any position, + * disagrees with the class and type the mechanism implies. */ +static CK_RV CheckGenPairAttrs(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + CK_OBJECT_CLASS expectClass, + CK_KEY_TYPE expectType) +{ + int i; + + /* Bound the count to int as elsewhere so a caller-supplied length cannot + * drive an over-read past the template array. */ + for (i = 0; i < (int)ulCount; i++) { + CK_ATTRIBUTE* attr = &pTemplate[i]; + + if (attr->type == CKA_CLASS) { + if (attr->pValue == NULL || + attr->ulValueLen != sizeof(CK_OBJECT_CLASS)) + return CKR_ATTRIBUTE_VALUE_INVALID; + if (*(CK_OBJECT_CLASS*)attr->pValue != expectClass) + return CKR_TEMPLATE_INCONSISTENT; + } + else if (attr->type == CKA_KEY_TYPE) { + if (attr->pValue == NULL || + attr->ulValueLen != sizeof(CK_KEY_TYPE)) + return CKR_ATTRIBUTE_VALUE_INVALID; + if (*(CK_KEY_TYPE*)attr->pValue != expectType) + return CKR_TEMPLATE_INCONSISTENT; + } + } + + return CKR_OK; +} + CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, @@ -7849,6 +7881,8 @@ CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE hSession, WP11_Object* pub = NULL; WP11_Object* priv = NULL; CK_ATTRIBUTE* reqAttr = NULL; + CK_KEY_TYPE pairType = 0; + int knownMech = 1; WOLFPKCS11_ENTER("C_GenerateKeyPair"); #ifdef DEBUG_WOLFPKCS11 @@ -7917,6 +7951,52 @@ CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE hSession, return rv; } + /* Reject a template whose class or key type contradicts the mechanism + * before any object is constructed. */ + switch (pMechanism->mechanism) { +#if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) + case CKM_RSA_PKCS_KEY_PAIR_GEN: + pairType = CKK_RSA; + break; +#endif +#ifdef HAVE_ECC + case CKM_EC_KEY_PAIR_GEN: + pairType = CKK_EC; + break; +#endif +#ifdef WOLFPKCS11_MLDSA + case CKM_ML_DSA_KEY_PAIR_GEN: + pairType = CKK_ML_DSA; + break; +#endif +#ifdef WOLFPKCS11_MLKEM + case CKM_ML_KEM_KEY_PAIR_GEN: + pairType = CKK_ML_KEM; + break; +#endif +#ifndef NO_DH + case CKM_DH_PKCS_KEY_PAIR_GEN: + pairType = CKK_DH; + break; +#endif + default: + knownMech = 0; + break; + } + if (knownMech) { + rv = CheckGenPairAttrs(pPublicKeyTemplate, ulPublicKeyAttributeCount, + CKO_PUBLIC_KEY, pairType); + if (rv == CKR_OK) { + rv = CheckGenPairAttrs(pPrivateKeyTemplate, + ulPrivateKeyAttributeCount, CKO_PRIVATE_KEY, + pairType); + } + if (rv != CKR_OK) { + WOLFPKCS11_LEAVE("C_GenerateKeyPair", rv); + return rv; + } + } + switch (pMechanism->mechanism) { #if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) case CKM_RSA_PKCS_KEY_PAIR_GEN: diff --git a/tests/generate_keypair_class_test.c b/tests/generate_keypair_class_test.c new file mode 100644 index 00000000..eaad2114 --- /dev/null +++ b/tests/generate_keypair_class_test.c @@ -0,0 +1,166 @@ +/* generate_keypair_class_test.c + * + * Copyright (C) 2006-2025 wolfSSL Inc. + * + * This file is part of wolfPKCS11. + * + * wolfPKCS11 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfPKCS11 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + * C_GenerateKeyPair must reject public or private templates whose CKA_CLASS + * or CKA_KEY_TYPE is inconsistent with the mechanism. + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include +#include + +#ifndef WOLFSSL_USER_SETTINGS + #include +#endif +#include +#include + +#ifndef WOLFPKCS11_USER_SETTINGS + #include +#endif +#include + +#ifndef HAVE_PKCS11_STATIC +#include +#endif + +#include "testdata.h" +#include "pkcs11_test_util.h" + +#define TEST_DIR "./store/generate_keypair_class_test" + +#ifdef HAVE_ECC +static int run_test(void) +{ + CK_RV rv; + CK_SESSION_HANDLE session = 0; + CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE; + CK_MECHANISM mech = { CKM_EC_KEY_PAIR_GEN, NULL, 0 }; + CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY; + CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY; + CK_OBJECT_CLASS dataClass = CKO_DATA; + CK_KEY_TYPE ecType = CKK_EC; + CK_KEY_TYPE rsaType = CKK_RSA; + CK_BBOOL ckFalse = CK_FALSE; + CK_BBOOL ckTrue = CK_TRUE; + + CK_ATTRIBUTE goodPub[] = { + { CKA_EC_PARAMS, ecc_p256_params, sizeof(ecc_p256_params) }, + { CKA_CLASS, &pubClass, sizeof(pubClass) }, + { CKA_KEY_TYPE, &ecType, sizeof(ecType) }, + }; + CK_ATTRIBUTE goodPriv[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &ecType, sizeof(ecType) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, + }; + CK_ATTRIBUTE badPub[] = { + { CKA_EC_PARAMS, ecc_p256_params, sizeof(ecc_p256_params) }, + { CKA_CLASS, &privClass, sizeof(privClass) }, + }; + CK_ATTRIBUTE badPriv[] = { + { CKA_CLASS, &pubClass, sizeof(pubClass) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, + }; + CK_ATTRIBUTE badPubType[] = { + { CKA_EC_PARAMS, ecc_p256_params, sizeof(ecc_p256_params) }, + { CKA_KEY_TYPE, &rsaType, sizeof(rsaType) }, + }; + CK_ATTRIBUTE dupPub[] = { + { CKA_EC_PARAMS, ecc_p256_params, sizeof(ecc_p256_params) }, + { CKA_CLASS, &pubClass, sizeof(pubClass) }, + { CKA_CLASS, &dataClass, sizeof(dataClass) }, + }; + CK_ATTRIBUTE simplePriv[] = { + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) }, + }; + + rv = pkcs11_load(); + CHECK_RV(rv, "load library", CKR_OK); + if (rv != CKR_OK) + return -1; + + rv = pkcs11_open_session(&session); + CHECK_RV(rv, "open session", CKR_OK); + if (rv != CKR_OK) + goto out; + + rv = funcList->C_GenerateKeyPair(session, &mech, + badPub, sizeof(badPub) / sizeof(*badPub), + simplePriv, sizeof(simplePriv) / sizeof(*simplePriv), + &pub, &priv); + CHECK_RV(rv, "public template wrong CKA_CLASS", CKR_TEMPLATE_INCONSISTENT); + + rv = funcList->C_GenerateKeyPair(session, &mech, + goodPub, sizeof(goodPub) / sizeof(*goodPub), + badPriv, sizeof(badPriv) / sizeof(*badPriv), + &pub, &priv); + CHECK_RV(rv, "private template wrong CKA_CLASS", CKR_TEMPLATE_INCONSISTENT); + + rv = funcList->C_GenerateKeyPair(session, &mech, + badPubType, sizeof(badPubType) / sizeof(*badPubType), + simplePriv, sizeof(simplePriv) / sizeof(*simplePriv), + &pub, &priv); + CHECK_RV(rv, "public template wrong CKA_KEY_TYPE", + CKR_TEMPLATE_INCONSISTENT); + + rv = funcList->C_GenerateKeyPair(session, &mech, + dupPub, sizeof(dupPub) / sizeof(*dupPub), + simplePriv, sizeof(simplePriv) / sizeof(*simplePriv), + &pub, &priv); + CHECK_RV(rv, "public template duplicate CKA_CLASS", + CKR_TEMPLATE_INCONSISTENT); + + rv = funcList->C_GenerateKeyPair(session, &mech, + goodPub, sizeof(goodPub) / sizeof(*goodPub), + goodPriv, sizeof(goodPriv) / sizeof(*goodPriv), + &pub, &priv); + CHECK_RV(rv, "consistent templates", CKR_OK); + +out: + if (session != 0) + funcList->C_CloseSession(session); + funcList->C_Finalize(NULL); + pkcs11_unload(); + return 0; +} +#endif /* HAVE_ECC */ + +int main(int argc, char* argv[]) +{ + (void)argc; + (void)argv; + +#ifndef WOLFPKCS11_NO_ENV + XSETENV("WOLFPKCS11_TOKEN_PATH", TEST_DIR, 1); +#endif + + printf("=== wolfPKCS11 C_GenerateKeyPair class consistency test ===\n"); +#ifdef HAVE_ECC + run_test(); +#else + printf("ECC not compiled in!\n"); +#endif + return pkcs11_test_summary(); +} diff --git a/tests/include.am b/tests/include.am index 15e87611..23b4d683 100644 --- a/tests/include.am +++ b/tests/include.am @@ -254,6 +254,10 @@ check_PROGRAMS += tests/generate_key_class_test noinst_PROGRAMS += tests/generate_key_class_test tests_generate_key_class_test_SOURCES = tests/generate_key_class_test.c tests_generate_key_class_test_LDADD = +check_PROGRAMS += tests/generate_keypair_class_test +noinst_PROGRAMS += tests/generate_keypair_class_test +tests_generate_keypair_class_test_SOURCES = tests/generate_keypair_class_test.c +tests_generate_keypair_class_test_LDADD = if BUILD_STATIC tests_pkcs11test_LDADD += src/libwolfpkcs11.la tests_pkcs11mtt_LDADD += src/libwolfpkcs11.la @@ -306,6 +310,7 @@ tests_tpm_decode_bounds_test_LDADD += src/libwolfpkcs11.la tests_concurrent_destroy_object_test_LDADD += src/libwolfpkcs11.la tests_hbs_persistence_test_LDADD += src/libwolfpkcs11.la tests_generate_key_class_test_LDADD += src/libwolfpkcs11.la +tests_generate_keypair_class_test_LDADD += src/libwolfpkcs11.la else tests_object_id_uniqueness_test_LDADD += src/libwolfpkcs11.la tests_empty_pin_store_test_LDADD += src/libwolfpkcs11.la @@ -350,6 +355,7 @@ tests_tpm_decode_bounds_test_LDADD += src/libwolfpkcs11.la tests_concurrent_destroy_object_test_LDADD += src/libwolfpkcs11.la tests_hbs_persistence_test_LDADD += src/libwolfpkcs11.la tests_generate_key_class_test_LDADD += src/libwolfpkcs11.la +tests_generate_keypair_class_test_LDADD += src/libwolfpkcs11.la endif EXTRA_DIST += tests/unit.h \