diff options
Diffstat (limited to 'SoftHSMv2/src/lib')
-rw-r--r-- | SoftHSMv2/src/lib/HwInfra/HwInfra.c | 719 | ||||
-rw-r--r-- | SoftHSMv2/src/lib/HwInfra/HwInfra.h | 87 | ||||
-rw-r--r-- | SoftHSMv2/src/lib/HwInfra/Makefile.am | 16 | ||||
-rwxr-xr-x | SoftHSMv2/src/lib/HwInfra/README | 24 | ||||
-rwxr-xr-x | SoftHSMv2/src/lib/HwInfra/hwpluginif.h | 223 | ||||
-rw-r--r-- | SoftHSMv2/src/lib/Makefile.am | 7 | ||||
-rw-r--r-- | SoftHSMv2/src/lib/SoftHSM.cpp | 174 | ||||
-rw-r--r-- | SoftHSMv2/src/lib/SoftHSM.h | 1 | ||||
-rw-r--r-- | SoftHSMv2/src/lib/session_mgr/Session.cpp | 19 | ||||
-rw-r--r-- | SoftHSMv2/src/lib/session_mgr/Session.h | 6 |
10 files changed, 1259 insertions, 17 deletions
diff --git a/SoftHSMv2/src/lib/HwInfra/HwInfra.c b/SoftHSMv2/src/lib/HwInfra/HwInfra.c new file mode 100644 index 0000000..528097d --- /dev/null +++ b/SoftHSMv2/src/lib/HwInfra/HwInfra.c @@ -0,0 +1,719 @@ +/* Copyright 2018 Intel Corporation, Inc +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <dirent.h> +#include <string.h> +#include <dlfcn.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include "HwInfra.h" +#include "hwpluginif.h" + +#include "cryptoki.h" + +char hw_plugins_parent_dir[MAX_PARENT_PATH_NAME+1] = ""; +char *default_hw_plugin_parent_dir = "/tmp/hwparent/"; +void *g_dl_handle; +SSHSM_HW_FUNCTIONS_t g_pluginfuncs; + + +/** + Function name : prepareHWPlugin + Description: This function is expected to be called by C_Initialize + of softHSM. This function does following + -- Reads the parent directory entries + -- If the subdirectory entry starts with 'S', then it calls loadHWPlugin + -- if the loadHWPlugin returns failure, then it finds the next subdirectory + that start with 'S' and calls loadHWPlugin. +**/ + +int prepareHWPlugin() +{ + DIR *dirhandle; + struct dirent *entry; + int len; + char *env; + int ret_val = 0; + + LOG("%s() called \n", __func__); + /** check if there is any envrionment variable defined to represent + ** hw plugin parent directory. + **/ + env = getenv("SSHSM_HW_PLUGINS_PARENT_DIR"); + if (env != NULL) + { + len = strlen(env); + if (len > MAX_PARENT_PATH_NAME) + { + LOG("SSHSM_HW_PLUGINS_PARENT_DIR environment is too long %d \n", len); + return(SSHSM_HW_PLUGIN_ERROR_BASE + ENVIRONMENT_TOO_LONG); + } + strcpy(hw_plugins_parent_dir, env); + } + else + { + strcpy(hw_plugins_parent_dir, default_hw_plugin_parent_dir); + } + + /**Read parent directory entries **/ + ret_val = -1; + dirhandle = opendir (hw_plugins_parent_dir); + if (dirhandle != NULL) + { + int count = 0; + while (NULL != (entry = readdir (dirhandle)) ) + { + count++; + /**Check if it is directory **/ + if (entry->d_type == DT_DIR) + { + /** See if it starts with 'S' **/ + if ((entry->d_name[0] == 'S') || + (entry->d_name[0] == 's') ) + { + /** Load plugin.so file if it exists in the subdirectory + load it and check whether the HW is present by calling + init function **/ + ret_val = loadHWPlugin( hw_plugins_parent_dir, + entry->d_name); + if(ret_val == 0) + { + break; + } + } + } + } + } + else + { + LOG ("Couldn't open the directory \n"); + return ret_val; + } + + closedir(dirhandle); + return ret_val; +} + +/** + Function name : loadHWPlugin + Description: It first checks whether there is plugin.so file, activate + directory and at least one key directory. if any of them not present, then + it returns error. If all three are present, then it calls + of softHSM. It calls HwPlugin_Initiate_Activate_and_load_key() function. +**/ + +int loadHWPlugin(char *parent_dir, char *pluginsubdir) +{ + char fullpath[256+1]; + DIR *dirhandle; + struct dirent *entry; + char so_present, activate_dir_present, key_dir_present; + hwpluginentries_t *entries; + int ret_val = -1; + + if (strlen(parent_dir) + strlen(pluginsubdir) > 256 ) + { + LOG("hwpluing path is too long \n"); + return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG); + } + + strcpy(fullpath, parent_dir); + strcat(fullpath, pluginsubdir); + + dirhandle = opendir(fullpath); + + entries = malloc(sizeof(hwpluginentries_t)); + if (entries == NULL ) + { + LOG("Could not allocate entries \n"); + closedir(dirhandle); + return(SSHSM_HW_PLUGIN_ERROR_BASE + ALLOCATION_ERROR); + } + memset(entries, 0, sizeof(hwpluginentries_t)); + + if (dirhandle != NULL) + { + so_present = 0; + activate_dir_present = 0; + key_dir_present = 0; + while (NULL != (entry = readdir (dirhandle)) ) + { + /** Ensure that the directory has plugin.so file, activate directory, + ** at least one key directory + **/ + + if ((entry->d_type == DT_REG) && + (strcmp(entry->d_name, "plugin.so") == 0)) + { + so_present = 1; + if (strlen(fullpath) + strlen("/")+ strlen(entry->d_name) > 256) + { + LOG("plugin so path is too long \n"); + ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG); + break; + } + strcpy(entries->so_full_path, fullpath); + strcat(entries->so_full_path, "/"); + strcat(entries->so_full_path, entry->d_name); + } + + if ((entry->d_type == DT_DIR) && + (strcmp(entry->d_name, "activate") == 0 )) + { + activate_dir_present = 1; + if (strlen(fullpath) + 2*strlen("/")+ strlen(entry->d_name) > 256) + { + LOG("activate path is too long \n"); + ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG); + break; + } + strcpy(entries->activate_dir_full_path, fullpath); + strcat(entries->activate_dir_full_path, "/"); + strcat(entries->activate_dir_full_path, entry->d_name); + strcat(entries->activate_dir_full_path, "/"); + } + + if ((entry->d_type == DT_DIR) && + (strncmp(entry->d_name, "key", 3) == 0 )) + { + key_dir_present = 1; + if (strlen(fullpath) + 2*strlen("/")+ strlen(entry->d_name) > 256) + { + LOG("activate path is too long \n"); + ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG); + break; + } + strcpy(entries->key_dir_full_path[entries->num_key_dirs], + fullpath); + strcat(entries->key_dir_full_path[entries->num_key_dirs], "/"); + strcat(entries->key_dir_full_path[entries->num_key_dirs], + entry->d_name); + strcat(entries->key_dir_full_path[entries->num_key_dirs], "/"); + entries->num_key_dirs++; + } + + if (so_present && activate_dir_present && key_dir_present) + { + printf("so dir path: %s \n", entries->so_full_path); + printf("activate dir path: %s \n", entries->activate_dir_full_path); + ret_val = HwPlugin_Initiate_Activate_and_load_keys(entries); + break; + } + } + + if (!so_present || !activate_dir_present || !key_dir_present) + { + LOG("Minimum set of entries not present hwplugin dir plugindir %s so_present %d activate present %d key present %d \n", fullpath, so_present, activate_dir_present, key_dir_present); + return(SSHSM_HW_PLUGIN_ERROR_BASE + INCOMPLETE_PLUGIN_DIR); + } + } + else + { + LOG("Could not open hwplugin directory %s \n", fullpath); + return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_OPEN_ERROR); + } + free(entries); + closedir(dirhandle); + return(ret_val); +} + + +/** +** Function name: HWPlugin_Initiate_Activate_and_load_keys +** Description: This function loads plugin, gets the function pointers, +** activates the plugin and then finally loads the keys +**/ +int HwPlugin_Initiate_Activate_and_load_keys(hwpluginentries_t *entries) +{ + int ret_val; + + ret_val = load_hw_plugin_and_get_function_pointers(entries->so_full_path, + &g_pluginfuncs); + if(ret_val != 0) + return(ret_val); + + ret_val = init_hw_plugin(&g_pluginfuncs); + if(ret_val != 0 ) + return(ret_val); + + ret_val = activate_hw_plugin(entries, &g_pluginfuncs); + if (ret_val != 0 ) + return(ret_val); + + ret_val = load_keys_in_hw_plugin(entries, &g_pluginfuncs); + if (ret_val != 0 ) + return(ret_val); + + return(0); +} + + +/** + Function name : load_hw_plugin_and_get_function_pointers +**/ + +int load_hw_plugin_and_get_function_pointers(char *so_path, + SSHSM_HW_FUNCTIONS_t *funcs) +{ + int (*functogetpluginfuncs)(SSHSM_HW_FUNCTIONS_t *fs); + int ret_val; + + g_dl_handle = dlopen(so_path, RTLD_NOW); + if(g_dl_handle == NULL ) + { + LOG("dlopen on %s failed: %s \n", so_path, dlerror()); + return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_DL_OPEN_ERROR); + } + + functogetpluginfuncs = NULL; + functogetpluginfuncs = dlsym(g_dl_handle, + "sshsm_hw_plugin_get_plugin_functions"); + + if (functogetpluginfuncs == NULL) + { + LOG("dlsym of sshsm_hw_plugin_get_plugin_functions : %s \n", dlerror() ); + return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_DL_SYM_ERROR); + } + + ret_val = functogetpluginfuncs(funcs); + + return ret_val; +} + +int init_hw_plugin(SSHSM_HW_FUNCTIONS_t *funcs) +{ + int ret_val; + + ret_val = (funcs->xxx_init)(); + + if(ret_val != 0 ) + { + LOG("HWPlugin init failed \n" ); + return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_INIT_ERROR); + + } + return(ret_val); +} + + +int activate_hw_plugin(hwpluginentries_t *entries, SSHSM_HW_FUNCTIONS_t *funcs) +{ + int ret_val; + + if( (entries == NULL) || (funcs == NULL) ) + { + ret_val = -1; + LOG("activate_hw_plugin: Input values are NULL \n"); + return ret_val; + } + /** Read all files starting with 'A' and pass the information to + ** plugin + **/ + + SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t comp_buffers; + + memset(&comp_buffers, 0, sizeof(SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t)); + + ret_val = get_all_file_contents(entries->activate_dir_full_path, 'A', + &comp_buffers); + + if (ret_val == 0 ) + { + ret_val = (funcs->xxx_activate)(&comp_buffers); + //free_buffers(&comp_buffers); + } + + return(ret_val); +} + + +int load_keys_in_hw_plugin(hwpluginentries_t *entries, + SSHSM_HW_FUNCTIONS_t *funcs) +{ + + int ret_val; + void *key_handle; + int ii; + //unsigned long hwkeyhandle=987654321; + //key_handle = (void *) &hwkeyhandle; + + SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t comp_buffers; + + /** + Travese through all key directories and load the key in plugin + **/ + + ret_val = -1; + for(ii = 0; ii < entries->num_key_dirs; ii++) + { + memset(&comp_buffers, 0, + sizeof(SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t)); + + ret_val = get_all_file_contents(entries->key_dir_full_path[ii], 'K', + &comp_buffers); + + if(ret_val == 0) + { + ret_val = (funcs->xxx_load_key)(&comp_buffers, &key_handle); + //free_buffers(&comp_buffers); + if(ret_val == 0) + { + /** Get PKCS11 information **/ + /** Call SoftHSM functions to create private key object */ + ret_val = program_pkcs11_info(entries->key_dir_full_path[ii], &key_handle); + } + } + + } + + return(0); +} + +int get_all_file_contents(char *dirpath, char starting_char, + SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t *c_buffers ) +{ + DIR *dirhandle; + struct dirent *entry; + + buffer_info_t *buffer; + char *token; + + struct stat st; + int fd; + + int ret_val = 0; + + + char fullpath[256+1]; + + dirhandle = opendir(dirpath); + if (dirhandle != NULL) + { + while (NULL != (entry = readdir (dirhandle))) + { + if ((entry->d_type == DT_REG) && + (entry->d_name[0] == starting_char)) + { + buffer = malloc(sizeof(buffer_info_t)); + if (buffer == NULL ) + { + LOG("Could not allocate entries \n"); + ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + ALLOCATION_ERROR); + break; + } + token = strchr(entry->d_name, '.'); + strcpy(buffer->id, token+1); + + /** get full path of the file **/ + if ((strlen(dirpath) + strlen(entry->d_name)) > 256) + { + LOG("file path is too long \n"); + ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG); + free(buffer); + break; + } + strcpy(fullpath,dirpath); + strcat(fullpath, entry->d_name); + stat(fullpath, &st); + buffer->buffer = malloc(st.st_size); + if(buffer->buffer == NULL) + { + LOG("Could not allocate entries \n"); + ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + ALLOCATION_ERROR); + free(buffer); + break; + } + buffer->length_of_buffer = st.st_size; + fd = open(fullpath, O_RDONLY); + if (fd == -1 ) + { + LOG("Could not open file %s \n", fullpath); + ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + ALLOCATION_ERROR); + free(buffer->buffer); + free(buffer); + break; + } + + if(read(fd, buffer->buffer, st.st_size) < 0) + { + LOG("Reading from file %s failed \n", fullpath); + continue; + } + + close(fd); + + /** Now write this buffer in c_buffers **/ + c_buffers->buffer_info[c_buffers->num_buffers] = buffer; + c_buffers->num_buffers++; + + } + } + } + else + { + LOG("Could not open hwplugin directory %s \n", dirpath); + return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_OPEN_ERROR); + } + + closedir(dirhandle); + //if (ret_val != 0 ) + //free_buffers(c_buffers); + + return(ret_val); +} + +void free_buffers ( SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t *c_buffers ) +{ + int ii; + + for(ii = 0; ii < c_buffers->num_buffers; ii++) + { + free(c_buffers->buffer_info[ii]->buffer); + free(c_buffers->buffer_info[ii]); + } +} + +int program_pkcs11_info (char *dirpath, void *key_handle) +{ + DIR *dirhandle; + struct dirent *entry; + + char fullpath[256+1]; + int ret_val = 0; + + FILE *fp; + char buffer[80+1]; + + unsigned int slot_id = 0; + unsigned char upin[64+1]; + int upin_len = 0; + unsigned char keyid[64+1]; + int key_id_len = 0; + unsigned char key_label[64+1] = ""; + char *valuep; + char *endvalue; + + + dirhandle = opendir(dirpath); + if (dirhandle != NULL) + { + while (NULL != (entry = readdir (dirhandle))) + { + if (strcmp(entry->d_name, "pkcs11.cfg") == 0 ) + { + /** get full path of the file **/ + if ((strlen(dirpath) + strlen(entry->d_name)) > 256) + { + LOG("file path is too long \n"); + ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG); + break; + } + strcpy(fullpath,dirpath); + strcat(fullpath, entry->d_name); + + fp = fopen(fullpath, "r"); + if(fp == NULL ) + { + ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG); + break; + } + while (fgets(buffer, 80, fp) != NULL) + { + valuep = strchr(buffer, ':'); + if(valuep == NULL) + continue; + valuep[0] = '\0'; + + /** Looks like \n is part of buffer that is read via fgets + ** Replacce tha with 0 **/ + endvalue = strchr(valuep+1, '\n'); + if(endvalue != NULL) + endvalue[0] = '\0'; + if (strcmp(buffer, "slot") == 0) + { + slot_id = strtoul(valuep+1, NULL, 10); + continue; + } + if(strcmp(buffer, "key_id") == 0 ) + { + strcpy((char*)keyid, valuep+1); + key_id_len = strlen((char*)keyid); + continue; + } + if(strcmp(buffer, "key_label") == 0 ) + { + strcpy((char*)key_label, valuep+1); + continue; + } + if(strcmp(buffer, "upin") == 0 ) + { + strcpy((char*) upin, valuep+1); + upin_len = strlen((char *) upin); + continue; + } + } + fclose(fp); + + /** Program key in SoftHSM **/ + ret_val = PrepareKeyInSoftHSM(slot_id, upin, upin_len, keyid, + key_id_len, key_label, key_handle); + + break; + } + + } + } + + return ret_val; +} + + +/*** PrepareKeyInSoftHSM +** Description: It creates the object in softhsm with given key id and +** key label and also stores the keyhandle that was returned by hardware plugin +** Inputs: +** - Slot ID +** - Key ID +** - Key Label +** - upin +** - pluginkeyHandle +** Output: +** - None +** Renturs +** - SUCCESS or FAILURE +*****/ +int PrepareKeyInSoftHSM(unsigned int slot_id, + unsigned char *upin, int upin_len, + unsigned char *key_id, int key_id_len, + unsigned char *key_label, void *key_handle) +{ + CK_SESSION_HANDLE hSession; + CK_RV ret_val; + int ii; + CK_OBJECT_HANDLE hKey; + unsigned char key_handle_str[32] = {0}; + + printf ("slot %ul upin %s key_id %s key_label %s \n", slot_id, upin, key_id, + key_label); + + if(!key_handle) + { + //ultoa((CK_ULONG)key_handle, key_handle_str, 16); // Linking error seen + printf("Key_handle to be stored: %lx \n", *((CK_ULONG *)key_handle) ); + sprintf((char *) key_handle_str, "%lx", *((CK_ULONG *)key_handle)); + } + else + { + printf("Input Key handle is NULL ! \n"); + } + + /** For creating the key object, first the session needs to be opened + C_OpenSession is used to open the session + **/ + ret_val = C_OpenSession(slot_id, CKF_SERIAL_SESSION | CKF_RW_SESSION, + NULL_PTR, NULL_PTR, &hSession); + + if (ret_val != CKR_OK) + { + printf("OpenSession failed for slot %x \n", slot_id); + return(ret_val); + } + + /** Next step is login + ** C_Login is used to login to the session + **/ + ret_val = C_Login(hSession, CKU_USER, upin, upin_len); + if (ret_val != CKR_OK) + { + printf("Login failed: 0x%lx | for slot %x upin below \n", ret_val, slot_id); + for (ii = 0; ii < upin_len; ii++ ) + printf("%2x %c \n", upin[ii], upin[ii]); + return(ret_val); + } + + CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_RSA; + CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE ; + + CK_ATTRIBUTE keyTemplate[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, key_label, strlen((char *) key_label) }, + { CKA_ID, key_id, (CK_ULONG)key_id_len }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_UNWRAP, &ckFalse, sizeof(ckFalse) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) }, + { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, + { CKA_PUBLIC_EXPONENT, 0, 0}, + { CKA_MODULUS, 0, 0}, + { CKA_PRIVATE_EXPONENT, 0, 0}, + { CKA_PRIME_2, 0, 0}, + { CKA_EXPONENT_1, 0, 0}, + { CKA_EXPONENT_2, 0, 0}, + { CKA_COEFFICIENT, 0, 0}, + { CKA_PRIME_1, key_handle_str, strlen((char *)key_handle_str) } + /** For now keep the key handle returned by Plugin in CK_PRIME_1. + ** TBD - Define new attribute to store this in future + ***/ + }; + + ret_val = C_CreateObject(hSession, keyTemplate, + sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE),&hKey); + if (ret_val != CKR_OK) + { + printf("CreateObject failed: 0x%lx | for slot %x | keylabel %s | keyid below \n", + ret_val, slot_id, key_label); + for (ii = 0; ii < key_id_len; ii++ ) + printf("%2x %c \n", key_id[ii], key_id[ii]); + //return(ret_val); + } + + ret_val = C_Logout(hSession); + if (ret_val != CKR_OK) + { + printf("Logout failed 0x%lx | for slot %x \n", ret_val, slot_id); + return(ret_val); + } + + ret_val = C_CloseSession(hSession); + if (ret_val != CKR_OK) + { + printf("C_CloseSession failed for slot %x \n", slot_id); + return(ret_val); + } + + return ret_val; +} + +int HwInfraSignInit(void *keyHandle, unsigned long mechanism, + void* param, int paramLen) +{ + return ( g_pluginfuncs.xxx_rsa_sign_init(keyHandle, mechanism, param, paramLen) ); +} + +int HwInfraSign( void *keyHandle, unsigned long mechanism, + unsigned char *msg, int msg_len, + unsigned char *outsig, int *outsiglen) +{ + return ( g_pluginfuncs.xxx_rsa_sign(keyHandle, mechanism, msg, msg_len, + outsig, outsiglen) ); +} + diff --git a/SoftHSMv2/src/lib/HwInfra/HwInfra.h b/SoftHSMv2/src/lib/HwInfra/HwInfra.h new file mode 100644 index 0000000..a62bd7d --- /dev/null +++ b/SoftHSMv2/src/lib/HwInfra/HwInfra.h @@ -0,0 +1,87 @@ +/* Copyright 2018 Intel Corporation, Inc +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include <stdio.h> +#include <sys/types.h> +#include <dirent.h> +#include <stdlib.h> +#include <string.h> + +#include "hwpluginif.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef __SSHSM_HW_INFRA_UTIL_H__ +#define __SSHSM_HW_INFRA_UTIL_H__ + +#define MAX_KEY_DIRS_SUPPORTED 64 + +typedef struct hwpluginentries_s { + char so_full_path[256+1]; + char activate_dir_full_path[256+1]; + int num_key_dirs; + char key_dir_full_path[MAX_KEY_DIRS_SUPPORTED][256+1]; +}hwpluginentries_t; + +int prepareHWPlugin(); +int loadHWPlugin(char *parent_dir, char *pluginsubdir); +int HwPlugin_Initiate_Activate_and_load_keys( hwpluginentries_t *); +int load_hw_plugin_and_get_function_pointers(char *, + SSHSM_HW_FUNCTIONS_t *funcs); +int init_hw_plugin(SSHSM_HW_FUNCTIONS_t *funcs); +int activate_hw_plugin(hwpluginentries_t *entries, SSHSM_HW_FUNCTIONS_t *funcs); +int load_keys_in_hw_plugin(hwpluginentries_t *entries, + SSHSM_HW_FUNCTIONS_t *funcs); +int get_all_file_contents(char *dirpath, char starting_char, + SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t *c_buffers ); + +void free_buffers ( SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t *c_buffers ); +int program_pkcs11_info (char *dirpath, void *key_handle); +int PrepareKeyInSoftHSM(unsigned int slot_id, + unsigned char *upin, int upin_len, + unsigned char *key_id, int key_id_len, + unsigned char *key_label, void *key_handle); + +int HwInfraSignInit(void *keyHandle, unsigned long mechanism, + void* param, int paramLen); + +int HwInfraSign( void *keyHandle, unsigned long mechanism, + unsigned char *msg, int msg_len, + unsigned char *outsig, int *outsiglen); + +#define MAX_PARENT_PATH_NAME 256 + +#define LOG printf +#define SSHSM_HW_PLUGIN_ERROR_BASE (10000) + +#define ENVIRONMENT_TOO_LONG (01) +#define PLUGIN_PATH_TOO_LONG (02) +#define PLUGIN_PATH_OPEN_ERROR (03) +#define INCOMPLETE_PLUGIN_DIR (04) +#define ALLOCATION_ERROR (05) +#define PLUGIN_DL_OPEN_ERROR (06) +#define PLUGIN_DL_SYM_ERROR (07) +#define PLUGIN_INIT_ERROR (10) + +#if defined(__cplusplus) +} +#endif + + +#endif /* __SSHSM_HW_INFRA_UTIL_H__ */ + + diff --git a/SoftHSMv2/src/lib/HwInfra/Makefile.am b/SoftHSMv2/src/lib/HwInfra/Makefile.am new file mode 100644 index 0000000..b327b15 --- /dev/null +++ b/SoftHSMv2/src/lib/HwInfra/Makefile.am @@ -0,0 +1,16 @@ +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +AM_CPPFLAGS = -I$(srcdir)/.. \ + -I$(srcdir)/../common \ + -I$(srcdir)/../crypto \ + -I$(srcdir)/../data_mgr \ + -I$(srcdir)/../object_store \ + -I$(srcdir)/../pkcs11 \ + -I$(srcdir)/../session_mgr + +noinst_LTLIBRARIES = libsofthsm_hwinfra.la +libsofthsm_hwinfra_la_SOURCES = HwInfra.c + +SUBDIRS = + +EXTRA_DIST = $(srcdir)/*.h diff --git a/SoftHSMv2/src/lib/HwInfra/README b/SoftHSMv2/src/lib/HwInfra/README new file mode 100755 index 0000000..ea301af --- /dev/null +++ b/SoftHSMv2/src/lib/HwInfra/README @@ -0,0 +1,24 @@ +/* Copyright 2018 Intel Corporation, Inc +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#Commands to build stub plugin +gcc -fPIC -c tpmplugin_stub.c +ld -shared -o plugin.so tpmplugin_stub.o + +#Commands to build hwinfra +gcc -o hwinfrautil hwinfrautil.c -ldl + + diff --git a/SoftHSMv2/src/lib/HwInfra/hwpluginif.h b/SoftHSMv2/src/lib/HwInfra/hwpluginif.h new file mode 100755 index 0000000..b078be3 --- /dev/null +++ b/SoftHSMv2/src/lib/HwInfra/hwpluginif.h @@ -0,0 +1,223 @@ +/* Copyright 2018 Intel Corporation, Inc +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef __SSHSM_HW_PLUGIN_IF_H__ +#define __SSHSM_HW_PLUGIN_IF_H__ + + +#if defined(__cplusplus) +extern "C" { +#endif + +#define MAX_ID_LENGTH (32) + +typedef struct buffer_info_s{ + char id[MAX_ID_LENGTH+1]; + int length_of_buffer; + unsigned char *buffer; + }buffer_info_t; + +/*** + * Init Callback + * Description: + * This function is called by HWPluginInfra as part of C_Initialize to figure + * out whether there is any correspnding HW is present to use this plugin. + * In case of TPM2.0 Plugin, + * it is expected that this function checks + * whether the TPM2.0 is present or not, by checking the capabilities + * using Tss2_Sys_GetCapability with TPM_CAP_TPM_PROPERTIES and + * TPM_PT_MANUFACTURER property. If this function returns SUCCESS, + * TPM plguin can assume that TPM2.0 is presenta nd return success + * In case of SGX Plugin: <To be filled> + * Parameters: + * Inputs: None + * OUtputs; None + * Returns : SUCCESS (if HW is present), FAILURE if HW is not present + * + ***/ +typedef int (*sshsm_hw_plugin_init)(); + +/*** + * UnInit Callback + * Description: This function is called by HWPluginInfra during C_Finalize(). + * This functin is gives chance for any cleanup by plugins. + ***/ +typedef int (*sshsm_hw_plugin_uninit)(); + + +/*** + * Activate Callback + * Description: This callback function is called by HWPluginInfra + * (as part of C_Intialize) to activate the + * HW via HW plugin. SofHSM HWPluginInfra reads set of files required for + * activation (from + * activation directory) and passes them as buffers. + * HWPluginInfra reads the file in 'activate directory' + * as part of C_Initialize and passes the file content as is + * to the activate callback function. + * If there are two files, then num_buffers in in_info would be 2. + * 'id' is name of the file (May not be used by TPM plugin) + * 'length_of_buffer' is the valid length of the buffer. + * 'buffer' contains the file content. + * HWPluginInfra in SoftHSM allocates memory for this structure and internal + * buffers and it frees them up after this function returns. Hence, + * the plugin should not expect that these buffers are valid after the call + * is returned. + * + * In case of TPM Plugin: + * It is expected that activate directory has a file with SRK Handle + * saved in it. Note that SRK is saved in TPM memory (persistence) + * Actiate function of TPM plugin is called with SRK handle. + * + ***/ +#define MAX_BUFFER_SEGMENTS 8 +typedef struct sshsm_hw_plugin_activate_in_info_s { + int num_buffers; + buffer_info_t *buffer_info[MAX_BUFFER_SEGMENTS]; +}SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t; + + +typedef int (*sshsm_hw_plugin_activate)( + SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t *activate_in_info + ); + + + +/*** + * Load Key Callback + * Description: This callback function is called by SoftHSM HWPluginInfra + * to load private keys into the HW using HW plugin. + * Each HW plugin expects the keys to be specific to its HW. + * Since SoftHSM HWPluginInfra is expected to be generic, the design + * chosen is that HWPluginInfra reads key content from files and pass + * that information to HW Plugins via this function pointer. + * Yet times, Key information for HW Plugins is exposed as multiple files. + * Hence, HWPluginInfra reads multiple files for each key. Since, there + * could be multiple keys, each set of files that correspond to one key + * is expected to have same file name, but with different extensions. Since + * the directory holding these file may also need to have other files + * related to key, but for PKCS11, it is expected that all HWPlugin related + * files should have its name start with HW. + * + * HWPluginInfra calls this callback function as many timne as number of + * distinct keys. For each distinct key, it reads the HW tagged files, loads + * them into the buffer pointers and calls the HW Plugin -loadkey- function. + * HWPluginInfra also stores the any returned buffers into the SoftHSM key + * object. + * + * In case of TPM Plugin, it does following: + * + * -- Gets the buffers in in_info structure. + * --- Typically, there are two buffers in TPM understandable way + * - public & private key portion + * --- From global variables, it knows SRKHandle, SAPI context. + * --- Using Tss2_Sys_Load(), it loads the key. + * + * -- In both cases, it also expected to return KeyHandle, which is + * keyObjectHandle in case of TPM. + * + * + ***/ + +/*** +typedef struct sshsm_hw_plugin_load_key_in_info_s { + int num_buffers; + buffer_info_t buffer_info[]; +}SSHSM_HW_PLUGIN_LOAD_KEY_IN_INFO_t; +***/ + + +typedef int (*sshsm_hw_plugin_load_key)( + SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t *loadkey_in_info, + void **keyHandle + ); + +typedef int (*sshsm_hw_plugin_unload_key)( + void **keyHandle + ); + + + +/*** + * Callback: RSA Sign Init + * Description: This is called by HWPluginInfra as part of C_SignInit function + * for RSA keys + */ + +typedef int (*sshsm_hw_plugin_rsa_sign_init)( + void *keyHandle, + unsigned long mechanism, + void *param, + int len + ); + + + +/*** + * Callback: RSA Sign Init + * Description: This is called by HWPluginInfra as part of C_Sign function + * for RSA keys. HWPluginInfra get the keyHandle from the key object. + * + * In case of TPM plugin, it does following: + * -- TSS2_Sys_Sing function is called. + * + * + */ + +typedef int (*sshsm_hw_plugin_rsa_sign)( + void *keyHandle, + unsigned long mechanism, + unsigned char *msg, + int msg_len, + unsigned char *outsig, + int *outsiglen + ); + +/*** + * Function Name: sshsm_hw_plugin_get_plugin_functions + * Descrpiton: Every HW plugin is expected to define this function. + * This function is expected to return its function as pointers to the + * caller. + * SoftHSM calls this function after loading the hw plugin .SO file. + * SoftHSM calls this function as part of C_initialize. + * Arugments: + * Outputs: funcs + * Inputs: None + * Return value: SUCCESS or FAILURE + * + ***/ + +typedef struct sshsm_hw_functions_s +{ + sshsm_hw_plugin_init xxx_init; + sshsm_hw_plugin_uninit xxx_uninit; + sshsm_hw_plugin_activate xxx_activate; + sshsm_hw_plugin_load_key xxx_load_key; + sshsm_hw_plugin_unload_key xxx_unload_key; + sshsm_hw_plugin_rsa_sign_init xxx_rsa_sign_init; + sshsm_hw_plugin_rsa_sign xxx_rsa_sign; + +}SSHSM_HW_FUNCTIONS_t; + + +int sshsm_hw_plugin_get_plugin_functions(SSHSM_HW_FUNCTIONS_t *funcs); + + +#if defined(__cplusplus) +} +#endif + +#endif + diff --git a/SoftHSMv2/src/lib/Makefile.am b/SoftHSMv2/src/lib/Makefile.am index c579d62..eac1704 100644 --- a/SoftHSMv2/src/lib/Makefile.am +++ b/SoftHSMv2/src/lib/Makefile.am @@ -8,6 +8,7 @@ AM_CPPFLAGS = -I$(srcdir)/common \ -I$(srcdir)/pkcs11 \ -I$(srcdir)/session_mgr \ -I$(srcdir)/slot_mgr \ + -I$(srcdir)/HwInfra \ @CRYPTO_INCLUDES@ lib_LTLIBRARIES = libsofthsm2.la @@ -23,7 +24,8 @@ libsofthsm2_la_LIBADD = common/libsofthsm_common.la \ handle_mgr/libsofthsm_handlemgr.la \ object_store/libsofthsm_objectstore.la \ session_mgr/libsofthsm_sessionmgr.la \ - slot_mgr/libsofthsm_slotmgr.la + slot_mgr/libsofthsm_slotmgr.la \ + HwInfra/libsofthsm_hwinfra.la libsofthsm2_la_LDFLAGS = -version-info @VERSION_INFO@ \ -avoid-version -module @@ -42,8 +44,9 @@ SUBDIRS = common \ object_store \ session_mgr \ slot_mgr \ + HwInfra \ handle_mgr \ test EXTRA_DIST = $(srcdir)/*.h \ - $(srcdir)/pkcs11/*.h + $(srcdir)/pkcs11/*.h diff --git a/SoftHSMv2/src/lib/SoftHSM.cpp b/SoftHSMv2/src/lib/SoftHSM.cpp index 7a23a8a..214178f 100644 --- a/SoftHSMv2/src/lib/SoftHSM.cpp +++ b/SoftHSMv2/src/lib/SoftHSM.cpp @@ -67,6 +67,8 @@ #include "P11Objects.h" #include "odd.h" +#include "HwInfra.h" + #if defined(WITH_OPENSSL) #include "OSSLCryptoFactory.h" #else @@ -101,6 +103,39 @@ std::auto_ptr<SoftHSM> SoftHSM::instance(NULL); #endif +static CK_RV Extract_key_handle(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, void *hwKeyHandle) +{ + CK_RV rv=CK_TRUE; + + // get value of the hw key handle + CK_ATTRIBUTE valAttrib[] = { + {CKA_PRIME_1, NULL_PTR, 0} + }; + + // Get the length of the attribute first + rv = C_GetAttributeValue(hSession, hObject, valAttrib, sizeof(valAttrib)/sizeof(CK_ATTRIBUTE)); + if(rv != CKR_OK) + { + printf("Getting length of keyHandle with C_GetAttributeValue() API failed ! \n"); + return rv; + } + + valAttrib[0].pValue = (CK_VOID_PTR) malloc(valAttrib[0].ulValueLen); + + rv = C_GetAttributeValue(hSession, hObject, valAttrib, sizeof(valAttrib)/sizeof(CK_ATTRIBUTE)); + + // Convert the keyHandle from string to CK_ULONG + sscanf((char*) valAttrib[0].pValue, "%lx", (CK_ULONG *) hwKeyHandle); + printf("Extract_key_handle:: hwKeyHandle: %lu \n", (CK_ULONG) hwKeyHandle); + + if(!(valAttrib[0].pValue)) + { + free(valAttrib[0].pValue); + } + + return rv; +} + static CK_RV newP11Object(CK_OBJECT_CLASS objClass, CK_KEY_TYPE keyType, CK_CERTIFICATE_TYPE certType, P11Object **p11object) { switch(objClass) { @@ -342,6 +377,7 @@ SoftHSM::SoftHSM() slotManager = NULL; sessionManager = NULL; handleManager = NULL; + isHWavailable = false; } // Destructor @@ -518,6 +554,17 @@ CK_RV SoftHSM::C_Initialize(CK_VOID_PTR pInitArgs) // Set the state to initialised isInitialised = true; + if(prepareHWPlugin()) + { + printf("HW plugin NOT available to use ! \n"); + isHWavailable = false; + } + else + { + printf("HW plugin available and initialized ! \n"); + isHWavailable = true; + } + return CKR_OK; } @@ -4168,20 +4215,33 @@ CK_RV SoftHSM::AsymSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechan #endif } - // Initialize signing - if (bAllowMultiPartOp && !asymCrypto->signInit(privateKey,mechanism,param,paramLen)) - { - asymCrypto->recyclePrivateKey(privateKey); - CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); - return CKR_MECHANISM_INVALID; - } - - // Check if re-authentication is required - if (key->getBooleanValue(CKA_ALWAYS_AUTHENTICATE, false)) - { - session->setReAuthentication(true); - } + // Initialize signing + if(isHWavailable) + { + // Extract HW key handle + CK_ULONG hwKeyHandle = 0; + if(!Extract_key_handle (hSession, hKey, &hwKeyHandle)) + { + LOG("ERROR in extracting key handle \n"); + session->resetOp(); + return CKR_GENERAL_ERROR; + } + LOG("Extracted key handle value: %lu \n", hwKeyHandle); + if(! HwInfraSignInit(&hwKeyHandle, mechanism, param, paramLen)) + { + return CKR_MECHANISM_INVALID; + } + } + else + { + if (bAllowMultiPartOp && !asymCrypto->signInit(privateKey,mechanism,param,paramLen)) + { + asymCrypto->recyclePrivateKey(privateKey); + CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); + return CKR_MECHANISM_INVALID; + } + } session->setOpType(SESSION_OP_SIGN); session->setAsymmetricCryptoOp(asymCrypto); session->setMechanism(mechanism); @@ -4189,6 +4249,7 @@ CK_RV SoftHSM::AsymSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechan session->setAllowMultiPartOp(bAllowMultiPartOp); session->setAllowSinglePartOp(true); session->setPrivateKey(privateKey); + session->setKeyHandle(hKey); return CKR_OK; } @@ -4336,6 +4397,79 @@ static CK_RV AsymSign(Session* session, CK_BYTE_PTR pData, CK_ULONG ulDataLen, C return CKR_OK; } +// AsymmetricAlgorithm version of C_Sign +static CK_RV AsymSignHW(CK_SESSION_HANDLE hSession, Session* session, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) +{ + AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp(); + AsymMech::Type mechanism = session->getMechanism(); + PrivateKey* privateKey = session->getPrivateKey(); + CK_ULONG hwKeyHandle = 0; + if (asymCrypto == NULL || !session->getAllowSinglePartOp() || privateKey == NULL) + { + session->resetOp(); + return CKR_OPERATION_NOT_INITIALIZED; + } + + // Size of the signature + CK_ULONG size = privateKey->getOutputLength(); + if (pSignature == NULL_PTR) + { + *pulSignatureLen = size; + return CKR_OK; + } + + // Check buffer sizeq + if (*pulSignatureLen < size) + { + *pulSignatureLen = size; + return CKR_BUFFER_TOO_SMALL; + } + + // Get the data + ByteString data; + + // We must allow input length <= k and therfore need to prepend the data with zeroes. + if (mechanism == AsymMech::RSA) { + data.wipe(size-ulDataLen); + } + + data += ByteString(pData, ulDataLen); + ByteString signature; + + // Extract HW key handle + CK_OBJECT_HANDLE hKey = session->getKeyHandle(); + if(!Extract_key_handle (hSession, hKey, &hwKeyHandle)) + { + LOG("ERROR in extracting key handle \n"); + session->resetOp(); + return CKR_GENERAL_ERROR; + } + LOG("Extracted key handle value: %lu \n", hwKeyHandle); + + // Sign the data + if(!HwInfraSign((void *)&hwKeyHandle, mechanism, + pData, ulDataLen, + pSignature, (int *) pulSignatureLen)) + { + session->resetOp(); + return CKR_GENERAL_ERROR; + } + + // Check size + if (*pulSignatureLen != size) + { + ERROR_MSG("The size of the signature differs from the size of the mechanism"); + session->resetOp(); + return CKR_GENERAL_ERROR; + } + + + session->resetOp(); + return CKR_OK; +} + + + // Sign the data in a single pass operation CK_RV SoftHSM::C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { @@ -4356,8 +4490,18 @@ CK_RV SoftHSM::C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ul return MacSign(session, pData, ulDataLen, pSignature, pulSignatureLen); else - return AsymSign(session, pData, ulDataLen, - pSignature, pulSignatureLen); + { + if(isHWavailable) + { + return AsymSignHW(hSession, session, pData, ulDataLen, + pSignature, pulSignatureLen); + } + else + { + return AsymSign(session, pData, ulDataLen, + pSignature, pulSignatureLen); + } + } } // MacAlgorithm version of C_SignUpdate diff --git a/SoftHSMv2/src/lib/SoftHSM.h b/SoftHSMv2/src/lib/SoftHSM.h index 70d497a..323f3a5 100644 --- a/SoftHSMv2/src/lib/SoftHSM.h +++ b/SoftHSMv2/src/lib/SoftHSM.h @@ -184,6 +184,7 @@ private: // Is the SoftHSM PKCS #11 library initialised? bool isInitialised; bool isRemovable; + bool isHWavailable; SessionObjectStore* sessionObjectStore; ObjectStore* objectStore; diff --git a/SoftHSMv2/src/lib/session_mgr/Session.cpp b/SoftHSMv2/src/lib/session_mgr/Session.cpp index 5db36fd..54c0ff7 100644 --- a/SoftHSMv2/src/lib/session_mgr/Session.cpp +++ b/SoftHSMv2/src/lib/session_mgr/Session.cpp @@ -58,6 +58,9 @@ Session::Session(Slot* inSlot, bool inIsReadWrite, CK_VOID_PTR inPApplication, C symmetricKey = NULL; param = NULL; paramLen = 0; + + // Storing Key handle in session + hKey = CK_INVALID_HANDLE; } // Constructor @@ -85,6 +88,9 @@ Session::Session() symmetricKey = NULL; param = NULL; paramLen = 0; + + // Storing Key handle in session + hKey = CK_INVALID_HANDLE; } // Destructor @@ -93,6 +99,19 @@ Session::~Session() resetOp(); } +void Session::setKeyHandle(CK_OBJECT_HANDLE inHKey) +{ + //store the key hanldle for subsequent use + hKey = inHKey; +} + + +CK_OBJECT_HANDLE Session::getKeyHandle() +{ + //return the Key handle for subsequent use + return hKey; +} + // Get session info CK_RV Session::getInfo(CK_SESSION_INFO_PTR pInfo) { diff --git a/SoftHSMv2/src/lib/session_mgr/Session.h b/SoftHSMv2/src/lib/session_mgr/Session.h index 142aaa5..128fb2b 100644 --- a/SoftHSMv2/src/lib/session_mgr/Session.h +++ b/SoftHSMv2/src/lib/session_mgr/Session.h @@ -124,6 +124,9 @@ public: void setSymmetricKey(SymmetricKey* inSymmetricKey); SymmetricKey* getSymmetricKey(); + void setKeyHandle(CK_OBJECT_HANDLE inHKey); + CK_OBJECT_HANDLE getKeyHandle(); + private: // Constructor Session(); @@ -170,6 +173,9 @@ private: // Symmetric Crypto SymmetricKey* symmetricKey; + + // Storing Key handle in session + CK_OBJECT_HANDLE hKey; }; #endif // !_SOFTHSM_V2_SESSION_H |