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"
27 #include "OSAttributes.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;
36 Function name : prepareHWPlugin
37 Description: This function is expected to be called by C_Initialize
38 of softHSM. This function does following
39 -- Reads the parent directory entries
40 -- If the subdirectory entry starts with 'S', then it calls loadHWPlugin
41 -- if the loadHWPlugin returns failure, then it finds the next subdirectory
42 that start with 'S' and calls loadHWPlugin.
53 LOG("%s() called \n", __func__);
54 /** check if there is any envrionment variable defined to represent
55 ** hw plugin parent directory.
57 env = getenv("SSHSM_HW_PLUGINS_PARENT_DIR");
61 if (len > MAX_PARENT_PATH_NAME)
63 LOG("SSHSM_HW_PLUGINS_PARENT_DIR environment is too long %d \n", len);
64 return(SSHSM_HW_PLUGIN_ERROR_BASE + ENVIRONMENT_TOO_LONG);
66 strcpy(hw_plugins_parent_dir, env);
70 strcpy(hw_plugins_parent_dir, default_hw_plugin_parent_dir);
73 /**Read parent directory entries **/
75 dirhandle = opendir (hw_plugins_parent_dir);
76 if (dirhandle != NULL)
79 while (NULL != (entry = readdir (dirhandle)) )
82 /**Check if it is directory **/
83 if (entry->d_type == DT_DIR)
85 /** See if it starts with 'S' **/
86 if ((entry->d_name[0] == 'S') ||
87 (entry->d_name[0] == 's') )
89 /** Load plugin.so file if it exists in the subdirectory
90 load it and check whether the HW is present by calling
92 ret_val = loadHWPlugin( hw_plugins_parent_dir,
104 LOG ("Couldn't open the directory \n");
113 Function name : loadHWPlugin
114 Description: It first checks whether there is plugin.so file, activate
115 directory and at least one key directory. if any of them not present, then
116 it returns error. If all three are present, then it calls
117 of softHSM. It calls HwPlugin_Initiate_Activate_and_load_key() function.
120 int loadHWPlugin(char *parent_dir, char *pluginsubdir)
122 char fullpath[256+1];
124 struct dirent *entry;
125 char so_present, activate_dir_present, key_dir_present;
126 hwpluginentries_t *entries;
129 if (strlen(parent_dir) + strlen(pluginsubdir) > 256 )
131 LOG("hwpluing path is too long \n");
132 return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG);
135 strcpy(fullpath, parent_dir);
136 strcat(fullpath, pluginsubdir);
138 dirhandle = opendir(fullpath);
140 entries = (hwpluginentries_t*)malloc(sizeof(hwpluginentries_t));
141 if (entries == NULL )
143 LOG("Could not allocate entries \n");
145 return(SSHSM_HW_PLUGIN_ERROR_BASE + ALLOCATION_ERROR);
147 memset(entries, 0, sizeof(hwpluginentries_t));
149 if (dirhandle != NULL)
152 activate_dir_present = 0;
154 while (NULL != (entry = readdir (dirhandle)) )
156 /** Ensure that the directory has plugin.so file, activate directory,
157 ** at least one key directory
160 if ((entry->d_type == DT_REG) &&
161 (strcmp(entry->d_name, "plugin.so") == 0))
164 if (strlen(fullpath) + strlen("/")+ strlen(entry->d_name) > 256)
166 LOG("plugin so path is too long \n");
167 ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG);
170 strcpy(entries->so_full_path, fullpath);
171 strcat(entries->so_full_path, "/");
172 strcat(entries->so_full_path, entry->d_name);
175 if ((entry->d_type == DT_DIR) &&
176 (strcmp(entry->d_name, "activate") == 0 ))
178 activate_dir_present = 1;
179 if (strlen(fullpath) + 2*strlen("/")+ strlen(entry->d_name) > 256)
181 LOG("activate path is too long \n");
182 ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG);
185 strcpy(entries->activate_dir_full_path, fullpath);
186 strcat(entries->activate_dir_full_path, "/");
187 strcat(entries->activate_dir_full_path, entry->d_name);
188 strcat(entries->activate_dir_full_path, "/");
191 if ((entry->d_type == DT_DIR) &&
192 (strncmp(entry->d_name, "key", 3) == 0 ))
195 if (strlen(fullpath) + 2*strlen("/")+ strlen(entry->d_name) > 256)
197 LOG("activate path is too long \n");
198 ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG);
201 strcpy(entries->key_dir_full_path[entries->num_key_dirs],
203 strcat(entries->key_dir_full_path[entries->num_key_dirs], "/");
204 strcat(entries->key_dir_full_path[entries->num_key_dirs],
206 strcat(entries->key_dir_full_path[entries->num_key_dirs], "/");
207 entries->num_key_dirs++;
210 if (so_present && activate_dir_present && key_dir_present)
212 printf("so dir path: %s \n", entries->so_full_path);
213 printf("activate dir path: %s \n", entries->activate_dir_full_path);
214 ret_val = HwPlugin_Initiate_Activate_and_load_keys(entries);
219 if (!so_present || !activate_dir_present || !key_dir_present)
221 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);
222 return(SSHSM_HW_PLUGIN_ERROR_BASE + INCOMPLETE_PLUGIN_DIR);
227 LOG("Could not open hwplugin directory %s \n", fullpath);
228 return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_OPEN_ERROR);
237 ** Function name: HWPlugin_Initiate_Activate_and_load_keys
238 ** Description: This function loads plugin, gets the function pointers,
239 ** activates the plugin and then finally loads the keys
241 int HwPlugin_Initiate_Activate_and_load_keys(hwpluginentries_t *entries)
245 ret_val = load_hw_plugin_and_get_function_pointers(entries->so_full_path,
250 ret_val = init_hw_plugin(&g_pluginfuncs);
254 ret_val = activate_hw_plugin(entries, &g_pluginfuncs);
258 ret_val = load_keys_in_hw_plugin(entries, &g_pluginfuncs);
267 Function name : load_hw_plugin_and_get_function_pointers
270 int load_hw_plugin_and_get_function_pointers(char *so_path,
271 SSHSM_HW_FUNCTIONS_t *funcs)
273 int (*functogetpluginfuncs)(SSHSM_HW_FUNCTIONS_t *fs);
276 g_dl_handle = dlopen(so_path, RTLD_NOW);
277 if(g_dl_handle == NULL )
279 LOG("dlopen on %s failed: %s \n", so_path, dlerror());
280 return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_DL_OPEN_ERROR);
283 functogetpluginfuncs = NULL;
284 functogetpluginfuncs = (int (*)(SSHSM_HW_FUNCTIONS_t *)) dlsym(g_dl_handle,
285 "sshsm_hw_plugin_get_plugin_functions");
287 if (functogetpluginfuncs == NULL)
289 LOG("dlsym of sshsm_hw_plugin_get_plugin_functions : %s \n", dlerror() );
290 return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_DL_SYM_ERROR);
293 ret_val = functogetpluginfuncs(funcs);
298 int init_hw_plugin(SSHSM_HW_FUNCTIONS_t *funcs)
302 ret_val = (funcs->xxx_init)();
306 LOG("HWPlugin init failed \n" );
307 return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_INIT_ERROR);
314 int activate_hw_plugin(hwpluginentries_t *entries, SSHSM_HW_FUNCTIONS_t *funcs)
318 if( (entries == NULL) || (funcs == NULL) )
321 LOG("activate_hw_plugin: Input values are NULL \n");
324 /** Read all files starting with 'A' and pass the information to
328 SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t comp_buffers;
330 memset(&comp_buffers, 0, sizeof(SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t));
332 ret_val = get_all_file_contents(entries->activate_dir_full_path, 'A',
337 ret_val = (funcs->xxx_activate)(&comp_buffers);
338 //free_buffers(&comp_buffers);
344 int load_keys_in_hw_plugin(hwpluginentries_t *entries,
345 SSHSM_HW_FUNCTIONS_t *funcs)
351 //unsigned long hwkeyhandle=987654321;
352 //key_handle = (void *) &hwkeyhandle;
354 SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t comp_buffers;
355 SSHSM_HW_PLUGIN_IMPORT_PUBLIC_KEY_INFO_t import_public_key;
358 Travese through all key directories and load the key in plugin
362 for(ii = 0; ii < entries->num_key_dirs; ii++)
364 memset(&comp_buffers, 0,
365 sizeof(SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t));
367 ret_val = get_all_file_contents(entries->key_dir_full_path[ii], 'K',
372 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 */
380 ret_val = program_pkcs11_info(entries->key_dir_full_path[ii],
381 &key_handle, &import_public_key);
382 if (import_public_key.modulus != NULL)
383 free(import_public_key.modulus);
384 if (import_public_key.exponent != NULL)
385 free(import_public_key.exponent);
395 int get_all_file_contents(char *dirpath, char starting_char,
396 SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t *c_buffers )
399 struct dirent *entry;
401 buffer_info_t *buffer;
410 char fullpath[256+1];
412 dirhandle = opendir(dirpath);
413 if (dirhandle != NULL)
415 while (NULL != (entry = readdir (dirhandle)))
417 if ((entry->d_type == DT_REG) &&
418 (entry->d_name[0] == starting_char))
420 buffer = (buffer_info_t*) malloc(sizeof(buffer_info_t));
423 LOG("Could not allocate entries \n");
424 ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + ALLOCATION_ERROR);
427 token = strchr(entry->d_name, '.');
428 strcpy(buffer->id, token+1);
430 /** get full path of the file **/
431 if ((strlen(dirpath) + strlen(entry->d_name)) > 256)
433 LOG("file path is too long \n");
434 ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG);
438 strcpy(fullpath,dirpath);
439 strcat(fullpath, entry->d_name);
441 buffer->buffer = (unsigned char*) malloc(st.st_size);
442 if(buffer->buffer == NULL)
444 LOG("Could not allocate entries \n");
445 ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + ALLOCATION_ERROR);
449 buffer->length_of_buffer = st.st_size;
450 fd = open(fullpath, O_RDONLY);
453 LOG("Could not open file %s \n", fullpath);
454 ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + ALLOCATION_ERROR);
455 free(buffer->buffer);
460 if(read(fd, buffer->buffer, st.st_size) < 0)
462 LOG("Reading from file %s failed \n", fullpath);
468 /** Now write this buffer in c_buffers **/
469 c_buffers->buffer_info[c_buffers->num_buffers] = buffer;
470 c_buffers->num_buffers++;
477 LOG("Could not open hwplugin directory %s \n", dirpath);
478 return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_OPEN_ERROR);
483 //free_buffers(c_buffers);
488 void free_buffers ( SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t *c_buffers )
492 for(ii = 0; ii < c_buffers->num_buffers; ii++)
494 free(c_buffers->buffer_info[ii]->buffer);
495 free(c_buffers->buffer_info[ii]);
499 int program_pkcs11_info (char *dirpath, void *key_handle,
500 SSHSM_HW_PLUGIN_IMPORT_PUBLIC_KEY_INFO_t *import_public_key)
503 struct dirent *entry;
505 char fullpath[256+1];
511 unsigned int slot_id = 0;
512 unsigned char upin[64+1];
514 unsigned char keyid[64+1];
516 unsigned char key_label[64+1] = "";
521 dirhandle = opendir(dirpath);
522 if (dirhandle != NULL)
524 while (NULL != (entry = readdir (dirhandle)))
526 if (strcmp(entry->d_name, "pkcs11.cfg") == 0 )
528 /** get full path of the file **/
529 if ((strlen(dirpath) + strlen(entry->d_name)) > 256)
531 LOG("file path is too long \n");
532 ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG);
535 strcpy(fullpath,dirpath);
536 strcat(fullpath, entry->d_name);
538 fp = fopen(fullpath, "r");
541 ret_val = (SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_PATH_TOO_LONG);
544 while (fgets(buffer, 80, fp) != NULL)
546 valuep = strchr(buffer, ':');
551 /** Looks like \n is part of buffer that is read via fgets
552 ** Replacce tha with 0 **/
553 endvalue = strchr(valuep+1, '\n');
556 if (strcmp(buffer, "slot") == 0)
558 slot_id = strtoul(valuep+1, NULL, 10);
561 if(strcmp(buffer, "key_id") == 0 )
563 strcpy((char*)keyid, valuep+1);
564 key_id_len = strlen((char*)keyid);
567 if(strcmp(buffer, "key_label") == 0 )
569 strcpy((char*)key_label, valuep+1);
572 if(strcmp(buffer, "upin") == 0 )
574 strcpy((char*) upin, valuep+1);
575 upin_len = strlen((char *) upin);
581 /** Program key in SoftHSM **/
582 ret_val = PrepareKeyInSoftHSM(slot_id, upin, upin_len, keyid,
583 key_id_len, key_label, key_handle, import_public_key);
595 void long_to_byte_string(const unsigned long longValue, unsigned char *out, size_t *outlen)
597 unsigned long setValue = longValue;
598 unsigned char byteStrIn[8];
601 for (i = 0; i < 8; i++)
603 byteStrIn[7-i] = (unsigned char) (setValue & 0xFF);
606 for (i = 0; i < 8; i++)
611 memcpy(out, &byteStrIn[i], 8-i);
617 /*** PrepareKeyInSoftHSM
618 ** Description: It creates the object in softhsm with given key id and
619 ** key label and also stores the keyhandle that was returned by hardware plugin
629 ** - SUCCESS or FAILURE
631 int PrepareKeyInSoftHSM(unsigned int slot_id,
632 unsigned char *upin, int upin_len,
633 unsigned char *key_id, int key_id_len,
634 unsigned char *key_label, void *key_handle,
635 SSHSM_HW_PLUGIN_IMPORT_PUBLIC_KEY_INFO_t *import_public_key)
637 CK_SESSION_HANDLE hSession;
640 CK_OBJECT_HANDLE hKey;
641 unsigned char key_handle_str[32] = {0};
643 printf ("slot %ul upin %s key_id %s key_label %s \n", slot_id, upin, key_id,
647 printf("Input Key handle is NULL ! \n");
648 return (SSHSM_HW_PLUGIN_ERROR_BASE + INVALID_KEY_ERROR);
650 if (import_public_key->modulus == NULL ||
651 import_public_key->exponent == NULL)
653 return (SSHSM_HW_PLUGIN_ERROR_BASE + INVALID_KEY_ERROR);
656 /** For creating the key object, first the session needs to be opened
657 C_OpenSession is used to open the session
659 ret_val = C_OpenSession(slot_id, CKF_SERIAL_SESSION | CKF_RW_SESSION,
660 NULL_PTR, NULL_PTR, &hSession);
662 if (ret_val != CKR_OK)
664 printf("OpenSession failed for slot %x \n", slot_id);
668 /** Next step is login
669 ** C_Login is used to login to the session
671 ret_val = C_Login(hSession, CKU_USER, upin, upin_len);
672 if (ret_val != CKR_OK)
674 printf("Login failed: 0x%lx | for slot %x upin below \n", ret_val, slot_id);
675 for (ii = 0; ii < upin_len; ii++ )
676 printf("%2x %c \n", upin[ii], upin[ii]);
680 CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY;
681 CK_KEY_TYPE keyType = CKK_RSA;
682 CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE ;
684 unsigned long int key_id_int = atol( (const char*) key_id );
685 unsigned char byte_str[8];
687 long_to_byte_string(key_id_int, byte_str, &outlen);
689 CK_ATTRIBUTE keyTemplate[] = {
690 { CKA_CLASS, &privClass, sizeof(privClass) },
691 { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
692 { CKA_LABEL, key_label, strlen((char *) key_label) },
693 { CKA_ID, byte_str, outlen },
694 { CKA_SIGN, &ckTrue, sizeof(ckTrue) },
695 { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) },
696 { CKA_UNWRAP, &ckFalse, sizeof(ckFalse) },
697 { CKA_TOKEN, &ckTrue, sizeof(ckTrue) },
698 { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) },
699 { CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse) },
700 { CKA_SENSITIVE, &ckFalse, sizeof(ckFalse) },
701 { CKA_PUBLIC_EXPONENT, import_public_key->exponent, import_public_key->exponent_size},
702 //{ CKA_MODULUS, pN, sizeof(pN) },
703 { CKA_MODULUS, import_public_key->modulus, import_public_key->modulus_size },
704 { CKA_PRIVATE_EXPONENT, 0, 0 },
705 { CKA_PRIME_2, 0, 0},
706 { CKA_EXPONENT_1, 0, 0},
707 { CKA_EXPONENT_2, 0, 0},
708 { CKA_COEFFICIENT, 0, 0},
709 { CKA_OS_PRIVATE_HANDLE, (CK_VOID_PTR ) *((CK_ULONG*)key_handle), sizeof(CK_ULONG) }
713 CK_OBJECT_HANDLE hObject;
714 CK_ULONG ulObjectCount;
717 rv = C_FindObjectsInit(hSession, keyTemplate, 0);
719 LOG ("C_FindObjectsInit rv %ld\n", rv);
721 rv = C_FindObjects(hSession, &hObject, 16, &ulObjectCount);
722 printf("PrepareKeyInSoftHSM: ulObjectCount %ld\n", ulObjectCount);
723 if(rv != CKR_OK || ulObjectCount == 0) {
724 ret_val = C_CreateObject(hSession, keyTemplate,
725 sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE),&hKey);
726 if (ret_val != CKR_OK)
728 printf("CreateObject failed: 0x%lx | for slot %x | keylabel %s | keyid below \n",
729 ret_val, slot_id, key_label);
730 for (ii = 0; ii < key_id_len; ii++ )
731 printf("%2x %c \n", key_id[ii], key_id[ii]);
736 printf("PrepareKeyInSoftHSM: Object already exists\n");
739 rv = C_FindObjectsFinal(hSession);
741 LOG ("C_FindObjectsFinal rv %ld\n", rv);
744 ret_val = C_Logout(hSession);
745 if (ret_val != CKR_OK)
747 printf("Logout failed 0x%lx | for slot %x \n", ret_val, slot_id);
751 ret_val = C_CloseSession(hSession);
752 if (ret_val != CKR_OK)
754 printf("C_CloseSession failed for slot %x \n", slot_id);
761 int HwInfraSignInit(void *keyHandle, unsigned long mechanism,
762 void* param, int paramLen, void **hwCryptoOpaque)
764 if (g_pluginfuncs.xxx_rsa_sign_init == NULL)
765 return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_INIT_ERROR);
767 return (g_pluginfuncs.xxx_rsa_sign_init(keyHandle, mechanism, param,
768 paramLen, hwCryptoOpaque)) ;
772 int HwInfraSign(void *keyHandle, unsigned long mechanism,
773 unsigned char *msg, int msg_len, void *hwCryptoOpaque,
774 unsigned char *outsig, int *outsiglen)
776 if (g_pluginfuncs.xxx_rsa_sign == NULL)
777 return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_INIT_ERROR);
779 return ( g_pluginfuncs.xxx_rsa_sign(keyHandle, mechanism, msg, msg_len,
780 hwCryptoOpaque, outsig, outsiglen) );
783 int HwInfraSignUpdate(void *keyHandle, unsigned long mechanism,
784 unsigned char *param, int paramLen, void *hwCryptoOpaque)
786 if (g_pluginfuncs.xxx_rsa_sign_update == NULL)
787 return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_INIT_ERROR);
789 int x = ( g_pluginfuncs.xxx_rsa_sign_update(keyHandle, mechanism, param,
790 paramLen, hwCryptoOpaque) );
794 int HwInfraSignFinal(void *keyHandle, unsigned long mechanism,
795 void *hwCryptoOpaque,
796 unsigned char *outsig, int *outsiglen)
798 if (g_pluginfuncs.xxx_rsa_sign_final == NULL)
799 return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_INIT_ERROR);
801 return ( g_pluginfuncs.xxx_rsa_sign_final(keyHandle, mechanism,
802 hwCryptoOpaque, outsig, outsiglen) );
805 int HwInfraSignCleanup(void *keyHandle, unsigned long mechanism,
806 void *hwCryptoOpaque)
808 if (g_pluginfuncs.xxx_rsa_sign_cleanup == NULL)
809 return(SSHSM_HW_PLUGIN_ERROR_BASE + PLUGIN_INIT_ERROR);
811 return ( g_pluginfuncs.xxx_rsa_sign_cleanup(keyHandle, mechanism,