diff options
Diffstat (limited to 'SoftHSMv2/src/bin')
37 files changed, 9940 insertions, 0 deletions
diff --git a/SoftHSMv2/src/bin/Makefile.am b/SoftHSMv2/src/bin/Makefile.am new file mode 100644 index 0000000..354c272 --- /dev/null +++ b/SoftHSMv2/src/bin/Makefile.am @@ -0,0 +1,10 @@ +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +SUBDIRS = common keyconv util dump + +if BUILD_MIGRATE +SUBDIRS += migrate +endif + +EXTRA_DIST = $(srcdir)/win32/*.cpp \ + $(srcdir)/win32/*.h diff --git a/SoftHSMv2/src/bin/common/Makefile.am b/SoftHSMv2/src/bin/common/Makefile.am new file mode 100644 index 0000000..e3a2b24 --- /dev/null +++ b/SoftHSMv2/src/bin/common/Makefile.am @@ -0,0 +1,3 @@ +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +EXTRA_DIST = $(srcdir)/*.h diff --git a/SoftHSMv2/src/bin/common/findslot.cpp b/SoftHSMv2/src/bin/common/findslot.cpp new file mode 100644 index 0000000..5936db7 --- /dev/null +++ b/SoftHSMv2/src/bin/common/findslot.cpp @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2016 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + findslot.cpp + + Helper function to find the slot + *****************************************************************************/ + +#include <config.h> +#include "findslot.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +extern CK_FUNCTION_LIST_PTR p11; + +// Find the slot/token +int findSlot(char* slot, char* serial, char* token, bool freeToken, CK_SLOT_ID& slotID) +{ + if (slot != NULL) + { + int slotNumber = atoi(slot); + if (slotNumber < 0) + { + fprintf(stderr, "ERROR: The slot number is negative.\n"); + return 1; + } + + slotID = slotNumber; + return 0; + } + + if (serial == NULL && token == NULL && freeToken == false) + { + fprintf(stderr, "ERROR: A slot/token must be supplied. " + "Use --slot <number>, --serial <serial>, " + "--token <label>, or --free\n"); + return 1; + } + + // Load the variables + CK_UTF8CHAR paddedSerial[16]; + CK_UTF8CHAR paddedToken[32]; + if (serial != NULL) + { + size_t inSize = strlen(serial); + size_t outSize = sizeof(paddedSerial); + if (inSize > outSize) + { + fprintf(stderr, "ERROR: --serial is too long.\n"); + return 1; + } + memset(paddedSerial, ' ', outSize); + memcpy(paddedSerial, serial, inSize); + } + if (token != NULL) + { + size_t inSize = strlen(token); + size_t outSize = sizeof(paddedToken); + if (inSize > outSize) + { + fprintf(stderr, "ERROR: --token is too long.\n"); + return 1; + } + memset(paddedToken, ' ', outSize); + memcpy(paddedToken, token, inSize); + } + + CK_ULONG ulSlotCount; + CK_RV rv = p11->C_GetSlotList(CK_TRUE, NULL_PTR, &ulSlotCount); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get the number of slots.\n"); + return 1; + } + + CK_SLOT_ID_PTR pSlotList = (CK_SLOT_ID_PTR) malloc(ulSlotCount*sizeof(CK_SLOT_ID)); + if (pSlotList == NULL) + { + fprintf(stderr, "ERROR: Could not allocate memory.\n"); + return 1; + } + + rv = p11->C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get the slot list.\n"); + free(pSlotList); + return 1; + } + + size_t counter = 0; + for (CK_ULONG i = 0; i < ulSlotCount; i++) + { + CK_TOKEN_INFO tokenInfo; + + rv = p11->C_GetTokenInfo(pSlotList[i], &tokenInfo); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get info about the token in slot %lu.\n", + pSlotList[i]); + free(pSlotList); + return 1; + } + + if (freeToken) + { + if ((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == 0) + { + printf("Slot %lu has a free/uninitialized token.\n", pSlotList[i]); + slotID = pSlotList[i]; + free(pSlotList); + return 0; + } + } + else + { + if (serial != NULL && token == NULL && + memcmp(tokenInfo.serialNumber, paddedSerial, sizeof(paddedSerial)) == 0) + { + printf("Found slot %lu with matching serial.\n", + pSlotList[i]); + slotID = pSlotList[i]; + counter++; + } + if (serial == NULL && token != NULL && + memcmp(tokenInfo.label, paddedToken, sizeof(paddedToken)) == 0) + { + printf("Found slot %lu with matching token label.\n", + pSlotList[i]); + slotID = pSlotList[i]; + counter++; + } + if (serial != NULL && token != NULL && + memcmp(tokenInfo.serialNumber, paddedSerial, sizeof(paddedSerial)) == 0 && + memcmp(tokenInfo.label, paddedToken, sizeof(paddedToken)) == 0) + { + printf("Found slot %lu with matching serial and token label.\n", + pSlotList[i]); + slotID = pSlotList[i]; + counter++; + } + } + } + + free(pSlotList); + + if (counter == 1) return 0; + if (counter > 1) + { + fprintf(stderr, "ERROR: Found multiple matching slots/tokens.\n"); + return 1; + } + + fprintf(stderr, "ERROR: Could not find a slot/token using --serial, --token, or --free.\n"); + return 1; +} + +// Find the slot/token +int findSlot(char* slot, char* serial, char* token, CK_SLOT_ID& slotID) +{ + if (slot != NULL) + { + int slotNumber = atoi(slot); + if (slotNumber < 0) + { + fprintf(stderr, "ERROR: The slot number is negative.\n"); + return 1; + } + + slotID = slotNumber; + return 0; + } + + if (serial == NULL && token == NULL) + { + fprintf(stderr, "ERROR: A slot/token must be supplied. " + "Use --slot <number>, --serial <serial>, " + "or --token <label>\n"); + return 1; + } + + // Load the variables + CK_UTF8CHAR paddedSerial[16]; + CK_UTF8CHAR paddedToken[32]; + if (serial != NULL) + { + size_t inSize = strlen(serial); + size_t outSize = sizeof(paddedSerial); + if (inSize > outSize) + { + fprintf(stderr, "ERROR: --serial is too long.\n"); + return 1; + } + memset(paddedSerial, ' ', outSize); + memcpy(paddedSerial, serial, inSize); + } + if (token != NULL) + { + size_t inSize = strlen(token); + size_t outSize = sizeof(paddedToken); + if (inSize > outSize) + { + fprintf(stderr, "ERROR: --token is too long.\n"); + return 1; + } + memset(paddedToken, ' ', outSize); + memcpy(paddedToken, token, inSize); + } + + CK_ULONG ulSlotCount; + CK_RV rv = p11->C_GetSlotList(CK_TRUE, NULL_PTR, &ulSlotCount); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get the number of slots.\n"); + return 1; + } + + CK_SLOT_ID_PTR pSlotList = (CK_SLOT_ID_PTR) malloc(ulSlotCount*sizeof(CK_SLOT_ID)); + if (pSlotList == NULL) + { + fprintf(stderr, "ERROR: Could not allocate memory.\n"); + return 1; + } + + rv = p11->C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get the slot list.\n"); + free(pSlotList); + return 1; + } + + size_t counter = 0; + for (CK_ULONG i = 0; i < ulSlotCount; i++) + { + CK_TOKEN_INFO tokenInfo; + + rv = p11->C_GetTokenInfo(pSlotList[i], &tokenInfo); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get info about the token in slot %lu.\n", + pSlotList[i]); + free(pSlotList); + return 1; + } + + if (serial != NULL && token == NULL && + memcmp(tokenInfo.serialNumber, paddedSerial, sizeof(paddedSerial)) == 0) + { + printf("Found slot %lu with matching serial.\n", + pSlotList[i]); + slotID = pSlotList[i]; + counter++; + } + if (serial == NULL && token != NULL && + memcmp(tokenInfo.label, paddedToken, sizeof(paddedToken)) == 0) + { + printf("Found slot %lu with matching token label.\n", + pSlotList[i]); + slotID = pSlotList[i]; + counter++; + } + if (serial != NULL && token != NULL && + memcmp(tokenInfo.serialNumber, paddedSerial, sizeof(paddedSerial)) == 0 && + memcmp(tokenInfo.label, paddedToken, sizeof(paddedToken)) == 0) + { + printf("Found slot %lu with matching serial and token label.\n", + pSlotList[i]); + slotID = pSlotList[i]; + counter++; + } + } + + free(pSlotList); + + if (counter == 1) return 0; + if (counter > 1) + { + fprintf(stderr, "ERROR: Found multiple matching slots/tokens.\n"); + return 1; + } + + fprintf(stderr, "ERROR: Could not find a slot/token using --serial, or --token\n"); + return 1; +} + +// Find the slot/token +int findSlot(CK_TOKEN_INFO tokenInfo, CK_SLOT_ID& slotID) +{ + CK_ULONG ulSlotCount; + CK_RV rv = p11->C_GetSlotList(CK_TRUE, NULL_PTR, &ulSlotCount); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get the number of slots.\n"); + return 1; + } + + CK_SLOT_ID_PTR pSlotList = (CK_SLOT_ID_PTR) malloc(ulSlotCount*sizeof(CK_SLOT_ID)); + if (pSlotList == NULL) + { + fprintf(stderr, "ERROR: Could not allocate memory.\n"); + return 1; + } + + rv = p11->C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get the slot list.\n"); + free(pSlotList); + return 1; + } + + size_t counter = 0; + for (CK_ULONG i = 0; i < ulSlotCount; i++) + { + CK_TOKEN_INFO currentTokenInfo; + + rv = p11->C_GetTokenInfo(pSlotList[i], ¤tTokenInfo); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get info about the token in slot %lu.\n", + pSlotList[i]); + free(pSlotList); + return 1; + } + + if (memcmp(currentTokenInfo.serialNumber, tokenInfo.serialNumber, sizeof(tokenInfo.serialNumber)) == 0 && + memcmp(currentTokenInfo.label, tokenInfo.label, sizeof(tokenInfo.label)) == 0) + { + slotID = pSlotList[i]; + counter++; + } + } + + free(pSlotList); + + if (counter == 1) return 0; + if (counter > 1) + { + fprintf(stderr, "ERROR: Found multiple matching slots/tokens.\n"); + return 1; + } + + fprintf(stderr, "ERROR: Could not find a slot/token using --serial, or --token\n"); + return 1; +} diff --git a/SoftHSMv2/src/bin/common/findslot.h b/SoftHSMv2/src/bin/common/findslot.h new file mode 100644 index 0000000..f8a7ba6 --- /dev/null +++ b/SoftHSMv2/src/bin/common/findslot.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + findslot.h + + Helper function to find the slot number + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_BIN_FINDSLOT_H +#define _SOFTHSM_V2_BIN_FINDSLOT_H + +#include "cryptoki.h" + +int findSlot(char* slot, char* serial, char* token, bool freeToken, CK_SLOT_ID& slotID); +int findSlot(char* slot, char* serial, char* token, CK_SLOT_ID& slotID); +int findSlot(CK_TOKEN_INFO tokenInfo, CK_SLOT_ID& slotID); + +#endif // !_SOFTHSM_V2_BIN_FINDSLOT_H diff --git a/SoftHSMv2/src/bin/common/getpw.cpp b/SoftHSMv2/src/bin/common/getpw.cpp new file mode 100644 index 0000000..938abd5 --- /dev/null +++ b/SoftHSMv2/src/bin/common/getpw.cpp @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + getpw.cpp + + Helper function to get a password from the user + *****************************************************************************/ + +#include <config.h> +#include "getpw.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef _WIN32 +#include <windows.h> +#else +#include <unistd.h> +#include <termios.h> +#include <signal.h> +#endif + +#ifndef _WIN32 +// Remember the signal number +static volatile sig_atomic_t signo; + +void sighandler(int s) +{ + signo = s; +} +#endif + +int getpin(const char* prompt, char* buffer, size_t size) +{ + if (prompt == NULL || buffer == NULL || size < 1) + return -1; + + printf("%s", prompt); + +#ifdef _WIN32 + HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE); + DWORD mode; + + // Save current console mode + if (!GetConsoleMode(hstdin, &mode)) + return -1; + + // Update the console mode + if (hstdin == INVALID_HANDLE_VALUE || !(SetConsoleMode(hstdin, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT))) + return -1; +#else + struct termios new_attr, old_attr; + + // Get current terminal attributes + if (tcgetattr(STDIN_FILENO, &old_attr) < 0) + return -1; + + // Save the mode flags + new_attr = old_attr; + + // Update the mode flags + new_attr.c_lflag &= ~ICANON; + new_attr.c_lflag &= ~ECHO; + + // Handle the SIGINT signal + signo = 0; + struct sigaction osa, sa; + sigaction(SIGINT, NULL, &osa); + if (osa.sa_handler != SIG_IGN) + { + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = sighandler; + sigaction(SIGINT, &sa, &osa); + } + + // Set the new terminal attributes + if (tcsetattr(STDIN_FILENO, 0, &new_attr) < 0) + return -1; +#endif + + size_t nread = 0; + int ch = 0; + while ((ch = getchar()) != '\n' && ch != EOF) + { + // Check buffer size + if ((nread+2) > size) + continue; + + putchar('*'); + buffer[nread] = ch; + nread++; + } + + putchar('\n'); + buffer[nread] = '\0'; + +#ifdef _WIN32 + // Restore the console mode + if (!SetConsoleMode(hstdin, mode)) + return -1; +#else + // Restore terminal + if (tcsetattr(STDIN_FILENO, 0, &old_attr) < 0) + return -1; + + // Restore the signal + sigaction(SIGINT, &osa, NULL); + if (signo) + raise(signo); +#endif + + return nread; +} + +// Get a password from the user +int getPW(char* pin, char* newPIN, CK_ULONG userType) +{ + char password1[MAX_PIN_LEN+1]; + char password2[MAX_PIN_LEN+1]; + size_t size = MAX_PIN_LEN+1; + int length = 0; + + // Check if the user has provided a password + if (pin) + { + length = strlen(pin); + // Save the PIN if it has the correct length + if (length >= MIN_PIN_LEN && length <= MAX_PIN_LEN) + memcpy(password1, pin, length+1); + } + + while (length < MIN_PIN_LEN || length > MAX_PIN_LEN) + { + if (userType == CKU_SO) + { + printf("=== SO PIN (%i-%i characters) ===\n", + MIN_PIN_LEN, MAX_PIN_LEN); + length = getpin("Please enter SO PIN: ", + password1, size); + } + else + { + printf("=== User PIN (%i-%i characters) ===\n", + MIN_PIN_LEN, MAX_PIN_LEN); + length = getpin("Please enter user PIN: ", + password1, size); + } + + if (length < 0) + return 1; + if (length < MIN_PIN_LEN || length > MAX_PIN_LEN) + { + fprintf(stderr, "ERROR: The length of the PIN is out of range.\n"); + length = 0; + continue; + } + + if (userType == CKU_SO) + { + length = getpin("Please reenter SO PIN: ", + password2, size); + } + else + { + length = getpin("Please reenter user PIN: ", + password2, size); + } + + if (length < 0) + return 1; + if (strcmp(password1, password2)) + { + fprintf(stderr, "ERROR: The entered PINs are not equal.\n"); + length = 0; + continue; + } + } + + memcpy(newPIN, password1, length+1); + return 0; +} diff --git a/SoftHSMv2/src/bin/common/getpw.h b/SoftHSMv2/src/bin/common/getpw.h new file mode 100644 index 0000000..1ca15a5 --- /dev/null +++ b/SoftHSMv2/src/bin/common/getpw.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + getpw.h + + Helper function to get a password from the user + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_BIN_GETPW_H +#define _SOFTHSM_V2_BIN_GETPW_H + +#include "cryptoki.h" + +int getPW(char* pin, char* newPIN, CK_ULONG userType); + +#endif // !_SOFTHSM_V2_BIN_GETPW_H diff --git a/SoftHSMv2/src/bin/common/library.cpp b/SoftHSMv2/src/bin/common/library.cpp new file mode 100644 index 0000000..af0dd93 --- /dev/null +++ b/SoftHSMv2/src/bin/common/library.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + library.cpp + + Support function for handling PKCS#11 libraries + *****************************************************************************/ + +#include <config.h> +#include "library.h" + +#include <stdio.h> +#include <stdlib.h> +#if defined(HAVE_DLOPEN) +#include <dlfcn.h> +#endif + +// Load the PKCS#11 library +CK_C_GetFunctionList loadLibrary(char* module, void** moduleHandle, + char **pErrMsg) +{ + CK_C_GetFunctionList pGetFunctionList = NULL; + +#if defined(HAVE_LOADLIBRARY) + HINSTANCE hDLL = NULL; + DWORD dw = NULL; + static char errMsg[100]; + + // Load PKCS #11 library + if (module) + { + hDLL = LoadLibraryA(module); + } + else + { + hDLL = LoadLibraryA(DEFAULT_PKCS11_LIB); + } + + if (hDLL == NULL) + { + // Failed to load the PKCS #11 library + dw = GetLastError(); + snprintf((char*)errMsg, sizeof(errMsg), "LoadLibraryA failed: 0x%08X", dw); + *pErrMsg = errMsg; + return NULL; + } + else + { + *pErrMsg = NULL; + } + + // Retrieve the entry point for C_GetFunctionList + pGetFunctionList = (CK_C_GetFunctionList) GetProcAddress(hDLL, "C_GetFunctionList"); + if (pGetFunctionList == NULL) + { + dw = GetLastError(); + snprintf((char*)errMsg, sizeof(errMsg), "getProcAddress failed: 0x%08X", dw); + *pErrMsg = errMsg; + FreeLibrary(hDLL); + return NULL; + } + + // Store the handle so we can FreeLibrary it later + *moduleHandle = hDLL; + +#elif defined(HAVE_DLOPEN) + void* pDynLib = NULL; + + // Load PKCS #11 library + if (module) + { + pDynLib = dlopen(module, RTLD_NOW | RTLD_LOCAL); + } + else + { + pDynLib = dlopen(DEFAULT_PKCS11_LIB, RTLD_NOW | RTLD_LOCAL); + } + + *pErrMsg = dlerror(); + if (pDynLib == NULL || *pErrMsg != NULL) + { + if (pDynLib != NULL) dlclose(pDynLib); + + // Failed to load the PKCS #11 library + return NULL; + } + + // Retrieve the entry point for C_GetFunctionList + pGetFunctionList = (CK_C_GetFunctionList) dlsym(pDynLib, "C_GetFunctionList"); + + // Store the handle so we can dlclose it later + *pErrMsg = dlerror(); + if (*pErrMsg != NULL) + { + dlclose(pDynLib); + + // An error occured during dlsym() + return NULL; + } + + *moduleHandle = pDynLib; +#else + fprintf(stderr, "ERROR: Not compiled with library support.\n"); + + return NULL; +#endif + + return pGetFunctionList; +} + +void unloadLibrary(void* moduleHandle) +{ + if (moduleHandle) + { +#if defined(HAVE_LOADLIBRARY) + FreeLibrary((HMODULE) moduleHandle); +#elif defined(HAVE_DLOPEN) + dlclose(moduleHandle); +#endif + } +} diff --git a/SoftHSMv2/src/bin/common/library.h b/SoftHSMv2/src/bin/common/library.h new file mode 100644 index 0000000..6c6b3e4 --- /dev/null +++ b/SoftHSMv2/src/bin/common/library.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + library.h + + Support function for handling PKCS#11 libraries + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_BIN_LIBRARY_H +#define _SOFTHSM_V2_BIN_LIBRARY_H + +#include "cryptoki.h" + +CK_C_GetFunctionList loadLibrary(char* module, void** moduleHandle, + char **pErrMsg); +void unloadLibrary(void* moduleHandle); + +#endif // !_SOFTHSM_V2_BIN_LIBRARY_H diff --git a/SoftHSMv2/src/bin/dump/Makefile.am b/SoftHSMv2/src/bin/dump/Makefile.am new file mode 100644 index 0000000..c70d6f6 --- /dev/null +++ b/SoftHSMv2/src/bin/dump/Makefile.am @@ -0,0 +1,24 @@ +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +AM_CPPFLAGS = -I$(srcdir)/../../lib \ + -I$(srcdir)/../../lib/object_store \ + -I$(srcdir)/../../lib/pkcs11 \ + @SQLITE3_INCLUDES@ + +dist_man_MANS = softhsm2-dump-file.1 + +bin_PROGRAMS = softhsm2-dump-file + +if BUILD_OBJECTSTORE_BACKEND_DB +dist_man_MANS += softhsm2-dump-db.1 +bin_PROGRAMS += softhsm2-dump-db +endif + +softhsm2_dump_file_SOURCES = softhsm2-dump-file.cpp + +softhsm2_dump_db_SOURCES = softhsm2-dump-db.cpp + +softhsm2_dump_db_LDADD = @SQLITE3_LIBS@ @YIELD_LIB@ + +EXTRA_DIST = $(srcdir)/*.h \ + softhsm2-dump-db.1 diff --git a/SoftHSMv2/src/bin/dump/common.h b/SoftHSMv2/src/bin/dump/common.h new file mode 100644 index 0000000..d38b924 --- /dev/null +++ b/SoftHSMv2/src/bin/dump/common.h @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2013 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + common.h + + Common definitions for SoftHSMv2 dump. + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_COMMON_H +#define _SOFTHSM_V2_COMMON_H + +#include <config.h> + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <map> +#include <set> +#include <string> +#include <stdexcept> +#include <vector> +#include "tables.h" + +// Table of attribute types +std::map<unsigned long, std::string> CKA_table; + +// Dump an attribute type +void dumpCKA(unsigned long cka, int size) +{ + // Lazy fill + if (CKA_table.empty()) + { + fill_CKA_table(CKA_table); + } + std::string msg; + try + { + msg = CKA_table.at(cka); + printf("%.*s", size, msg.c_str()); + } + catch (const std::out_of_range&) + { + if (cka & CKA_VENDOR_DEFINED) + { + cka &= ~CKA_VENDOR_DEFINED; + printf("CKA_VENDOR_DEFINED | 0x%lx", cka); + } + else + { + printf("unknown 0x%lx", cka); + } + } +} + +// Table of mechanism types +std::map<unsigned long, std::string> CKM_table; + +// Dump a mechanism type +void dumpCKM(unsigned long cka, int size) +{ + // Lazy fill + if (CKM_table.empty()) + { + fill_CKM_table(CKM_table); + } + std::string msg; + try + { + msg = CKM_table.at(cka); + printf("%.*s", size, msg.c_str()); + } + catch (const std::out_of_range&) + { + if (cka & CKM_VENDOR_DEFINED) + { + cka &= ~CKM_VENDOR_DEFINED; + printf("CKM_VENDOR_DEFINED | 0x%lx", cka); + } + else + { + printf("unknown 0x%lx", cka); + } + } +} + +// Table of object classes +std::map<unsigned long, std::string> CKO_table; + +// Dump a object class +void dumpCKO(unsigned long cka, int size) +{ + // Lazy fill + if (CKO_table.empty()) + { + fill_CKO_table(CKO_table); + } + std::string msg; + try + { + msg = CKO_table.at(cka); + printf("%.*s", size, msg.c_str()); + } + catch (const std::out_of_range&) + { + if (cka & CKO_VENDOR_DEFINED) + { + cka &= ~CKO_VENDOR_DEFINED; + printf("CKO_VENDOR_DEFINED | 0x%lx", cka); + } + else + { + printf("unknown 0x%lx", cka); + } + } +} + +// Table of hw feature types +std::map<unsigned long, std::string> CKH_table; + +// Dump a hw feature type +void dumpCKH(unsigned long cka, int size) +{ + // Lazy fill + if (CKH_table.empty()) + { + fill_CKH_table(CKH_table); + } + std::string msg; + try + { + msg = CKH_table.at(cka); + printf("%.*s", size, msg.c_str()); + } + catch (const std::out_of_range&) + { + if (cka & CKH_VENDOR_DEFINED) + { + cka &= ~CKH_VENDOR_DEFINED; + printf("CKH_VENDOR_DEFINED | 0x%lx", cka); + } + else + { + printf("unknown 0x%lx", cka); + } + } +} + +// Table of key types +std::map<unsigned long, std::string> CKK_table; + +// Dump a key type +void dumpCKK(unsigned long cka, int size) +{ + // Lazy fill + if (CKK_table.empty()) + { + fill_CKK_table(CKK_table); + } + std::string msg; + try + { + msg = CKK_table.at(cka); + printf("%.*s", size, msg.c_str()); + } + catch (const std::out_of_range&) + { + if (cka & CKK_VENDOR_DEFINED) + { + cka &= ~CKK_VENDOR_DEFINED; + printf("CKK_VENDOR_DEFINED | 0x%lx", cka); + } + else + { + printf("unknown 0x%lx", cka); + } + } +} + +// Table of certificate types +std::map<unsigned long, std::string> CKC_table; + +// Dump a certificate type +void dumpCKC(unsigned long cka, int size) +{ + // Lazy fill + if (CKC_table.empty()) + { + fill_CKC_table(CKC_table); + } + std::string msg; + try + { + msg = CKC_table.at(cka); + printf("%.*s", size, msg.c_str()); + } + catch (const std::out_of_range&) + { + if (cka & CKC_VENDOR_DEFINED) + { + cka &= ~CKC_VENDOR_DEFINED; + printf("CKC_VENDOR_DEFINED | 0x%lx", cka); + } + else + { + printf("unknown 0x%lx", cka); + } + } +} + +// Dump a PKCS#11 integer type +void dumpCKx(uint64_t cka, uint64_t value, int size) +{ + if ((uint32_t)value == (uint32_t)~0) + { + printf("CK_UNAVAILABLE_INFORMATION"); + return; + } + + switch ((unsigned long) cka) + { + case CKA_CLASS: + if ((uint64_t)((uint32_t)value) != value) + { + printf("overflow object class"); + break; + } + dumpCKO((unsigned long) value, size); + break; + case CKA_CERTIFICATE_TYPE: + if ((uint64_t)((uint32_t)value) != value) + { + printf("overflow certificate type"); + break; + } + dumpCKC((unsigned long) value, size); + break; + case CKA_KEY_TYPE: + if ((uint64_t)((uint32_t)value) != value) + { + printf("overflow key type"); + break; + } + dumpCKK((unsigned long) value, size); + break; + case CKA_KEY_GEN_MECHANISM: + if ((uint64_t)((uint32_t)value) != value) + { + printf("overflow mechanism type"); + break; + } + dumpCKM((unsigned long) value, size); + break; + case CKA_HW_FEATURE_TYPE: + if ((uint64_t)((uint32_t)value) != value) + { + printf("overflow hw feature type"); + break; + } + dumpCKH((unsigned long) value, size); + break; + default: + printf("CK_ULONG %lu(0x%lx)", + (unsigned long) value, + (unsigned long) value); + break; + } +} + +// Dump a boolean (in fact unsigned 8 bit long) value, true is 0xff +void dumpBool(uint8_t value, bool inArray = false) +{ + printf("%02hhx %s", value, inArray ? " " : ""); + switch (value) + { + case 0: + printf("FALSE"); + break; + case 0xff: + printf("TRUE"); + break; + default: + printf("(invalid) TRUE"); + break; + } +} + +// Dump a boolean (in fact unsigned 8 bit long) value, true is 1 +void dumpBool1(uint8_t value, bool inArray = false) +{ + printf("%02hhx %s", value, inArray ? " " : ""); + switch (value) + { + case 0: + printf("FALSE"); + break; + case 1: + printf("TRUE"); + break; + default: + printf("(invalid) TRUE"); + break; + } +} + +// Dump an unsigned 64 bit long value +void dumpULong(uint64_t value, bool inArray = false) +{ + for (int i = 56; i >= 0; i -= 8) + { + uint8_t v; + v = (value >> i) & 0xff; + printf("%02hhx ", v); + } + if (inArray) + { + printf(" "); + } +} + +// Dump an unsigned 32 bit long value +void dumpU32(uint32_t value, bool inArray = false) +{ + for (int i = 24; i >= 0; i -= 8) + { + uint8_t v; + v = (value >> i) & 0xff; + printf("%02hhx ", v); + } + printf(" "); + if (inArray) + { + printf(" "); + } +} + +// Dump a byte string (aka uint8_t vector) value +void dumpBytes(const std::vector<uint8_t>& value, bool inArray = false) +{ + size_t len = value.size(); + size_t i = 0; + while (i + 8 <= len) + { + for (size_t j = 0; j < 8; j++) + { + printf("%02hhx ", value[i + j]); + } + if (inArray) + { + printf(" "); + } + printf("<"); + for (size_t j = 0; j < 8; j++) + { + uint8_t c = value[i + j]; + if (isgraph((int) c) == 0) + { + printf("."); + } + else + { + printf("%c", (int) c); + } + } + printf(">\n"); + i += 8; + } + len -= i; + if (len == 0) + { + return; + } + + for (size_t j = 0; j < len; j++) + { + printf("%02hhx ", value[i + j]); + } + for (size_t j = len; j < 8; j++) + { + printf(" "); + } + if (inArray) + { + printf(" "); + } + printf("<"); + for (size_t j = 0; j < len; j++) + { + uint8_t c = value[i + j]; + if (isgraph((int) c) == 0) + { + printf("."); + } + else + { + printf("%c", (int) c); + } + } + for (size_t j =len; j < 8; j++) + { + printf(" "); + } + printf(">\n"); +} + +// Attribute (in an array) template +template<typename T, typename K, typename I> +class AttributeTK +{ +public: + T type; + K kind; + + uint8_t boolValue; + I ulongValue; + std::vector<uint8_t> bytestrValue; + std::set<I> mechSetValue; + + // Dump an array (in fact an Attribute vector) value + void dumpType() const; + void dumpKind() const; + void dumpBoolValue() const; + void dumpULongValue(I value) const; + bool isBoolean() const; + bool isInteger() const; + bool isBinary() const; + bool isMechSet() const; + void dump() const { + dumpType(); + if ((sizeof(type) > 4) && + ((uint64_t)((uint32_t)type) != type)) + { + printf("overflow attribute type\n"); + } + else + { + dumpCKA((unsigned long) type, 47); + printf("\n"); + } + + dumpKind(); + if (isBoolean()) + { + printf("boolean attribute\n"); + dumpBoolValue(); + printf("\n"); + } + else if (isInteger()) + { + printf("unsigned long attribute\n"); + dumpULongValue(ulongValue); + dumpCKx(type, ulongValue, 47); + printf("\n"); + } + else if (isBinary()) + { + printf("byte string attribute\n"); + I size = bytestrValue.size(); + dumpULongValue(size); + printf("(length %lu)\n", (unsigned long) size); + dumpBytes(bytestrValue, true); + } + else if (isMechSet()) + { + printf("mechanism set attribute\n"); + I size = mechSetValue.size(); + dumpULongValue(size); + printf("(length %lu)\n", (unsigned long) size); + for (typename std::set<I>::const_iterator i = mechSetValue.begin(); i != mechSetValue.end(); ++i) + { + dumpULongValue(*i); + dumpCKM(*i, 47); + printf("\n"); + } + } + else + { + printf("unknown attribute format\n"); + } + } +}; + +#endif // !_SOFTHSM_V2_COMMON_H diff --git a/SoftHSMv2/src/bin/dump/softhsm2-dump-db.1 b/SoftHSMv2/src/bin/dump/softhsm2-dump-db.1 new file mode 100644 index 0000000..00f455b --- /dev/null +++ b/SoftHSMv2/src/bin/dump/softhsm2-dump-db.1 @@ -0,0 +1,18 @@ +.TH SOFTHSM2-DUMP-DB 1 "20 March 2014" "SoftHSM" +.SH NAME +softhsm2-dump-db \- SoftHSM database dump +.SH SYNOPSIS +.PP +.B softhsm2-dump-db +.I path +.SH DESCRIPTION +.B softhsm2-dump +is a tool that can dump SoftHSM v2 database for debugging purposes. +.LP +.SH OPTIONS +.TP +.B \fIpath\fR +The SoftHSM v2 database file that is going to be dumped. +.TP +.B \-\-help\fR, \fB\-h\fR +Show the help information. diff --git a/SoftHSMv2/src/bin/dump/softhsm2-dump-db.cpp b/SoftHSMv2/src/bin/dump/softhsm2-dump-db.cpp new file mode 100644 index 0000000..f55a9db --- /dev/null +++ b/SoftHSMv2/src/bin/dump/softhsm2-dump-db.cpp @@ -0,0 +1,968 @@ +/* + * Copyright (c) 2013 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + softhsm2-dump-db.cpp + + This program can be used for dumping SoftHSM v2 database. + *****************************************************************************/ + +#include <config.h> + +#include <sched.h> +#include <sqlite3.h> +#include <string.h> + +#include "common.h" + +// Attribute types in database arrays +enum AttributeKind +{ + akUnknown, + akBoolean, + akInteger, + akBinary, + akArray +}; + +// Attribute specialization +typedef AttributeTK<CK_ATTRIBUTE_TYPE, AttributeKind, unsigned long> Attribute; + +template<> +bool Attribute::isBoolean() const +{ + return kind == akBoolean; +} + +template<> +bool Attribute::isInteger() const +{ + return kind == akInteger; +} + +template<> +bool Attribute::isBinary() const +{ + return kind == akBinary; +} + +template<> +bool Attribute::isMechSet() const +{ + // Mechanism sets are stored as binary in the database + return false; +} + +template<> +void Attribute::dumpType() const +{ + if (sizeof(type) == 4) + { + dumpU32((uint32_t)type, true); + } + else + { + dumpULong(type, true); + } +} + +template<> +void Attribute::dumpKind() const +{ + dumpU32((uint32_t) kind, true); +} + +template<> +void Attribute::dumpBoolValue() const +{ + dumpBool1(boolValue, true); +} + +template<> +void Attribute::dumpULongValue(unsigned long value) const +{ + if (sizeof(unsigned long) == 4) + { + dumpU32(value, true); + } + else + { + dumpULong(value, true); + } +} + +// dumpArray specialization +typedef std::vector<Attribute> va_type; + +void dumpArray(const va_type& value) +{ + for (va_type::const_iterator attr = value.begin(); attr != value.end(); ++attr) + attr->dump(); +} + +// Get a boolean (in fact unsigned 8 bit long) value +bool getBool(sqlite3* db, long long oid, long long id, uint64_t& type, uint8_t& value) +{ + int rv; + sqlite3_stmt* sql = NULL; + std::string command = "select type,value from attribute_boolean where object_id=? and id=?;"; + + value = 0; + + rv = sqlite3_prepare_v2(db, command.c_str(), -1, &sql, NULL); + if (rv != SQLITE_OK) + { + fprintf(stderr, + "can't find boolean attribute id=%lld object=%lld: %d(%s)\n", + id, oid, rv, sqlite3_errmsg(db)); + sqlite3_finalize(sql); + return false; + } + rv = sqlite3_bind_int64(sql, 1, oid); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't bind the object id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sql); + return false; + } + sqlite3_bind_int64(sql, 2, id); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't bind the attribute id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sql); + return false; + } + while ((rv = sqlite3_step(sql)) == SQLITE_BUSY) + { + sched_yield(); + } + if (rv != SQLITE_ROW) + { + fprintf(stderr, + "can't read boolean attribute id=%lld object=%lld: %d(%s)\n", + id, oid, rv, sqlite3_errmsg(db)); + sqlite3_finalize(sql); + return false; + } + type = sqlite3_column_int64(sql, 0); + value = sqlite3_column_int(sql, 1); + sqlite3_finalize(sql); + + return true; +} + +// Get an unsigned 64 bit long value +bool getULong(sqlite3* db, long long oid, long long id, uint64_t& type, uint64_t& value) +{ + int rv; + sqlite3_stmt* sql = NULL; + std::string command = "select type,value from attribute_integer where object_id=? and id=?;"; + + value = 0ULL; + + rv = sqlite3_prepare_v2(db, command.c_str(), -1, &sql, NULL); + if (rv != SQLITE_OK) + { + fprintf(stderr, + "can't find integer attribute id=%lld object=%lld: %d(%s)\n", + id, oid, rv, sqlite3_errmsg(db)); + sqlite3_finalize(sql); + return false; + } + rv = sqlite3_bind_int64(sql, 1, oid); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't bind the object id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sql); + return false; + } + sqlite3_bind_int64(sql, 2, id); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't bind the attribute id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sql); + return false; + } + while ((rv = sqlite3_step(sql)) == SQLITE_BUSY) + { + sched_yield(); + } + if (rv != SQLITE_ROW) + { + fprintf(stderr, + "can't read integer attribute id=%lld object=%lld: %d(%s)\n", + id, oid, rv, sqlite3_errmsg(db)); + sqlite3_finalize(sql); + return false; + } + type = sqlite3_column_int64(sql, 0); + value = sqlite3_column_int64(sql, 1); + sqlite3_finalize(sql); + + return true; +} + +// Get a byte string (aka uint8_t vector) value +bool getBytes(sqlite3* db, long long oid, long long id, uint64_t& type, std::vector<uint8_t>& value) +{ + int rv; + sqlite3_stmt* sql = NULL; + std::string command = "select type,value from attribute_binary where object_id=? and id=?;"; + size_t len; + const uint8_t* val; + + value.clear(); + + rv = sqlite3_prepare_v2(db, command.c_str(), -1, &sql, NULL); + if (rv != SQLITE_OK) + { + fprintf(stderr, + "can't find binary attribute id=%lld object=%lld: %d(%s)\n", + id, oid, rv, sqlite3_errmsg(db)); + sqlite3_finalize(sql); + return false; + } + rv = sqlite3_bind_int64(sql, 1, oid); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't bind the object id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sql); + return false; + } + sqlite3_bind_int64(sql, 2, id); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't bind the attribute id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sql); + return false; + } + while ((rv = sqlite3_step(sql)) == SQLITE_BUSY) + { + sched_yield(); + } + if (rv != SQLITE_ROW) + { + fprintf(stderr, + "can't read binary attribute id=%lld object=%lld: %d(%s)\n", + id, oid, rv, sqlite3_errmsg(db)); + sqlite3_finalize(sql); + return false; + } + type = sqlite3_column_int64(sql, 0); + len = sqlite3_column_bytes(sql, 1); + val = (const uint8_t*) sqlite3_column_blob(sql, 1); + for (size_t i = 0; i < len; ++i) + { + value.push_back(val[i]); + } + sqlite3_finalize(sql); + + return true; +} + +// Get an array (aka Attribute vector) value +bool getArray(sqlite3* db, long long oid, long long id, uint64_t& type, std::vector<Attribute>& value) +{ + int rv; + sqlite3_stmt* sql = NULL; + std::string command = "select type,value from attribute_array where object_id=? and id=?;"; + size_t len; + const uint8_t* val; + + value.clear(); + + rv = sqlite3_prepare_v2(db, command.c_str(), -1, &sql, NULL); + if (rv != SQLITE_OK) + { + fprintf(stderr, + "can't find array attribute id=%lld object=%lld: %d(%s)\n", + id, oid, rv, sqlite3_errmsg(db)); + sqlite3_finalize(sql); + return false; + } + rv = sqlite3_bind_int64(sql, 1, oid); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't bind the object id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sql); + return false; + } + sqlite3_bind_int64(sql, 2, id); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't bind the attribute id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sql); + return false; + } + while ((rv = sqlite3_step(sql)) == SQLITE_BUSY) + { + sched_yield(); + } + if (rv != SQLITE_ROW) + { + fprintf(stderr, + "can't read array attribute id=%lld object=%lld: %d(%s)\n", + id, oid, rv, sqlite3_errmsg(db)); + sqlite3_finalize(sql); + return false; + } + type = sqlite3_column_int64(sql, 0); + len = sqlite3_column_bytes(sql, 1); + val = (const uint8_t*) sqlite3_column_blob(sql, 1); + +// CK_ATTRIBUTE_TYPE type, AttributeKind kind +// bool -> int, integer -> unsigned long, binary -> unsigned long + vector + + for (size_t pos = 0; pos < len; ) + { + // finished? + if (pos == len) break; + + Attribute attr; + + if (pos + sizeof(attr.type) > len) + { + fprintf(stderr, "overflow array item type\n"); + sqlite3_finalize(sql); + return false; + } + memcpy(&attr.type, val + pos, sizeof(attr.type)); + pos += sizeof(attr.type); + + if (pos + sizeof(attr.kind) > len) + { + fprintf(stderr, "overflow array item kind\n"); + sqlite3_finalize(sql); + return false; + } + memcpy(&attr.kind, val + pos, sizeof(attr.kind)); + pos += sizeof(attr.kind); + + if (attr.kind == akBoolean) + { + if (pos + sizeof(attr.boolValue) > len) + { + fprintf(stderr, "overflow array boolean item\n"); + sqlite3_finalize(sql); + return false; + } + memcpy(&attr.boolValue, val + pos, sizeof(attr.boolValue)); + pos += sizeof(attr.boolValue); + } + else if (attr.kind == akInteger) + { + if (pos + sizeof(attr.ulongValue) > len) + { + fprintf(stderr, "overflow array integer item\n"); + sqlite3_finalize(sql); + return false; + } + memcpy(&attr.ulongValue, val + pos, sizeof(attr.ulongValue)); + pos += sizeof(attr.ulongValue); + } + else if (attr.kind == akBinary) + { + unsigned long size; + if (pos + sizeof(size) > len) + { + fprintf(stderr, "overflow array binary item\n"); + sqlite3_finalize(sql); + return false; + } + memcpy(&size, val + pos, sizeof(size)); + pos += sizeof(size); + + if (pos + size > len) + { + fprintf(stderr, "overflow array binary item\n"); + sqlite3_finalize(sql); + return false; + } + attr.bytestrValue.resize(size); + for (unsigned long i = 0; i < size; ++i) + { + attr.bytestrValue[i] = val[pos + i]; + } + pos += size; + } + else + { + fprintf(stderr, "unknown array item\n"); + sqlite3_finalize(sql); + return false; + } + + value.push_back(attr); + } + sqlite3_finalize(sql); + + return true; +} + +// Dump boolean attributes of an object +void dump_booleans(sqlite3* db, long long oid) +{ + int rv; + unsigned long count; + sqlite3_stmt* sqlcnt = NULL; + sqlite3_stmt* sqlid = NULL; + std::string commandcnt = "select count(id) from attribute_boolean where object_id=?;"; + std::string commandid = "select id from attribute_boolean where object_id=?;"; + rv = sqlite3_prepare_v2(db, commandcnt.c_str(), -1, &sqlcnt, NULL); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't count the object table: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlcnt); + return; + } + rv = sqlite3_bind_int64(sqlcnt, 1, oid); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't bind the object id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlcnt); + return; + } + while ((rv = sqlite3_step(sqlcnt)) == SQLITE_BUSY) + { + sched_yield(); + } + if (rv != SQLITE_ROW) + { + fprintf(stderr, "can't count the object table: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlcnt); + return; + } + count = sqlite3_column_int(sqlcnt, 0); + sqlite3_finalize(sqlcnt); + if (count == 0) + return; + + printf("%lu boolean attributes for object %lld\n", count, oid); + + rv = sqlite3_prepare_v2(db, commandid.c_str(), -1, &sqlid, NULL); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't count the object table: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlid); + return; + } + rv = sqlite3_bind_int64(sqlid, 1, oid); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't bind the object id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlid); + return; + } + while (count-- > 0) { + while ((rv = sqlite3_step(sqlid)) == SQLITE_BUSY) + { + sched_yield(); + } + if (rv != SQLITE_ROW) + { + if (rv != SQLITE_DONE) + { + fprintf(stderr, + "can't get next object id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + } + sqlite3_finalize(sqlid); + return; + } + long long id = sqlite3_column_int64(sqlid, 0); + + uint64_t type; + uint8_t value; + if (!getBool(db, oid, id, type, value)) + { + return; + } + dumpULong(type); + if ((uint64_t)((uint32_t)type) != type) + { + printf("overflow attribute type\n"); + } + else + { + dumpCKA((unsigned long) type, 48); + printf("\n"); + } + + dumpBool1(value); + printf("\n"); + } +} + +// Dump integer attributes of an object +void dump_integers(sqlite3* db, long long oid) +{ + int rv; + unsigned long count; + sqlite3_stmt* sqlcnt = NULL; + sqlite3_stmt* sqlid = NULL; + std::string commandcnt = "select count(id) from attribute_integer where object_id=?;"; + std::string commandid = "select id from attribute_integer where object_id=?;"; + rv = sqlite3_prepare_v2(db, commandcnt.c_str(), -1, &sqlcnt, NULL); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't count the object table: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlcnt); + return; + } + rv = sqlite3_bind_int64(sqlcnt, 1, oid); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't bind the object id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlcnt); + return; + } + while ((rv = sqlite3_step(sqlcnt)) == SQLITE_BUSY) + { + sched_yield(); + } + if (rv != SQLITE_ROW) + { + fprintf(stderr, "can't count the object table: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlcnt); + return; + } + count = sqlite3_column_int(sqlcnt, 0); + sqlite3_finalize(sqlcnt); + if (count == 0) + return; + + printf("%lu integer attributes for object %lld\n", count, oid); + + rv = sqlite3_prepare_v2(db, commandid.c_str(), -1, &sqlid, NULL); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't count the object table: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlid); + return; + } + rv = sqlite3_bind_int64(sqlid, 1, oid); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't bind the object id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlid); + return; + } + while (count-- > 0) { + while ((rv = sqlite3_step(sqlid)) == SQLITE_BUSY) + { + sched_yield(); + } + if (rv != SQLITE_ROW) + { + if (rv != SQLITE_DONE) + { + fprintf(stderr, + "can't get next object id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + } + sqlite3_finalize(sqlid); + return; + } + long long id = sqlite3_column_int64(sqlid, 0); + + uint64_t type; + uint64_t value; + if (!getULong(db, oid, id, type, value)) + { + return; + } + dumpULong(type); + if ((uint64_t)((uint32_t)type) != type) + { + printf("overflow attribute type\n"); + } + else + { + dumpCKA((unsigned long) type, 48); + printf("\n"); + } + dumpULong(value); + dumpCKx(type, value, 48); + printf("\n"); + } +} + +// Dump binary attributes of an object +void dump_binaries(sqlite3* db, long long oid) +{ + int rv; + unsigned long count; + sqlite3_stmt* sqlcnt = NULL; + sqlite3_stmt* sqlid = NULL; + std::string commandcnt = "select count(id) from attribute_binary where object_id=?;"; + std::string commandid = "select id from attribute_binary where object_id=?;"; + rv = sqlite3_prepare_v2(db, commandcnt.c_str(), -1, &sqlcnt, NULL); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't count the object table: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlcnt); + return; + } + rv = sqlite3_bind_int64(sqlcnt, 1, oid); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't bind the object id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlcnt); + return; + } + while ((rv = sqlite3_step(sqlcnt)) == SQLITE_BUSY) + { + sched_yield(); + } + if (rv != SQLITE_ROW) + { + fprintf(stderr, "can't count the object table: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlcnt); + return; + } + count = sqlite3_column_int(sqlcnt, 0); + sqlite3_finalize(sqlcnt); + if (count == 0) + return; + + printf("%lu binary attributes for object %lld\n", count, oid); + + rv = sqlite3_prepare_v2(db, commandid.c_str(), -1, &sqlid, NULL); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't count the object table: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlid); + return; + } + rv = sqlite3_bind_int64(sqlid, 1, oid); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't bind the object id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlid); + return; + } + while (count-- > 0) { + while ((rv = sqlite3_step(sqlid)) == SQLITE_BUSY) + { + sched_yield(); + } + if (rv != SQLITE_ROW) + { + if (rv != SQLITE_DONE) + { + fprintf(stderr, + "can't get next object id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + } + sqlite3_finalize(sqlid); + return; + } + long long id = sqlite3_column_int64(sqlid, 0); + + uint64_t type; + std::vector<uint8_t> value; + if (!getBytes(db, oid, id, type, value)) + { + return; + } + dumpULong(type); + if ((uint64_t)((uint32_t)type) != type) + { + printf("overflow attribute type\n"); + } + else + { + dumpCKA((unsigned long) type, 48); + printf("\n"); + } + dumpULong((uint64_t) value.size()); + printf("(length %lu)\n", (unsigned long) value.size()); + dumpBytes(value); + } +} + +// Dump array attributes of an object +void dump_arrays(sqlite3* db, long long oid) +{ + int rv; + unsigned long count; + sqlite3_stmt* sqlcnt = NULL; + sqlite3_stmt* sqlid = NULL; + std::string commandcnt = "select count(id) from attribute_array where object_id=?;"; + std::string commandid = "select id from attribute_array where object_id=?;"; + rv = sqlite3_prepare_v2(db, commandcnt.c_str(), -1, &sqlcnt, NULL); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't count the object table: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlcnt); + return; + } + rv = sqlite3_bind_int64(sqlcnt, 1, oid); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't bind the object id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlcnt); + return; + } + while ((rv = sqlite3_step(sqlcnt)) == SQLITE_BUSY) + { + sched_yield(); + } + if (rv != SQLITE_ROW) + { + fprintf(stderr, "can't count the object table: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlcnt); + return; + } + count = sqlite3_column_int(sqlcnt, 0); + sqlite3_finalize(sqlcnt); + if (count == 0) + return; + + printf("%lu array attributes for object %lld\n", count, oid); + + rv = sqlite3_prepare_v2(db, commandid.c_str(), -1, &sqlid, NULL); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't count the object table: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlid); + return; + } + rv = sqlite3_bind_int64(sqlid, 1, oid); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't bind the object id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlid); + return; + } + while (count-- > 0) { + while ((rv = sqlite3_step(sqlid)) == SQLITE_BUSY) + { + sched_yield(); + } + if (rv != SQLITE_ROW) + { + if (rv != SQLITE_DONE) + { + fprintf(stderr, + "can't get next object id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + } + sqlite3_finalize(sqlid); + return; + } + long long id = sqlite3_column_int64(sqlid, 0); + + uint64_t type; + std::vector<Attribute> value; + if (!getArray(db, oid, id, type, value)) + { + return; + } + dumpULong(type); + if ((uint64_t)((uint32_t)type) != type) + { + printf("overflow attribute type\n"); + } + else + { + dumpCKA((unsigned long) type, 48); + printf("\n"); + } + dumpULong((uint64_t) value.size()); + printf("(length %lu)\n", (unsigned long) value.size()); + dumpArray(value); + } +} + +// Dump an object +void dump_object(sqlite3* db, long long oid) +{ + printf("dump object id=%lld\n", oid); + dump_booleans(db, oid); + dump_integers(db, oid); + dump_binaries(db, oid); + dump_arrays(db, oid); +} + +// Core function +void dump(sqlite3* db) +{ + int rv; + unsigned long count; + sqlite3_stmt* sqlcnt = NULL; + sqlite3_stmt* sqlid = NULL; + std::string commandcnt = "select count(id) from object;"; + std::string commandid = "select id from object;"; + + rv = sqlite3_prepare_v2(db, commandcnt.c_str(), -1, &sqlcnt, NULL); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't count the object table: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlcnt); + return; + } + while ((rv = sqlite3_step(sqlcnt)) == SQLITE_BUSY) + { + sched_yield(); + } + if (rv != SQLITE_ROW) + { + fprintf(stderr, "can't count the object table: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlcnt); + return; + } + count = sqlite3_column_int(sqlcnt, 0); + sqlite3_finalize(sqlcnt); + printf("%lu objects\n", count); + + rv = sqlite3_prepare_v2(db, commandid.c_str(), -1, &sqlid, NULL); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't count the object table: %d(%s)\n", + rv, sqlite3_errmsg(db)); + sqlite3_finalize(sqlid); + return; + } + while (count-- > 0) { + while ((rv = sqlite3_step(sqlid)) == SQLITE_BUSY) + { + sched_yield(); + } + if (rv != SQLITE_ROW) + { + if (rv != SQLITE_DONE) + { + fprintf(stderr, + "can't get next object id: %d(%s)\n", + rv, sqlite3_errmsg(db)); + } + sqlite3_finalize(sqlid); + return; + } + long long oid = sqlite3_column_int64(sqlid, 0); + dump_object(db, oid); + } +} + +// Display the usage +void usage() +{ + printf("SoftHSM dump tool. From SoftHSM v2 database.\n"); + printf("Usage: softhsm2-dump-db path\n"); +} + +// Check the existence of a table +void check_table_exist(sqlite3* db, std::string name) +{ + int rv; + std::string command = "select count(id) from " + name + ";"; + + rv = sqlite3_exec(db, command.c_str(), NULL, NULL, NULL); + if (rv != SQLITE_OK) + { + fprintf(stderr, "can't find '%s' table\n", name.c_str()); + sqlite3_close(db); + exit(0); + } +} + +// The main function +int main(int argc, char* argv[]) +{ + int rv; + sqlite3* db = NULL; + + if (argc != 2) + { + usage(); + exit(0); + } + + rv = sqlite3_open_v2(argv[1], &db, SQLITE_OPEN_READONLY, NULL); + if (rv != SQLITE_OK) + { + if (db == NULL) + { + fprintf(stderr, + "can't open database file %s\n", + argv[1]); + } + else + { + fprintf(stderr, + "can't open database file %s: %d(%s)\n", + argv[1], + rv, + sqlite3_errmsg(db)); + } + sqlite3_close(db); + exit(0); + } + + // No user version to check + + check_table_exist(db, "object"); + check_table_exist(db, "attribute_boolean"); + check_table_exist(db, "attribute_integer"); + check_table_exist(db, "attribute_binary"); + check_table_exist(db, "attribute_array"); + + printf("Dump of object file \"%s\"\n", argv[1]); + dump(db); + sqlite3_close(db); + exit(1); +} diff --git a/SoftHSMv2/src/bin/dump/softhsm2-dump-file.1 b/SoftHSMv2/src/bin/dump/softhsm2-dump-file.1 new file mode 100644 index 0000000..5167f70 --- /dev/null +++ b/SoftHSMv2/src/bin/dump/softhsm2-dump-file.1 @@ -0,0 +1,18 @@ +.TH SOFTHSM2-DUMP-FILE 1 "20 March 2014" "SoftHSM" +.SH NAME +softhsm2-dump-file \- SoftHSM object file dump +.SH SYNOPSIS +.PP +.B softhsm2-dump-file +.I path +.SH DESCRIPTION +.B softhsm2-dump-file +is a tool that can dump SoftHSM v2 object file for debugging purposes. +.LP +.SH OPTIONS +.TP +.B \fIpath\fR +The SoftHSM v2 object file that is going to be dumped. +.TP +.B \-\-help\fR, \fB\-h\fR +Show the help information. diff --git a/SoftHSMv2/src/bin/dump/softhsm2-dump-file.cpp b/SoftHSMv2/src/bin/dump/softhsm2-dump-file.cpp new file mode 100644 index 0000000..994f67e --- /dev/null +++ b/SoftHSMv2/src/bin/dump/softhsm2-dump-file.cpp @@ -0,0 +1,537 @@ +/* + * Copyright (c) 2013 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + softhsm2-dump-file.cpp + + This program can be used for dumping SoftHSM v2 object files. + *****************************************************************************/ + +#include <config.h> + +#include "common.h" + +// Attribute types on disk +#define BOOLEAN_ATTR 0x1 +#define ULONG_ATTR 0x2 +#define BYTES_ATTR 0x3 +#define ATTRMAP_ATTR 0x4 +#define MECHSET_ATTR 0x5 + +// Maximum byte string length (1Gib) +#define MAX_BYTES 0x3fffffff + +typedef AttributeTK<uint64_t, uint64_t, uint64_t> Attribute; + +// Attribute specialization +template<> +bool Attribute::isBoolean() const +{ + return kind == BOOLEAN_ATTR; +} + +template<> +bool Attribute::isInteger() const +{ + return kind == ULONG_ATTR; +} + +template<> +bool Attribute::isBinary() const +{ + return kind == BYTES_ATTR; +} + +template<> +bool Attribute::isMechSet() const +{ + return kind == MECHSET_ATTR; +} + +template<> +void Attribute::dumpType() const +{ + dumpULong(type, true); +} + +template<> +void Attribute::dumpKind() const +{ + dumpULong(kind, true); +} + +template<> +void Attribute::dumpBoolValue() const +{ + dumpBool(boolValue, true); +} + +template<> +void Attribute::dumpULongValue(uint64_t value) const +{ + dumpULong(value, true); +} + +// dumpMap specialization +typedef std::vector<Attribute> va_type; + +void dumpMap(const va_type& value) +{ + for (va_type::const_iterator attr = value.begin(); attr != value.end(); ++attr) + attr->dump(); +} + +// Read a boolean (in fact unsigned 8 bit long) value +bool readBool(FILE* stream, uint8_t& value) +{ + value = 0; + fpos_t pos; + if (fgetpos(stream, &pos) != 0) + { + return false; + } + uint8_t v; + if (fread(&v, 1, 1, stream) != 1) + { + (void) fsetpos(stream, &pos); + return false; + } + value = v; + return true; +} + +// Read an unsigned 64 bit long value +bool readULong(FILE* stream, uint64_t& value) +{ + value = 0; + fpos_t pos; + if (fgetpos(stream, &pos) != 0) + { + return false; + } + uint8_t v[8]; + if (fread(v, 1, 8, stream) != 8) + { + (void) fsetpos(stream, &pos); + return false; + } + for (size_t i = 0; i < 8; i++) + { + value <<= 8; + value += v[i]; + } + return true; +} + +// Read a byte string (aka uint8_t vector) value +bool readBytes(FILE* stream, std::vector<uint8_t>& value) +{ + size_t len = value.size(); + fpos_t pos; + if (fgetpos(stream, &pos) != 0) + { + return false; + } + if (fread(&value[0], 1, len, stream) != len) + { + (void) fsetpos(stream, &pos); + return false; + } + return true; +} + +// Read a map (aka Attribute vector) value +bool readMap(FILE* stream, uint64_t len, std::vector<Attribute>& value) +{ + fpos_t pos; + if (fgetpos(stream, &pos) != 0) + { + return false; + } + while (len != 0) + { + Attribute attr; + + if (len < 8) + { + (void) fsetpos(stream, &pos); + return false; + } + if (!readULong(stream, attr.type)) + { + (void) fsetpos(stream, &pos); + return false; + } + len -= 8; + + if (len < 8) + { + (void) fsetpos(stream, &pos); + return false; + } + if (!readULong(stream, attr.kind)) + { + (void) fsetpos(stream, &pos); + return false; + } + len -= 8; + + if (attr.kind == BOOLEAN_ATTR) + { + if (len < 1) + { + (void) fsetpos(stream, &pos); + return false; + } + len -= 1; + if (!readBool(stream, attr.boolValue)) + { + (void) fsetpos(stream, &pos); + return false; + } + } + else if (attr.kind == ULONG_ATTR) + { + if (len < 8) + { + (void) fsetpos(stream, &pos); + return false; + } + if (!readULong(stream, attr.ulongValue)) + { + (void) fsetpos(stream, &pos); + return false; + } + len -= 8; + } + else if (attr.kind == BYTES_ATTR) + { + uint64_t size; + if (len < 8) + { + (void) fsetpos(stream, &pos); + return false; + } + if (!readULong(stream, size)) + { + (void) fsetpos(stream, &pos); + return false; + } + len -= 8; + + if (len < size) + { + (void) fsetpos(stream, &pos); + return false; + } + attr.bytestrValue.resize((size_t)size); + if (!readBytes(stream, attr.bytestrValue)) + { + (void) fsetpos(stream, &pos); + return false; + } + len -= size; + } + else if (attr.kind == MECHSET_ATTR) + { + uint64_t size; + if (len < 8) + { + (void) fsetpos(stream, &pos); + return false; + } + if (!readULong(stream, size)) + { + (void) fsetpos(stream, &pos); + return false; + } + len -= 8; + + if (len < size * 8) + { + (void) fsetpos(stream, &pos); + return false; + } + + for (unsigned long i = 0; i < size; i++) + { + uint64_t mech; + if (!readULong(stream, mech)) + { + (void) fsetpos(stream, &pos); + return false; + } + attr.mechSetValue.insert(mech); + } + len -= size * 8; + } + else + { + (void) fsetpos(stream, &pos); + return false; + } + + value.push_back(attr); + } + + return true; +} + +// Error case +void corrupt(FILE* stream) +{ + uint8_t v; + for (size_t i = 0; i < 8; i++) + { + if (fread(&v, 1, 1, stream) != 1) + { + if (ferror(stream)) + { + printf("get an error...\n"); + } + return; + } + if (i != 0) + { + printf(" "); + } + printf("%02hhx", v); + } + if (fread(&v, 1, 1, stream) != 1) + { + if (ferror(stream)) + { + printf("\nget an error...\n"); + } + return; + } + printf("...\n"); +} + +// Core function +void dump(FILE* stream) +{ + uint64_t gen; + if (!readULong(stream, gen)) + { + if (feof(stream)) + { + printf("empty file\n"); + } + else + { + corrupt(stream); + } + return; + } + dumpULong(gen); + printf("generation %lu\n", (unsigned long) gen); + + while (!feof(stream)) + { + uint64_t p11type; + if (!readULong(stream, p11type)) + { + corrupt(stream); + return; + } + dumpULong(p11type); + if ((uint64_t)((uint32_t)p11type) != p11type) + { + printf("overflow attribute type\n"); + } + else + { + dumpCKA((unsigned long) p11type, 48); + printf("\n"); + } + + uint64_t disktype; + if (!readULong(stream, disktype)) + { + corrupt(stream); + return; + } + dumpULong(disktype); + switch (disktype) + { + case BOOLEAN_ATTR: + printf("boolean attribute\n"); + break; + case ULONG_ATTR: + printf("unsigned long attribute\n"); + break; + case BYTES_ATTR: + printf("byte string attribute\n"); + break; + case ATTRMAP_ATTR: + printf("attribute map attribute\n"); + break; + case MECHSET_ATTR: + printf("mechanism set attribute\n"); + break; + default: + printf("unknown attribute format\n"); + break; + } + + if (disktype == BOOLEAN_ATTR) + { + uint8_t value; + if (!readBool(stream, value)) + { + corrupt(stream); + return; + } + dumpBool(value); + printf("\n"); + } + else if (disktype == ULONG_ATTR) + { + uint64_t value; + if (!readULong(stream, value)) + { + corrupt(stream); + return; + } + dumpULong(value); + dumpCKx(p11type, value, 48); + printf("\n"); + } + else if (disktype == BYTES_ATTR) + { + uint64_t len; + if (!readULong(stream, len)) + { + corrupt(stream); + return; + } + dumpULong(len); + if (len > MAX_BYTES) + { + printf("overflow length...\n"); + return; + } + printf("(length %lu)\n", (unsigned long) len); + + std::vector<uint8_t> value((size_t) len); + if (!readBytes(stream, value)) + { + corrupt(stream); + return; + } + dumpBytes(value); + } + else if (disktype == ATTRMAP_ATTR) + { + uint64_t len; + if (!readULong(stream, len)) + { + corrupt(stream); + return; + } + dumpULong(len); + if (len > MAX_BYTES) + { + printf("overflow length...\n"); + return; + } + printf("(length %lu)\n", (unsigned long) len); + + std::vector<Attribute> value; + if (!readMap(stream, len, value)) + { + corrupt(stream); + return; + } + dumpMap(value); + } + else if (disktype == MECHSET_ATTR) + { + uint64_t len; + if (!readULong(stream, len)) + { + corrupt(stream); + return; + } + dumpULong(len); + if (len > MAX_BYTES) + { + printf("overflow length...\n"); + return; + } + printf("(length %lu)\n", (unsigned long) len); + + for (unsigned long i = 0; i < len; i++) + { + uint64_t mech; + if (!readULong(stream, mech)) + { + corrupt(stream); + return; + } + dumpULong(mech); + dumpCKM(mech, 48); + printf("\n"); + } + } + else + { + corrupt(stream); + return; + } + } +} + +// Display the usage +void usage() +{ + printf("SoftHSM dump tool. From SoftHSM v2 object file.\n"); + printf("Usage: softhsm2-dump-file path\n"); +} + +// The main function +int main(int argc, char* argv[]) +{ + FILE* stream; + + if (argc != 2) + { + usage(); + exit(0); + } + + stream = fopen(argv[1], "r"); + if (stream == NULL) + { + fprintf(stderr, "can't open object file %s\n", argv[1]); + exit(0); + } + + printf("Dump of object file \"%s\"\n", argv[1]); + dump(stream); + exit(1); +} diff --git a/SoftHSMv2/src/bin/dump/tables.h b/SoftHSMv2/src/bin/dump/tables.h new file mode 100644 index 0000000..76d64fb --- /dev/null +++ b/SoftHSMv2/src/bin/dump/tables.h @@ -0,0 +1,554 @@ +/* + * Copyright (c) 2013 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + tables.h + + Tables from PKCS#11 specs. + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_TABLES_H +#define _SOFTHSM_V2_TABLES_H + +#include "OSAttributes.h" + +// Attribute types +void fill_CKA_table(std::map<unsigned long, std::string> &t) +{ + t[CKA_CLASS] = "CKA_CLASS"; + t[CKA_TOKEN] = "CKA_TOKEN"; + t[CKA_PRIVATE] = "CKA_PRIVATE"; + t[CKA_LABEL] = "CKA_LABEL"; + t[CKA_APPLICATION] = "CKA_APPLICATION"; + t[CKA_VALUE] = "CKA_VALUE"; + t[CKA_OBJECT_ID] = "CKA_OBJECT_ID"; + t[CKA_CERTIFICATE_TYPE] = "CKA_CERTIFICATE_TYPE"; + t[CKA_ISSUER] = "CKA_ISSUER"; + t[CKA_SERIAL_NUMBER] = "CKA_SERIAL_NUMBER"; + t[CKA_AC_ISSUER] = "CKA_AC_ISSUER"; + t[CKA_OWNER] = "CKA_OWNER"; + t[CKA_ATTR_TYPES] = "CKA_ATTR_TYPES"; + t[CKA_TRUSTED] = "CKA_TRUSTED"; + t[CKA_CERTIFICATE_CATEGORY] = "CKA_CERTIFICATE_CATEGORY"; + t[CKA_JAVA_MIDP_SECURITY_DOMAIN] = "CKA_JAVA_MIDP_SECURITY_DOMAIN"; + t[CKA_URL] = "CKA_URL"; + t[CKA_HASH_OF_SUBJECT_PUBLIC_KEY] = "CKA_HASH_OF_SUBJECT_PUBLIC_KEY"; + t[CKA_HASH_OF_ISSUER_PUBLIC_KEY] = "CKA_HASH_OF_ISSUER_PUBLIC_KEY"; + t[CKA_NAME_HASH_ALGORITHM] = "CKA_NAME_HASH_ALGORITHM"; + t[CKA_CHECK_VALUE] = "CKA_CHECK_VALUE"; + t[CKA_KEY_TYPE] = "CKA_KEY_TYPE"; + t[CKA_SUBJECT] = "CKA_SUBJECT"; + t[CKA_ID] = "CKA_ID"; + t[CKA_SENSITIVE] = "CKA_SENSITIVE"; + t[CKA_ENCRYPT] = "CKA_ENCRYPT"; + t[CKA_DECRYPT] = "CKA_DECRYPT"; + t[CKA_WRAP] = "CKA_WRAP"; + t[CKA_UNWRAP] = "CKA_UNWRAP"; + t[CKA_SIGN] = "CKA_SIGN"; + t[CKA_SIGN_RECOVER] = "CKA_SIGN_RECOVER"; + t[CKA_VERIFY] = "CKA_VERIFY"; + t[CKA_VERIFY_RECOVER] = "CKA_VERIFY_RECOVER"; + t[CKA_DERIVE] = "CKA_DERIVE"; + t[CKA_START_DATE] = "CKA_START_DATE"; + t[CKA_END_DATE] = "CKA_END_DATE"; + t[CKA_MODULUS] = "CKA_MODULUS"; + t[CKA_MODULUS_BITS] = "CKA_MODULUS_BITS"; + t[CKA_PUBLIC_EXPONENT] = "CKA_PUBLIC_EXPONENT"; + t[CKA_PRIVATE_EXPONENT] = "CKA_PRIVATE_EXPONENT"; + t[CKA_PRIME_1] = "CKA_PRIME_1"; + t[CKA_PRIME_2] = "CKA_PRIME_2"; + t[CKA_EXPONENT_1] = "CKA_EXPONENT_1"; + t[CKA_EXPONENT_2] = "CKA_EXPONENT_2"; + t[CKA_COEFFICIENT] = "CKA_COEFFICIENT"; + t[CKA_PUBLIC_KEY_INFO] = "CKA_PUBLIC_KEY_INFO"; + t[CKA_PRIME] = "CKA_PRIME"; + t[CKA_SUBPRIME] = "CKA_SUBPRIME"; + t[CKA_BASE] = "CKA_BASE"; + t[CKA_PRIME_BITS] = "CKA_PRIME_BITS"; + t[CKA_SUBPRIME_BITS] = "CKA_SUBPRIME_BITS"; + t[CKA_VALUE_BITS] = "CKA_VALUE_BITS"; + t[CKA_VALUE_LEN] = "CKA_VALUE_LEN"; + t[CKA_EXTRACTABLE] = "CKA_EXTRACTABLE"; + t[CKA_LOCAL] = "CKA_LOCAL"; + t[CKA_NEVER_EXTRACTABLE] = "CKA_NEVER_EXTRACTABLE"; + t[CKA_ALWAYS_SENSITIVE] = "CKA_ALWAYS_SENSITIVE"; + t[CKA_KEY_GEN_MECHANISM] = "CKA_KEY_GEN_MECHANISM"; + t[CKA_MODIFIABLE] = "CKA_MODIFIABLE"; + t[CKA_COPYABLE] = "CKA_COPYABLE"; + t[CKA_DESTROYABLE] = "CKA_DESTROYABLE"; + t[CKA_EC_PARAMS] = "CKA_EC_PARAMS"; + t[CKA_EC_POINT] = "CKA_EC_POINT"; + t[CKA_SECONDARY_AUTH] = "CKA_SECONDARY_AUTH"; + t[CKA_AUTH_PIN_FLAGS] = "CKA_AUTH_PIN_FLAGS"; + t[CKA_ALWAYS_AUTHENTICATE] = "CKA_ALWAYS_AUTHENTICATE"; + t[CKA_WRAP_WITH_TRUSTED] = "CKA_WRAP_WITH_TRUSTED"; + t[CKA_WRAP_TEMPLATE] = "CKA_WRAP_TEMPLATE"; + t[CKA_UNWRAP_TEMPLATE] = "CKA_UNWRAP_TEMPLATE"; + t[CKA_DERIVE_TEMPLATE] = "CKA_DERIVE_TEMPLATE"; + t[CKA_OTP_FORMAT] = "CKA_OTP_FORMAT"; + t[CKA_OTP_LENGTH] = "CKA_OTP_LENGTH"; + t[CKA_OTP_TIME_INTERVAL] = "CKA_OTP_TIME_INTERVAL"; + t[CKA_OTP_USER_FRIENDLY_MODE] = "CKA_OTP_USER_FRIENDLY_MODE"; + t[CKA_OTP_CHALLENGE_REQUIREMENT] = "CKA_OTP_CHALLENGE_REQUIREMENT"; + t[CKA_OTP_TIME_REQUIREMENT] = "CKA_OTP_TIME_REQUIREMENT"; + t[CKA_OTP_COUNTER_REQUIREMENT] = "CKA_OTP_COUNTER_REQUIREMENT"; + t[CKA_OTP_PIN_REQUIREMENT] = "CKA_OTP_PIN_REQUIREMENT"; + t[CKA_OTP_COUNTER] = "CKA_OTP_COUNTER"; + t[CKA_OTP_TIME] = "CKA_OTP_TIME"; + t[CKA_OTP_USER_IDENTIFIER] = "CKA_OTP_USER_IDENTIFIER"; + t[CKA_OTP_SERVICE_IDENTIFIER] = "CKA_OTP_SERVICE_IDENTIFIER"; + t[CKA_OTP_SERVICE_LOGO] = "CKA_OTP_SERVICE_LOGO"; + t[CKA_OTP_SERVICE_LOGO_TYPE] = "CKA_OTP_SERVICE_LOGO_TYPE"; + t[CKA_GOSTR3410_PARAMS] = "CKA_GOSTR3410_PARAMS"; + t[CKA_GOSTR3411_PARAMS] = "CKA_GOSTR3411_PARAMS"; + t[CKA_GOST28147_PARAMS] = "CKA_GOST28147_PARAMS"; + t[CKA_HW_FEATURE_TYPE] = "CKA_HW_FEATURE_TYPE"; + t[CKA_RESET_ON_INIT] = "CKA_RESET_ON_INIT"; + t[CKA_HAS_RESET] = "CKA_HAS_RESET"; + t[CKA_PIXEL_X] = "CKA_PIXEL_X"; + t[CKA_PIXEL_Y] = "CKA_PIXEL_Y"; + t[CKA_RESOLUTION] = "CKA_RESOLUTION"; + t[CKA_CHAR_ROWS] = "CKA_CHAR_ROWS"; + t[CKA_CHAR_COLUMNS] = "CKA_CHAR_COLUMNS"; + t[CKA_COLOR] = "CKA_COLOR"; + t[CKA_BITS_PER_PIXEL] = "CKA_BITS_PER_PIXEL"; + t[CKA_CHAR_SETS] = "CKA_CHAR_SETS"; + t[CKA_ENCODING_METHODS] = "CKA_ENCODING_METHODS"; + t[CKA_MIME_TYPES] = "CKA_MIME_TYPES"; + t[CKA_MECHANISM_TYPE] = "CKA_MECHANISM_TYPE"; + t[CKA_REQUIRED_CMS_ATTRIBUTES] = "CKA_REQUIRED_CMS_ATTRIBUTES"; + t[CKA_DEFAULT_CMS_ATTRIBUTES] = "CKA_DEFAULT_CMS_ATTRIBUTES"; + t[CKA_SUPPORTED_CMS_ATTRIBUTES] = "CKA_SUPPORTED_CMS_ATTRIBUTES"; + t[CKA_ALLOWED_MECHANISMS] = "CKA_ALLOWED_MECHANISMS"; + // local extensions + t[CKA_VENDOR_SOFTHSM] = "CKA_VENDOR_SOFTHSM"; + t[CKA_OS_TOKENLABEL] = "CKA_OS_TOKENLABEL"; + t[CKA_OS_TOKENSERIAL] = "CKA_OS_TOKENSERIAL"; + t[CKA_OS_TOKENFLAGS] = "CKA_OS_TOKENFLAGS"; + t[CKA_OS_SOPIN] = "CKA_OS_SOPIN"; + t[CKA_OS_USERPIN] = "CKA_OS_USERPIN"; +} + +void fill_CKM_table(std::map<unsigned long, std::string> &t) +{ + t[CKM_RSA_PKCS_KEY_PAIR_GEN] = "CKM_RSA_PKCS_KEY_PAIR_GEN"; + t[CKM_RSA_PKCS] = "CKM_RSA_PKCS"; + t[CKM_RSA_9796] = "CKM_RSA_9796"; + t[CKM_RSA_X_509] = "CKM_RSA_X_509"; + t[CKM_MD2_RSA_PKCS] = "CKM_MD2_RSA_PKCS"; + t[CKM_MD5_RSA_PKCS] = "CKM_MD5_RSA_PKCS"; + t[CKM_SHA1_RSA_PKCS] = "CKM_SHA1_RSA_PKCS"; + t[CKM_RIPEMD128_RSA_PKCS] = "CKM_RIPEMD128_RSA_PKCS"; + t[CKM_RIPEMD160_RSA_PKCS] = "CKM_RIPEMD160_RSA_PKCS"; + t[CKM_RSA_PKCS_OAEP] = "CKM_RSA_PKCS_OAEP"; + t[CKM_RSA_X9_31_KEY_PAIR_GEN] = "CKM_RSA_X9_31_KEY_PAIR_GEN"; + t[CKM_RSA_X9_31] = "CKM_RSA_X9_31"; + t[CKM_SHA1_RSA_X9_31] = "CKM_SHA1_RSA_X9_31"; + t[CKM_RSA_PKCS_PSS] = "CKM_RSA_PKCS_PSS"; + t[CKM_SHA1_RSA_PKCS_PSS] = "CKM_SHA1_RSA_PKCS_PSS"; + t[CKM_DSA_KEY_PAIR_GEN] = "CKM_DSA_KEY_PAIR_GEN"; + t[CKM_DSA] = "CKM_DSA"; + t[CKM_DSA_SHA1] = "CKM_DSA_SHA1"; + t[CKM_DSA_SHA224] = "CKM_DSA_SHA224"; + t[CKM_DSA_SHA256] = "CKM_DSA_SHA256"; + t[CKM_DSA_SHA384] = "CKM_DSA_SHA384"; + t[CKM_DSA_SHA512] = "CKM_DSA_SHA512"; + t[CKM_DH_PKCS_KEY_PAIR_GEN] = "CKM_DH_PKCS_KEY_PAIR_GEN"; + t[CKM_DH_PKCS_DERIVE] = "CKM_DH_PKCS_DERIVE"; + t[CKM_X9_42_DH_KEY_PAIR_GEN] = "CKM_X9_42_DH_KEY_PAIR_GEN"; + t[CKM_X9_42_DH_DERIVE] = "CKM_X9_42_DH_DERIVE"; + t[CKM_X9_42_DH_HYBRID_DERIVE] = "CKM_X9_42_DH_HYBRID_DERIVE"; + t[CKM_X9_42_MQV_DERIVE] = "CKM_X9_42_MQV_DERIVE"; + t[CKM_SHA256_RSA_PKCS] = "CKM_SHA256_RSA_PKCS"; + t[CKM_SHA384_RSA_PKCS] = "CKM_SHA384_RSA_PKCS"; + t[CKM_SHA512_RSA_PKCS] = "CKM_SHA512_RSA_PKCS"; + t[CKM_SHA256_RSA_PKCS_PSS] = "CKM_SHA256_RSA_PKCS_PSS"; + t[CKM_SHA384_RSA_PKCS_PSS] = "CKM_SHA384_RSA_PKCS_PSS"; + t[CKM_SHA512_RSA_PKCS_PSS] = "CKM_SHA512_RSA_PKCS_PSS"; + t[CKM_SHA224_RSA_PKCS] = "CKM_SHA224_RSA_PKCS"; + t[CKM_SHA224_RSA_PKCS_PSS] = "CKM_SHA224_RSA_PKCS_PSS"; + t[CKM_SHA512_224] = "CKM_SHA512_224"; + t[CKM_SHA512_224_HMAC] = "CKM_SHA512_224_HMAC"; + t[CKM_SHA512_224_HMAC_GENERAL] = "CKM_SHA512_224_HMAC_GENERAL"; + t[CKM_SHA512_224_KEY_DERIVATION] = "CKM_SHA512_224_KEY_DERIVATION"; + t[CKM_SHA512_256] = "CKM_SHA512_256"; + t[CKM_SHA512_256_HMAC] = "CKM_SHA512_256_HMAC"; + t[CKM_SHA512_256_HMAC_GENERAL] = "CKM_SHA512_256_HMAC_GENERAL"; + t[CKM_SHA512_256_KEY_DERIVATION] = "CKM_SHA512_256_KEY_DERIVATION"; + t[CKM_SHA512_T] = "CKM_SHA512_T"; + t[CKM_SHA512_T_HMAC] = "CKM_SHA512_T_HMAC"; + t[CKM_SHA512_T_HMAC_GENERAL] = "CKM_SHA512_T_HMAC_GENERAL"; + t[CKM_SHA512_T_KEY_DERIVATION] = "CKM_SHA512_T_KEY_DERIVATION"; + t[CKM_RC2_KEY_GEN] = "CKM_RC2_KEY_GEN"; + t[CKM_RC2_ECB] = "CKM_RC2_ECB"; + t[CKM_RC2_CBC] = "CKM_RC2_CBC"; + t[CKM_RC2_MAC] = "CKM_RC2_MAC"; + t[CKM_RC2_MAC_GENERAL] = "CKM_RC2_MAC_GENERAL"; + t[CKM_RC2_CBC_PAD] = "CKM_RC2_CBC_PAD"; + t[CKM_RC4_KEY_GEN] = "CKM_RC4_KEY_GEN"; + t[CKM_RC4] = "CKM_RC4"; + t[CKM_DES_KEY_GEN] = "CKM_DES_KEY_GEN"; + t[CKM_DES_ECB] = "CKM_DES_ECB"; + t[CKM_DES_CBC] = "CKM_DES_CBC"; + t[CKM_DES_MAC] = "CKM_DES_MAC"; + t[CKM_DES_MAC_GENERAL] = "CKM_DES_MAC_GENERAL"; + t[CKM_DES_CBC_PAD] = "CKM_DES_CBC_PAD"; + t[CKM_DES2_KEY_GEN] = "CKM_DES2_KEY_GEN"; + t[CKM_DES3_KEY_GEN] = "CKM_DES3_KEY_GEN"; + t[CKM_DES3_ECB] = "CKM_DES3_ECB"; + t[CKM_DES3_CBC] = "CKM_DES3_CBC"; + t[CKM_DES3_MAC] = "CKM_DES3_MAC"; + t[CKM_DES3_MAC_GENERAL] = "CKM_DES3_MAC_GENERAL"; + t[CKM_DES3_CBC_PAD] = "CKM_DES3_CBC_PAD"; + t[CKM_DES3_CMAC_GENERAL] = "CKM_DES3_CMAC_GENERAL"; + t[CKM_DES3_CMAC] = "CKM_DES3_CMAC"; + t[CKM_CDMF_KEY_GEN] = "CKM_CDMF_KEY_GEN"; + t[CKM_CDMF_ECB] = "CKM_CDMF_ECB"; + t[CKM_CDMF_CBC] = "CKM_CDMF_CBC"; + t[CKM_CDMF_MAC] = "CKM_CDMF_MAC"; + t[CKM_CDMF_MAC_GENERAL] = "CKM_CDMF_MAC_GENERAL"; + t[CKM_CDMF_CBC_PAD] = "CKM_CDMF_CBC_PAD"; + t[CKM_DES_OFB64] = "CKM_DES_OFB64"; + t[CKM_DES_OFB8] = "CKM_DES_OFB8"; + t[CKM_DES_CFB64] = "CKM_DES_CFB64"; + t[CKM_DES_CFB8] = "CKM_DES_CFB8"; + t[CKM_MD2] = "CKM_MD2"; + t[CKM_MD2_HMAC] = "CKM_MD2_HMAC"; + t[CKM_MD2_HMAC_GENERAL] = "CKM_MD2_HMAC_GENERAL"; + t[CKM_MD5] = "CKM_MD5"; + t[CKM_MD5_HMAC] = "CKM_MD5_HMAC"; + t[CKM_MD5_HMAC_GENERAL] = "CKM_MD5_HMAC_GENERAL"; + t[CKM_SHA_1] = "CKM_SHA_1"; + t[CKM_SHA_1_HMAC] = "CKM_SHA_1_HMAC"; + t[CKM_SHA_1_HMAC_GENERAL] = "CKM_SHA_1_HMAC_GENERAL"; + t[CKM_RIPEMD128] = "CKM_RIPEMD128"; + t[CKM_RIPEMD128_HMAC] = "CKM_RIPEMD128_HMAC"; + t[CKM_RIPEMD128_HMAC_GENERAL] = "CKM_RIPEMD128_HMAC_GENERAL"; + t[CKM_RIPEMD160] = "CKM_RIPEMD160"; + t[CKM_RIPEMD160_HMAC] = "CKM_RIPEMD160_HMAC"; + t[CKM_RIPEMD160_HMAC_GENERAL] = "CKM_RIPEMD160_HMAC_GENERAL"; + t[CKM_SHA256] = "CKM_SHA256"; + t[CKM_SHA256_HMAC] = "CKM_SHA256_HMAC"; + t[CKM_SHA256_HMAC_GENERAL] = "CKM_SHA256_HMAC_GENERAL"; + t[CKM_SHA224] = "CKM_SHA224"; + t[CKM_SHA224_HMAC] = "CKM_SHA224_HMAC"; + t[CKM_SHA224_HMAC_GENERAL] = "CKM_SHA224_HMAC_GENERAL"; + t[CKM_SHA384] = "CKM_SHA384"; + t[CKM_SHA384_HMAC] = "CKM_SHA384_HMAC"; + t[CKM_SHA384_HMAC_GENERAL] = "CKM_SHA384_HMAC_GENERAL"; + t[CKM_SHA512] = "CKM_SHA512"; + t[CKM_SHA512_HMAC] = "CKM_SHA512_HMAC"; + t[CKM_SHA512_HMAC_GENERAL] = "CKM_SHA512_HMAC_GENERAL"; + t[CKM_SECURID_KEY_GEN] = "CKM_SECURID_KEY_GEN"; + t[CKM_SECURID] = "CKM_SECURID"; + t[CKM_HOTP_KEY_GEN] = "CKM_HOTP_KEY_GEN"; + t[CKM_HOTP] = "CKM_HOTP"; + t[CKM_ACTI] = "CKM_ACTI"; + t[CKM_ACTI_KEY_GEN] = "CKM_ACTI_KEY_GEN"; + t[CKM_CAST_KEY_GEN] = "CKM_CAST_KEY_GEN"; + t[CKM_CAST_ECB] = "CKM_CAST_ECB"; + t[CKM_CAST_CBC] = "CKM_CAST_CBC"; + t[CKM_CAST_MAC] = "CKM_CAST_MAC"; + t[CKM_CAST_MAC_GENERAL] = "CKM_CAST_MAC_GENERAL"; + t[CKM_CAST_CBC_PAD] = "CKM_CAST_CBC_PAD"; + t[CKM_CAST3_KEY_GEN] = "CKM_CAST3_KEY_GEN"; + t[CKM_CAST3_ECB] = "CKM_CAST3_ECB"; + t[CKM_CAST3_CBC] = "CKM_CAST3_CBC"; + t[CKM_CAST3_MAC] = "CKM_CAST3_MAC"; + t[CKM_CAST3_MAC_GENERAL] = "CKM_CAST3_MAC_GENERAL"; + t[CKM_CAST3_CBC_PAD] = "CKM_CAST3_CBC_PAD"; + t[CKM_CAST128_KEY_GEN] = "CKM_CAST128_KEY_GEN"; + t[CKM_CAST128_ECB] = "CKM_CAST128_ECB"; + t[CKM_CAST128_CBC] = "CKM_CAST128_CBC"; + t[CKM_CAST128_MAC] = "CKM_CAST128_MAC"; + t[CKM_CAST128_MAC_GENERAL] = "CKM_CAST128_MAC_GENERAL"; + t[CKM_CAST128_CBC_PAD] = "CKM_CAST128_CBC_PAD"; + t[CKM_RC5_KEY_GEN] = "CKM_RC5_KEY_GEN"; + t[CKM_RC5_ECB] = "CKM_RC5_ECB"; + t[CKM_RC5_CBC] = "CKM_RC5_CBC"; + t[CKM_RC5_MAC] = "CKM_RC5_MAC"; + t[CKM_RC5_MAC_GENERAL] = "CKM_RC5_MAC_GENERAL"; + t[CKM_RC5_CBC_PAD] = "CKM_RC5_CBC_PAD"; + t[CKM_IDEA_KEY_GEN] = "CKM_IDEA_KEY_GEN"; + t[CKM_IDEA_ECB] = "CKM_IDEA_ECB"; + t[CKM_IDEA_CBC] = "CKM_IDEA_CBC"; + t[CKM_IDEA_MAC] = "CKM_IDEA_MAC"; + t[CKM_IDEA_MAC_GENERAL] = "CKM_IDEA_MAC_GENERAL"; + t[CKM_IDEA_CBC_PAD] = "CKM_IDEA_CBC_PAD"; + t[CKM_GENERIC_SECRET_KEY_GEN] = "CKM_GENERIC_SECRET_KEY_GEN"; + t[CKM_CONCATENATE_BASE_AND_KEY] = "CKM_CONCATENATE_BASE_AND_KEY"; + t[CKM_CONCATENATE_BASE_AND_DATA] = "CKM_CONCATENATE_BASE_AND_DATA"; + t[CKM_CONCATENATE_DATA_AND_BASE] = "CKM_CONCATENATE_DATA_AND_BASE"; + t[CKM_XOR_BASE_AND_DATA] = "CKM_XOR_BASE_AND_DATA"; + t[CKM_EXTRACT_KEY_FROM_KEY] = "CKM_EXTRACT_KEY_FROM_KEY"; + t[CKM_SSL3_PRE_MASTER_KEY_GEN] = "CKM_SSL3_PRE_MASTER_KEY_GEN"; + t[CKM_SSL3_MASTER_KEY_DERIVE] = "CKM_SSL3_MASTER_KEY_DERIVE"; + t[CKM_SSL3_KEY_AND_MAC_DERIVE] = "CKM_SSL3_KEY_AND_MAC_DERIVE"; + t[CKM_SSL3_MASTER_KEY_DERIVE_DH] = "CKM_SSL3_MASTER_KEY_DERIVE_DH"; + t[CKM_TLS_PRE_MASTER_KEY_GEN] = "CKM_TLS_PRE_MASTER_KEY_GEN"; + t[CKM_TLS_MASTER_KEY_DERIVE] = "CKM_TLS_MASTER_KEY_DERIVE"; + t[CKM_TLS_KEY_AND_MAC_DERIVE] = "CKM_TLS_KEY_AND_MAC_DERIVE"; + t[CKM_TLS_MASTER_KEY_DERIVE_DH] = "CKM_TLS_MASTER_KEY_DERIVE_DH"; + t[CKM_TLS_PRF] = "CKM_TLS_PRF"; + t[CKM_SSL3_MD5_MAC] = "CKM_SSL3_MD5_MAC"; + t[CKM_SSL3_SHA1_MAC] = "CKM_SSL3_SHA1_MAC"; + t[CKM_MD5_KEY_DERIVATION] = "CKM_MD5_KEY_DERIVATION"; + t[CKM_MD2_KEY_DERIVATION] = "CKM_MD2_KEY_DERIVATION"; + t[CKM_SHA1_KEY_DERIVATION] = "CKM_SHA1_KEY_DERIVATION"; + t[CKM_SHA256_KEY_DERIVATION] = "CKM_SHA256_KEY_DERIVATION"; + t[CKM_SHA384_KEY_DERIVATION] = "CKM_SHA384_KEY_DERIVATION"; + t[CKM_SHA512_KEY_DERIVATION] = "CKM_SHA512_KEY_DERIVATION"; + t[CKM_SHA224_KEY_DERIVATION] = "CKM_SHA224_KEY_DERIVATION"; + t[CKM_PBE_MD2_DES_CBC] = "CKM_PBE_MD2_DES_CBC"; + t[CKM_PBE_MD5_DES_CBC] = "CKM_PBE_MD5_DES_CBC"; + t[CKM_PBE_MD5_CAST_CBC] = "CKM_PBE_MD5_CAST_CBC"; + t[CKM_PBE_MD5_CAST3_CBC] = "CKM_PBE_MD5_CAST3_CBC"; + t[CKM_PBE_MD5_CAST128_CBC] = "CKM_PBE_MD5_CAST128_CBC"; + t[CKM_PBE_SHA1_CAST128_CBC] = "CKM_PBE_SHA1_CAST128_CBC"; + t[CKM_PBE_SHA1_RC4_128] = "CKM_PBE_SHA1_RC4_128"; + t[CKM_PBE_SHA1_RC4_40] = "CKM_PBE_SHA1_RC4_40"; + t[CKM_PBE_SHA1_DES3_EDE_CBC] = "CKM_PBE_SHA1_DES3_EDE_CBC"; + t[CKM_PBE_SHA1_DES2_EDE_CBC] = "CKM_PBE_SHA1_DES2_EDE_CBC"; + t[CKM_PBE_SHA1_RC2_128_CBC] = "CKM_PBE_SHA1_RC2_128_CBC"; + t[CKM_PBE_SHA1_RC2_40_CBC] = "CKM_PBE_SHA1_RC2_40_CBC"; + t[CKM_PKCS5_PBKD2] = "CKM_PKCS5_PBKD2"; + t[CKM_PBA_SHA1_WITH_SHA1_HMAC] = "CKM_PBA_SHA1_WITH_SHA1_HMAC"; + t[CKM_WTLS_PRE_MASTER_KEY_GEN] = "CKM_WTLS_PRE_MASTER_KEY_GEN"; + t[CKM_WTLS_MASTER_KEY_DERIVE] = "CKM_WTLS_MASTER_KEY_DERIVE"; + t[CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC] = "CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC"; + t[CKM_WTLS_PRF] = "CKM_WTLS_PRF"; + t[CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE] = "CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE"; + t[CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE] = "CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE"; + t[CKM_TLS10_MAC_SERVER] = "CKM_TLS10_MAC_SERVER"; + t[CKM_TLS10_MAC_CLIENT] = "CKM_TLS10_MAC_CLIENT"; + t[CKM_TLS12_MAC] = "CKM_TLS12_MAC"; + t[CKM_TLS12_KDF] = "CKM_TLS12_KDF"; + t[CKM_TLS12_MASTER_KEY_DERIVE] = "CKM_TLS12_MASTER_KEY_DERIVE"; + t[CKM_TLS12_KEY_AND_MAC_DERIVE] = "CKM_TLS12_KEY_AND_MAC_DERIVE"; + t[CKM_TLS12_MASTER_KEY_DERIVE_DH] = "CKM_TLS12_MASTER_KEY_DERIVE_DH"; + t[CKM_TLS12_KEY_SAFE_DERIVE] = "CKM_TLS12_KEY_SAFE_DERIVE"; + t[CKM_TLS_MAC] = "CKM_TLS_MAC"; + t[CKM_TLS_KDF] = "CKM_TLS_KDF"; + t[CKM_KEY_WRAP_LYNKS] = "CKM_KEY_WRAP_LYNKS"; + t[CKM_KEY_WRAP_SET_OAEP] = "CKM_KEY_WRAP_SET_OAEP"; + t[CKM_CMS_SIG] = "CKM_CMS_SIG"; + t[CKM_KIP_DERIVE] = "CKM_KIP_DERIVE"; + t[CKM_KIP_WRAP] = "CKM_KIP_WRAP"; + t[CKM_KIP_MAC] = "CKM_KIP_MAC"; + t[CKM_CAMELLIA_KEY_GEN] = "CKM_CAMELLIA_KEY_GEN"; + t[CKM_CAMELLIA_ECB] = "CKM_CAMELLIA_ECB"; + t[CKM_CAMELLIA_CBC] = "CKM_CAMELLIA_CBC"; + t[CKM_CAMELLIA_MAC] = "CKM_CAMELLIA_MAC"; + t[CKM_CAMELLIA_MAC_GENERAL] = "CKM_CAMELLIA_MAC_GENERAL"; + t[CKM_CAMELLIA_CBC_PAD] = "CKM_CAMELLIA_CBC_PAD"; + t[CKM_CAMELLIA_ECB_ENCRYPT_DATA] = "CKM_CAMELLIA_ECB_ENCRYPT_DATA"; + t[CKM_CAMELLIA_CBC_ENCRYPT_DATA] = "CKM_CAMELLIA_CBC_ENCRYPT_DATA"; + t[CKM_CAMELLIA_CTR] = "CKM_CAMELLIA_CTR"; + t[CKM_ARIA_KEY_GEN] = "CKM_ARIA_KEY_GEN"; + t[CKM_ARIA_ECB] = "CKM_ARIA_ECB"; + t[CKM_ARIA_CBC] = "CKM_ARIA_CBC"; + t[CKM_ARIA_MAC] = "CKM_ARIA_MAC"; + t[CKM_ARIA_MAC_GENERAL] = "CKM_ARIA_MAC_GENERAL"; + t[CKM_ARIA_CBC_PAD] = "CKM_ARIA_CBC_PAD"; + t[CKM_ARIA_ECB_ENCRYPT_DATA] = "CKM_ARIA_ECB_ENCRYPT_DATA"; + t[CKM_ARIA_CBC_ENCRYPT_DATA] = "CKM_ARIA_CBC_ENCRYPT_DATA"; + t[CKM_SEED_KEY_GEN] = "CKM_SEED_KEY_GEN"; + t[CKM_SEED_ECB] = "CKM_SEED_ECB"; + t[CKM_SEED_CBC] = "CKM_SEED_CBC"; + t[CKM_SEED_MAC] = "CKM_SEED_MAC"; + t[CKM_SEED_MAC_GENERAL] = "CKM_SEED_MAC_GENERAL"; + t[CKM_SEED_CBC_PAD] = "CKM_SEED_CBC_PAD"; + t[CKM_SEED_ECB_ENCRYPT_DATA] = "CKM_SEED_ECB_ENCRYPT_DATA"; + t[CKM_SEED_CBC_ENCRYPT_DATA] = "CKM_SEED_CBC_ENCRYPT_DATA"; + t[CKM_SKIPJACK_KEY_GEN] = "CKM_SKIPJACK_KEY_GEN"; + t[CKM_SKIPJACK_ECB64] = "CKM_SKIPJACK_ECB64"; + t[CKM_SKIPJACK_CBC64] = "CKM_SKIPJACK_CBC64"; + t[CKM_SKIPJACK_OFB64] = "CKM_SKIPJACK_OFB64"; + t[CKM_SKIPJACK_CFB64] = "CKM_SKIPJACK_CFB64"; + t[CKM_SKIPJACK_CFB32] = "CKM_SKIPJACK_CFB32"; + t[CKM_SKIPJACK_CFB16] = "CKM_SKIPJACK_CFB16"; + t[CKM_SKIPJACK_CFB8] = "CKM_SKIPJACK_CFB8"; + t[CKM_SKIPJACK_WRAP] = "CKM_SKIPJACK_WRAP"; + t[CKM_SKIPJACK_PRIVATE_WRAP] = "CKM_SKIPJACK_PRIVATE_WRAP"; + t[CKM_SKIPJACK_RELAYX] = "CKM_SKIPJACK_RELAYX"; + t[CKM_KEA_KEY_PAIR_GEN] = "CKM_KEA_KEY_PAIR_GEN"; + t[CKM_KEA_KEY_DERIVE] = "CKM_KEA_KEY_DERIVE"; + t[CKM_FORTEZZA_TIMESTAMP] = "CKM_FORTEZZA_TIMESTAMP"; + t[CKM_BATON_KEY_GEN] = "CKM_BATON_KEY_GEN"; + t[CKM_BATON_ECB128] = "CKM_BATON_ECB128"; + t[CKM_BATON_ECB96] = "CKM_BATON_ECB96"; + t[CKM_BATON_CBC128] = "CKM_BATON_CBC128"; + t[CKM_BATON_COUNTER] = "CKM_BATON_COUNTER"; + t[CKM_BATON_SHUFFLE] = "CKM_BATON_SHUFFLE"; + t[CKM_BATON_WRAP] = "CKM_BATON_WRAP"; + t[CKM_EC_KEY_PAIR_GEN] = "CKM_EC_KEY_PAIR_GEN"; + t[CKM_ECDSA] = "CKM_ECDSA"; + t[CKM_ECDSA_SHA1] = "CKM_ECDSA_SHA1"; + t[CKM_ECDSA_SHA224] = "CKM_ECDSA_SHA224"; + t[CKM_ECDSA_SHA256] = "CKM_ECDSA_SHA256"; + t[CKM_ECDSA_SHA384] = "CKM_ECDSA_SHA384"; + t[CKM_ECDSA_SHA512] = "CKM_ECDSA_SHA512"; + t[CKM_ECDH1_DERIVE] = "CKM_ECDH1_DERIVE"; + t[CKM_ECDH1_COFACTOR_DERIVE] = "CKM_ECDH1_COFACTOR_DERIVE"; + t[CKM_ECMQV_DERIVE] = "CKM_ECMQV_DERIVE"; + t[CKM_ECDH_AES_KEY_WRAP] = "CKM_ECDH_AES_KEY_WRAP"; + t[CKM_RSA_AES_KEY_WRAP] = "CKM_RSA_AES_KEY_WRAP"; + t[CKM_JUNIPER_KEY_GEN] = "CKM_JUNIPER_KEY_GEN"; + t[CKM_JUNIPER_ECB128] = "CKM_JUNIPER_ECB128"; + t[CKM_JUNIPER_CBC128] = "CKM_JUNIPER_CBC128"; + t[CKM_JUNIPER_COUNTER] = "CKM_JUNIPER_COUNTER"; + t[CKM_JUNIPER_SHUFFLE] = "CKM_JUNIPER_SHUFFLE"; + t[CKM_JUNIPER_WRAP] = "CKM_JUNIPER_WRAP"; + t[CKM_FASTHASH] = "CKM_FASTHASH"; + t[CKM_AES_KEY_GEN] = "CKM_AES_KEY_GEN"; + t[CKM_AES_ECB] = "CKM_AES_ECB"; + t[CKM_AES_CBC] = "CKM_AES_CBC"; + t[CKM_AES_MAC] = "CKM_AES_MAC"; + t[CKM_AES_MAC_GENERAL] = "CKM_AES_MAC_GENERAL"; + t[CKM_AES_CBC_PAD] = "CKM_AES_CBC_PAD"; + t[CKM_AES_CTR] = "CKM_AES_CTR"; + t[CKM_AES_GCM] = "CKM_AES_GCM"; + t[CKM_AES_CCM] = "CKM_AES_CCM"; + t[CKM_AES_CTS] = "CKM_AES_CTS"; + t[CKM_AES_CMAC] = "CKM_AES_CMAC"; + t[CKM_AES_CMAC_GENERAL] = "CKM_AES_CMAC_GENERAL"; + t[CKM_AES_XCBC_MAC] = "CKM_AES_XCBC_MAC"; + t[CKM_AES_XCBC_MAC_96] = "CKM_AES_XCBC_MAC_96"; + t[CKM_AES_GMAC] = "CKM_AES_GMAC"; + t[CKM_BLOWFISH_KEY_GEN] = "CKM_BLOWFISH_KEY_GEN"; + t[CKM_BLOWFISH_CBC] = "CKM_BLOWFISH_CBC"; + t[CKM_TWOFISH_KEY_GEN] = "CKM_TWOFISH_KEY_GEN"; + t[CKM_TWOFISH_CBC] = "CKM_TWOFISH_CBC"; + t[CKM_BLOWFISH_CBC_PAD] = "CKM_BLOWFISH_CBC_PAD"; + t[CKM_TWOFISH_CBC_PAD] = "CKM_TWOFISH_CBC_PAD"; + t[CKM_DES_ECB_ENCRYPT_DATA] = "CKM_DES_ECB_ENCRYPT_DATA"; + t[CKM_DES_CBC_ENCRYPT_DATA] = "CKM_DES_CBC_ENCRYPT_DATA"; + t[CKM_DES3_ECB_ENCRYPT_DATA] = "CKM_DES3_ECB_ENCRYPT_DATA"; + t[CKM_DES3_CBC_ENCRYPT_DATA] = "CKM_DES3_CBC_ENCRYPT_DATA"; + t[CKM_AES_ECB_ENCRYPT_DATA] = "CKM_AES_ECB_ENCRYPT_DATA"; + t[CKM_AES_CBC_ENCRYPT_DATA] = "CKM_AES_CBC_ENCRYPT_DATA"; + t[CKM_GOSTR3410_KEY_PAIR_GEN] = "CKM_GOSTR3410_KEY_PAIR_GEN"; + t[CKM_GOSTR3410] = "CKM_GOSTR3410"; + t[CKM_GOSTR3410_WITH_GOSTR3411] = "CKM_GOSTR3410_WITH_GOSTR3411"; + t[CKM_GOSTR3410_KEY_WRAP] = "CKM_GOSTR3410_KEY_WRAP"; + t[CKM_GOSTR3410_DERIVE] = "CKM_GOSTR3410_DERIVE"; + t[CKM_GOSTR3411] = "CKM_GOSTR3411"; + t[CKM_GOSTR3411_HMAC] = "CKM_GOSTR3411_HMAC"; + t[CKM_GOST28147_KEY_GEN] = "CKM_GOST28147_KEY_GEN"; + t[CKM_GOST28147_ECB] = "CKM_GOST28147_ECB"; + t[CKM_GOST28147] = "CKM_GOST28147"; + t[CKM_GOST28147_MAC] = "CKM_GOST28147_MAC"; + t[CKM_GOST28147_KEY_WRAP] = "CKM_GOST28147_KEY_WRAP"; + t[CKM_DSA_PARAMETER_GEN] = "CKM_DSA_PARAMETER_GEN"; + t[CKM_DH_PKCS_PARAMETER_GEN] = "CKM_DH_PKCS_PARAMETER_GEN"; + t[CKM_X9_42_DH_PARAMETER_GEN] = "CKM_X9_42_DH_PARAMETER_GEN"; + t[CKM_DSA_PROBABLISTIC_PARAMETER_GEN] = "CKM_DSA_PROBABLISTIC_PARAMETER_GEN"; + t[CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN] = "CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN"; + t[CKM_AES_OFB] = "CKM_AES_OFB"; + t[CKM_AES_CFB64] = "CKM_AES_CFB64"; + t[CKM_AES_CFB8] = "CKM_AES_CFB8"; + t[CKM_AES_CFB128] = "CKM_AES_CFB128"; + t[CKM_AES_CFB1] = "CKM_AES_CFB1"; + t[CKM_AES_KEY_WRAP] = "CKM_AES_KEY_WRAP"; + t[CKM_AES_KEY_WRAP_PAD] = "CKM_AES_KEY_WRAP_PAD"; + t[CKM_RSA_PKCS_TPM_1_1] = "CKM_RSA_PKCS_TPM_1_1"; + t[CKM_RSA_PKCS_OAEP_TPM_1_1] = "CKM_RSA_PKCS_OAEP_TPM_1_1"; +} + +void fill_CKO_table(std::map<unsigned long, std::string> &t) +{ + t[CKO_DATA] = "CKO_DATA"; + t[CKO_CERTIFICATE] = "CKO_CERTIFICATE"; + t[CKO_PUBLIC_KEY] = "CKO_PUBLIC_KEY"; + t[CKO_PRIVATE_KEY] = "CKO_PRIVATE_KEY"; + t[CKO_SECRET_KEY] = "CKO_SECRET_KEY"; + t[CKO_HW_FEATURE] = "CKO_HW_FEATURE"; + t[CKO_DOMAIN_PARAMETERS] = "CKO_DOMAIN_PARAMETERS"; + t[CKO_MECHANISM] = "CKO_MECHANISM"; + t[CKO_OTP_KEY] = "CKO_OTP_KEY"; +} + +void fill_CKH_table(std::map<unsigned long, std::string> &t) +{ + t[CKH_MONOTONIC_COUNTER] = "CKH_MONOTONIC_COUNTER"; + t[CKH_CLOCK] = "CKH_CLOCK"; + t[CKH_USER_INTERFACE] = "CKH_USER_INTERFACE"; +} + +void fill_CKK_table(std::map<unsigned long, std::string> &t) +{ + t[CKK_RSA] = "CKK_RSA"; + t[CKK_DSA] = "CKK_DSA"; + t[CKK_DH] = "CKK_DH"; + t[CKK_EC] = "CKK_EC"; + t[CKK_X9_42_DH] = "CKK_X9_42_DH"; + t[CKK_KEA] = "CKK_KEA"; + t[CKK_GENERIC_SECRET] = "CKK_GENERIC_SECRET"; + t[CKK_RC2] = "CKK_RC2"; + t[CKK_RC4] = "CKK_RC4"; + t[CKK_DES] = "CKK_DES"; + t[CKK_DES2] = "CKK_DES2"; + t[CKK_DES3] = "CKK_DES3"; + t[CKK_CAST] = "CKK_CAST"; + t[CKK_CAST3] = "CKK_CAST3"; + t[CKK_CAST128] = "CKK_CAST128"; + t[CKK_RC5] = "CKK_RC5"; + t[CKK_IDEA] = "CKK_IDEA"; + t[CKK_SKIPJACK] = "CKK_SKIPJACK"; + t[CKK_BATON] = "CKK_BATON"; + t[CKK_JUNIPER] = "CKK_JUNIPER"; + t[CKK_CDMF] = "CKK_CDMF"; + t[CKK_AES] = "CKK_AES"; + t[CKK_BLOWFISH] = "CKK_BLOWFISH"; + t[CKK_TWOFISH] = "CKK_TWOFISH"; + t[CKK_SECURID] = "CKK_SECURID"; + t[CKK_HOTP] = "CKK_HOTP"; + t[CKK_ACTI] = "CKK_ACTI"; + t[CKK_CAMELLIA] = "CKK_CAMELLIA"; + t[CKK_ARIA] = "CKK_ARIA"; + t[CKK_MD5_HMAC] = "CKK_MD5_HMAC"; + t[CKK_SHA_1_HMAC] = "CKK_SHA_1_HMAC"; + t[CKK_RIPEMD128_HMAC] = "CKK_RIPEMD128_HMAC"; + t[CKK_RIPEMD160_HMAC] = "CKK_RIPEMD160_HMAC"; + t[CKK_SHA256_HMAC] = "CKK_SHA256_HMAC"; + t[CKK_SHA384_HMAC] = "CKK_SHA384_HMAC"; + t[CKK_SHA512_HMAC] = "CKK_SHA512_HMAC"; + t[CKK_SHA224_HMAC] = "CKK_SHA224_HMAC"; + t[CKK_SEED] = "CKK_SEED"; + t[CKK_GOSTR3410] = "CKK_GOSTR3410"; + t[CKK_GOSTR3411] = "CKK_GOSTR3411"; + t[CKK_GOST28147] = "CKK_GOST28147"; +} + +void fill_CKC_table(std::map<unsigned long, std::string> &t) +{ + t[CKC_X_509] = "CKC_X_509"; + t[CKC_X_509_ATTR_CERT] = "CKC_X_509_ATTR_CERT"; + t[CKC_WTLS] = "CKC_WTLS"; + t[CKC_OPENPGP] = "CKC_OPENPGP"; +} + +#endif // !_SOFTHSM_V2_TABLES_H diff --git a/SoftHSMv2/src/bin/keyconv/Makefile.am b/SoftHSMv2/src/bin/keyconv/Makefile.am new file mode 100644 index 0000000..b4268c2 --- /dev/null +++ b/SoftHSMv2/src/bin/keyconv/Makefile.am @@ -0,0 +1,26 @@ +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +AM_CPPFLAGS = -I$(srcdir)/../../lib/crypto \ + @CRYPTO_INCLUDES@ + +dist_man_MANS = softhsm2-keyconv.1 + +bin_PROGRAMS = softhsm2-keyconv + +softhsm2_keyconv_SOURCES = softhsm2-keyconv.cpp \ + base64.c +softhsm2_keyconv_LDADD = @CRYPTO_LIBS@ + +# Compile with OpenSSL support +if WITH_OPENSSL +softhsm2_keyconv_SOURCES += softhsm2-keyconv-ossl.cpp \ + ../../lib/crypto/OSSLComp.cpp +endif + +# Compile with Botan support +if WITH_BOTAN +softhsm2_keyconv_SOURCES += softhsm2-keyconv-botan.cpp +endif + +EXTRA_DIST = $(srcdir)/*.h \ + $(srcdir)/*.cpp diff --git a/SoftHSMv2/src/bin/keyconv/base64.c b/SoftHSMv2/src/bin/keyconv/base64.c new file mode 100644 index 0000000..3eb1201 --- /dev/null +++ b/SoftHSMv2/src/bin/keyconv/base64.c @@ -0,0 +1,311 @@ +/* $OpenBSD: base64.c,v 1.3 2002/06/09 08:13:07 todd Exp $ */ + +/* + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$ISC: base64.c,v 8.6 1999/01/08 19:25:18 vixie Exp $"; +#endif /* not lint */ + +#include <sys/types.h> +#ifndef _WIN32 +#include <sys/param.h> +#include <sys/socket.h> +#endif + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define Assert(Cond) if (!(Cond)) abort() + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + +int +b64_ntop(unsigned char const *src, size_t srclength, char *target, size_t targsize) { + size_t datalength = 0; + unsigned char input[3]; + unsigned char output[4]; + size_t i; + + while (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + Assert(output[0] < 64); + Assert(output[1] < 64); + Assert(output[2] < 64); + Assert(output[3] < 64); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + Assert(output[0] < 64); + Assert(output[1] < 64); + Assert(output[2] < 64); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + if (srclength == 1) + target[datalength++] = Pad64; + else + target[datalength++] = Base64[output[2]]; + target[datalength++] = Pad64; + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return (datalength); +} + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +int +b64_pton(char const *src, unsigned char *target, size_t targsize) { + int tarindex, state, ch; + char *pos; + + state = 0; + tarindex = 0; + + while ((ch = *src++) != '\0') { + if (isspace(ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if ((size_t)tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if ((size_t)tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + target[tarindex+1] = ((pos - Base64) & 0x0f) + << 4 ; + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if ((size_t)tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + target[tarindex+1] = ((pos - Base64) & 0x03) + << 6; + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if ((size_t)tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + default: + abort(); + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = *src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for ((void)NULL; ch != '\0'; ch = *src++) + if (!isspace(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = *src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for ((void)NULL; ch != '\0'; ch = *src++) + if (!isspace(ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} diff --git a/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv-botan.cpp b/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv-botan.cpp new file mode 100644 index 0000000..cb5700f --- /dev/null +++ b/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv-botan.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + softhsm2-keyconv-botan.cpp + + Code specific for Botan + *****************************************************************************/ + +#include <config.h> +#define KEYCONV_BOTAN +#include "softhsm2-keyconv.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <iostream> +#include <fstream> + +#include <botan/init.h> +#include <botan/auto_rng.h> +#include <botan/pkcs8.h> +#include <botan/rsa.h> +#include <botan/dsa.h> +#include <botan/bigint.h> +#include <botan/version.h> + +// Init Botan +void crypto_init() +{ + Botan::LibraryInitializer::initialize(); +} + +// Final Botan +void crypto_final() +{ + Botan::LibraryInitializer::deinitialize(); +} + +// Save the RSA key as a PKCS#8 file +int save_rsa_pkcs8(char* out_path, char* file_pin, key_material_t* pkey) +{ + int result = 0; + Botan::Private_Key* priv_key = NULL; + Botan::AutoSeeded_RNG* rng = NULL; + Botan::BigInt bigE, bigP, bigQ, bigN, bigD; + + // See if the key material was found. + if + ( + pkey[TAG_MODULUS].size <= 0 || + pkey[TAG_PUBEXP].size <= 0 || + pkey[TAG_PRIVEXP].size <= 0 || + pkey[TAG_PRIME1].size <= 0 || + pkey[TAG_PRIME2].size <= 0 + ) + { + fprintf(stderr, "ERROR: Some parts of the key material is missing in the input file.\n"); + return 1; + } + + bigE = Botan::BigInt((Botan::byte*)pkey[TAG_PUBEXP].big, pkey[TAG_PUBEXP].size); + bigP = Botan::BigInt((Botan::byte*)pkey[TAG_PRIME1].big, pkey[TAG_PRIME1].size); + bigQ = Botan::BigInt((Botan::byte*)pkey[TAG_PRIME2].big, pkey[TAG_PRIME2].size); + bigN = Botan::BigInt((Botan::byte*)pkey[TAG_MODULUS].big, pkey[TAG_MODULUS].size); + bigD = Botan::BigInt((Botan::byte*)pkey[TAG_PRIVEXP].big, pkey[TAG_PRIVEXP].size); + + rng = new Botan::AutoSeeded_RNG(); + + try + { +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,34) + priv_key = new Botan::RSA_PrivateKey(bigP, bigQ, bigE, bigD, bigN); +#else + priv_key = new Botan::RSA_PrivateKey(*rng, bigP, bigQ, bigE, bigD, bigN); +#endif + } + catch(std::exception& e) + { + fprintf(stderr, "%s\n", e.what()); + fprintf(stderr, "ERROR: Could not extract the private key from the file.\n"); + delete rng; + return 1; + } + + std::ofstream priv_file(out_path); + if (!priv_file.is_open()) + { + fprintf(stderr, "ERROR: Could not open file for output.\n"); + delete rng; + delete priv_key; + return 1; + } + + try + { + if (file_pin == NULL) + { + priv_file << Botan::PKCS8::PEM_encode(*priv_key); + } + else + { +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + priv_file << Botan::PKCS8::PEM_encode(*priv_key, *rng, file_pin, std::chrono::milliseconds(300), "PBE-PKCS5v15(MD5,DES/CBC)"); +#else + priv_file << Botan::PKCS8::PEM_encode(*priv_key, *rng, file_pin, "PBE-PKCS5v15(MD5,DES/CBC)"); +#endif + } + + printf("The key has been written to %s\n", out_path); + } + catch(std::exception& e) + { + fprintf(stderr, "%s\n", e.what()); + fprintf(stderr, "ERROR: Could not write to file.\n"); + result = 1; + } + + delete rng; + delete priv_key; + priv_file.close(); + + return result; +} + +// Save the DSA key as a PKCS#8 file +int save_dsa_pkcs8(char* out_path, char* file_pin, key_material_t* pkey) +{ + int result = 0; + Botan::Private_Key* priv_key = NULL; + Botan::AutoSeeded_RNG* rng = NULL; + Botan::BigInt bigDP, bigDQ, bigDG, bigDX; + + // See if the key material was found. + if + ( + pkey[TAG_PRIME].size <= 0 || + pkey[TAG_SUBPRIME].size <= 0 || + pkey[TAG_BASE].size <= 0 || + pkey[TAG_PRIVVAL].size <= 0 + ) + { + fprintf(stderr, "ERROR: Some parts of the key material is missing in the input file.\n"); + return 1; + } + + bigDP = Botan::BigInt((Botan::byte*)pkey[TAG_PRIME].big, pkey[TAG_PRIME].size); + bigDQ = Botan::BigInt((Botan::byte*)pkey[TAG_SUBPRIME].big, pkey[TAG_SUBPRIME].size); + bigDG = Botan::BigInt((Botan::byte*)pkey[TAG_BASE].big, pkey[TAG_BASE].size); + bigDX = Botan::BigInt((Botan::byte*)pkey[TAG_PRIVVAL].big, pkey[TAG_PRIVVAL].size); + + rng = new Botan::AutoSeeded_RNG(); + + try + { + priv_key = new Botan::DSA_PrivateKey(*rng, Botan::DL_Group(bigDP, bigDQ, bigDG), bigDX); + } + catch (std::exception& e) + { + fprintf(stderr, "%s\n", e.what()); + fprintf(stderr, "ERROR: Could not extract the private key from the file.\n"); + delete rng; + return 1; + } + + std::ofstream priv_file(out_path); + if (!priv_file.is_open()) + { + fprintf(stderr, "ERROR: Could not open file for output.\n"); + delete rng; + delete priv_key; + return 1; + } + + try + { + if (file_pin == NULL) + { + priv_file << Botan::PKCS8::PEM_encode(*priv_key); + } + else + { +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + priv_file << Botan::PKCS8::PEM_encode(*priv_key, *rng, file_pin, std::chrono::milliseconds(300), "PBE-PKCS5v15(MD5,DES/CBC)"); +#else + priv_file << Botan::PKCS8::PEM_encode(*priv_key, *rng, file_pin, "PBE-PKCS5v15(MD5,DES/CBC)"); +#endif + } + + printf("The key has been written to %s\n", out_path); + } + catch (std::exception& e) + { + fprintf(stderr, "%s\n", e.what()); + fprintf(stderr, "ERROR: Could not write to file.\n"); + result = 1; + } + + delete rng; + delete priv_key; + priv_file.close(); + + return result; +} diff --git a/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv-ossl.cpp b/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv-ossl.cpp new file mode 100644 index 0000000..a5cd8eb --- /dev/null +++ b/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv-ossl.cpp @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + softhsm2-keyconv-ossl.cpp + + Code specific for OpenSSL + *****************************************************************************/ + +#include <config.h> +#define KEYCONV_OSSL +#include "softhsm2-keyconv.h" +#include "OSSLComp.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <iostream> +#include <fstream> + +#include <openssl/pem.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/pkcs12.h> +#include <openssl/dsa.h> +#include <openssl/rsa.h> + +// Init OpenSSL +void crypto_init() +{ + OpenSSL_add_all_algorithms(); +#ifdef WITH_FIPS + if (!FIPS_mode_set(1)) + { + fprintf(stderr, "ERROR: can't enter into FIPS mode.\n"); + exit(0); + } +#endif +} + +// Final OpenSSL +void crypto_final() +{ + EVP_cleanup(); + CRYPTO_cleanup_all_ex_data(); +} + +// Save the RSA key as a PKCS#8 file +int save_rsa_pkcs8(char* out_path, char* file_pin, key_material_t* pkey) +{ + RSA* rsa = NULL; + EVP_PKEY* ossl_pkey = NULL; + PKCS8_PRIV_KEY_INFO* p8inf = NULL; + BIO* out = NULL; + X509_SIG* p8 = NULL; + int result = 0; + + // See if the key material was found. + if + ( + pkey[TAG_MODULUS].size <= 0 || + pkey[TAG_PUBEXP].size <= 0 || + pkey[TAG_PRIVEXP].size <= 0 || + pkey[TAG_PRIME1].size <= 0 || + pkey[TAG_PRIME2].size <= 0 || + pkey[TAG_EXP1].size <= 0 || + pkey[TAG_EXP2].size <= 0 || + pkey[TAG_COEFF].size <= 0 + ) + { + fprintf(stderr, "ERROR: Some parts of the key material is missing in the input file.\n"); + return 1; + } + + rsa = RSA_new(); + BIGNUM* bn_p = BN_bin2bn((unsigned char*)pkey[TAG_PRIME1].big, pkey[TAG_PRIME1].size, NULL); + BIGNUM* bn_q = BN_bin2bn((unsigned char*)pkey[TAG_PRIME2].big, pkey[TAG_PRIME2].size, NULL); + BIGNUM* bn_d = BN_bin2bn((unsigned char*)pkey[TAG_PRIVEXP].big, pkey[TAG_PRIVEXP].size, NULL); + BIGNUM* bn_n = BN_bin2bn((unsigned char*)pkey[TAG_MODULUS].big, pkey[TAG_MODULUS].size, NULL); + BIGNUM* bn_e = BN_bin2bn((unsigned char*)pkey[TAG_PUBEXP].big, pkey[TAG_PUBEXP].size, NULL); + BIGNUM* bn_dmp1 = BN_bin2bn((unsigned char*)pkey[TAG_EXP1].big, pkey[TAG_EXP1].size, NULL); + BIGNUM* bn_dmq1 = BN_bin2bn((unsigned char*)pkey[TAG_EXP2].big, pkey[TAG_EXP2].size, NULL); + BIGNUM* bn_iqmp = BN_bin2bn((unsigned char*)pkey[TAG_COEFF].big, pkey[TAG_COEFF].size, NULL); + RSA_set0_factors(rsa, bn_p, bn_q); + RSA_set0_crt_params(rsa, bn_dmp1, bn_dmq1, bn_iqmp); + RSA_set0_key(rsa, bn_n, bn_e, bn_d); + + ossl_pkey = EVP_PKEY_new(); + + // Convert RSA to EVP_PKEY + if (!EVP_PKEY_set1_RSA(ossl_pkey, rsa)) + { + fprintf(stderr, "ERROR: Could not convert RSA key to EVP_PKEY.\n"); + RSA_free(rsa); + EVP_PKEY_free(ossl_pkey); + return 1; + } + RSA_free(rsa); + + // Convert EVP_PKEY to PKCS#8 + if (!(p8inf = EVP_PKEY2PKCS8(ossl_pkey))) + { + fprintf(stderr, "ERROR: Could not convert EVP_PKEY to PKCS#8.\n"); + EVP_PKEY_free(ossl_pkey); + return 1; + } + EVP_PKEY_free(ossl_pkey); + + // Open output file + if (!(out = BIO_new_file (out_path, "wb"))) + { + fprintf(stderr, "ERROR: Could not open the output file.\n"); + PKCS8_PRIV_KEY_INFO_free(p8inf); + return 1; + } + + // Write to disk + if (file_pin == NULL) + { + PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8inf); + printf("The key has been written to %s\n", out_path); + } + else + { + // Encrypt p8 + if (!(p8 = PKCS8_encrypt(NID_pbeWithMD5AndDES_CBC, NULL, + file_pin, strlen(file_pin), NULL, + 0, PKCS12_DEFAULT_ITER, p8inf))) + { + fprintf(stderr, "ERROR: Could not encrypt the PKCS#8 file\n"); + result = 1; + } + else + { + PEM_write_bio_PKCS8(out, p8); + X509_SIG_free(p8); + printf("The key has been written to %s\n", out_path); + } + } + + PKCS8_PRIV_KEY_INFO_free(p8inf); + BIO_free_all(out); + + return result; +} + +// Save the DSA key as a PKCS#8 file +int save_dsa_pkcs8(char* out_path, char* file_pin, key_material_t* pkey) +{ + DSA* dsa = NULL; + EVP_PKEY* ossl_pkey = NULL; + PKCS8_PRIV_KEY_INFO* p8inf = NULL; + BIO* out = NULL; + X509_SIG* p8 = NULL; + int result = 0; + + // See if the key material was found. + if + ( + pkey[TAG_PRIME].size <= 0 || + pkey[TAG_SUBPRIME].size <= 0 || + pkey[TAG_BASE].size <= 0 || + pkey[TAG_PRIVVAL].size <= 0 || + pkey[TAG_PUBVAL].size <= 0 + ) + { + fprintf(stderr, "ERROR: Some parts of the key material is missing in the input file.\n"); + return 1; + } + + dsa = DSA_new(); + BIGNUM* bn_p = BN_bin2bn((unsigned char*)pkey[TAG_PRIME].big, pkey[TAG_PRIME].size, NULL); + BIGNUM* bn_q = BN_bin2bn((unsigned char*)pkey[TAG_SUBPRIME].big, pkey[TAG_SUBPRIME].size, NULL); + BIGNUM* bn_g = BN_bin2bn((unsigned char*)pkey[TAG_BASE].big, pkey[TAG_BASE].size, NULL); + BIGNUM* bn_priv_key = BN_bin2bn((unsigned char*)pkey[TAG_PRIVVAL].big, pkey[TAG_PRIVVAL].size, NULL); + BIGNUM* bn_pub_key = BN_bin2bn((unsigned char*)pkey[TAG_PUBVAL].big, pkey[TAG_PUBVAL].size, NULL); + + DSA_set0_pqg(dsa, bn_p, bn_q, bn_g); + DSA_set0_key(dsa, bn_pub_key, bn_priv_key); + + ossl_pkey = EVP_PKEY_new(); + + // Convert DSA to EVP_PKEY + if (!EVP_PKEY_set1_DSA(ossl_pkey, dsa)) + { + fprintf(stderr, "ERROR: Could not convert DSA key to EVP_PKEY.\n"); + DSA_free(dsa); + EVP_PKEY_free(ossl_pkey); + return 1; + } + DSA_free(dsa); + + // Convert EVP_PKEY to PKCS#8 + if (!(p8inf = EVP_PKEY2PKCS8(ossl_pkey))) + { + fprintf(stderr, "ERROR: Could not convert EVP_PKEY to PKCS#8.\n"); + EVP_PKEY_free(ossl_pkey); + return 1; + } + EVP_PKEY_free(ossl_pkey); + + // Open output file + if (!(out = BIO_new_file (out_path, "wb"))) + { + fprintf(stderr, "ERROR: Could not open the output file.\n"); + PKCS8_PRIV_KEY_INFO_free(p8inf); + return 1; + } + + // Write to disk + if (file_pin == NULL) + { + PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8inf); + printf("The key has been written to %s\n", out_path); + } + else + { + // Encrypt p8 + if (!(p8 = PKCS8_encrypt(NID_pbeWithMD5AndDES_CBC, NULL, + file_pin, strlen(file_pin), NULL, + 0, PKCS12_DEFAULT_ITER, p8inf))) + { + fprintf(stderr, "ERROR: Could not encrypt the PKCS#8 file\n"); + result = 1; + } + else + { + PEM_write_bio_PKCS8(out, p8); + X509_SIG_free(p8); + printf("The key has been written to %s\n", out_path); + } + } + + PKCS8_PRIV_KEY_INFO_free(p8inf); + BIO_free_all(out); + + return result; +} diff --git a/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.1 b/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.1 new file mode 100644 index 0000000..b716bc8 --- /dev/null +++ b/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.1 @@ -0,0 +1,63 @@ +.TH SOFTHSM2-KEYCONV 1 "20 March 2014" "SoftHSM" +.SH NAME +softhsm2-keyconv \- converting from BIND to PKCS#8 key file format +.SH SYNOPSIS +.B softhsm2-keyconv +.B \-\-in +.I path +.B \-\-out +.I path +.RB [ \-\-pin +.IR PIN ] +.SH DESCRIPTION +.B softhsm2-keyconv +can convert BIND .private-key files to the PKCS#8 file format. +This is so that you can import the PKCS#8 file into +libsofthsm using the command +.BR softhsm2\-util . +If you have another file format, then +.B openssl +probably can help you to convert it into the PKCS#8 file format. +.SH OPTIONS +.B \-\-help\fR, \fB\-h\fR +Shows the help screen. +.TP +.B \-\-in \fIpath\fR +The +.I path +to the input file. +.TP +.B \-\-out \fIpath\fR +The +.I path +to the output file. +.TP +.B \-\-pin \fIPIN\fR +The +.I PIN +will be used to encrypt the PKCS#8 file. +If not given then the PKCS#8 file will be unencrypted. +.TP +.B \-\-version\fR, \fB\-v\fR +Show the version info. +.SH EXAMPLES +The following command can be used to convert a BIND .private-key file to a PKCS#8 file: +.LP +.RS +.nf +softhsm2-keyconv \-\-in Kexample.com.+007+05474.private \\ +.ti +0.7i +\-\-out rsa.pem +.fi +.RE +.LP +.SH AUTHORS +Written by Rickard Bellgrim, Francis Dupont, René Post, and Roland van Rijswijk. +.SH "SEE ALSO" +.IR softhsm2-migrate (1), +.IR softhsm2-util (1), +.IR softhsm2.conf (5), +.IR openssl (1), +.IR named (1), +.IR dnssec-keygen (1), +.IR dnssec-signzone (1) diff --git a/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.cpp b/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.cpp new file mode 100644 index 0000000..aeb75c3 --- /dev/null +++ b/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.cpp @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/************************************************************ +* +* softhsm2-keyconv +* +* This program is for converting from BIND .private-key +* format to PKCS#8 key file format. So that keys can be +* imported from BIND to SoftHSM. +* +* Some of the design/code is from keyconv.c written by +* Hakan Olsson and Jakob Schlyter in 2000 and 2001. +* +************************************************************/ + +#include <config.h> +#include "softhsm2-keyconv.h" + +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <string.h> +#ifndef _WIN32 +#include <unistd.h> +#else +#include <io.h> +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#define open _open +#define close _close +#endif +#include <iostream> +#include <fstream> +#include <stdint.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +void usage() +{ + printf("Converting from BIND .private-key format to PKCS#8 key file format.\n"); + printf("Usage: softhsm2-keyconv [OPTIONS]\n"); + printf("Options:\n"); + printf(" -h Shows this help screen.\n"); + printf(" --help Shows this help screen.\n"); + printf(" --in <path> The path to the input file.\n"); + printf(" --out <path> The path to the output file.\n"); + printf(" --pin <PIN> To encrypt PKCS#8 file. Optional.\n"); + printf(" -v Show version info.\n"); + printf(" --version Show version info.\n"); +} + +// Give a number to each option +enum { + OPT_HELP = 0x100, + OPT_IN, + OPT_OUT, + OPT_PIN, + OPT_VERSION +}; + +// Define the options +static const struct option long_options[] = { + { "help", 0, NULL, OPT_HELP }, + { "in", 1, NULL, OPT_IN }, + { "out", 1, NULL, OPT_OUT }, + { "pin", 1, NULL, OPT_PIN }, + { "version", 0, NULL, OPT_VERSION }, + { NULL, 0, NULL, 0 } +}; + +int main(int argc, char* argv[]) +{ + int option_index = 0; + int opt, result; + + char* in_path = NULL; + char* out_path = NULL; + char* file_pin = NULL; + + if (argc == 1) + { + usage(); + exit(0); + } + + while ((opt = getopt_long(argc, argv, "hv", long_options, &option_index)) != -1) + { + switch (opt) + { + case OPT_IN: + in_path = optarg; + break; + case OPT_OUT: + out_path = optarg; + break; + case OPT_PIN: + file_pin = optarg; + break; + case OPT_VERSION: + case 'v': + printf("%s\n", PACKAGE_VERSION); + exit(0); + break; + case OPT_HELP: + case 'h': + default: + usage(); + exit(0); + break; + } + } + + // We should convert to PKCS#8 + result = to_pkcs8(in_path, out_path, file_pin); + + return result; +} + +// Convert from BIND to PKCS#8 +int to_pkcs8(char* in_path, char* out_path, char* file_pin) +{ + FILE* file_pointer = NULL; + char line[MAX_LINE], data[MAX_LINE]; + char* value_pointer = NULL; + int lineno = 0, m, n, error = 0, found, algorithm = DNS_KEYALG_ERROR, data_length; + uint32_t bitfield = 0; + key_material_t pkey[TAG_MAX]; + + if (in_path == NULL) + { + fprintf(stderr, "ERROR: A path to the input file must be supplied. Use --in <path>\n"); + return 1; + } + + if (out_path == NULL) + { + fprintf(stderr, "ERROR: A path to the output file must be supplied. Use --out <path>\n"); + return 1; + } + + file_pointer = fopen(in_path, "r"); + if (file_pointer == NULL) + { + fprintf(stderr, "ERROR: Could not open input file %.100s for reading.\n", in_path); + return 1; + } + + // Loop over all of the lines + while (fgets(line, MAX_LINE, file_pointer) != NULL) + { + lineno++; + + // Find the current text field in the BIND file. + for (m = 0, found = -1; found == -1 && file_tags[m]; m++) + { + if (strncasecmp(line, file_tags[m], strlen(file_tags[m])) == 0) + { + found = m; + } + } + + // The text files is not recognized. + if (found == -1) + { + fprintf(stderr, "ERROR: Unrecognized input line %i\n", lineno); + fprintf(stderr, "ERROR: --> %s", line); + continue; + } + + // Point to the data for this text field. + value_pointer = line + strlen(file_tags[found]) + 1; + + // Continue if we are at the end of the string + if (*value_pointer == 0) + { + continue; + } + + // Check that we do not get duplicates. + if (bitfield & (1 << found)) + { + fprintf(stderr, "ERROR: Duplicate \"%s\" field, line %i - ignored\n", + file_tags[found], lineno); + continue; + } + bitfield |= (1 << found); + + // Handle the data for this text field. + switch (found) + { + case TAG_VERSION: + if (sscanf(value_pointer, "v%i.%i", &m, &n) != 2) + { + fprintf(stderr, "ERROR: Invalid/unknown version string " + "(%.100s).\n", value_pointer); + error = 1; + break; + } + if (m > FILE_MAJOR_VERSION || (m == FILE_MAJOR_VERSION && n > FILE_MINOR_VERSION)) + { + fprintf(stderr, "ERROR: Cannot parse this version of file format, " + "v%i.%i.\n", m, n); + error = 1; + } + break; + case TAG_ALGORITHM: + algorithm = strtol(value_pointer, NULL, 10); + break; + // RSA + case TAG_MODULUS: + case TAG_PUBEXP: + case TAG_PRIVEXP: + case TAG_PRIME1: + case TAG_PRIME2: + case TAG_EXP1: + case TAG_EXP2: + case TAG_COEFF: + // DSA + case TAG_PRIME: + case TAG_SUBPRIME: + case TAG_BASE: + case TAG_PRIVVAL: + case TAG_PUBVAL: + data_length = b64_pton(value_pointer, (unsigned char*)data, MAX_LINE); + if (data_length == -1) + { + error = 1; + fprintf(stderr, "ERROR: Could not parse the base64 string on line %i.\n", lineno); + } + else + { + pkey[found].big = malloc(data_length); + if (!pkey[found].big) + { + fprintf(stderr, "ERROR: Could not allocate memory.\n"); + error = 1; + break; + } + memcpy(pkey[found].big, data, data_length); + pkey[found].size = data_length; + } + break; + // Do not need these + case TAG_CREATED: + case TAG_PUBLISH: + case TAG_ACTIVATE: + default: + break; + } + } + + fclose(file_pointer); + + // Something went wrong. Clean up and quit. + if (error) + { + free_key_material(pkey); + return error; + } + + // Create and set file permissions if the file does not exist. + int fd = open(out_path, O_CREAT, S_IRUSR | S_IWUSR); + if (fd == -1) + { + fprintf(stderr, "ERROR: Could not open the output file: %s (errno %i)\n", + out_path, errno); + free_key_material(pkey); + return 1; + } + ::close(fd); + + crypto_init(); + + // Save the the key to the disk + switch (algorithm) + { + case DNS_KEYALG_ERROR: + fprintf(stderr, "ERROR: The algorithm %i was not given in the file.\n", + algorithm); + error = 1; + break; + case DNS_KEYALG_RSAMD5: + case DNS_KEYALG_RSASHA1: + case DNS_KEYALG_RSASHA1_NSEC3_SHA1: + case DNS_KEYALG_RSASHA256: + case DNS_KEYALG_RSASHA512: + error = save_rsa_pkcs8(out_path, file_pin, pkey); + break; + case DNS_KEYALG_DSA: + case DNS_KEYALG_DSA_NSEC3_SHA1: + error = save_dsa_pkcs8(out_path, file_pin, pkey); + break; + case DNS_KEYALG_ECC: + case DNS_KEYALG_ECC_GOST: + default: + fprintf(stderr, "ERROR: The algorithm %i is not supported.\n", + algorithm); + error = 1; + break; + } + + crypto_final(); + free_key_material(pkey); + + return error; +} + +// Free allocated memory +void free_key_material(key_material_t* pkey) +{ + int i; + + if (!pkey) + { + return; + } + + for (i = 0; i < TAG_MAX; i++) + { + if (pkey[i].big) + { + free(pkey[i].big); + } + } +} diff --git a/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.h b/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.h new file mode 100644 index 0000000..fdeb719 --- /dev/null +++ b/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SOFTHSM_V2_SOFTHSM2_KEYCONV_H +#define _SOFTHSM_V2_SOFTHSM2_KEYCONV_H 1 + +#include <stdlib.h> + +typedef struct key_material_t { + unsigned long size; + void* big; + key_material_t() { + size = 0; + big = NULL; + } +} key_material_t; + +// Main functions + +void usage(); +int to_pkcs8(char* in_path, char* out_path, char* file_pin); + +// Support functions + +int save_rsa_pkcs8(char* out_path, char* file_pin, key_material_t* pkey); +int save_dsa_pkcs8(char* out_path, char* file_pin, key_material_t* pkey); +void free_key_material(key_material_t* pkey); +void crypto_init(); +void crypto_final(); + +// base64.c prototypes + +#ifdef __cplusplus +extern "C" { +#endif +int b64_pton(const char* , unsigned char*, size_t); +int b64_ntop(const unsigned char*, size_t, char*, size_t); +#ifdef __cplusplus +} +#endif + +// The BIND file version number. +#define FILE_MAJOR_VERSION 1 +#define FILE_MINOR_VERSION 3 + +// Key algorithm number +#define DNS_KEYALG_ERROR -1 +#define DNS_KEYALG_RSAMD5 1 +#define DNS_KEYALG_DSA 3 +#define DNS_KEYALG_ECC 4 +#define DNS_KEYALG_RSASHA1 5 +#define DNS_KEYALG_DSA_NSEC3_SHA1 6 +#define DNS_KEYALG_RSASHA1_NSEC3_SHA1 7 +#define DNS_KEYALG_RSASHA256 8 +#define DNS_KEYALG_RSASHA512 10 +#define DNS_KEYALG_ECC_GOST 12 + +// Maximum number of lines / line length +#define MAX_LINE 4096 + +// The text fields supported +#if !defined(KEYCONV_BOTAN) && !defined(KEYCONV_OSSL) +static const char* file_tags[] = { + "Private-key-format:", + "Algorithm:", + "Modulus:", + "PublicExponent:", + "PrivateExponent:", + "Prime1:", + "Prime2:", + "Exponent1:", + "Exponent2:", + "Coefficient:", + "Prime(p):", + "Private_value(x):", + "Public_value(y):", + "Subprime(q):", + "Base(g):", + "Created:", + "Publish:", + "Activate:", + NULL +}; +#endif + +// The number of each text field. +// Must match the tags above. +enum FILE_TAGS { + TAG_VERSION = 0, + TAG_ALGORITHM, + TAG_MODULUS, + TAG_PUBEXP, + TAG_PRIVEXP, + TAG_PRIME1, + TAG_PRIME2, + TAG_EXP1, + TAG_EXP2, + TAG_COEFF, + TAG_PRIME, + TAG_PRIVVAL, + TAG_PUBVAL, + TAG_SUBPRIME, + TAG_BASE, + TAG_CREATED, + TAG_PUBLISH, + TAG_ACTIVATE, + // So we know how long this list is + TAG_MAX +}; + +#endif /* _SOFTHSM_V2_SOFTHSM2_KEYCONV_H */ diff --git a/SoftHSMv2/src/bin/migrate/Makefile.am b/SoftHSMv2/src/bin/migrate/Makefile.am new file mode 100644 index 0000000..020c6a7 --- /dev/null +++ b/SoftHSMv2/src/bin/migrate/Makefile.am @@ -0,0 +1,20 @@ +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +AM_CPPFLAGS = -I$(srcdir)/../../lib/pkcs11 \ + -I$(srcdir)/../common \ + @SQLITE3_INCLUDES@ + +dist_man_MANS = softhsm2-migrate.1 + +bin_PROGRAMS = softhsm2-migrate + +AUTOMAKE_OPTIONS = subdir-objects + +softhsm2_migrate_SOURCES = softhsm2-migrate.cpp \ + ../common/findslot.cpp \ + ../common/getpw.cpp \ + ../common/library.cpp +softhsm2_migrate_LDADD = @SQLITE3_LIBS@ \ + @YIELD_LIB@ + +EXTRA_DIST = $(srcdir)/*.h diff --git a/SoftHSMv2/src/bin/migrate/softhsm2-migrate.1 b/SoftHSMv2/src/bin/migrate/softhsm2-migrate.1 new file mode 100644 index 0000000..65dc00c --- /dev/null +++ b/SoftHSMv2/src/bin/migrate/softhsm2-migrate.1 @@ -0,0 +1,67 @@ +.TH SOFTHSM2-MIGRATE 1 "20 April 2016" "SoftHSM" +.SH NAME +softhsm2-migrate \- SoftHSM v1 migration tool +.SH SYNOPSIS +.PP +.B softhsm2-migrate \-\-db +.I path +.B \-\-token +.I label +.RB [ \-\-pin +.I PIN +.B \-\-no\-public\-key] +.SH DESCRIPTION +.B softhsm2-migrate +is a tool that can migrate SoftHSM v1 databases to PKCS#11. +The default HSM is SoftHSM v2, but can be used with other +PKCS#11 libraries by using the option +.B \-\-module +.LP +.SH OPTIONS +.TP +.B \-\-db \fIpath\fR +The SoftHSM v1 database that is going to be migrated. +The location of the token database can be found in +the configuration file for SoftHSM v1. +.TP +.B \-\-help\fR, \fB\-h\fR +Show the help information. +.TP +.B \-\-module \fIpath\fR +Use another PKCS#11 library than SoftHSM. +.TP +.B \-\-no\-public\-key +Do not migrate the public key. +.TP +.B \-\-pin \fIPIN\fR +The +.I PIN +for the normal user. +.TP +.B \-\-serial \fInumber\fR +Will use the token with a matching serial number. +.TP +.B \-\-slot \fInumber\fR +The database will be migrated to this slot. +.TP +.B \-\-token \fIlabel\fR +Will use the token with a matching token label. +.TP +.B \-\-version\fR, \fB\-v\fR +Show the version info. +.SH EXAMPLE +.LP +A token database can be migrated with the following command: +.LP +.RS +.nf +softhsm2-migrate \-\-db /home/user/token.db \-\-token mytoken +.fi +.RE +.SH AUTHORS +Written by Rickard Bellgrim, Francis Dupont, René Post, and Roland van Rijswijk. +.LP +.SH "SEE ALSO" +.IR softhsm2-keyconv (1), +.IR softhsm2-util (1), +.IR softhsm2.conf (5) diff --git a/SoftHSMv2/src/bin/migrate/softhsm2-migrate.cpp b/SoftHSMv2/src/bin/migrate/softhsm2-migrate.cpp new file mode 100644 index 0000000..0e6dc90 --- /dev/null +++ b/SoftHSMv2/src/bin/migrate/softhsm2-migrate.cpp @@ -0,0 +1,798 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + softhsm2-migrate.cpp + + This program can be used for migrating SoftHSM v1 databases to any + PKCS#11 library. The default library is the libsofthsm2.so + *****************************************************************************/ + +#include <config.h> +#include "softhsm2-migrate.h" +#include "findslot.h" +#include "getpw.h" +#include "library.h" + +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <string.h> +#ifndef _WIN32 +#include <unistd.h> +#endif +#include <iostream> +#include <fstream> +#include <sched.h> + +#ifdef _WIN32 +#define sched_yield() SleepEx(0, 0) +#endif + +// Display the usage +void usage() +{ + printf("SoftHSM migration tool. From SoftHSM v1 database to PKCS#11.\n"); + printf("Usage: softhsm2-migrate [OPTIONS]\n"); + printf("Options:\n"); + printf(" -h Shows this help screen.\n"); + printf(" --help Shows this help screen.\n"); + printf(" --db <path> The SoftHSM v1 database that is going to be migrated.\n"); + printf(" --module <path> Use another PKCS#11 library than SoftHSM.\n"); + printf(" --no-public-key Do not migrate the public key.\n"); + printf(" --pin <PIN> The PIN for the normal user.\n"); + printf(" --serial <number> Will use the token with a matching serial number.\n"); + printf(" --slot <number> The slot where the token is located.\n"); + printf(" --token <label> Will use the token with a matching token label.\n"); + printf(" -v Show version info.\n"); + printf(" --version Show version info.\n"); +} + +// Enumeration of the long options +enum { + OPT_HELP = 0x100, + OPT_DB, + OPT_MODULE, + OPT_NO_PUBLIC_KEY, + OPT_PIN, + OPT_SERIAL, + OPT_SLOT, + OPT_TOKEN, + OPT_VERSION +}; + +// Text representation of the long options +static const struct option long_options[] = { + { "help", 0, NULL, OPT_HELP }, + { "db", 1, NULL, OPT_DB }, + { "module", 1, NULL, OPT_MODULE }, + { "no-public-key", 0, NULL, OPT_NO_PUBLIC_KEY }, + { "pin", 1, NULL, OPT_PIN }, + { "serial", 1, NULL, OPT_SERIAL }, + { "slot", 1, NULL, OPT_SLOT }, + { "token" , 1, NULL, OPT_TOKEN }, + { "version", 0, NULL, OPT_VERSION }, + { NULL, 0, NULL, 0 } +}; + +CK_FUNCTION_LIST_PTR p11; + +// Prepared statements +sqlite3_stmt* select_an_attribute_sql = NULL; +sqlite3_stmt* select_object_ids_sql = NULL; +sqlite3_stmt* count_object_id_sql = NULL; + + +// The main function +int main(int argc, char* argv[]) +{ + int option_index = 0; + int opt; + + char* dbPath = NULL; + char* userPIN = NULL; + char* module = NULL; + char* slot = NULL; + char* serial = NULL; + char* token = NULL; + char *errMsg = NULL; + int noPublicKey = 0; + + int result = 0; + CK_RV rv; + + moduleHandle = NULL; + p11 = NULL; + CK_SLOT_ID slotID = 0; + + if (argc == 1) + { + usage(); + exit(0); + } + + while ((opt = getopt_long(argc, argv, "hv", long_options, &option_index)) != -1) + { + switch (opt) + { + case OPT_DB: + dbPath = optarg; + break; + case OPT_SLOT: + slot = optarg; + break; + case OPT_SERIAL: + serial = optarg; + break; + case OPT_TOKEN: + token = optarg; + break; + case OPT_MODULE: + module = optarg; + break; + case OPT_NO_PUBLIC_KEY: + noPublicKey = 1; + break; + case OPT_PIN: + userPIN = optarg; + break; + case OPT_VERSION: + case 'v': + printf("%s\n", PACKAGE_VERSION); + exit(0); + break; + case OPT_HELP: + case 'h': + default: + usage(); + exit(0); + break; + } + } + + // Get a pointer to the function list for PKCS#11 library + CK_C_GetFunctionList pGetFunctionList = loadLibrary(module, &moduleHandle, &errMsg); + if (pGetFunctionList == NULL) + { + fprintf(stderr, "ERROR: Could not load the PKCS#11 library/module: %s\n", errMsg); + fprintf(stderr, "ERROR: Please check log files for additional information.\n"); + exit(1); + } + + // Load the function list + (*pGetFunctionList)(&p11); + + // Initialize the library + rv = p11->C_Initialize(NULL_PTR); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not initialize the PKCS#11 library/module: %s\n", module ? module : DEFAULT_PKCS11_LIB); + fprintf(stderr, "ERROR: Please check log files for additional information.\n"); + exit(1); + } + + // Get the slotID + result = findSlot(slot, serial, token, slotID); + + if (!result) + { + // Migrate the database + result = migrate(dbPath, slotID, userPIN, noPublicKey); + } + + // Finalize the library + p11->C_Finalize(NULL_PTR); + unloadLibrary(moduleHandle); + + return result; +} + +// Migrate the database +int migrate(char* dbPath, CK_SLOT_ID slotID, char* userPIN, int noPublicKey) +{ + CK_SESSION_HANDLE hSession; + sqlite3* db = NULL; + int result; + + if (dbPath == NULL) + { + fprintf(stderr, "ERROR: A path to the database must be supplied. " + "Use --db <path>\n"); + return 1; + } + + // Open the database + db = openDB(dbPath); + if (db == NULL) + { + return 1; + } + + // Connect to the PKCS#11 library + result = openP11(slotID, userPIN, &hSession); + if (result) + { + sqlite3_close(db); + return result; + } + + // Prepare the statements + if (prepStatements(db)) + { + fprintf(stderr, "ERROR: Could not prepare the statements\n"); + finalStatements(); + sqlite3_close(db); + return 1; + } + + // Start the migration + result = db2session(db, hSession, noPublicKey); + + // Finalize the statements + finalStatements(); + + sqlite3_close(db); + + if (result) + { + fprintf(stderr, "ERROR: Unable to migrate all of the objects.\n"); + } + else + { + printf("The database has been migrated to the new HSM\n"); + } + + return result; +} + +// Prepare the statements +int prepStatements(sqlite3* db) +{ + select_an_attribute_sql = NULL; + select_object_ids_sql = NULL; + count_object_id_sql = NULL; + + const char select_an_attribute_str[] = "SELECT value,length FROM Attributes WHERE objectID = ? AND type = ?;"; + const char select_object_ids_str[] = "SELECT objectID FROM Objects;"; + const char count_object_id_str[] = "SELECT COUNT(objectID) FROM Objects;"; + + if + ( + sqlite3_prepare_v2(db, select_an_attribute_str, -1, &select_an_attribute_sql, NULL) || + sqlite3_prepare_v2(db, select_object_ids_str, -1, &select_object_ids_sql, NULL) || + sqlite3_prepare_v2(db, count_object_id_str, -1, &count_object_id_sql, NULL) + ) + { + return 1; + } + + return 0; +} + +// Finalize the statements +void finalStatements() +{ + if (select_an_attribute_sql) sqlite3_finalize(select_an_attribute_sql); + if (select_object_ids_sql) sqlite3_finalize(select_object_ids_sql); + if (count_object_id_sql) sqlite3_finalize(count_object_id_sql); +} + +// Open a connection to a valid SoftHSM v1 database +sqlite3* openDB(char* dbPath) +{ + int result; + sqlite3* db = NULL; + sqlite3_stmt* pragStatem = NULL; + int dbVersion; + + // Open the database + result = sqlite3_open(dbPath, &db); + if (result) + { + fprintf(stderr, "ERROR: Could not open token database. " + "Probably wrong path or privileges: %s\n", dbPath); + return NULL; + } + + // Check the schema version + if (sqlite3_prepare_v2(db, "PRAGMA user_version;", -1, &pragStatem, NULL)) + { + fprintf(stderr, "ERROR: Could not prepare a SQL statement\n"); + sqlite3_close(db); + return NULL; + } + if (sqlite3_step(pragStatem) == SQLITE_ROW) + { + dbVersion = sqlite3_column_int(pragStatem, 0); + sqlite3_finalize(pragStatem); + + if (dbVersion != 100) + { + fprintf(stderr, "ERROR: Wrong database schema version: %s\n", dbPath); + sqlite3_close(db); + return NULL; + } + } + else + { + fprintf(stderr, "ERROR: The token database has not been initialized by SoftHSM\n"); + sqlite3_finalize(pragStatem); + sqlite3_close(db); + return NULL; + } + + // Check that the Token table exist + result = sqlite3_exec(db, "SELECT COUNT(variableID) FROM Token;", NULL, NULL, NULL); + if (result) + { + fprintf(stderr, "ERROR: The Token table is missing the in database\n"); + sqlite3_close(db); + return NULL; + } + + // Check that the Objects table exist + result = sqlite3_exec(db, "SELECT COUNT(objectID) FROM Objects;", NULL, NULL, NULL); + if (result) + { + fprintf(stderr, "ERROR: The Objects table is missing the in database\n"); + sqlite3_close(db); + return NULL; + } + + // Check that the Attributes table exist + result = sqlite3_exec(db, "SELECT COUNT(attributeID) FROM Attributes;", NULL, NULL, NULL); + if (result) + { + fprintf(stderr, "ERROR: The Attributes table is missing in the database\n"); + sqlite3_close(db); + return NULL; + } + + return db; +} + +// Connect and login to the token +int openP11(CK_SLOT_ID slotID, char* userPIN, CK_SESSION_HANDLE* hSession) +{ + char user_pin_copy[MAX_PIN_LEN+1]; + CK_RV rv; + + rv = p11->C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, + NULL_PTR, NULL_PTR, hSession); + if (rv != CKR_OK) + { + if (rv == CKR_SLOT_ID_INVALID) + { + fprintf(stderr, "ERROR: The given slot does not exist.\n"); + } + else + { + fprintf(stderr, "ERROR: Could not open a session on the given slot.\n"); + } + return 1; + } + + // Get the password + if (getPW(userPIN, user_pin_copy, CKU_USER) != 0) + { + fprintf(stderr, "ERROR: Could not get user PIN\n"); + return 1; + } + + rv = p11->C_Login(*hSession, CKU_USER, (CK_UTF8CHAR_PTR)user_pin_copy, strlen(user_pin_copy)); + if (rv != CKR_OK) + { + if (rv == CKR_PIN_INCORRECT) { + fprintf(stderr, "ERROR: The given user PIN does not match the one in the token.\n"); + } + else + { + fprintf(stderr, "ERROR: Could not log in on the token.\n"); + } + return 1; + } + + return 0; +} + +// Migrate the database to the session +int db2session(sqlite3* db, CK_SESSION_HANDLE hSession, int noPublicKey) +{ + CK_ULONG objectCount; + int result = 0, rv; + CK_OBJECT_HANDLE* objects = NULL; + CK_OBJECT_CLASS ckClass; + + // Get all objects + objects = getObjects(db, &objectCount); + if (objects == NULL) + { + fprintf(stderr, "ERROR: Could not find any objects in the database.\n"); + return 1; + } + + // Loop over all objects + for (unsigned i = 0; i < objectCount; i++) + { + ckClass = getObjectClass(objects[i]); + + switch (ckClass) + { + case CKO_PUBLIC_KEY: + if (noPublicKey) continue; + if (getKeyType(objects[i]) != CKK_RSA) + { + fprintf(stderr, "ERROR: Cannot export object %lu. Only supporting RSA keys. " + "Continuing.\n", objects[i]); + result = 1; + break; + } + rv = dbRSAPub2session(db, objects[i], hSession); + if (rv) result = 1; + break; + case CKO_PRIVATE_KEY: + if (getKeyType(objects[i]) != CKK_RSA) + { + fprintf(stderr, "ERROR: Cannot export object %lu. Only supporting RSA keys. " + "Continuing.\n", objects[i]); + result = 1; + break; + } + rv = dbRSAPriv2session(db, objects[i], hSession); + if (rv) result = 1; + break; + case CKO_VENDOR_DEFINED: + fprintf(stderr, "ERROR: Could not get the class of object %lu. " + "Continuing.\n", objects[i]); + result = 1; + break; + default: + fprintf(stderr, "ERROR: Not supporting class %lu in object %lu. " + "Continuing.\n", ckClass, objects[i]); + result = 1; + break; + } + } + + free(objects); + + return result; +} + +// Get the key type from key objects +CK_KEY_TYPE getKeyType(CK_OBJECT_HANDLE objectRef) +{ + int retSQL = 0; + CK_KEY_TYPE retVal = CKK_VENDOR_DEFINED; + + sqlite3_bind_int(select_an_attribute_sql, 1, objectRef); + sqlite3_bind_int(select_an_attribute_sql, 2, CKA_KEY_TYPE); + + // Get result + while ((retSQL = sqlite3_step(select_an_attribute_sql)) == SQLITE_BUSY) + { + sched_yield(); + } + + // Get attribute + if (retSQL == SQLITE_ROW) + { + CK_VOID_PTR pValue = (CK_VOID_PTR)sqlite3_column_blob(select_an_attribute_sql, 0); + CK_ULONG length = sqlite3_column_int(select_an_attribute_sql, 1); + + if (pValue != NULL_PTR && length == sizeof(CK_KEY_TYPE)) + { + retVal = *(CK_KEY_TYPE*)pValue; + } + } + + sqlite3_reset(select_an_attribute_sql); + + return retVal; +} + +// Get the class of the object +CK_OBJECT_CLASS getObjectClass(CK_OBJECT_HANDLE objectRef) +{ + int retSQL = 0; + CK_OBJECT_CLASS retVal = CKO_VENDOR_DEFINED; + + sqlite3_bind_int(select_an_attribute_sql, 1, objectRef); + sqlite3_bind_int(select_an_attribute_sql, 2, CKA_CLASS); + + // Get the result + while ((retSQL = sqlite3_step(select_an_attribute_sql)) == SQLITE_BUSY) + { + sched_yield(); + } + + // Get attribute + if (retSQL == SQLITE_ROW) + { + CK_VOID_PTR pValue = (CK_VOID_PTR)sqlite3_column_blob(select_an_attribute_sql, 0); + CK_ULONG length = sqlite3_column_int(select_an_attribute_sql, 1); + + if (pValue != NULL_PTR && length == sizeof(CK_OBJECT_CLASS)) + { + retVal = *(CK_OBJECT_CLASS*)pValue; + } + } + + sqlite3_reset(select_an_attribute_sql); + + return retVal; +} + +// Get all object IDs +CK_OBJECT_HANDLE* getObjects(sqlite3* /*db*/, CK_ULONG* objectCount) +{ + CK_ULONG objectsInDB; + CK_ULONG counter = 0; + CK_OBJECT_HANDLE* objectRefs = NULL; + int retSQL = 0; + + *objectCount = 0; + + // Find out how many objects we have. + while ((retSQL = sqlite3_step(count_object_id_sql)) == SQLITE_BUSY) + { + sched_yield(); + } + + if (retSQL != SQLITE_ROW) + { + fprintf(stderr, "ERROR: Could not count the number of objects in the database\n"); + sqlite3_reset(count_object_id_sql); + return NULL; + } + + // Get the number of objects + objectsInDB = sqlite3_column_int(count_object_id_sql, 0); + sqlite3_reset(count_object_id_sql); + + if (!objectsInDB) + { + fprintf(stderr, "ERROR: There are not objects in the database\n"); + return NULL; + } + + // Create the object-reference buffer + objectRefs = (CK_OBJECT_HANDLE*)malloc(objectsInDB * sizeof(CK_OBJECT_HANDLE)); + if (objectRefs == NULL) + { + fprintf(stderr, "ERROR: Could not allocate memory\n"); + return NULL; + } + + // Get all the object ids + while + ( + ((retSQL = sqlite3_step(select_object_ids_sql)) == SQLITE_BUSY || retSQL == SQLITE_ROW) && + counter < objectsInDB + ) + { + if(retSQL == SQLITE_BUSY) + { + sched_yield(); + continue; + } + + objectRefs[counter++] = sqlite3_column_int(select_object_ids_sql, 0); + } + + *objectCount = counter; + + sqlite3_reset(select_object_ids_sql); + + return objectRefs; +} + +// Extract the information about the public RSA key and save it in the token +int dbRSAPub2session(sqlite3* /*db*/, CK_OBJECT_HANDLE objectID, CK_SESSION_HANDLE hSession) +{ + int result = 0; + int i; + CK_OBJECT_HANDLE hKey; + CK_RV rv; + + CK_ATTRIBUTE pubTemplate[] = { + { CKA_CLASS, NULL, 0 }, + { CKA_KEY_TYPE, NULL, 0 }, + { CKA_TOKEN, NULL, 0 }, + { CKA_PRIVATE, NULL, 0 }, + { CKA_MODIFIABLE, NULL, 0 }, + { CKA_LABEL, NULL, 0 }, + { CKA_ID, NULL, 0 }, + { CKA_START_DATE, NULL, 0 }, + { CKA_END_DATE, NULL, 0 }, + { CKA_DERIVE, NULL, 0 }, + { CKA_SUBJECT, NULL, 0 }, + { CKA_ENCRYPT, NULL, 0 }, + { CKA_VERIFY, NULL, 0 }, + { CKA_VERIFY_RECOVER, NULL, 0 }, + { CKA_WRAP, NULL, 0 }, + { CKA_MODULUS, NULL, 0 }, + { CKA_PUBLIC_EXPONENT, NULL, 0 } + }; + + for (i = 0; i < 17; i++) + { + result = getAttribute(objectID, &pubTemplate[i]); + if (result) + { + freeTemplate(pubTemplate, 17); + return 1; + } + } + + rv = p11->C_CreateObject(hSession, pubTemplate, 17, &hKey); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR %X: Could not save the public key in the token. " + "Skipping object %lu\n", (unsigned int)rv, objectID); + result = 1; + } + else + { + printf("Object %lu has been migrated\n", objectID); + } + + freeTemplate(pubTemplate, 17); + + return result; +} + +// Extract the information about the private RSA key and save it in the token +int dbRSAPriv2session(sqlite3* /*db*/, CK_OBJECT_HANDLE objectID, CK_SESSION_HANDLE hSession) +{ + int result = 0; + int i; + CK_OBJECT_HANDLE hKey; + CK_RV rv; + + CK_ATTRIBUTE privTemplate[] = { + { CKA_CLASS, NULL, 0 }, + { CKA_TOKEN, NULL, 0 }, + { CKA_PRIVATE, NULL, 0 }, + { CKA_MODIFIABLE, NULL, 0 }, + { CKA_LABEL, NULL, 0 }, + { CKA_KEY_TYPE, NULL, 0 }, + { CKA_ID, NULL, 0 }, + { CKA_START_DATE, NULL, 0 }, + { CKA_END_DATE, NULL, 0 }, + { CKA_DERIVE, NULL, 0 }, + { CKA_SUBJECT, NULL, 0 }, + { CKA_SENSITIVE, NULL, 0 }, + { CKA_DECRYPT, NULL, 0 }, + { CKA_SIGN, NULL, 0 }, + { CKA_SIGN_RECOVER, NULL, 0 }, + { CKA_UNWRAP, NULL, 0 }, + { CKA_EXTRACTABLE, NULL, 0 }, + { CKA_WRAP_WITH_TRUSTED, NULL, 0 }, + { CKA_MODULUS, NULL, 0 }, + { CKA_PUBLIC_EXPONENT, NULL, 0 }, + { CKA_PRIVATE_EXPONENT, NULL, 0 }, + { CKA_PRIME_1, NULL, 0 }, + { CKA_PRIME_2, NULL, 0 } +// SoftHSM v1 did not store these values +// { CKA_EXPONENT_1, NULL, 0 }, +// { CKA_EXPONENT_2, NULL, 0 }, +// { CKA_COEFFICIENT, NULL, 0 } + }; + + for (i = 0; i < 23; i++) + { + result = getAttribute(objectID, &privTemplate[i]); + if (result) + { + freeTemplate(privTemplate, 23); + return 1; + } + } + + rv = p11->C_CreateObject(hSession, privTemplate, 23, &hKey); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR %X: Could not save the private key in the token. " + "Skipping object %lu\n", (unsigned int)rv, objectID); + result = 1; + } + else + { + printf("Object %lu has been migrated\n", objectID); + } + + freeTemplate(privTemplate, 23); + + return result; +} + +// Get the value of the given attribute +int getAttribute(CK_OBJECT_HANDLE objectRef, CK_ATTRIBUTE* attTemplate) +{ + int retSQL = 0; + int retVal = 0; + + sqlite3_bind_int(select_an_attribute_sql, 1, objectRef); + sqlite3_bind_int(select_an_attribute_sql, 2, attTemplate->type); + + // Get result + while ((retSQL = sqlite3_step(select_an_attribute_sql)) == SQLITE_BUSY) + { + sched_yield(); + } + + // Get the attribute + if (retSQL == SQLITE_ROW) + { + CK_VOID_PTR pValue = (CK_VOID_PTR)sqlite3_column_blob(select_an_attribute_sql, 0); + CK_ULONG length = sqlite3_column_int(select_an_attribute_sql, 1); + + if (length) + { + attTemplate->pValue = malloc(length); + if (!attTemplate->pValue) + { + fprintf(stderr, "ERROR: Could not allocate memory. " + "Skipping object %lu\n", objectRef); + retVal = 1; + } + else + { + // Copy data + memcpy(attTemplate->pValue, pValue, length); + } + } + + attTemplate->ulValueLen = length; + } + else + { + fprintf(stderr, "ERROR: Do not have attribute %lu. " + "Skipping object %lu\n", attTemplate->type, objectRef); + retVal = 1; + } + + sqlite3_reset(select_an_attribute_sql); + + return retVal; +} + +// Free allocated memory in the template +void freeTemplate(CK_ATTRIBUTE* attTemplate, int size) +{ + int i; + + if (!attTemplate) return; + + for (i = 0; i < size; i++) + { + if(attTemplate[i].pValue) + { + free(attTemplate[i].pValue); + } + } +} diff --git a/SoftHSMv2/src/bin/migrate/softhsm2-migrate.h b/SoftHSMv2/src/bin/migrate/softhsm2-migrate.h new file mode 100644 index 0000000..1b5a066 --- /dev/null +++ b/SoftHSMv2/src/bin/migrate/softhsm2-migrate.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + softhsm2-migrate.h + + This program can be used for migrating SoftHSM v1 databases to any + PKCS#11 library. The default library is the libsofthsm2.so + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_SOFTHSM2_MIGRATE_H +#define _SOFTHSM_V2_SOFTHSM2_MIGRATE_H + +#include "cryptoki.h" +#include <sqlite3.h> + +// Main functions + +void usage(); +int migrate(char* dbPath, CK_SLOT_ID slotID, char* userPIN, int noPublicKey); + +// Support functions + +sqlite3* openDB(char* dbPath); +int openP11(CK_SLOT_ID slotID, char* userPIN, CK_SESSION_HANDLE* hSession); +int db2session(sqlite3* db, CK_SESSION_HANDLE hSession, int noPublicKey); +int dbRSAPub2session(sqlite3* db, CK_OBJECT_HANDLE objectID, CK_SESSION_HANDLE hSession); +int dbRSAPriv2session(sqlite3* db, CK_OBJECT_HANDLE objectID, CK_SESSION_HANDLE hSession); +void freeTemplate(CK_ATTRIBUTE* attTemplate, int size); + +// Database functions + +CK_OBJECT_HANDLE* getObjects(sqlite3* db, CK_ULONG* objectCount); +CK_OBJECT_CLASS getObjectClass(CK_OBJECT_HANDLE objectRef); +CK_KEY_TYPE getKeyType(CK_OBJECT_HANDLE objectRef); +int getAttribute(CK_OBJECT_HANDLE objectRef, CK_ATTRIBUTE* attTemplate); +int prepStatements(sqlite3* db); +void finalStatements(); + +// Library + +static void* moduleHandle; +extern CK_FUNCTION_LIST_PTR p11; + +#endif // !_SOFTHSM_V2_SOFTHSM2_MIGRATE_H diff --git a/SoftHSMv2/src/bin/util/Makefile.am b/SoftHSMv2/src/bin/util/Makefile.am new file mode 100644 index 0000000..a552e14 --- /dev/null +++ b/SoftHSMv2/src/bin/util/Makefile.am @@ -0,0 +1,40 @@ +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +AM_CPPFLAGS = -I$(srcdir)/../common \ + -I$(srcdir)/../../lib/ \ + -I$(srcdir)/../../lib/common \ + -I$(srcdir)/../../lib/crypto \ + -I$(srcdir)/../../lib/data_mgr \ + -I$(srcdir)/../../lib/object_store \ + -I$(srcdir)/../../lib/pkcs11 \ + @CRYPTO_INCLUDES@ \ + @SQLITE3_INCLUDES@ + +dist_man_MANS = softhsm2-util.1 + +bin_PROGRAMS = softhsm2-util + +AUTOMAKE_OPTIONS = subdir-objects + +softhsm2_util_SOURCES = softhsm2-util.cpp \ + ../common/findslot.cpp \ + ../common/getpw.cpp \ + ../common/library.cpp + +softhsm2_util_LDADD = @CRYPTO_LIBS@ \ + @SQLITE3_LIBS@ \ + ../../lib/libsofthsm_convarch.la + +# Compile with support of OpenSSL +if WITH_OPENSSL +softhsm2_util_SOURCES += softhsm2-util-ossl.cpp \ + ../../lib/crypto/OSSLComp.cpp +endif + +# Compile with support of Botan +if WITH_BOTAN +softhsm2_util_SOURCES += softhsm2-util-botan.cpp +endif + +EXTRA_DIST = $(srcdir)/*.h \ + $(srcdir)/*.cpp diff --git a/SoftHSMv2/src/bin/util/softhsm2-util-botan.cpp b/SoftHSMv2/src/bin/util/softhsm2-util-botan.cpp new file mode 100644 index 0000000..cecc0ce --- /dev/null +++ b/SoftHSMv2/src/bin/util/softhsm2-util-botan.cpp @@ -0,0 +1,704 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + softhsm2-util-botan.cpp + + Code specific for Botan + *****************************************************************************/ + +#include <config.h> +#define UTIL_BOTAN +#include "softhsm2-util.h" +#include "softhsm2-util-botan.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <iostream> +#include <fstream> + +#include <botan/init.h> +#include <botan/auto_rng.h> +#include <botan/pkcs8.h> +#include <botan/bigint.h> +#include <botan/version.h> +#include <botan/der_enc.h> + +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14) +#include <botan/libstate.h> +bool wasInitialized = false; +#endif + +// Init Botan +void crypto_init() +{ +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14) + // The PKCS#11 library might be using Botan + // Check if it has already initialized Botan + if (Botan::Global_State_Management::global_state_exists()) + { + wasInitialized = true; + } + + if (!wasInitialized) + { + Botan::LibraryInitializer::initialize("thread_safe=true"); + } +#else + Botan::LibraryInitializer::initialize("thread_safe=true"); +#endif +} + +// Final Botan +void crypto_final() +{ +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14) + if (!wasInitialized) + { + Botan::LibraryInitializer::deinitialize(); + } +#else + Botan::LibraryInitializer::deinitialize(); +#endif +} + +// Import a aes secret key from given path +int crypto_import_aes_key +( + CK_SESSION_HANDLE hSession, + char* filePath, + char* label, + char* objID, + size_t objIDLen +) +{ + const size_t cMaxAesKeySize = 1024 + 1; // including null-character + char aesKeyValue[cMaxAesKeySize]; + FILE* fp = fopen(filePath, "rb"); + if (fp == NULL) + { + fprintf(stderr, "ERROR: Could not open the secret key file.\n"); + return 1; + } + if (fgets(aesKeyValue, cMaxAesKeySize, fp) == NULL) + { + fprintf(stderr, "ERROR: Could not read the secret key file.\n"); + fclose(fp); + return 1; + } + fclose(fp); + + CK_BBOOL ckTrue = CK_TRUE; + CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; + CK_KEY_TYPE keyType = CKK_AES; + CK_ATTRIBUTE keyTemplate[] = { + { CKA_CLASS, &keyClass, sizeof(keyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, &aesKeyValue, strlen(aesKeyValue) } + }; + + CK_OBJECT_HANDLE hKey; + CK_RV rv = p11->C_CreateObject(hSession, keyTemplate, 9, &hKey); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not save the secret key in the token. " + "Maybe the algorithm is not supported.\n"); + return 1; + } + + return 0; +} + +// Import a key pair from given path +int crypto_import_key_pair +( + CK_SESSION_HANDLE hSession, + char* filePath, + char* filePIN, + char* label, + char* objID, + size_t objIDLen, + int noPublicKey +) +{ + Botan::Private_Key* pkey = crypto_read_file(filePath, filePIN); + if (pkey == NULL) + { + return 1; + } + + Botan::RSA_PrivateKey* rsa = NULL; + Botan::DSA_PrivateKey* dsa = NULL; +#ifdef WITH_ECC + Botan::ECDSA_PrivateKey* ecdsa = NULL; +#endif + + if (pkey->algo_name().compare("RSA") == 0) + { + rsa = dynamic_cast<Botan::RSA_PrivateKey*>(pkey); + } + else if (pkey->algo_name().compare("DSA") == 0) + { + dsa = dynamic_cast<Botan::DSA_PrivateKey*>(pkey); + } +#ifdef WITH_ECC + else if (pkey->algo_name().compare("ECDSA") == 0) + { + ecdsa = dynamic_cast<Botan::ECDSA_PrivateKey*>(pkey); + } +#endif + else + { + fprintf(stderr, "ERROR: %s is not a supported algorithm.\n", + pkey->algo_name().c_str()); + delete pkey; + return 1; + } + + int result = 0; + + if (rsa) + { + result = crypto_save_rsa(hSession, label, objID, objIDLen, noPublicKey, rsa); + } + else if (dsa) + { + result = crypto_save_dsa(hSession, label, objID, objIDLen, noPublicKey, dsa); + } +#ifdef WITH_ECC + else if (ecdsa) + { + result = crypto_save_ecdsa(hSession, label, objID, objIDLen, noPublicKey, ecdsa); + } +#endif + else + { + fprintf(stderr, "ERROR: Could not get the key material.\n"); + result = 1; + } + + delete pkey; + return result; +} + +// Read the key from file +Botan::Private_Key* crypto_read_file(char* filePath, char* filePIN) +{ + if (filePath == NULL) + { + return NULL; + } + + Botan::AutoSeeded_RNG* rng = new Botan::AutoSeeded_RNG(); + Botan::Private_Key* pkey = NULL; + + try + { +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + if (filePIN == NULL) + { + pkey = Botan::PKCS8::load_key(std::string(filePath), *rng); + } + else + { + pkey = Botan::PKCS8::load_key(std::string(filePath), *rng, std::string(filePIN)); + } +#else + if (filePIN == NULL) + { + pkey = Botan::PKCS8::load_key(filePath, *rng); + } + else + { + pkey = Botan::PKCS8::load_key(filePath, *rng, filePIN); + } +#endif + } + catch (std::exception& e) + { + fprintf(stderr, "%s\n", e.what()); + fprintf(stderr, "ERROR: Perhaps wrong path to file, wrong file format, " + "or wrong PIN to file (--file-pin <PIN>).\n"); + delete rng; + return NULL; + } + delete rng; + + return pkey; +} + +// Save the key data in PKCS#11 +int crypto_save_rsa +( + CK_SESSION_HANDLE hSession, + char* label, + char* objID, + size_t objIDLen, + int noPublicKey, + Botan::RSA_PrivateKey* rsa +) +{ + rsa_key_material_t* keyMat = crypto_malloc_rsa(rsa); + if (!keyMat) + { + fprintf(stderr, "ERROR: Could not convert the key material to binary information.\n"); + return 1; + } + + CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY, privClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_RSA; + CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE; + if (noPublicKey) + { + ckToken = CK_FALSE; + } + CK_ATTRIBUTE pubTemplate[] = { + { CKA_CLASS, &pubClass, sizeof(pubClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_TOKEN, &ckToken, sizeof(ckToken) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_WRAP, &ckTrue, sizeof(ckTrue) }, + { CKA_PUBLIC_EXPONENT, keyMat->bigE, keyMat->sizeE }, + { CKA_MODULUS, keyMat->bigN, keyMat->sizeN } + }; + CK_ATTRIBUTE privTemplate[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_UNWRAP, &ckTrue, sizeof(ckTrue) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) }, + { CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse) }, + { CKA_PUBLIC_EXPONENT, keyMat->bigE, keyMat->sizeE }, + { CKA_MODULUS, keyMat->bigN, keyMat->sizeN }, + { CKA_PRIVATE_EXPONENT, keyMat->bigD, keyMat->sizeD }, + { CKA_PRIME_1, keyMat->bigP, keyMat->sizeP }, + { CKA_PRIME_2, keyMat->bigQ, keyMat->sizeQ }, + { CKA_EXPONENT_1, keyMat->bigDMP1, keyMat->sizeDMP1 }, + { CKA_EXPONENT_2, keyMat->bigDMQ1, keyMat->sizeDMQ1 }, + { CKA_COEFFICIENT, keyMat->bigIQMP, keyMat->sizeIQMP } + }; + + CK_OBJECT_HANDLE hKey1, hKey2; + CK_RV rv = p11->C_CreateObject(hSession, privTemplate, 19, &hKey1); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not save the private key in the token. " + "Maybe the algorithm is not supported.\n"); + crypto_free_rsa(keyMat); + return 1; + } + + rv = p11->C_CreateObject(hSession, pubTemplate, 10, &hKey2); + crypto_free_rsa(keyMat); + + if (rv != CKR_OK) + { + p11->C_DestroyObject(hSession, hKey1); + fprintf(stderr, "ERROR: Could not save the public key in the token.\n"); + return 1; + } + + printf("The key pair has been imported.\n"); + + return 0; +} + +// Convert the Botan key to binary +rsa_key_material_t* crypto_malloc_rsa(Botan::RSA_PrivateKey* rsa) +{ + if (rsa == NULL) + { + return NULL; + } + + rsa_key_material_t* keyMat = (rsa_key_material_t*)malloc(sizeof(rsa_key_material_t)); + if (keyMat == NULL) + { + return NULL; + } + + keyMat->sizeE = rsa->get_e().bytes(); + keyMat->sizeN = rsa->get_n().bytes(); + keyMat->sizeD = rsa->get_d().bytes(); + keyMat->sizeP = rsa->get_p().bytes(); + keyMat->sizeQ = rsa->get_q().bytes(); + keyMat->sizeDMP1 = rsa->get_d1().bytes(); + keyMat->sizeDMQ1 = rsa->get_d2().bytes(); + keyMat->sizeIQMP = rsa->get_c().bytes(); + + keyMat->bigE = (CK_VOID_PTR)malloc(keyMat->sizeE); + keyMat->bigN = (CK_VOID_PTR)malloc(keyMat->sizeN); + keyMat->bigD = (CK_VOID_PTR)malloc(keyMat->sizeD); + keyMat->bigP = (CK_VOID_PTR)malloc(keyMat->sizeP); + keyMat->bigQ = (CK_VOID_PTR)malloc(keyMat->sizeQ); + keyMat->bigDMP1 = (CK_VOID_PTR)malloc(keyMat->sizeDMP1); + keyMat->bigDMQ1 = (CK_VOID_PTR)malloc(keyMat->sizeDMQ1); + keyMat->bigIQMP = (CK_VOID_PTR)malloc(keyMat->sizeIQMP); + + if + ( + !keyMat->bigE || + !keyMat->bigN || + !keyMat->bigD || + !keyMat->bigP || + !keyMat->bigQ || + !keyMat->bigDMP1 || + !keyMat->bigDMQ1 || + !keyMat->bigIQMP + ) + { + crypto_free_rsa(keyMat); + return NULL; + } + + rsa->get_e().binary_encode((Botan::byte*)keyMat->bigE); + rsa->get_n().binary_encode((Botan::byte*)keyMat->bigN); + rsa->get_d().binary_encode((Botan::byte*)keyMat->bigD); + rsa->get_p().binary_encode((Botan::byte*)keyMat->bigP); + rsa->get_q().binary_encode((Botan::byte*)keyMat->bigQ); + rsa->get_d1().binary_encode((Botan::byte*)keyMat->bigDMP1); + rsa->get_d2().binary_encode((Botan::byte*)keyMat->bigDMQ1); + rsa->get_c().binary_encode((Botan::byte*)keyMat->bigIQMP); + + return keyMat; +} + +// Free the memory of the key +void crypto_free_rsa(rsa_key_material_t* keyMat) +{ + if (keyMat == NULL) return; + if (keyMat->bigE) free(keyMat->bigE); + if (keyMat->bigN) free(keyMat->bigN); + if (keyMat->bigD) free(keyMat->bigD); + if (keyMat->bigP) free(keyMat->bigP); + if (keyMat->bigQ) free(keyMat->bigQ); + if (keyMat->bigDMP1) free(keyMat->bigDMP1); + if (keyMat->bigDMQ1) free(keyMat->bigDMQ1); + if (keyMat->bigIQMP) free(keyMat->bigIQMP); + free(keyMat); +} + +// Save the key data in PKCS#11 +int crypto_save_dsa +( + CK_SESSION_HANDLE hSession, + char* label, + char* objID, + size_t objIDLen, + int noPublicKey, + Botan::DSA_PrivateKey* dsa +) +{ + dsa_key_material_t* keyMat = crypto_malloc_dsa(dsa); + if (keyMat == NULL) + { + fprintf(stderr, "ERROR: Could not convert the key material to binary information.\n"); + return 1; + } + + CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY, privClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_DSA; + CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE; + if (noPublicKey) + { + ckToken = CK_FALSE; + } + CK_ATTRIBUTE pubTemplate[] = { + { CKA_CLASS, &pubClass, sizeof(pubClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_TOKEN, &ckToken, sizeof(ckToken) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_ENCRYPT, &ckFalse, sizeof(ckFalse) }, + { CKA_WRAP, &ckFalse, sizeof(ckFalse) }, + { CKA_PRIME, keyMat->bigP, keyMat->sizeP }, + { CKA_SUBPRIME, keyMat->bigQ, keyMat->sizeQ }, + { CKA_BASE, keyMat->bigG, keyMat->sizeG }, + { CKA_VALUE, keyMat->bigY, keyMat->sizeY } + }; + CK_ATTRIBUTE privTemplate[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_DECRYPT, &ckFalse, sizeof(ckFalse) }, + { CKA_UNWRAP, &ckFalse, sizeof(ckFalse) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) }, + { CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse) }, + { CKA_PRIME, keyMat->bigP, keyMat->sizeP }, + { CKA_SUBPRIME, keyMat->bigQ, keyMat->sizeQ }, + { CKA_BASE, keyMat->bigG, keyMat->sizeG }, + { CKA_VALUE, keyMat->bigX, keyMat->sizeX } + }; + + CK_OBJECT_HANDLE hKey1, hKey2; + CK_RV rv = p11->C_CreateObject(hSession, privTemplate, 15, &hKey1); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not save the private key in the token. " + "Maybe the algorithm is not supported.\n"); + crypto_free_dsa(keyMat); + return 1; + } + + rv = p11->C_CreateObject(hSession, pubTemplate, 12, &hKey2); + crypto_free_dsa(keyMat); + + if (rv != CKR_OK) + { + p11->C_DestroyObject(hSession, hKey1); + fprintf(stderr, "ERROR: Could not save the public key in the token.\n"); + return 1; + } + + printf("The key pair has been imported.\n"); + + return 0; +} + +// Convert the Botan key to binary +dsa_key_material_t* crypto_malloc_dsa(Botan::DSA_PrivateKey* dsa) +{ + if (dsa == NULL) + { + return NULL; + } + + dsa_key_material_t *keyMat = (dsa_key_material_t *)malloc(sizeof(dsa_key_material_t)); + if (keyMat == NULL) + { + return NULL; + } + + keyMat->sizeP = dsa->group_p().bytes(); + keyMat->sizeQ = dsa->group_q().bytes(); + keyMat->sizeG = dsa->group_g().bytes(); + keyMat->sizeX = dsa->get_x().bytes(); + keyMat->sizeY = dsa->get_y().bytes(); + + keyMat->bigP = (CK_VOID_PTR)malloc(keyMat->sizeP); + keyMat->bigQ = (CK_VOID_PTR)malloc(keyMat->sizeQ); + keyMat->bigG = (CK_VOID_PTR)malloc(keyMat->sizeG); + keyMat->bigX = (CK_VOID_PTR)malloc(keyMat->sizeX); + keyMat->bigY = (CK_VOID_PTR)malloc(keyMat->sizeY); + + if (!keyMat->bigP || !keyMat->bigQ || !keyMat->bigG || !keyMat->bigX || !keyMat->bigY) + { + crypto_free_dsa(keyMat); + return NULL; + } + + dsa->group_p().binary_encode((Botan::byte*)keyMat->bigP); + dsa->group_q().binary_encode((Botan::byte*)keyMat->bigQ); + dsa->group_g().binary_encode((Botan::byte*)keyMat->bigG); + dsa->get_x().binary_encode((Botan::byte*)keyMat->bigX); + dsa->get_y().binary_encode((Botan::byte*)keyMat->bigY); + + return keyMat; +} + +// Free the memory of the key +void crypto_free_dsa(dsa_key_material_t* keyMat) +{ + if (keyMat == NULL) return; + if (keyMat->bigP) free(keyMat->bigP); + if (keyMat->bigQ) free(keyMat->bigQ); + if (keyMat->bigG) free(keyMat->bigG); + if (keyMat->bigX) free(keyMat->bigX); + if (keyMat->bigY) free(keyMat->bigY); + free(keyMat); +} + +#ifdef WITH_ECC +// Save the key data in PKCS#11 +int crypto_save_ecdsa +( + CK_SESSION_HANDLE hSession, + char* label, + char* objID, + size_t objIDLen, + int noPublicKey, + Botan::ECDSA_PrivateKey* ecdsa +) +{ + ecdsa_key_material_t* keyMat = crypto_malloc_ecdsa(ecdsa); + if (keyMat == NULL) + { + fprintf(stderr, "ERROR: Could not convert the key material to binary information.\n"); + return 1; + } + + CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY, privClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_ECDSA; + CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE; + if (noPublicKey) + { + ckToken = CK_FALSE; + } + CK_ATTRIBUTE pubTemplate[] = { + { CKA_CLASS, &pubClass, sizeof(pubClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_TOKEN, &ckToken, sizeof(ckToken) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_ENCRYPT, &ckFalse, sizeof(ckFalse) }, + { CKA_WRAP, &ckFalse, sizeof(ckFalse) }, + { CKA_EC_PARAMS, keyMat->derParams, keyMat->sizeParams }, + { CKA_EC_POINT, keyMat->derQ, keyMat->sizeQ } + }; + CK_ATTRIBUTE privTemplate[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_DECRYPT, &ckFalse, sizeof(ckFalse) }, + { CKA_UNWRAP, &ckFalse, sizeof(ckFalse) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) }, + { CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse) }, + { CKA_EC_PARAMS, keyMat->derParams, keyMat->sizeParams }, + { CKA_VALUE, keyMat->bigD, keyMat->sizeD } + }; + + CK_OBJECT_HANDLE hKey1, hKey2; + CK_RV rv = p11->C_CreateObject(hSession, privTemplate, 13, &hKey1); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not save the private key in the token. " + "Maybe the algorithm is not supported.\n"); + crypto_free_ecdsa(keyMat); + return 1; + } + + rv = p11->C_CreateObject(hSession, pubTemplate, 10, &hKey2); + crypto_free_ecdsa(keyMat); + + if (rv != CKR_OK) + { + p11->C_DestroyObject(hSession, hKey1); + fprintf(stderr, "ERROR: Could not save the public key in the token.\n"); + return 1; + } + + printf("The key pair has been imported.\n"); + + return 0; +} + +// Convert the Botan key to binary +ecdsa_key_material_t* crypto_malloc_ecdsa(Botan::ECDSA_PrivateKey* ecdsa) +{ + if (ecdsa == NULL) + { + return NULL; + } + + ecdsa_key_material_t *keyMat = (ecdsa_key_material_t *)malloc(sizeof(ecdsa_key_material_t)); + if (keyMat == NULL) + { + return NULL; + } + +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + std::vector<Botan::byte> derEC = ecdsa->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID); + Botan::secure_vector<Botan::byte> derPoint; +#else + Botan::SecureVector<Botan::byte> derEC = ecdsa->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID); + Botan::SecureVector<Botan::byte> derPoint; +#endif + + try + { +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + Botan::secure_vector<Botan::byte> repr = Botan::EC2OSP(ecdsa->public_point(), + Botan::PointGFp::UNCOMPRESSED); +#else + Botan::SecureVector<Botan::byte> repr = Botan::EC2OSP(ecdsa->public_point(), + Botan::PointGFp::UNCOMPRESSED); +#endif + + derPoint = Botan::DER_Encoder() + .encode(repr, Botan::OCTET_STRING) + .get_contents(); + } + catch (...) + { + return NULL; + } + + keyMat->sizeParams = derEC.size(); + keyMat->sizeD = ecdsa->private_value().bytes(); + keyMat->sizeQ = derPoint.size(); + + keyMat->derParams = (CK_VOID_PTR)malloc(keyMat->sizeParams); + keyMat->bigD = (CK_VOID_PTR)malloc(keyMat->sizeD); + keyMat->derQ = (CK_VOID_PTR)malloc(keyMat->sizeQ); + + if (!keyMat->derParams || !keyMat->bigD || !keyMat->derQ) + { + crypto_free_ecdsa(keyMat); + return NULL; + } + + memcpy(keyMat->derParams, &derEC[0], derEC.size()); + ecdsa->private_value().binary_encode((Botan::byte*)keyMat->bigD); + memcpy(keyMat->derQ, &derPoint[0], derPoint.size()); + + return keyMat; +} + +// Free the memory of the key +void crypto_free_ecdsa(ecdsa_key_material_t* keyMat) +{ + if (keyMat == NULL) return; + if (keyMat->derParams) free(keyMat->derParams); + if (keyMat->bigD) free(keyMat->bigD); + if (keyMat->derQ) free(keyMat->derQ); + free(keyMat); +} +#endif diff --git a/SoftHSMv2/src/bin/util/softhsm2-util-botan.h b/SoftHSMv2/src/bin/util/softhsm2-util-botan.h new file mode 100644 index 0000000..8cd4a5e --- /dev/null +++ b/SoftHSMv2/src/bin/util/softhsm2-util-botan.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + softhsm2-util-botan.h + + Header file for Botan implemented + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_SOFTHSM2_UTIL_BOTAN_H +#define _SOFTHSM_V2_SOFTHSM2_UTIL_BOTAN_H + +#include <botan/rsa.h> +#include <botan/dsa.h> +#ifdef WITH_ECC +#include <botan/ecdsa.h> +#endif + +typedef struct rsa_key_material_t { + CK_ULONG sizeE; + CK_ULONG sizeN; + CK_ULONG sizeD; + CK_ULONG sizeP; + CK_ULONG sizeQ; + CK_ULONG sizeDMP1; + CK_ULONG sizeDMQ1; + CK_ULONG sizeIQMP; + CK_VOID_PTR bigE; + CK_VOID_PTR bigN; + CK_VOID_PTR bigD; + CK_VOID_PTR bigP; + CK_VOID_PTR bigQ; + CK_VOID_PTR bigDMP1; + CK_VOID_PTR bigDMQ1; + CK_VOID_PTR bigIQMP; + rsa_key_material_t() { + sizeE = 0; + sizeN = 0; + sizeD = 0; + sizeP = 0; + sizeQ = 0; + sizeDMP1 = 0; + sizeDMQ1 = 0; + sizeIQMP = 0; + bigE = NULL_PTR; + bigN = NULL_PTR; + bigD = NULL_PTR; + bigP = NULL_PTR; + bigQ = NULL_PTR; + bigDMP1 = NULL_PTR; + bigDMQ1 = NULL_PTR; + bigIQMP = NULL_PTR; + } +} rsa_key_material_t; + +typedef struct dsa_key_material_t { + CK_ULONG sizeP; + CK_ULONG sizeQ; + CK_ULONG sizeG; + CK_ULONG sizeX; + CK_ULONG sizeY; + CK_VOID_PTR bigP; + CK_VOID_PTR bigQ; + CK_VOID_PTR bigG; + CK_VOID_PTR bigX; + CK_VOID_PTR bigY; + dsa_key_material_t() { + sizeP = 0; + sizeQ = 0; + sizeG = 0; + sizeX = 0; + sizeY = 0; + bigP = NULL_PTR; + bigQ = NULL_PTR; + bigG = NULL_PTR; + bigX = NULL_PTR; + bigY = NULL_PTR; + } +} dsa_key_material_t; + +#ifdef WITH_ECC +typedef struct ecdsa_key_material_t { + CK_ULONG sizeParams; + CK_ULONG sizeD; + CK_ULONG sizeQ; + CK_VOID_PTR derParams; + CK_VOID_PTR bigD; + CK_VOID_PTR derQ; + ecdsa_key_material_t() { + sizeParams = 0; + sizeD = 0; + sizeQ = 0; + derParams = NULL_PTR; + bigD = NULL_PTR; + derQ = NULL_PTR; + } +} ecdsa_key_material_t; +#endif + +Botan::Private_Key* crypto_read_file(char* filePath, char* filePIN); + +// RSA +int crypto_save_rsa(CK_SESSION_HANDLE hSession, char* label, char* objID, size_t objIDLen, int noPublicKey, Botan::RSA_PrivateKey* rsa); +rsa_key_material_t* crypto_malloc_rsa(Botan::RSA_PrivateKey* rsa); +void crypto_free_rsa(rsa_key_material_t* keyMat); + +// DSA +int crypto_save_dsa(CK_SESSION_HANDLE hSession, char* label, char* objID, size_t objIDLen, int noPublicKey, Botan::DSA_PrivateKey* dsa); +dsa_key_material_t* crypto_malloc_dsa(Botan::DSA_PrivateKey* dsa); +void crypto_free_dsa(dsa_key_material_t* keyMat); + +// ECDSA +#ifdef WITH_ECC +int crypto_save_ecdsa(CK_SESSION_HANDLE hSession, char* label, char* objID, size_t objIDLen, int noPublicKey, Botan::ECDSA_PrivateKey* ecdsa); +ecdsa_key_material_t* crypto_malloc_ecdsa(Botan::ECDSA_PrivateKey* ecdsa); +void crypto_free_ecdsa(ecdsa_key_material_t* keyMat); +#endif + +#endif // !_SOFTHSM_V2_SOFTHSM2_UTIL_OSSL_H diff --git a/SoftHSMv2/src/bin/util/softhsm2-util-ossl.cpp b/SoftHSMv2/src/bin/util/softhsm2-util-ossl.cpp new file mode 100644 index 0000000..fedfd28 --- /dev/null +++ b/SoftHSMv2/src/bin/util/softhsm2-util-ossl.cpp @@ -0,0 +1,790 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + softhsm2-util-ossl.cpp + + Code specific for OpenSSL + *****************************************************************************/ + +#include <config.h> +#define UTIL_OSSL +#include "softhsm2-util.h" +#include "softhsm2-util-ossl.h" +#include "OSSLComp.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <iostream> +#include <fstream> + +#include <openssl/pem.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/pkcs12.h> + +// Init OpenSSL +void crypto_init() +{ + // We do not need to do this one + // OpenSSL_add_all_algorithms(); +#ifdef WITH_FIPS + // The PKCS#11 library might be using a FIPS capable OpenSSL + if (FIPS_mode()) + return; + if (!FIPS_mode_set(1)) + { + fprintf(stderr, "ERROR: can't enter into FIPS mode.\n"); + exit(0); + } +#endif +} + +// Final OpenSSL +void crypto_final() +{ + // EVP_cleanup(); + CRYPTO_cleanup_all_ex_data(); +} + +int crypto_import_aes_key +( + CK_SESSION_HANDLE hSession, + char* filePath, + char* label, + char* objID, + size_t objIDLen +) +{ + const size_t cMaxAesKeySize = 1024 + 1; // including null-character + char aesKeyValue[cMaxAesKeySize]; + FILE* fp = fopen(filePath, "rb"); + if (fp == NULL) + { + fprintf(stderr, "ERROR: Could not open the secret key file.\n"); + return 1; + } + if (fgets(aesKeyValue, cMaxAesKeySize, fp) == NULL) + { + fprintf(stderr, "ERROR: Could not read the secret key file.\n"); + fclose(fp); + return 1; + } + fclose(fp); + + CK_BBOOL ckTrue = CK_TRUE; + CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; + CK_KEY_TYPE keyType = CKK_AES; + CK_ATTRIBUTE keyTemplate[] = { + { CKA_CLASS, &keyClass, sizeof(keyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, &aesKeyValue, strlen(aesKeyValue) } + }; + + CK_OBJECT_HANDLE hKey; + CK_RV rv = p11->C_CreateObject(hSession, keyTemplate, 9, &hKey); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not save the secret key in the token. " + "Maybe the algorithm is not supported.\n"); + return 1; + } + + return 0; +} + +// Import a key pair from given path +int crypto_import_key_pair +( + CK_SESSION_HANDLE hSession, + char* filePath, + char* filePIN, + char* label, + char* objID, + size_t objIDLen, + int noPublicKey +) +{ + EVP_PKEY* pkey = crypto_read_file(filePath, filePIN); + if (pkey == NULL) + { + return 1; + } + + RSA* rsa = NULL; + DSA* dsa = NULL; +#ifdef WITH_ECC + EC_KEY* ecdsa = NULL; +#endif + + switch (EVP_PKEY_type(EVP_PKEY_id(pkey))) + { + case EVP_PKEY_RSA: + rsa = EVP_PKEY_get1_RSA(pkey); + break; + case EVP_PKEY_DSA: + dsa = EVP_PKEY_get1_DSA(pkey); + break; +#ifdef WITH_ECC + case EVP_PKEY_EC: + ecdsa = EVP_PKEY_get1_EC_KEY(pkey); + break; +#endif + default: + fprintf(stderr, "ERROR: Cannot handle this algorithm.\n"); + EVP_PKEY_free(pkey); + return 1; + break; + } + EVP_PKEY_free(pkey); + + int result = 0; + + if (rsa) + { + result = crypto_save_rsa(hSession, label, objID, objIDLen, noPublicKey, rsa); + RSA_free(rsa); + } + else if (dsa) + { + result = crypto_save_dsa(hSession, label, objID, objIDLen, noPublicKey, dsa); + DSA_free(dsa); + } +#ifdef WITH_ECC + else if (ecdsa) + { + result = crypto_save_ecdsa(hSession, label, objID, objIDLen, noPublicKey, ecdsa); + EC_KEY_free(ecdsa); + } +#endif + else + { + fprintf(stderr, "ERROR: Could not get the key material.\n"); + result = 1; + } + + return result; +} + +// Read the key from file +EVP_PKEY* crypto_read_file(char* filePath, char* filePIN) +{ + BIO* in = NULL; + PKCS8_PRIV_KEY_INFO* p8inf = NULL; + EVP_PKEY* pkey = NULL; + X509_SIG* p8 = NULL; + + if (!(in = BIO_new_file(filePath, "rb"))) + { + fprintf(stderr, "ERROR: Could open the PKCS#8 file: %s\n", filePath); + return NULL; + } + + // The PKCS#8 file is encrypted + if (filePIN) + { + p8 = PEM_read_bio_PKCS8(in, NULL, NULL, NULL); + BIO_free(in); + + if (!p8) + { + fprintf(stderr, "ERROR: Could not read the PKCS#8 file. " + "Maybe the file is not encrypted.\n"); + return NULL; + } + + p8inf = PKCS8_decrypt(p8, filePIN, strlen(filePIN)); + X509_SIG_free(p8); + + if (!p8inf) + { + fprintf(stderr, "ERROR: Could not decrypt the PKCS#8 file. " + "Maybe wrong PIN to file (--file-pin <PIN>)\n"); + return NULL; + } + } + else + { + p8inf = PEM_read_bio_PKCS8_PRIV_KEY_INFO(in, NULL, NULL, NULL); + BIO_free(in); + + if (!p8inf) + { + fprintf(stderr, "ERROR: Could not read the PKCS#8 file. " + "Maybe it is encypted (--file-pin <PIN>)\n"); + return NULL; + } + } + + // Convert the PKCS#8 to OpenSSL + pkey = EVP_PKCS82PKEY(p8inf); + PKCS8_PRIV_KEY_INFO_free(p8inf); + if (!pkey) + { + fprintf(stderr, "ERROR: Could not convert the key.\n"); + return NULL; + } + + return pkey; +} + +// Save the key data in PKCS#11 +int crypto_save_rsa +( + CK_SESSION_HANDLE hSession, + char* label, + char* objID, + size_t objIDLen, + int noPublicKey, + RSA* rsa +) +{ + rsa_key_material_t* keyMat = crypto_malloc_rsa(rsa); + if (!keyMat) + { + fprintf(stderr, "ERROR: Could not convert the key material to binary information.\n"); + return 1; + } + + CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY, privClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_RSA; + CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE; + if (noPublicKey) + { + ckToken = CK_FALSE; + } + CK_ATTRIBUTE pubTemplate[] = { + { CKA_CLASS, &pubClass, sizeof(pubClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_TOKEN, &ckToken, sizeof(ckToken) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_WRAP, &ckTrue, sizeof(ckTrue) }, + { CKA_PUBLIC_EXPONENT, keyMat->bigE, keyMat->sizeE }, + { CKA_MODULUS, keyMat->bigN, keyMat->sizeN } + }; + CK_ATTRIBUTE privTemplate[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_UNWRAP, &ckTrue, sizeof(ckTrue) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) }, + { CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse) }, + { CKA_PUBLIC_EXPONENT, keyMat->bigE, keyMat->sizeE }, + { CKA_MODULUS, keyMat->bigN, keyMat->sizeN }, + { CKA_PRIVATE_EXPONENT, keyMat->bigD, keyMat->sizeD }, + { CKA_PRIME_1, keyMat->bigP, keyMat->sizeP }, + { CKA_PRIME_2, keyMat->bigQ, keyMat->sizeQ }, + { CKA_EXPONENT_1, keyMat->bigDMP1, keyMat->sizeDMP1 }, + { CKA_EXPONENT_2, keyMat->bigDMQ1, keyMat->sizeDMQ1 }, + { CKA_COEFFICIENT, keyMat->bigIQMP, keyMat->sizeIQMP } + }; + + CK_OBJECT_HANDLE hKey1, hKey2; + CK_RV rv = p11->C_CreateObject(hSession, privTemplate, 19, &hKey1); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not save the private key in the token. " + "Maybe the algorithm is not supported.\n"); + crypto_free_rsa(keyMat); + return 1; + } + + rv = p11->C_CreateObject(hSession, pubTemplate, 10, &hKey2); + crypto_free_rsa(keyMat); + + if (rv != CKR_OK) + { + p11->C_DestroyObject(hSession, hKey1); + fprintf(stderr, "ERROR: Could not save the public key in the token.\n"); + return 1; + } + + printf("The key pair has been imported.\n"); + + return 0; +} + +// Convert the OpenSSL key to binary +rsa_key_material_t* crypto_malloc_rsa(RSA* rsa) +{ + if (rsa == NULL) + { + return NULL; + } + + rsa_key_material_t* keyMat = (rsa_key_material_t*)malloc(sizeof(rsa_key_material_t)); + if (keyMat == NULL) + { + return NULL; + } + + const BIGNUM* bn_e = NULL; + const BIGNUM* bn_n = NULL; + const BIGNUM* bn_d = NULL; + const BIGNUM* bn_p = NULL; + const BIGNUM* bn_q = NULL; + const BIGNUM* bn_dmp1 = NULL; + const BIGNUM* bn_dmq1 = NULL; + const BIGNUM* bn_iqmp = NULL; + RSA_get0_factors(rsa, &bn_p, &bn_q); + RSA_get0_crt_params(rsa, &bn_dmp1, &bn_dmq1, &bn_iqmp); + RSA_get0_key(rsa, &bn_n, &bn_e, &bn_d); + + keyMat->sizeE = BN_num_bytes(bn_e); + keyMat->sizeN = BN_num_bytes(bn_n); + keyMat->sizeD = BN_num_bytes(bn_d); + keyMat->sizeP = BN_num_bytes(bn_p); + keyMat->sizeQ = BN_num_bytes(bn_q); + keyMat->sizeDMP1 = BN_num_bytes(bn_dmp1); + keyMat->sizeDMQ1 = BN_num_bytes(bn_dmq1); + keyMat->sizeIQMP = BN_num_bytes(bn_iqmp); + + keyMat->bigE = (CK_VOID_PTR)malloc(keyMat->sizeE); + keyMat->bigN = (CK_VOID_PTR)malloc(keyMat->sizeN); + keyMat->bigD = (CK_VOID_PTR)malloc(keyMat->sizeD); + keyMat->bigP = (CK_VOID_PTR)malloc(keyMat->sizeP); + keyMat->bigQ = (CK_VOID_PTR)malloc(keyMat->sizeQ); + keyMat->bigDMP1 = (CK_VOID_PTR)malloc(keyMat->sizeDMP1); + keyMat->bigDMQ1 = (CK_VOID_PTR)malloc(keyMat->sizeDMQ1); + keyMat->bigIQMP = (CK_VOID_PTR)malloc(keyMat->sizeIQMP); + + if + ( + !keyMat->bigE || + !keyMat->bigN || + !keyMat->bigD || + !keyMat->bigP || + !keyMat->bigQ || + !keyMat->bigDMP1 || + !keyMat->bigDMQ1 || + !keyMat->bigIQMP + ) + { + crypto_free_rsa(keyMat); + return NULL; + } + + BN_bn2bin(bn_e, (unsigned char*)keyMat->bigE); + BN_bn2bin(bn_n, (unsigned char*)keyMat->bigN); + BN_bn2bin(bn_d, (unsigned char*)keyMat->bigD); + BN_bn2bin(bn_p, (unsigned char*)keyMat->bigP); + BN_bn2bin(bn_q, (unsigned char*)keyMat->bigQ); + BN_bn2bin(bn_dmp1, (unsigned char*)keyMat->bigDMP1); + BN_bn2bin(bn_dmq1, (unsigned char*)keyMat->bigDMQ1); + BN_bn2bin(bn_iqmp, (unsigned char*)keyMat->bigIQMP); + + return keyMat; +} + +// Free the memory of the key +void crypto_free_rsa(rsa_key_material_t* keyMat) +{ + if (keyMat == NULL) return; + if (keyMat->bigE) free(keyMat->bigE); + if (keyMat->bigN) free(keyMat->bigN); + if (keyMat->bigD) free(keyMat->bigD); + if (keyMat->bigP) free(keyMat->bigP); + if (keyMat->bigQ) free(keyMat->bigQ); + if (keyMat->bigDMP1) free(keyMat->bigDMP1); + if (keyMat->bigDMQ1) free(keyMat->bigDMQ1); + if (keyMat->bigIQMP) free(keyMat->bigIQMP); + free(keyMat); +} + +// Save the key data in PKCS#11 +int crypto_save_dsa +( + CK_SESSION_HANDLE hSession, + char* label, + char* objID, + size_t objIDLen, + int noPublicKey, + DSA* dsa +) +{ + dsa_key_material_t* keyMat = crypto_malloc_dsa(dsa); + if (keyMat == NULL) + { + fprintf(stderr, "ERROR: Could not convert the key material to binary information.\n"); + return 1; + } + + CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY, privClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_DSA; + CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE; + if (noPublicKey) + { + ckToken = CK_FALSE; + } + CK_ATTRIBUTE pubTemplate[] = { + { CKA_CLASS, &pubClass, sizeof(pubClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_TOKEN, &ckToken, sizeof(ckToken) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_ENCRYPT, &ckFalse, sizeof(ckFalse) }, + { CKA_WRAP, &ckFalse, sizeof(ckFalse) }, + { CKA_PRIME, keyMat->bigP, keyMat->sizeP }, + { CKA_SUBPRIME, keyMat->bigQ, keyMat->sizeQ }, + { CKA_BASE, keyMat->bigG, keyMat->sizeG }, + { CKA_VALUE, keyMat->bigY, keyMat->sizeY } + }; + CK_ATTRIBUTE privTemplate[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_DECRYPT, &ckFalse, sizeof(ckFalse) }, + { CKA_UNWRAP, &ckFalse, sizeof(ckFalse) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) }, + { CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse) }, + { CKA_PRIME, keyMat->bigP, keyMat->sizeP }, + { CKA_SUBPRIME, keyMat->bigQ, keyMat->sizeQ }, + { CKA_BASE, keyMat->bigG, keyMat->sizeG }, + { CKA_VALUE, keyMat->bigX, keyMat->sizeX } + }; + + CK_OBJECT_HANDLE hKey1, hKey2; + CK_RV rv = p11->C_CreateObject(hSession, privTemplate, 15, &hKey1); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not save the private key in the token. " + "Maybe the algorithm is not supported.\n"); + crypto_free_dsa(keyMat); + return 1; + } + + rv = p11->C_CreateObject(hSession, pubTemplate, 12, &hKey2); + crypto_free_dsa(keyMat); + + if (rv != CKR_OK) + { + p11->C_DestroyObject(hSession, hKey1); + fprintf(stderr, "ERROR: Could not save the public key in the token.\n"); + return 1; + } + + printf("The key pair has been imported.\n"); + + return 0; +} + +// Convert the OpenSSL key to binary +dsa_key_material_t* crypto_malloc_dsa(DSA* dsa) +{ + if (dsa == NULL) + { + return NULL; + } + + dsa_key_material_t* keyMat = (dsa_key_material_t*)malloc(sizeof(dsa_key_material_t)); + if (keyMat == NULL) + { + return NULL; + } + + const BIGNUM* bn_p = NULL; + const BIGNUM* bn_q = NULL; + const BIGNUM* bn_g = NULL; + const BIGNUM* bn_priv_key = NULL; + const BIGNUM* bn_pub_key = NULL; + DSA_get0_pqg(dsa, &bn_p, &bn_q, &bn_g); + DSA_get0_key(dsa, &bn_pub_key, &bn_priv_key); + + keyMat->sizeP = BN_num_bytes(bn_p); + keyMat->sizeQ = BN_num_bytes(bn_q); + keyMat->sizeG = BN_num_bytes(bn_g); + keyMat->sizeX = BN_num_bytes(bn_priv_key); + keyMat->sizeY = BN_num_bytes(bn_pub_key); + + keyMat->bigP = (CK_VOID_PTR)malloc(keyMat->sizeP); + keyMat->bigQ = (CK_VOID_PTR)malloc(keyMat->sizeQ); + keyMat->bigG = (CK_VOID_PTR)malloc(keyMat->sizeG); + keyMat->bigX = (CK_VOID_PTR)malloc(keyMat->sizeX); + keyMat->bigY = (CK_VOID_PTR)malloc(keyMat->sizeY); + + if (!keyMat->bigP || !keyMat->bigQ || !keyMat->bigG || !keyMat->bigX || !keyMat->bigY) + { + crypto_free_dsa(keyMat); + return NULL; + } + + BN_bn2bin(bn_p, (unsigned char*)keyMat->bigP); + BN_bn2bin(bn_q, (unsigned char*)keyMat->bigQ); + BN_bn2bin(bn_g, (unsigned char*)keyMat->bigG); + BN_bn2bin(bn_priv_key, (unsigned char*)keyMat->bigX); + BN_bn2bin(bn_pub_key, (unsigned char*)keyMat->bigY); + + return keyMat; +} + +// Free the memory of the key +void crypto_free_dsa(dsa_key_material_t* keyMat) +{ + if (keyMat == NULL) return; + if (keyMat->bigP) free(keyMat->bigP); + if (keyMat->bigQ) free(keyMat->bigQ); + if (keyMat->bigG) free(keyMat->bigG); + if (keyMat->bigX) free(keyMat->bigX); + if (keyMat->bigY) free(keyMat->bigY); + free(keyMat); +} + +#ifdef WITH_ECC + +// Save the key data in PKCS#11 +int crypto_save_ecdsa +( + CK_SESSION_HANDLE hSession, + char* label, + char* objID, + size_t objIDLen, + int noPublicKey, + EC_KEY* ecdsa +) +{ + ecdsa_key_material_t* keyMat = crypto_malloc_ecdsa(ecdsa); + if (keyMat == NULL) + { + fprintf(stderr, "ERROR: Could not convert the key material to binary information.\n"); + return 1; + } + + CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY, privClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_EC; + CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE; + if (noPublicKey) + { + ckToken = CK_FALSE; + } + CK_ATTRIBUTE pubTemplate[] = { + { CKA_CLASS, &pubClass, sizeof(pubClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_TOKEN, &ckToken, sizeof(ckToken) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_ENCRYPT, &ckFalse, sizeof(ckFalse) }, + { CKA_WRAP, &ckFalse, sizeof(ckFalse) }, + { CKA_EC_PARAMS, keyMat->derParams, keyMat->sizeParams }, + { CKA_EC_POINT, keyMat->derQ, keyMat->sizeQ }, + }; + CK_ATTRIBUTE privTemplate[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_DECRYPT, &ckFalse, sizeof(ckFalse) }, + { CKA_UNWRAP, &ckFalse, sizeof(ckFalse) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) }, + { CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse) }, + { CKA_EC_PARAMS, keyMat->derParams, keyMat->sizeParams }, + { CKA_VALUE, keyMat->bigD, keyMat->sizeD } + }; + + CK_OBJECT_HANDLE hKey1, hKey2; + CK_RV rv = p11->C_CreateObject(hSession, privTemplate, 13, &hKey1); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not save the private key in the token. " + "Maybe the algorithm is not supported.\n"); + crypto_free_ecdsa(keyMat); + return 1; + } + + rv = p11->C_CreateObject(hSession, pubTemplate, 10, &hKey2); + crypto_free_ecdsa(keyMat); + + if (rv != CKR_OK) + { + p11->C_DestroyObject(hSession, hKey1); + fprintf(stderr, "ERROR: Could not save the public key in the token.\n"); + return 1; + } + + printf("The key pair has been imported.\n"); + + return 0; +} + +// Convert the OpenSSL key to binary +ecdsa_key_material_t* crypto_malloc_ecdsa(EC_KEY* ec_key) +{ + int result; + + if (ec_key == NULL) + { + return NULL; + } + + ecdsa_key_material_t* keyMat = (ecdsa_key_material_t*)malloc(sizeof(ecdsa_key_material_t)); + if (keyMat == NULL) + { + return NULL; + } + + const BIGNUM *d = EC_KEY_get0_private_key(ec_key); + const EC_GROUP *group = EC_KEY_get0_group(ec_key); + const EC_POINT *point = EC_KEY_get0_public_key(ec_key); + + keyMat->sizeParams = i2d_ECPKParameters(group, NULL); + keyMat->sizeD = BN_num_bytes(d); + + keyMat->derParams = (CK_VOID_PTR)malloc(keyMat->sizeParams); + keyMat->bigD = (CK_VOID_PTR)malloc(keyMat->sizeD); + keyMat->derQ = NULL; + + if (!keyMat->derParams || !keyMat->bigD) + { + crypto_free_ecdsa(keyMat); + return NULL; + } + + /* + * i2d functions increment the pointer, so we have to use a + * sacrificial pointer + */ + unsigned char *derParams = (unsigned char*) keyMat->derParams; + result = i2d_ECPKParameters(group, &derParams); + if (result == 0) + { + crypto_free_ecdsa(keyMat); + return NULL; + } + BN_bn2bin(d, (unsigned char*)keyMat->bigD); + + size_t point_length = EC_POINT_point2oct(group, + point, + POINT_CONVERSION_UNCOMPRESSED, + NULL, + 0, + NULL); + + // Definite, short + if (point_length <= 0x7f) + { + keyMat->sizeQ = 2 + point_length; + keyMat->derQ = (CK_VOID_PTR)malloc(keyMat->sizeQ); + if (!keyMat->derQ) + { + crypto_free_ecdsa(keyMat); + return NULL; + } + + unsigned char *derQ = (unsigned char *)keyMat->derQ; + derQ[0] = V_ASN1_OCTET_STRING; + derQ[1] = point_length & 0x7f; + result = EC_POINT_point2oct(group, + point, + POINT_CONVERSION_UNCOMPRESSED, + &derQ[2], + point_length, + NULL); + if (result == 0) + { + crypto_free_ecdsa(keyMat); + return NULL; + } + } + // Definite, long + else + { + // Count significate bytes + size_t bytes = sizeof(size_t); + for(; bytes > 0; bytes--) + { + size_t value = point_length >> ((bytes - 1) * 8); + if (value & 0xFF) break; + } + + keyMat->sizeQ = 2 + bytes + point_length; + keyMat->derQ = (CK_VOID_PTR)malloc(keyMat->sizeQ); + if (!keyMat->derQ) + { + crypto_free_ecdsa(keyMat); + return NULL; + } + + unsigned char *derQ = (unsigned char *)keyMat->derQ; + derQ[0] = V_ASN1_OCTET_STRING; + derQ[1] = 0x80 | bytes; + + size_t len = point_length; + for (size_t i = 1; i <= bytes; i++) + { + derQ[2+bytes-i] = (unsigned char) (len & 0xFF); + len >>= 8; + } + + result = EC_POINT_point2oct(group, + point, + POINT_CONVERSION_UNCOMPRESSED, + &derQ[2+bytes], + point_length, + NULL); + if (result == 0) + { + crypto_free_ecdsa(keyMat); + return NULL; + } + } + + return keyMat; +} + +// Free the memory of the key +void crypto_free_ecdsa(ecdsa_key_material_t* keyMat) +{ + if (keyMat == NULL) return; + if (keyMat->derParams) free(keyMat->derParams); + if (keyMat->bigD) free(keyMat->bigD); + if (keyMat->derQ) free(keyMat->derQ); + free(keyMat); +} + +#endif diff --git a/SoftHSMv2/src/bin/util/softhsm2-util-ossl.h b/SoftHSMv2/src/bin/util/softhsm2-util-ossl.h new file mode 100644 index 0000000..7a2a31a --- /dev/null +++ b/SoftHSMv2/src/bin/util/softhsm2-util-ossl.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + softhsm2-util-ossl.h + + Header file for OpenSSL implemented + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_SOFTHSM2_UTIL_OSSL_H +#define _SOFTHSM_V2_SOFTHSM2_UTIL_OSSL_H + +#include <openssl/rsa.h> +#include <openssl/dsa.h> +#ifdef WITH_ECC +#include <openssl/ec.h> +#endif + +typedef struct rsa_key_material_t { + CK_ULONG sizeE; + CK_ULONG sizeN; + CK_ULONG sizeD; + CK_ULONG sizeP; + CK_ULONG sizeQ; + CK_ULONG sizeDMP1; + CK_ULONG sizeDMQ1; + CK_ULONG sizeIQMP; + CK_VOID_PTR bigE; + CK_VOID_PTR bigN; + CK_VOID_PTR bigD; + CK_VOID_PTR bigP; + CK_VOID_PTR bigQ; + CK_VOID_PTR bigDMP1; + CK_VOID_PTR bigDMQ1; + CK_VOID_PTR bigIQMP; + rsa_key_material_t() { + sizeE = 0; + sizeN = 0; + sizeD = 0; + sizeP = 0; + sizeQ = 0; + sizeDMP1 = 0; + sizeDMQ1 = 0; + sizeIQMP = 0; + bigE = NULL_PTR; + bigN = NULL_PTR; + bigD = NULL_PTR; + bigP = NULL_PTR; + bigQ = NULL_PTR; + bigDMP1 = NULL_PTR; + bigDMQ1 = NULL_PTR; + bigIQMP = NULL_PTR; + } +} rsa_key_material_t; + +typedef struct dsa_key_material_t { + CK_ULONG sizeP; + CK_ULONG sizeQ; + CK_ULONG sizeG; + CK_ULONG sizeX; + CK_ULONG sizeY; + CK_VOID_PTR bigP; + CK_VOID_PTR bigQ; + CK_VOID_PTR bigG; + CK_VOID_PTR bigX; + CK_VOID_PTR bigY; + dsa_key_material_t() { + sizeP = 0; + sizeQ = 0; + sizeG = 0; + sizeX = 0; + sizeY = 0; + bigP = NULL_PTR; + bigQ = NULL_PTR; + bigG = NULL_PTR; + bigX = NULL_PTR; + bigY = NULL_PTR; + } +} dsa_key_material_t; + +#ifdef WITH_ECC +typedef struct ecdsa_key_material_t { + CK_ULONG sizeParams; + CK_ULONG sizeD; + CK_ULONG sizeQ; + CK_VOID_PTR derParams; + CK_VOID_PTR bigD; + CK_VOID_PTR derQ; + ecdsa_key_material_t() { + sizeParams = 0; + sizeD = 0; + sizeQ = 0; + derParams = NULL_PTR; + bigD = NULL_PTR; + derQ = NULL_PTR; + } +} ecdsa_key_material_t; +#endif + +EVP_PKEY* crypto_read_file(char* filePath, char* filePIN); + +// RSA +int crypto_save_rsa(CK_SESSION_HANDLE hSession, char* label, char* objID, size_t objIDLen, int noPublicKey, RSA* rsa); +rsa_key_material_t* crypto_malloc_rsa(RSA* rsa); +void crypto_free_rsa(rsa_key_material_t* keyMat); + +// DSA +int crypto_save_dsa(CK_SESSION_HANDLE hSession, char* label, char* objID, size_t objIDLen, int noPublicKey, DSA* dsa); +dsa_key_material_t* crypto_malloc_dsa(DSA* dsa); +void crypto_free_dsa(dsa_key_material_t* keyMat); + +#ifdef WITH_ECC +// ECDSA +int crypto_save_ecdsa(CK_SESSION_HANDLE hSession, char* label, char* objID, size_t objIDLen, int noPublicKey, EC_KEY* ecdsa); +ecdsa_key_material_t* crypto_malloc_ecdsa(EC_KEY* ecdsa); +void crypto_free_ecdsa(ecdsa_key_material_t* keyMat); +#endif + +#endif // !_SOFTHSM_V2_SOFTHSM2_UTIL_OSSL_H diff --git a/SoftHSMv2/src/bin/util/softhsm2-util.1 b/SoftHSMv2/src/bin/util/softhsm2-util.1 new file mode 100644 index 0000000..1998226 --- /dev/null +++ b/SoftHSMv2/src/bin/util/softhsm2-util.1 @@ -0,0 +1,259 @@ +.TH SOFTHSM2-UTIL 1 "22 September 2017" "SoftHSM" +.SH NAME +softhsm2-util \- support tool for libsofthsm2 +.SH SYNOPSIS +.B softhsm2-util \-\-show-slots +.PP +.B softhsm2-util \-\-init-token +.B \-\-free +.B \-\-label +.I text +\\ +.ti +0.7i +.RB [ \-\-so-pin +.I PIN +.B \-\-pin +.IR PIN ] +.PP +.B softhsm2-util \-\-import +.I path +.RB [ \-\-file-pin +.IR PIN ] +.B \-\-token +.I label +\\ +.ti +0.7i +.RB [ \-\-pin +.I PIN +.B \-\-no\-public\-key] +.B \-\-label +.I text +.B \-\-id +.I hex +.PP +.B softhsm2-util \-\-import +.I path +.B \-\-aes +.B \-\-token +.I label +\\ +.ti +0.7i +.RB [ \-\-pin +.I PIN] +.B \-\-label +.I text +.B \-\-id +.I hex +.PP +.B softhsm2-util \-\-delete\-token +.B \-\-token +.I text +.SH DESCRIPTION +.B softhsm2-util +is a support tool mainly for libsofthsm2. It can also +be used with other PKCS#11 libraries by using the option +.B \-\-module +.PP +Read the sections below to get more information on +the libsofthsm2 and PKCS#11. +Most applications assumes that the token they want +to use is already initialized. +It is then up to the user +to initialize the PKCS#11 token. +This is done by using the PKCS#11 interface, +but instead of writing your own +tool you can use the +.B softhsm2-util +tool. +.PP +Keys are usually created directly in the token, +but the user may want to use an existing key pair. +Keys can be imported to a token by using the PKCS#11 interface, +but this tool can also be used if the +user has the key pair in a PKCS#8 file. +If you need to convert keys from +BIND .private-key format over to PKCS#8, +one can +use +.BR softhsm2-keyconv . +.LP +The libary +.BR libsofthsm2 , +known as SoftHSM, provides cryptographic functionality +by using the PKCS#11 API. +It was developed as a part of the OpenDNSSEC project, +thus designed to meet the requirements +of OpenDNSSEC, +but can also work together with other +software that want to use the functionality +of the PKCS#11 API. +.PP +SoftHSM is a software implementation of a generic cryptographic device with a PKCS#11 interface. +These devices are often called tokens. +Read in the manual softhsm2.conf(5) on how to create these +tokens and how they are added to a slot in SoftHSM. +.LP +The +.B PKCS#11 +API +can be used to handle and store cryptographic keys. +This interface +specifies how to communicate with cryptographic devices such as HSMs +(Hardware Security Modules) and smart cards. +The purpose of these devices +is, among others, +to generate cryptographic keys and sign information without +revealing private-key material to the outside world. +They are often designed +to perform well on these specific tasks +compared to ordinary processes in a normal computer. +.LP +.SH ACTIONS +.TP +.B \-\-delete\-token +Delete the token at a given slot. +Use with +.BR \-\-token +or +.BR \-\-serial . +Any content in token will be erased. +.TP +.B \-\-help\fR, \fB\-h\fR +Show the help information. +.TP +.B \-\-import \fIpath\fR +Import a key pair from the given +.IR path . +The file must be in PKCS#8-format. +.br +Use with +.BR \-\-slot +or +.BR \-\-token +or +.BR \-\-serial , +.BR \-\-file-pin , +.BR \-\-pin , +.BR \-\-no\-public\-key , +.BR \-\-label , +and +.BR \-\-id . +.br +Can also be used with +.BR \-\-aes +to use file as is and import it as AES. +.TP +.B \-\-init-token +Initialize the token at a given slot, token label or token serial. +If the token is already initialized then this command +will reinitialize it, thus erasing all the objects in the token. +The matching Security Officer (SO) PIN must also +be provided when doing reinitialization. +Initialized tokens will be reassigned to another slot (based on +the token serial number). +.br +Use with +.BR \-\-slot +or +.BR \-\-token +or +.BR \-\-serial +or +.BR \-\-free , +.BR \-\-label , +.BR \-\-so-pin , +and +.BR \-\-pin . +.LP +.TP +.B \-\-show-slots +Display all the available slots and their current status. +.TP +.B \-\-version\fR, \fB\-v\fR +Show the version info. +.SH OPTIONS +.TP +.B \-\-aes +Used to tell import to use file as is and import it as AES. +.TP +.B \-\-file-pin \fIPIN\fR +The +.I PIN +will be used to decrypt the PKCS#8 file. +If not given then the PKCS#8 file is assumed to be unencrypted. +.TP +.B \-\-force +Use this option to override the warnings and force the given action. +.TP +.B \-\-free +Use the first free/uninitialized token. +.TP +.B \-\-id \fIhex\fR +Choose an ID of the key pair. +The ID is in hexadecimal with a variable length. +Use with +.B \-\-force +when importing a key pair if the ID already exists. +.TP +.B \-\-label \fItext\fR +Defines the +.I label +of the object or the token that will be set. +.TP +.B \-\-module \fIpath\fR +Use another PKCS#11 library than SoftHSM. +.TP +.B \-\-no\-public\-key +Do not import the public key. +.TP +.B \-\-pin \fIPIN\fR +The +.I PIN +for the normal user. +.TP +.B \-\-serial \fInumber\fR +Will use the token with a matching serial number. +.TP +.B \-\-slot \fInumber\fR +The slot where the token is located. +.TP +.B \-\-so-pin \fIPIN\fR +The +.I PIN +for the Security Officer (SO). +.TP +.B \-\-token \fIlabel\fR +Will use the token with a matching token label. +.SH EXAMPLES +.LP +The token can be initialized using this command: +.LP +.RS +.nf +softhsm2-util \-\-init-token \-\-slot 1 \-\-label "mytoken" +.fi +.RE +.LP +A key pair can be imported using the softhsm tool where you specify the path +to the key file, slot number, label and ID of the new objects, and the +user PIN. +The file must be in PKCS#8 format. +.LP +.RS +.nf +softhsm2-util \-\-import key1.pem \-\-token "mytoken" \-\-label "My key" \\ +.ti +0.7i +\-\-id A1B2 \-\-pin 123456 +.fi +(Add, \-\-file-pin +.IR PIN , +if the key file is encrypted.) +.RE +.LP +.SH AUTHORS +Written by Rickard Bellgrim, Francis Dupont, René Post, and Roland van Rijswijk. +.LP +.SH "SEE ALSO" +.IR softhsm2-keyconv (1), +.IR softhsm2-migrate (1), +.IR softhsm2.conf (5) diff --git a/SoftHSMv2/src/bin/util/softhsm2-util.cpp b/SoftHSMv2/src/bin/util/softhsm2-util.cpp new file mode 100644 index 0000000..465df4a --- /dev/null +++ b/SoftHSMv2/src/bin/util/softhsm2-util.cpp @@ -0,0 +1,1318 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + softhsm2-util.cpp + + This program can be used for interacting with HSMs using PKCS#11. + The default library is the libsofthsm2.so + *****************************************************************************/ + +#include <config.h> +#include "softhsm2-util.h" +#include "findslot.h" +#include "getpw.h" +#include "library.h" +#include "log.h" +#include "Configuration.h" +#include "SimpleConfigLoader.h" +#include "Directory.h" +#include "MutexFactory.h" +#include "ObjectStoreToken.h" +#include "OSPathSep.h" + +#if defined(WITH_OPENSSL) +#include "OSSLCryptoFactory.h" +#else +#include "BotanCryptoFactory.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <string.h> +#ifndef _WIN32 +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#else +#include <direct.h> +#include <io.h> +#endif +#include <iostream> +#include <fstream> + +// Initialise the one-and-only instance + +#ifdef HAVE_CXX11 + +std::unique_ptr<MutexFactory> MutexFactory::instance(nullptr); +std::unique_ptr<SecureMemoryRegistry> SecureMemoryRegistry::instance(nullptr); +#if defined(WITH_OPENSSL) +std::unique_ptr<OSSLCryptoFactory> OSSLCryptoFactory::instance(nullptr); +#else +std::unique_ptr<BotanCryptoFactory> BotanCryptoFactory::instance(nullptr); +#endif + +#else + +std::auto_ptr<MutexFactory> MutexFactory::instance(NULL); +std::auto_ptr<SecureMemoryRegistry> SecureMemoryRegistry::instance(NULL); +#if defined(WITH_OPENSSL) +std::auto_ptr<OSSLCryptoFactory> OSSLCryptoFactory::instance(NULL); +#else +std::auto_ptr<BotanCryptoFactory> BotanCryptoFactory::instance(NULL); +#endif + +#endif + +// Display the usage +void usage() +{ + printf("Support tool for PKCS#11\n"); + printf("Usage: softhsm2-util [ACTION] [OPTIONS]\n"); + printf("Action:\n"); + printf(" --delete-token Delete the token at a given slot.\n"); + printf(" Use with --token or --serial.\n"); + printf(" WARNING: Any content in token will be erased.\n"); + printf(" -h Shows this help screen.\n"); + printf(" --help Shows this help screen.\n"); + printf(" --import <path> Import a key pair from the given path.\n"); + printf(" The file must be in PKCS#8-format.\n"); + printf(" Use with --slot or --token or --serial, --file-pin,\n"); + printf(" --label, --id, --no-public-key, and --pin.\n"); + printf(" --init-token Initialize the token at a given slot.\n"); + printf(" Use with --slot or --token or --serial or --free,\n"); + printf(" --label, --so-pin, and --pin.\n"); + printf(" WARNING: Any content in token will be erased.\n"); + printf(" --show-slots Display all the available slots.\n"); + printf(" -v Show version info.\n"); + printf(" --version Show version info.\n"); + printf("Options:\n"); + printf(" --aes Used to tell import to use file as is and import it as AES.\n"); + printf(" --file-pin <PIN> Supply a PIN if the file is encrypted.\n"); + printf(" --force Used to override a warning.\n"); + printf(" --free Use the first free/uninitialized token.\n"); + printf(" --id <hex> Defines the ID of the object. Hexadecimal characters.\n"); + printf(" Use with --force if multiple key pairs may share\n"); + printf(" the same ID.\n"); + printf(" --label <text> Defines the label of the object or the token.\n"); + printf(" --module <path> Use another PKCS#11 library than SoftHSM.\n"); + printf(" --no-public-key Do not import the public key.\n"); + printf(" --pin <PIN> The PIN for the normal user.\n"); + printf(" --serial <number> Will use the token with a matching serial number.\n"); + printf(" --slot <number> The slot where the token is located.\n"); + printf(" --so-pin <PIN> The PIN for the Security Officer (SO).\n"); + printf(" --token <label> Will use the token with a matching token label.\n"); +} + +// Enumeration of the long options +enum { + OPT_DELETE_TOKEN = 0x100, + OPT_FILE_PIN, + OPT_FORCE, + OPT_FREE, + OPT_HELP, + OPT_ID, + OPT_IMPORT, + OPT_INIT_TOKEN, + OPT_LABEL, + OPT_MODULE, + OPT_NO_PUBLIC_KEY, + OPT_PIN, + OPT_SERIAL, + OPT_SHOW_SLOTS, + OPT_SLOT, + OPT_SO_PIN, + OPT_TOKEN, + OPT_VERSION, + OPT_AES +}; + +// Text representation of the long options +static const struct option long_options[] = { + { "delete-token", 0, NULL, OPT_DELETE_TOKEN }, + { "file-pin", 1, NULL, OPT_FILE_PIN }, + { "force", 0, NULL, OPT_FORCE }, + { "free", 0, NULL, OPT_FREE }, + { "help", 0, NULL, OPT_HELP }, + { "id", 1, NULL, OPT_ID }, + { "import", 1, NULL, OPT_IMPORT }, + { "init-token", 0, NULL, OPT_INIT_TOKEN }, + { "label", 1, NULL, OPT_LABEL }, + { "module", 1, NULL, OPT_MODULE }, + { "no-public-key", 0, NULL, OPT_NO_PUBLIC_KEY }, + { "pin", 1, NULL, OPT_PIN }, + { "serial", 1, NULL, OPT_SERIAL }, + { "show-slots", 0, NULL, OPT_SHOW_SLOTS }, + { "slot", 1, NULL, OPT_SLOT }, + { "so-pin", 1, NULL, OPT_SO_PIN }, + { "token", 1, NULL, OPT_TOKEN }, + { "version", 0, NULL, OPT_VERSION }, + { "aes", 0, NULL, OPT_AES }, + { NULL, 0, NULL, 0 } +}; + +CK_FUNCTION_LIST_PTR p11; + +// The main function +int main(int argc, char* argv[]) +{ + int option_index = 0; + int opt; + + char* inPath = NULL; + char* soPIN = NULL; + char* userPIN = NULL; + char* filePIN = NULL; + char* label = NULL; + char* module = NULL; + char* objectID = NULL; + char* slot = NULL; + char* serial = NULL; + char* token = NULL; + char* errMsg = NULL; + int forceExec = 0; + bool freeToken = false; + int noPublicKey = 0; + bool importAES = false; + + int doInitToken = 0; + int doShowSlots = 0; + int doImport = 0; + int doDeleteToken = 0; + int action = 0; + bool needP11 = false; + int rv = 0; + CK_SLOT_ID slotID = 0; + + moduleHandle = NULL; + p11 = NULL; + + while ((opt = getopt_long(argc, argv, "hv", long_options, &option_index)) != -1) + { + switch (opt) + { + case OPT_SHOW_SLOTS: + doShowSlots = 1; + action++; + needP11 = true; + break; + case OPT_INIT_TOKEN: + doInitToken = 1; + action++; + needP11 = true; + break; + case OPT_IMPORT: + doImport = 1; + action++; + inPath = optarg; + needP11 = true; + break; + case OPT_AES: + importAES = true; + break; + case OPT_DELETE_TOKEN: + doDeleteToken = 1; + action++; + break; + case OPT_SLOT: + slot = optarg; + break; + case OPT_LABEL: + label = optarg; + break; + case OPT_SERIAL: + serial = optarg; + break; + case OPT_TOKEN: + token = optarg; + break; + case OPT_MODULE: + module = optarg; + break; + case OPT_NO_PUBLIC_KEY: + noPublicKey = 1; + break; + case OPT_ID: + objectID = optarg; + break; + case OPT_SO_PIN: + soPIN = optarg; + break; + case OPT_PIN: + userPIN = optarg; + break; + case OPT_FILE_PIN: + filePIN = optarg; + break; + case OPT_FORCE: + forceExec = 1; + break; + case OPT_FREE: + freeToken = true; + break; + case OPT_VERSION: + case 'v': + printf("%s\n", PACKAGE_VERSION); + exit(0); + break; + case OPT_HELP: + case 'h': + default: + usage(); + exit(0); + break; + } + } + + // No action given, display the usage. + if (action != 1) + { + usage(); + exit(1); + } + + if (needP11) + { + // Check the basic setup of SoftHSM + if (!checkSetup()) + { + fprintf(stderr, "ERROR: Please verify that the SoftHSM configuration is correct.\n"); + exit(1); + } + + // Get a pointer to the function list for PKCS#11 library + CK_C_GetFunctionList pGetFunctionList = loadLibrary(module, &moduleHandle, &errMsg); + if (!pGetFunctionList) + { + fprintf(stderr, "ERROR: Could not load the PKCS#11 library/module: %s\n", errMsg); + fprintf(stderr, "ERROR: Please check log files for additional information.\n"); + exit(1); + } + + // Load the function list + (*pGetFunctionList)(&p11); + + // Initialize the library + CK_RV p11rv = p11->C_Initialize(NULL_PTR); + if (p11rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not initialize the PKCS#11 library/module: %s\n", module ? module : DEFAULT_PKCS11_LIB); + fprintf(stderr, "ERROR: Please check log files for additional information.\n"); + exit(1); + } + } + + // We should create the token. + if (doInitToken) + { + // Get the slotID + rv = findSlot(slot, serial, token, freeToken, slotID); + if (!rv) + { + rv = initToken(slotID, label, soPIN, userPIN); + } + } + + // Show all available slots + if (!rv && doShowSlots) + { + rv = showSlots(); + } + + // Import a key pair from the given path + if (!rv && doImport) + { + // Get the slotID + rv = findSlot(slot, serial, token, slotID); + if (!rv) + { + rv = importAES ? importSecretKey(inPath, slotID, userPIN, label, objectID) + : importKeyPair(inPath, filePIN, slotID, userPIN, label, objectID, forceExec, noPublicKey); + } + } + + // We should delete the token. + if (!rv && doDeleteToken) + { + if (deleteToken(serial, token)) + { + rv = 0; + } + else + { + rv = 1; + } + } + + // Finalize the library + if (needP11) + { + p11->C_Finalize(NULL_PTR); + unloadLibrary(moduleHandle); + } + + return rv; +} + +// Check the basic setup of SoftHSM +bool checkSetup() +{ + // Initialize the SoftHSM internal functions + if (!initSoftHSM()) + { + finalizeSoftHSM(); + return false; + } + + std::string basedir = Configuration::i()->getString("directories.tokendir", DEFAULT_TOKENDIR); + + // Try open the token directory + Directory storeDir(basedir); + if (!storeDir.isValid()) + { + fprintf(stderr, "ERROR: Failed to enumerate object store in %s\n", basedir.c_str()); + finalizeSoftHSM(); + return false; + } + + finalizeSoftHSM(); + return true; +} + +// Initialize the token +int initToken(CK_SLOT_ID slotID, char* label, char* soPIN, char* userPIN) +{ + char so_pin_copy[MAX_PIN_LEN+1]; + char user_pin_copy[MAX_PIN_LEN+1]; + + if (label == NULL) + { + fprintf(stderr, "ERROR: A label for the token must be supplied. " + "Use --label <text>\n"); + return 1; + } + + if (strlen(label) > 32) + { + fprintf(stderr, "ERROR: The token label must not have a length " + "greater than 32 chars.\n"); + return 1; + } + + // Get the passwords + if (getPW(soPIN, so_pin_copy, CKU_SO) != 0) + { + fprintf(stderr, "ERROR: Could not get SO PIN\n"); + return 1; + } + if (getPW(userPIN, user_pin_copy, CKU_USER) != 0) + { + fprintf(stderr, "ERROR: Could not get user PIN\n"); + return 1; + } + + // Load the variables + CK_UTF8CHAR paddedLabel[32]; + memset(paddedLabel, ' ', sizeof(paddedLabel)); + memcpy(paddedLabel, label, strlen(label)); + + CK_RV rv = p11->C_InitToken(slotID, (CK_UTF8CHAR_PTR)so_pin_copy, strlen(so_pin_copy), paddedLabel); + + switch (rv) + { + case CKR_OK: + break; + case CKR_SLOT_ID_INVALID: + fprintf(stderr, "CKR_SLOT_ID_INVALID: Slot %lu does not exist.\n", slotID); + return 1; + break; + case CKR_PIN_INCORRECT: + fprintf(stderr, "CKR_PIN_INCORRECT: The given SO PIN does not match the " + "one in the token. Needed when reinitializing the token.\n"); + return 1; + break; + case CKR_TOKEN_NOT_PRESENT: + fprintf(stderr, "CKR_TOKEN_NOT_PRESENT: The token is not present. " + "Please read the HSM manual for further assistance.\n"); + return 1; + break; + default: + fprintf(stderr, "ERROR rv=0x%08X: Could not initialize the token.\n", (unsigned int)rv); + fprintf(stderr, "Please check log files for additional information.\n"); + return 1; + break; + } + + CK_SESSION_HANDLE hSession; + rv = p11->C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not open a session with the library.\n"); + return 1; + } + + rv = p11->C_Login(hSession, CKU_SO, (CK_UTF8CHAR_PTR)so_pin_copy, strlen(so_pin_copy)); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not log in on the token.\n"); + return 1; + } + + rv = p11->C_InitPIN(hSession, (CK_UTF8CHAR_PTR)user_pin_copy, strlen(user_pin_copy)); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not initialize the user PIN.\n"); + return 1; + } + + // Get the token info + CK_TOKEN_INFO tokenInfo; + rv = p11->C_GetTokenInfo(slotID, &tokenInfo); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get info about the initialized token in slot %lu.\n", slotID); + return 1; + } + + // Reload the library + p11->C_Finalize(NULL_PTR); + rv = p11->C_Initialize(NULL_PTR); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not initialize the library.\n"); + return 1; + } + + // Get the slotID + CK_SLOT_ID newSlotID; + if (findSlot(tokenInfo, newSlotID)) + { + return 1; + } + + if (slotID == newSlotID) + { + printf("The token has been initialized on slot %lu\n", newSlotID); + } + else + { + printf("The token has been initialized and is reassigned to slot %lu\n", newSlotID); + } + + return 0; +} + +// Delete the token +bool deleteToken(char* serial, char* token) +{ + if (serial == NULL && token == NULL) + { + fprintf(stderr, "ERROR: A token must be supplied. " + "Use --serial <serial> or --token <label>\n"); + return false; + } + + // Initialize the SoftHSM internal functions + if (!initSoftHSM()) + { + finalizeSoftHSM(); + return false; + } + + bool rv = true; + std::string basedir = Configuration::i()->getString("directories.tokendir", DEFAULT_TOKENDIR); + std::string tokendir; + + rv = findTokenDirectory(basedir, tokendir, serial, token); + + if (rv) + { + std::string fulldir = basedir; + if (fulldir.find_last_of(OS_PATHSEP) != (fulldir.size()-1)) + { + fulldir += OS_PATHSEP + tokendir; + } + else + { + fulldir += tokendir; + } + + rv = rmdir(fulldir); + if (rv) + { + printf("The token (%s) has been deleted.\n", fulldir.c_str()); + } + } + + finalizeSoftHSM(); + + return rv; +} + +bool initSoftHSM() +{ + // Not using threading + MutexFactory::i()->disable(); + + // Initiate SecureMemoryRegistry + if (SecureMemoryRegistry::i() == NULL) + { + fprintf(stderr, "ERROR: Could not initiate SecureMemoryRegistry.\n"); + return false; + } + + // Build the CryptoFactory + if (CryptoFactory::i() == NULL) + { + fprintf(stderr, "ERROR: Could not initiate CryptoFactory.\n"); + return false; + } + +#ifdef WITH_FIPS + // Check the FIPS status + if (!CryptoFactory::i()->getFipsSelfTestStatus()) + { + fprintf(stderr, "ERROR: FIPS self test failed.\n"); + return false; + } +#endif + + // Load the configuration + if (!Configuration::i()->reload(SimpleConfigLoader::i())) + { + fprintf(stderr, "ERROR: Could not load the SoftHSM configuration.\n"); + return false; + } + + // Configure the log level + if (!setLogLevel(Configuration::i()->getString("log.level", DEFAULT_LOG_LEVEL))) + { + fprintf(stderr, "ERROR: Could not configure the log level.\n"); + return false; + } + + // Configure object store storage backend used by all tokens. + if (!ObjectStoreToken::selectBackend(Configuration::i()->getString("objectstore.backend", DEFAULT_OBJECTSTORE_BACKEND))) + { + fprintf(stderr, "ERROR: Could not select token backend.\n"); + return false; + } + + return true; +} + +void finalizeSoftHSM() +{ + CryptoFactory::reset(); + SecureMemoryRegistry::reset(); +} + +// Find the token directory +bool findTokenDirectory(std::string basedir, std::string& tokendir, char* serial, char* label) +{ + if (serial == NULL && label == NULL) + { + return false; + } + + // Load the variables + CK_UTF8CHAR paddedSerial[16]; + CK_UTF8CHAR paddedLabel[32]; + if (serial != NULL) + { + size_t inSize = strlen(serial); + size_t outSize = sizeof(paddedSerial); + if (inSize > outSize) + { + fprintf(stderr, "ERROR: --serial is too long.\n"); + return false; + } + memset(paddedSerial, ' ', outSize); + memcpy(paddedSerial, serial, inSize); + } + if (label != NULL) + { + size_t inSize = strlen(label); + size_t outSize = sizeof(paddedLabel); + if (inSize > outSize) + { + fprintf(stderr, "ERROR: --token is too long.\n"); + return false; + } + memset(paddedLabel, ' ', outSize); + memcpy(paddedLabel, label, inSize); + } + + // Find all tokens in the specified path + Directory storeDir(basedir); + + if (!storeDir.isValid()) + { + fprintf(stderr, "Failed to enumerate object store in %s\n", basedir.c_str()); + + return false; + } + + // Assume that all subdirectories are tokens + std::vector<std::string> dirs = storeDir.getSubDirs(); + + ByteString tokenLabel; + ByteString tokenSerial; + CK_UTF8CHAR paddedTokenSerial[16]; + CK_UTF8CHAR paddedTokenLabel[32]; + size_t counter = 0; + for (std::vector<std::string>::iterator i = dirs.begin(); i != dirs.end(); i++) + { + memset(paddedTokenSerial, ' ', sizeof(paddedTokenSerial)); + memset(paddedTokenLabel, ' ', sizeof(paddedTokenLabel)); + + // Create a token instance + ObjectStoreToken* token = ObjectStoreToken::accessToken(basedir, *i); + + if (!token->isValid()) + { + delete token; + continue; + } + + if (token->getTokenLabel(tokenLabel) && tokenLabel.size() <= sizeof(paddedTokenLabel)) + { + strncpy((char*) paddedTokenLabel, (char*) tokenLabel.byte_str(), tokenLabel.size()); + } + if (token->getTokenSerial(tokenSerial) && tokenSerial.size() <= sizeof(paddedTokenSerial)) + { + strncpy((char*) paddedTokenSerial, (char*) tokenSerial.byte_str(), tokenSerial.size()); + } + + if (serial != NULL && label == NULL && + memcmp(paddedTokenSerial, paddedSerial, sizeof(paddedSerial)) == 0) + { + printf("Found token (%s) with matching serial.\n", i->c_str()); + tokendir = i->c_str(); + counter++; + } + if (serial == NULL && label != NULL && + memcmp(paddedTokenLabel, paddedLabel, sizeof(paddedLabel)) == 0) + { + printf("Found token (%s) with matching token label.\n", i->c_str()); + tokendir = i->c_str(); + counter++; + } + if (serial != NULL && label != NULL && + memcmp(paddedTokenSerial, paddedSerial, sizeof(paddedSerial)) == 0 && + memcmp(paddedTokenLabel, paddedLabel, sizeof(paddedLabel)) == 0) + { + printf("Found token (%s) with matching serial and token label.\n", i->c_str()); + tokendir = i->c_str(); + counter++; + } + + delete token; + } + + if (counter == 1) return true; + if (counter > 1) + { + fprintf(stderr, "ERROR: Found multiple matching tokens.\n"); + return false; + } + + fprintf(stderr, "ERROR: Could not find a token using --serial or --token.\n"); + return false; +} + + +// Delete a directory +bool rmdir(std::string path) +{ + bool rv = true; + +#ifndef _WIN32 + // Enumerate the directory + DIR* dir = opendir(path.c_str()); + + if (dir == NULL) + { + fprintf(stderr, "ERROR: Failed to open directory %s\n", path.c_str()); + return false; + } + + // Enumerate the directory + struct dirent* entry = NULL; + + while ((entry = readdir(dir)) != NULL) + { + bool handled = false; + + // Check if this is the . or .. entry + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) + { + continue; + } + + // Convert the name of the entry to a C++ string + std::string name(entry->d_name); + std::string fullPath = path + OS_PATHSEP + name; + +#if defined(_DIRENT_HAVE_D_TYPE) && defined(_BSD_SOURCE) + // Determine the type of the entry + switch(entry->d_type) + { + case DT_DIR: + // This is a directory + rv = rmdir(fullPath); + handled = true; + break; + case DT_REG: + // This is a regular file + rv = rm(fullPath); + handled = true; + break; + default: + break; + } +#endif + + if (rv == false) + break; + + if (!handled) + { + // The entry type has to be determined using lstat + struct stat entryStatus; + + if (!lstat(fullPath.c_str(), &entryStatus)) + { + if (S_ISDIR(entryStatus.st_mode)) + { + // This is a directory + rv = rmdir(fullPath); + } + else if (S_ISREG(entryStatus.st_mode)) + { + // This is a regular file + rv = rm(fullPath); + } + } + + if (rv == false) + break; + } + } + + // Close the directory + closedir(dir); +#else + // Enumerate the directory + std::string pattern; + intptr_t h; + struct _finddata_t fi; + + if ((path.back() == '/') || (path.back() == '\\')) + pattern = path + "*"; + else + pattern = path + "/*"; + memset(&fi, 0, sizeof(fi)); + h = _findfirst(pattern.c_str(), &fi); + if (h == -1) + { + // empty directory + if (errno == ENOENT) + goto finished; + + fprintf(stderr, "ERROR: Failed to open directory %s\n", path.c_str()); + + return false; + } + + // scan files & subdirs + do + { + // Check if this is the . or .. entry + if (!strcmp(fi.name, ".") || !strcmp(fi.name, "..")) + continue; + + std::string fullPath = path + OS_PATHSEP + fi.name; + if ((fi.attrib & _A_SUBDIR) == 0) + { + // This is a regular file + rv = rm(fullPath); + } + else + { + // This is a directory + rv = rmdir(fullPath); + } + + memset(&fi, 0, sizeof(fi)); + + if (rv == false) + break; + } while (_findnext(h, &fi) == 0); + + (void) _findclose(h); + + finished: +#endif + + if (rv == false) + return false; + + int result; +#ifndef _WIN32 + result = ::rmdir(path.c_str()); +#else + result = _rmdir(path.c_str()); +#endif + + if (result != 0) + { + fprintf(stderr, "ERROR: Could not delete the directory: %s\n", path.c_str()); + return false; + } + + return true; +} + +// Delete a file +bool rm(std::string path) +{ + int result; + +#ifndef _WIN32 + result = ::remove(path.c_str()); +#else + result = _unlink(path.c_str()); +#endif + + if (result != 0) + { + fprintf(stderr, "ERROR: Could not delete the file: %s\n", path.c_str()); + return false; + } + + return true; +} + +// Show what slots are available +int showSlots() +{ + CK_ULONG ulSlotCount; + CK_RV rv = p11->C_GetSlotList(CK_FALSE, NULL_PTR, &ulSlotCount); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get the number of slots.\n"); + return 1; + } + + CK_SLOT_ID_PTR pSlotList = (CK_SLOT_ID_PTR) malloc(ulSlotCount*sizeof(CK_SLOT_ID)); + if (!pSlotList) + { + fprintf(stderr, "ERROR: Could not allocate memory.\n"); + return 1; + } + + rv = p11->C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get the slot list.\n"); + free(pSlotList); + return 1; + } + + printf("Available slots:\n"); + + for (CK_ULONG i = 0; i < ulSlotCount; i++) + { + CK_SLOT_INFO slotInfo; + CK_TOKEN_INFO tokenInfo; + + rv = p11->C_GetSlotInfo(pSlotList[i], &slotInfo); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get info about slot %lu.\n", pSlotList[i]); + continue; + } + + printf("Slot %lu\n", pSlotList[i]); + printf(" Slot info:\n"); + printf(" Description: %.*s\n", 64, slotInfo.slotDescription); + printf(" Manufacturer ID: %.*s\n", 32, slotInfo.manufacturerID); + printf(" Hardware version: %i.%i\n", slotInfo.hardwareVersion.major, + slotInfo.hardwareVersion.minor); + printf(" Firmware version: %i.%i\n", slotInfo.firmwareVersion.major, + slotInfo.firmwareVersion.minor); + printf(" Token present: "); + if ((slotInfo.flags & CKF_TOKEN_PRESENT) == 0) + { + printf("no\n"); + continue; + } + + printf("yes\n"); + printf(" Token info:\n"); + + rv = p11->C_GetTokenInfo(pSlotList[i], &tokenInfo); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get info about the token in slot %lu.\n", + pSlotList[i]); + continue; + } + + printf(" Manufacturer ID: %.*s\n", 32, tokenInfo.manufacturerID); + printf(" Model: %.*s\n", 16, tokenInfo.model); + printf(" Hardware version: %i.%i\n", tokenInfo.hardwareVersion.major, + tokenInfo.hardwareVersion.minor); + printf(" Firmware version: %i.%i\n", tokenInfo.firmwareVersion.major, + tokenInfo.firmwareVersion.minor); + printf(" Serial number: %.*s\n", 16, tokenInfo.serialNumber); + printf(" Initialized: "); + if ((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == 0) + { + printf("no\n"); + } + else + { + printf("yes\n"); + } + + printf(" User PIN init.: "); + if ((tokenInfo.flags & CKF_USER_PIN_INITIALIZED) == 0) + { + printf("no\n"); + } + else + { + printf("yes\n"); + } + + printf(" Label: %.*s\n", 32, tokenInfo.label); + + } + + free(pSlotList); + + return 0; +} + +// Import a key pair from given path +int importKeyPair +( + char* filePath, + char* filePIN, + CK_SLOT_ID slotID, + char* userPIN, + char* label, + char* objectID, + int forceExec, + int noPublicKey +) +{ + char user_pin_copy[MAX_PIN_LEN+1]; + + if (label == NULL) + { + fprintf(stderr, "ERROR: A label for the object must be supplied. " + "Use --label <text>\n"); + return 1; + } + + if (objectID == NULL) + { + fprintf(stderr, "ERROR: An ID for the object must be supplied. " + "Use --id <hex>\n"); + return 1; + } + + size_t objIDLen = 0; + char* objID = hexStrToBin(objectID, strlen(objectID), &objIDLen); + if (objID == NULL) + { + fprintf(stderr, "Please edit --id <hex> to correct error.\n"); + return 1; + } + + CK_SESSION_HANDLE hSession; + CK_RV rv = p11->C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, + NULL_PTR, NULL_PTR, &hSession); + if (rv != CKR_OK) + { + if (rv == CKR_SLOT_ID_INVALID) + { + fprintf(stderr, "ERROR: The given slot does not exist.\n"); + } + else + { + fprintf(stderr, "ERROR: Could not open a session on the given slot.\n"); + } + free(objID); + return 1; + } + + // Get the password + if (getPW(userPIN, user_pin_copy, CKU_USER) != 0) + { + fprintf(stderr, "ERROR: Could not get user PIN\n"); + free(objID); + return 1; + } + + rv = p11->C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)user_pin_copy, strlen(user_pin_copy)); + if (rv != CKR_OK) + { + if (rv == CKR_PIN_INCORRECT) { + fprintf(stderr, "ERROR: The given user PIN does not match the one in the token.\n"); + } + else + { + fprintf(stderr, "ERROR: Could not log in on the token.\n"); + } + free(objID); + return 1; + } + + CK_OBJECT_HANDLE oHandle = searchObject(hSession, objID, objIDLen); + if (oHandle != CK_INVALID_HANDLE && forceExec == 0) + { + free(objID); + fprintf(stderr, "ERROR: The ID is already assigned to another object. " + "Use --force to override this message.\n"); + return 1; + } + + crypto_init(); + int result = crypto_import_key_pair(hSession, filePath, filePIN, label, objID, objIDLen, noPublicKey); + crypto_final(); + + free(objID); + + return result; +} + +// Import a secret key from given path +int importSecretKey(char* filePath, CK_SLOT_ID slotID, char* userPIN, char* label, char* objectID) +{ + char user_pin_copy[MAX_PIN_LEN+1]; + + if (label == NULL) + { + fprintf(stderr, "ERROR: A label for the object must be supplied. " + "Use --label <text>\n"); + return 1; + } + + if (objectID == NULL) + { + fprintf(stderr, "ERROR: An ID for the object must be supplied. " + "Use --id <hex>\n"); + return 1; + } + + size_t objIDLen = 0; + char* objID = hexStrToBin(objectID, strlen(objectID), &objIDLen); + if (objID == NULL) + { + fprintf(stderr, "Please edit --id <hex> to correct error.\n"); + return 1; + } + + // Get the password + if (getPW(userPIN, user_pin_copy, CKU_USER) != 0) + { + fprintf(stderr, "ERROR: Could not get user PIN\n"); + return 1; + } + + CK_SESSION_HANDLE hSession; + CK_RV rv = p11->C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, + NULL_PTR, NULL_PTR, &hSession); + if (rv != CKR_OK) + { + if (rv == CKR_SLOT_ID_INVALID) + { + fprintf(stderr, "ERROR: The given slot does not exist.\n"); + } + else + { + fprintf(stderr, "ERROR: Could not open a session on the given slot.\n"); + } + return 1; + } + + rv = p11->C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)user_pin_copy, strlen(user_pin_copy)); + if (rv != CKR_OK) + { + if (rv == CKR_PIN_INCORRECT) { + fprintf(stderr, "ERROR: The given user PIN does not match the one in the token.\n"); + } + else + { + fprintf(stderr, "ERROR: Could not log in on the token.\n"); + } + return 1; + } + + crypto_init(); + int result = crypto_import_aes_key(hSession, filePath, label, objID, objIDLen); + crypto_final(); + + return result; +} + +// Convert a char array of hexadecimal characters into a binary representation +char* hexStrToBin(char* objectID, int idLength, size_t* newLen) +{ + char* bytes = NULL; + + if (idLength < 2 || idLength % 2 != 0) + { + fprintf(stderr, "ERROR: Invalid length on hex string.\n"); + return NULL; + } + + for (int i = 0; i < idLength; i++) + { + if (hexdigit_to_int(objectID[i]) == -1) + { + fprintf(stderr, "ERROR: Invalid character in hex string.\n"); + return NULL; + } + } + + *newLen = idLength / 2; + bytes = (char*) malloc(*newLen); + if (bytes == NULL) + { + fprintf(stderr, "ERROR: Could not allocate memory.\n"); + return NULL; + } + + for (size_t i = 0; i < *newLen; i++) + { + bytes[i] = hexdigit_to_int(objectID[2*i]) * 16 + + hexdigit_to_int(objectID[2*i+1]); + } + + return bytes; +} + +// Return the integer value of a hexadecimal character +int hexdigit_to_int(char ch) +{ + switch (ch) + { + case '0': + return 0; + case '1': + return 1; + case '2': + return 2; + case '3': + return 3; + case '4': + return 4; + case '5': + return 5; + case '6': + return 6; + case '7': + return 7; + case '8': + return 8; + case '9': + return 9; + case 'a': + case 'A': + return 10; + case 'b': + case 'B': + return 11; + case 'c': + case 'C': + return 12; + case 'd': + case 'D': + return 13; + case 'e': + case 'E': + return 14; + case 'f': + case 'F': + return 15; + default: + return -1; + } +} + +// Search for an object +CK_OBJECT_HANDLE searchObject(CK_SESSION_HANDLE hSession, char* objID, size_t objIDLen) +{ + if (objID == NULL) + { + return CK_INVALID_HANDLE; + } + + CK_OBJECT_CLASS oClass = CKO_PRIVATE_KEY; + CK_OBJECT_HANDLE hObject = CK_INVALID_HANDLE; + CK_ULONG objectCount = 0; + + CK_ATTRIBUTE objTemplate[] = { + { CKA_CLASS, &oClass, sizeof(oClass) }, + { CKA_ID, objID, objIDLen } + }; + + CK_RV rv = p11->C_FindObjectsInit(hSession, objTemplate, 2); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not prepare the object search.\n"); + return CK_INVALID_HANDLE; + } + + rv = p11->C_FindObjects(hSession, &hObject, 1, &objectCount); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get the search results.\n"); + return CK_INVALID_HANDLE; + } + + rv = p11->C_FindObjectsFinal(hSession); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not finalize the search.\n"); + return CK_INVALID_HANDLE; + } + + if (objectCount == 0) + { + return CK_INVALID_HANDLE; + } + + return hObject; +} diff --git a/SoftHSMv2/src/bin/util/softhsm2-util.h b/SoftHSMv2/src/bin/util/softhsm2-util.h new file mode 100644 index 0000000..3c49314 --- /dev/null +++ b/SoftHSMv2/src/bin/util/softhsm2-util.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + softhsm2-util.h + + This program can be used for interacting with HSMs using PKCS#11. + The default library is the libsofthsm2.so + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_SOFTHSM2_UTIL_H +#define _SOFTHSM_V2_SOFTHSM2_UTIL_H + +#include "cryptoki.h" +#include <string> + +// Main functions + +void usage(); +bool checkSetup(); +int initToken(CK_SLOT_ID slotID, char* label, char* soPIN, char* userPIN); +bool deleteToken(char* serial, char* token); +bool findTokenDirectory(std::string basedir, std::string& tokendir, char* serial, char* label); +bool rmdir(std::string path); +bool rm(std::string path); +int showSlots(); +int importKeyPair(char* filePath, char* filePIN, CK_SLOT_ID slotID, char* userPIN, char* objectLabel, char* objectID, int forceExec, int noPublicKey); +int importSecretKey(char* filePath, CK_SLOT_ID slotID, char* userPIN, char* label, char* objectID); +int crypto_import_key_pair(CK_SESSION_HANDLE hSession, char* filePath, char* filePIN, char* label, char* objID, size_t objIDLen, int noPublicKey); +int crypto_import_aes_key(CK_SESSION_HANDLE hSession, char* filePath, char* label, char* objID, size_t objIDLen); + +// Support functions + +void crypto_init(); +void crypto_final(); + +/// SoftHSM internal funtions +bool initSoftHSM(); +void finalizeSoftHSM(); + +/// Hex +char* hexStrToBin(char* objectID, int idLength, size_t* newLen); +int hexdigit_to_int(char ch); + +/// Library +#if !defined(UTIL_BOTAN) && !defined(UTIL_OSSL) +static void* moduleHandle; +#endif +extern CK_FUNCTION_LIST_PTR p11; + +/// PKCS#11 support +CK_OBJECT_HANDLE searchObject(CK_SESSION_HANDLE hSession, char* objID, size_t objIDLen); + +#endif // !_SOFTHSM_V2_SOFTHSM2_UTIL_H diff --git a/SoftHSMv2/src/bin/win32/getopt.cpp b/SoftHSMv2/src/bin/win32/getopt.cpp new file mode 100644 index 0000000..dfeabe2 --- /dev/null +++ b/SoftHSMv2/src/bin/win32/getopt.cpp @@ -0,0 +1,520 @@ +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <config.h> +#include <getopt.h> +#include <stdlib.h> +#include <string.h> + +#ifdef _WIN32 + +/* Windows needs warnx(). We change the definition though: + * 1. (another) global is defined, opterrmsg, which holds the error message + * 2. errors are always printed out on stderr w/o the program name + * Note that opterrmsg always gets set no matter what opterr is set to. The + * error message will not be printed if opterr is 0 as usual. + */ + +#include <stdio.h> +#include <stdarg.h> + +extern char opterrmsg[128]; +char opterrmsg[128]; /* last error message is stored here */ + +static void warnx(int print_error, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (fmt != NULL) + _vsnprintf(opterrmsg, 128, fmt, ap); + else + opterrmsg[0]='\0'; + va_end(ap); + if (print_error) { + fprintf(stderr, opterrmsg); + fprintf(stderr, "\n"); + } +} + +#endif /*_WIN32*/ + +/* not part of the original file */ +#ifndef _DIAGASSERT +#define _DIAGASSERT(X) +#endif + +#if HAVE_CONFIG_H && !HAVE_GETOPT_LONG && !HAVE_DECL_OPTIND +#define REPLACE_GETOPT +#endif + +int opterr = 1; /* if error message should be printed */ +int optind = 1; /* index into parent argv vector */ +int optopt = '?'; /* character checked for validity */ +int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#if !HAVE_GETOPT_LONG +#define IGNORE_FIRST (*options == '-' || *options == '+') +#define PRINT_ERROR ((opterr) && ((*options != ':') \ + || (IGNORE_FIRST && options[1] != ':'))) +#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL) +#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST) +/* XXX: GNU ignores PC if *options == '-' */ +#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-') + +/* return values */ +#define BADCH (int)'?' +#define BADARG ((IGNORE_FIRST && options[1] == ':') \ + || (*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 + +#define EMSG "" + +static int getopt_internal(int, char * const *, const char *); +static int gcd(int, int); +static void permute_args(int, int, int, char * const *); + +static char *place = EMSG; /* option letter processing */ + +/* XXX: set optreset to 1 rather than these two */ +static int nonopt_start = -1; /* first non option argument (for permute) */ +static int nonopt_end = -1; /* first option after non options (for permute) */ + +/* Error messages */ +static const char recargchar[] = "option requires an argument -- %c"; +static const char recargstring[] = "option requires an argument -- %s"; +static const char ambig[] = "ambiguous option -- %.*s"; +static const char noarg[] = "option doesn't take an argument -- %.*s"; +static const char illoptchar[] = "unknown option -- %c"; +static const char illoptstring[] = "unknown option -- %s"; + + +/* + * Compute the greatest common divisor of a and b. + */ +static int +gcd(int a, int b) +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return b; +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void +permute_args(int panonopt_start, int panonopt_end, + int opt_end, char * const *nargv) +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + _DIAGASSERT(nargv != NULL); + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **) nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **)nargv)[cstart] = swap; + } + } +} + +/* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + * Returns -2 if -- is found (can be long option or end of options marker). + */ +static int +getopt_internal(int nargc, char * const *nargv, const char *options) +{ + char *oli; /* option letter list index */ + int optchar; + + _DIAGASSERT(nargv != NULL); + _DIAGASSERT(options != NULL); + + optarg = NULL; + + /* + * XXX Some programs (like rsyncd) expect to be able to + * XXX re-initialize optind to 0 and have getopt_long(3) + * XXX properly function again. Work around this braindamage. + */ + if (optind == 0) + optind = 1; + + if (optreset) + nonopt_start = nonopt_end = -1; +start: + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return -1; + } + if ((*(place = nargv[optind]) != '-') + || (place[1] == '\0')) { /* found non-option */ + place = EMSG; + if (IN_ORDER) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + optarg = nargv[optind++]; + return INORDER; + } + if (!PERMUTE) { + /* + * if no permutation wanted, stop parsing + * at first non-option + */ + return -1; + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + nonopt_start = optind - + (nonopt_end - nonopt_start); + nonopt_end = -1; + } + optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = optind; + if (place[1] && *++place == '-') { /* found "--" */ + place++; + return -2; + } + } + if ((optchar = (int)*place++) == (int)':' || + (oli = (char *) strchr(options + (IGNORE_FIRST ? 1 : 0), + optchar)) == NULL) { + /* option letter unknown or ':' */ + if (!*place) + ++optind; +#ifndef _WIN32 + if (PRINT_ERROR) + warnx(illoptchar, optchar); +#else + warnx(PRINT_ERROR, illoptchar, optchar); +#endif + optopt = optchar; + return BADCH; + } + if (optchar == 'W' && oli[1] == ';') { /* -W long-option */ + /* XXX: what if no long options provided (called by getopt)? */ + if (*place) + return -2; + + if (++optind >= nargc) { /* no arg */ + place = EMSG; +#ifndef _WIN32 + if (PRINT_ERROR) + warnx(recargchar, optchar); +#else + warnx(PRINT_ERROR, recargchar, optchar); +#endif + optopt = optchar; + return BADARG; + } else /* white space */ + place = nargv[optind]; + /* + * Handle -W arg the same as --arg (which causes getopt to + * stop parsing). + */ + return -2; + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++optind; + } else { /* takes (optional) argument */ + optarg = NULL; + if (*place) /* no white space */ + optarg = place; + /* XXX: disable test for :: if PC? (GNU doesn't) */ + else if (oli[1] != ':') { /* arg not optional */ + if (++optind >= nargc) { /* no arg */ + place = EMSG; +#ifndef _WIN32 + if (PRINT_ERROR) + warnx(recargchar, optchar); +#else + warnx(PRINT_ERROR, recargchar, optchar); +#endif + optopt = optchar; + return BADARG; + } else + optarg = nargv[optind]; + } + place = EMSG; + ++optind; + } + /* dump back option letter */ + return optchar; +} + +/* + * getopt -- + * Parse argc/argv argument vector. + * + * [eventually this will replace the real getopt] + */ +int +getopt(int nargc, char * const *nargv, const char *options) +{ + int retval; + + _DIAGASSERT(nargv != NULL); + _DIAGASSERT(options != NULL); + + if ((retval = getopt_internal(nargc, nargv, options)) == -2) { + ++optind; + /* + * We found an option (--), so if we skipped non-options, + * we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, optind, + nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + retval = -1; + } + return retval; +} + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +getopt_long(int nargc, + char * const *nargv, + const char *options, + const struct option *long_options, + int *idx) +{ + int retval; + + _DIAGASSERT(nargv != NULL); + _DIAGASSERT(options != NULL); + _DIAGASSERT(long_options != NULL); + /* idx may be NULL */ + + if ((retval = getopt_internal(nargc, nargv, options)) == -2) { + char *current_argv, *has_equal; + size_t current_argv_len; + int i, match; + + current_argv = place; + match = -1; + + optind++; + place = EMSG; + + if (*current_argv == '\0') { /* found "--" */ + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return -1; + } + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == + (unsigned)current_argv_len) { + /* exact match */ + match = i; + break; + } + if (match == -1) /* partial match */ + match = i; + else { + /* ambiguous abbreviation */ +#ifndef _WIN32 + if (PRINT_ERROR) + warnx(ambig, (int)current_argv_len, + current_argv); +#else + warnx(PRINT_ERROR, ambig, (int)current_argv_len, + current_argv); +#endif + optopt = 0; + return BADCH; + } + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { +#ifndef _WIN32 + if (PRINT_ERROR) + warnx(noarg, (int)current_argv_len, + current_argv); +#else + warnx(PRINT_ERROR, noarg, (int)current_argv_len, + current_argv); +#endif + /* + * XXX: GNU sets optopt to val regardless of + * flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + return BADARG; + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == + required_argument) { + /* + * optional argument doesn't use + * next nargv + */ + optarg = nargv[optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument; leading ':' + * indicates no error should be generated + */ +#ifndef _WIN32 + if (PRINT_ERROR) + warnx(recargstring, current_argv); +#else + warnx(PRINT_ERROR, recargstring, current_argv); +#endif + /* + * XXX: GNU sets optopt to val regardless + * of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + --optind; + return BADARG; + } + } else { /* unknown option */ +#ifndef _WIN32 + if (PRINT_ERROR) + warnx(illoptstring, current_argv); +#else + warnx(PRINT_ERROR, illoptstring, current_argv); +#endif + optopt = 0; + return BADCH; + } + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + retval = 0; + } else + retval = long_options[match].val; + if (idx) + *idx = match; + } + return retval; +} +#endif /* !GETOPT_LONG */ diff --git a/SoftHSMv2/src/bin/win32/getopt.h b/SoftHSMv2/src/bin/win32/getopt.h new file mode 100644 index 0000000..f6b65a5 --- /dev/null +++ b/SoftHSMv2/src/bin/win32/getopt.h @@ -0,0 +1,101 @@ +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +#ifdef _WIN32 +/* from <sys/cdefs.h> */ +# ifdef __cplusplus +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +# else +# define __BEGIN_DECLS +# define __END_DECLS +# endif +# define __P(args) args +#endif + +/*#ifndef _WIN32 +#include <sys/cdefs.h> +#include <unistd.h> +#endif*/ + +/* + * Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions + */ +#if !defined(_POSIX_SOURCE) && !defined(_XOPEN_SOURCE) +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +struct option { + /* name of long option */ + const char *name; + /* + * one of no_argument, required_argument, and optional_argument: + * whether option takes an argument + */ + int has_arg; + /* if not NULL, set *flag to val when option found */ + int *flag; + /* if flag not NULL, value to set *flag to; else return value */ + int val; +}; + +__BEGIN_DECLS +int getopt_long __P((int, char * const *, const char *, + const struct option *, int *)); +__END_DECLS +#endif + +#ifdef _WIN32 +/* These are global getopt variables */ +__BEGIN_DECLS + +extern int opterr, /* if error message should be printed */ + optind, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +extern char* optarg; /* argument associated with option */ + +/* Original getopt */ +int getopt __P((int, char * const *, const char *)); + +__END_DECLS +#endif + +#endif /* !_GETOPT_H_ */ diff --git a/SoftHSMv2/src/bin/win32/getpassphase.cpp b/SoftHSMv2/src/bin/win32/getpassphase.cpp new file mode 100644 index 0000000..9d8aaca --- /dev/null +++ b/SoftHSMv2/src/bin/win32/getpassphase.cpp @@ -0,0 +1,35 @@ +/* WIN32 getpassphrase */ + +#include <config.h> +#include <stdio.h> + +char * +getpassphrase(const char *prompt) { + static char buf[128]; + HANDLE h; + DWORD cc, mode; + int cnt; + + h = GetStdHandle(STD_INPUT_HANDLE); + fputs(prompt, stderr); + fflush(stderr); + fflush(stdout); + FlushConsoleInputBuffer(h); + GetConsoleMode(h, &mode); + SetConsoleMode(h, ENABLE_PROCESSED_INPUT); + + for (cnt = 0; cnt < sizeof(buf) - 1; cnt++) + { + ReadFile(h, buf + cnt, 1, &cc, NULL); + if (buf[cnt] == '\r') + break; + fputc('*', stdout); + fflush(stderr); + fflush(stdout); + } + + SetConsoleMode(h, mode); + buf[cnt] = '\0'; + fputs("\n", stderr); + return (buf); +} |