/* wc_pkcs11.c * * Copyright (C) 2006-2026 wolfSSL Inc. * * This file is part of wolfSSL. * * wolfSSL 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. * * wolfSSL 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 */ #include #ifdef HAVE_PKCS11 #ifndef HAVE_PKCS11_STATIC #include #endif #include #include #ifndef NO_RSA #include #endif #ifdef NO_INLINE #include #else #define WOLFSSL_MISC_INCLUDED #include #endif #ifndef WOLFSSL_HAVE_ECC_KEY_GET_PRIV /* FIPS build has replaced ecc.h. */ #define wc_ecc_key_get_priv(key) (&((key)->k)) #define WOLFSSL_HAVE_ECC_KEY_GET_PRIV #endif #if defined(NO_PKCS11_RSA) && !defined(NO_RSA) #define NO_RSA #endif #if defined(NO_PKCS11_ECC) && defined(HAVE_ECC) #undef HAVE_ECC #endif #if defined(NO_PKCS11_AES) && !defined(NO_AES) #define NO_AES #endif #if defined(NO_PKCS11_AESGCM) && defined(HAVE_AESGCM) #undef HAVE_AESGCM #endif #if defined(NO_PKCS11_AESCBC) && defined(HAVE_AES_CBC) #undef HAVE_AES_CBC #endif #if defined(NO_PKCS11_HMAC) && !defined(NO_HMAC) #define NO_HMAC #endif #if defined(NO_PKCS11_RNG) && !defined(WC_NO_RNG) #define WC_NO_RNG #endif #if defined(NO_PKCS11_MLDSA) && defined(HAVE_DILITHIUM) #undef HAVE_DILITHIUM #endif #if defined(NO_PKCS11_MLKEM) && defined(WOLFSSL_HAVE_MLKEM) #undef WOLFSSL_HAVE_MLKEM #endif #if (defined(HAVE_ECC) && !defined(NO_PKCS11_ECDH)) || \ defined(WOLFSSL_HAVE_MLKEM) /* Pointer to false required for templates. */ static CK_BBOOL ckFalse = CK_FALSE; #endif #if !defined(NO_RSA) || defined(HAVE_ECC) || (!defined(NO_AES) && \ (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || \ !defined(NO_HMAC) || defined(HAVE_DILITHIUM) || \ defined(WOLFSSL_HAVE_MLKEM) /* Pointer to true required for templates. */ static CK_BBOOL ckTrue = CK_TRUE; #endif #ifndef NO_RSA /* Pointer to RSA key type required for templates. */ static CK_KEY_TYPE rsaKeyType = CKK_RSA; #endif #ifdef HAVE_ECC /* Pointer to EC key type required for templates. */ static CK_KEY_TYPE ecKeyType = CKK_EC; #endif #if defined(WOLFSSL_HAVE_MLKEM) /* Pointer to ML-KEM key type required for templates. */ static CK_KEY_TYPE mlkemKeyType = CKK_ML_KEM; #endif #if defined(HAVE_DILITHIUM) /* Pointer to ML-DSA key type required for templates. */ static CK_KEY_TYPE mldsaKeyType = CKK_ML_DSA; #endif #if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_DILITHIUM) || \ defined(WOLFSSL_HAVE_MLKEM) /* Pointer to public key class required for templates. */ static CK_OBJECT_CLASS pubKeyClass = CKO_PUBLIC_KEY; /* Pointer to private key class required for templates. */ static CK_OBJECT_CLASS privKeyClass = CKO_PRIVATE_KEY; #endif #if (!defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || \ !defined(NO_HMAC) || (defined(HAVE_ECC) && !defined(NO_PKCS11_ECDH)) || \ defined(WOLFSSL_HAVE_MLKEM) /* Pointer to secret key class required for templates. */ static CK_OBJECT_CLASS secretKeyClass = CKO_SECRET_KEY; #endif #if (!defined(NO_AES) && (defined(WOLFSSL_AES_COUNTER))) /* AES CTR parameter structure for PKCS#11. */ typedef struct CK_AES_CTR_PARAMS { CK_ULONG ulCounterBits; CK_BYTE cb[WC_AES_BLOCK_SIZE]; } CK_AES_CTR_PARAMS; #endif #if !defined(NO_CERTS) static CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; #endif #ifdef WOLFSSL_DEBUG_PKCS11 /* Enable logging of PKCS#11 calls and return value. */ #define PKCS11_RV(op, rv) pkcs11_rv(op, rv) /* Enable logging of PKCS#11 calls and value. */ #define PKCS11_VAL(op, val) pkcs11_val(op, val) /* Enable logging of PKCS#11 template. */ #define PKCS11_DUMP_TEMPLATE(name, templ, cnt) \ pkcs11_dump_template(name, templ, cnt) /* Enable logging of PKCS#11 mechanism info. */ #define PKCS11_DUMP_MECHANSIM(name, mechanism) \ pkcs11_dump_mechanism(name, mechanism) /* Formats of template items - used to instruct how to log information. */ enum PKCS11_TYPE_FORMATS { PKCS11_FMT_BOOLEAN, PKCS11_FMT_CLASS, PKCS11_FMT_KEY_TYPE, PKCS11_FMT_STRING, PKCS11_FMT_NUMBER, PKCS11_FMT_DATA, PKCS11_FMT_POINTER }; /* Information for logging a template item. */ static struct PKCS11_TYPE_STR { /** Attribute type in template. */ CK_ATTRIBUTE_TYPE type; /** String to log corresponding to attribute type. */ const char* str; /** Format of data associated with template item. */ int format; } typeStr[] = { { CKA_CLASS, "CKA_CLASS", PKCS11_FMT_CLASS }, { CKA_TOKEN, "CKA_TOKEN", PKCS11_FMT_BOOLEAN }, { CKA_PRIVATE, "CKA_PRIVATE", PKCS11_FMT_BOOLEAN }, { CKA_LABEL, "CKA_LABEL", PKCS11_FMT_STRING }, { CKA_VALUE, "CKA_VALUE", PKCS11_FMT_DATA }, { CKA_OBJECT_ID, "CKA_OBJECT_ID", PKCS11_FMT_POINTER }, { CKA_KEY_TYPE, "CKA_KEY_TYPE", PKCS11_FMT_KEY_TYPE }, { CKA_ID, "CKA_ID", PKCS11_FMT_DATA }, { CKA_SENSITIVE, "CKA_SENSITIVE", PKCS11_FMT_BOOLEAN }, { CKA_ENCRYPT, "CKA_ENCRYPT", PKCS11_FMT_BOOLEAN }, { CKA_DECRYPT, "CKA_DECRYPT", PKCS11_FMT_BOOLEAN }, { CKA_SIGN, "CKA_SIGN", PKCS11_FMT_BOOLEAN }, { CKA_VERIFY, "CKA_VERIFY", PKCS11_FMT_BOOLEAN }, { CKA_DERIVE, "CKA_DERIVE", PKCS11_FMT_BOOLEAN }, { CKA_MODULUS_BITS, "CKA_MODULUS_BITS", PKCS11_FMT_NUMBER }, { CKA_MODULUS, "CKA_MODULUS", PKCS11_FMT_DATA }, { CKA_PUBLIC_EXPONENT, "CKA_PUBLIC_EXPONENT", PKCS11_FMT_DATA }, { CKA_PRIVATE_EXPONENT, "CKA_PRIVATE_EXPONENT", PKCS11_FMT_DATA }, { CKA_PRIME_1, "CKA_PRIME_1", PKCS11_FMT_DATA }, { CKA_PRIME_2, "CKA_PRIME_2", PKCS11_FMT_DATA }, { CKA_EXPONENT_1, "CKA_EXPONENT_1", PKCS11_FMT_DATA }, { CKA_EXPONENT_2, "CKA_EXPONENT_2", PKCS11_FMT_DATA }, { CKA_VALUE_LEN, "CKA_VALUE_LEN", PKCS11_FMT_NUMBER }, { CKA_COEFFICIENT, "CKA_COEFFICIENT", PKCS11_FMT_DATA }, { CKA_EXTRACTABLE, "CKA_EXTRACTABLE", PKCS11_FMT_BOOLEAN }, { CKA_EC_PARAMS, "CKA_EC_PARAMS", PKCS11_FMT_DATA }, { CKA_EC_POINT, "CKA_EC_POINT", PKCS11_FMT_DATA }, { CKA_ENCAPSULATE, "CKA_ENCAPSULATE", PKCS11_FMT_BOOLEAN }, { CKA_DECAPSULATE, "CKA_DECAPSULATE", PKCS11_FMT_BOOLEAN }, { CKA_PARAMETER_SET, "CKA_PARAMETER_SET", PKCS11_FMT_NUMBER }, }; /* Count of known attribute types for logging. */ #define PKCS11_TYPE_STR_CNT ((int)(sizeof(typeStr) / sizeof(*typeStr))) /* * Dump/log the PKCS #11 template. * * This is only for debugging purposes. Only the values needed are recognised. * * @param [in] name PKCS #11 template name. * @param [in] templ PKCS #11 template to dump. * @param [in] cnt Count of template entries. */ static void pkcs11_dump_template(const char* name, CK_ATTRIBUTE* templ, CK_ULONG cnt) { CK_ULONG i; int j; char line[80]; char type[25]; int format; CK_KEY_TYPE keyType; CK_OBJECT_CLASS keyClass; WOLFSSL_MSG(name); for (i = 0; i < cnt; i++) { format = PKCS11_FMT_POINTER; for (j = 0; j < PKCS11_TYPE_STR_CNT; j++) { if (templ[i].type == typeStr[j].type) { XSNPRINTF(type, sizeof(type), "%s", typeStr[j].str); format = typeStr[j].format; break; } } if (j == PKCS11_TYPE_STR_CNT) { XSNPRINTF(type, sizeof(type), "%08lxUL", templ[i].type); } switch (format) { case PKCS11_FMT_BOOLEAN: #if !defined(NO_RSA) || defined(HAVE_ECC) || (!defined(NO_AES) && \ (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || !defined(NO_HMAC) if (templ[i].pValue == &ckTrue) { XSNPRINTF(line, sizeof(line), "%25s: TRUE", type); WOLFSSL_MSG(line); } else #endif #if defined(HAVE_ECC) && !defined(NO_PKCS11_ECDH) if (templ[i].pValue == &ckFalse) { XSNPRINTF(line, sizeof(line), "%25s: FALSE", type); WOLFSSL_MSG(line); } else #endif { XSNPRINTF(line, sizeof(line), "%25s: INVALID (%p)", type, templ[i].pValue); WOLFSSL_MSG(line); } break; case PKCS11_FMT_CLASS: keyClass = *(CK_OBJECT_CLASS*)templ[i].pValue; if (keyClass == CKO_PUBLIC_KEY) { XSNPRINTF(line, sizeof(line), "%25s: PUBLIC", type); WOLFSSL_MSG(line); } else if (keyClass == CKO_PRIVATE_KEY) { XSNPRINTF(line, sizeof(line), "%25s: PRIVATE", type); WOLFSSL_MSG(line); } else if (keyClass == CKO_SECRET_KEY) { XSNPRINTF(line, sizeof(line), "%25s: SECRET", type); WOLFSSL_MSG(line); } else if (keyClass == CKO_CERTIFICATE) { XSNPRINTF(line, sizeof(line), "%25s: CERTIFICATE", type); WOLFSSL_MSG(line); } else { XSNPRINTF(line, sizeof(line), "%25s: UNKNOWN (%p)", type, templ[i].pValue); WOLFSSL_MSG(line); } break; case PKCS11_FMT_KEY_TYPE: keyType = *(CK_KEY_TYPE*)templ[i].pValue; switch (keyType) { case CKK_RSA: XSNPRINTF(line, sizeof(line), "%25s: RSA", type); break; case CKK_DH: XSNPRINTF(line, sizeof(line), "%25s: DH", type); break; case CKK_EC: XSNPRINTF(line, sizeof(line), "%25s: EC", type); break; case CKK_GENERIC_SECRET: XSNPRINTF(line, sizeof(line), "%25s: GENERIC_SECRET", type); break; case CKK_AES: XSNPRINTF(line, sizeof(line), "%25s: AES", type); break; case CKK_MD5_HMAC: XSNPRINTF(line, sizeof(line), "%25s: MD5_HMAC", type); break; case CKK_SHA_1_HMAC: XSNPRINTF(line, sizeof(line), "%25s: SHA_1_HMAC", type); break; case CKK_SHA256_HMAC: XSNPRINTF(line, sizeof(line), "%25s: SHA256_HMAC", type); break; case CKK_SHA384_HMAC: XSNPRINTF(line, sizeof(line), "%25s: SHA384_HMAC", type); break; case CKK_SHA512_HMAC: XSNPRINTF(line, sizeof(line), "%25s: SHA512_HMAC", type); break; case CKK_SHA224_HMAC: XSNPRINTF(line, sizeof(line), "%25s: SHA224_HMAC", type); break; case CKK_ML_DSA: XSNPRINTF(line, sizeof(line), "%25s: ML_DSA", type); break; case CKK_ML_KEM: XSNPRINTF(line, sizeof(line), "%25s: ML_KEM", type); break; default: XSNPRINTF(line, sizeof(line), "%25s: UNKNOWN (%08lx)", type, keyType); break; } WOLFSSL_MSG(line); break; case PKCS11_FMT_STRING: XSNPRINTF(line, sizeof(line), "%25s: %s", type, (char*)templ[i].pValue); WOLFSSL_MSG(line); break; case PKCS11_FMT_NUMBER: if (templ[i].ulValueLen <= 1) { XSNPRINTF(line, sizeof(line), "%25s: 0x%02x (%d)", type, *(byte*)templ[i].pValue, *(byte*)templ[i].pValue); } else if (templ[i].ulValueLen <= 2) { XSNPRINTF(line, sizeof(line), "%25s: 0x%04x (%d)", type, *(word16*)templ[i].pValue, *(word16*)templ[i].pValue); } else if (templ[i].ulValueLen <= 4) { XSNPRINTF(line, sizeof(line), "%25s: 0x%08x (%d)", type, *(word32*)templ[i].pValue, *(word32*)templ[i].pValue); } else if (templ[i].ulValueLen <= 8) { XSNPRINTF(line, sizeof(line), "%25s: 0x%016lx (%ld)", type, *(word64*)templ[i].pValue, *(word64*)templ[i].pValue); } else { XSNPRINTF(line, sizeof(line), "%25s: INVALID (%ld)", type, templ[i].ulValueLen); } WOLFSSL_MSG(line); break; case PKCS11_FMT_DATA: if (templ[i].ulValueLen == CK_UNAVAILABLE_INFORMATION) { XSNPRINTF(line, sizeof(line), "%25s: unavailable", type); WOLFSSL_MSG(line); break; } XSNPRINTF(line, sizeof(line), "%25s: %ld", type, templ[i].ulValueLen); WOLFSSL_MSG(line); if (templ[i].pValue == NULL) { XSNPRINTF(line, sizeof(line), "%27s(nil)", ""); WOLFSSL_MSG(line); break; } XSNPRINTF(line, sizeof(line), "%27s", ""); for (j = 0; j < (int)templ[i].ulValueLen && j < 80; j++) { char hex[6]; XSNPRINTF(hex, sizeof(hex), "0x%02x,", ((byte*)templ[i].pValue)[j]); XSTRNCAT(line, hex, sizeof(line) - XSTRLEN(line) - 1); if ((j % 8) == 7) { WOLFSSL_MSG(line); XSNPRINTF(line, sizeof(line), "%27s", ""); } } if (j == (int)templ[i].ulValueLen) { if ((j % 8) != 0) { WOLFSSL_MSG(line); } } else if (j < (int)templ[i].ulValueLen) { XSNPRINTF(line, sizeof(line), "%27s...", ""); WOLFSSL_MSG(line); } break; case PKCS11_FMT_POINTER: XSNPRINTF(line, sizeof(line), "%25s: %p %ld", type, templ[i].pValue, templ[i].ulValueLen); WOLFSSL_MSG(line); break; } } } /* Information for logging a mechanism */ static struct PKCS11_MECHANISM_STR { /** Mechanism. */ CK_MECHANISM_TYPE mech; /** String to log corresponding mechanism. */ const char* str; } mechStr[] = { { CKM_RSA_PKCS_KEY_PAIR_GEN, "CKM_RSA_PKCS_KEY_PAIR_GEN" }, { CKM_RSA_X_509, "CKM_RSA_X_509" }, { CKM_DH_PKCS_KEY_PAIR_GEN, "CKM_DH_PKCS_KEY_PAIR_GEN" }, { CKM_DH_PKCS_DERIVE, "CKM_DH_PKCS_DERIVE" }, { CKM_MD5_HMAC, "CKM_MD5_HMAC" }, { CKM_SHA_1_HMAC, "CKM_SHA_1_HMAC" }, { CKM_SHA256_HMAC, "CKM_SHA256_HMAC" }, { CKM_SHA224_HMAC, "CKM_SHA224_HMAC" }, { CKM_SHA384_HMAC, "CKM_SHA384_HMAC" }, { CKM_SHA512_HMAC, "CKM_SHA512_HMAC" }, { CKM_GENERIC_SECRET_KEY_GEN, "CKM_GENERIC_SECRET_KEY_GEN" }, { CKM_EC_KEY_PAIR_GEN, "CKM_EC_KEY_PAIR_GEN" }, { CKM_ECDSA, "CKM_ECDSA" }, { CKM_ECDH1_DERIVE, "CKM_ECDH1_DERIVE" }, { CKM_ECDH1_COFACTOR_DERIVE, "CKM_ECDH1_COFACTOR_DERIVE" }, { CKM_AES_KEY_GEN, "CKM_AES_KEY_GEN" }, { CKM_AES_CBC, "CKM_AES_CBC" }, { CKM_AES_GCM, "CKM_AES_GCM" }, { CKM_ML_KEM_KEY_PAIR_GEN, "CKM_ML_KEM_KEY_PAIR_GEN" }, { CKM_ML_KEM, "CKM_ML_KEM" }, { CKM_ML_DSA_KEY_PAIR_GEN, "CKM_ML_DSA_KEY_PAIR_GEN" }, { CKM_ML_DSA, "CKM_ML_DSA" }, { CKM_HASH_ML_DSA, "CKM_HASH_ML_DSA" }, }; /* Count of known mechanism for logging. */ #define PKCS11_MECH_STR_CNT ((int)(sizeof(mechStr) / sizeof(*mechStr))) /* * Dump/log the PKCS #11 mechanism. * * This is only for debugging purposes. Only the values needed are recognised. * * @param [in] op PKCS #11 operation that was attempted. * @param [in] mech PKCS #11 mechanism to dump. */ static void pkcs11_dump_mechanism(const char* op, CK_MECHANISM_TYPE mech) { char line[80]; const char *mechName = NULL; int i; for (i = 0; i < PKCS11_MECH_STR_CNT; i++) { if (mech == mechStr[i].mech) { mechName = mechStr[i].str; break; } } if (i == PKCS11_MECH_STR_CNT) { mechName = "UNKNOWN"; } XSNPRINTF(line, 80, "%s: %s", op, mechName); WOLFSSL_MSG(line); } /* * Log a PKCS #11 return value with the name of function called. * * This is only for debugging purposes. Only the values needed are recognized. * * @param [in] op PKCS #11 operation that was attempted. * @param [in] rv PKCS #11 return value. */ static void pkcs11_rv(const char* op, CK_RV rv) { char line[80]; if (rv == CKR_OK) { XSNPRINTF(line, 80, "%s: OK", op); } else if (rv == CKR_MECHANISM_INVALID) { XSNPRINTF(line, 80, "%s: MECHANISM_INVALID", op); } else if (rv == CKR_SIGNATURE_INVALID) { XSNPRINTF(line, 80, "%s: SIGNATURE_INVALID", op); } else { XSNPRINTF(line, 80, "%s: %08lxUL (FAILED)", op, rv); } WOLFSSL_MSG(line); } /* * Log a value from a PKCS #11 operation. * * This is only for debugging purposes. * * @param [in] op PKCS #11 operation that was attempted. * @param [in] val Value to log. */ static void pkcs11_val(const char* op, CK_ULONG val) { char line[80]; XSNPRINTF(line, 80, "%s: %ld", op, val); WOLFSSL_MSG(line); } #else /* Disable logging of PKCS#11 calls and return value. */ #define PKCS11_RV(op, ev) WC_DO_NOTHING /* Disable logging of PKCS#11 calls and value. */ #define PKCS11_VAL(op, val) WC_DO_NOTHING /* Disable logging of PKCS#11 template. */ #define PKCS11_DUMP_TEMPLATE(name, templ, cnt) WC_DO_NOTHING /* Disable logging of PKCS#11 mechanism info. */ #define PKCS11_DUMP_MECHANSIM(name, mechanism) WC_DO_NOTHING #endif /** * Load library, get function list and initialize PKCS#11. * * @param [in] dev Device object. * @param [in] library Library name including path. * @param [in] heap Heap hint. * @return BAD_FUNC_ARG when dev or library are NULL pointers. * @return BAD_PATH_ERROR when dynamic library cannot be opened. * @return WC_INIT_E when the initialization PKCS#11 fails. * @return WC_HW_E when unable to get PKCS#11 function list. * @return 0 on success. */ int wc_Pkcs11_Initialize(Pkcs11Dev* dev, const char* library, void* heap) { return wc_Pkcs11_Initialize_v3(dev, library, heap, NULL, NULL, NULL); } /** * Load library, get function list and initialize PKCS#11. * * @param [in] dev Device object. * @param [in] library Library name including path. * @param [in] heap Heap hint. * @param [out] rvp PKCS#11 return value. Last return value seen. * May be NULL. * @return BAD_FUNC_ARG when dev or library are NULL pointers. * @return BAD_PATH_ERROR when dynamic library cannot be opened. * @return WC_INIT_E when the initialization PKCS#11 fails. * @return WC_HW_E when unable to get PKCS#11 function list. * @return 0 on success. */ int wc_Pkcs11_Initialize_ex(Pkcs11Dev* dev, const char* library, void* heap, CK_RV* rvp) { return wc_Pkcs11_Initialize_v3(dev, library, heap, NULL, NULL, rvp); } /** * Load library, get function list and initialize PKCS#11. * * @param [in] dev Device object. * @param [in] library Library name including path. * @param [in] heap Heap hint. * @param [in,out] version On in, desired version of interface. * On out, actual obtained version of interface. * @param [in] interfaceName Name of the interface to use. * @param [out] rvp PKCS#11 return value. Last return value seen. * May be NULL. * @return BAD_FUNC_ARG when dev or library are NULL pointers. * @return BAD_PATH_ERROR when dynamic library cannot be opened. * @return WC_INIT_E when the initialization PKCS#11 fails. * @return WC_HW_E when unable to get PKCS#11 function list. * @return 0 on success. */ int wc_Pkcs11_Initialize_v3(Pkcs11Dev* dev, const char* library, void* heap, int* version, const char* interfaceName, CK_RV* rvp) { int ret = 0; CK_RV rv = CKR_OK; #if !defined(HAVE_PKCS11_STATIC) && !defined(HAVE_PKCS11_V3_STATIC) void* func; #endif CK_C_INITIALIZE_ARGS args; CK_VERSION_PTR version_ptr = NULL; if (dev == NULL) ret = BAD_FUNC_ARG; #if !defined(HAVE_PKCS11_STATIC) && !defined(HAVE_PKCS11_V3_STATIC) if (library == NULL) ret = BAD_FUNC_ARG; #endif if (ret == 0) { dev->heap = heap; #if defined(HAVE_PKCS11_V3_STATIC) CK_INTERFACE_PTR interface = NULL; CK_VERSION pkcs11_version = {0, 0}; if (version != NULL) { if (*version == WC_PCKS11VERSION_2_20) { pkcs11_version.major = 2; pkcs11_version.minor = 20; } else if (*version == WC_PCKS11VERSION_2_40) { pkcs11_version.major = 2; pkcs11_version.minor = 40; } else if (*version == WC_PCKS11VERSION_3_0) { pkcs11_version.major = 3; pkcs11_version.minor = 0; } else if (*version == WC_PCKS11VERSION_3_1) { pkcs11_version.major = 3; pkcs11_version.minor = 1; } else if (*version == WC_PCKS11VERSION_3_2) { pkcs11_version.major = 3; pkcs11_version.minor = 2; } version_ptr = &pkcs11_version; } else { version_ptr = NULL; } rv = C_GetInterface((CK_UTF8CHAR_PTR) interfaceName, version_ptr, &interface, 0); if (rv == CKR_OK) { dev->func = interface->pFunctionList; version_ptr = (CK_VERSION_PTR) interface->pFunctionList; if (version_ptr->major == 2 && version_ptr->minor == 20) { dev->version = WC_PCKS11VERSION_2_20; } else if (version_ptr->major == 2 && version_ptr->minor == 40) { dev->version = WC_PCKS11VERSION_2_40; } else if (version_ptr->major == 3 && version_ptr->minor == 0) { dev->version = WC_PCKS11VERSION_3_0; } else if (version_ptr->major == 3 && version_ptr->minor == 1) { dev->version = WC_PCKS11VERSION_3_1; } else if (version_ptr->major == 3 && version_ptr->minor == 2) { dev->version = WC_PCKS11VERSION_3_2; } else { WOLFSSL_MSG_EX("Unsupported PKCS#11 version: %d.%d", version_ptr->major, version_ptr->minor); ret = WC_HW_E; } } else { PKCS11_RV("CK_C_GetInterface", rv); ret = WC_HW_E; } #elif defined(HAVE_PKCS11_STATIC) rv = C_GetFunctionList(&dev->func); if (rv == CKR_OK) { version_ptr = (CK_VERSION_PTR) dev->func; if (version_ptr->major == 2 && version_ptr->minor == 20) { dev->version = WC_PCKS11VERSION_2_20; } else if (version_ptr->major == 2 && version_ptr->minor == 40) { dev->version = WC_PCKS11VERSION_2_40; } else { WOLFSSL_MSG_EX("Unsupported PKCS#11 version: %d.%d", version_ptr->major, version_ptr->minor); ret = WC_HW_E; } } else { PKCS11_RV("CK_C_GetFunctionList", rv); ret = WC_HW_E; } #else /* Load dynamic library */ dev->dlHandle = dlopen(library, RTLD_NOW | RTLD_LOCAL); if (dev->dlHandle == NULL) { WOLFSSL_MSG(dlerror()); ret = BAD_PATH_ERROR; } if (ret == 0) { /* Check if the library supports PKCS#11 version 3.0 (or above) by * looking for the C_GetInterface method (only present for >= V3.0). */ func = dlsym(dev->dlHandle, "C_GetInterface"); if (func != NULL) { /* Function is present, use it */ CK_INTERFACE_PTR interface = NULL; CK_VERSION pkcs11_version = {0, 0}; if (version != NULL) { if (*version == WC_PCKS11VERSION_2_20) { pkcs11_version.major = 2; pkcs11_version.minor = 20; } else if (*version == WC_PCKS11VERSION_2_40) { pkcs11_version.major = 2; pkcs11_version.minor = 40; } else if (*version == WC_PCKS11VERSION_3_0) { pkcs11_version.major = 3; pkcs11_version.minor = 0; } else if (*version == WC_PCKS11VERSION_3_1) { pkcs11_version.major = 3; pkcs11_version.minor = 1; } else if (*version == WC_PCKS11VERSION_3_2) { pkcs11_version.major = 3; pkcs11_version.minor = 2; } version_ptr = &pkcs11_version; } else { version_ptr = NULL; } rv = ((CK_C_GetInterface)func)((CK_UTF8CHAR_PTR) interfaceName, version_ptr, &interface, 0); if (rv == CKR_OK) { dev->func = interface->pFunctionList; version_ptr = (CK_VERSION_PTR) interface->pFunctionList; if (version_ptr->major == 2 && version_ptr->minor == 20) { dev->version = WC_PCKS11VERSION_2_20; } else if (version_ptr->major == 2 && version_ptr->minor == 40) { dev->version = WC_PCKS11VERSION_2_40; } else if (version_ptr->major == 3 && version_ptr->minor == 0) { dev->version = WC_PCKS11VERSION_3_0; } else if (version_ptr->major == 3 && version_ptr->minor == 1) { dev->version = WC_PCKS11VERSION_3_1; } else if (version_ptr->major == 3 && version_ptr->minor == 2) { dev->version = WC_PCKS11VERSION_3_2; } else { WOLFSSL_MSG_EX("Unsupported PKCS#11 version: %d.%d", version_ptr->major, version_ptr->minor); ret = WC_HW_E; } } else { PKCS11_RV("CK_C_GetInterface", rv); ret = WC_HW_E; } } else { /* Function not present, try a 2.x library by looking for * C_GetFunctionList. */ func = dlsym(dev->dlHandle, "C_GetFunctionList"); if (func == NULL) { #if defined(_WIN32) WOLFSSL_MSG_EX("GetProcAddress(): %d", GetLastError()); #else WOLFSSL_MSG(dlerror()); #endif ret = WC_HW_E; } if (ret == 0) { rv = ((CK_C_GetFunctionList)func)(&dev->func); if (rv == CKR_OK) { version_ptr = (CK_VERSION_PTR) dev->func; if (version_ptr->major == 2 && version_ptr->minor == 20) { dev->version = WC_PCKS11VERSION_2_20; } else if (version_ptr->major == 2 && version_ptr->minor == 40) { dev->version = WC_PCKS11VERSION_2_40; } else { WOLFSSL_MSG_EX("Unsupported PKCS#11 version: %d.%d", version_ptr->major, version_ptr->minor); ret = WC_HW_E; } } else { PKCS11_RV("CK_C_GetFunctionList", rv); ret = WC_HW_E; } } } } #endif } if (ret == 0 && version != NULL) *version = dev->version; if (ret == 0) { XMEMSET(&args, 0x00, sizeof(args)); args.flags = CKF_OS_LOCKING_OK; rv = dev->func->C_Initialize(&args); if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED) { WOLFSSL_MSG("PKCS#11 already initialized"); rv = CKR_OK; } else if (rv != CKR_OK) { PKCS11_RV("C_Initialize", rv); ret = WC_INIT_E; } } if (rvp != NULL) { *rvp = rv; } if (ret != 0) { wc_Pkcs11_Finalize(dev); } return ret; } /** * Close the Pkcs#11 library. * * @param [in] dev Device object. */ void wc_Pkcs11_Finalize(Pkcs11Dev* dev) { if (dev != NULL #if !defined(HAVE_PKCS11_STATIC) && !defined(HAVE_PKCS11_V3_STATIC) && dev->dlHandle != NULL #endif ) { if (dev->func != NULL) { dev->func->C_Finalize(NULL); dev->func = NULL; } #if !defined(HAVE_PKCS11_STATIC) && !defined(HAVE_PKCS11_V3_STATIC) dlclose(dev->dlHandle); dev->dlHandle = NULL; #endif } } /* lookup by token name and return slotId or (-1) if not found */ static int Pkcs11Slot_FindByTokenName(Pkcs11Dev* dev, const char* tokenName, size_t tokenNameSz) { int ret = -1; CK_RV rv; CK_ULONG slotCnt = 0; CK_TOKEN_INFO tinfo; int idx = -1; CK_SLOT_ID* slot = NULL; rv = dev->func->C_GetSlotList(CK_TRUE, NULL, &slotCnt); if (rv == CKR_OK) { slot = (CK_SLOT_ID*)XMALLOC(slotCnt * sizeof(*slot), dev->heap, DYNAMIC_TYPE_TMP_BUFFER); if (slot == NULL) goto out; rv = dev->func->C_GetSlotList(CK_TRUE, slot, &slotCnt); if (rv != CKR_OK) goto out; for (idx = 0; idx < (int)slotCnt; idx++) { rv = dev->func->C_GetTokenInfo(slot[idx], &tinfo); PKCS11_RV("C_GetTokenInfo", rv); if (rv == CKR_OK && XMEMCMP(tinfo.label, tokenName, tokenNameSz) == 0) { ret = (int)slot[idx]; break; } } } out: XFREE(slot, dev->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; } /* lookup by slotId or tokenName */ static int Pkcs11Token_Init(Pkcs11Token* token, Pkcs11Dev* dev, int slotId, const char* tokenName, size_t tokenNameSz) { int ret = 0; CK_RV rv; CK_SLOT_ID* slot = NULL; CK_ULONG slotCnt = 0; if (token == NULL || dev == NULL) { ret = BAD_FUNC_ARG; } if (ret == 0) { if (slotId < 0) { rv = dev->func->C_GetSlotList(CK_TRUE, NULL, &slotCnt); PKCS11_RV("C_GetSlotList", rv); if (rv != CKR_OK) { ret = WC_HW_E; } if (ret == 0) { slot = (CK_SLOT_ID*)XMALLOC(slotCnt * sizeof(*slot), dev->heap, DYNAMIC_TYPE_TMP_BUFFER); if (slot == NULL) ret = MEMORY_E; } if (ret == 0) { rv = dev->func->C_GetSlotList(CK_TRUE, slot, &slotCnt); PKCS11_RV("C_GetSlotList", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { if (tokenName != NULL && tokenNameSz > 0) { /* find based on token name */ slotId = Pkcs11Slot_FindByTokenName(dev, tokenName, tokenNameSz); } else { /* Use first available slot with a token. */ slotId = (int)slot[0]; } } } else { /* verify slotId is valid */ CK_SLOT_INFO sinfo; rv = dev->func->C_GetSlotInfo(slotId, &sinfo); PKCS11_RV("C_GetSlotInfo", rv); if (rv != CKR_OK) { ret = WC_INIT_E; } } } if (ret == 0) { token->func = dev->func; token->slotId = (CK_SLOT_ID)slotId; token->handle = NULL_PTR; token->userPin = NULL_PTR; token->userPinSz = 0; token->userPinLogin = 0; token->version = dev->version; } XFREE(slot, dev->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; } /** * Set up a token for use. Lookup by slotId or tokenName. Set User PIN. * * @param [in] token Token object. * @param [in] dev PKCS#11 device object. * @param [in] slotId Slot number of the token.
* Passing -1 uses the first available slot. * @param [in] tokenName Name of token to initialize (optional) * @param [in] userPin PIN to use to login as user. * @param [in] userPinSz Number of bytes in PIN. * @return BAD_FUNC_ARG when token, dev and/or tokenName is NULL. * @return WC_INIT_E when initializing token fails. * @return WC_HW_E when another PKCS#11 library call fails. * @return 0 on success. */ int wc_Pkcs11Token_Init(Pkcs11Token* token, Pkcs11Dev* dev, int slotId, const char* tokenName, const unsigned char* userPin, int userPinSz) { int ret; size_t tokenNameSz = 0; if (tokenName != NULL) { tokenNameSz = XSTRLEN(tokenName); } ret = Pkcs11Token_Init(token, dev, slotId, tokenName, tokenNameSz); if (ret == 0 && userPin != NULL) { token->userPin = (CK_UTF8CHAR_PTR)userPin; token->userPinSz = (CK_ULONG)userPinSz; token->userPinLogin = 1; } return ret; } /** * Set up a token for use. Lookup by slotId or tokenName. * * @param [in] token Token object. * @param [in] dev PKCS#11 device object. * @param [in] slotId Slot number of the token.
* Passing -1 uses the first available slot. * @param [in] tokenName Name of token to initialize (optional) * @return BAD_FUNC_ARG when token, dev and/or tokenName is NULL. * @return WC_INIT_E when initializing token fails. * @return WC_HW_E when another PKCS#11 library call fails. * @return 0 on success. */ int wc_Pkcs11Token_Init_NoLogin(Pkcs11Token* token, Pkcs11Dev* dev, int slotId, const char* tokenName) { size_t tokenNameSz = 0; if (tokenName != NULL) { tokenNameSz = XSTRLEN(tokenName); } return Pkcs11Token_Init(token, dev, slotId, tokenName, tokenNameSz); } /** * Set up a token for use. Lookup by slotId or tokenName/size. Set User PIN. * * @param [in] token Token object. * @param [in] dev PKCS#11 device object. * @param [in] tokenName Name of token to initialize. * @param [in] tokenNameSz Name size for token * @param [in] userPin PIN to use to login as user. * @param [in] userPinSz Number of bytes in PIN. * @return BAD_FUNC_ARG when token, dev and/or tokenName is NULL. * @return WC_INIT_E when initializing token fails. * @return WC_HW_E when another PKCS#11 library call fails. * @return 0 on success. */ int wc_Pkcs11Token_InitName(Pkcs11Token* token, Pkcs11Dev* dev, const char* tokenName, int tokenNameSz, const unsigned char* userPin, int userPinSz) { int ret = Pkcs11Token_Init(token, dev, -1, tokenName, (size_t)tokenNameSz); if (ret == 0 && userPin != NULL) { token->userPin = (CK_UTF8CHAR_PTR)userPin; token->userPinSz = (CK_ULONG)userPinSz; token->userPinLogin = 1; } return ret; } /** * Set up a token for use. Lookup by slotId or tokenName/size. * * @param [in] token Token object. * @param [in] dev PKCS#11 device object. * @param [in] tokenName Name of token to initialize. * @param [in] tokenNameSz Name size for token * @param [in] userPin PIN to use to login as user. * @param [in] userPinSz Number of bytes in PIN. * @return BAD_FUNC_ARG when token, dev and/or tokenName is NULL. * @return WC_INIT_E when initializing token fails. * @return WC_HW_E when another PKCS#11 library call fails. * @return 0 on success. */ int wc_Pkcs11Token_InitName_NoLogin(Pkcs11Token* token, Pkcs11Dev* dev, const char* tokenName, int tokenNameSz) { return Pkcs11Token_Init(token, dev, -1, tokenName, (size_t)tokenNameSz); } /** * Finalize token. * Closes all sessions on token. * * @param [in] token Token object. */ void wc_Pkcs11Token_Final(Pkcs11Token* token) { if (token != NULL && token->func != NULL) { token->func->C_CloseAllSessions(token->slotId); token->handle = NULL_PTR; ForceZero(token->userPin, (word32)token->userPinSz); } } /** * Open a session on a token. * * @param [in] token Token object. * @param [in] session Session object. * @param [in] readWrite Boolean indicating to open session for Read/Write. * @return BAD_FUNC_ARG when token or session is NULL. * @return WC_HW_E when opening the session fails. * @return 0 on success. */ static int Pkcs11OpenSession(Pkcs11Token* token, Pkcs11Session* session, int readWrite) { int ret = 0; CK_RV rv; if (token == NULL || session == NULL) ret = BAD_FUNC_ARG; if (ret == 0) { if (token->handle != NULL_PTR) session->handle = token->handle; else { /* Create a new session. */ CK_FLAGS flags = CKF_SERIAL_SESSION; if (readWrite) flags |= CKF_RW_SESSION; rv = token->func->C_OpenSession(token->slotId, flags, (CK_VOID_PTR)NULL, (CK_NOTIFY)NULL, &session->handle); PKCS11_RV("C_OpenSession", rv); if (rv != CKR_OK) { ret = WC_HW_E; } if (ret == 0 && token->userPinLogin) { rv = token->func->C_Login(session->handle, CKU_USER, token->userPin, token->userPinSz); PKCS11_RV("C_Login", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } } } if (ret == 0) { session->func = token->func; session->slotId = token->slotId; session->version = token->version; } return ret; } /** * Close a session on a token. * Won't close a session created externally. * * @param [in] token Token object. * @param [in] session Session object. */ static void Pkcs11CloseSession(Pkcs11Token* token, Pkcs11Session* session) { if (token != NULL && session != NULL && token->handle != session->handle) { if (token->userPin != NULL) session->func->C_Logout(session->handle); session->func->C_CloseSession(session->handle); } } /** * Open a session on the token to be used for all operations. * * @param [in] token Token object. * @param [in] readWrite Boolean indicating to open session for Read/Write. * @return BAD_FUNC_ARG when token is NULL. * @return WC_HW_E when opening the session fails. * @return 0 on success. */ int wc_Pkcs11Token_Open(Pkcs11Token* token, int readWrite) { int ret = 0; Pkcs11Session session; if (token == NULL) ret = BAD_FUNC_ARG; if (ret == 0) { ret = Pkcs11OpenSession(token, &session, readWrite); token->handle = session.handle; } return ret; } /** * Close the token's session. * All object, like keys, will be destroyed. * * @param [in] token Token object. */ void wc_Pkcs11Token_Close(Pkcs11Token* token) { Pkcs11Session session; if (token != NULL) { session.func = token->func; session.handle = token->handle; token->handle = NULL_PTR; Pkcs11CloseSession(token, &session); } } #if (!defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || \ !defined(NO_HMAC) /* * Create a secret key. * * @param [out] key Handle to key object. * @param [in] session Session object. * @param [in] keyType Type of secret key to create. * @param [in] data Data of the secret key. * @param [in] len Length of data in bytes. * @param [in] id Identifier to set against key. * @param [in] idLen Length of identifier. * @param [in] label Label to set against key. * @param [in] labelLen Length of label. * @param [in] op Operation to support with key. * @return WC_HW_E when another PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11CreateSecretKey(CK_OBJECT_HANDLE* key, Pkcs11Session* session, CK_KEY_TYPE keyType, unsigned char* data, int len, unsigned char* id, int idLen, char* label, int labelLen, int op) { int ret = 0; CK_RV rv; /* Empty entries for optional label/ID. */ CK_ATTRIBUTE keyTemplateEncDec[] = { { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, { CKA_VALUE, NULL, 0 }, { 0, NULL, 0 }, { 0, NULL, 0 } }; /* Empty entries for optional label/ID. */ CK_ATTRIBUTE keyTemplateSignVfy[] = { { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, { CKA_VALUE, NULL, 0 }, { 0, NULL, 0 }, { 0, NULL, 0 } }; CK_ATTRIBUTE* keyTemplate = NULL; /* 5 mandatory entries + 2 optional. */ int keyTmplCnt = 5; WOLFSSL_MSG("PKCS#11: Create Secret Key"); if (op == CKA_ENCRYPT || op == CKA_DECRYPT) { keyTemplate = keyTemplateEncDec; } else if (op == CKA_SIGN) { keyTemplate = keyTemplateSignVfy; } else { WOLFSSL_MSG("PKCS#11: Invalid operation type"); ret = WC_HW_E; } if (ret == 0) { /* Set the secret to store. */ keyTemplate[keyTmplCnt-1].pValue = data; keyTemplate[keyTmplCnt-1].ulValueLen = (CK_ULONG)len; if (labelLen > 0) { keyTemplate[keyTmplCnt].type = CKA_LABEL; keyTemplate[keyTmplCnt].pValue = label; keyTemplate[keyTmplCnt].ulValueLen = labelLen; keyTmplCnt++; } if (idLen > 0) { keyTemplate[keyTmplCnt].type = CKA_ID; keyTemplate[keyTmplCnt].pValue = id; keyTemplate[keyTmplCnt].ulValueLen = idLen; keyTmplCnt++; } PKCS11_DUMP_TEMPLATE("Secret Key", keyTemplate, keyTmplCnt); /* Create an object containing key data for device to use. */ rv = session->func->C_CreateObject(session->handle, keyTemplate, keyTmplCnt, key); PKCS11_RV("C_CreateObject", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } return ret; } #endif #if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) /** * Create a PKCS#11 object containing the RSA private key data. * * @param [out] privateKey Handle to private key object. * @param [in] session Session object. * @param [in] rsaKey RSA key with private key data. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11CreateRsaPrivateKey(CK_OBJECT_HANDLE* privateKey, Pkcs11Session* session, RsaKey* rsaKey, int permanent) { int ret = 0; CK_RV rv; /* Empty entries for optional label/ID. */ CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, { CKA_KEY_TYPE, &rsaKeyType, sizeof(rsaKeyType) }, { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, { CKA_MODULUS, NULL, 0 }, { CKA_PRIVATE_EXPONENT, NULL, 0 }, { CKA_PRIME_1, NULL, 0 }, { CKA_PRIME_2, NULL, 0 }, { CKA_EXPONENT_1, NULL, 0 }, { CKA_EXPONENT_2, NULL, 0 }, { CKA_COEFFICIENT, NULL, 0 }, { CKA_PUBLIC_EXPONENT, NULL, 0 }, { 0, NULL, 0 }, { 0, NULL, 0 } }; /* Mandatory entries + 2 optional. */ CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate) - 2; /* Set the modulus and private key data. */ keyTemplate[ 4].pValue = rsaKey->n.raw.buf; keyTemplate[ 4].ulValueLen = rsaKey->n.raw.len; keyTemplate[ 5].pValue = rsaKey->d.raw.buf; keyTemplate[ 5].ulValueLen = rsaKey->d.raw.len; keyTemplate[ 6].pValue = rsaKey->p.raw.buf; keyTemplate[ 6].ulValueLen = rsaKey->p.raw.len; keyTemplate[ 7].pValue = rsaKey->q.raw.buf; keyTemplate[ 7].ulValueLen = rsaKey->q.raw.len; keyTemplate[ 8].pValue = rsaKey->dP.raw.buf; keyTemplate[ 8].ulValueLen = rsaKey->dP.raw.len; keyTemplate[ 9].pValue = rsaKey->dQ.raw.buf; keyTemplate[ 9].ulValueLen = rsaKey->dQ.raw.len; keyTemplate[10].pValue = rsaKey->u.raw.buf; keyTemplate[10].ulValueLen = rsaKey->u.raw.len; keyTemplate[11].pValue = rsaKey->e.raw.buf; keyTemplate[11].ulValueLen = rsaKey->e.raw.len; if (permanent && rsaKey->labelLen > 0) { keyTemplate[keyTmplCnt].type = CKA_LABEL; keyTemplate[keyTmplCnt].pValue = rsaKey->label; keyTemplate[keyTmplCnt].ulValueLen = rsaKey->labelLen; keyTmplCnt++; } if (permanent && rsaKey->idLen > 0) { keyTemplate[keyTmplCnt].type = CKA_ID; keyTemplate[keyTmplCnt].pValue = rsaKey->id; keyTemplate[keyTmplCnt].ulValueLen = rsaKey->idLen; keyTmplCnt++; } PKCS11_DUMP_TEMPLATE("RSA Private Key", keyTemplate, keyTmplCnt); rv = session->func->C_CreateObject(session->handle, keyTemplate, keyTmplCnt, privateKey); PKCS11_RV("C_CreateObject", rv); if (rv != CKR_OK) { ret = WC_HW_E; } return ret; } #endif /* !NO_RSA && WOLFSSL_KEY_GEN */ #ifdef HAVE_ECC /** * Set the ECC parameters into the template. * * @param [in] key ECC key. * @param [in] tmpl PKCS#11 template. * @param [in] idx Index of template to put parameters into. * @return NOT_COMPILED_IN when the EC parameters are not known. * @return 0 on success. */ static int Pkcs11EccSetParams(ecc_key* key, CK_ATTRIBUTE* tmpl, int idx) { int ret = 0; if (key != NULL && key->dp != NULL && key->dp->oid != NULL) { unsigned char* derParams = tmpl[idx].pValue; #if defined(HAVE_OID_ENCODING) word32 oidSz = ECC_MAX_OID_LEN - 2; ret = wc_EncodeObjectId(key->dp->oid, key->dp->oidSz, derParams+2, &oidSz); if (ret != 0) { return ret; } tmpl[idx].ulValueLen = oidSz + 2; derParams[0] = ASN_OBJECT_ID; derParams[1] = oidSz; #else /* ASN.1 encoding: OBJ + ecc parameters OID */ tmpl[idx].ulValueLen = key->dp->oidSz + 2; derParams[0] = ASN_OBJECT_ID; derParams[1] = key->dp->oidSz; XMEMCPY(derParams + 2, key->dp->oid, key->dp->oidSz); #endif } else ret = NOT_COMPILED_IN; return ret; } /** * Create a PKCS#11 object containing the ECC public key data. * Encode the public key as an OCTET_STRING of the encoded point. * * @param [out] publicKey Handle to public key object. * @param [in] session Session object. * @param [in] public_key ECC public key. * @param [in] operation Cryptographic operation key is to be used for. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return 0 on success. */ static int Pkcs11CreateEccPublicKey(CK_OBJECT_HANDLE* publicKey, Pkcs11Session* session, ecc_key* public_key, CK_ATTRIBUTE_TYPE operation) { int ret = 0; int i; unsigned char* ecPoint = NULL; word32 len; CK_RV rv; CK_UTF8CHAR params[ECC_MAX_OID_LEN]; /* Empty entries for optional label/ID. */ CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, { CKA_KEY_TYPE, &ecKeyType, sizeof(ecKeyType) }, { operation, &ckTrue, sizeof(ckTrue) }, { CKA_EC_PARAMS, params, 0 }, { CKA_EC_POINT, NULL, 0 }, { 0, NULL, 0 }, { 0, NULL, 0 } }; /* Mandatory entries + 2 optional. */ CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate) - 2; if (public_key->labelLen > 0) { keyTemplate[keyTmplCnt].type = CKA_LABEL; keyTemplate[keyTmplCnt].pValue = public_key->label; keyTemplate[keyTmplCnt].ulValueLen = public_key->labelLen; keyTmplCnt++; } if (public_key->idLen > 0) { keyTemplate[keyTmplCnt].type = CKA_ID; keyTemplate[keyTmplCnt].pValue = public_key->id; keyTemplate[keyTmplCnt].ulValueLen = public_key->idLen; keyTmplCnt++; } ret = Pkcs11EccSetParams(public_key, keyTemplate, 3); if (ret == 0) { /* ASN1 encoded: OCT + uncompressed point */ len = 3 + 1 + 2 * public_key->dp->size; ecPoint = (unsigned char*)XMALLOC(len, public_key->heap, DYNAMIC_TYPE_ECC); if (ecPoint == NULL) ret = MEMORY_E; } if (ret == 0) { len -= 3; i = 0; ecPoint[i++] = ASN_OCTET_STRING; if (len >= ASN_LONG_LENGTH) ecPoint[i++] = ASN_LONG_LENGTH | 1; ecPoint[i++] = len; if (public_key->type == 0) public_key->type = ECC_PUBLICKEY; PRIVATE_KEY_UNLOCK(); ret = wc_ecc_export_x963(public_key, ecPoint + i, &len); PRIVATE_KEY_LOCK(); } if (ret == 0) { keyTemplate[4].pValue = ecPoint; keyTemplate[4].ulValueLen = len + i; PKCS11_DUMP_TEMPLATE("Ec Public Key", keyTemplate, keyTmplCnt); rv = session->func->C_CreateObject(session->handle, keyTemplate, keyTmplCnt, publicKey); PKCS11_RV("C_CreateObject", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } XFREE(ecPoint, public_key->heap, DYNAMIC_TYPE_ECC); return ret; } /** * Create a PKCS#11 object containing the ECC private key data. * * @param privateKey [out] Handle to private key object. * @param session [in] Session object. * @param private_key [in] ECC private key. * @param operation [in] Cryptographic operation key is to be used for. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11CreateEccPrivateKey(CK_OBJECT_HANDLE* privateKey, Pkcs11Session* session, ecc_key* private_key, CK_ATTRIBUTE_TYPE operation) { int ret = 0; CK_RV rv; CK_UTF8CHAR params[ECC_MAX_OID_LEN]; /* Empty entries for optional label/ID. */ CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, { CKA_KEY_TYPE, &ecKeyType, sizeof(ecKeyType) }, { operation, &ckTrue, sizeof(ckTrue) }, { CKA_EC_PARAMS, params, 0 }, { CKA_VALUE, NULL, 0 }, { 0, NULL, 0 }, { 0, NULL, 0 } }; /* Mandatory entries + 2 optional. */ CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate) - 2; if (private_key->labelLen > 0) { keyTemplate[keyTmplCnt].type = CKA_LABEL; keyTemplate[keyTmplCnt].pValue = private_key->label; keyTemplate[keyTmplCnt].ulValueLen = private_key->labelLen; keyTmplCnt++; } if (private_key->idLen > 0) { keyTemplate[keyTmplCnt].type = CKA_ID; keyTemplate[keyTmplCnt].pValue = private_key->id; keyTemplate[keyTmplCnt].ulValueLen = private_key->idLen; keyTmplCnt++; } ret = Pkcs11EccSetParams(private_key, keyTemplate, 3); if (ret == 0) { word32 privLen = private_key->dp->size; byte* priv = (byte*)XMALLOC(privLen, private_key->heap, DYNAMIC_TYPE_TMP_BUFFER); if (priv == NULL) { ret = MEMORY_E; } if (ret == 0) { PRIVATE_KEY_LOCK(); ret = wc_ecc_export_private_only(private_key, priv, &privLen); PRIVATE_KEY_UNLOCK(); } if (ret == 0) { keyTemplate[4].pValue = priv; keyTemplate[4].ulValueLen = privLen; PKCS11_DUMP_TEMPLATE("Ec Private Key", keyTemplate, keyTmplCnt); rv = session->func->C_CreateObject(session->handle, keyTemplate, keyTmplCnt, privateKey); PKCS11_RV("C_CreateObject", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (priv != NULL) ForceZero(priv, privLen); XFREE(priv, private_key->heap, DYNAMIC_TYPE_TMP_BUFFER); } return ret; } #endif #ifdef WOLFSSL_HAVE_MLKEM /** * Create a PKCS#11 object containing the ML-KEM public key data. */ static int Pkcs11CreateMlKemPublicKey(CK_OBJECT_HANDLE* handle, Pkcs11Session* session, MlKemKey* key, CK_MECHANISM_INFO_PTR mechInfo) { int ret = 0; CK_RV rv; CK_ULONG publicKeyLen = 0; CK_ML_KEM_PARAMETER_SET_TYPE param_set = 0; unsigned char* publicKey = NULL; CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, { CKA_KEY_TYPE, &mlkemKeyType, sizeof(mlkemKeyType) }, { CKA_ENCAPSULATE, &ckTrue, sizeof(ckTrue) }, { CKA_VALUE, NULL, 0 }, { CKA_PARAMETER_SET, ¶m_set, sizeof(param_set) }, { 0, NULL, 0 }, { 0, NULL, 0 }, }; CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate) - 2; if (mechInfo == NULL || (key->flags & MLKEM_FLAG_PUB_SET) == 0) { ret = BAD_FUNC_ARG; } if (ret == 0 && key->labelLen > 0) { keyTemplate[keyTmplCnt].type = CKA_LABEL; keyTemplate[keyTmplCnt].pValue = key->label; keyTemplate[keyTmplCnt].ulValueLen = key->labelLen; keyTmplCnt++; } if (ret == 0 && key->idLen > 0) { keyTemplate[keyTmplCnt].type = CKA_ID; keyTemplate[keyTmplCnt].pValue = key->id; keyTemplate[keyTmplCnt].ulValueLen = key->idLen; keyTmplCnt++; } if (ret == 0) { switch (key->type) { #ifndef WOLFSSL_NO_ML_KEM case WC_ML_KEM_512: param_set = CKP_ML_KEM_512; publicKeyLen = WC_ML_KEM_512_PUBLIC_KEY_SIZE; break; case WC_ML_KEM_768: param_set = CKP_ML_KEM_768; publicKeyLen = WC_ML_KEM_768_PUBLIC_KEY_SIZE; break; case WC_ML_KEM_1024: param_set = CKP_ML_KEM_1024; publicKeyLen = WC_ML_KEM_1024_PUBLIC_KEY_SIZE; break; default: ret = NOT_COMPILED_IN; break; #else default: ret = NOT_COMPILED_IN; break; #endif } } if ((ret == 0) && ((mechInfo->ulMinKeySize > publicKeyLen) || (mechInfo->ulMaxKeySize < publicKeyLen))) { ret = WC_KEY_SIZE_E; } if (ret == 0) { publicKey = (unsigned char*)XMALLOC(publicKeyLen, key->heap, DYNAMIC_TYPE_TMP_BUFFER); if (publicKey == NULL) { ret = MEMORY_E; } } if (ret == 0) { ret = wc_MlKemKey_EncodePublicKey(key, publicKey, (word32)publicKeyLen); } if (ret == 0) { keyTemplate[3].pValue = publicKey; keyTemplate[3].ulValueLen = publicKeyLen; PKCS11_DUMP_TEMPLATE("ML-KEM Public Key", keyTemplate, keyTmplCnt); rv = session->func->C_CreateObject(session->handle, keyTemplate, keyTmplCnt, handle); PKCS11_RV("C_CreateObject", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } XFREE(publicKey, key->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; } /** * Create a PKCS#11 object containing the ML-KEM private key data. */ static int Pkcs11CreateMlKemPrivateKey(CK_OBJECT_HANDLE* privateKey, Pkcs11Session* session, MlKemKey* key, CK_MECHANISM_INFO_PTR mechInfo) { int ret = 0; CK_RV rv; CK_ULONG privateKeyLen = 0; CK_ML_KEM_PARAMETER_SET_TYPE param_set = 0; unsigned char* privateData = NULL; CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, { CKA_KEY_TYPE, &mlkemKeyType, sizeof(mlkemKeyType) }, { CKA_DECAPSULATE, &ckTrue, sizeof(ckTrue) }, { CKA_VALUE, NULL, 0 }, { CKA_PARAMETER_SET, ¶m_set, sizeof(param_set) }, { 0, NULL, 0 }, { 0, NULL, 0 }, }; CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate) - 2; if (mechInfo == NULL || (key->flags & MLKEM_FLAG_PRIV_SET) == 0) { ret = BAD_FUNC_ARG; } if (ret == 0 && key->labelLen > 0) { keyTemplate[keyTmplCnt].type = CKA_LABEL; keyTemplate[keyTmplCnt].pValue = key->label; keyTemplate[keyTmplCnt].ulValueLen = key->labelLen; keyTmplCnt++; } if (ret == 0 && key->idLen > 0) { keyTemplate[keyTmplCnt].type = CKA_ID; keyTemplate[keyTmplCnt].pValue = key->id; keyTemplate[keyTmplCnt].ulValueLen = key->idLen; keyTmplCnt++; } if (ret == 0) { switch (key->type) { #ifndef WOLFSSL_NO_ML_KEM case WC_ML_KEM_512: param_set = CKP_ML_KEM_512; privateKeyLen = WC_ML_KEM_512_PRIVATE_KEY_SIZE; break; case WC_ML_KEM_768: param_set = CKP_ML_KEM_768; privateKeyLen = WC_ML_KEM_768_PRIVATE_KEY_SIZE; break; case WC_ML_KEM_1024: param_set = CKP_ML_KEM_1024; privateKeyLen = WC_ML_KEM_1024_PRIVATE_KEY_SIZE; break; default: ret = NOT_COMPILED_IN; break; #else default: ret = NOT_COMPILED_IN; break; #endif } } if ((ret == 0) && ((mechInfo->ulMinKeySize > privateKeyLen) || (mechInfo->ulMaxKeySize < privateKeyLen))) { ret = WC_KEY_SIZE_E; } if (ret == 0) { privateData = (unsigned char*)XMALLOC(privateKeyLen, key->heap, DYNAMIC_TYPE_TMP_BUFFER); if (privateData == NULL) { ret = MEMORY_E; } } if (ret == 0) { ret = wc_MlKemKey_EncodePrivateKey(key, privateData, (word32)privateKeyLen); } if (ret == 0) { keyTemplate[3].pValue = privateData; keyTemplate[3].ulValueLen = privateKeyLen; PKCS11_DUMP_TEMPLATE("ML-KEM Private Key", keyTemplate, keyTmplCnt); rv = session->func->C_CreateObject(session->handle, keyTemplate, keyTmplCnt, privateKey); PKCS11_RV("C_CreateObject", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (privateData != NULL) { ForceZero(privateData, privateKeyLen); } XFREE(privateData, key->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; } #endif /* WOLFSSL_HAVE_MLKEM */ #ifdef HAVE_DILITHIUM /** * Create a PKCS#11 object containing the ML-DSA public key data. * @param handle [out] Handle to public key object. * @param session [in] Session object. * @param key [in] ML-DSA key. * @param mechInfo [in] Pointer to a filled MECHANISM_INFO object. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return 0 on success. */ static int Pkcs11CreateMldsaPublicKey(CK_OBJECT_HANDLE* handle, Pkcs11Session* session, MlDsaKey* key, CK_MECHANISM_INFO_PTR mechInfo) { int ret = 0; CK_RV rv; CK_ULONG publicKeyLen = 0; CK_ML_DSA_PARAMETER_SET_TYPE param_set = 0; /* Empty entries for optional label/ID. */ CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, { CKA_KEY_TYPE, &mldsaKeyType, sizeof(mldsaKeyType) }, { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, { CKA_VALUE, NULL, 0 }, { CKA_PARAMETER_SET, ¶m_set, sizeof(param_set) }, { 0, NULL, 0 }, { 0, NULL, 0 }, }; /* Mandatory entries + 2 optional. */ CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate) - 2; if (!key->pubKeySet) { ret = BAD_FUNC_ARG; } if (key->labelLen > 0) { keyTemplate[keyTmplCnt].type = CKA_LABEL; keyTemplate[keyTmplCnt].pValue = key->label; keyTemplate[keyTmplCnt].ulValueLen = key->labelLen; keyTmplCnt++; } if (key->idLen > 0) { keyTemplate[keyTmplCnt].type = CKA_ID; keyTemplate[keyTmplCnt].pValue = key->id; keyTemplate[keyTmplCnt].ulValueLen = key->idLen; keyTmplCnt++; } if ((key->level == WC_ML_DSA_44) && (mechInfo->ulMinKeySize <= ML_DSA_LEVEL2_PUB_KEY_SIZE) && (mechInfo->ulMaxKeySize >= ML_DSA_LEVEL2_PUB_KEY_SIZE)) { publicKeyLen = ML_DSA_LEVEL2_PUB_KEY_SIZE; param_set = CKP_ML_DSA_44; } else if ((key->level == WC_ML_DSA_65) && (mechInfo->ulMinKeySize <= ML_DSA_LEVEL3_PUB_KEY_SIZE) && (mechInfo->ulMaxKeySize >= ML_DSA_LEVEL3_PUB_KEY_SIZE)) { publicKeyLen = ML_DSA_LEVEL3_PUB_KEY_SIZE; param_set = CKP_ML_DSA_65; } else if ((key->level == WC_ML_DSA_87) && (mechInfo->ulMinKeySize <= ML_DSA_LEVEL5_PUB_KEY_SIZE) && (mechInfo->ulMaxKeySize >= ML_DSA_LEVEL5_PUB_KEY_SIZE)) { publicKeyLen = ML_DSA_LEVEL5_PUB_KEY_SIZE; param_set = CKP_ML_DSA_87; } else { ret = WC_KEY_SIZE_E; } if (ret == 0) { keyTemplate[3].pValue = (byte*) key->p; keyTemplate[3].ulValueLen = publicKeyLen; PKCS11_DUMP_TEMPLATE("ML-DSA Public Key", keyTemplate, keyTmplCnt); rv = session->func->C_CreateObject(session->handle, keyTemplate, keyTmplCnt, handle); PKCS11_RV("C_CreateObject", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } return ret; } /** * Create a PKCS#11 object containing the ML-DSA private key data. * * @param handle [out] Handle to private key object. * @param session [in] Session object. * @param key [in] ML-DSA key. * @param mechInfo [in] Pointer to a filled MECHANISM_INFO object. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11CreateMldsaPrivateKey(CK_OBJECT_HANDLE* privateKey, Pkcs11Session* session, MlDsaKey* key, CK_MECHANISM_INFO_PTR mechInfo) { int ret = 0; CK_RV rv; CK_ULONG privateKeyLen = 0; CK_ML_DSA_PARAMETER_SET_TYPE param_set = 0; /* Empty entries for optional label/ID. */ CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, { CKA_KEY_TYPE, &mldsaKeyType, sizeof(mldsaKeyType) }, { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, { CKA_VALUE, NULL, 0 }, { CKA_PARAMETER_SET, ¶m_set, sizeof(param_set) }, { 0, NULL, 0 }, { 0, NULL, 0 } }; /* Mandatory entries + 2 optional. */ CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate) - 2; if (key->labelLen > 0) { keyTemplate[keyTmplCnt].type = CKA_LABEL; keyTemplate[keyTmplCnt].pValue = key->label; keyTemplate[keyTmplCnt].ulValueLen = key->labelLen; keyTmplCnt++; } if (key->idLen > 0) { keyTemplate[keyTmplCnt].type = CKA_ID; keyTemplate[keyTmplCnt].pValue = key->id; keyTemplate[keyTmplCnt].ulValueLen = key->idLen; keyTmplCnt++; } if ((key->level == WC_ML_DSA_44) && (mechInfo->ulMinKeySize <= ML_DSA_LEVEL2_PUB_KEY_SIZE) && (mechInfo->ulMaxKeySize >= ML_DSA_LEVEL2_PUB_KEY_SIZE)) { privateKeyLen = ML_DSA_LEVEL2_KEY_SIZE; param_set = CKP_ML_DSA_44; } else if ((key->level == WC_ML_DSA_65) && (mechInfo->ulMinKeySize <= ML_DSA_LEVEL3_PUB_KEY_SIZE) && (mechInfo->ulMaxKeySize >= ML_DSA_LEVEL3_PUB_KEY_SIZE)) { privateKeyLen = ML_DSA_LEVEL3_KEY_SIZE; param_set = CKP_ML_DSA_65; } else if ((key->level == WC_ML_DSA_87) && (mechInfo->ulMinKeySize <= ML_DSA_LEVEL5_PUB_KEY_SIZE) && (mechInfo->ulMaxKeySize >= ML_DSA_LEVEL5_PUB_KEY_SIZE)) { privateKeyLen = ML_DSA_LEVEL5_KEY_SIZE; param_set = CKP_ML_DSA_87; } else { ret = WC_KEY_SIZE_E; } if (ret == 0) { keyTemplate[3].pValue = (byte*) key->k; keyTemplate[3].ulValueLen = privateKeyLen; PKCS11_DUMP_TEMPLATE("ML-DSA Private Key", keyTemplate, keyTmplCnt); rv = session->func->C_CreateObject(session->handle, keyTemplate, keyTmplCnt, privateKey); PKCS11_RV("C_CreateObject", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } return ret; } #endif /* HAVE_DILITHIUM */ #if !defined(NO_RSA) || defined(HAVE_ECC) || (!defined(NO_AES) && \ (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || \ !defined(NO_HMAC) || defined(HAVE_DILITHIUM) || \ defined(WOLFSSL_HAVE_MLKEM) /** * Check if mechanism is available in session on token. * * @param [in] session Session object. * @param [in] mech Mechanism to look for. * @param [out] mechInfoPtr Mechanism info return data (optional). * @return NOT_COMPILED_IN when mechanism not available. * @return 0 when mechanism is available. */ static int Pkcs11MechAvail(Pkcs11Session* session, CK_MECHANISM_TYPE mech, CK_MECHANISM_INFO_PTR mechInfoPtr) { int ret = 0; CK_RV rv; CK_MECHANISM_INFO mechInfo; PKCS11_DUMP_MECHANSIM("PKCS#11: Check if mechanism is available", mech); rv = session->func->C_GetMechanismInfo(session->slotId, mech, &mechInfo); PKCS11_RV("C_GetMechanismInfo", rv); if (rv != CKR_OK) { ret = NOT_COMPILED_IN; } if (mechInfoPtr != NULL) { *mechInfoPtr = mechInfo; } return ret; } #endif #ifndef NO_HMAC /** * Return the mechanism type and key type for the digest type when using HMAC. * * @param [in] macType Digest type - e.g. WC_SHA256. * @param [in] mechType Mechanism type - e.g. CKM_SHA256_HMAC. * @param [in] keyType Key type - e.g. CKK_SHA256_HMAC. * @return NOT_COMPILED_IN if the digest algorithm isn't recognised. * @return 0 otherwise. */ static int Pkcs11HmacTypes(int macType, int* mechType, int* keyType) { int ret = 0; switch (macType) { #ifndef NO_MD5 case WC_MD5: *mechType = CKM_MD5_HMAC; *keyType = CKK_MD5_HMAC; break; #endif #ifndef NO_SHA case WC_SHA: *mechType = CKM_SHA_1_HMAC; *keyType = CKK_SHA_1_HMAC; break; #endif #ifdef WOLFSSL_SHA224 case WC_SHA224: *mechType = CKM_SHA224_HMAC; *keyType = CKK_SHA224_HMAC; break; #endif #ifndef NO_SHA256 case WC_SHA256: *mechType = CKM_SHA256_HMAC; *keyType = CKK_SHA256_HMAC; break; #endif #ifdef WOLFSSL_SHA384 case WC_SHA384: *mechType = CKM_SHA384_HMAC; *keyType = CKK_SHA384_HMAC; break; #endif #ifdef WOLFSSL_SHA512 case WC_SHA512: *mechType = CKM_SHA512_HMAC; *keyType = CKK_SHA512_HMAC; break; #endif default: ret = NOT_COMPILED_IN; break; } return ret; } #endif /** * Store the private key on the token in the session. * * @param [in] token Token to store private key on. * @param [in] type Key type. * @param [in] clear Clear out the private data from software key. * @param [in] key Key type specific object. * @return NOT_COMPILED_IN when mechanism not available. * @return 0 on success. */ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key) { int ret = 0; Pkcs11Session session; CK_OBJECT_HANDLE privKey = NULL_PTR; ret = Pkcs11OpenSession(token, &session, 1); if (ret == 0) { switch (type) { #if !defined(NO_AES) && defined(HAVE_AESGCM) case PKCS11_KEY_TYPE_AES_GCM: { Aes* aes = (Aes*)key; ret = Pkcs11MechAvail(&session, CKM_AES_GCM, NULL); if (ret == 0) { ret = Pkcs11CreateSecretKey(&privKey, &session, CKK_AES, (unsigned char*)aes->devKey, aes->keylen, (unsigned char*)aes->id, aes->idLen, aes->label, aes->labelLen, CKA_ENCRYPT); } if (ret == 0 && clear) ForceZero(aes->devKey, aes->keylen); break; } #endif #if !defined(NO_AES) && defined(HAVE_AES_CBC) case PKCS11_KEY_TYPE_AES_CBC: { Aes* aes = (Aes*)key; ret = Pkcs11MechAvail(&session, CKM_AES_CBC, NULL); if (ret == 0) { ret = Pkcs11CreateSecretKey(&privKey, &session, CKK_AES, (unsigned char*)aes->devKey, aes->keylen, (unsigned char*)aes->id, aes->idLen, aes->label, aes->labelLen, CKA_ENCRYPT); } if (ret == 0 && clear) ForceZero(aes->devKey, aes->keylen); break; } #endif #ifndef NO_HMAC case PKCS11_KEY_TYPE_HMAC: { Hmac* hmac = (Hmac*)key; int mechType; int keyType; ret = Pkcs11HmacTypes(hmac->macType, &mechType, &keyType); if (ret == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) break; if (ret == 0) ret = Pkcs11MechAvail(&session, mechType, NULL); if (ret == 0) { ret = Pkcs11CreateSecretKey(&privKey, &session, keyType, (unsigned char*)hmac->keyRaw, hmac->keyLen, (unsigned char*)hmac->id, hmac->idLen, hmac->label, hmac->labelLen, CKA_SIGN); if (ret == WC_NO_ERR_TRACE(WC_HW_E)) { ret = Pkcs11CreateSecretKey(&privKey, &session, CKK_GENERIC_SECRET, (unsigned char*)hmac->keyRaw, hmac->keyLen, (unsigned char*)hmac->id, hmac->idLen, hmac->label, hmac->labelLen, CKA_SIGN); } } break; } #endif #if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) case PKCS11_KEY_TYPE_RSA: { RsaKey* rsaKey = (RsaKey*)key; ret = Pkcs11MechAvail(&session, CKM_RSA_X_509, NULL); if (ret == 0) ret = Pkcs11CreateRsaPrivateKey(&privKey, &session, rsaKey, 1); if (ret == 0 && clear) { mp_forcezero(&rsaKey->u); mp_forcezero(&rsaKey->dQ); mp_forcezero(&rsaKey->dP); mp_forcezero(&rsaKey->q); mp_forcezero(&rsaKey->p); mp_forcezero(&rsaKey->d); } break; } #endif #ifdef HAVE_ECC case PKCS11_KEY_TYPE_EC: { ecc_key* eccKey = (ecc_key*)key; int ret2 = WC_NO_ERR_TRACE(NOT_COMPILED_IN); #ifndef NO_PKCS11_ECDH if ((eccKey->flags & WC_ECC_FLAG_DEC_SIGN) == 0) { /* Try ECDH mechanism first. */ ret = Pkcs11MechAvail(&session, CKM_ECDH1_DERIVE, NULL); if (ret == 0) { ret = Pkcs11CreateEccPrivateKey(&privKey, &session, eccKey, CKA_DERIVE); } } #endif if (ret == 0 || ret == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) { /* Try ECDSA mechanism next. */ ret2 = Pkcs11MechAvail(&session, CKM_ECDSA, NULL); if (ret2 == 0) { ret2 = Pkcs11CreateEccPrivateKey(&privKey, &session, eccKey, CKA_SIGN); if (ret2 == 0) { CK_OBJECT_HANDLE pubKey = NULL_PTR; /* Store public key for validation with cert. */ ret2 = Pkcs11CreateEccPublicKey(&pubKey, &session, eccKey, CKA_VERIFY); if (ret2 != 0) { /* Delete the private key if the public key * creation failed to avoid leaving an orphaned * private key on the token. */ session.func->C_DestroyObject(session.handle, privKey); } } } /* OK for this to fail if set for ECDH. */ if (ret == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) ret = ret2; } if (ret == 0 && clear) mp_forcezero(wc_ecc_key_get_priv(eccKey)); break; } #endif #ifdef WOLFSSL_HAVE_MLKEM case PKCS11_KEY_TYPE_MLKEM: { MlKemKey* mlkemKey = (MlKemKey*)key; CK_MECHANISM_INFO mechInfo; ret = Pkcs11MechAvail(&session, CKM_ML_KEM, &mechInfo); if (ret == 0 && ((mlkemKey->flags & MLKEM_FLAG_PRIV_SET) != 0)) { ret = Pkcs11CreateMlKemPrivateKey(&privKey, &session, mlkemKey, &mechInfo); } if (ret == 0 && ((mlkemKey->flags & MLKEM_FLAG_PUB_SET) != 0)) { CK_OBJECT_HANDLE pubKey = NULL_PTR; /* Store public key for validation with private key. */ ret = Pkcs11CreateMlKemPublicKey(&pubKey, &session, mlkemKey, &mechInfo); if (ret != 0 && privKey != NULL_PTR) { /* Delete the private key if the public key * creation failed to avoid leaving an orphaned * private key on the token. */ session.func->C_DestroyObject(session.handle, privKey); } } if (ret == 0 && clear && ((mlkemKey->flags & MLKEM_FLAG_PRIV_SET) != 0)) { ForceZero(mlkemKey->priv, sizeof(mlkemKey->priv)); ForceZero(mlkemKey->z, sizeof(mlkemKey->z)); } break; } #endif /* WOLFSSL_HAVE_MLKEM */ #if defined(HAVE_DILITHIUM) case PKCS11_KEY_TYPE_MLDSA: { MlDsaKey* mldsaKey = (MlDsaKey*) key; CK_MECHANISM_INFO mechInfo; ret = Pkcs11MechAvail(&session, CKM_ML_DSA, &mechInfo); if (ret == 0 && mldsaKey->prvKeySet) { ret = Pkcs11CreateMldsaPrivateKey(&privKey, &session, mldsaKey, &mechInfo); } if (ret == 0 && mldsaKey->pubKeySet) { CK_OBJECT_HANDLE pubKey = NULL_PTR; /* Store public key for validation with cert. */ ret = Pkcs11CreateMldsaPublicKey(&pubKey, &session, mldsaKey, &mechInfo); if (ret != 0) { /* Delete the private key if the public key creation * failed to avoid leaving an orphaned private key * on the token. */ session.func->C_DestroyObject(session.handle, privKey); } } #if !defined(WOLFSSL_DILITHIUM_ASSIGN_KEY) && \ !defined(WOLFSSL_DILITHIUM_DYNAMIC_KEYS) if (ret == 0 && clear) { ForceZero(mldsaKey->k, sizeof(mldsaKey->k)); } #elif defined(WOLFSSL_DILITHIUM_DYNAMIC_KEYS) if (ret == 0 && clear && mldsaKey->k != NULL) { ForceZero(mldsaKey->k, mldsaKey->kSz); } #endif break; } #endif /* HAVE_DILITHIUM*/ default: ret = NOT_COMPILED_IN; break; } Pkcs11CloseSession(token, &session); } (void)privKey; (void)clear; (void)key; return ret; } #if !defined(NO_RSA) || defined(HAVE_ECC) || (!defined(NO_AES) && \ (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || \ !defined(NO_HMAC) || !defined(NO_CERTS) /** * Find the PKCS#11 object containing key data using template. * * @param [out] key Handle to key object. * @param [in] session Session object. * @param [in] keyTemplate PKCS #11 template to use in search. * @param [in] keyTmplCnt Count of entries in PKCS #11 template. * @param [out] count Number of keys matching template. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11FindKeyByTemplate(CK_OBJECT_HANDLE* key, Pkcs11Session* session, CK_ATTRIBUTE *keyTemplate, CK_ULONG keyTmplCnt, CK_ULONG *count) { int ret = 0; CK_RV rv; WOLFSSL_MSG("PKCS#11: Find Key By Template"); PKCS11_DUMP_TEMPLATE("Find Key", keyTemplate, keyTmplCnt); rv = session->func->C_FindObjectsInit(session->handle, keyTemplate, keyTmplCnt); PKCS11_RV("C_FindObjectsInit", rv); if (rv != CKR_OK) { ret = WC_HW_E; } if (ret == 0) { rv = session->func->C_FindObjects(session->handle, key, 1, count); PKCS11_RV("C_FindObjects", rv); PKCS11_VAL("C_FindObjects Count", *count); if (rv != CKR_OK) { ret = WC_HW_E; } rv = session->func->C_FindObjectsFinal(session->handle); PKCS11_RV("C_FindObjectsFinal", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } return ret; } /** * Find the PKCS#11 object containing the private key data by label. * * @param [out] key Handle to key object. * @param [in] keyClass Public or private key class. * @param [in] keyType Type of key. * @param [in] session Session object. * @param [in] id Identifier set against a key. * @param [in] idLen Length of identifier. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11FindKeyByLabel(CK_OBJECT_HANDLE* key, CK_OBJECT_CLASS keyClass, CK_KEY_TYPE keyType, Pkcs11Session* session, char* label, int labelLen) { int ret = 0; CK_ULONG count; CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &keyClass, sizeof(keyClass) }, { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, { CKA_LABEL, label, (CK_ULONG)labelLen } }; CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate); WOLFSSL_MSG("PKCS#11: Find Key By Label"); ret = Pkcs11FindKeyByTemplate(key, session, keyTemplate, keyTmplCnt, &count); if (ret == 0 && count == 0) ret = WC_HW_E; return ret; } /** * Find the PKCS#11 object containing the private key data by ID. * * @param [out] key Handle to key object. * @param [in] keyClass Public or private key class. * @param [in] keyType Type of key. * @param [in] session Session object. * @param [in] id Identifier set against a key. * @param [in] idLen Length of identifier. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11FindKeyById(CK_OBJECT_HANDLE* key, CK_OBJECT_CLASS keyClass, CK_KEY_TYPE keyType, Pkcs11Session* session, byte* id, int idLen) { int ret = 0; CK_ULONG count; CK_ATTRIBUTE keyTemplate[] = { #ifndef WC_PKCS11_FIND_WITH_ID_ONLY { CKA_CLASS, &keyClass, sizeof(keyClass) }, { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, #endif { CKA_ID, id, (CK_ULONG)idLen } }; CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate); WOLFSSL_MSG("PKCS#11: Find Key By Id"); ret = Pkcs11FindKeyByTemplate(key, session, keyTemplate, keyTmplCnt, &count); if (ret == 0 && count == 0) ret = WC_HW_E; return ret; } #endif #ifndef NO_RSA /** * Find the PKCS#11 object containing the RSA public or private key data with * the modulus specified. * * @param [out] key Handle to key object. * @param [in] keyClass Public or private key class. * @param [in] session Session object. * @param [in] rsaKey RSA key with modulus to search on. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11FindRsaKey(CK_OBJECT_HANDLE* key, CK_OBJECT_CLASS keyClass, Pkcs11Session* session, RsaKey* rsaKey) { CK_ULONG count; CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &keyClass, sizeof(keyClass) }, { CKA_KEY_TYPE, &rsaKeyType, sizeof(rsaKeyType) }, { CKA_MODULUS, NULL, 0 }, }; CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate); /* Set the modulus. */ keyTemplate[2].pValue = rsaKey->n.raw.buf; keyTemplate[2].ulValueLen = rsaKey->n.raw.len; return Pkcs11FindKeyByTemplate(key, session, keyTemplate, keyTmplCnt, &count); } /** * Make a handle to a public RSA key. * * @param [in] session Session object. * @param [in] rsaKey RSA key with modulus to search on. * @param [in] sessionKey Whether to create a session key. * @param [out] publicKey Handle to public key object. */ static int Pkcs11RsaPublicKey(Pkcs11Session* session, RsaKey* rsaKey, int sessionKey, CK_OBJECT_HANDLE* publicKey) { int ret = 0; CK_RV rv; CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, { CKA_KEY_TYPE, &rsaKeyType, sizeof(rsaKeyType) }, { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, { CKA_MODULUS, NULL, 0 }, { CKA_PUBLIC_EXPONENT, NULL, 0 } }; CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate); if (sessionKey) { /* Set the modulus and public exponent data. */ keyTemplate[3].pValue = rsaKey->n.raw.buf; keyTemplate[3].ulValueLen = rsaKey->n.raw.len; keyTemplate[4].pValue = rsaKey->e.raw.buf; keyTemplate[4].ulValueLen = rsaKey->e.raw.len; PKCS11_DUMP_TEMPLATE("RSA Public Key", keyTemplate, keyTmplCnt); /* Create an object containing public key data for device to use. */ rv = session->func->C_CreateObject(session->handle, keyTemplate, keyTmplCnt, publicKey); PKCS11_RV("C_CreateObject", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } else if (rsaKey->labelLen > 0) { ret = Pkcs11FindKeyByLabel(publicKey, CKO_PUBLIC_KEY, CKK_RSA, session, rsaKey->label, rsaKey->labelLen); } else { ret = Pkcs11FindKeyById(publicKey, CKO_PUBLIC_KEY, CKK_RSA, session, rsaKey->id, rsaKey->idLen); } return ret; } /** * Get the RSA public key data from the PKCS#11 object. * * @param [in] key RSA key to put the data into. * @param [in] session Session object. * @param [in] pubkey Public key object. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return 0 on success. */ static int Pkcs11GetRsaPublicKey(RsaKey* key, Pkcs11Session* session, CK_OBJECT_HANDLE pubKey) { int ret = 0; unsigned char* mod = NULL; unsigned char* exp = NULL; int modSz, expSz; CK_ATTRIBUTE tmpl[] = { { CKA_MODULUS, NULL_PTR, 0 }, { CKA_PUBLIC_EXPONENT, NULL_PTR, 0 } }; CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); CK_RV rv; PKCS11_DUMP_TEMPLATE("Get RSA Public Key Length", tmpl, tmplCnt); rv = session->func->C_GetAttributeValue(session->handle, pubKey, tmpl, tmplCnt); PKCS11_RV("C_GetAttributeValue", rv); if (rv != CKR_OK) { ret = WC_HW_E; } PKCS11_DUMP_TEMPLATE("RSA Public Key Length", tmpl, tmplCnt); if (ret == 0) { modSz = (int)tmpl[0].ulValueLen; expSz = (int)tmpl[1].ulValueLen; mod = (unsigned char*)XMALLOC(modSz, key->heap, DYNAMIC_TYPE_TMP_BUFFER); if (mod == NULL) ret = MEMORY_E; } if (ret == 0) { exp = (unsigned char*)XMALLOC(expSz, key->heap, DYNAMIC_TYPE_TMP_BUFFER); if (exp == NULL) ret = MEMORY_E; } if (ret == 0) { tmpl[0].pValue = mod; tmpl[1].pValue = exp; PKCS11_DUMP_TEMPLATE("Get RSA Public Key", tmpl, tmplCnt); rv = session->func->C_GetAttributeValue(session->handle, pubKey, tmpl, tmplCnt); PKCS11_RV("C_GetAttributeValue", rv); if (rv != CKR_OK) { ret = WC_HW_E; } PKCS11_DUMP_TEMPLATE("RSA Public Key", tmpl, tmplCnt); } if (ret == 0) ret = wc_RsaPublicKeyDecodeRaw(mod, modSz, exp, expSz, key); XFREE(exp, key->heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(mod, key->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; } /** * Get the RSA modulus size in bytes from the PKCS#11 object. * * @param [in] session Session object. * @param [in] pubkey Public key object. * @param [out] modSize Size of the modulus in bytes. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return 0 on success. */ static int Pkcs11GetRsaModulusSize(Pkcs11Session* session, CK_OBJECT_HANDLE pubKey, int* modSize) { int ret = 0; CK_ATTRIBUTE tmpl[] = { { CKA_MODULUS, NULL_PTR, 0 } }; CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); CK_RV rv; PKCS11_DUMP_TEMPLATE("Get RSA Modulus Length", tmpl, tmplCnt); rv = session->func->C_GetAttributeValue(session->handle, pubKey, tmpl, tmplCnt); PKCS11_RV("C_GetAttributeValue", rv); if (rv != CKR_OK) { ret = WC_HW_E; } PKCS11_DUMP_TEMPLATE("RSA Modulus Length", tmpl, tmplCnt); if (ret == 0) { *modSize = (int)tmpl[0].ulValueLen; } return ret; } /** * Make a handle to a private RSA key. * * @param [in] session Session object. * @param [in] rsaKey RSA key with modulus to search on. * @param [in] sessionKey Whether to create a session key. * @param [out] publicKey Handle to private key object. */ static int Pkcs11RsaPrivateKey(Pkcs11Session* session, RsaKey* rsaKey, int sessionKey, CK_OBJECT_HANDLE* privateKey) { int ret; if (sessionKey) { #ifdef WOLFSSL_KEY_GEN ret = Pkcs11CreateRsaPrivateKey(privateKey, session, rsaKey, 0); #else /* RSA Key Generation support not compiled in */ ret = NOT_COMPILED_IN; #endif } else if (rsaKey->labelLen > 0) { ret = Pkcs11FindKeyByLabel(privateKey, CKO_PRIVATE_KEY, CKK_RSA, session, rsaKey->label, rsaKey->labelLen); } else if (rsaKey->idLen > 0) { ret = Pkcs11FindKeyById(privateKey, CKO_PRIVATE_KEY, CKK_RSA, session, rsaKey->id, rsaKey->idLen); } else { ret = Pkcs11FindRsaKey(privateKey, CKO_PRIVATE_KEY, session, rsaKey); } if ((ret == 0) && (!sessionKey)) { ret = Pkcs11GetRsaPublicKey(rsaKey, session, *privateKey); } return ret; } /** * Get the hash length associated with the WolfCrypt hash type. * * @param [in] hType Hash Type. * @return -1 if hash type not recognized. * @return hash length on success. */ int wc_hash2sz(int hType) { switch(hType) { case WC_HASH_TYPE_SHA: return 20; case WC_HASH_TYPE_SHA224: return 28; case WC_HASH_TYPE_SHA256: return 32; case WC_HASH_TYPE_SHA384: return 48; case WC_HASH_TYPE_SHA512: return 64; default: /* unsupported WC_HASH_TYPE_XXXX */ return -1; } } /** * Get PKCS11 hash mechanism associated with the WolfCrypt hash type. * * @param [in] hType Hash Type. * @return 0 if hash type not recognized. * @return PKCS11 mechanism on success. */ CK_MECHANISM_TYPE wc_hash2ckm(int hType) { switch(hType) { case WC_HASH_TYPE_SHA: return CKM_SHA_1; case WC_HASH_TYPE_SHA224: return CKM_SHA224; case WC_HASH_TYPE_SHA256: return CKM_SHA256; case WC_HASH_TYPE_SHA384: return CKM_SHA384; case WC_HASH_TYPE_SHA512: return CKM_SHA512; default: /* unsupported WC_HASH_TYPE_XXXX */ return 0UL; } } /** * Get PKCS11 MGF hash mechanism associated with the WolfCrypt MGF hash type. * * @param [in] mgf MGF Type. * @return 0 if MGF type not recognized. * @return PKCS11 MGF hash mechanism on success. */ CK_MECHANISM_TYPE wc_mgf2ckm(int mgf) { switch(mgf) { case WC_MGF1SHA1: return CKG_MGF1_SHA1; case WC_MGF1SHA224: return CKG_MGF1_SHA224; case WC_MGF1SHA256: return CKG_MGF1_SHA256; case WC_MGF1SHA384: return CKG_MGF1_SHA384; case WC_MGF1SHA512: return CKG_MGF1_SHA512; default: /* unsupported WC_MGF1XXXX */ return 0x0UL; } } /** * Exponentiate the input with the public part of the RSA key. * Used in public encrypt and decrypt. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * 0 on success. */ static int Pkcs11RsaEncrypt(Pkcs11Session* session, wc_CryptoInfo* info, CK_OBJECT_HANDLE key) { int ret = 0; CK_MECHANISM_TYPE mechanism = 0x0UL; CK_RV rv; CK_MECHANISM mech; CK_ULONG outLen; #ifdef WOLF_CRYPTO_CB_RSA_PAD CK_RSA_PKCS_OAEP_PARAMS oaepParams; #endif WOLFSSL_MSG("PKCS#11: RSA Public Key Operation"); if (info->pk.rsa.outLen == NULL) { ret = BAD_FUNC_ARG; } switch(info->pk.type) { #ifdef WOLF_CRYPTO_CB_RSA_PAD case WC_PK_TYPE_RSA_PKCS: mechanism = CKM_RSA_PKCS; break; case WC_PK_TYPE_RSA_OAEP: mechanism = CKM_RSA_PKCS_OAEP; break; #endif case WC_PK_TYPE_RSA: mechanism = CKM_RSA_X_509; break; } if (ret == 0) { /* Raw RSA encrypt/decrypt operation. */ mech.mechanism = mechanism; mech.ulParameterLen = 0; mech.pParameter = NULL; #ifdef WOLF_CRYPTO_CB_RSA_PAD if (mechanism == CKM_RSA_PKCS_OAEP) { XMEMSET(&oaepParams, 0, sizeof(oaepParams)); mech.ulParameterLen = sizeof(CK_RSA_PKCS_OAEP_PARAMS); mech.pParameter = &oaepParams; oaepParams.source = CKZ_DATA_SPECIFIED; oaepParams.hashAlg = wc_hash2ckm(info->pk.rsa.padding->hash); oaepParams.mgf = wc_mgf2ckm(info->pk.rsa.padding->mgf); } #endif rv = session->func->C_EncryptInit(session->handle, &mech, key); PKCS11_RV("C_EncryptInit", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { outLen = (CK_ULONG)*info->pk.rsa.outLen; rv = session->func->C_Encrypt(session->handle, (CK_BYTE_PTR)info->pk.rsa.in, info->pk.rsa.inLen, info->pk.rsa.out, &outLen); PKCS11_RV("C_Encrypt", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { *info->pk.rsa.outLen = (word32)outLen; } return ret; } /** * Exponentiate the input with the private part of the RSA key. * Used in private encrypt and decrypt. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @param [in] func Function to perform - decrypt or sign. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11RsaDecrypt(Pkcs11Session* session, wc_CryptoInfo* info, CK_OBJECT_HANDLE key) { int ret = 0; CK_MECHANISM_TYPE mechanism = 0x0UL; CK_RV rv; CK_MECHANISM mech; CK_ULONG outLen; #ifdef WOLF_CRYPTO_CB_RSA_PAD CK_RSA_PKCS_OAEP_PARAMS oaepParams; #endif WOLFSSL_MSG("PKCS#11: RSA Private Key Operation"); if (info->pk.rsa.outLen == NULL) { ret = BAD_FUNC_ARG; } switch(info->pk.type) { #ifdef WOLF_CRYPTO_CB_RSA_PAD case WC_PK_TYPE_RSA_PKCS: mechanism = CKM_RSA_PKCS; break; case WC_PK_TYPE_RSA_OAEP: mechanism = CKM_RSA_PKCS_OAEP; break; #endif case WC_PK_TYPE_RSA: mechanism = CKM_RSA_X_509; break; } if (ret == 0) { /* Raw RSA encrypt/decrypt operation. */ mech.mechanism = mechanism; mech.ulParameterLen = 0; mech.pParameter = NULL; #ifdef WOLF_CRYPTO_CB_RSA_PAD if (mechanism == CKM_RSA_PKCS_OAEP) { XMEMSET(&oaepParams, 0, sizeof(oaepParams)); mech.ulParameterLen = sizeof(CK_RSA_PKCS_OAEP_PARAMS); mech.pParameter = &oaepParams; oaepParams.source = CKZ_DATA_SPECIFIED; oaepParams.hashAlg = wc_hash2ckm(info->pk.rsa.padding->hash); oaepParams.mgf = wc_mgf2ckm(info->pk.rsa.padding->mgf); } #endif rv = session->func->C_DecryptInit(session->handle, &mech, key); PKCS11_RV("C_DecryptInit", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { PKCS11_VAL("C_Decrypt inLen", info->pk.rsa.inLen); PKCS11_VAL("C_Decrypt outLen", *info->pk.rsa.outLen); outLen = (CK_ULONG)*info->pk.rsa.outLen; rv = session->func->C_Decrypt(session->handle, (CK_BYTE_PTR)info->pk.rsa.in, info->pk.rsa.inLen, info->pk.rsa.out, &outLen); PKCS11_RV("C_Decrypt", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { *info->pk.rsa.outLen = (word32)outLen; } return ret; } /** * Exponentiate the input with the private part of the RSA key. * Used in private encrypt and decrypt. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @param [in] func Function to perform - decrypt or sign. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11RsaSign(Pkcs11Session* session, wc_CryptoInfo* info, CK_OBJECT_HANDLE key) { int ret = 0; CK_RV rv; CK_MECHANISM mech; CK_ULONG outLen; CK_MECHANISM_TYPE mechanism; #ifdef WOLF_CRYPTO_CB_RSA_PAD CK_RSA_PKCS_PSS_PARAMS pssParams; int hLen; int saltLen; #endif WOLFSSL_MSG("PKCS#11: RSA Private Key Operation"); if (info->pk.rsa.outLen == NULL) { ret = BAD_FUNC_ARG; } switch(info->pk.type) { #ifdef WOLF_CRYPTO_CB_RSA_PAD case WC_PK_TYPE_RSA_PKCS: mechanism = CKM_RSA_PKCS; break; case WC_PK_TYPE_RSA_PSS: mechanism = CKM_RSA_PKCS_PSS; break; #endif /* WOLF_CRYPTO_CB_RSA_PAD */ default: mechanism = CKM_RSA_X_509; break; } if (ret == 0) { /* Raw RSA encrypt/decrypt operation. */ mech.mechanism = mechanism; mech.ulParameterLen = 0; mech.pParameter = NULL; #ifdef WOLF_CRYPTO_CB_RSA_PAD if (mechanism == CKM_RSA_PKCS_PSS) { mech.ulParameterLen = sizeof(CK_RSA_PKCS_PSS_PARAMS); mech.pParameter = &pssParams; pssParams.hashAlg = wc_hash2ckm(info->pk.rsa.padding->hash); pssParams.mgf = wc_mgf2ckm(info->pk.rsa.padding->mgf); saltLen = info->pk.rsa.padding->saltLen; hLen = wc_hash2sz(info->pk.rsa.padding->hash); /* Same salt length code as rsa.c */ if (saltLen == RSA_PSS_SALT_LEN_DEFAULT) saltLen = hLen; #ifndef WOLFSSL_PSS_LONG_SALT else if (saltLen > hLen) { return PSS_SALTLEN_E; } #endif #ifndef WOLFSSL_PSS_SALT_LEN_DISCOVER else if (saltLen < RSA_PSS_SALT_LEN_DEFAULT) { return PSS_SALTLEN_E; } #else else if (saltLen == RSA_PSS_SALT_LEN_DISCOVER) { saltLen = *(info->pk.rsa.outLen) - hLen - 2; if (saltLen < 0) { return PSS_SALTLEN_E; } } else if (saltLen < RSA_PSS_SALT_LEN_DISCOVER) { return PSS_SALTLEN_E; } #endif if (*(info->pk.rsa.outLen) - hLen < (word32)(saltLen + 2)) { return PSS_SALTLEN_E; } pssParams.sLen = saltLen; } #endif /* WOLF_CRYPTO_CB_RSA_PAD */ rv = session->func->C_SignInit(session->handle, &mech, key); PKCS11_RV("C_SignInit", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { PKCS11_VAL("C_Sign inLen", info->pk.rsa.inLen); PKCS11_VAL("C_Sign outLen", *info->pk.rsa.outLen); outLen = (CK_ULONG)*info->pk.rsa.outLen; rv = session->func->C_Sign(session->handle, (CK_BYTE_PTR)info->pk.rsa.in, info->pk.rsa.inLen, info->pk.rsa.out, &outLen); PKCS11_RV("C_Sign", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) *info->pk.rsa.outLen = (word32)outLen; return ret; } /** * Perform an RSA operation. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11Rsa(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; CK_MECHANISM_INFO mechInfo; CK_MECHANISM_TYPE mechanism = 0x0UL; int sessionKey = 0; CK_OBJECT_HANDLE key; RsaKey* rsaKey = info->pk.rsa.key; int type = info->pk.rsa.type; switch(info->pk.type) { #ifndef NO_PKCS11_RSA_PKCS case WC_PK_TYPE_RSA_PKCS: mechanism = CKM_RSA_PKCS; break; case WC_PK_TYPE_RSA_PSS: mechanism = CKM_RSA_PKCS_PSS; break; case WC_PK_TYPE_RSA_OAEP: mechanism = CKM_RSA_PKCS_OAEP; break; #endif /* !NO_PKCS11_RSA_PKCS */ case WC_PK_TYPE_RSA: mechanism = CKM_RSA_X_509; break; } /* Check operation is supported. */ ret = Pkcs11MechAvail(session, mechanism, &mechInfo); if (ret == 0) { if ((type == RSA_PUBLIC_ENCRYPT) || (type == RSA_PUBLIC_DECRYPT)) { sessionKey = !mp_iszero(&rsaKey->e); /* Make a handle to a public key. */ ret = Pkcs11RsaPublicKey(session, rsaKey, sessionKey, &key); } else { sessionKey = !mp_iszero(&rsaKey->d); /* Make a handle to a private key. */ ret = Pkcs11RsaPrivateKey(session, rsaKey, sessionKey, &key); } } if (ret == 0) { if (type == RSA_PUBLIC_ENCRYPT) { WOLFSSL_MSG("PKCS#11: Public Encrypt"); if ((mechInfo.flags & CKF_ENCRYPT) != 0) { ret = Pkcs11RsaEncrypt(session, info, key); } else { ret = NOT_COMPILED_IN; } } else if (type == RSA_PUBLIC_DECRYPT) { WOLFSSL_MSG("PKCS#11: Public Decrypt"); if ((mechInfo.flags & CKF_ENCRYPT) != 0) { ret = Pkcs11RsaEncrypt(session, info, key); } else { ret = NOT_COMPILED_IN; } } else if (type == RSA_PRIVATE_DECRYPT) { WOLFSSL_MSG("PKCS#11: Private Decrypt"); if ((mechInfo.flags & CKF_DECRYPT) != 0) { ret = Pkcs11RsaDecrypt(session, info, key); } else { ret = Pkcs11RsaSign(session, info, key); } } else if (type == RSA_PRIVATE_ENCRYPT) { WOLFSSL_MSG("PKCS#11: Private Encrypt"); if ((mechInfo.flags & CKF_SIGN) != 0) { ret = Pkcs11RsaSign(session, info, key); } else { ret = Pkcs11RsaDecrypt(session, info, key); } } } if (sessionKey) { session->func->C_DestroyObject(session->handle, key); } return ret; } #ifdef WOLFSSL_KEY_GEN /** * Perform an RSA key generation operation. * The private key data stays on the device. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11RsaKeyGen(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; RsaKey* key = info->pk.rsakg.key; CK_RV rv; CK_ULONG bits = info->pk.rsakg.size; CK_OBJECT_HANDLE pubKey = NULL_PTR, privKey = NULL_PTR; CK_MECHANISM mech; static CK_BYTE pub_exp[] = { 0x01, 0x00, 0x01, 0x00 }; CK_ATTRIBUTE pubKeyTmpl[] = { { CKA_MODULUS_BITS, &bits, sizeof(bits) }, { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, { CKA_PUBLIC_EXPONENT, &pub_exp, sizeof(pub_exp) } }; CK_ULONG pubTmplCnt = sizeof(pubKeyTmpl)/sizeof(*pubKeyTmpl); /* Empty entries for optional label/ID. */ CK_ATTRIBUTE privKeyTmpl[] = { { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, { 0, NULL, 0 }, { 0, NULL, 0 } }; /* 2 mandatory entries + 2 optional. */ int privTmplCnt = 2; int i; ret = Pkcs11MechAvail(session, CKM_RSA_PKCS_KEY_PAIR_GEN, NULL); if (ret == 0) { WOLFSSL_MSG("PKCS#11: RSA Key Generation Operation"); /* Most commonly used public exponent value (array initialized). */ if (info->pk.rsakg.e != WC_RSA_EXPONENT) { for (i = 0; i < (int)sizeof(pub_exp); i++) pub_exp[i] = (info->pk.rsakg.e >> (8 * i)) & 0xff; } for (i = (int)sizeof(pub_exp) - 1; pub_exp[i] == 0; i--) { } pubKeyTmpl[3].ulValueLen = i + 1; if (key->labelLen != 0) { privKeyTmpl[privTmplCnt].type = CKA_LABEL; privKeyTmpl[privTmplCnt].pValue = key->label; privKeyTmpl[privTmplCnt].ulValueLen = key->labelLen; privTmplCnt++; } if (key->idLen != 0) { privKeyTmpl[privTmplCnt].type = CKA_ID; privKeyTmpl[privTmplCnt].pValue = key->id; privKeyTmpl[privTmplCnt].ulValueLen = key->idLen; privTmplCnt++; } mech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; mech.ulParameterLen = 0; mech.pParameter = NULL; PKCS11_DUMP_TEMPLATE("Public Key", pubKeyTmpl, pubTmplCnt); PKCS11_DUMP_TEMPLATE("Private Key", privKeyTmpl, privTmplCnt); rv = session->func->C_GenerateKeyPair(session->handle, &mech, pubKeyTmpl, pubTmplCnt, privKeyTmpl, privTmplCnt, &pubKey, &privKey); PKCS11_RV("C_GenerateKeyPair", rv); if (rv != CKR_OK) { ret = -1; } } if (ret == 0) ret = Pkcs11GetRsaPublicKey(key, session, pubKey); if (pubKey != NULL_PTR) ret = (int)session->func->C_DestroyObject(session->handle, pubKey); if (ret != 0 && privKey != NULL_PTR) ret = (int)session->func->C_DestroyObject(session->handle, privKey); return ret; } #endif /* WOLFSSL_KEY_GEN */ #endif /* !NO_RSA */ #ifdef HAVE_ECC /** * Find the PKCS#11 object containing the ECC public or private key data. * Search for public key by public point. * * @param [out] key Handle to key object. * @param [in] keyClass Public or private key class. * @param [in] session Session object. * @param [in] eccKey ECC key with parameters. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return 0 on success. */ static int Pkcs11FindEccKey(CK_OBJECT_HANDLE* key, CK_OBJECT_CLASS keyClass, Pkcs11Session* session, ecc_key* eccKey, int op) { int ret = 0; int i; unsigned char* ecPoint = NULL; word32 len = 0; CK_ULONG count; CK_UTF8CHAR params[ECC_MAX_OID_LEN]; CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &keyClass, sizeof(keyClass) }, { CKA_KEY_TYPE, &ecKeyType, sizeof(ecKeyType) }, { CKA_EC_PARAMS, params, 0 }, { op, &ckTrue, sizeof(ckTrue) }, { CKA_EC_POINT, NULL, 0 }, }; CK_ULONG attrCnt = 4; ret = Pkcs11EccSetParams(eccKey, keyTemplate, 2); if (ret == 0 && keyClass == CKO_PUBLIC_KEY) { /* ASN1 encoded: OCT + uncompressed point */ len = 3 + 1 + 2 * eccKey->dp->size; ecPoint = (unsigned char*)XMALLOC(len, eccKey->heap, DYNAMIC_TYPE_ECC); if (ecPoint == NULL) ret = MEMORY_E; } if (ret == 0 && keyClass == CKO_PUBLIC_KEY) { len -= 3; i = 0; ecPoint[i++] = ASN_OCTET_STRING; if (len >= ASN_LONG_LENGTH) ecPoint[i++] = (ASN_LONG_LENGTH | 1); ecPoint[i++] = len; if (eccKey->type == 0) eccKey->type = ECC_PUBLICKEY; PRIVATE_KEY_UNLOCK(); ret = wc_ecc_export_x963(eccKey, ecPoint + i, &len); PRIVATE_KEY_LOCK(); } if (ret == 0 && keyClass == CKO_PUBLIC_KEY) { keyTemplate[attrCnt].pValue = ecPoint; keyTemplate[attrCnt].ulValueLen = len + i; attrCnt++; } if (ret == 0) { ret = Pkcs11FindKeyByTemplate(key, session, keyTemplate, attrCnt, &count); } XFREE(ecPoint, eccKey->heap, DYNAMIC_TYPE_ECC); return ret; } /** * Gets the public key data from the PKCS#11 object and puts into the ECC key. * * @param [in] key ECC public key. * @param [in] session Session object. * @param [in] pubKey ECC public key PKCS#11 object. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return 0 on success. */ static int Pkcs11GetEccPublicKey(ecc_key* key, Pkcs11Session* session, CK_OBJECT_HANDLE pubKey) { int ret = 0; word32 i = 0; int curveIdx; unsigned char* point = NULL; int pointSz = 0; byte tag; CK_RV rv; CK_ATTRIBUTE tmpl[] = { { CKA_EC_POINT, NULL_PTR, 0 }, }; CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); rv = session->func->C_GetAttributeValue(session->handle, pubKey, tmpl, tmplCnt); PKCS11_RV("C_GetAttributeValue", rv); if (rv != CKR_OK) { ret = WC_HW_E; } if (ret == 0) { pointSz = (int)tmpl[0].ulValueLen; point = (unsigned char*)XMALLOC(pointSz, key->heap, DYNAMIC_TYPE_ECC); if (point == NULL) ret = MEMORY_E; } if (ret == 0) { tmpl[0].pValue = point; PKCS11_DUMP_TEMPLATE("Get Ec Public Key", tmpl, tmplCnt); rv = session->func->C_GetAttributeValue(session->handle, pubKey, tmpl, tmplCnt); PKCS11_RV("C_GetAttributeValue", rv); if (rv != CKR_OK) { ret = WC_HW_E; } PKCS11_DUMP_TEMPLATE("Ec Public Key", tmpl, tmplCnt); } /* Make sure the data is big enough for ASN.1: OCT + uncompressed point */ if (ret == 0 && pointSz < key->dp->size * 2 + 1 + 2) ret = ASN_PARSE_E; /* Step over the OCTET_STRING wrapper. */ if (ret == 0 && GetASNTag(point, &i, &tag, pointSz) != 0) ret = ASN_PARSE_E; if (ret == 0 && tag != ASN_OCTET_STRING) ret = ASN_PARSE_E; if (ret == 0 && point[i] >= ASN_LONG_LENGTH) { if (point[i++] != (ASN_LONG_LENGTH | 1)) ret = ASN_PARSE_E; else if (pointSz < key->dp->size * 2 + 1 + 3) ret = ASN_PARSE_E; } if (ret == 0 && point[i++] != key->dp->size * 2 + 1) ret = ASN_PARSE_E; if (ret == 0) { curveIdx = wc_ecc_get_curve_idx(key->dp->id); ret = wc_ecc_import_point_der(point + i, pointSz - i, curveIdx, &key->pubkey); } /* make sure the ecc_key type has been set */ if (ret == 0 && key->type == 0) { key->type = ECC_PUBLICKEY; } XFREE(point, key->heap, DYNAMIC_TYPE_ECC); return ret; } #ifndef NO_PKCS11_EC_KEYGEN /** * Perform an ECC key generation operation. * The private key data stays on the device. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11EcKeyGen(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; ecc_key* key = info->pk.eckg.key; CK_RV rv; CK_OBJECT_HANDLE pubKey = NULL_PTR, privKey = NULL_PTR; CK_MECHANISM mech; CK_UTF8CHAR params[ECC_MAX_OID_LEN]; CK_ATTRIBUTE pubKeyTmpl[] = { { CKA_EC_PARAMS, params, 0 }, { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, }; int pubTmplCnt = 1; /* Empty entries for optional label/ID. */ CK_ATTRIBUTE privKeyTmplDerive[] = { { CKA_DERIVE, &ckTrue, sizeof(ckTrue) }, { 0, NULL, 0 }, { 0, NULL, 0 }, }; /* Empty entries for optional label/ID. */ CK_ATTRIBUTE privKeyTmplEncSign[] = { { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, { 0, NULL, 0 }, { 0, NULL, 0 }, }; CK_ATTRIBUTE* privKeyTmpl = privKeyTmplDerive; /* Mandatory entries + 2 optional. */ int privTmplCnt = 1; ret = Pkcs11MechAvail(session, CKM_EC_KEY_PAIR_GEN, NULL); if (ret == 0) { WOLFSSL_MSG("PKCS#11: EC Key Generation Operation"); ret = Pkcs11EccSetParams(key, pubKeyTmpl, 0); } if (ret == 0) { /* Default is to use for derivation. */ if ((key->flags & WC_ECC_FLAG_DEC_SIGN) == WC_ECC_FLAG_DEC_SIGN) { privKeyTmpl = privKeyTmplEncSign; privTmplCnt = 2; pubTmplCnt = 2; } if (key->labelLen != 0) { privKeyTmpl[privTmplCnt].type = CKA_LABEL; privKeyTmpl[privTmplCnt].pValue = key->label; privKeyTmpl[privTmplCnt].ulValueLen = key->labelLen; privTmplCnt++; } if (key->idLen != 0) { privKeyTmpl[privTmplCnt].type = CKA_ID; privKeyTmpl[privTmplCnt].pValue = key->id; privKeyTmpl[privTmplCnt].ulValueLen = key->idLen; privTmplCnt++; } mech.mechanism = CKM_EC_KEY_PAIR_GEN; mech.ulParameterLen = 0; mech.pParameter = NULL; PKCS11_DUMP_TEMPLATE("Ec Private", privKeyTmpl, privTmplCnt); PKCS11_DUMP_TEMPLATE("Ec Public", pubKeyTmpl, pubTmplCnt); rv = session->func->C_GenerateKeyPair(session->handle, &mech, pubKeyTmpl, pubTmplCnt, privKeyTmpl, privTmplCnt, &pubKey, &privKey); PKCS11_RV("C_GenerateKeyPair", rv); if (rv != CKR_OK) { ret = -1; } } if (ret == 0) ret = Pkcs11GetEccPublicKey(key, session, pubKey); if (pubKey != NULL_PTR) session->func->C_DestroyObject(session->handle, pubKey); if (ret == 0 && privKey != NULL_PTR) { key->devCtx = (void*)(wc_ptr_t)privKey; } else if (ret != 0 && privKey != NULL_PTR) { session->func->C_DestroyObject(session->handle, privKey); } return ret; } #endif #ifndef NO_PKCS11_ECDH /** * Extracts the secret key data from the PKCS#11 object. * * @param [in] session Session object. * @param [in] secret PKCS#11 object with the secret key data. * @param [in] out Buffer to hold secret data. * @param [in,out] outLen On in, length of buffer. * On out, the length of data in buffer. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11ExtractSecret(Pkcs11Session* session, CK_OBJECT_HANDLE secret, byte* out, word32* outLen) { int ret = 0; CK_ATTRIBUTE tmpl[] = { {CKA_VALUE, NULL_PTR, 0} }; CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); CK_RV rv; PKCS11_DUMP_TEMPLATE("Get Secret Length", tmpl, tmplCnt); rv = session->func->C_GetAttributeValue(session->handle, secret, tmpl, tmplCnt); PKCS11_RV("C_GetAttributeValue", rv); if (rv != CKR_OK) { ret = WC_HW_E; } PKCS11_DUMP_TEMPLATE("Secret Length", tmpl, tmplCnt); if (ret == 0) { if (tmpl[0].ulValueLen == CK_UNAVAILABLE_INFORMATION) ret = WC_HW_E; else if (tmpl[0].ulValueLen > *outLen) ret = BUFFER_E; } if (ret == 0) { tmpl[0].pValue = out; PKCS11_DUMP_TEMPLATE("Get Secret", tmpl, tmplCnt); rv = session->func->C_GetAttributeValue(session->handle, secret, tmpl, tmplCnt); PKCS11_RV("C_GetAttributeValue", rv); if (rv != CKR_OK) { ret = WC_HW_E; } PKCS11_DUMP_TEMPLATE("Secret", tmpl, tmplCnt); *outLen = (word32)tmpl[0].ulValueLen; } return ret; } /** * Performs the ECDH secret generation operation. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * 0 on success. */ static int Pkcs11ECDH(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; int sessionKey = 0; unsigned char* point = NULL; word32 pointLen; CK_RV rv; CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; CK_MECHANISM mech; CK_ECDH1_DERIVE_PARAMS params; CK_OBJECT_HANDLE privateKey = NULL_PTR; CK_OBJECT_HANDLE secret = CK_INVALID_HANDLE; CK_ULONG secSz; CK_ATTRIBUTE tmpl[] = { { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, { CKA_SENSITIVE, &ckFalse, sizeof(ckFalse) }, { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, { CKA_VALUE_LEN, &secSz, sizeof(secSz) } }; CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); ret = Pkcs11MechAvail(session, CKM_ECDH1_DERIVE, NULL); if (ret == 0 && info->pk.ecdh.outlen == NULL) { ret = BAD_FUNC_ARG; } if (ret == 0) { WOLFSSL_MSG("PKCS#11: EC Key Derivation Operation"); if (info->pk.ecdh.private_key->devCtx != NULL) { privateKey = (CK_OBJECT_HANDLE)(wc_ptr_t) info->pk.ecdh.private_key->devCtx; } else if ((sessionKey = !mp_iszero( wc_ecc_key_get_priv(info->pk.ecdh.private_key)))) ret = Pkcs11CreateEccPrivateKey(&privateKey, session, info->pk.ecdh.private_key, CKA_DERIVE); else if (info->pk.ecdh.private_key->labelLen > 0) { ret = Pkcs11FindKeyByLabel(&privateKey, CKO_PRIVATE_KEY, CKK_EC, session, info->pk.ecdh.private_key->label, info->pk.ecdh.private_key->labelLen); } else if (info->pk.ecdh.private_key->idLen > 0) { ret = Pkcs11FindKeyById(&privateKey, CKO_PRIVATE_KEY, CKK_EC, session, info->pk.ecdh.private_key->id, info->pk.ecdh.private_key->idLen); } else { ret = Pkcs11FindEccKey(&privateKey, CKO_PRIVATE_KEY, session, info->pk.ecdh.public_key, CKA_DERIVE); } } if (ret == 0) { PRIVATE_KEY_UNLOCK(); ret = wc_ecc_export_x963(info->pk.ecdh.public_key, NULL, &pointLen); PRIVATE_KEY_LOCK(); if (ret == WC_NO_ERR_TRACE(LENGTH_ONLY_E)) { point = (unsigned char*)XMALLOC(pointLen, info->pk.ecdh.public_key->heap, DYNAMIC_TYPE_ECC_BUFFER); PRIVATE_KEY_UNLOCK(); ret = wc_ecc_export_x963(info->pk.ecdh.public_key, point, &pointLen); PRIVATE_KEY_LOCK(); } } if (ret == 0) { secSz = *info->pk.ecdh.outlen; if (info->pk.ecdh.private_key->dp != NULL && secSz > (CK_ULONG)info->pk.ecdh.private_key->dp->size) secSz = info->pk.ecdh.private_key->dp->size; params.kdf = CKD_NULL; params.pSharedData = NULL; params.ulSharedDataLen = 0; params.pPublicData = point; params.ulPublicDataLen = pointLen; mech.mechanism = CKM_ECDH1_DERIVE; mech.ulParameterLen = sizeof(params); mech.pParameter = ¶ms; PKCS11_DUMP_TEMPLATE("ECDH key", tmpl, tmplCnt); rv = session->func->C_DeriveKey(session->handle, &mech, privateKey, tmpl, tmplCnt, &secret); PKCS11_RV("C_DeriveKey", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { ret = Pkcs11ExtractSecret(session, secret, info->pk.ecdh.out, info->pk.ecdh.outlen); } if (secret != CK_INVALID_HANDLE) session->func->C_DestroyObject(session->handle, secret); if (sessionKey && privateKey != NULL_PTR) session->func->C_DestroyObject(session->handle, privateKey); if (point != NULL) XFREE(point, info->pk.ecdh.public_key->heap, DYNAMIC_TYPE_ECC_BUFFER); return ret; } #endif /** * Encode, in place, the ECDSA signature. * Two fixed width values into ASN.1 DER encoded SEQ { INT, INT } * * @param [in,out] sig Signature data. * @param [in] sz Size of original signature data. * @return Length of the ASN.1 DER encoded signature. */ static word32 Pkcs11ECDSASig_Encode(byte* sig, word32 sz) { word32 rHigh, sHigh, seqLen; word32 rStart = 0, sStart = 0; word32 sigSz, rSz, rLen, sSz, sLen; word32 i; /* Find first byte of data in r and s. */ while (rStart < sz - 1 && sig[rStart] == 0x00) rStart++; while (sStart < sz - 1 && sig[sz + sStart] == 0x00) sStart++; /* Check if 0 needs to be prepended to make integer a positive number. */ rHigh = sig[rStart] >> 7; sHigh = sig[sz + sStart] >> 7; /* Calculate length of integer to put into ASN.1 encoding. */ rLen = sz - rStart; sLen = sz - sStart; /* r and s: INT (2 bytes) + [ 0x00 ] + integer */ rSz = 2 + rHigh + rLen; sSz = 2 + sHigh + sLen; /* Calculate the complete ASN.1 DER encoded size. */ sigSz = rSz + sSz; if (sigSz >= ASN_LONG_LENGTH) seqLen = 3; else seqLen = 2; /* Move s and then r integers into their final places. */ XMEMMOVE(sig + seqLen + rSz + (sSz - sLen), sig + sz + sStart, sLen); XMEMMOVE(sig + seqLen + (rSz - rLen), sig + rStart, rLen); /* Put the ASN.1 DER encoding around data. */ i = 0; sig[i++] = ASN_CONSTRUCTED | ASN_SEQUENCE; if (seqLen == 3) sig[i++] = ASN_LONG_LENGTH | 0x01; sig[i++] = sigSz; sig[i++] = ASN_INTEGER; sig[i++] = rHigh + (sz - rStart); if (rHigh) sig[i++] = 0x00; i += sz - rStart; sig[i++] = ASN_INTEGER; sig[i++] = sHigh + (sz - sStart); if (sHigh) sig[i] = 0x00; return seqLen + sigSz; } /** * Decode the ECDSA signature. * ASN.1 DER encode SEQ { INT, INT } converted to two fixed with values. * * @param [in] in ASN.1 DER encoded signature. * @param [in] inSz Size of ASN.1 signature. * @param [in] sig Output buffer. * @param [in] sz Size of output buffer. * @return ASN_PARSE_E when the ASN.1 encoding is invalid. * @return 0 on success. */ static int Pkcs11ECDSASig_Decode(const byte* in, word32 inSz, byte* sig, word32 sz) { int ret = 0; word32 i = 0; byte tag; int len, seqLen = 2; /* Make sure zeros in place when decoding short integers. */ XMEMSET(sig, 0, sz * 2); /* Check min data for: SEQ + INT. */ if (inSz < 5) ret = ASN_PARSE_E; /* Check SEQ */ if (ret == 0 && in[i++] != (ASN_CONSTRUCTED | ASN_SEQUENCE)) ret = ASN_PARSE_E; if (ret == 0 && in[i] >= ASN_LONG_LENGTH) { if (in[i] != (ASN_LONG_LENGTH | 0x01)) ret = ASN_PARSE_E; else { i++; seqLen++; } } if (ret == 0 && in[i++] != inSz - seqLen) ret = ASN_PARSE_E; /* Check INT */ if (ret == 0 && GetASNTag(in, &i, &tag, inSz) != 0) ret = ASN_PARSE_E; if (ret == 0 && tag != ASN_INTEGER) ret = ASN_PARSE_E; if (ret == 0 && (len = in[i++]) > sz + 1) ret = ASN_PARSE_E; /* Check there is space for INT data */ if (ret == 0 && i + len > inSz) ret = ASN_PARSE_E; if (ret == 0) { /* Skip leading zero */ if (in[i] == 0x00) { i++; len--; } /* Copy r into sig. */ XMEMCPY(sig + sz - len, in + i, len); i += len; } /* Check min data for: INT. */ if (ret == 0 && i + 2 > inSz) ret = ASN_PARSE_E; /* Check INT */ if (ret == 0 && GetASNTag(in, &i, &tag, inSz) != 0) ret = ASN_PARSE_E; if (ret == 0 && tag != ASN_INTEGER) ret = ASN_PARSE_E; if (ret == 0 && (len = in[i++]) > sz + 1) ret = ASN_PARSE_E; /* Check there is space for INT data */ if (ret == 0 && i + len > inSz) ret = ASN_PARSE_E; if (ret == 0) { /* Skip leading zero */ if (in[i] == 0x00) { i++; len--; } /* Copy s into sig. */ XMEMCPY(sig + sz + sz - len, in + i, len); } return ret; } /** * Get the parameters from the private key on the device. * * @param [in] session Session object. * @param [in] privKey PKCS #11 object handle of private key.. * @param [in] key Ecc key to set parameters against. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11GetEccParams(Pkcs11Session* session, CK_OBJECT_HANDLE privKey, ecc_key* key) { int ret = 0; int curveId; CK_RV rv; byte oid[16]; CK_ATTRIBUTE template[] = { { CKA_EC_PARAMS, (CK_VOID_PTR)oid, sizeof(oid) } }; PKCS11_DUMP_TEMPLATE("Get Ec Params", template, 1); rv = session->func->C_GetAttributeValue(session->handle, privKey, template, 1); PKCS11_RV("C_GetAttributeValue", rv); if (rv != CKR_OK) { ret = WC_HW_E; } PKCS11_DUMP_TEMPLATE("Ec Params", template, 1); if (ret == 0) { /* PKCS #11 wraps the OID in ASN.1 */ curveId = wc_ecc_get_curve_id_from_oid(oid + 2, (word32)template[0].ulValueLen - 2); if (curveId == ECC_CURVE_INVALID) ret = WC_HW_E; } if (ret == 0) ret = wc_ecc_set_curve(key, 0, curveId); return ret; } /** * Performs the ECDSA signing operation. * * @param session [in] Session object. * @param info [in] Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11ECDSA_Sign(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; int sessionKey = 0; word32 sz; CK_RV rv; CK_ULONG outLen; CK_MECHANISM mech; CK_MECHANISM_INFO mechInfo; CK_OBJECT_HANDLE privateKey = NULL_PTR; /* Check operation is supported. */ ret = Pkcs11MechAvail(session, CKM_ECDSA, &mechInfo); if (ret == 0 && (mechInfo.flags & CKF_SIGN) == 0) { ret = NOT_COMPILED_IN; } if (ret == 0 && info->pk.eccsign.outlen == NULL) { ret = BAD_FUNC_ARG; } if (ret == 0 && info->pk.eccsign.out == NULL) { ret = BAD_FUNC_ARG; } if (ret == 0) { WOLFSSL_MSG("PKCS#11: EC Signing Operation"); if (info->pk.eccsign.key->devCtx != NULL) { privateKey = (CK_OBJECT_HANDLE)(wc_ptr_t) info->pk.eccsign.key->devCtx; } else if ((sessionKey = !mp_iszero( wc_ecc_key_get_priv(info->pk.eccsign.key)))) ret = Pkcs11CreateEccPrivateKey(&privateKey, session, info->pk.eccsign.key, CKA_SIGN); else if (info->pk.eccsign.key->labelLen > 0) { ret = Pkcs11FindKeyByLabel(&privateKey, CKO_PRIVATE_KEY, CKK_EC, session, info->pk.eccsign.key->label, info->pk.eccsign.key->labelLen); if (ret == 0 && info->pk.eccsign.key->dp == NULL) { ret = Pkcs11GetEccParams(session, privateKey, info->pk.eccsign.key); } } else if (info->pk.eccsign.key->idLen > 0) { ret = Pkcs11FindKeyById(&privateKey, CKO_PRIVATE_KEY, CKK_EC, session, info->pk.eccsign.key->id, info->pk.eccsign.key->idLen); if (ret == 0 && info->pk.eccsign.key->dp == NULL) { ret = Pkcs11GetEccParams(session, privateKey, info->pk.eccsign.key); } } else { ret = Pkcs11FindEccKey(&privateKey, CKO_PRIVATE_KEY, session, info->pk.eccsign.key, CKA_SIGN); } } if (ret == 0) { sz = info->pk.eccsign.key->dp->size; /* Maximum encoded size is two ordinates + 8 bytes of ASN.1. */ if (*info->pk.eccsign.outlen < (word32)wc_ecc_sig_size_calc(sz)) ret = BUFFER_E; } if (ret == 0) { mech.mechanism = CKM_ECDSA; mech.ulParameterLen = 0; mech.pParameter = NULL; rv = session->func->C_SignInit(session->handle, &mech, privateKey); PKCS11_RV("C_SignInit", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { outLen = *info->pk.eccsign.outlen; rv = session->func->C_Sign(session->handle, (CK_BYTE_PTR)info->pk.eccsign.in, info->pk.eccsign.inlen, info->pk.eccsign.out, &outLen); PKCS11_RV("C_Sign", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { *info->pk.eccsign.outlen = Pkcs11ECDSASig_Encode(info->pk.eccsign.out, sz); } if (sessionKey && privateKey != NULL_PTR) session->func->C_DestroyObject(session->handle, privateKey); return ret; } /** * Performs the ECDSA verification operation. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return 0 on success. */ static int Pkcs11ECDSA_Verify(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; int sessionKey = 0; CK_RV rv; CK_MECHANISM mech; CK_MECHANISM_INFO mechInfo; CK_OBJECT_HANDLE publicKey = NULL_PTR; unsigned char* sig = NULL; ecc_key* key = info->pk.eccverify.key; word32 sz = key->dp->size; /* Check operation is supported. */ ret = Pkcs11MechAvail(session, CKM_ECDSA, &mechInfo); if (ret == 0 && (mechInfo.flags & CKF_VERIFY) == 0) { ret = NOT_COMPILED_IN; } if (ret == 0 && info->pk.eccverify.res == NULL) { ret = BAD_FUNC_ARG; } if (ret == 0) { WOLFSSL_MSG("PKCS#11: EC Verification Operation"); if (key->labelLen > 0) { ret = Pkcs11FindKeyByLabel(&publicKey, CKO_PUBLIC_KEY, CKK_EC, session, key->label, key->labelLen); if (ret == 0 && key->dp == NULL) { ret = Pkcs11GetEccParams(session, publicKey, key); } } else if (key->idLen > 0) { ret = Pkcs11FindKeyById(&publicKey, CKO_PUBLIC_KEY, CKK_EC, session, key->id, key->idLen); if (ret == 0 && key->dp == NULL) { ret = Pkcs11GetEccParams(session, publicKey, key); } } else if (!mp_iszero(key->pubkey.x)) { ret = Pkcs11CreateEccPublicKey(&publicKey, session, key, CKA_VERIFY); sessionKey = 1; } else ret = Pkcs11FindEccKey(&publicKey, CKO_PUBLIC_KEY, session, info->pk.eccsign.key, CKA_VERIFY); } if (ret == 0) { sig = (unsigned char *)XMALLOC(sz * 2, key->heap, DYNAMIC_TYPE_TMP_BUFFER); if (sig == NULL) ret = MEMORY_E; } if (ret == 0) { ret = Pkcs11ECDSASig_Decode(info->pk.eccverify.sig, info->pk.eccverify.siglen, sig, sz); } if (ret == 0) { mech.mechanism = CKM_ECDSA; mech.ulParameterLen = 0; mech.pParameter = NULL; rv = session->func->C_VerifyInit(session->handle, &mech, publicKey); PKCS11_RV("C_VerifyInit", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { *info->pk.eccverify.res = 0; rv = session->func->C_Verify(session->handle, (CK_BYTE_PTR)info->pk.eccverify.hash, info->pk.eccverify.hashlen, (CK_BYTE_PTR)sig, sz * 2); PKCS11_RV("C_Verify", rv); if (rv == CKR_SIGNATURE_INVALID) { } else if (rv != CKR_OK) ret = WC_HW_E; else *info->pk.eccverify.res = 1; } if (sessionKey && publicKey != NULL_PTR) session->func->C_DestroyObject(session->handle, publicKey); if (sig != NULL) XFREE(sig, info->pk.eccverify.key->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; } #endif #ifndef NO_RSA /** * Check the private RSA key matches the public key. * * @param [in] priv RSA private key. * @param [in] publicKey Encoded RSA public key. * @param [in] pubKeySize Length of encoded RSA public key. * @return MEMORY_E when a memory allocation fails. * @return MP_CMP_E when the public parts are different. * @return 0 on success. */ static int wc_Pkcs11CheckPrivKey_Rsa(RsaKey* priv, const unsigned char* publicKey, word32 pubKeySize) { int ret = 0; WC_DECLARE_VAR(pub, RsaKey, 1, 0); word32 keyIdx = 0; WC_ALLOC_VAR_EX(pub, RsaKey, 1, NULL, DYNAMIC_TYPE_RSA, ret=MEMORY_E); if ((ret == 0) && (ret = wc_InitRsaKey(pub, NULL)) == 0) { if (ret == 0) { ret = wc_RsaPublicKeyDecode(publicKey, &keyIdx, pub, pubKeySize); } if (ret == 0) { /* both keys extracted successfully now check n and e * values are the same. This is dereferencing RsaKey */ if (mp_cmp(&(priv->n), &(pub->n)) != MP_EQ || mp_cmp(&(priv->e), &(pub->e)) != MP_EQ) { ret = MP_CMP_E; } else ret = 0; } wc_FreeRsaKey(pub); } WC_FREE_VAR_EX(pub, NULL, DYNAMIC_TYPE_RSA); return ret; } /** * Checks the RSA private key matches the RSA public key. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return MP_CMP_E when the public parts are different. * @return 0 on success. */ static int Pkcs11RsaCheckPrivKey(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; CK_OBJECT_HANDLE privateKey; RsaKey* priv = info->pk.rsa_check.key; if (mp_iszero(&priv->n) || mp_iszero(&priv->e)) { /* Get the RSA private key object. */ if (priv->labelLen > 0) { ret = Pkcs11FindKeyByLabel(&privateKey, CKO_PRIVATE_KEY, CKK_RSA, session, priv->label, priv->labelLen); } else if (priv->idLen > 0) { ret = Pkcs11FindKeyById(&privateKey, CKO_PRIVATE_KEY, CKK_RSA, session, priv->id, priv->idLen); } else { ret = Pkcs11FindRsaKey(&privateKey, CKO_PRIVATE_KEY, session, priv); } if (ret == 0) { /* Extract the public key components. */ ret = Pkcs11GetRsaPublicKey(priv, session, privateKey); } } if (ret == 0) { /* Compare the extracted public parts with the public key. */ ret = wc_Pkcs11CheckPrivKey_Rsa(priv, info->pk.rsa_check.pubKey, info->pk.rsa_check.pubKeySz); } return ret; } /** * Get the size of the RSA key in bytes. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return NOT_COMPILED_IN when no modulus, label or id. * @return 0 on success. */ static int Pkcs11RsaGetSize(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; CK_OBJECT_HANDLE privateKey; const RsaKey* priv = info->pk.rsa_get_size.key; if (!mp_iszero(&priv->n)) { /* Use the key's modulus MP integer to determine size. */ *info->pk.rsa_get_size.keySize = mp_unsigned_bin_size(&priv->n); } else { /* Get the RSA private key object. */ if (priv->labelLen > 0) { ret = Pkcs11FindKeyByLabel(&privateKey, CKO_PRIVATE_KEY, CKK_RSA, session, (char*)priv->label, priv->labelLen); } else if (priv->idLen > 0) { ret = Pkcs11FindKeyById(&privateKey, CKO_PRIVATE_KEY, CKK_RSA, session, (unsigned char*)priv->id, priv->idLen); } else { /* Lookup is by modulus which is not present. */ ret = NOT_COMPILED_IN; } if (ret == 0) { /* Lookup the modulus size in bytes. */ ret = Pkcs11GetRsaModulusSize(session, privateKey, info->pk.rsa_get_size.keySize); } } return ret; } #endif #ifdef HAVE_ECC /** * Check the private ECC key matches the public key. * Do this by looking up the public key data from the associated public key. * The public key object handle is passed in for the private key. * * @param [in] privateKey Handle to private key object. * @param [in] publicKey Encoded EC public key. * @param [in] pubKeySize Length of encoded EC public key. * @return MEMORY_E when a memory allocation fails. * @return MP_CMP_E when the public parts are different. * @return 0 on success. */ static int wc_Pkcs11CheckPrivKey_Ecc(ecc_key* priv, const unsigned char* publicKey, word32 pubKeySize) { int ret = 0; WC_DECLARE_VAR(pub, ecc_key, 1, 0); word32 keyIdx = 0; WC_ALLOC_VAR_EX(pub, ecc_key, 1, NULL, DYNAMIC_TYPE_ECC, ret=MEMORY_E); if ((ret == 0) && (ret = wc_ecc_init(pub)) == 0) { ret = wc_EccPublicKeyDecode(publicKey, &keyIdx, pub, pubKeySize); if (ret == 0) { /* both keys extracted successfully now check curve and * pubkey. */ if ((pub->idx != priv->idx) || (wc_ecc_cmp_point(&priv->pubkey, &pub->pubkey) != MP_EQ)) { ret = MP_CMP_E; } else { ret = 0; } } wc_ecc_free(pub); } WC_FREE_VAR_EX(pub, NULL, DYNAMIC_TYPE_ECC); return ret; } /** * Checks the ECC private key matches the ECC public key. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return MEMORY_E when a memory allocation fails. * @return MP_CMP_E when the public parts are different. * @return 0 on success. */ static int Pkcs11EccCheckPrivKey(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; ecc_key* priv = info->pk.ecc_check.key; CK_OBJECT_HANDLE privateKey; if (mp_iszero(priv->pubkey.x) || mp_iszero(priv->pubkey.y)) { /* Get the public key object as the private key object doesn't have * the public point stored in it. */ if (priv->labelLen > 0) { ret = Pkcs11FindKeyByLabel(&privateKey, CKO_PUBLIC_KEY, CKK_EC, session, priv->label, priv->labelLen); } else if (priv->idLen > 0) { ret = Pkcs11FindKeyById(&privateKey, CKO_PUBLIC_KEY, CKK_EC, session, priv->id, priv->idLen); } else { ret = Pkcs11FindEccKey(&privateKey, CKO_PUBLIC_KEY, session, priv, CKA_SIGN); } if (ret == 0 && priv->dp == NULL) { /* Extract the group id. */ ret = Pkcs11GetEccParams(session, privateKey, priv); } if (ret == 0) { /* Extract the public point. */ ret = Pkcs11GetEccPublicKey(priv, session, privateKey); } } if (ret == 0) { /* Compare the extracted public parts with the public key. */ ret = wc_Pkcs11CheckPrivKey_Ecc(priv, info->pk.ecc_check.pubKey, info->pk.ecc_check.pubKeySz); } return ret; } /** * Deletes the ECC private key. * * @param [in] session Session object. * @param [in] key ECC key. * @return 0 on success. */ static int Pkcs11EccDeletePrivKey(Pkcs11Session* session, ecc_key* key) { CK_OBJECT_HANDLE privateKey; if (key != NULL && key->devCtx != NULL) { privateKey = (CK_OBJECT_HANDLE)(wc_ptr_t)key->devCtx; session->func->C_DestroyObject(session->handle, privateKey); key->devCtx = NULL; } return 0; } #endif #ifdef WOLFSSL_HAVE_MLKEM /* Finds the first ML-KEM key matching the key type. */ static int Pkcs11FindMlKemKey(CK_OBJECT_HANDLE* handle, CK_OBJECT_CLASS keyClass, Pkcs11Session* session, MlKemKey* key) { int ret = 0; CK_ULONG count = 0; CK_ML_KEM_PARAMETER_SET_TYPE param_set = 0; CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &keyClass, sizeof(keyClass) }, { CKA_KEY_TYPE, &mlkemKeyType, sizeof(mlkemKeyType) }, { CKA_PARAMETER_SET, ¶m_set, sizeof(param_set) }, }; CK_ULONG attrCnt = sizeof(keyTemplate) / sizeof(*keyTemplate); switch (key->type) { #ifndef WOLFSSL_NO_ML_KEM case WC_ML_KEM_512: param_set = CKP_ML_KEM_512; break; case WC_ML_KEM_768: param_set = CKP_ML_KEM_768; break; case WC_ML_KEM_1024: param_set = CKP_ML_KEM_1024; break; default: ret = NOT_COMPILED_IN; break; #else default: ret = NOT_COMPILED_IN; break; #endif } if (ret == 0) { ret = Pkcs11FindKeyByTemplate(handle, session, keyTemplate, attrCnt, &count); } if (ret == 0 && count == 0) { ret = WC_HW_E; } return ret; } static int Pkcs11GetMlKemPublicKey(MlKemKey* key, Pkcs11Session* session, CK_OBJECT_HANDLE keyHandle) { int ret = 0; CK_ULONG pubKeySize; CK_ML_KEM_PARAMETER_SET_TYPE paramSet = 0; unsigned char* pubKey = NULL; CK_ATTRIBUTE tmpl[] = { { CKA_VALUE, NULL, 0 }, { CKA_PARAMETER_SET, ¶mSet, sizeof(paramSet) } }; CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); CK_RV rv; PKCS11_DUMP_TEMPLATE("Get ML-KEM Public Key Length", tmpl, tmplCnt); rv = session->func->C_GetAttributeValue(session->handle, keyHandle, tmpl, tmplCnt); PKCS11_RV("C_GetAttributeValue", rv); if (rv != CKR_OK) { ret = WC_HW_E; } PKCS11_DUMP_TEMPLATE("ML-KEM Public Key Length", tmpl, tmplCnt); if (ret == 0) { #ifndef WOLFSSL_NO_ML_KEM switch (paramSet) { case CKP_ML_KEM_512: key->type = WC_ML_KEM_512; break; case CKP_ML_KEM_768: key->type = WC_ML_KEM_768; break; case CKP_ML_KEM_1024: key->type = WC_ML_KEM_1024; break; default: ret = WC_KEY_SIZE_E; break; } #else ret = NOT_COMPILED_IN; #endif } if (ret == 0) { pubKeySize = tmpl[0].ulValueLen; pubKey = (unsigned char*)XMALLOC(pubKeySize, key->heap, DYNAMIC_TYPE_TMP_BUFFER); if (pubKey == NULL) { ret = MEMORY_E; } } if (ret == 0) { tmpl[0].pValue = pubKey; PKCS11_DUMP_TEMPLATE("Get ML-KEM Public Key", tmpl, tmplCnt); rv = session->func->C_GetAttributeValue(session->handle, keyHandle, tmpl, tmplCnt); PKCS11_RV("C_GetAttributeValue", rv); if (rv != CKR_OK) { ret = WC_HW_E; } PKCS11_DUMP_TEMPLATE("ML-KEM Public Key", tmpl, tmplCnt); } if (ret == 0) { ret = wc_MlKemKey_DecodePublicKey(key, pubKey, (word32)pubKeySize); } XFREE(pubKey, key->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; } static int Pkcs11MlKemKeyGen(Pkcs11Session* session, MlKemKey* key) { int ret = 0; CK_RV rv; CK_OBJECT_HANDLE pubKey = NULL_PTR, privKey = NULL_PTR; CK_MECHANISM mech; CK_MECHANISM_INFO mechInfo; CK_ML_KEM_PARAMETER_SET_TYPE param_set = 0; CK_ULONG pubKeyLen = 0; CK_ATTRIBUTE pubKeyTmpl[] = { { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, { CKA_ENCAPSULATE, &ckTrue, sizeof(ckTrue) }, { CKA_KEY_TYPE, &mlkemKeyType, sizeof(mlkemKeyType) }, { CKA_PARAMETER_SET, ¶m_set, sizeof(param_set) }, { 0, NULL, 0 }, { 0, NULL, 0 } }; CK_ULONG pubTmplCnt = sizeof(pubKeyTmpl) / sizeof(*pubKeyTmpl) - 2; CK_ATTRIBUTE privKeyTmpl[] = { { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, { CKA_DECAPSULATE, &ckTrue, sizeof(ckTrue) }, { CKA_KEY_TYPE, &mlkemKeyType, sizeof(mlkemKeyType) }, { 0, NULL, 0 }, { 0, NULL, 0 } }; CK_ULONG privTmplCnt = sizeof(privKeyTmpl) / sizeof(*privKeyTmpl) - 2; ret = Pkcs11MechAvail(session, CKM_ML_KEM_KEY_PAIR_GEN, &mechInfo); if (ret == 0) { switch (key->type) { #ifndef WOLFSSL_NO_ML_KEM case WC_ML_KEM_512: param_set = CKP_ML_KEM_512; pubKeyLen = WC_ML_KEM_512_PUBLIC_KEY_SIZE; break; case WC_ML_KEM_768: param_set = CKP_ML_KEM_768; pubKeyLen = WC_ML_KEM_768_PUBLIC_KEY_SIZE; break; case WC_ML_KEM_1024: param_set = CKP_ML_KEM_1024; pubKeyLen = WC_ML_KEM_1024_PUBLIC_KEY_SIZE; break; default: ret = NOT_COMPILED_IN; break; #else default: ret = NOT_COMPILED_IN; break; #endif } } if ((ret == 0) && ((mechInfo.ulMinKeySize > pubKeyLen) || (mechInfo.ulMaxKeySize < pubKeyLen))) { ret = WC_KEY_SIZE_E; } if (ret == 0) { WOLFSSL_MSG("PKCS#11: ML-KEM Key Generation Operation"); if (key->labelLen != 0) { privKeyTmpl[privTmplCnt].type = CKA_LABEL; privKeyTmpl[privTmplCnt].pValue = key->label; privKeyTmpl[privTmplCnt].ulValueLen = key->labelLen; privTmplCnt++; pubKeyTmpl[pubTmplCnt].type = CKA_LABEL; pubKeyTmpl[pubTmplCnt].pValue = key->label; pubKeyTmpl[pubTmplCnt].ulValueLen = key->labelLen; pubTmplCnt++; } if (key->idLen != 0) { privKeyTmpl[privTmplCnt].type = CKA_ID; privKeyTmpl[privTmplCnt].pValue = key->id; privKeyTmpl[privTmplCnt].ulValueLen = key->idLen; privTmplCnt++; pubKeyTmpl[pubTmplCnt].type = CKA_ID; pubKeyTmpl[pubTmplCnt].pValue = key->id; pubKeyTmpl[pubTmplCnt].ulValueLen = key->idLen; pubTmplCnt++; } mech.mechanism = CKM_ML_KEM_KEY_PAIR_GEN; mech.ulParameterLen = 0; mech.pParameter = NULL; PKCS11_DUMP_TEMPLATE("Private Key", privKeyTmpl, privTmplCnt); PKCS11_DUMP_TEMPLATE("Public Key", pubKeyTmpl, pubTmplCnt); rv = session->func->C_GenerateKeyPair(session->handle, &mech, pubKeyTmpl, pubTmplCnt, privKeyTmpl, privTmplCnt, &pubKey, &privKey); PKCS11_RV("C_GenerateKeyPair", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { ret = Pkcs11GetMlKemPublicKey(key, session, pubKey); } /* Destroy the public key object, as encapsulation using the public key will * probably be performed outside of the PKCS#11 token. If not, user can call * wc_Pkcs11StoreKey() to import the public key to the token. */ if (pubKey != NULL_PTR) { session->func->C_DestroyObject(session->handle, pubKey); } if (ret == 0 && privKey != NULL_PTR) { key->devCtx = (void*)(wc_ptr_t)privKey; key->flags |= MLKEM_FLAG_PRIV_SET; } else if (ret != 0 && privKey != NULL_PTR) { session->func->C_DestroyObject(session->handle, privKey); } return ret; } static int Pkcs11MlKemEncapsulate(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; int sessionKey = 0; CK_RV rv; CK_MECHANISM mech; CK_MECHANISM_INFO mechInfo; CK_ULONG ctLen; CK_OBJECT_HANDLE publicKey = NULL_PTR; CK_OBJECT_HANDLE sharedKey = NULL_PTR; CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; CK_FUNCTION_LIST_3_2_PTR functionList = NULL; MlKemKey* key = (MlKemKey*)info->pk.pqc_encaps.key; word32 outLen = WC_ML_KEM_SS_SZ; CK_ATTRIBUTE sharedKeyTempl[] = { { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, { CKA_SENSITIVE, &ckFalse, sizeof(ckFalse) }, { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, }; CK_ULONG sharedKeyTmplCnt = sizeof(sharedKeyTempl) / sizeof(*sharedKeyTempl); if (session->version >= WC_PCKS11VERSION_3_2) { functionList = (CK_FUNCTION_LIST_3_2_PTR)session->func; } else { return NOT_COMPILED_IN; } ret = Pkcs11MechAvail(session, CKM_ML_KEM, &mechInfo); if (ret == 0 && (mechInfo.flags & CKF_ENCAPSULATE) == 0) { ret = NOT_COMPILED_IN; } if (ret == 0 && info->pk.pqc_encaps.sharedSecret == NULL) { ret = BAD_FUNC_ARG; } if (ret == 0 && info->pk.pqc_encaps.ciphertext == NULL) { ret = BAD_FUNC_ARG; } if (ret == 0) { WOLFSSL_MSG("PKCS#11: ML-KEM Encapsulation Operation"); if (key->labelLen > 0) { ret = Pkcs11FindKeyByLabel(&publicKey, CKO_PUBLIC_KEY, CKK_ML_KEM, session, key->label, key->labelLen); } else if (key->idLen > 0) { ret = Pkcs11FindKeyById(&publicKey, CKO_PUBLIC_KEY, CKK_ML_KEM, session, key->id, key->idLen); } else if ((key->flags & MLKEM_FLAG_PUB_SET) != 0) { ret = Pkcs11CreateMlKemPublicKey(&publicKey, session, key, &mechInfo); sessionKey = 1; } else { /* Fallback: find the first ML-KEM key matching the key type. */ ret = Pkcs11FindMlKemKey(&publicKey, CKO_PUBLIC_KEY, session, key); } } if (ret == 0) { mech.mechanism = CKM_ML_KEM; mech.ulParameterLen = 0; mech.pParameter = NULL; ctLen = info->pk.pqc_encaps.ciphertextLen; rv = functionList->C_EncapsulateKey(session->handle, &mech, publicKey, sharedKeyTempl, sharedKeyTmplCnt, (CK_BYTE_PTR) info->pk.pqc_encaps.ciphertext, &ctLen, &sharedKey); PKCS11_RV("C_EncapsulateKey", rv); if (rv != CKR_OK || (word32)ctLen != info->pk.pqc_encaps.ciphertextLen) { ret = WC_HW_E; } } if (ret == 0) { outLen = info->pk.pqc_encaps.sharedSecretLen; ret = Pkcs11ExtractSecret(session, sharedKey, info->pk.pqc_encaps.sharedSecret, &outLen); if (ret == 0 && outLen != info->pk.pqc_encaps.sharedSecretLen) { ret = WC_HW_E; } } if (sessionKey && publicKey != NULL_PTR) { session->func->C_DestroyObject(session->handle, publicKey); } if (sharedKey != NULL_PTR) { session->func->C_DestroyObject(session->handle, sharedKey); } return ret; } static int Pkcs11MlKemDecapsulate(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; int sessionKey = 0; CK_RV rv; CK_MECHANISM mech; CK_MECHANISM_INFO mechInfo; CK_OBJECT_HANDLE privateKey = NULL_PTR; CK_OBJECT_HANDLE sharedKey = NULL_PTR; CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; CK_FUNCTION_LIST_3_2_PTR functionList = NULL; MlKemKey* key = (MlKemKey*)info->pk.pqc_decaps.key; word32 outLen = WC_ML_KEM_SS_SZ; CK_ATTRIBUTE sharedKeyTempl[] = { { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, { CKA_SENSITIVE, &ckFalse, sizeof(ckFalse) }, { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, }; CK_ULONG sharedKeyTmplCnt = sizeof(sharedKeyTempl) / sizeof(*sharedKeyTempl); if (session->version >= WC_PCKS11VERSION_3_2) { functionList = (CK_FUNCTION_LIST_3_2_PTR)session->func; } else { return NOT_COMPILED_IN; } ret = Pkcs11MechAvail(session, CKM_ML_KEM, &mechInfo); if (ret == 0 && (mechInfo.flags & CKF_DECAPSULATE) == 0) { ret = NOT_COMPILED_IN; } if (ret == 0 && info->pk.pqc_decaps.sharedSecret == NULL) { ret = BAD_FUNC_ARG; } if (ret == 0 && info->pk.pqc_decaps.ciphertext == NULL) { ret = BAD_FUNC_ARG; } if (ret == 0) { WOLFSSL_MSG("PKCS#11: ML-KEM Decapsulation Operation"); if (key->devCtx != NULL) { privateKey = (CK_OBJECT_HANDLE)(wc_ptr_t)key->devCtx; } else if (key->labelLen > 0) { ret = Pkcs11FindKeyByLabel(&privateKey, CKO_PRIVATE_KEY, CKK_ML_KEM, session, key->label, key->labelLen); } else if (key->idLen > 0) { ret = Pkcs11FindKeyById(&privateKey, CKO_PRIVATE_KEY, CKK_ML_KEM, session, key->id, key->idLen); } else if ((key->flags & MLKEM_FLAG_PRIV_SET) != 0) { ret = Pkcs11CreateMlKemPrivateKey(&privateKey, session, key, &mechInfo); sessionKey = 1; } else { /* Fallback: find the first ML-KEM key matching the key type. */ ret = Pkcs11FindMlKemKey(&privateKey, CKO_PRIVATE_KEY, session, key); } } if (ret == 0) { mech.mechanism = CKM_ML_KEM; mech.ulParameterLen = 0; mech.pParameter = NULL; rv = functionList->C_DecapsulateKey(session->handle, &mech, privateKey, sharedKeyTempl, sharedKeyTmplCnt, (CK_BYTE_PTR) info->pk.pqc_decaps.ciphertext, info->pk.pqc_decaps.ciphertextLen, &sharedKey); PKCS11_RV("C_DecapsulateKey", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { outLen = info->pk.pqc_decaps.sharedSecretLen; ret = Pkcs11ExtractSecret(session, sharedKey, info->pk.pqc_decaps.sharedSecret, &outLen); if (ret == 0 && outLen != info->pk.pqc_decaps.sharedSecretLen) { ret = WC_HW_E; } } if (sessionKey && privateKey != NULL_PTR) { session->func->C_DestroyObject(session->handle, privateKey); } if (sharedKey != NULL_PTR) { session->func->C_DestroyObject(session->handle, sharedKey); } return ret; } static int Pkcs11MlKemDeletePrivKey(Pkcs11Session* session, MlKemKey* key) { CK_OBJECT_HANDLE privateKey; if (key != NULL && key->devCtx != NULL) { privateKey = (CK_OBJECT_HANDLE)(wc_ptr_t)key->devCtx; session->func->C_DestroyObject(session->handle, privateKey); key->devCtx = NULL; } return 0; } static int Pkcs11PqcKemKeyGen(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; switch (info->pk.pqc_kem_kg.type) { case WC_PQC_KEM_TYPE_KYBER: ret = Pkcs11MlKemKeyGen(session, (MlKemKey*)info->pk.pqc_kem_kg.key); break; default: ret = NOT_COMPILED_IN; break; } return ret; } static int Pkcs11PqcKemEncapsulate(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; switch (info->pk.pqc_encaps.type) { case WC_PQC_KEM_TYPE_KYBER: ret = Pkcs11MlKemEncapsulate(session, info); break; default: ret = NOT_COMPILED_IN; break; } return ret; } static int Pkcs11PqcKemDecapsulate(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; switch (info->pk.pqc_decaps.type) { case WC_PQC_KEM_TYPE_KYBER: ret = Pkcs11MlKemDecapsulate(session, info); break; default: ret = NOT_COMPILED_IN; break; } return ret; } #endif /* WOLFSSL_HAVE_MLKEM */ #if defined(HAVE_DILITHIUM) /** * Find the PKCS#11 object containing the ML-DSA public or private key data. * * @param handle [out] Handle to key object. * @param keyClass [in] Public or private key class. * @param session [in] Session object. * @param key [in] ML-DSA key. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return 0 on success. */ static int Pkcs11FindMldsaKey(CK_OBJECT_HANDLE* handle, CK_OBJECT_CLASS keyClass, Pkcs11Session* session, MlDsaKey* key) { int ret = 0; CK_ULONG count = 0; CK_ML_DSA_PARAMETER_SET_TYPE param_set = 0; CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &keyClass, sizeof(keyClass) }, { CKA_KEY_TYPE, &mldsaKeyType, sizeof(mldsaKeyType) }, { CKA_PARAMETER_SET, ¶m_set, sizeof(param_set) }, }; CK_ULONG attrCnt = sizeof(keyTemplate) / sizeof(*keyTemplate); if (key->level == WC_ML_DSA_44) { param_set = CKP_ML_DSA_44; } else if (key->level == WC_ML_DSA_65) { param_set = CKP_ML_DSA_65; } else if (key->level == WC_ML_DSA_87) { param_set = CKP_ML_DSA_87; } else { ret = NOT_COMPILED_IN; } if (ret == 0) { ret = Pkcs11FindKeyByTemplate(handle, session, keyTemplate, attrCnt, &count); } if (ret == 0 && count == 0) { ret = WC_HW_E; } return ret; } /** * Gets the public key data from the PKCS#11 object and puts into the ML-DSA * key. * * @param key [in] ML-DSA key. * @param session [in] Session object. * @param keyHandle [in] ML-DSA public key PKCS#11 object handle. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return 0 on success. */ static int Pkcs11GetMldsaPublicKey(MlDsaKey* key, Pkcs11Session* session, CK_OBJECT_HANDLE keyHandle) { int ret = 0; CK_ULONG pubKeySize; unsigned char* pubKey = NULL; CK_ATTRIBUTE tmpl[] = { { CKA_VALUE, NULL, 0 } }; CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); CK_RV rv; PKCS11_DUMP_TEMPLATE("Get ML-DSA Public Key Length", tmpl, tmplCnt); rv = session->func->C_GetAttributeValue(session->handle, keyHandle, tmpl, tmplCnt); PKCS11_RV("C_GetAttributeValue", rv); if (rv != CKR_OK) { ret = WC_HW_E; } PKCS11_DUMP_TEMPLATE("ML-DSA Public Key Length", tmpl, tmplCnt); if (ret == 0) { pubKeySize = tmpl[0].ulValueLen; pubKey = (unsigned char*)XMALLOC(pubKeySize, key->heap, DYNAMIC_TYPE_TMP_BUFFER); if (pubKey == NULL) ret = MEMORY_E; } if (ret == 0) { tmpl[0].pValue = pubKey; PKCS11_DUMP_TEMPLATE("Get ML-DSA Public Key", tmpl, tmplCnt); rv = session->func->C_GetAttributeValue(session->handle, keyHandle, tmpl, tmplCnt); PKCS11_RV("C_GetAttributeValue", rv); if (rv != CKR_OK) { ret = WC_HW_E; } PKCS11_DUMP_TEMPLATE("ML-DSA Public Key", tmpl, tmplCnt); } if (ret == 0) { if (pubKeySize == ML_DSA_LEVEL2_PUB_KEY_SIZE) wc_MlDsaKey_SetParams(key, WC_ML_DSA_44); else if (pubKeySize == ML_DSA_LEVEL3_PUB_KEY_SIZE) wc_MlDsaKey_SetParams(key, WC_ML_DSA_65); else if (pubKeySize == ML_DSA_LEVEL5_PUB_KEY_SIZE) wc_MlDsaKey_SetParams(key, WC_ML_DSA_87); else ret = WC_KEY_SIZE_E; } if (ret == 0) ret = wc_MlDsaKey_ImportPubRaw(key, pubKey, pubKeySize); if (pubKey != NULL) XFREE(pubKey, key->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; } /** * Convert the wolfCrypt hash type to a digest mechanism. * * @param hashType [in] Hash type. * @param hashMech [out] Pointer to digest mechanism. * @return BAD_FUNC_ARG when the hash type is not recognized. * 0 on success. */ static int Pkcs11GetMldsaPreHash(int hashType, CK_MECHANISM_TYPE_PTR hashMech) { int ret = 0; if (hashMech == NULL) { return BAD_FUNC_ARG; } switch (hashType) { case WC_HASH_TYPE_SHA256: *hashMech = CKM_SHA256; break; case WC_HASH_TYPE_SHA384: *hashMech = CKM_SHA384; break; case WC_HASH_TYPE_SHA512: *hashMech = CKM_SHA512; break; #ifndef WOLFSSL_NOSHA512_256 case WC_HASH_TYPE_SHA512_256: *hashMech = CKM_SHA512_256; break; #endif case WC_HASH_TYPE_SHA3_256: *hashMech = CKM_SHA3_256; break; case WC_HASH_TYPE_SHA3_384: *hashMech = CKM_SHA3_384; break; case WC_HASH_TYPE_SHA3_512: *hashMech = CKM_SHA3_512; break; default: ret = BAD_FUNC_ARG; break; } return ret; } /** * Perform an ML-DSA key generation operation. * The private key data stays on the device. * * @param [in] session Session object. * @param [in] key ML-DSA key. Already configured with the desired * level and parameters. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11MldsaKeyGen(Pkcs11Session* session, MlDsaKey* key) { int ret = 0; CK_RV rv; CK_OBJECT_HANDLE pubKey = NULL_PTR, privKey = NULL_PTR; CK_MECHANISM mech; CK_MECHANISM_INFO mechInfo; CK_ML_DSA_PARAMETER_SET_TYPE param_set = 0; /* Empty entries for optional label/ID. */ CK_ATTRIBUTE pubKeyTmpl[] = { { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, { CKA_KEY_TYPE, &mldsaKeyType, sizeof(mldsaKeyType) }, { CKA_PARAMETER_SET, ¶m_set, sizeof(param_set) }, { 0, NULL, 0 }, { 0, NULL, 0 } }; /* Mandatory entries + 2 optional. */ CK_ULONG pubTmplCnt = sizeof(pubKeyTmpl)/sizeof(*pubKeyTmpl) - 2; /* Empty entries for optional label/ID. */ CK_ATTRIBUTE privKeyTmpl[] = { { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, { CKA_KEY_TYPE, &mldsaKeyType, sizeof(mldsaKeyType) }, { 0, NULL, 0 }, { 0, NULL, 0 } }; /* Mandatory entries + 2 optional. */ CK_ULONG privTmplCnt = sizeof(privKeyTmpl)/sizeof(*privKeyTmpl) - 2; ret = Pkcs11MechAvail(session, CKM_ML_DSA_KEY_PAIR_GEN, &mechInfo); if (ret == 0) { if ((key->level == WC_ML_DSA_44) && (mechInfo.ulMinKeySize <= ML_DSA_LEVEL2_PUB_KEY_SIZE) && (mechInfo.ulMaxKeySize >= ML_DSA_LEVEL2_PUB_KEY_SIZE)) { param_set = CKP_ML_DSA_44; } else if ((key->level == WC_ML_DSA_65) && (mechInfo.ulMinKeySize <= ML_DSA_LEVEL3_PUB_KEY_SIZE) && (mechInfo.ulMaxKeySize >= ML_DSA_LEVEL3_PUB_KEY_SIZE)) { param_set = CKP_ML_DSA_65; } else if ((key->level == WC_ML_DSA_87) && (mechInfo.ulMinKeySize <= ML_DSA_LEVEL5_PUB_KEY_SIZE) && (mechInfo.ulMaxKeySize >= ML_DSA_LEVEL5_PUB_KEY_SIZE)) { param_set = CKP_ML_DSA_87; } else { ret = WC_KEY_SIZE_E; } } if (ret == 0) { WOLFSSL_MSG("PKCS#11: ML-DSA Key Generation Operation"); if (key->labelLen != 0) { privKeyTmpl[privTmplCnt].type = CKA_LABEL; privKeyTmpl[privTmplCnt].pValue = key->label; privKeyTmpl[privTmplCnt].ulValueLen = key->labelLen; privTmplCnt++; pubKeyTmpl[pubTmplCnt].type = CKA_LABEL; pubKeyTmpl[pubTmplCnt].pValue = key->label; pubKeyTmpl[pubTmplCnt].ulValueLen = key->labelLen; pubTmplCnt++; } if (key->idLen != 0) { privKeyTmpl[privTmplCnt].type = CKA_ID; privKeyTmpl[privTmplCnt].pValue = key->id; privKeyTmpl[privTmplCnt].ulValueLen = key->idLen; privTmplCnt++; pubKeyTmpl[pubTmplCnt].type = CKA_ID; pubKeyTmpl[pubTmplCnt].pValue = key->id; pubKeyTmpl[pubTmplCnt].ulValueLen = key->idLen; pubTmplCnt++; } mech.mechanism = CKM_ML_DSA_KEY_PAIR_GEN; mech.ulParameterLen = 0; mech.pParameter = NULL; PKCS11_DUMP_TEMPLATE("Private Key", privKeyTmpl, privTmplCnt); PKCS11_DUMP_TEMPLATE("Public Key", pubKeyTmpl, pubTmplCnt); rv = session->func->C_GenerateKeyPair(session->handle, &mech, pubKeyTmpl, pubTmplCnt, privKeyTmpl, privTmplCnt, &pubKey, &privKey); PKCS11_RV("C_GenerateKeyPair", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) ret = Pkcs11GetMldsaPublicKey(key, session, pubKey); if (pubKey != NULL_PTR) session->func->C_DestroyObject(session->handle, pubKey); if (ret == 0 && privKey != NULL_PTR) { key->devCtx = (void*)(wc_ptr_t)privKey; } else if (ret != 0 && privKey != NULL_PTR) session->func->C_DestroyObject(session->handle, privKey); return ret; } /** * Performs the ML-DSA signing operation. * * @param session [in] Session object. * @param info [in] Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11MldsaSign(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; int sessionKey = 0; CK_RV rv; CK_ULONG outLen; CK_MECHANISM mech; CK_MECHANISM_INFO mechInfo; CK_OBJECT_HANDLE privateKey = NULL_PTR; MlDsaKey* key = (MlDsaKey*) info->pk.pqc_sign.key; union { CK_SIGN_ADDITIONAL_CONTEXT pure; CK_HASH_SIGN_ADDITIONAL_CONTEXT preHash; } paramSet; XMEMSET(¶mSet, 0, sizeof(paramSet)); /* Check operation is supported. */ if (info->pk.pqc_sign.preHashType != WC_HASH_TYPE_NONE) { ret = Pkcs11MechAvail(session, CKM_HASH_ML_DSA, &mechInfo); } else { ret = Pkcs11MechAvail(session, CKM_ML_DSA, &mechInfo); } if (ret == 0 && (mechInfo.flags & CKF_SIGN) == 0) { ret = NOT_COMPILED_IN; } if (ret == 0 && info->pk.pqc_sign.outlen == NULL) { ret = BAD_FUNC_ARG; } if (ret == 0 && info->pk.pqc_sign.out == NULL) { ret = BAD_FUNC_ARG; } if (ret == 0) { WOLFSSL_MSG("PKCS#11: ML-DSA Signing Operation"); if (key->devCtx != NULL) { privateKey = (CK_OBJECT_HANDLE)(wc_ptr_t)key->devCtx; } else if ((sessionKey = key->prvKeySet)) ret = Pkcs11CreateMldsaPrivateKey(&privateKey, session, key, &mechInfo); else if (key->labelLen > 0) { ret = Pkcs11FindKeyByLabel(&privateKey, CKO_PRIVATE_KEY, CKK_ML_DSA, session, key->label, key->labelLen); } else if (key->idLen > 0) { ret = Pkcs11FindKeyById(&privateKey, CKO_PRIVATE_KEY, CKK_ML_DSA, session, key->id, key->idLen); } else { ret = Pkcs11FindMldsaKey(&privateKey, CKO_PRIVATE_KEY, session, key); } } if (ret == 0) { /* Prepare mechanism structure */ mech.mechanism = CKM_ML_DSA; mech.ulParameterLen = 0; mech.pParameter = NULL; if (info->pk.pqc_sign.preHashType != WC_HASH_TYPE_NONE) { /* Set the preHash algorithm */ ret = Pkcs11GetMldsaPreHash(info->pk.pqc_sign.preHashType, ¶mSet.preHash.hash); if (ret == 0) { mech.mechanism = CKM_HASH_ML_DSA; mech.pParameter = ¶mSet.preHash; mech.ulParameterLen = sizeof(paramSet.preHash); } /* Set the context data */ if (info->pk.pqc_sign.context != NULL && info->pk.pqc_sign.contextLen > 0) { paramSet.preHash.pContext = (byte*)info->pk.pqc_sign.context; paramSet.preHash.ulContextLen = info->pk.pqc_sign.contextLen; } else { paramSet.preHash.pContext = NULL; paramSet.preHash.ulContextLen = 0; } /* Hard-code the hedge variant to CKH_HEDGE_REQUIRED as we currently * do not support deterministic signing for ML-DSA via the CryptoCb * interface. */ paramSet.preHash.hedgeVariant = CKH_HEDGE_REQUIRED; } else { /* Set the context data */ if (info->pk.pqc_sign.context != NULL && info->pk.pqc_sign.contextLen > 0) { paramSet.pure.pContext = (byte*) info->pk.pqc_sign.context; paramSet.pure.ulContextLen = info->pk.pqc_sign.contextLen; /* Hard-code the hedge variant to CKH_HEDGE_REQUIRED as we * currently do not support deterministic signing for ML-DSA * via the CryptoCb interface. */ paramSet.pure.hedgeVariant = CKH_HEDGE_REQUIRED; mech.pParameter = ¶mSet.pure; mech.ulParameterLen = sizeof(paramSet.pure); } } } if (ret == 0) { rv = session->func->C_SignInit(session->handle, &mech, privateKey); PKCS11_RV("C_SignInit", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { outLen = *info->pk.pqc_sign.outlen; rv = session->func->C_Sign(session->handle, (CK_BYTE_PTR)info->pk.pqc_sign.in, info->pk.pqc_sign.inlen, info->pk.pqc_sign.out, &outLen); PKCS11_RV("C_Sign", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { *info->pk.pqc_sign.outlen = outLen; } if (sessionKey) session->func->C_DestroyObject(session->handle, privateKey); return ret; } /** * Performs the ML-DSA verification operation. * * @param session [in] Session object. * @param info [in] Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return 0 on success. */ static int Pkcs11MldsaVerify(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; int sessionKey = 0; CK_RV rv; CK_MECHANISM mech; CK_MECHANISM_INFO mechInfo; CK_OBJECT_HANDLE publicKey = NULL_PTR; MlDsaKey* key = (MlDsaKey*) info->pk.pqc_verify.key; union { CK_SIGN_ADDITIONAL_CONTEXT pure; CK_HASH_SIGN_ADDITIONAL_CONTEXT preHash; } paramSet; XMEMSET(¶mSet, 0, sizeof(paramSet)); /* Check operation is supported. */ if (info->pk.pqc_verify.preHashType != WC_HASH_TYPE_NONE) { ret = Pkcs11MechAvail(session, CKM_HASH_ML_DSA, &mechInfo); } else { ret = Pkcs11MechAvail(session, CKM_ML_DSA, &mechInfo); } if (ret == 0 && (mechInfo.flags & CKF_VERIFY) == 0) { ret = NOT_COMPILED_IN; } if (ret == 0 && info->pk.pqc_verify.res == NULL) { ret = BAD_FUNC_ARG; } if (ret == 0) { WOLFSSL_MSG("PKCS#11: ML-DSA Verification Operation"); if (key->labelLen > 0) { ret = Pkcs11FindKeyByLabel(&publicKey, CKO_PUBLIC_KEY, CKK_ML_DSA, session, key->label, key->labelLen); } else if (key->idLen > 0) { ret = Pkcs11FindKeyById(&publicKey, CKO_PUBLIC_KEY, CKK_ML_DSA, session, key->id, key->idLen); } else if (key->pubKeySet) { ret = Pkcs11CreateMldsaPublicKey(&publicKey, session, key, &mechInfo); sessionKey = 1; } else { ret = Pkcs11FindMldsaKey(&publicKey, CKO_PUBLIC_KEY, session, key); } } if (ret == 0) { /* Prepare mechanism structure */ mech.mechanism = CKM_ML_DSA; mech.ulParameterLen = 0; mech.pParameter = NULL; if (info->pk.pqc_verify.preHashType != WC_HASH_TYPE_NONE) { /* Set the preHash algorithm */ ret = Pkcs11GetMldsaPreHash(info->pk.pqc_verify.preHashType, ¶mSet.preHash.hash); if (ret == 0) { mech.mechanism = CKM_HASH_ML_DSA; mech.pParameter = ¶mSet.preHash; mech.ulParameterLen = sizeof(paramSet.preHash); } /* Set the context data */ if (info->pk.pqc_verify.context != NULL && info->pk.pqc_verify.contextLen > 0) { paramSet.preHash.pContext = (byte*) info->pk.pqc_verify.context; paramSet.preHash.ulContextLen = info->pk.pqc_verify.contextLen; } else { paramSet.preHash.pContext = NULL; paramSet.preHash.ulContextLen = 0; } } else { /* Set the context data */ if (info->pk.pqc_verify.context != NULL && info->pk.pqc_verify.contextLen > 0) { paramSet.pure.pContext = (byte*) info->pk.pqc_verify.context; paramSet.pure.ulContextLen = info->pk.pqc_verify.contextLen; mech.pParameter = ¶mSet.pure; mech.ulParameterLen = sizeof(paramSet.pure); } } } if (ret == 0) { rv = session->func->C_VerifyInit(session->handle, &mech, publicKey); PKCS11_RV("C_VerifyInit", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { *info->pk.pqc_verify.res = 0; rv = session->func->C_Verify(session->handle, (CK_BYTE_PTR)info->pk.pqc_verify.msg, info->pk.pqc_verify.msglen, (CK_BYTE_PTR)info->pk.pqc_verify.sig, info->pk.pqc_verify.siglen); PKCS11_RV("C_Verify", rv); if (rv == CKR_SIGNATURE_INVALID) ret = SIG_VERIFY_E; else if (rv != CKR_OK) ret = WC_HW_E; else *info->pk.pqc_verify.res = 1; } if (sessionKey && publicKey != NULL_PTR) session->func->C_DestroyObject(session->handle, publicKey); return ret; } /** * Checks whether the stored ML-DSA private key matches the given public key. * Do this by looking up the public key data from the associated private key. * * @param session [in] Session object. * @param info [in] Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return MP_CMP_E when the public parts are different. * @return 0 on success. */ static int Pkcs11MldsaCheckPrivKey(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; byte key_level = 0; word32 storedKeySize = 0; word32 idx = 0; CK_OBJECT_HANDLE privKeyHandle; MlDsaKey* privKey = (MlDsaKey*) info->pk.pqc_sig_check.key; WC_DECLARE_VAR(pubKey, MlDsaKey, 1, privKey->heap); WC_ALLOC_VAR_EX(pubKey, MlDsaKey, 1, privKey->heap, DYNAMIC_TYPE_DILITHIUM, ret = MEMORY_E); /* Get the ML-DSA public key object. */ if (ret == 0 && privKey->labelLen > 0) ret = Pkcs11FindKeyByLabel(&privKeyHandle, CKO_PUBLIC_KEY, CKK_ML_DSA, session, privKey->label, privKey->labelLen); else if (ret == 0 && privKey->idLen > 0) ret = Pkcs11FindKeyById(&privKeyHandle, CKO_PUBLIC_KEY, CKK_ML_DSA, session, privKey->id, privKey->idLen); else if (ret == 0) ret = Pkcs11FindMldsaKey(&privKeyHandle, CKO_PUBLIC_KEY, session, privKey); if (ret == 0) { /* Extract the public key components. */ ret = Pkcs11GetMldsaPublicKey(privKey, session, privKeyHandle); } /* Get the security level of the private key */ if (ret == 0) ret = wc_MlDsaKey_GetParams(privKey, &key_level); if (ret == 0) { if (key_level == WC_ML_DSA_44) storedKeySize = ML_DSA_LEVEL2_PUB_KEY_SIZE; else if (key_level == WC_ML_DSA_65) storedKeySize = ML_DSA_LEVEL3_PUB_KEY_SIZE; else if (key_level == WC_ML_DSA_87) storedKeySize = ML_DSA_LEVEL5_PUB_KEY_SIZE; else ret = WC_KEY_SIZE_E; } if ((ret == 0) && ((ret = wc_MlDsaKey_Init(pubKey, privKey->heap, INVALID_DEVID)) == 0)) { ret = wc_MlDsaKey_SetParams(pubKey, key_level); if (ret == 0) { ret = wc_MlDsaKey_PublicKeyDecode(pubKey, info->pk.pqc_sig_check.pubKey, info->pk.pqc_sig_check.pubKeySz, &idx); } if (ret == 0) { /* Compare the data of the provided public key with the data * stored in the private key object */ ret = XMEMCMP(privKey->p, pubKey->p, storedKeySize); if (ret != 0) ret = MP_CMP_E; } wc_MlDsaKey_Free(pubKey); } WC_FREE_VAR_EX(pubKey, privKey->heap, DYNAMIC_TYPE_DILITHIUM); return ret; } /** * Deletes the ML-DSA private key. * * @param [in] session Session object. * @param [in] key ML-DSA key. * @return 0 on success. */ static int Pkcs11MldsaDeletePrivKey(Pkcs11Session* session, MlDsaKey* key) { CK_OBJECT_HANDLE privateKey; if (key != NULL && key->devCtx != NULL) { privateKey = (CK_OBJECT_HANDLE)(wc_ptr_t)key->devCtx; session->func->C_DestroyObject(session->handle, privateKey); key->devCtx = NULL; } return 0; } /** * Perform a PQC key generation operation. * The private key data stays on the device. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11PqcSigKeyGen(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; switch (info->pk.pqc_sig_kg.type) { case WC_PQC_SIG_TYPE_DILITHIUM: ret = Pkcs11MldsaKeyGen(session, (MlDsaKey*)info->pk.pqc_sig_kg.key); break; default: ret = NOT_COMPILED_IN; break; } return ret; } /** * Performs the signing operation with the PQC algorithm. * * @param session [in] Session object. * @param info [in] Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11PqcSigSign(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; switch (info->pk.pqc_sign.type) { case WC_PQC_SIG_TYPE_DILITHIUM: ret = Pkcs11MldsaSign(session, info); break; default: ret = NOT_COMPILED_IN; break; } return ret; } /** * Performs the verification operation with the PQC algorithm. * * @param session [in] Session object. * @param info [in] Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return 0 on success. */ static int Pkcs11PqcSigVerify(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; switch (info->pk.pqc_verify.type) { case WC_PQC_SIG_TYPE_DILITHIUM: ret = Pkcs11MldsaVerify(session, info); break; default: ret = NOT_COMPILED_IN; break; } return ret; } /** * Checks whether the stored PQC private key matches the given PQC public key. * * @param session [in] Session object. * @param info [in] Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return MP_CMP_E when the public parts are different. * @return 0 on success. */ static int Pkcs11PqcSigCheckPrivKey(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; switch (info->pk.pqc_sig_check.type) { case WC_PQC_SIG_TYPE_DILITHIUM: ret = Pkcs11MldsaCheckPrivKey(session, info); break; default: ret = NOT_COMPILED_IN; break; } return ret; } #endif /* HAVE_DILITHIUM */ #if !defined(NO_AES) && defined(HAVE_AESGCM) /** * Performs the AES-GCM encryption operation. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return 0 on success. */ static int Pkcs11AesGcmEncrypt(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; CK_RV rv; Aes* aes = info->cipher.aesgcm_enc.aes; CK_GCM_PARAMS params; CK_MECHANISM_INFO mechInfo; CK_OBJECT_HANDLE key = NULL_PTR; CK_MECHANISM mech; CK_ULONG outLen; /* Check operation is supported. */ ret = Pkcs11MechAvail(session, CKM_AES_GCM, &mechInfo); if (ret == 0 && (mechInfo.flags & CKF_ENCRYPT) == 0) { ret = NOT_COMPILED_IN; } if (ret == 0) { WOLFSSL_MSG("PKCS#11: AES-GCM Encryption Operation"); /* Create a private key object or find by label or id. */ if (aes->idLen == 0 && aes->labelLen == 0) { ret = Pkcs11CreateSecretKey(&key, session, CKK_AES, (unsigned char*)aes->devKey, aes->keylen, NULL, 0, NULL, 0, CKA_ENCRYPT); } else if (aes->labelLen != 0) { ret = Pkcs11FindKeyByLabel(&key, CKO_SECRET_KEY, CKK_AES, session, aes->label, aes->labelLen); } else { ret = Pkcs11FindKeyById(&key, CKO_SECRET_KEY, CKK_AES, session, aes->id, aes->idLen); } } if (ret == 0) { params.pIv = (CK_BYTE_PTR)info->cipher.aesgcm_enc.iv; params.ulIvLen = info->cipher.aesgcm_enc.ivSz; params.pAAD = (CK_BYTE_PTR)info->cipher.aesgcm_enc.authIn; params.ulAADLen = info->cipher.aesgcm_enc.authInSz; params.ulTagBits = info->cipher.aesgcm_enc.authTagSz * 8; mech.mechanism = CKM_AES_GCM; mech.ulParameterLen = sizeof(params); mech.pParameter = ¶ms; rv = session->func->C_EncryptInit(session->handle, &mech, key); PKCS11_RV("C_EncryptInit", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { outLen = info->cipher.aesgcm_enc.sz; rv = session->func->C_EncryptUpdate(session->handle, (CK_BYTE_PTR)info->cipher.aesgcm_enc.in, info->cipher.aesgcm_enc.sz, info->cipher.aesgcm_enc.out, &outLen); PKCS11_RV("C_EncryptUpdate", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { /* Authentication tag comes out in final block. */ outLen = info->cipher.aesgcm_enc.authTagSz; rv = session->func->C_EncryptFinal(session->handle, info->cipher.aesgcm_enc.authTag, &outLen); PKCS11_RV("C_EncryptFinal", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (aes->idLen == 0 && aes->labelLen == 0 && key != NULL_PTR) session->func->C_DestroyObject(session->handle, key); return ret; } /** * Performs the AES-GCM decryption operation. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return 0 on success. */ static int Pkcs11AesGcmDecrypt(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; CK_RV rv; Aes* aes = info->cipher.aesgcm_enc.aes; CK_GCM_PARAMS params; CK_MECHANISM_INFO mechInfo; CK_OBJECT_HANDLE key = NULL_PTR; CK_MECHANISM mech; CK_ULONG outLen; word32 len; /* Check operation is supported. */ ret = Pkcs11MechAvail(session, CKM_AES_GCM, &mechInfo); if (ret == 0 && (mechInfo.flags & CKF_DECRYPT) == 0) { ret = NOT_COMPILED_IN; } if (ret == 0) { WOLFSSL_MSG("PKCS#11: AES-GCM Decryption Operation"); /* Create a private key object or find by id. */ if (aes->idLen == 0 && aes->labelLen == 0) { ret = Pkcs11CreateSecretKey(&key, session, CKK_AES, (unsigned char*)aes->devKey, aes->keylen, NULL, 0, NULL, 0, CKA_DECRYPT); } else if (aes->labelLen != 0) { ret = Pkcs11FindKeyByLabel(&key, CKO_SECRET_KEY, CKK_AES, session, aes->label, aes->labelLen); } else { ret = Pkcs11FindKeyById(&key, CKO_SECRET_KEY, CKK_AES, session, aes->id, aes->idLen); } } if (ret == 0) { params.pIv = (CK_BYTE_PTR)info->cipher.aesgcm_dec.iv; params.ulIvLen = info->cipher.aesgcm_dec.ivSz; params.pAAD = (CK_BYTE_PTR)info->cipher.aesgcm_dec.authIn; params.ulAADLen = info->cipher.aesgcm_dec.authInSz; params.ulTagBits = info->cipher.aesgcm_dec.authTagSz * 8; mech.mechanism = CKM_AES_GCM; mech.ulParameterLen = sizeof(params); mech.pParameter = ¶ms; rv = session->func->C_DecryptInit(session->handle, &mech, key); PKCS11_RV("C_DecryptInit", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { outLen = len = info->cipher.aesgcm_dec.sz; rv = session->func->C_DecryptUpdate(session->handle, (CK_BYTE_PTR)info->cipher.aesgcm_dec.in, info->cipher.aesgcm_dec.sz, info->cipher.aesgcm_dec.out, &outLen); PKCS11_RV("C_DecryptUpdate", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { /* Put authentication tag in as encrypted data. */ outLen = len = (len + info->cipher.aesgcm_dec.authTagSz - (word32)outLen); rv = session->func->C_DecryptUpdate(session->handle, (CK_BYTE_PTR)info->cipher.aesgcm_dec.authTag, info->cipher.aesgcm_dec.authTagSz, info->cipher.aesgcm_dec.out, &outLen); PKCS11_RV("C_DecryptUpdate", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { outLen = len = (len - (word32)outLen); /* Decrypted data comes out now. */ rv = session->func->C_DecryptFinal(session->handle, info->cipher.aesgcm_dec.out, &outLen); PKCS11_RV("C_DecryptFinal", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (aes->idLen == 0 && aes->labelLen == 0 && key != NULL_PTR) session->func->C_DestroyObject(session->handle, key); return ret; } #endif #if !defined(NO_AES) && defined(HAVE_AES_CBC) /** * Performs the AES-CBC encryption operation. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return 0 on success. */ static int Pkcs11AesCbcEncrypt(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; CK_RV rv; Aes* aes = info->cipher.aescbc.aes; CK_MECHANISM_INFO mechInfo; CK_OBJECT_HANDLE key = NULL_PTR; CK_MECHANISM mech; CK_ULONG outLen; /* Check operation is supported. */ ret = Pkcs11MechAvail(session, CKM_AES_CBC, &mechInfo); if (ret == 0 && (mechInfo.flags & CKF_ENCRYPT) == 0) { ret = NOT_COMPILED_IN; } if (ret == 0) { WOLFSSL_MSG("PKCS#11: AES-CBC Encryption Operation"); /* Create a private key object or find by id. */ if (aes->idLen == 0 && aes->labelLen == 0) { ret = Pkcs11CreateSecretKey(&key, session, CKK_AES, (unsigned char*)aes->devKey, aes->keylen, NULL, 0, NULL, 0, CKA_ENCRYPT); } else if (aes->labelLen != 0) { ret = Pkcs11FindKeyByLabel(&key, CKO_SECRET_KEY, CKK_AES, session, aes->label, aes->labelLen); } else { ret = Pkcs11FindKeyById(&key, CKO_SECRET_KEY, CKK_AES, session, aes->id, aes->idLen); } } if (ret == 0) { mech.mechanism = CKM_AES_CBC; mech.ulParameterLen = WC_AES_BLOCK_SIZE; mech.pParameter = (CK_BYTE_PTR)info->cipher.aescbc.aes->reg; rv = session->func->C_EncryptInit(session->handle, &mech, key); PKCS11_RV("C_EncryptInit", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { outLen = info->cipher.aescbc.sz; rv = session->func->C_Encrypt(session->handle, (CK_BYTE_PTR)info->cipher.aescbc.in, info->cipher.aescbc.sz, info->cipher.aescbc.out, &outLen); PKCS11_RV("C_Encrypt", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (aes->idLen == 0 && aes->labelLen == 0 && key != NULL_PTR) session->func->C_DestroyObject(session->handle, key); return ret; } /** * Performs the AES-CBC decryption operation. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return 0 on success. */ static int Pkcs11AesCbcDecrypt(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; CK_RV rv; Aes* aes = info->cipher.aescbc.aes; CK_MECHANISM_INFO mechInfo; CK_OBJECT_HANDLE key = NULL_PTR; CK_MECHANISM mech; CK_ULONG outLen; /* Check operation is supported. */ ret = Pkcs11MechAvail(session, CKM_AES_CBC, &mechInfo); if (ret == 0 && (mechInfo.flags & CKF_DECRYPT) == 0) { ret = NOT_COMPILED_IN; } if (ret == 0) { WOLFSSL_MSG("PKCS#11: AES-CBC Decryption Operation"); /* Create a private key object or find by id. */ if (aes->idLen == 0 && aes->labelLen == 0) { ret = Pkcs11CreateSecretKey(&key, session, CKK_AES, (unsigned char*)aes->devKey, aes->keylen, NULL, 0, NULL, 0, CKA_DECRYPT); } else if (aes->labelLen != 0) { ret = Pkcs11FindKeyByLabel(&key, CKO_SECRET_KEY, CKK_AES, session, aes->label, aes->labelLen); } else { ret = Pkcs11FindKeyById(&key, CKO_SECRET_KEY, CKK_AES, session, aes->id, aes->idLen); } } if (ret == 0) { mech.mechanism = CKM_AES_CBC; mech.ulParameterLen = WC_AES_BLOCK_SIZE; mech.pParameter = (CK_BYTE_PTR)info->cipher.aescbc.aes->reg; rv = session->func->C_DecryptInit(session->handle, &mech, key); PKCS11_RV("C_DecryptInit", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { outLen = info->cipher.aescbc.sz; rv = session->func->C_Decrypt(session->handle, (CK_BYTE_PTR)info->cipher.aescbc.in, info->cipher.aescbc.sz, info->cipher.aescbc.out, &outLen); PKCS11_RV("C_Decrypt", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (aes->idLen == 0 && aes->labelLen == 0 && key != NULL_PTR) session->func->C_DestroyObject(session->handle, key); return ret; } #endif #if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER) /** * Performs the AES-CTR encryption operation. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return 0 on success. */ static int Pkcs11AesCtrEncrypt(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; CK_RV rv; Aes* aes = info->cipher.aesctr.aes; CK_MECHANISM_INFO mechInfo; CK_AES_CTR_PARAMS params; CK_OBJECT_HANDLE key = NULL_PTR; CK_MECHANISM mech; CK_ULONG outLen; /* Check operation is supported. */ ret = Pkcs11MechAvail(session, CKM_AES_CTR, &mechInfo); if (ret == 0 && (mechInfo.flags & CKF_ENCRYPT) == 0) { ret = NOT_COMPILED_IN; } if (ret == 0) { WOLFSSL_MSG("PKCS#11: AES-CTR Encryption Operation"); /* Create a private key object or find by id. */ if (aes->idLen == 0 && aes->labelLen == 0) { ret = Pkcs11CreateSecretKey(&key, session, CKK_AES, (unsigned char*)aes->devKey, aes->keylen, NULL, 0, NULL, 0, CKA_ENCRYPT); } else if (aes->labelLen != 0) { ret = Pkcs11FindKeyByLabel(&key, CKO_SECRET_KEY, CKK_AES, session, aes->label, aes->labelLen); } else { ret = Pkcs11FindKeyById(&key, CKO_SECRET_KEY, CKK_AES, session, aes->id, aes->idLen); } } if (ret == 0) { XMEMSET(¶ms, 0, sizeof(params)); params.ulCounterBits = WC_AES_BLOCK_SIZE * 8; XMEMCPY(params.cb, info->cipher.aesctr.aes->reg, WC_AES_BLOCK_SIZE); mech.mechanism = CKM_AES_CTR; mech.ulParameterLen = sizeof(params); mech.pParameter = ¶ms; rv = session->func->C_EncryptInit(session->handle, &mech, key); PKCS11_RV("C_EncryptInit", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { outLen = info->cipher.aesctr.sz; rv = session->func->C_Encrypt(session->handle, (CK_BYTE_PTR)info->cipher.aesctr.in, info->cipher.aesctr.sz, info->cipher.aesctr.out, &outLen); PKCS11_RV("C_Encrypt", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (aes->idLen == 0 && aes->labelLen == 0 && key != NULL_PTR) session->func->C_DestroyObject(session->handle, key); return ret; } /** * Performs the AES-CTR decryption operation. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return MEMORY_E when a memory allocation fails. * @return 0 on success. */ static int Pkcs11AesCtrDecrypt(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; CK_RV rv; Aes* aes = info->cipher.aesctr.aes; CK_MECHANISM_INFO mechInfo; CK_AES_CTR_PARAMS params; CK_OBJECT_HANDLE key = NULL_PTR; CK_MECHANISM mech; CK_ULONG outLen; /* Check operation is supported. */ ret = Pkcs11MechAvail(session, CKM_AES_CTR, &mechInfo); if (ret == 0 && (mechInfo.flags & CKF_DECRYPT) == 0) { ret = NOT_COMPILED_IN; } if (ret == 0) { WOLFSSL_MSG("PKCS#11: AES-CTR Decryption Operation"); /* Create a private key object or find by id. */ if (aes->idLen == 0 && aes->labelLen == 0) { ret = Pkcs11CreateSecretKey(&key, session, CKK_AES, (unsigned char*)aes->devKey, aes->keylen, NULL, 0, NULL, 0, CKA_DECRYPT); } else if (aes->labelLen != 0) { ret = Pkcs11FindKeyByLabel(&key, CKO_SECRET_KEY, CKK_AES, session, aes->label, aes->labelLen); } else { ret = Pkcs11FindKeyById(&key, CKO_SECRET_KEY, CKK_AES, session, aes->id, aes->idLen); } } if (ret == 0) { XMEMSET(¶ms, 0, sizeof(params)); params.ulCounterBits = WC_AES_BLOCK_SIZE * 8; XMEMCPY(params.cb, info->cipher.aesctr.aes->reg, WC_AES_BLOCK_SIZE); mech.mechanism = CKM_AES_CTR; mech.ulParameterLen = sizeof(params); mech.pParameter = ¶ms; rv = session->func->C_DecryptInit(session->handle, &mech, key); PKCS11_RV("C_DecryptInit", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (ret == 0) { outLen = info->cipher.aesctr.sz; rv = session->func->C_Decrypt(session->handle, (CK_BYTE_PTR)info->cipher.aesctr.in, info->cipher.aesctr.sz, info->cipher.aesctr.out, &outLen); PKCS11_RV("C_Decrypt", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } if (aes->idLen == 0 && aes->labelLen == 0 && key != NULL_PTR) session->func->C_DestroyObject(session->handle, key); return ret; } #endif #ifndef NO_HMAC /** * Updates or calculates the HMAC of the data. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11Hmac(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; CK_RV rv; Hmac* hmac = info->hmac.hmac; CK_MECHANISM_INFO mechInfo; CK_OBJECT_HANDLE key = NULL_PTR; CK_MECHANISM mech; CK_ULONG outLen; int mechType; int keyType; if (hmac->innerHashKeyed == WC_HMAC_INNER_HASH_KEYED_SW) ret = NOT_COMPILED_IN; if (ret == 0) ret = Pkcs11HmacTypes(info->hmac.macType, &mechType, &keyType); if (ret == 0) { /* Check operation is supported. */ ret = Pkcs11MechAvail(session, mechType, &mechInfo); if (ret == 0 && (mechInfo.flags & CKF_SIGN) == 0) { ret = NOT_COMPILED_IN; } } /* Check whether key been used to initialized. */ if (ret == 0 && !hmac->innerHashKeyed) { WOLFSSL_MSG("PKCS#11: HMAC Init"); /* Check device supports key length. */ if (mechInfo.ulMaxKeySize > 0 && (hmac->keyLen < mechInfo.ulMinKeySize || hmac->keyLen > mechInfo.ulMaxKeySize)) { WOLFSSL_MSG("PKCS#11: Key Length not supported"); ret = NOT_COMPILED_IN; } /* Create a private key object or find by id. */ if (ret == 0 && hmac->idLen == 0 && hmac->labelLen == 0) { ret = Pkcs11CreateSecretKey(&key, session, keyType, (unsigned char*)hmac->keyRaw, hmac->keyLen, NULL, 0, NULL, 0, CKA_SIGN); if (ret == WC_NO_ERR_TRACE(WC_HW_E)) { ret = Pkcs11CreateSecretKey(&key, session, CKK_GENERIC_SECRET, (unsigned char*)hmac->keyRaw, hmac->keyLen, NULL, 0, NULL, 0, CKA_SIGN); } } else if (ret == 0 && hmac->labelLen != 0) { ret = Pkcs11FindKeyByLabel(&key, CKO_SECRET_KEY, keyType, session, hmac->label, hmac->labelLen); if (ret == WC_NO_ERR_TRACE(WC_HW_E)) { ret = Pkcs11FindKeyByLabel(&key, CKO_SECRET_KEY, CKK_GENERIC_SECRET, session, hmac->label, hmac->labelLen); } } else if (ret == 0) { ret = Pkcs11FindKeyById(&key, CKO_SECRET_KEY, keyType, session, hmac->id, hmac->idLen); if (ret == WC_NO_ERR_TRACE(WC_HW_E)) { ret = Pkcs11FindKeyById(&key, CKO_SECRET_KEY, CKK_GENERIC_SECRET, session, hmac->id, hmac->idLen); } } /* Initialize HMAC operation */ if (ret == 0) { mech.mechanism = mechType; mech.ulParameterLen = 0; mech.pParameter = NULL; rv = session->func->C_SignInit(session->handle, &mech, key); PKCS11_RV("C_SignInit", rv); if (rv != CKR_OK) { ret = WC_HW_E; } } /* Don't initialize HMAC again if this succeeded */ if (ret == 0) hmac->innerHashKeyed = WC_HMAC_INNER_HASH_KEYED_DEV; } /* Update the HMAC if input data passed in. */ if (ret == 0 && info->hmac.inSz > 0) { WOLFSSL_MSG("PKCS#11: HMAC Update"); rv = session->func->C_SignUpdate(session->handle, (CK_BYTE_PTR)info->hmac.in, info->hmac.inSz); PKCS11_RV("C_SignUpdate", rv); /* Some algorithm implementations only support C_Sign. */ if (rv == CKR_MECHANISM_INVALID) { WOLFSSL_MSG("PKCS#11: HMAC Update/Final not supported"); ret = NOT_COMPILED_IN; /* Allow software implementation to set key. */ hmac->innerHashKeyed = 0; } else if (rv != CKR_OK) ret = WC_HW_E; } /* Calculate the HMAC result if output buffer specified. */ if (ret == 0 && info->hmac.digest != NULL) { WOLFSSL_MSG("PKCS#11: HMAC Final"); outLen = WC_MAX_DIGEST_SIZE; rv = session->func->C_SignFinal(session->handle, (CK_BYTE_PTR)info->hmac.digest, &outLen); PKCS11_RV("C_SignFinal", rv); /* Some algorithm implementations only support C_Sign. */ if (rv != CKR_OK) { ret = WC_HW_E; } else hmac->innerHashKeyed = 0; } if (hmac->idLen == 0 && hmac->labelLen == 0 && key != NULL_PTR) session->func->C_DestroyObject(session->handle, key); return ret; } #endif #ifndef WC_NO_RNG #ifndef HAVE_HASHDRBG /** * Performs random number generation. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11RandomBlock(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; CK_RV rv; WOLFSSL_MSG("PKCS#11: Generate Random for Block"); rv = session->func->C_GenerateRandom(session->handle, info->rng.out, info->rng.sz); PKCS11_RV("C_GenerateRandom", rv); if (rv != CKR_OK) { ret = WC_HW_E; } return ret; } #endif /** * Generates entropy (seed) data. * * @param [in] session Session object. * @param [in] info Cryptographic operation data. * @return WC_HW_E when a PKCS#11 library call fails. * @return 0 on success. */ static int Pkcs11RandomSeed(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; CK_RV rv; WOLFSSL_MSG("PKCS#11: Generate Random for Seed"); rv = session->func->C_GenerateRandom(session->handle, info->seed.seed, info->seed.sz); PKCS11_RV("C_GenerateRandom", rv); if (rv != CKR_OK) { ret = WC_HW_E; } return ret; } #endif #ifndef NO_CERTS static int Pkcs11GetCert(Pkcs11Session* session, wc_CryptoInfo* info) { int ret = 0; CK_RV rv = 0; CK_ULONG count = 0; CK_OBJECT_HANDLE certHandle = CK_INVALID_HANDLE; byte *certData = NULL; CK_ATTRIBUTE certTemplate[2] = { { CKA_CLASS, &certClass, sizeof(certClass) } }; CK_ATTRIBUTE tmpl[] = { { CKA_VALUE, NULL_PTR, 0 } }; CK_ULONG certTmplCnt = sizeof(certTemplate) / sizeof(*certTemplate); CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); WOLFSSL_MSG("PKCS#11: Retrieve certificate"); if (info->cert.labelLen > 0) { certTemplate[1].type = CKA_LABEL; certTemplate[1].pValue = (CK_VOID_PTR)info->cert.label; certTemplate[1].ulValueLen = info->cert.labelLen; } else if (info->cert.idLen > 0) { certTemplate[1].type = CKA_ID; certTemplate[1].pValue = (CK_VOID_PTR)info->cert.id; certTemplate[1].ulValueLen = info->cert.idLen; } else { ret = BAD_FUNC_ARG; goto exit; } ret = Pkcs11FindKeyByTemplate( &certHandle, session, certTemplate, certTmplCnt, &count); if (ret == 0 && count == 0) { ret = WC_HW_E; goto exit; } PKCS11_DUMP_TEMPLATE("Get Certificate Length", tmpl, tmplCnt); rv = session->func->C_GetAttributeValue( session->handle, certHandle, tmpl, tmplCnt); PKCS11_RV("C_GetAttributeValue", rv); if (rv != CKR_OK) { ret = WC_HW_E; goto exit; } if (tmpl[0].ulValueLen <= 0) { ret = WC_HW_E; goto exit; } certData = (byte *)XMALLOC( (int)tmpl[0].ulValueLen, info->cert.heap, DYNAMIC_TYPE_CERT); if (certData == NULL) { ret = MEMORY_E; goto exit; } tmpl[0].pValue = certData; rv = session->func->C_GetAttributeValue( session->handle, certHandle, tmpl, tmplCnt); PKCS11_RV("C_GetAttributeValue", rv); if (rv != CKR_OK) { ret = WC_HW_E; goto exit; } *info->cert.certDataOut = certData; *info->cert.certSz = (word32)tmpl[0].ulValueLen; if (info->cert.certFormatOut != NULL) { *info->cert.certFormatOut = CTC_FILETYPE_ASN1; } certData = NULL; exit: XFREE(certData, info->cert.heap, DYNAMIC_TYPE_CERT); return ret; } #endif /* !NO_CERTS */ /** * Perform a cryptographic operation using PKCS#11 device. * * @param [in] devId Device identifier. * @param [in] info Cryptographic operation data. * @param [in] ctx Context data for device - the token object. * @return WC_HW_E when a PKCS#11 library call fails. * @return NOT_COMPILED_IN when an unsupported operation is requested. * @return 0 on success. */ int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) { int ret = 0; Pkcs11Token* token = (Pkcs11Token*)ctx; Pkcs11Session session; #ifdef WOLFSSL_PKCS11_RW_TOKENS int readWrite = 1; #else int readWrite = 0; #endif if (devId <= INVALID_DEVID || info == NULL || ctx == NULL) ret = BAD_FUNC_ARG; /* Open and close a session around each operation as the operation may not * be compiled in. */ if (ret == 0) { if (info->algo_type == WC_ALGO_TYPE_PK) { #if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_DILITHIUM) || \ defined(WOLFSSL_HAVE_MLKEM) switch (info->pk.type) { #ifndef NO_RSA case WC_PK_TYPE_RSA: #ifdef WOLF_CRYPTO_CB_RSA_PAD case WC_PK_TYPE_RSA_PKCS: case WC_PK_TYPE_RSA_PSS: case WC_PK_TYPE_RSA_OAEP: #endif ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11Rsa(&session, info); Pkcs11CloseSession(token, &session); } break; #ifdef WOLFSSL_KEY_GEN case WC_PK_TYPE_RSA_KEYGEN: ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11RsaKeyGen(&session, info); Pkcs11CloseSession(token, &session); } break; #endif case WC_PK_TYPE_RSA_CHECK_PRIV_KEY: ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11RsaCheckPrivKey(&session, info); Pkcs11CloseSession(token, &session); } break; case WC_PK_TYPE_RSA_GET_SIZE: ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11RsaGetSize(&session, info); Pkcs11CloseSession(token, &session); } break; #endif #ifdef HAVE_ECC #ifndef NO_PKCS11_EC_KEYGEN case WC_PK_TYPE_EC_KEYGEN: ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11EcKeyGen(&session, info); Pkcs11CloseSession(token, &session); } break; #endif #ifndef NO_PKCS11_ECDH case WC_PK_TYPE_ECDH: ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11ECDH(&session, info); Pkcs11CloseSession(token, &session); } break; #endif case WC_PK_TYPE_ECDSA_SIGN: ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11ECDSA_Sign(&session, info); Pkcs11CloseSession(token, &session); } break; case WC_PK_TYPE_ECDSA_VERIFY: ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11ECDSA_Verify(&session, info); Pkcs11CloseSession(token, &session); } break; case WC_PK_TYPE_EC_CHECK_PRIV_KEY: ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11EccCheckPrivKey(&session, info); Pkcs11CloseSession(token, &session); } break; #endif #ifdef WOLFSSL_HAVE_MLKEM case WC_PK_TYPE_PQC_KEM_KEYGEN: ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11PqcKemKeyGen(&session, info); Pkcs11CloseSession(token, &session); } break; case WC_PK_TYPE_PQC_KEM_ENCAPS: ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11PqcKemEncapsulate(&session, info); Pkcs11CloseSession(token, &session); } break; case WC_PK_TYPE_PQC_KEM_DECAPS: ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11PqcKemDecapsulate(&session, info); Pkcs11CloseSession(token, &session); } break; #endif #if defined(HAVE_DILITHIUM) case WC_PK_TYPE_PQC_SIG_KEYGEN: ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11PqcSigKeyGen(&session, info); Pkcs11CloseSession(token, &session); } break; case WC_PK_TYPE_PQC_SIG_SIGN: ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11PqcSigSign(&session, info); Pkcs11CloseSession(token, &session); } break; case WC_PK_TYPE_PQC_SIG_VERIFY: ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11PqcSigVerify(&session, info); Pkcs11CloseSession(token, &session); } break; case WC_PK_TYPE_PQC_SIG_CHECK_PRIV_KEY: ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11PqcSigCheckPrivKey(&session, info); Pkcs11CloseSession(token, &session); } break; #endif default: ret = NOT_COMPILED_IN; break; } #else ret = NOT_COMPILED_IN; #endif /* !NO_RSA || HAVE_ECC || HAVE_DILITHIUM || WOLFSSL_HAVE_MLKEM */ } else if (info->algo_type == WC_ALGO_TYPE_CIPHER) { #ifndef NO_AES switch (info->cipher.type) { #ifdef HAVE_AESGCM case WC_CIPHER_AES_GCM: if (info->cipher.enc) { ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11AesGcmEncrypt(&session, info); Pkcs11CloseSession(token, &session); } } else { ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11AesGcmDecrypt(&session, info); Pkcs11CloseSession(token, &session); } } break; #endif #ifdef HAVE_AES_CBC case WC_CIPHER_AES_CBC: if (info->cipher.enc) { ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11AesCbcEncrypt(&session, info); Pkcs11CloseSession(token, &session); } } else { ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11AesCbcDecrypt(&session, info); Pkcs11CloseSession(token, &session); } } break; #endif #ifdef WOLFSSL_AES_COUNTER case WC_CIPHER_AES_CTR: if (info->cipher.enc) { ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11AesCtrEncrypt(&session, info); Pkcs11CloseSession(token, &session); } } else { ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11AesCtrDecrypt(&session, info); Pkcs11CloseSession(token, &session); } } break; #endif default: ret = NOT_COMPILED_IN; break; } #else ret = NOT_COMPILED_IN; #endif } else if (info->algo_type == WC_ALGO_TYPE_HMAC) { #ifndef NO_HMAC Hmac* hmac = info->hmac.hmac; /* Sign ops are session-scoped; cache the session across * multi-call HMAC dispatches. */ if (hmac != NULL && hmac->devCtx != NULL) { session.func = token->func; session.slotId = token->slotId; session.version = token->version; session.handle = (CK_SESSION_HANDLE)(wc_ptr_t)hmac->devCtx; ret = Pkcs11Hmac(&session, info); if (ret != 0 || hmac->innerHashKeyed != WC_HMAC_INNER_HASH_KEYED_DEV) { Pkcs11CloseSession(token, &session); hmac->devCtx = NULL; /* Don't leave stale DEV state past session close; * leave SW state (owned by software fallback). */ if (hmac->innerHashKeyed == WC_HMAC_INNER_HASH_KEYED_DEV) hmac->innerHashKeyed = 0; } } else { ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11Hmac(&session, info); if (ret == 0 && hmac != NULL && hmac->innerHashKeyed == WC_HMAC_INNER_HASH_KEYED_DEV) { hmac->devCtx = (void*)(wc_ptr_t)session.handle; } else { Pkcs11CloseSession(token, &session); if (hmac != NULL && hmac->innerHashKeyed == WC_HMAC_INNER_HASH_KEYED_DEV) hmac->innerHashKeyed = 0; } } } #else ret = NOT_COMPILED_IN; #endif } else if (info->algo_type == WC_ALGO_TYPE_RNG) { #if !defined(WC_NO_RNG) && !defined(HAVE_HASHDRBG) ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11RandomBlock(&session, info); Pkcs11CloseSession(token, &session); } #else ret = NOT_COMPILED_IN; #endif } else if (info->algo_type == WC_ALGO_TYPE_SEED) { #ifndef WC_NO_RNG ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11RandomSeed(&session, info); Pkcs11CloseSession(token, &session); } #else ret = NOT_COMPILED_IN; #endif } else if (info->algo_type == WC_ALGO_TYPE_CERT) { #ifndef NO_CERTS ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11GetCert(&session, info); Pkcs11CloseSession(token, &session); } #else ret = NOT_COMPILED_IN; #endif } else if (info->algo_type == WC_ALGO_TYPE_FREE) { #ifdef HAVE_ECC if (info->free.algo == WC_ALGO_TYPE_PK && info->free.type == WC_PK_TYPE_EC_KEYGEN) { ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11EccDeletePrivKey(&session, (ecc_key*)info->free.obj); Pkcs11CloseSession(token, &session); } } else #endif #ifdef HAVE_DILITHIUM if (info->free.algo == WC_ALGO_TYPE_PK && info->free.type == WC_PK_TYPE_PQC_SIG_KEYGEN && info->free.subType == WC_PQC_SIG_TYPE_DILITHIUM) { ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11MldsaDeletePrivKey(&session, (MlDsaKey*)info->free.obj); Pkcs11CloseSession(token, &session); } } else #endif #ifdef WOLFSSL_HAVE_MLKEM if (info->free.algo == WC_ALGO_TYPE_PK && info->free.type == WC_PK_TYPE_PQC_KEM_KEYGEN && info->free.subType == WC_PQC_KEM_TYPE_KYBER) { ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11MlKemDeletePrivKey(&session, (MlKemKey*)info->free.obj); Pkcs11CloseSession(token, &session); } } else #endif { ret = NOT_COMPILED_IN; } } else { ret = NOT_COMPILED_IN; } } return ret; } #endif /* HAVE_PKCS11 */