/* wc_pkcs11.c * * Copyright (C) 2006-2022 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 2 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 #endif #include #ifdef HAVE_PKCS11 #ifndef HAVE_PKCS11_STATIC #include #endif #include #include #include #include #ifndef NO_RSA #include #endif #ifdef NO_INLINE #include #else #define WOLFSSL_MISC_INCLUDED #include #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 /* Maximim length of the EC parameter string. */ #define MAX_EC_PARAM_LEN 16 #if defined(HAVE_ECC) && !defined(NO_PKCS11_ECDH) /* 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) /* 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(NO_RSA) || defined(HAVE_ECC) /* 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)) /* Pointer to secret key class required for templates. */ static CK_OBJECT_CLASS secretKeyClass = CKO_SECRET_KEY; #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) /* 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_POINTER }, { 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 }, }; /* 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 { 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; 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: 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, 5); 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; } } } /* * 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) /* Disable logging of PKCS#11 calls and value. */ #define PKCS11_VAL(op, val) /* Disable logging of PKCS#11 template. */ #define PKCS11_DUMP_TEMPLATE(name, templ, cnt) #endif /** * Load library, get function list and initialize PKCS#11. * * @param [in] dev Device object. * @param [in] library Library name including path. * @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) { int ret = 0; CK_RV rv; #ifndef HAVE_PKCS11_STATIC void* func; #endif CK_C_INITIALIZE_ARGS args; if (dev == NULL || library == NULL) ret = BAD_FUNC_ARG; if (ret == 0) { dev->heap = heap; #ifndef HAVE_PKCS11_STATIC 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) { WOLFSSL_MSG(dlerror()); ret = WC_HW_E; } } if (ret == 0) { rv = ((CK_C_GetFunctionList)func)(&dev->func); #else rv = C_GetFunctionList(&dev->func); #endif if (rv != CKR_OK) { PKCS11_RV("CK_C_GetFunctionList", ret); ret = WC_HW_E; } } if (ret == 0) { XMEMSET(&args, 0x00, sizeof(args)); args.flags = CKF_OS_LOCKING_OK; rv = dev->func->C_Initialize(&args); if (rv != CKR_OK) { PKCS11_RV("C_Initialize", ret); ret = WC_INIT_E; } } 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 #ifndef HAVE_PKCS11_STATIC && dev->dlHandle != NULL #endif ) { if (dev->func != NULL) { dev->func->C_Finalize(NULL); dev->func = NULL; } #ifndef HAVE_PKCS11_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) { CK_RV rv; CK_ULONG slotCnt = 0; CK_TOKEN_INFO tinfo; int slotId = -1; rv = dev->func->C_GetSlotList(CK_TRUE, NULL, &slotCnt); if (rv == CKR_OK) { for (slotId = 0; slotId < (int)slotCnt; slotId++) { rv = dev->func->C_GetTokenInfo(slotId, &tinfo); PKCS11_RV("C_GetTokenInfo", rv); if (rv == CKR_OK && XMEMCMP(tinfo.label, tokenName, tokenNameSz) == 0) { return slotId; } } } return -1; } /* lookup by slotId or tokenName */ static int Pkcs11Token_Init(Pkcs11Token* token, Pkcs11Dev* dev, int slotId, const char* tokenName, size_t tokenNameSz, const unsigned char* userPin, size_t userPinSz) { 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 = (CK_UTF8CHAR_PTR)userPin; token->userPinSz = (CK_ULONG)userPinSz; } if (slot != NULL) { XFREE(slot, dev->heap, DYNAMIC_TYPE_TMP_BUFFER); } 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) * @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) { size_t tokenNameSz = 0; if (tokenName != NULL) { tokenNameSz = XSTRLEN(tokenName); } return Pkcs11Token_Init(token, dev, slotId, tokenName, tokenNameSz, userPin, (size_t)userPinSz); } /** * 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(Pkcs11Token* token, Pkcs11Dev* dev, const char* tokenName, int tokenNameSz, const unsigned char* userPin, int userPinSz) { return Pkcs11Token_Init(token, dev, -1, tokenName, (size_t)tokenNameSz, userPin, (size_t)userPinSz); } /** * 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->userPin != NULL) { 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; } 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 #ifndef NO_RSA /** * 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 #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->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 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[MAX_EC_PARAM_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; } } if (ecPoint != NULL) 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[MAX_EC_PARAM_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) { keyTemplate[4].pValue = private_key->k.raw.buf; keyTemplate[4].ulValueLen = private_key->k.raw.len; 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; } } 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 [in] session Session object. * @param [in] mech Mechanism to look for. * @return NOT_COMPILED_IN when mechanism not available. * @return 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); PKCS11_RV("C_GetMechanismInfo", rv); 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 [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); 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); 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 == 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, hmac->label, hmac->labelLen, CKA_SIGN); if (ret == 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 #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, 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 = 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); 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); if (ret2 == 0) { CK_OBJECT_HANDLE pubKey = NULL_PTR; /* Store public key for validation with cert. */ ret2 = Pkcs11CreateEccPublicKey(&pubKey, &session, eccKey, CKA_VERIFY); } } /* 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 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[] = { { 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"); 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); if (exp != NULL) XFREE(exp, key->heap, DYNAMIC_TYPE_TMP_BUFFER); if (mod != NULL) XFREE(mod, key->heap, DYNAMIC_TYPE_TMP_BUFFER); 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) { ret = Pkcs11CreateRsaPrivateKey(privateKey, session, rsaKey, 0); } 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; } /** * 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_RV rv; CK_MECHANISM mech; CK_ULONG outLen; WOLFSSL_MSG("PKCS#11: RSA Public Key Operation"); if (info->pk.rsa.outLen == NULL) { ret = BAD_FUNC_ARG; } 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, 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_RV rv; CK_MECHANISM mech; CK_ULONG outLen; WOLFSSL_MSG("PKCS#11: RSA Private Key Operation"); if (info->pk.rsa.outLen == NULL) { ret = BAD_FUNC_ARG; } 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, 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; WOLFSSL_MSG("PKCS#11: RSA Private Key Operation"); if (info->pk.rsa.outLen == NULL) { ret = BAD_FUNC_ARG; } if (ret == 0) { /* Raw RSA encrypt/decrypt operation. */ mech.mechanism = CKM_RSA_X_509; 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; } } 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_RV rv; CK_MECHANISM_INFO mechInfo; int sessionKey = 0; CK_OBJECT_HANDLE key; RsaKey* rsaKey = info->pk.rsa.key; int type = info->pk.rsa.type; /* Check operation is supported. */ rv = session->func->C_GetMechanismInfo(session->slotId, CKM_RSA_X_509, &mechInfo); PKCS11_RV("C_GetMechanismInfo", rv); if (rv != CKR_OK) { ret = NOT_COMPILED_IN; } 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 (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_DECRYPT) != 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); 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_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 }, { 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) { PKCS11_DUMP_TEMPLATE("Find Ec Key", keyTemplate, attrCnt); rv = session->func->C_FindObjectsInit(session->handle, keyTemplate, attrCnt); 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; } } if (ecPoint != NULL) 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; } if (point != NULL) 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[MAX_EC_PARAM_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); 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) 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 > *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); 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->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 == 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 (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 (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 [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. */ rv = session->func->C_GetMechanismInfo(session->slotId, CKM_ECDSA, &mechInfo); PKCS11_RV("C_GetMechanismInfo", rv); 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 && info->pk.eccsign.out == 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->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) 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; 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); PKCS11_RV("C_GetMechanismInfo", rv); 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 = (unsigned char *)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); 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 (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; #ifdef WOLFSSL_SMALL_STACK RsaKey* pub = NULL; #else RsaKey pub[1]; #endif word32 keyIdx = 0; #ifdef WOLFSSL_SMALL_STACK pub = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA); if (pub == NULL) { ret = MEMORY_E; } #endif 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); } #ifdef WOLFSSL_SMALL_STACK if (pub != NULL) { XFREE(pub, NULL, DYNAMIC_TYPE_RSA); } #endif 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 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 (info->pk.rsa.key->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; } #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; #ifdef WOLFSSL_SMALL_STACK ecc_key* pub = NULL; #else ecc_key pub[1]; #endif word32 keyIdx = 0; #ifdef WOLFSSL_SMALL_STACK pub = (ecc_key*)XMALLOC(sizeof(ecc_key), NULL, DYNAMIC_TYPE_ECC); if (pub == NULL) { ret = MEMORY_E; } #endif 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); } #ifdef WOLFSSL_SMALL_STACK if (pub != NULL) { XFREE(pub, NULL, DYNAMIC_TYPE_ECC); } #endif 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; } #endif #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. */ rv = session->func->C_GetMechanismInfo(session->slotId, CKM_AES_GCM, &mechInfo); PKCS11_RV("C_GetMechanismInfo", rv); 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 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. */ rv = session->func->C_GetMechanismInfo(session->slotId, CKM_AES_GCM, &mechInfo); PKCS11_RV("C_GetMechanismInfo", rv); 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 (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. */ rv = session->func->C_GetMechanismInfo(session->slotId, CKM_AES_CBC, &mechInfo); PKCS11_RV("C_GetMechanismInfo", rv); 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 (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 = 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. */ rv = session->func->C_GetMechanismInfo(session->slotId, CKM_AES_CBC, &mechInfo); PKCS11_RV("C_GetMechanismInfo", rv); 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 (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 = 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 #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. */ rv = session->func->C_GetMechanismInfo(session->slotId, mechType, &mechInfo); PKCS11_RV("C_GetMechanismInfo", rv); 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 && hmac->labelLen == 0) { ret = Pkcs11CreateSecretKey(&key, session, keyType, (unsigned char*)hmac->keyRaw, hmac->keyLen, NULL, 0, NULL, 0, CKA_SIGN); if (ret == 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_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_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 /** * 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 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; /* 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) switch (info->pk.type) { #ifndef NO_RSA case WC_PK_TYPE_RSA: 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; #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 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 = 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 } #else ret = NOT_COMPILED_IN; #endif } else if (info->algo_type == WC_ALGO_TYPE_HMAC) { #ifndef NO_HMAC ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { ret = Pkcs11Hmac(&session, info); Pkcs11CloseSession(token, &session); } #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 ret = NOT_COMPILED_IN; } return ret; } #endif /* HAVE_PKCS11 */