1 /* Copyright 2018 Intel Corporation, Inc
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
18 #include <sys/types.h>
26 #include "hwpluginif.h"
30 char hw_plugins_parent_dir[MAX_PARENT_PATH_NAME+1] = "";
31 char *default_hw_plugin_parent_dir = "/tmp/hwparent/";
33 SSHSM_HW_FUNCTIONS_t g_pluginfuncs;
37 Function name : prepareHWPlugin
38 Description: This function is expected to be called by C_Initialize
39 of softHSM. This function does following
40 -- Reads the parent directory entries
41 -- If the subdirectory entry starts with 'S', then it calls loadHWPlugin
42 -- if the loadHWPlugin returns failure, then it finds the next subdirectory
43 that start with 'S' and calls loadHWPlugin.
54 LOG("%s() called \n", __func__);
55 /** check if there is any envrionment variable defined to represent
56 ** hw plugin parent directory.
58 env = getenv("SSHSM_HW_PLUGINS_PARENT_DIR");
62 if (len > MAX_PARENT_PATH_NAME)
64 LOG("SSHSM_HW_PLUGINS_PARENT_DIR environment is too long %d \n", len);
65 return(SSHSM_HW_PLUGIN_ERROR_BASE + ENVIRONMENT_TOO_LONG);
67 strcpy(hw_plugins_parent_dir, env);
71 strcpy(hw_plugins_parent_dir, default_hw_plugin_parent_dir);
74 /**Read parent directory entries **/
76 dirhandle = opendir (hw_plugins_parent_dir);
77 if (dirhandle != NULL)
80 while (NULL != (entry = readdir (dirhandle)) )
83 /**Check if it is directory **/
84 if (entry->d_type == DT_DIR)
86 /** See if it starts with 'S' **/
87 if ((entry->d_name[0] == 'S') ||
88 (entry->d_name[0] == 's') )
90 /** Load plugin.so file if it exists in the subdirectory
91 load it and check whether the HW is present by calling
93 ret_val = loadHWPlugin( hw_plugins_parent_dir,
105 LOG ("Couldn't open the directory \n");
114 Function name : loadHWPlugin
115 Description: It first checks whether there is plugin.so file, activate
116 directory and at least one key directory. if any of them not present, then
117 it returns error. If all three are present, then it calls
118 of softHSM. It calls HwPlugin_Initiate_Activate_and_load_key() function.
121 int loadHWPlugin(char *parent_dir, char *pluginsubdir)
123 char fullpath[256+1];
125 struct dirent *entry;
126 char so_present, activate_dir_present, key_dir_present;
127 hwpluginentries_t *entries;
130 if (strlen(parent_dir) + strlen(pluginsubdir) > 256 )
132 LOG("hwpluing path is too long \n");
133 return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG);
136 strcpy(fullpath, parent_dir);
137 strcat(fullpath, pluginsubdir);
139 dirhandle = opendir(fullpath);
141 entries = malloc(sizeof(hwpluginentries_t));
142 if (entries == NULL )
144 LOG("Could not allocate entries \n");
146 return(SSHSM_HW_PLUGIN_ERROR_BASE + ALLOCATION_ERROR);
148 memset(entries, 0, sizeof(hwpluginentries_t));
150 if (dirhandle != NULL)
153 activate_dir_present = 0;
155 while (NULL != (entry = readdir (dirhandle)) )
157 /** Ensure that the directory has plugin.so file, activate directory,
158 ** at least one key directory
161 if ((entry->d_type == DT_REG) &&
162 (strcmp(entry->d_name, "plugin.so") == 0))
165 if (strlen(fullpath) + strlen("/")+ strlen(entry->d_name) > 256)
167 LOG("plugin so path is too long \n");
168 ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG);
171 strcpy(entries->so_full_path, fullpath);
172 strcat(entries->so_full_path, "/");
173 strcat(entries->so_full_path, entry->d_name);
176 if ((entry->d_type == DT_DIR) &&
177 (strcmp(entry->d_name, "activate") == 0 ))
179 activate_dir_present = 1;
180 if (strlen(fullpath) + 2*strlen("/")+ strlen(entry->d_name) > 256)
182 LOG("activate path is too long \n");
183 ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG);
186 strcpy(entries->activate_dir_full_path, fullpath);
187 strcat(entries->activate_dir_full_path, "/");
188 strcat(entries->activate_dir_full_path, entry->d_name);
189 strcat(entries->activate_dir_full_path, "/");
192 if ((entry->d_type == DT_DIR) &&
193 (strncmp(entry->d_name, "key", 3) == 0 ))
196 if (strlen(fullpath) + 2*strlen("/")+ strlen(entry->d_name) > 256)
198 LOG("activate path is too long \n");
199 ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG);
202 strcpy(entries->key_dir_full_path[entries->num_key_dirs],
204 strcat(entries->key_dir_full_path[entries->num_key_dirs], "/");
205 strcat(entries->key_dir_full_path[entries->num_key_dirs],
207 strcat(entries->key_dir_full_path[entries->num_key_dirs], "/");
208 entries->num_key_dirs++;
211 if (so_present && activate_dir_present && key_dir_present)
213 printf("so dir path: %s \n", entries->so_full_path);
214 printf("activate dir path: %s \n", entries->activate_dir_full_path);
215 ret_val = HwPlugin_Initiate_Activate_and_load_keys(entries);
220 if (!so_present || !activate_dir_present || !key_dir_present)
222 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);
223 return(SSHSM_HW_PLUGIN_ERROR_BASE + INCOMPLETE_PLUGIN_DIR);
228 LOG("Could not open hwplugin directory %s \n", fullpath);
229 return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_OPEN_ERROR);
238 ** Function name: HWPlugin_Initiate_Activate_and_load_keys
239 ** Description: This function loads plugin, gets the function pointers,
240 ** activates the plugin and then finally loads the keys
242 int HwPlugin_Initiate_Activate_and_load_keys(hwpluginentries_t *entries)
246 ret_val = load_hw_plugin_and_get_function_pointers(entries->so_full_path,
251 ret_val = init_hw_plugin(&g_pluginfuncs);
255 ret_val = activate_hw_plugin(entries, &g_pluginfuncs);
259 ret_val = load_keys_in_hw_plugin(entries, &g_pluginfuncs);
268 Function name : load_hw_plugin_and_get_function_pointers
271 int load_hw_plugin_and_get_function_pointers(char *so_path,
272 SSHSM_HW_FUNCTIONS_t *funcs)
274 int (*functogetpluginfuncs)(SSHSM_HW_FUNCTIONS_t *fs);
277 g_dl_handle = dlopen(so_path, RTLD_NOW);
278 if(g_dl_handle == NULL )
280 LOG("dlopen on %s failed: %s \n", so_path, dlerror());
281 return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_DL_OPEN_ERROR);
284 functogetpluginfuncs = NULL;
285 functogetpluginfuncs = dlsym(g_dl_handle,
286 "sshsm_hw_plugin_get_plugin_functions");
288 if (functogetpluginfuncs == NULL)
290 LOG("dlsym of sshsm_hw_plugin_get_plugin_functions : %s \n", dlerror() );
291 return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_DL_SYM_ERROR);
294 ret_val = functogetpluginfuncs(funcs);
299 int init_hw_plugin(SSHSM_HW_FUNCTIONS_t *funcs)
303 ret_val = (funcs->xxx_init)();
307 LOG("HWPlugin init failed \n" );
308 return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_INIT_ERROR);
315 int activate_hw_plugin(hwpluginentries_t *entries, SSHSM_HW_FUNCTIONS_t *funcs)
319 if( (entries == NULL) || (funcs == NULL) )
322 LOG("activate_hw_plugin: Input values are NULL \n");
325 /** Read all files starting with 'A' and pass the information to
329 SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t comp_buffers;
331 memset(&comp_buffers, 0, sizeof(SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t));
333 ret_val = get_all_file_contents(entries->activate_dir_full_path, 'A',
338 ret_val = (funcs->xxx_activate)(&comp_buffers);
339 //free_buffers(&comp_buffers);
346 int load_keys_in_hw_plugin(hwpluginentries_t *entries,
347 SSHSM_HW_FUNCTIONS_t *funcs)
353 //unsigned long hwkeyhandle=987654321;
354 //key_handle = (void *) &hwkeyhandle;
356 SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t comp_buffers;
359 Travese through all key directories and load the key in plugin
363 for(ii = 0; ii < entries->num_key_dirs; ii++)
365 memset(&comp_buffers, 0,
366 sizeof(SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t));
368 ret_val = get_all_file_contents(entries->key_dir_full_path[ii], 'K',
373 ret_val = (funcs->xxx_load_key)(&comp_buffers, &key_handle);
374 //free_buffers(&comp_buffers);
377 /** Get PKCS11 information **/
378 /** Call SoftHSM functions to create private key object */
379 ret_val = program_pkcs11_info(entries->key_dir_full_path[ii], &key_handle);
388 int get_all_file_contents(char *dirpath, char starting_char,
389 SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t *c_buffers )
392 struct dirent *entry;
394 buffer_info_t *buffer;
403 char fullpath[256+1];
405 dirhandle = opendir(dirpath);
406 if (dirhandle != NULL)
408 while (NULL != (entry = readdir (dirhandle)))
410 if ((entry->d_type == DT_REG) &&
411 (entry->d_name[0] == starting_char))
413 buffer = malloc(sizeof(buffer_info_t));
416 LOG("Could not allocate entries \n");
417 ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + ALLOCATION_ERROR);
420 token = strchr(entry->d_name, '.');
421 strcpy(buffer->id, token+1);
423 /** get full path of the file **/
424 if ((strlen(dirpath) + strlen(entry->d_name)) > 256)
426 LOG("file path is too long \n");
427 ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG);
431 strcpy(fullpath,dirpath);
432 strcat(fullpath, entry->d_name);
434 buffer->buffer = malloc(st.st_size);
435 if(buffer->buffer == NULL)
437 LOG("Could not allocate entries \n");
438 ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + ALLOCATION_ERROR);
442 buffer->length_of_buffer = st.st_size;
443 fd = open(fullpath, O_RDONLY);
446 LOG("Could not open file %s \n", fullpath);
447 ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + ALLOCATION_ERROR);
448 free(buffer->buffer);
453 if(read(fd, buffer->buffer, st.st_size) < 0)
455 LOG("Reading from file %s failed \n", fullpath);
461 /** Now write this buffer in c_buffers **/
462 c_buffers->buffer_info[c_buffers->num_buffers] = buffer;
463 c_buffers->num_buffers++;
470 LOG("Could not open hwplugin directory %s \n", dirpath);
471 return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_OPEN_ERROR);
476 //free_buffers(c_buffers);
481 void free_buffers ( SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t *c_buffers )
485 for(ii = 0; ii < c_buffers->num_buffers; ii++)
487 free(c_buffers->buffer_info[ii]->buffer);
488 free(c_buffers->buffer_info[ii]);
492 int program_pkcs11_info (char *dirpath, void *key_handle)
495 struct dirent *entry;
497 char fullpath[256+1];
503 unsigned int slot_id = 0;
504 unsigned char upin[64+1];
506 unsigned char keyid[64+1];
508 unsigned char key_label[64+1] = "";
513 dirhandle = opendir(dirpath);
514 if (dirhandle != NULL)
516 while (NULL != (entry = readdir (dirhandle)))
518 if (strcmp(entry->d_name, "pkcs11.cfg") == 0 )
520 /** get full path of the file **/
521 if ((strlen(dirpath) + strlen(entry->d_name)) > 256)
523 LOG("file path is too long \n");
524 ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG);
527 strcpy(fullpath,dirpath);
528 strcat(fullpath, entry->d_name);
530 fp = fopen(fullpath, "r");
533 ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG);
536 while (fgets(buffer, 80, fp) != NULL)
538 valuep = strchr(buffer, ':');
543 /** Looks like \n is part of buffer that is read via fgets
544 ** Replacce tha with 0 **/
545 endvalue = strchr(valuep+1, '\n');
548 if (strcmp(buffer, "slot") == 0)
550 slot_id = strtoul(valuep+1, NULL, 10);
553 if(strcmp(buffer, "key_id") == 0 )
555 strcpy((char*)keyid, valuep+1);
556 key_id_len = strlen((char*)keyid);
559 if(strcmp(buffer, "key_label") == 0 )
561 strcpy((char*)key_label, valuep+1);
564 if(strcmp(buffer, "upin") == 0 )
566 strcpy((char*) upin, valuep+1);
567 upin_len = strlen((char *) upin);
573 /** Program key in SoftHSM **/
574 ret_val = PrepareKeyInSoftHSM(slot_id, upin, upin_len, keyid,
575 key_id_len, key_label, key_handle);
587 /*** PrepareKeyInSoftHSM
588 ** Description: It creates the object in softhsm with given key id and
589 ** key label and also stores the keyhandle that was returned by hardware plugin
599 ** - SUCCESS or FAILURE
601 int PrepareKeyInSoftHSM(unsigned int slot_id,
602 unsigned char *upin, int upin_len,
603 unsigned char *key_id, int key_id_len,
604 unsigned char *key_label, void *key_handle)
606 CK_SESSION_HANDLE hSession;
609 CK_OBJECT_HANDLE hKey;
610 unsigned char key_handle_str[32] = {0};
612 printf ("slot %ul upin %s key_id %s key_label %s \n", slot_id, upin, key_id,
617 //ultoa((CK_ULONG)key_handle, key_handle_str, 16); // Linking error seen
618 printf("Key_handle to be stored: %lx \n", *((CK_ULONG *)key_handle) );
619 sprintf((char *) key_handle_str, "%lx", *((CK_ULONG *)key_handle));
623 printf("Input Key handle is NULL ! \n");
626 /** For creating the key object, first the session needs to be opened
627 C_OpenSession is used to open the session
629 ret_val = C_OpenSession(slot_id, CKF_SERIAL_SESSION | CKF_RW_SESSION,
630 NULL_PTR, NULL_PTR, &hSession);
632 if (ret_val != CKR_OK)
634 printf("OpenSession failed for slot %x \n", slot_id);
638 /** Next step is login
639 ** C_Login is used to login to the session
641 ret_val = C_Login(hSession, CKU_USER, upin, upin_len);
642 if (ret_val != CKR_OK)
644 printf("Login failed: 0x%lx | for slot %x upin below \n", ret_val, slot_id);
645 for (ii = 0; ii < upin_len; ii++ )
646 printf("%2x %c \n", upin[ii], upin[ii]);
650 CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY;
651 CK_KEY_TYPE keyType = CKK_RSA;
652 CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE ;
654 CK_ATTRIBUTE keyTemplate[] = {
655 { CKA_CLASS, &privClass, sizeof(privClass) },
656 { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
657 { CKA_LABEL, key_label, strlen((char *) key_label) },
658 { CKA_ID, key_id, (CK_ULONG)key_id_len },
659 { CKA_SIGN, &ckTrue, sizeof(ckTrue) },
660 { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) },
661 { CKA_UNWRAP, &ckFalse, sizeof(ckFalse) },
662 { CKA_TOKEN, &ckTrue, sizeof(ckTrue) },
663 { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) },
664 { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) },
665 { CKA_PUBLIC_EXPONENT, 0, 0},
666 { CKA_MODULUS, 0, 0},
667 { CKA_PRIVATE_EXPONENT, 0, 0},
668 { CKA_PRIME_2, 0, 0},
669 { CKA_EXPONENT_1, 0, 0},
670 { CKA_EXPONENT_2, 0, 0},
671 { CKA_COEFFICIENT, 0, 0},
672 { CKA_PRIME_1, key_handle_str, strlen((char *)key_handle_str) }
673 /** For now keep the key handle returned by Plugin in CK_PRIME_1.
674 ** TBD - Define new attribute to store this in future
678 ret_val = C_CreateObject(hSession, keyTemplate,
679 sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE),&hKey);
680 if (ret_val != CKR_OK)
682 printf("CreateObject failed: 0x%lx | for slot %x | keylabel %s | keyid below \n",
683 ret_val, slot_id, key_label);
684 for (ii = 0; ii < key_id_len; ii++ )
685 printf("%2x %c \n", key_id[ii], key_id[ii]);
689 ret_val = C_Logout(hSession);
690 if (ret_val != CKR_OK)
692 printf("Logout failed 0x%lx | for slot %x \n", ret_val, slot_id);
696 ret_val = C_CloseSession(hSession);
697 if (ret_val != CKR_OK)
699 printf("C_CloseSession failed for slot %x \n", slot_id);
706 int HwInfraSignInit(void *keyHandle, unsigned long mechanism,
707 void* param, int paramLen)
709 return ( g_pluginfuncs.xxx_rsa_sign_init(keyHandle, mechanism, param, paramLen) );
712 int HwInfraSign( void *keyHandle, unsigned long mechanism,
713 unsigned char *msg, int msg_len,
714 unsigned char *outsig, int *outsiglen)
716 return ( g_pluginfuncs.xxx_rsa_sign(keyHandle, mechanism, msg, msg_len,
717 outsig, outsiglen) );