diff options
Diffstat (limited to 'FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/wc_pkcs11.c')
-rw-r--r-- | FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/wc_pkcs11.c | 2546 |
1 files changed, 2546 insertions, 0 deletions
diff --git a/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/wc_pkcs11.c b/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/wc_pkcs11.c new file mode 100644 index 000000000..cac0a0fcc --- /dev/null +++ b/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/wc_pkcs11.c @@ -0,0 +1,2546 @@ +/* wc_pkcs11.c + * + * Copyright (C) 2006-2020 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 + */ + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif + +#include <wolfssl/wolfcrypt/settings.h> + +#ifdef HAVE_PKCS11 + +#include <dlfcn.h> + +#include <wolfssl/wolfcrypt/wc_pkcs11.h> +#include <wolfssl/wolfcrypt/error-crypt.h> +#include <wolfssl/wolfcrypt/asn.h> +#include <wolfssl/wolfcrypt/logging.h> +#ifndef NO_RSA + #include <wolfssl/wolfcrypt/rsa.h> +#endif +#ifdef NO_INLINE + #include <wolfssl/wolfcrypt/misc.h> +#else + #define WOLFSSL_MISC_INCLUDED + #include <wolfcrypt/src/misc.c> +#endif + +#define MAX_EC_PARAM_LEN 16 + +#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(HAVE_ECC) && !defined(NO_PKCS11_ECDH) +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) +static CK_BBOOL ckTrue = CK_TRUE; +#endif + +#ifndef NO_RSA +static CK_KEY_TYPE rsaKeyType = CKK_RSA; +#endif +#ifdef HAVE_ECC +static CK_KEY_TYPE ecKeyType = CKK_EC; +#endif +#if !defined(NO_RSA) || defined(HAVE_ECC) +static CK_OBJECT_CLASS pubKeyClass = CKO_PUBLIC_KEY; +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)) +static CK_OBJECT_CLASS secretKeyClass = CKO_SECRET_KEY; +#endif + +/** + * Load library, get function list and initialize PKCS#11. + * + * @param dev [in] Device object. + * @param library [in] Library name including path. + * @return BAD_FUNC_ARG when dev or library are NULL pointers. + * BAD_PATH_ERROR when dynamic library cannot be opened. + * WC_INIT_E when the initialization PKCS#11 fails. + * WC_HW_E when unable to get PKCS#11 function list. + * 0 on success. + */ +int wc_Pkcs11_Initialize(Pkcs11Dev* dev, const char* library, void* heap) +{ + int ret = 0; + void* func; + CK_C_INITIALIZE_ARGS args; + + if (dev == NULL || library == NULL) + ret = BAD_FUNC_ARG; + + if (ret == 0) { + dev->heap = heap; + dev->dlHandle = dlopen(library, RTLD_NOW | RTLD_LOCAL); + if (dev->dlHandle == NULL) { + WOLFSSL_MSG(dlerror()); + ret = BAD_PATH_ERROR; + } + } + + if (ret == 0) { + dev->func = NULL; + func = dlsym(dev->dlHandle, "C_GetFunctionList"); + if (func == NULL) + ret = WC_HW_E; + } + if (ret == 0) { + if (((CK_C_GetFunctionList)func)(&dev->func) != CKR_OK) + ret = WC_HW_E; + } + + if (ret == 0) { + XMEMSET(&args, 0x00, sizeof(args)); + args.flags = CKF_OS_LOCKING_OK; + if (dev->func->C_Initialize(&args) != CKR_OK) + ret = WC_INIT_E; + } + + if (ret != 0) + wc_Pkcs11_Finalize(dev); + + return ret; +} + +/** + * Close the Pkcs#11 library. + * + * @param dev [in] Device object. + */ +void wc_Pkcs11_Finalize(Pkcs11Dev* dev) +{ + if (dev != NULL && dev->dlHandle != NULL) { + if (dev->func != NULL) { + dev->func->C_Finalize(NULL); + dev->func = NULL; + } + dlclose(dev->dlHandle); + dev->dlHandle = NULL; + } +} + +/** + * Set up a token for use. + * + * @param token [in] Token object. + * @param dev [in] PKCS#11 device object. + * @param slotId [in] Slot number of the token.<br> + * Passing -1 uses the first available slot. + * @param tokenName [in] Name of token to initialize. + * @param userPin [in] PIN to use to login as user. + * @param userPinSz [in] Number of bytes in PIN. + * @return BAD_FUNC_ARG when token, dev and/or tokenName is NULL. + * WC_INIT_E when initializing token fails. + * WC_HW_E when another PKCS#11 library call fails. + * -1 when no slot available. + * 0 on success. + */ +int wc_Pkcs11Token_Init(Pkcs11Token* token, Pkcs11Dev* dev, int slotId, + const char* tokenName, const unsigned char* userPin, int userPinSz) +{ + int ret = 0; + CK_RV rv; + CK_SLOT_ID* slot = NULL; + CK_ULONG slotCnt = 0; + + if (token == NULL || dev == NULL || tokenName == NULL) + ret = BAD_FUNC_ARG; + + if (ret == 0) { + if (slotId < 0) { + /* Use first available slot with a token. */ + rv = dev->func->C_GetSlotList(CK_TRUE, NULL, &slotCnt); + 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); + if (rv != CKR_OK) + ret = WC_HW_E; + } + if (ret == 0) { + if (slotCnt > 0) + slotId = (int)slot[0]; + else + ret = WC_HW_E; + } + } + } + if (ret == 0) { + token->func = dev->func; + token->slotId = (CK_SLOT_ID)slotId; + token->handle = NULL_PTR; + token->userPin = (CK_UTF8CHAR_PTR)userPin; + token->userPinSz = (CK_ULONG)userPinSz; + } + + if (slot != NULL) + XFREE(slot, dev->heap, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +/** + * Finalize token. + * Closes all sessions on token. + * + * @param token [in] 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 token [in] Token object. + * @param session [in] Session object. + * @param readWrite [in] Boolean indicating to open session for Read/Write. + * @return BAD_FUNC_ARG when token or session is NULL. + * WC_HW_E when opening the session fails. + * 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); + if (rv != CKR_OK) + ret = WC_HW_E; + if (ret == 0 && token->userPin != NULL) { + rv = token->func->C_Login(session->handle, CKU_USER, + token->userPin, token->userPinSz); + if (rv != CKR_OK) + ret = WC_HW_E; + } + } + } + if (ret == 0) { + session->func = token->func; + session->slotId = token->slotId; + } + + return ret; +} + +/** + * Close a session on a token. + * Won't close a session created externally. + * + * @param token [in] Token object. + * @param session [in] 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 token [in] Token object. + * @param readWrite [in] Boolean indicating to open session for Read/Write. + * @return BAD_FUNC_ARG when token is NULL. + * WC_HW_E when opening the session fails. + * 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 token [in] 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) +static int Pkcs11CreateSecretKey(CK_OBJECT_HANDLE* key, Pkcs11Session* session, + CK_KEY_TYPE keyType, unsigned char* data, + int len, unsigned char* id, int idLen) +{ + int ret = 0; + CK_RV rv; + CK_ATTRIBUTE keyTemplate[] = { + { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, NULL, 0 }, + { CKA_ID, id, (CK_ULONG)idLen } + }; + int keyTmplCnt = 4; + + WOLFSSL_MSG("PKCS#11: Create Secret Key"); + + /* Set the modulus and public exponent data. */ + keyTemplate[3].pValue = data; + keyTemplate[3].ulValueLen = (CK_ULONG)len; + + if (idLen > 0) + keyTmplCnt++; + + /* Create an object containing key data for device to use. */ + rv = session->func->C_CreateObject(session->handle, keyTemplate, keyTmplCnt, + key); + if (rv != CKR_OK) + ret = WC_HW_E; + + return ret; +} +#endif + +#ifndef NO_RSA +/** + * Create a PKCS#11 object containing the RSA private key data. + * + * @param privateKey [out] Henadle to private key object. + * @param session [in] Session object. + * @param rsaKey [in] RSA key with private key data. + * @return WC_HW_E when a PKCS#11 library call fails. + * 0 on success. + */ +static int Pkcs11CreateRsaPrivateKey(CK_OBJECT_HANDLE* privateKey, + Pkcs11Session* session, + RsaKey* rsaKey) +{ + int ret = 0; + CK_RV rv; + CK_ATTRIBUTE keyTemplate[] = { + { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, + { CKA_KEY_TYPE, &rsaKeyType, sizeof(rsaKeyType) }, + { CKA_DECRYPT, &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 } + }; + CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate); + + /* Set the modulus and private key data. */ + keyTemplate[ 3].pValue = rsaKey->n.raw.buf; + keyTemplate[ 3].ulValueLen = rsaKey->n.raw.len; + keyTemplate[ 4].pValue = rsaKey->d.raw.buf; + keyTemplate[ 4].ulValueLen = rsaKey->d.raw.len; + keyTemplate[ 5].pValue = rsaKey->p.raw.buf; + keyTemplate[ 5].ulValueLen = rsaKey->p.raw.len; + keyTemplate[ 6].pValue = rsaKey->q.raw.buf; + keyTemplate[ 6].ulValueLen = rsaKey->q.raw.len; + keyTemplate[ 7].pValue = rsaKey->dP.raw.buf; + keyTemplate[ 7].ulValueLen = rsaKey->dP.raw.len; + keyTemplate[ 8].pValue = rsaKey->dQ.raw.buf; + keyTemplate[ 8].ulValueLen = rsaKey->dQ.raw.len; + keyTemplate[ 9].pValue = rsaKey->u.raw.buf; + keyTemplate[ 9].ulValueLen = rsaKey->u.raw.len; + keyTemplate[10].pValue = rsaKey->e.raw.buf; + keyTemplate[10].ulValueLen = rsaKey->e.raw.len; + + rv = session->func->C_CreateObject(session->handle, keyTemplate, keyTmplCnt, + privateKey); + if (rv != CKR_OK) + ret = WC_HW_E; + + return ret; +} +#endif + +#ifdef HAVE_ECC +/** + * Set the ECC parameters into the template. + * + * @param key [in] ECC key. + * @param tmpl [in] PKCS#11 template. + * @param idx [in] Index of template to put parameters into. + * @return NOT_COMPILE_IN when the EC parameters are not known. + * 0 on success. + */ +static int Pkcs11EccSetParams(ecc_key* key, CK_ATTRIBUTE* tmpl, int idx) +{ + int ret = 0; + + if (key->dp != NULL && key->dp->oid != NULL) { + unsigned char* derParams = tmpl[idx].pValue; + /* 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); + } + else + ret = NOT_COMPILED_IN; + + return ret; +} + +/** + * Create a PKCS#11 object containing the ECC private key data. + * + * @param privateKey [out] Henadle 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. + * 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[MAX_EC_PARAM_LEN]; + 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 } + }; + CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate); + + ret = Pkcs11EccSetParams(private_key, keyTemplate, 3); + if (ret == 0) { + keyTemplate[4].pValue = private_key->k.raw.buf; + keyTemplate[4].ulValueLen = private_key->k.raw.len; + + rv = session->func->C_CreateObject(session->handle, keyTemplate, + keyTmplCnt, privateKey); + if (rv != CKR_OK) + ret = WC_HW_E; + } + + return ret; +} +#endif + +#if !defined(NO_RSA) || defined(HAVE_ECC) || (!defined(NO_AES) && \ + (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || !defined(NO_HMAC) +/** + * Check if mechanism is available in session on token. + * + * @param session [in] Session object. + * @param mech [in] Mechanism to look for. + * @return NOT_COMPILED_IN when mechanism not available. + * 0 when mechanism is available. + */ +static int Pkcs11MechAvail(Pkcs11Session* session, CK_MECHANISM_TYPE mech) +{ + int ret = 0; + CK_RV rv; + CK_MECHANISM_INFO mechInfo; + + rv = session->func->C_GetMechanismInfo(session->slotId, mech, &mechInfo); + if (rv != CKR_OK) + ret = NOT_COMPILED_IN; + + return ret; +} +#endif + +#ifndef NO_HMAC +/** + * Return the mechanism type and key type for the digest type when using HMAC. + * + * @param macType [in] Digest type - e.g. WC_SHA256. + * @param mechType [in] Mechanism type - e.g. CKM_SHA256_HMAC. + * @param keyType [in] Key type - e.g. CKK_SHA256_HMAC. + * @return NOT_COMPILED_IN if the digest algorithm isn't recognised. + * 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 token [in] Token to store private key on. + * @param type [in] Key type. + * @param clear [in] Clear out the private data from software key. + * @param key [in] Key type specific object. + * @return NOT_COMPILED_IN when mechanism not available. + * 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); + if (ret == 0) { + ret = Pkcs11CreateSecretKey(&privKey, &session, CKK_AES, + (unsigned char*)aes->devKey, + aes->keylen, + (unsigned char*)aes->id, + aes->idLen); + } + 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); + if (ret == 0) { + ret = Pkcs11CreateSecretKey(&privKey, &session, CKK_AES, + (unsigned char*)aes->devKey, + aes->keylen, + (unsigned char*)aes->id, + aes->idLen); + } + 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 == NOT_COMPILED_IN) + break; + + if (ret == 0) + ret = Pkcs11MechAvail(&session, mechType); + if (ret == 0) { + ret = Pkcs11CreateSecretKey(&privKey, &session, keyType, + (unsigned char*)hmac->keyRaw, + hmac->keyLen, + (unsigned char*)hmac->id, + hmac->idLen); + if (ret == WC_HW_E) { + ret = Pkcs11CreateSecretKey(&privKey, &session, + CKK_GENERIC_SECRET, + (unsigned char*)hmac->keyRaw, + hmac->keyLen, + (unsigned char*)hmac->id, + hmac->idLen); + } + } + break; + } + #endif + #ifndef NO_RSA + case PKCS11_KEY_TYPE_RSA: { + RsaKey* rsaKey = (RsaKey*)key; + + ret = Pkcs11MechAvail(&session, CKM_RSA_X_509); + if (ret == 0) + ret = Pkcs11CreateRsaPrivateKey(&privKey, &session, rsaKey); + 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 = NOT_COMPILED_IN; + + #ifndef NO_PKCS11_ECDH + /* Try ECDH mechanism first. */ + ret = Pkcs11MechAvail(&session, CKM_ECDH1_DERIVE); + if (ret == 0) { + ret = Pkcs11CreateEccPrivateKey(&privKey, &session, eccKey, + CKA_DERIVE); + } + #endif + if (ret == 0 || ret == NOT_COMPILED_IN) { + /* Try ECDSA mechanism next. */ + ret2 = Pkcs11MechAvail(&session, CKM_ECDSA); + if (ret2 == 0) { + ret2 = Pkcs11CreateEccPrivateKey(&privKey, &session, + eccKey, CKA_SIGN); + } + /* OK for this to fail if set for ECDH. */ + if (ret == NOT_COMPILED_IN) + ret = ret2; + } + if (ret == 0 && clear) + mp_forcezero(&eccKey->k); + break; + } + #endif + 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) +/** + * Find the PKCS#11 object containing the RSA public or private key data with + * the modulus specified. + * + * @param key [out] Henadle to key object. + * @param keyClass [in] Public or private key class. + * @param keyType [in] Type of key. + * @param session [in] Session object. + * @param id [in] Identifier set against a key. + * @param idLen [in] Length of identifier. + * @return WC_HW_E when a PKCS#11 library call fails. + * 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_RV rv; + CK_ULONG count; + CK_ATTRIBUTE keyTemplate[] = { + { CKA_CLASS, &keyClass, sizeof(keyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_ID, id, (CK_ULONG)idLen } + }; + CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate); + + WOLFSSL_MSG("PKCS#11: Find Key By Id"); + + rv = session->func->C_FindObjectsInit(session->handle, keyTemplate, + keyTmplCnt); + if (rv != CKR_OK) + ret = WC_HW_E; + if (ret == 0) { + rv = session->func->C_FindObjects(session->handle, key, 1, &count); + if (rv != CKR_OK) + ret = WC_HW_E; + rv = session->func->C_FindObjectsFinal(session->handle); + if (rv != CKR_OK) + ret = WC_HW_E; + } + 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 key [out] Henadle to key object. + * @param keyClass [in] Public or private key class. + * @param session [in] Session object. + * @param rsaKey [in] RSA key with modulus to search on. + * @return WC_HW_E when a PKCS#11 library call fails. + * 0 on success. + */ +static int Pkcs11FindRsaKey(CK_OBJECT_HANDLE* key, CK_OBJECT_CLASS keyClass, + Pkcs11Session* session, RsaKey* rsaKey) +{ + int ret = 0; + CK_RV rv; + 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; + + rv = session->func->C_FindObjectsInit(session->handle, keyTemplate, + keyTmplCnt); + if (rv != CKR_OK) + ret = WC_HW_E; + if (ret == 0) { + rv = session->func->C_FindObjects(session->handle, key, 1, &count); + if (rv != CKR_OK) + ret = WC_HW_E; + rv = session->func->C_FindObjectsFinal(session->handle); + if (rv != CKR_OK) + ret = WC_HW_E; + } + + return ret; +} + +/** + * Exponentiate the input with the public part of the RSA key. + * Used in public encrypt and decrypt. + * + * @param session [in] Session object. + * @param info [in] Cryptographic operation data. + * @return WC_HW_E when a PKCS#11 library call fails. + * 0 on success. + */ +static int Pkcs11RsaPublic(Pkcs11Session* session, wc_CryptoInfo* info) +{ + int ret = 0; + CK_RV rv; + CK_MECHANISM mech; + CK_ULONG outLen; + CK_OBJECT_HANDLE publicKey = NULL_PTR; + int sessionKey = 0; + 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); + + WOLFSSL_MSG("PKCS#11: RSA Public Key Operation"); + + if (info->pk.rsa.outLen == NULL) { + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + if ((sessionKey = !mp_iszero(&info->pk.rsa.key->e))) { + /* Set the modulus and public exponent data. */ + keyTemplate[3].pValue = info->pk.rsa.key->n.raw.buf; + keyTemplate[3].ulValueLen = info->pk.rsa.key->n.raw.len; + keyTemplate[4].pValue = info->pk.rsa.key->e.raw.buf; + keyTemplate[4].ulValueLen = info->pk.rsa.key->e.raw.len; + + /* Create an object containing public key data for device to use. */ + rv = session->func->C_CreateObject(session->handle, keyTemplate, + keyTmplCnt, &publicKey); + if (rv != CKR_OK) + ret = WC_HW_E; + } + else { + ret = Pkcs11FindKeyById(&publicKey, CKO_PUBLIC_KEY, CKK_RSA, + session, info->pk.rsa.key->id, + info->pk.rsa.key->idLen); + } + } + + if (ret == 0) { + /* Raw RSA encrypt/decrypt operation. */ + mech.mechanism = CKM_RSA_X_509; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rv = session->func->C_EncryptInit(session->handle, &mech, publicKey); + 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); + if (rv != CKR_OK) + ret = WC_HW_E; + } + if (ret == 0) + *info->pk.rsa.outLen = (word32)outLen; + + if (sessionKey) + session->func->C_DestroyObject(session->handle, publicKey); + + return ret; +} + +/** + * Exponentiate the input with the private part of the RSA key. + * Used in private encrypt and decrypt. + * + * @param session [in] Session object. + * @param info [in] Cryptographic operation data. + * @return WC_HW_E when a PKCS#11 library call fails. + * 0 on success. + */ +static int Pkcs11RsaPrivate(Pkcs11Session* session, wc_CryptoInfo* info) +{ + int ret = 0; + CK_RV rv; + CK_MECHANISM mech; + CK_ULONG outLen; + CK_OBJECT_HANDLE privateKey = NULL_PTR; + int sessionKey = 0; + + WOLFSSL_MSG("PKCS#11: RSA Private Key Operation"); + + if (info->pk.rsa.outLen == NULL) { + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + if ((sessionKey = !mp_iszero(&info->pk.rsa.key->d))) { + ret = Pkcs11CreateRsaPrivateKey(&privateKey, session, + info->pk.rsa.key); + } + else if (info->pk.rsa.key->idLen > 0) { + ret = Pkcs11FindKeyById(&privateKey, CKO_PRIVATE_KEY, CKK_RSA, + session, info->pk.rsa.key->id, + info->pk.rsa.key->idLen); + } + else { + ret = Pkcs11FindRsaKey(&privateKey, CKO_PRIVATE_KEY, session, + info->pk.rsa.key); + } + } + + if (ret == 0) { + /* Raw RSA encrypt/decrypt operation. */ + mech.mechanism = CKM_RSA_X_509; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rv = session->func->C_DecryptInit(session->handle, &mech, privateKey); + if (rv != CKR_OK) + ret = WC_HW_E; + } + if (ret == 0) { + 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); + if (rv != CKR_OK) + ret = WC_HW_E; + } + if (ret == 0) + *info->pk.rsa.outLen = (word32)outLen; + + if (sessionKey) + session->func->C_DestroyObject(session->handle, privateKey); + + return ret; +} + +/** + * Perform an RSA operation. + * + * @param session [in] Session object. + * @param info [in] Cryptographic operation data. + * @return WC_HW_E when a PKCS#11 library call fails. + * 0 on success. + */ +static int Pkcs11Rsa(Pkcs11Session* session, wc_CryptoInfo* info) +{ + int ret = 0; + CK_RV rv; + CK_MECHANISM_INFO mechInfo; + + /* Check operation is supported. */ + rv = session->func->C_GetMechanismInfo(session->slotId, CKM_RSA_X_509, + &mechInfo); + if (rv != CKR_OK) + ret = NOT_COMPILED_IN; + + if (ret == 0) { + if (info->pk.rsa.type == RSA_PUBLIC_ENCRYPT || + info->pk.rsa.type == RSA_PUBLIC_DECRYPT) { + if ((mechInfo.flags & CKF_ENCRYPT) == 0) + ret = NOT_COMPILED_IN; + else + ret = Pkcs11RsaPublic(session, info); + } + else if (info->pk.rsa.type == RSA_PRIVATE_ENCRYPT || + info->pk.rsa.type == RSA_PRIVATE_DECRYPT) { + if ((mechInfo.flags & CKF_DECRYPT) == 0) + ret = NOT_COMPILED_IN; + else + ret = Pkcs11RsaPrivate(session, info); + } + else + ret = NOT_COMPILED_IN; + } + + return ret; +} + +#ifdef WOLFSSL_KEY_GEN +/** + * Get the RSA public key data from the PKCS#11 object. + * + * @param key [in] RSA key to put the data into. + * @param session [in] Session object. + * @param pubkey [in] Public key object. + * @return WC_HW_E when a PKCS#11 library call fails. + * MEMORY_E when a memory allocation fails. + * 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; + + rv = session->func->C_GetAttributeValue(session->handle, pubKey, tmpl, + tmplCnt); + if (rv != CKR_OK) + ret = WC_HW_E; + + if (ret == 0) { + modSz = tmpl[0].ulValueLen; + expSz = 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; + + rv = session->func->C_GetAttributeValue(session->handle, pubKey, + tmpl, tmplCnt); + if (rv != CKR_OK) + ret = WC_HW_E; + } + if (ret == 0) + ret = wc_RsaPublicKeyDecodeRaw(mod, modSz, exp, expSz, key); + + if (exp != NULL) + XFREE(exp, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (mod != NULL) + XFREE(mod, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +/** + * Perform an RSA key generation operation. + * The private key data stays on the device. + * + * @param session [in] Session object. + * @param info [in] Cryptographic operation data. + * @return WC_HW_E when a PKCS#11 library call fails. + * 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); + CK_ATTRIBUTE privKeyTmpl[] = { + {CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, + {CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + {CKA_ID, NULL, 0 } + }; + int privTmplCnt = 2; + int i; + + ret = Pkcs11MechAvail(session, CKM_RSA_PKCS_KEY_PAIR_GEN); + 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->idLen != 0) { + 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; + + rv = session->func->C_GenerateKeyPair(session->handle, &mech, + pubKeyTmpl, pubTmplCnt, + privKeyTmpl, privTmplCnt, + &pubKey, &privKey); + if (rv != CKR_OK) + ret = -1; + } + + if (ret == 0) + ret = Pkcs11GetRsaPublicKey(key, session, pubKey); + + if (pubKey != NULL_PTR) + ret = session->func->C_DestroyObject(session->handle, pubKey); + if (ret != 0 && privKey != NULL_PTR) + ret = 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 with + * the modulus specified. + * + * @param key [out] Henadle to key object. + * @param keyClass [in] Public or private key class. + * @param session [in] Session object. + * @param eccKey [in] ECC key with parameters. + * @return WC_HW_E when a PKCS#11 library call fails. + * MEMORY_E when a memory allocation fails. + * 0 on success. + */ +static int Pkcs11FindEccKey(CK_OBJECT_HANDLE* key, CK_OBJECT_CLASS keyClass, + Pkcs11Session* session, ecc_key* eccKey) +{ + int ret = 0; + int i; + unsigned char* ecPoint = NULL; + word32 len = 0; + CK_RV rv; + CK_ULONG count; + CK_UTF8CHAR params[MAX_EC_PARAM_LEN]; + CK_ATTRIBUTE keyTemplate[] = { + { CKA_CLASS, &keyClass, sizeof(keyClass) }, + { CKA_KEY_TYPE, &ecKeyType, sizeof(ecKeyType) }, + { CKA_EC_PARAMS, params, 0 }, + { CKA_EC_POINT, NULL, 0 }, + }; + CK_ULONG attrCnt = 3; + + 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; + ret = wc_ecc_export_x963(eccKey, ecPoint + i, &len); + } + if (ret == 0 && keyClass == CKO_PUBLIC_KEY) { + keyTemplate[3].pValue = ecPoint; + keyTemplate[3].ulValueLen = len + i; + attrCnt++; + } + if (ret == 0) { + rv = session->func->C_FindObjectsInit(session->handle, keyTemplate, + attrCnt); + if (rv != CKR_OK) + ret = WC_HW_E; + } + if (ret == 0) { + rv = session->func->C_FindObjects(session->handle, key, 1, &count); + if (rv != CKR_OK) + ret = WC_HW_E; + rv = session->func->C_FindObjectsFinal(session->handle); + if (rv != CKR_OK) + ret = WC_HW_E; + } + + if (ecPoint != NULL) + XFREE(ecPoint, eccKey->heap, DYNAMIC_TYPE_ECC); + + 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 publicKey [out] Henadle to public key object. + * @param session [in] Session object. + * @param public_key [in] ECC public key. + * @param operation [in] Cryptographic operation key is to be used for. + * @return WC_HW_E when a PKCS#11 library call fails. + * MEMORY_E when a memory allocation fails. + * 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[MAX_EC_PARAM_LEN]; + 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 } + }; + CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate); + + 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; + ret = wc_ecc_export_x963(public_key, ecPoint + i, &len); + } + if (ret == 0) { + keyTemplate[4].pValue = ecPoint; + keyTemplate[4].ulValueLen = len + i; + + rv = session->func->C_CreateObject(session->handle, keyTemplate, + keyTmplCnt, publicKey); + if (rv != CKR_OK) + ret = WC_HW_E; + } + + if (ecPoint != NULL) + XFREE(ecPoint, public_key->heap, DYNAMIC_TYPE_ECC); + + return ret; +} + +#ifndef NO_PKCS11_EC_KEYGEN +/** + * Gets the public key data from the PKCS#11 object and puts into the ECC key. + * + * @param key [in] ECC public key. + * @param session [in] Session object. + * @param pubKey [in] ECC public key PKCS#11 object. + * @return WC_HW_E when a PKCS#11 library call fails. + * MEMORY_E when a memory allocation fails. + * 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; + 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); + 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; + + rv = session->func->C_GetAttributeValue(session->handle, pubKey, + tmpl, tmplCnt); + if (rv != CKR_OK) + ret = WC_HW_E; + } + + /* 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); + } + + if (point != NULL) + XFREE(point, key->heap, DYNAMIC_TYPE_ECC); + + return ret; +} + +/** + * Perform an ECC key generation operation. + * The private key data stays on the device. + * + * @param session [in] Session object. + * @param info [in] Cryptographic operation data. + * @return WC_HW_E when a PKCS#11 library call fails. + * 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[MAX_EC_PARAM_LEN]; + CK_ATTRIBUTE pubKeyTmpl[] = { + { CKA_EC_PARAMS, params, 0 }, + { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + }; + int pubTmplCnt = sizeof(pubKeyTmpl)/sizeof(*pubKeyTmpl); + CK_ATTRIBUTE privKeyTmpl[] = { + { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_DERIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_ID, NULL, 0 }, + }; + int privTmplCnt = 3; + + ret = Pkcs11MechAvail(session, CKM_EC_KEY_PAIR_GEN); + if (ret == 0) { + WOLFSSL_MSG("PKCS#11: EC Key Generation Operation"); + + ret = Pkcs11EccSetParams(key, pubKeyTmpl, 0); + } + if (ret == 0) { + if (key->idLen != 0) { + privKeyTmpl[privTmplCnt].pValue = key->id; + privKeyTmpl[privTmplCnt].ulValueLen = key->idLen; + privTmplCnt++; + } + + mech.mechanism = CKM_EC_KEY_PAIR_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rv = session->func->C_GenerateKeyPair(session->handle, &mech, + pubKeyTmpl, pubTmplCnt, + privKeyTmpl, privTmplCnt, + &pubKey, &privKey); + 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) + 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 session [in] Session object. + * @param secret [in] PKCS#11 object with the secret key data. + * @param out [in] Buffer to hold secret data. + * @param outLen [in,out] On in, length of buffer. + * On out, the length of data in buffer. + * @return WC_HW_E when a PKCS#11 library call fails. + * 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; + + rv = session->func->C_GetAttributeValue(session->handle, secret, tmpl, + tmplCnt); + if (rv != CKR_OK) + ret = WC_HW_E; + if (ret == 0) { + if (tmpl[0].ulValueLen > *outLen) + ret = BUFFER_E; + } + if (ret == 0) { + tmpl[0].pValue = out; + rv = session->func->C_GetAttributeValue(session->handle, secret, + tmpl, tmplCnt); + if (rv != CKR_OK) + ret = WC_HW_E; + *outLen = (word32)tmpl[0].ulValueLen; + } + + return ret; +} + +/** + * Performs the ECDH secret generation operation. + * + * @param session [in] Session object. + * @param info [in] 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); + if (ret == 0 && info->pk.ecdh.outlen == NULL) { + ret = BAD_FUNC_ARG; + } + if (ret == 0) { + WOLFSSL_MSG("PKCS#11: EC Key Derivation Operation"); + + + if ((sessionKey = !mp_iszero(&info->pk.ecdh.private_key->k))) + ret = Pkcs11CreateEccPrivateKey(&privateKey, session, + info->pk.ecdh.private_key, CKA_DERIVE); + 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); + } + } + if (ret == 0) { + ret = wc_ecc_export_x963(info->pk.ecdh.public_key, NULL, &pointLen); + if (ret == LENGTH_ONLY_E) { + point = (unsigned char*)XMALLOC(pointLen, + info->pk.ecdh.public_key->heap, + DYNAMIC_TYPE_ECC_BUFFER); + ret = wc_ecc_export_x963(info->pk.ecdh.public_key, point, + &pointLen); + } + } + + if (ret == 0) { + secSz = *info->pk.ecdh.outlen; + if (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; + + rv = session->func->C_DeriveKey(session->handle, &mech, privateKey, + tmpl, tmplCnt, &secret); + if (rv != CKR_OK) + ret = WC_HW_E; + } + + if (ret == 0) { + ret = Pkcs11ExtractSecret(session, secret, info->pk.ecdh.out, + info->pk.ecdh.outlen); + } + + if (sessionKey) + 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 sig [in,out] Signature data. + * @param sz [in] Size of original signature data. + * @return Length of the ASN.1 DER enencoded 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 inSz [in] Size of ASN.1 signature. + * @param sig [in] Output buffer. + * @param sz [in] Size of output buffer. + * @return ASN_PARSE_E when the ASN.1 encoding is invalid. + * 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 session [in] Session object. + * @param privKey [in] PKCS #11 object handle of private key.. + * @param key [in] Ecc key to set parameters against. + * @return WC_HW_E when a PKCS#11 library call fails. + * 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) } + }; + + rv = session->func->C_GetAttributeValue(session->handle, privKey, template, + 1); + if (rv != CKR_OK) + ret = WC_HW_E; + 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. + * 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. */ + rv = session->func->C_GetMechanismInfo(session->slotId, CKM_ECDSA, + &mechInfo); + if (rv != CKR_OK || (mechInfo.flags & CKF_SIGN) == 0) + ret = NOT_COMPILED_IN; + + if (ret == 0 && info->pk.eccsign.outlen == NULL) { + ret = BAD_FUNC_ARG; + } + if (ret == 0) { + WOLFSSL_MSG("PKCS#11: EC Signing Operation"); + + if ((sessionKey = !mp_iszero(&info->pk.eccsign.key->k))) + ret = Pkcs11CreateEccPrivateKey(&privateKey, session, + info->pk.eccsign.key, CKA_SIGN); + 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); + } + } + + 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); + 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); + if (rv != CKR_OK) + ret = WC_HW_E; + } + + if (ret == 0) { + *info->pk.eccsign.outlen = Pkcs11ECDSASig_Encode(info->pk.eccsign.out, + sz); + } + + if (sessionKey) + session->func->C_DestroyObject(session->handle, privateKey); + + return ret; +} + +/** + * Performs the ECDSA verification operation. + * + * @param session [in] Session object. + * @param info [in] Cryptographic operation data. + * @return WC_HW_E when a PKCS#11 library call fails. + * MEMORY_E when a memory allocation fails. + * 0 on success. + */ +static int Pkcs11ECDSA_Verify(Pkcs11Session* session, wc_CryptoInfo* info) +{ + int ret = 0; + CK_RV rv; + CK_MECHANISM mech; + CK_MECHANISM_INFO mechInfo; + CK_OBJECT_HANDLE publicKey = NULL_PTR; + unsigned char* sig = NULL; + word32 sz = info->pk.eccverify.key->dp->size; + + /* Check operation is supported. */ + rv = session->func->C_GetMechanismInfo(session->slotId, CKM_ECDSA, + &mechInfo); + if (rv != CKR_OK || (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"); + + ret = Pkcs11CreateEccPublicKey(&publicKey, session, + info->pk.eccverify.key, CKA_VERIFY); + } + + if (ret == 0) { + sig = XMALLOC(sz * 2, info->pk.eccverify.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); + 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); + if (rv == CKR_SIGNATURE_INVALID) { + } + else if (rv != CKR_OK) + ret = WC_HW_E; + else + *info->pk.eccverify.res = 1; + } + + if (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 + +#if !defined(NO_AES) && defined(HAVE_AESGCM) +/** + * Performs the AES-GCM encryption operation. + * + * @param session [in] Session object. + * @param info [in] Cryptographic operation data. + * @return WC_HW_E when a PKCS#11 library call fails. + * MEMORY_E when a memory allocation fails. + * 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. */ + rv = session->func->C_GetMechanismInfo(session->slotId, CKM_AES_GCM, + &mechInfo); + if (rv != CKR_OK || (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 id. */ + if (ret == 0 && aes->idLen == 0) { + ret = Pkcs11CreateSecretKey(&key, session, CKK_AES, + (unsigned char*)aes->devKey, aes->keylen, + NULL, 0); + + } + else if (ret == 0) { + 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); + 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); + 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); + if (rv != CKR_OK) + ret = WC_HW_E; + } + + if (aes->idLen == 0 && key != NULL_PTR) + session->func->C_DestroyObject(session->handle, key); + + return ret; +} + +/** + * Performs the AES-GCM decryption operation. + * + * @param session [in] Session object. + * @param info [in] Cryptographic operation data. + * @return WC_HW_E when a PKCS#11 library call fails. + * MEMORY_E when a memory allocation fails. + * 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. */ + rv = session->func->C_GetMechanismInfo(session->slotId, CKM_AES_GCM, + &mechInfo); + if (rv != CKR_OK || (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 (ret == 0 && aes->idLen == 0) { + ret = Pkcs11CreateSecretKey(&key, session, CKK_AES, + (unsigned char*)aes->devKey, aes->keylen, + NULL, 0); + } + else if (ret == 0) { + 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); + 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); + 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); + 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); + if (rv != CKR_OK) + ret = WC_HW_E; + } + + if (aes->idLen == 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 session [in] Session object. + * @param info [in] Cryptographic operation data. + * @return WC_HW_E when a PKCS#11 library call fails. + * MEMORY_E when a memory allocation fails. + * 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. */ + rv = session->func->C_GetMechanismInfo(session->slotId, CKM_AES_CBC, + &mechInfo); + if (rv != CKR_OK || (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 (ret == 0 && aes->idLen == 0) { + ret = Pkcs11CreateSecretKey(&key, session, CKK_AES, + (unsigned char*)aes->devKey, aes->keylen, + NULL, 0); + + } + else if (ret == 0) { + ret = Pkcs11FindKeyById(&key, CKO_SECRET_KEY, CKK_AES, session, aes->id, + aes->idLen); + } + + if (ret == 0) { + mech.mechanism = CKM_AES_CBC; + mech.ulParameterLen = AES_BLOCK_SIZE; + mech.pParameter = (CK_BYTE_PTR)info->cipher.aescbc.aes->reg; + + rv = session->func->C_EncryptInit(session->handle, &mech, key); + 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); + if (rv != CKR_OK) + ret = WC_HW_E; + } + + if (aes->idLen == 0 && key != NULL_PTR) + session->func->C_DestroyObject(session->handle, key); + + return ret; +} + +/** + * Performs the AES-CBC decryption operation. + * + * @param session [in] Session object. + * @param info [in] Cryptographic operation data. + * @return WC_HW_E when a PKCS#11 library call fails. + * MEMORY_E when a memory allocation fails. + * 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. */ + rv = session->func->C_GetMechanismInfo(session->slotId, CKM_AES_CBC, + &mechInfo); + if (rv != CKR_OK || (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 (ret == 0 && aes->idLen == 0) { + ret = Pkcs11CreateSecretKey(&key, session, CKK_AES, + (unsigned char*)aes->devKey, aes->keylen, + NULL, 0); + } + else if (ret == 0) { + ret = Pkcs11FindKeyById(&key, CKO_SECRET_KEY, CKK_AES, session, aes->id, + aes->idLen); + } + + if (ret == 0) { + mech.mechanism = CKM_AES_CBC; + mech.ulParameterLen = AES_BLOCK_SIZE; + mech.pParameter = (CK_BYTE_PTR)info->cipher.aescbc.aes->reg; + + rv = session->func->C_DecryptInit(session->handle, &mech, key); + if (rv != CKR_OK) + ret = WC_HW_E; + } + if (ret == 0) { + outLen = info->cipher.aescbc.sz; + rv = session->func->C_DecryptUpdate(session->handle, + (CK_BYTE_PTR)info->cipher.aescbc.in, + info->cipher.aescbc.sz, + info->cipher.aescbc.out, + &outLen); + if (rv != CKR_OK) + ret = WC_HW_E; + } + + if (aes->idLen == 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 session [in] Session object. + * @param info [in] Cryptographic operation data. + * @return WC_HW_E when a PKCS#11 library call fails. + * 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. */ + rv = session->func->C_GetMechanismInfo(session->slotId, mechType, + &mechInfo); + if (rv != CKR_OK || (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) { + ret = Pkcs11CreateSecretKey(&key, session, keyType, + (unsigned char*)hmac->keyRaw, hmac->keyLen, + NULL, 0); + if (ret == WC_HW_E) { + ret = Pkcs11CreateSecretKey(&key, session, CKK_GENERIC_SECRET, + (unsigned char*)hmac->keyRaw, hmac->keyLen, + NULL, 0); + } + + } + else if (ret == 0) { + ret = Pkcs11FindKeyById(&key, CKO_SECRET_KEY, keyType, session, + hmac->id, hmac->idLen); + if (ret == 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); + if (rv != CKR_OK) + ret = WC_HW_E; + } + + /* Don't imitialize 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); + /* 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); + /* Some algorithm implementations only support C_Sign. */ + if (rv != CKR_OK) + ret = WC_HW_E; + else + hmac->innerHashKeyed = 0; + } + + if (hmac->idLen == 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 session [in] Session object. + * @param info [in] Cryptographic operation data. + * @return WC_HW_E when a PKCS#11 library call fails. + * 0 on success. + */ +static int Pkcs11RandomBlock(Pkcs11Session* session, wc_CryptoInfo* info) +{ + int ret = 0; + CK_RV rv; + + rv = session->func->C_GenerateRandom(session->handle, info->rng.out, + info->rng.sz); + if (rv != CKR_OK) + ret = WC_HW_E; + return ret; +} +#endif + +/** + * Generates entropy (seed) data. + * + * @param session [in] Session object. + * @param info [in] Cryptographic operation data. + * @return WC_HW_E when a PKCS#11 library call fails. + * 0 on success. + */ +static int Pkcs11RandomSeed(Pkcs11Session* session, wc_CryptoInfo* info) +{ + int ret = 0; + CK_RV rv; + + rv = session->func->C_GenerateRandom(session->handle, info->seed.seed, + info->seed.sz); + if (rv != CKR_OK) + ret = WC_HW_E; + return ret; +} +#endif + +/** + * Perform a cryptographic operation using PKCS#11 device. + * + * @param devId [in] Device identifier. + * @param info [in] Cryptographic operation data. + * @param ctx [in] Context data for device - the token object. + * @return WC_HW_E when a PKCS#11 library call fails. + * 0 on success. + */ +int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) +{ + int ret = 0; + Pkcs11Token* token = (Pkcs11Token*)ctx; + Pkcs11Session session; + int readWrite = 0; + + if (devId <= INVALID_DEVID || info == NULL || ctx == NULL) + ret = BAD_FUNC_ARG; + + if (ret == 0) { + ret = Pkcs11OpenSession(token, &session, readWrite); + if (ret == 0) { + if (info->algo_type == WC_ALGO_TYPE_PK) { +#if !defined(NO_RSA) || defined(HAVE_ECC) + switch (info->pk.type) { + #ifndef NO_RSA + case WC_PK_TYPE_RSA: + ret = Pkcs11Rsa(&session, info); + break; + #ifdef WOLFSSL_KEY_GEN + case WC_PK_TYPE_RSA_KEYGEN: + ret = Pkcs11RsaKeyGen(&session, info); + break; + #endif + #endif + #ifdef HAVE_ECC + #ifndef NO_PKCS11_EC_KEYGEN + case WC_PK_TYPE_EC_KEYGEN: + ret = Pkcs11EcKeyGen(&session, info); + break; + #endif + #ifndef NO_PKCS11_ECDH + case WC_PK_TYPE_ECDH: + ret = Pkcs11ECDH(&session, info); + break; + #endif + case WC_PK_TYPE_ECDSA_SIGN: + ret = Pkcs11ECDSA_Sign(&session, info); + break; + case WC_PK_TYPE_ECDSA_VERIFY: + ret = Pkcs11ECDSA_Verify(&session, info); + break; + #endif + default: + ret = NOT_COMPILED_IN; + break; + } +#else + ret = NOT_COMPILED_IN; +#endif /* !NO_RSA || HAVE_ECC */ + } + 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 = Pkcs11AesGcmEncrypt(&session, info); + else + ret = Pkcs11AesGcmDecrypt(&session, info); + break; + #endif + #ifdef HAVE_AES_CBC + case WC_CIPHER_AES_CBC: + if (info->cipher.enc) + ret = Pkcs11AesCbcEncrypt(&session, info); + else + ret = Pkcs11AesCbcDecrypt(&session, info); + break; + #endif + } + #else + ret = NOT_COMPILED_IN; + #endif + } + else if (info->algo_type == WC_ALGO_TYPE_HMAC) { + #ifndef NO_HMAC + ret = Pkcs11Hmac(&session, info); + #else + ret = NOT_COMPILED_IN; + #endif + } + else if (info->algo_type == WC_ALGO_TYPE_RNG) { + #if !defined(WC_NO_RNG) && !defined(HAVE_HASHDRBG) + ret = Pkcs11RandomBlock(&session, info); + #else + ret = NOT_COMPILED_IN; + #endif + } + else if (info->algo_type == WC_ALGO_TYPE_SEED) { + #ifndef WC_NO_RNG + ret = Pkcs11RandomSeed(&session, info); + #else + ret = NOT_COMPILED_IN; + #endif + } + else + ret = NOT_COMPILED_IN; + + Pkcs11CloseSession(token, &session); + } + } + + return ret; +} + +#endif /* HAVE_PKCS11 */ + |