1 /*
2  * COPYRIGHT (c) International Business Machines Corp. 2001-2017
3  *
4  * This program is provided under the terms of the Common Public License,
5  * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this
6  * software constitutes recipient's acceptance of CPL-1.0 terms which can be
7  * found in the file LICENSE file or at
8  * https://opensource.org/licenses/cpl1.0.php
9  */
10 
11 /*
12  * openCryptoki ICSF token
13  *
14  * Author: Marcelo Cerri (mhcerri@br.ibm.com)
15  *
16  * Based on CCC token.
17  *
18  */
19 
20 #define _GNU_SOURCE
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <limits.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <pthread.h>
30 #include <errno.h>
31 #include "pkcs11types.h"
32 #include "defs.h"
33 #include "host_defs.h"
34 #include "pbkdf.h"
35 #include "h_extern.h"
36 #include "tok_specific.h"
37 #include "tok_struct.h"
38 #include "icsf_config.h"
39 #include "pbkdf.h"
40 #include "list.h"
41 #include "attributes.h"
42 #include "../api/apiproto.h"
43 #include "trace.h"
44 #include "shared_memory.h"
45 #include "slotmgr.h"
46 
47 /* Default token attributes */
48 const char manuf[] = "IBM Corp.";
49 const char model[] = "IBM ICSFTok ";
50 const char descr[] = "IBM PKCS#11 ICSF token";
51 const char label[] = "IBM OS PKCS#11   ";
52 
53 /* mechanisms provided by this token */
54 MECH_LIST_ELEMENT mech_list[] = {
55     {CKM_DES_KEY_GEN, {8, 8, CKF_HW | CKF_GENERATE}},
56     {CKM_DES_ECB, {0, 0, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}},
57     {CKM_DES_CBC, {0, 0, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}},
58     {CKM_DES_CBC_PAD,
59      {0, 0, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}},
60     {CKM_DES3_ECB, {0, 0, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}},
61     {CKM_DES3_CBC, {0, 0, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}},
62     {CKM_DES3_CBC_PAD,
63      {0, 0, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}},
64     {CKM_DES3_KEY_GEN, {24, 24, CKF_HW | CKF_GENERATE}},
65     {CKM_DES2_KEY_GEN, {24, 24, CKF_HW | CKF_GENERATE}},
66     {CKM_RSA_PKCS_KEY_PAIR_GEN, {512, 4096, CKF_HW | CKF_GENERATE_KEY_PAIR}},
67     {CKM_RSA_PKCS,
68      {512, 4096, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP |
69       CKF_SIGN | CKF_VERIFY | CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER}},
70     {CKM_RSA_X_509,
71      {512, 4096, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | CKF_VERIFY |
72       CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER}},
73     {CKM_MD5_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}},
74     {CKM_SHA1_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}},
75     {CKM_SHA256_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}},
76     {CKM_SHA384_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}},
77     {CKM_SHA512_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}},
78     {CKM_SHA_1, {0, 0, CKF_HW | CKF_DIGEST}},
79     {CKM_SHA_1_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}},
80     {CKM_SHA256_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}},
81     {CKM_SHA384_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}},
82     {CKM_SHA512_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}},
83     {CKM_MD5, {0, 0, CKF_DIGEST}},
84     {CKM_MD5_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}},
85     {CKM_AES_KEY_GEN, {16, 32, CKF_HW | CKF_GENERATE}},
86     {CKM_AES_ECB, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}},
87     {CKM_AES_CBC, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}},
88     {CKM_AES_CBC_PAD,
89      {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}},
90     {CKM_DH_PKCS_KEY_PAIR_GEN, {512, 2048, CKF_GENERATE_KEY_PAIR}},
91     {CKM_DH_PKCS_DERIVE, {512, 2048, CKF_DERIVE}},
92     {CKM_DSA_KEY_PAIR_GEN, {512, 2048, CKF_HW | CKF_GENERATE_KEY_PAIR}},
93     {CKM_DSA_SHA1, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}},
94     {CKM_DSA, {512, 2048, CKF_HW | CKF_SIGN | CKF_VERIFY}},
95     {CKM_ECDSA_SHA1,
96      {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_F_P |
97       CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS}},
98     {CKM_ECDSA,
99      {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_F_P |
100       CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS}},
101     {CKM_EC_KEY_PAIR_GEN,
102      {160, 521, CKF_HW | CKF_GENERATE_KEY_PAIR | CKF_EC_F_P |
103       CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS}},
104     {CKM_SSL3_PRE_MASTER_KEY_GEN, {48, 48, CKF_HW | CKF_GENERATE}},
105     {CKM_SSL3_MD5_MAC, {384, 384, CKF_SIGN | CKF_VERIFY}},
106     {CKM_SSL3_SHA1_MAC, {384, 384, CKF_SIGN | CKF_VERIFY}},
107     {CKM_SSL3_MASTER_KEY_DERIVE, {48, 48, CKF_DERIVE}},
108     {CKM_SSL3_KEY_AND_MAC_DERIVE, {48, 48, CKF_DERIVE}},
109     {CKM_TLS_KEY_AND_MAC_DERIVE, {48, 48, CKF_DERIVE}},
110     {CKM_GENERIC_SECRET_KEY_GEN, {80, 2048, CKF_HW | CKF_GENERATE}},
111 };
112 
113 CK_ULONG mech_list_len = (sizeof(mech_list) / sizeof(MECH_LIST_ELEMENT));
114 
115 /*
116  * This list contains one element to each session and it's used to keep
117  * session specific data. Any insertion or deletion in this list should
118  * be protected by sess_list_mutex.
119  *
120  * This lock is intended to protect the linked list, not the content of each
121  * element. Since PKCS#11 applications should not use the same session for
122  * different threads, the only concurrency that we have to deal is when adding
123  * or removing a session to or from the list.
124  */
125 list_t sessions = LIST_INIT();
126 extern pthread_mutex_t sess_list_mutex;
127 
128 /* Each element of the list sessions should have this type: */
129 struct session_state {
130     CK_SESSION_HANDLE session_id;
131     LDAP *ld;
132 
133     /* List element */
134     list_entry_t sessions;
135 };
136 
137 /*
138  * This binary tree keeps the mapping between ICSF object handles and PKCS#11
139  * object handles. The tree index is used as the PKCS#11 handle.
140  *
141  * Any insertion or deletion in this tree should be protected by
142  * obj_list_rw_mutex.
143  */
144 struct btree objects;
145 extern pthread_rwlock_t obj_list_rw_mutex;
146 
147 /* Each element of the btree objects should have this type: */
148 struct icsf_object_mapping {
149     CK_SESSION_HANDLE session_id;
150     struct icsf_object_record icsf_object;
151 };
152 
153 /*
154  * Structure used to keep track of data used in multi-part operations.
155  */
156 struct icsf_multi_part_context {
157     int initiated;
158     char chain_data[ICSF_CHAINING_DATA_LEN];
159     char *data;
160     size_t data_len;
161     size_t used_data_len;
162 };
163 
164 /*
165  * Get the session specific structure.
166  */
get_session_state(CK_SESSION_HANDLE session_id)167 static struct session_state *get_session_state(CK_SESSION_HANDLE session_id)
168 {
169     struct session_state *found = NULL;
170     struct session_state *s;
171 
172     /* Lock sessions list */
173     if (pthread_mutex_lock(&sess_list_mutex)) {
174         TRACE_ERROR("Failed to lock mutex.\n");
175         return NULL;
176     }
177 
178     for_each_list_entry(&sessions, struct session_state, s, sessions) {
179         if (s->session_id == session_id) {
180             found = s;
181             goto done;
182         }
183     }
184 
185 done:
186     /* Unlock */
187     if (pthread_mutex_unlock(&sess_list_mutex)) {
188         TRACE_ERROR("Mutex Unlock failed.\n");
189         return NULL;
190     }
191 
192     return found;
193 }
194 
195 /*
196  * Remove all mapped objects.
197  */
purge_object_mapping()198 static CK_RV purge_object_mapping()
199 {
200     bt_destroy(&objects, free);
201 
202     return CKR_OK;
203 }
204 
205 /* Store ICSF specific data for each slot*/
206 struct slot_data {
207     int initialized;
208     char conf_name[PATH_MAX + 1];
209     char uri[PATH_MAX + 1];
210     char dn[NAME_MAX + 1];
211     char ca_file[PATH_MAX + 1];
212     char cert_file[PATH_MAX + 1];
213     char key_file[PATH_MAX + 1];
214     int mech;
215 };
216 struct slot_data *slot_data[NUMBER_SLOTS_MANAGED];
217 
218 /*
219  * Converts an ICSF reason code to an ock error code
220  */
icsf_to_ock_err(int icsf_return_code,int icsf_reason_code)221 int icsf_to_ock_err(int icsf_return_code, int icsf_reason_code)
222 {
223     switch (icsf_return_code) {
224     case 0:
225         return CKR_OK;
226     case 4:
227         switch (icsf_reason_code) {
228         case 8000:
229         case 11000:
230             return CKR_SIGNATURE_INVALID;
231         }
232         break;
233     case 8:
234         switch (icsf_reason_code) {
235         case 2154:
236             return CKR_KEY_TYPE_INCONSISTENT;
237         case 2028:
238             return CKR_WRAPPED_KEY_INVALID;
239         case 3003:
240             return CKR_BUFFER_TOO_SMALL;
241         case 3019:
242             return CKR_SESSION_HANDLE_INVALID;
243         case 3027:
244             return CKR_SESSION_HANDLE_INVALID;
245         case 3029:
246             return CKR_ATTRIBUTE_TYPE_INVALID;
247         case 3030:
248             return CKR_ATTRIBUTE_VALUE_INVALID;
249         case 3033:
250             return CKR_TEMPLATE_INCOMPLETE;
251         case 3034:
252         case 3035:
253             return CKR_ATTRIBUTE_READ_ONLY;
254         case 3038:
255             return CKR_KEY_FUNCTION_NOT_PERMITTED;
256         case 3039:
257             return CKR_KEY_TYPE_INCONSISTENT;
258         case 3041:
259             return CKR_KEY_NOT_WRAPPABLE;
260         case 3043:
261             return CKR_KEY_HANDLE_INVALID;
262         case 3045:
263             return CKR_KEY_UNEXTRACTABLE;
264         case 72:
265         case 11000:
266             return CKR_DATA_LEN_RANGE;
267         case 11028:
268             return CKR_SIGNATURE_INVALID;
269         }
270         break;
271     }
272     return CKR_FUNCTION_FAILED;
273 }
274 
275 /*
276  * Called during C_Initialize.
277  */
icsftok_init(STDLL_TokData_t * tokdata,CK_SLOT_ID slot_id,char * conf_name)278 CK_RV icsftok_init(STDLL_TokData_t * tokdata, CK_SLOT_ID slot_id,
279                    char *conf_name)
280 {
281     CK_RV rc;
282     struct slot_data *data;
283 
284     TRACE_INFO("icsf %s slot=%lu running\n", __func__, slot_id);
285 
286     /* Check Slot ID */
287     if (slot_id >= NUMBER_SLOTS_MANAGED) {
288         TRACE_ERROR("Invalid slot ID: %lu\n", slot_id);
289         return CKR_FUNCTION_FAILED;
290     }
291 
292     rc = XProcLock(tokdata);
293     if (rc != CKR_OK)
294         return CKR_FUNCTION_FAILED;
295 
296     if (slot_data[slot_id] == NULL) {
297         TRACE_ERROR("ICSF slot data not initialized.\n");
298         rc = CKR_FUNCTION_FAILED;
299         goto done;
300     }
301 
302     data = slot_data[slot_id];
303     data->initialized = 0;
304     strncpy(data->conf_name, conf_name, sizeof(data->conf_name) - 1);
305     data->conf_name[sizeof(data->conf_name) - 1] = '\0';
306 
307 done:
308     if (rc == CKR_OK)
309         rc = XProcUnLock(tokdata);
310     else
311         XProcUnLock(tokdata);
312 
313     return rc;
314 }
315 
token_specific_init_token_data(STDLL_TokData_t * tokdata,CK_SLOT_ID slot_id)316 CK_RV token_specific_init_token_data(STDLL_TokData_t * tokdata,
317                                      CK_SLOT_ID slot_id)
318 {
319     CK_RV rc = CKR_OK;
320     const char *conf_name = NULL;
321     struct icsf_config config;
322 
323     /* Check Slot ID */
324     if (slot_id >= NUMBER_SLOTS_MANAGED) {
325         TRACE_ERROR("Invalid slot ID: %lu\n", slot_id);
326         return CKR_FUNCTION_FAILED;
327     }
328 
329     rc = XProcLock(tokdata);
330     if (rc != CKR_OK)
331         return CKR_FUNCTION_FAILED;
332 
333     if (slot_data[slot_id] == NULL) {
334         TRACE_ERROR("ICSF slot data not initialized.\n");
335         rc = CKR_FUNCTION_FAILED;
336         goto done;
337     }
338 
339     /* Check if data needs to be retrieved for this slot */
340     if (slot_data[slot_id]->initialized) {
341         TRACE_DEVEL("Slot data already initialized for slot %lu. "
342                     "Skipping it\n", slot_id);
343         goto done;
344     }
345 
346     /* Check config file */
347     conf_name = slot_data[slot_id]->conf_name;
348     if (!conf_name || !conf_name[0]) {
349         TRACE_ERROR("Missing config for slot %lu.\n", slot_id);
350         rc = CKR_FUNCTION_FAILED;
351         goto done;
352     }
353 
354     TRACE_DEVEL("DEBUG: conf_name=\"%s\".\n", conf_name);
355     if (parse_config_file(conf_name, slot_id, &config)) {
356         TRACE_ERROR("Failed to parse file \"%s\" for slot %lu.\n",
357                     conf_name, slot_id);
358         rc = CKR_FUNCTION_FAILED;
359         goto done;
360     }
361 
362     /* Copy general info */
363     memcpy(tokdata->nv_token_data->token_info.label, config.name,
364            strlen(config.name));
365     memcpy(tokdata->nv_token_data->token_info.manufacturerID, config.manuf,
366            strlen(config.manuf));
367     memcpy(tokdata->nv_token_data->token_info.model, config.model,
368            strlen(config.model));
369     memcpy(tokdata->nv_token_data->token_info.serialNumber, config.serial,
370            strlen(config.serial));
371 
372     /* Copy ICSF specific info */
373     strcpy(slot_data[slot_id]->uri, config.uri);
374     strcpy(slot_data[slot_id]->dn, config.dn);
375     strcpy(slot_data[slot_id]->ca_file, config.ca_file);
376     strcpy(slot_data[slot_id]->cert_file, config.cert_file);
377     strcpy(slot_data[slot_id]->key_file, config.key_file);
378     slot_data[slot_id]->initialized = 1;
379     slot_data[slot_id]->mech = config.mech;
380 
381 done:
382     if (rc == CKR_OK)
383         rc = XProcUnLock(tokdata);
384     else
385         XProcUnLock(tokdata);
386 
387     return rc;
388 }
389 
token_specific_load_token_data(STDLL_TokData_t * tokdata,CK_SLOT_ID slot_id,FILE * fh)390 CK_RV token_specific_load_token_data(STDLL_TokData_t * tokdata,
391                                      CK_SLOT_ID slot_id, FILE * fh)
392 {
393     CK_RV rc;
394     struct slot_data data;
395 
396     /* Check Slot ID */
397     if (slot_id >= NUMBER_SLOTS_MANAGED) {
398         TRACE_ERROR("Invalid slot ID: %lu\n", slot_id);
399         return CKR_FUNCTION_FAILED;
400     }
401 
402     if (!fread(&data, sizeof(data), 1, fh)) {
403         TRACE_ERROR("Failed to read ICSF slot data.\n");
404         return CKR_FUNCTION_FAILED;
405     }
406 
407     rc = XProcLock(tokdata);
408     if (rc != CKR_OK)
409         return CKR_FUNCTION_FAILED;
410 
411     if (slot_data[slot_id] == NULL) {
412         TRACE_ERROR("ICSF slot data not initialized.\n");
413         rc = CKR_FUNCTION_FAILED;
414         goto done;
415     }
416 
417     memcpy(slot_data[slot_id], &data, sizeof(data));
418 
419 done:
420     if (rc == CKR_OK)
421         rc = XProcUnLock(tokdata);
422     else
423         XProcUnLock(tokdata);
424 
425     return rc;
426 }
427 
token_specific_save_token_data(STDLL_TokData_t * tokdata,CK_SLOT_ID slot_id,FILE * fh)428 CK_RV token_specific_save_token_data(STDLL_TokData_t * tokdata,
429                                      CK_SLOT_ID slot_id, FILE * fh)
430 {
431     CK_RV rc;
432 
433     /* Check Slot ID */
434     if (slot_id >= NUMBER_SLOTS_MANAGED) {
435         TRACE_ERROR("Invalid slot ID: %lu\n", slot_id);
436         return CKR_FUNCTION_FAILED;
437     }
438 
439     rc = XProcLock(tokdata);
440     if (rc != CKR_OK)
441         return CKR_FUNCTION_FAILED;
442 
443     if (slot_data[slot_id] == NULL) {
444         TRACE_ERROR("ICSF slot data not initialized.\n");
445         rc = CKR_FUNCTION_FAILED;
446         goto done;
447     }
448 
449     if (!fwrite(slot_data[slot_id], sizeof(**slot_data), 1, fh)) {
450         TRACE_ERROR("Failed to write ICSF slot data.\n");
451         rc = CKR_FUNCTION_FAILED;
452         goto done;
453     }
454 
455 done:
456     if (rc == CKR_OK)
457         rc = XProcUnLock(tokdata);
458     else
459         XProcUnLock(tokdata);
460 
461     return rc;
462 }
463 
464 /*
465  * Initialize the shared memory region. ICSF has to use a custom method for
466  * this because it uses additional data in the shared memory and in the future
467  * multiple slots should be supported for ICSF.
468  */
token_specific_attach_shm(STDLL_TokData_t * tokdata,CK_SLOT_ID slot_id)469 CK_RV token_specific_attach_shm(STDLL_TokData_t * tokdata, CK_SLOT_ID slot_id)
470 {
471     CK_RV rc;
472     int ret;
473     void *ptr;
474     LW_SHM_TYPE **shm = &tokdata->global_shm;
475     size_t len = sizeof(**shm) + sizeof(**slot_data);
476     char *shm_id = NULL;
477 
478     if (slot_id >= NUMBER_SLOTS_MANAGED) {
479         TRACE_ERROR("Invalid slot ID: %lu\n", slot_id);
480         return CKR_FUNCTION_FAILED;
481     }
482 
483     if (asprintf(&shm_id, "/icsf-%lu", slot_id) < 0) {
484         TRACE_ERROR("Failed to allocate shared memory id "
485                     "for slot %lu.\n", slot_id);
486         return CKR_HOST_MEMORY;
487     }
488     TRACE_DEVEL("Attaching to shared memory \"%s\".\n", shm_id);
489 
490     rc = XProcLock(tokdata);
491     if (rc != CKR_OK)
492         return CKR_FUNCTION_FAILED;
493 
494     /*
495      * Attach to an existing shared memory region or create it if it doesn't
496      * exists. When the it's created (ret=0) the region is initialized with
497      * zeroes.
498      */
499     ret = sm_open(shm_id, 0666, (void **) &ptr, len, 1);
500     if (ret < 0) {
501         TRACE_ERROR("Failed to open shared memory \"%s\".\n", shm_id);
502         rc = CKR_FUNCTION_FAILED;
503         goto done;
504     }
505 
506     *shm = ptr;
507     slot_data[slot_id] = (struct slot_data *)((unsigned char *)ptr
508                                               + sizeof(**shm));
509 
510 done:
511     if (rc == CKR_OK)
512         rc = XProcUnLock(tokdata);
513     else
514         XProcUnLock(tokdata);
515 
516     if (shm_id)
517         free(shm_id);
518 
519     return rc;
520 }
521 
login(STDLL_TokData_t * tokdata,LDAP ** ld,CK_SLOT_ID slot_id,CK_BYTE * pin,CK_ULONG pin_len,const char * pass_file_type)522 CK_RV login(STDLL_TokData_t * tokdata, LDAP ** ld, CK_SLOT_ID slot_id,
523             CK_BYTE * pin, CK_ULONG pin_len, const char *pass_file_type)
524 {
525     CK_RV rc;
526     struct slot_data data;
527     LDAP *ldapd = NULL;
528     int ret;
529 
530     UNUSED(pass_file_type);
531 
532     /* Check Slot ID */
533     if (slot_id >= NUMBER_SLOTS_MANAGED) {
534         TRACE_ERROR("Invalid slot ID: %lu\n", slot_id);
535         return CKR_FUNCTION_FAILED;
536     }
537 
538     rc = XProcLock(tokdata);
539     if (rc != CKR_OK) {
540         TRACE_ERROR("Failed to get process lock.\n");
541         goto done;
542     }
543 
544     /* Check slot data */
545     if (slot_data[slot_id] == NULL || !slot_data[slot_id]->initialized) {
546         TRACE_ERROR("ICSF slot data not initialized.\n");
547         rc = CKR_FUNCTION_FAILED;
548         goto done;
549     }
550     memcpy(&data, slot_data[slot_id], sizeof(data));
551 
552     rc = XProcUnLock(tokdata);
553     if (rc != CKR_OK) {
554         TRACE_ERROR("Failed to release process lock.\n");
555         goto done;
556     }
557 
558     if (data.mech == ICSF_CFG_MECH_SIMPLE) {
559         CK_BYTE mk[MAX_KEY_SIZE];
560         CK_BYTE racf_pass[PIN_SIZE];
561         int mk_len = sizeof(mk);
562         int racf_pass_len = sizeof(racf_pass);
563         char pk_dir_buf[PATH_MAX];
564         char fname[PATH_MAX];
565 
566         /* Load master key */
567         sprintf(fname, "%s/MK_SO", get_pk_dir(pk_dir_buf));
568         if (get_masterkey(pin, pin_len, fname, mk, &mk_len)) {
569             TRACE_DEVEL("Failed to get masterkey \"%s\".\n", fname);
570             return CKR_FUNCTION_FAILED;
571         }
572 
573         /* Load RACF password */
574         if (get_racf(mk, mk_len, racf_pass, &racf_pass_len)) {
575             TRACE_DEVEL("Failed to get RACF password.\n");
576             return CKR_FUNCTION_FAILED;
577         }
578 
579         /* Simple bind */
580         ret = icsf_login(&ldapd, data.uri, data.dn, (char *)racf_pass);
581     } else {
582         /* SASL bind */
583         ret = icsf_sasl_login(&ldapd, data.uri, data.cert_file,
584                               data.key_file, data.ca_file, NULL);
585     }
586 
587     if (ret) {
588         TRACE_DEVEL("Failed to bind to %s\n", data.uri);
589         rc = CKR_FUNCTION_FAILED;
590         goto done;
591     }
592 
593     if (icsf_check_pkcs_extension(ldapd)) {
594         TRACE_ERROR("ICSF LDAP externsion not supported.\n");
595         rc = CKR_FUNCTION_FAILED;
596         goto done;
597     }
598 
599 done:
600     if (rc == CKR_OK && ld)
601         *ld = ldapd;
602 
603     return rc;
604 }
605 
reset_token_data(STDLL_TokData_t * tokdata,CK_SLOT_ID slot_id,CK_CHAR_PTR pin,CK_ULONG pin_len)606 CK_RV reset_token_data(STDLL_TokData_t * tokdata, CK_SLOT_ID slot_id,
607                        CK_CHAR_PTR pin, CK_ULONG pin_len)
608 {
609     CK_BYTE mk[MAX_KEY_SIZE];
610     CK_BYTE racf_pass[PIN_SIZE];
611     int mk_len = sizeof(mk);
612     int racf_pass_len = sizeof(racf_pass);
613     char pk_dir_buf[PATH_MAX];
614     char fname[PATH_MAX];
615 
616     /* Remove user's masterkey */
617     if (slot_data[slot_id]->mech == ICSF_CFG_MECH_SIMPLE) {
618         sprintf(fname, "%s/MK_USER", get_pk_dir(pk_dir_buf));
619         if (unlink(fname) && errno == ENOENT)
620             TRACE_WARNING("Failed to remove \"%s\".\n", fname);
621 
622         /* Load master key */
623         sprintf(fname, "%s/MK_SO", get_pk_dir(pk_dir_buf));
624         if (get_masterkey(pin, pin_len, fname, mk, &mk_len)) {
625             TRACE_DEVEL("Failed to load masterkey \"%s\".\n", fname);
626             return CKR_FUNCTION_FAILED;
627         }
628 
629         /* Load RACF password */
630         if (get_racf(mk, mk_len, racf_pass, &racf_pass_len)) {
631             TRACE_DEVEL("Failed to get RACF password.\n");
632             return CKR_FUNCTION_FAILED;
633         }
634 
635         /* Generate new key */
636         if (get_randombytes(mk, mk_len)) {
637             TRACE_DEVEL("Failed to generate new master key.\n");
638             return CKR_FUNCTION_FAILED;
639         }
640 
641         /* Save racf password using the new master key */
642         if (secure_racf(racf_pass, racf_pass_len, mk, mk_len)) {
643             TRACE_DEVEL("Failed to save racf password.\n");
644             return CKR_FUNCTION_FAILED;
645         }
646     }
647 
648     /* Reset token data and keep token name */
649     slot_data[slot_id]->initialized = 0;
650     load_token_data(tokdata, slot_id);
651     init_slotInfo(&tokdata->slot_info);
652     tokdata->nv_token_data->token_info.flags |= CKF_TOKEN_INITIALIZED;
653 
654     if (slot_data[slot_id]->mech == ICSF_CFG_MECH_SIMPLE) {
655         /* Save master key */
656         if (secure_masterkey(mk, mk_len, pin, pin_len, fname)) {
657             TRACE_DEVEL("Failed to save the new master key.\n");
658             return CKR_FUNCTION_FAILED;
659         }
660     }
661 
662     if (save_token_data(tokdata, slot_id)) {
663         TRACE_DEVEL("Failed to save token data.\n");
664         return CKR_FUNCTION_FAILED;
665     }
666 
667     return CKR_OK;
668 }
669 
destroy_objects(STDLL_TokData_t * tokdata,CK_SLOT_ID slot_id,CK_CHAR_PTR token_name,CK_CHAR_PTR pin,CK_ULONG pin_len)670 CK_RV destroy_objects(STDLL_TokData_t * tokdata, CK_SLOT_ID slot_id,
671                       CK_CHAR_PTR token_name, CK_CHAR_PTR pin, CK_ULONG pin_len)
672 {
673     CK_RV rv = CKR_OK;
674     LDAP *ld = NULL;
675     struct icsf_object_record records[16];
676     struct icsf_object_record *previous = NULL;
677     size_t i, records_len;
678     int reason = 0;
679     int rc;
680 
681     if (login(tokdata, &ld, slot_id, pin, pin_len, RACFFILE))
682         return CKR_FUNCTION_FAILED;
683 
684     TRACE_DEVEL("Destroying objects in slot %lu.\n", slot_id);
685     do {
686         records_len = sizeof(records) / sizeof(records[0]);
687 
688         rc = icsf_list_objects(ld, NULL, (char *)token_name, 0, NULL,
689                                previous, records, &records_len, 0);
690         if (ICSF_RC_IS_ERROR(rc)) {
691             TRACE_DEVEL("Failed to list objects for slot %lu.\n", slot_id);
692             rv = CKR_FUNCTION_FAILED;
693             goto done;
694         }
695 
696         for (i = 0; i < records_len; i++) {
697             if ((rc = icsf_destroy_object(ld, &reason, &records[i]))) {
698                 TRACE_DEVEL("Failed to destroy object "
699                             "%s/%lu/%c in slot %lu.\n",
700                             records[i].token_name,
701                             records[i].sequence, records[i].id, slot_id);
702                 rv = icsf_to_ock_err(rc, reason);
703                 goto done;
704             }
705         }
706 
707         if (records_len)
708             previous = &records[records_len - 1];
709     } while (records_len);
710 
711 done:
712     if (icsf_logout(ld) && rv == CKR_OK)
713         rv = CKR_FUNCTION_FAILED;
714 
715     return rv;
716 }
717 
718 /*
719  * Initialize token.
720  */
icsftok_init_token(STDLL_TokData_t * tokdata,CK_SLOT_ID slot_id,CK_CHAR_PTR pin,CK_ULONG pin_len,CK_CHAR_PTR label)721 CK_RV icsftok_init_token(STDLL_TokData_t * tokdata, CK_SLOT_ID slot_id,
722                          CK_CHAR_PTR pin, CK_ULONG pin_len, CK_CHAR_PTR label)
723 {
724     CK_RV rc = CKR_OK;
725     CK_BYTE hash_sha[SHA1_HASH_SIZE];
726 
727     UNUSED(label);
728 
729     /* Check pin */
730     rc = compute_sha1(tokdata, pin, pin_len, hash_sha);
731     if (memcmp(tokdata->nv_token_data->so_pin_sha, hash_sha,
732                SHA1_HASH_SIZE) != 0) {
733         TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT));
734         rc = CKR_PIN_INCORRECT;
735         goto done;
736     }
737 
738     if ((rc = reset_token_data(tokdata, slot_id, pin, pin_len)))
739         goto done;
740 
741     if ((rc = destroy_objects(tokdata, slot_id,
742                               tokdata->nv_token_data->token_info.label,
743                               pin, pin_len)))
744         goto done;
745 
746     /* purge the object btree */
747     if (purge_object_mapping()) {
748         TRACE_DEVEL("Failed to purge objects.\n");
749         rc = CKR_FUNCTION_FAILED;
750     }
751 
752 done:
753     return rc;
754 }
755 
icsftok_init_pin(STDLL_TokData_t * tokdata,SESSION * sess,CK_CHAR_PTR pPin,CK_ULONG ulPinLen)756 CK_RV icsftok_init_pin(STDLL_TokData_t * tokdata, SESSION * sess,
757                        CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
758 {
759     CK_RV rc = CKR_OK;
760     CK_BYTE hash_sha[SHA1_HASH_SIZE];
761     CK_SLOT_ID sid;
762     char fname[PATH_MAX];
763     char pk_dir_buf[PATH_MAX];
764 
765     /* get slot id */
766     sid = sess->session_info.slotID;
767 
768     /* compute the SHA of the user pin */
769     rc = compute_sha1(tokdata, pPin, ulPinLen, hash_sha);
770     if (rc != CKR_OK) {
771         TRACE_ERROR("Hash Computation Failed.\n");
772         return rc;
773     }
774 
775     /* encrypt the masterkey and store in MK_USER if using SIMPLE AUTH
776      * to authenticate to ldao server. The masterkey protects the
777      * racf passwd.
778      */
779     if (slot_data[sid]->mech == ICSF_CFG_MECH_SIMPLE) {
780         sprintf(fname, "%s/MK_USER", get_pk_dir(pk_dir_buf));
781 
782         rc = secure_masterkey(tokdata->master_key,
783                               AES_KEY_SIZE_256, pPin, ulPinLen, fname);
784         if (rc != CKR_OK) {
785             TRACE_DEVEL("Could not create MK_USER.\n");
786             return rc;
787         }
788     }
789 
790     rc = XProcLock(tokdata);
791     if (rc != CKR_OK) {
792         TRACE_ERROR("Failed to get process lock.\n");
793         return rc;
794     }
795 
796     memcpy(tokdata->nv_token_data->user_pin_sha, hash_sha, SHA1_HASH_SIZE);
797     tokdata->nv_token_data->token_info.flags |= CKF_USER_PIN_INITIALIZED;
798     tokdata->nv_token_data->token_info.flags &= ~(CKF_USER_PIN_TO_BE_CHANGED);
799     tokdata->nv_token_data->token_info.flags &= ~(CKF_USER_PIN_LOCKED);
800 
801     rc = XProcUnLock(tokdata);
802     if (rc != CKR_OK) {
803         TRACE_ERROR("Process Lock Failed.\n");
804         return rc;
805     }
806 
807     return rc;
808 }
809 
icsftok_set_pin(STDLL_TokData_t * tokdata,SESSION * sess,CK_CHAR_PTR pOldPin,CK_ULONG ulOldLen,CK_CHAR_PTR pNewPin,CK_ULONG ulNewLen)810 CK_RV icsftok_set_pin(STDLL_TokData_t * tokdata, SESSION * sess,
811                       CK_CHAR_PTR pOldPin, CK_ULONG ulOldLen,
812                       CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen)
813 {
814     CK_RV rc = CKR_OK;
815     CK_BYTE new_hash_sha[SHA1_HASH_SIZE];
816     CK_BYTE old_hash_sha[SHA1_HASH_SIZE];
817     CK_SLOT_ID sid;
818     char fname[PATH_MAX];
819     char pk_dir_buf[PATH_MAX];
820 
821     /* get slot id */
822     sid = sess->session_info.slotID;
823 
824     rc = compute_sha1(tokdata, pNewPin, ulNewLen, new_hash_sha);
825     rc |= compute_sha1(tokdata, pOldPin, ulOldLen, old_hash_sha);
826     if (rc != CKR_OK) {
827         TRACE_ERROR("Hash Computation Failed.\n");
828         return rc;
829     }
830 
831     /* check that the old pin  and new pin are not the same. */
832     if (memcmp(old_hash_sha, new_hash_sha, SHA1_HASH_SIZE) == 0) {
833         TRACE_ERROR("%s\n", ock_err(ERR_PIN_INVALID));
834         return CKR_PIN_INVALID;
835     }
836 
837     /* check the length requirements */
838     if ((ulNewLen < MIN_PIN_LEN) || (ulNewLen > MAX_PIN_LEN)) {
839         TRACE_ERROR("%s\n", ock_err(ERR_PIN_LEN_RANGE));
840         return CKR_PIN_LEN_RANGE;
841     }
842 
843     if ((sess->session_info.state == CKS_RW_USER_FUNCTIONS) ||
844         (sess->session_info.state == CKS_RW_PUBLIC_SESSION)) {
845         /* check that old pin matches what is in NVTOK.DAT */
846         if (memcmp
847             (tokdata->nv_token_data->user_pin_sha, old_hash_sha,
848              SHA1_HASH_SIZE) != 0) {
849             TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT));
850             return CKR_PIN_INCORRECT;
851         }
852         /* if using simple auth, encrypt masterkey with new pin */
853         if (slot_data[sid]->mech == ICSF_CFG_MECH_SIMPLE) {
854             sprintf(fname, "%s/MK_USER", get_pk_dir(pk_dir_buf));
855             rc = secure_masterkey(tokdata->master_key,
856                                   AES_KEY_SIZE_256, pNewPin, ulNewLen, fname);
857             if (rc != CKR_OK) {
858                 TRACE_ERROR("Save Master Key Failed.\n");
859                 return rc;
860             }
861         }
862 
863         /* grab lock and change shared memory */
864         rc = XProcLock(tokdata);
865         if (rc != CKR_OK) {
866             TRACE_ERROR("Process Lock Failed.\n");
867             return rc;
868         }
869 
870         memcpy(tokdata->nv_token_data->user_pin_sha, new_hash_sha,
871                SHA1_HASH_SIZE);
872         tokdata->nv_token_data->token_info.flags &=
873             ~(CKF_USER_PIN_TO_BE_CHANGED);
874 
875         rc = XProcUnLock(tokdata);
876         if (rc != CKR_OK) {
877             TRACE_ERROR("Process Lock Failed.\n");
878             return rc;
879         }
880 
881     } else if (sess->session_info.state == CKS_RW_SO_FUNCTIONS) {
882 
883         /* check that old pin matches what is in NVTOK.DAT */
884         if (memcmp
885             (tokdata->nv_token_data->so_pin_sha, old_hash_sha,
886              SHA1_HASH_SIZE) != 0) {
887             TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT));
888             return CKR_PIN_INCORRECT;
889         }
890 
891         /* check that new pin is not the default */
892         if (memcmp(new_hash_sha, default_so_pin_sha, SHA1_HASH_SIZE) == 0) {
893             TRACE_ERROR("%s\n", ock_err(ERR_PIN_INVALID));
894             return CKR_PIN_INVALID;
895         }
896 
897         if (slot_data[sid]->mech == ICSF_CFG_MECH_SIMPLE) {
898             /*
899              * if using simle auth, encrypt masterkey with new pin
900              */
901             sprintf(fname, "%s/MK_SO", get_pk_dir(pk_dir_buf));
902             rc = secure_masterkey(tokdata->master_key,
903                                   AES_KEY_SIZE_256, pNewPin, ulNewLen, fname);
904             if (rc != CKR_OK) {
905                 TRACE_ERROR("Save Master Key Failed.\n");
906                 return rc;
907             }
908         }
909 
910         /* grab lock and change shared memory */
911         rc = XProcLock(tokdata);
912         if (rc != CKR_OK) {
913             TRACE_ERROR("Process Lock Failed.\n");
914             return rc;
915         }
916 
917         memcpy(tokdata->nv_token_data->so_pin_sha, new_hash_sha,
918                SHA1_HASH_SIZE);
919         tokdata->nv_token_data->token_info.flags &= ~(CKF_SO_PIN_TO_BE_CHANGED);
920 
921         XProcUnLock(tokdata);
922         if (rc != CKR_OK) {
923             TRACE_ERROR("Process Lock Failed.\n");
924             return rc;
925         }
926     } else {
927         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY));
928         return CKR_SESSION_READ_ONLY;
929     }
930 
931     rc = save_token_data(tokdata, sid);
932     if (rc != CKR_OK) {
933         TRACE_ERROR("Save Token Failed.\n");
934         return rc;
935     }
936 
937     return rc;
938 }
939 
getLDAPhandle(STDLL_TokData_t * tokdata,CK_SLOT_ID slot_id)940 LDAP *getLDAPhandle(STDLL_TokData_t * tokdata, CK_SLOT_ID slot_id)
941 {
942     CK_BYTE racfpwd[PIN_SIZE];
943     int racflen;
944     char *ca_dir = NULL;
945     LDAP *new_ld = NULL;
946     CK_RV rc = CKR_OK;
947 
948     if (slot_data[slot_id] == NULL) {
949         TRACE_ERROR("ICSF slot data not initialized.\n");
950         return NULL;
951     }
952     /* Check if using sasl or simple auth */
953     if (slot_data[slot_id]->mech == ICSF_CFG_MECH_SIMPLE) {
954         TRACE_INFO("Using SIMPLE auth with slot ID: %lu\n", slot_id);
955         /* get racf passwd */
956         rc = get_racf(tokdata->master_key, AES_KEY_SIZE_256, racfpwd, &racflen);
957         if (rc != CKR_OK) {
958             TRACE_DEVEL("Failed to get racf passwd.\n");
959             return NULL;
960         }
961 
962         /* ok got the passwd, perform simple ldap bind call */
963         rc = icsf_login(&new_ld, slot_data[slot_id]->uri,
964                         slot_data[slot_id]->dn, (char *)racfpwd);
965         if (rc != CKR_OK) {
966             TRACE_DEVEL("Failed to bind to ldap server.\n");
967             return NULL;
968         }
969     } else {
970         TRACE_INFO("Using SASL auth with slot ID: %lu\n", slot_id);
971         rc = icsf_sasl_login(&new_ld, slot_data[slot_id]->uri,
972                              slot_data[slot_id]->cert_file,
973                              slot_data[slot_id]->key_file,
974                              slot_data[slot_id]->ca_file, ca_dir);
975         if (rc != CKR_OK) {
976             TRACE_DEVEL("Failed to bind to ldap server.\n");
977             return NULL;
978         }
979     }
980 
981     return new_ld;
982 }
983 
icsf_get_handles(STDLL_TokData_t * tokdata,CK_SLOT_ID slot_id)984 CK_RV icsf_get_handles(STDLL_TokData_t * tokdata, CK_SLOT_ID slot_id)
985 {
986     struct session_state *s;
987 
988     /* Any prior sessions without an ldap descriptor, can now get one. */
989     /* Lock sessions list */
990     if (pthread_mutex_lock(&sess_list_mutex)) {
991         TRACE_ERROR("Failed to lock mutex.\n");
992         return CKR_FUNCTION_FAILED;
993     }
994 
995     for_each_list_entry(&sessions, struct session_state, s, sessions) {
996         if (s->ld == NULL)
997             s->ld = getLDAPhandle(tokdata, slot_id);
998     }
999 
1000     if (pthread_mutex_unlock(&sess_list_mutex)) {
1001         TRACE_ERROR("Mutex Unlock failed.\n");
1002         return CKR_FUNCTION_FAILED;
1003     }
1004 
1005     return CKR_OK;
1006 }
1007 
icsftok_open_session(STDLL_TokData_t * tokdata,SESSION * sess)1008 CK_RV icsftok_open_session(STDLL_TokData_t * tokdata, SESSION * sess)
1009 {
1010     CK_RV rc = CKR_OK;
1011     LDAP *ld;
1012     struct session_state *session_state;
1013 
1014     /* Sanity */
1015     if (sess == NULL) {
1016         TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD));
1017         return CKR_FUNCTION_FAILED;
1018     }
1019 
1020     /* Add session to list */
1021     session_state = malloc(sizeof(struct session_state));
1022     if (!session_state) {
1023         TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
1024         return CKR_FUNCTION_FAILED;
1025     }
1026     session_state->session_id = sess->handle;
1027     session_state->ld = NULL;
1028 
1029     if (pthread_mutex_lock(&sess_list_mutex)) {
1030         TRACE_ERROR("Failed to lock mutex.\n");
1031         free(session_state);
1032         return CKR_FUNCTION_FAILED;
1033     }
1034     /* see if user has logged in to acquire ldap handle for session.
1035      * pkcs#11v2.2 states that all sessions within a process have
1036      * same login state.
1037      */
1038     if (global_login_state == CKS_RW_USER_FUNCTIONS ||
1039         global_login_state == CKS_RO_USER_FUNCTIONS) {
1040         ld = getLDAPhandle(tokdata, sess->session_info.slotID);
1041         if (ld == NULL) {
1042             TRACE_DEVEL("Failed to get LDAP handle for session.\n");
1043             rc = CKR_FUNCTION_FAILED;
1044             goto done;
1045         }
1046         /* put the new ldap handle into the session state. */
1047         session_state->ld = ld;
1048     }
1049 
1050     /* put new session_state into the list */
1051     list_insert_head(&sessions, &session_state->sessions);
1052 
1053 done:
1054     /* Unlock */
1055     if (pthread_mutex_unlock(&sess_list_mutex)) {
1056         TRACE_ERROR("Mutex Unlock Failed.\n");
1057         rc = CKR_FUNCTION_FAILED;
1058     }
1059 
1060     if (rc != CKR_OK)
1061         free(session_state);
1062 
1063     return rc;
1064 }
1065 
1066 /*
1067  * Close a session.
1068  *
1069  * Must be called with sess_list_mutex locked.
1070  */
close_session(STDLL_TokData_t * tokdata,struct session_state * session_state)1071 static CK_RV close_session(STDLL_TokData_t * tokdata,
1072                            struct session_state *session_state)
1073 {
1074     CK_RV rc = CKR_OK;
1075     unsigned long i;
1076     int reason = 0;
1077 
1078     UNUSED(tokdata);
1079 
1080     /* Remove each session object */
1081     for (i = 1; i <= objects.size; i++) {
1082         struct icsf_object_mapping *mapping;
1083 
1084         /* Skip missing ids */
1085         if (!(mapping = bt_get_node_value(&objects, i)))
1086             continue;
1087 
1088         /* Skip object from other sessions */
1089         if (mapping->session_id != session_state->session_id)
1090             continue;
1091 
1092         /* Skip token objects */
1093         if (mapping->icsf_object.id != ICSF_SESSION_OBJECT)
1094             continue;
1095 
1096         if ((rc = icsf_destroy_object(session_state->ld, &reason,
1097                                       &mapping->icsf_object))) {
1098             /* Log error */
1099             TRACE_DEBUG("Failed to remove icsf object: %s/%lu/%c",
1100                         mapping->icsf_object.token_name,
1101                         mapping->icsf_object.sequence, mapping->icsf_object.id);
1102             rc = icsf_to_ock_err(rc, reason);
1103             break;
1104         }
1105 
1106         /* Remove object from object list */
1107         bt_node_free(&objects, i, &free);
1108     }
1109     if (rc)
1110         return rc;
1111 
1112     /* Log off from LDAP server */
1113     if (session_state->ld) {
1114         if (icsf_logout(session_state->ld)) {
1115             TRACE_DEVEL("Failed to disconnect from LDAP server.\n");
1116             return CKR_FUNCTION_FAILED;
1117         }
1118         session_state->ld = NULL;
1119     }
1120 
1121     /* Remove session */
1122     list_remove(&session_state->sessions);
1123     if (list_is_empty(&sessions)) {
1124         if (purge_object_mapping()) {
1125             TRACE_DEVEL("Failed to purge objects.\n");
1126             rc = CKR_FUNCTION_FAILED;
1127         }
1128     }
1129     free(session_state);
1130 
1131     return rc;
1132 }
1133 
1134 /*
1135  * Called during C_CloseSession.
1136  */
icsftok_close_session(STDLL_TokData_t * tokdata,SESSION * session)1137 CK_RV icsftok_close_session(STDLL_TokData_t * tokdata, SESSION * session)
1138 {
1139     CK_RV rc;
1140     struct session_state *session_state;
1141 
1142     /* Get the related session_state */
1143     if (session == NULL
1144         || !(session_state = get_session_state(session->handle))) {
1145         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
1146         return CKR_SESSION_HANDLE_INVALID;
1147     }
1148 
1149     if ((rc = close_session(tokdata, session_state)))
1150         TRACE_ERROR("close_session failed\n");
1151 
1152     return rc;
1153 }
1154 
1155 /*
1156  * Called during C_Finalize and C_CloseAllSessions
1157  */
icsftok_close_all_sessions(STDLL_TokData_t * tokdata)1158 CK_RV icsftok_close_all_sessions(STDLL_TokData_t * tokdata)
1159 {
1160     CK_RV rc = CKR_OK;
1161     struct session_state *session_state;
1162     list_entry_t *e;
1163 
1164     /* Lock to add a new session in the list */
1165     if (pthread_mutex_lock(&sess_list_mutex)) {
1166         TRACE_ERROR("Failed to lock mutex.\n");
1167         return CKR_FUNCTION_FAILED;
1168     }
1169 
1170     for_each_list_entry_safe(&sessions, struct session_state, session_state,
1171                              sessions, e) {
1172         if ((rc = close_session(tokdata, session_state)))
1173             break;
1174     }
1175 
1176     /* Unlock */
1177     if (pthread_mutex_unlock(&sess_list_mutex)) {
1178         TRACE_ERROR("Mutex Unlock Failed.\n");
1179         return CKR_FUNCTION_FAILED;
1180     }
1181 
1182     return rc;
1183 }
1184 
icsftok_login(STDLL_TokData_t * tokdata,SESSION * sess,CK_USER_TYPE userType,CK_CHAR_PTR pPin,CK_ULONG ulPinLen)1185 CK_RV icsftok_login(STDLL_TokData_t * tokdata, SESSION * sess,
1186                     CK_USER_TYPE userType, CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
1187 {
1188     CK_RV rc = CKR_OK;
1189     char fname[PATH_MAX];
1190     CK_BYTE hash_sha[SHA1_HASH_SIZE];
1191     int mklen;
1192     char pk_dir_buf[PATH_MAX];
1193     CK_SLOT_ID slot_id = sess->session_info.slotID;
1194 
1195     /* Check Slot ID */
1196     if (slot_id >= NUMBER_SLOTS_MANAGED) {
1197         TRACE_ERROR("Invalid slot ID: %lu\n", slot_id);
1198         return CKR_FUNCTION_FAILED;
1199     }
1200 
1201     /* compute the sha of the pin. */
1202     rc = compute_sha1(tokdata, pPin, ulPinLen, hash_sha);
1203     if (rc != CKR_OK) {
1204         TRACE_ERROR("Hash Computation Failed.\n");
1205         return rc;
1206     }
1207 
1208     rc = XProcLock(tokdata);
1209     if (rc != CKR_OK) {
1210         TRACE_ERROR("Process Lock Failed.\n");
1211         return rc;
1212     }
1213 
1214     if (userType == CKU_USER) {
1215         /* check if pin initialized */
1216         if (memcmp(tokdata->nv_token_data->user_pin_sha,
1217                    "00000000000000000000", SHA1_HASH_SIZE) == 0) {
1218             TRACE_ERROR("%s\n", ock_err(ERR_USER_PIN_NOT_INITIALIZED));
1219             rc = CKR_USER_PIN_NOT_INITIALIZED;
1220             goto done;
1221         }
1222 
1223         /* check that pin is the same as the one in NVTOK.DAT */
1224         if (memcmp(tokdata->nv_token_data->user_pin_sha, hash_sha,
1225                    SHA1_HASH_SIZE) != 0) {
1226             TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT));
1227             rc = CKR_PIN_INCORRECT;
1228             goto done;
1229         }
1230 
1231         /* now load the master key */
1232         if (slot_data[slot_id]->mech == ICSF_CFG_MECH_SIMPLE) {
1233             sprintf(fname, "%s/MK_USER", get_pk_dir(pk_dir_buf));
1234             rc = get_masterkey(pPin, ulPinLen, fname,
1235                                tokdata->master_key, &mklen);
1236             if (rc != CKR_OK) {
1237                 TRACE_DEVEL("Failed to load master key.\n");
1238                 goto done;
1239             }
1240         }
1241     } else {
1242         /* if SO ... */
1243 
1244         /* check that pin is the same as the one in NVTOK.DAT */
1245         if (memcmp(tokdata->nv_token_data->so_pin_sha, hash_sha,
1246                    SHA1_HASH_SIZE) != 0) {
1247             TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT));
1248             rc = CKR_PIN_INCORRECT;
1249             goto done;
1250         }
1251 
1252         if (slot_data[slot_id]->mech == ICSF_CFG_MECH_SIMPLE) {
1253             /* now load the master key */
1254             sprintf(fname, "%s/MK_SO", get_pk_dir(pk_dir_buf));
1255             rc = get_masterkey(pPin, ulPinLen, fname,
1256                                tokdata->master_key, &mklen);
1257             if (rc != CKR_OK) {
1258                 TRACE_DEVEL("Failed to load master key.\n");
1259                 goto done;
1260             }
1261         }
1262     }
1263     /* Now that user is authenticated, can get racf passwd and
1264      * establish ldap handle for session. This will get done
1265      * when we call icsf_get_handles() in SC_Login().
1266      */
1267 done:
1268     if (rc == CKR_OK)
1269         rc = XProcUnLock(tokdata);
1270     else
1271         XProcUnLock(tokdata);
1272 
1273     return rc;
1274 }
1275 
check_session_permissions(SESSION * sess,CK_ATTRIBUTE * attrs,CK_ULONG attrs_len)1276 static CK_RV check_session_permissions(SESSION * sess, CK_ATTRIBUTE * attrs,
1277                                        CK_ULONG attrs_len)
1278 {
1279     CK_RV rc = CKR_OK;
1280     /* PKCS#11 default value for CKA_TOKEN is FALSE */
1281     CK_BBOOL is_token_obj = FALSE;
1282     /* ICSF default value for CKA_PRIVATE is TRUE */
1283     CK_BBOOL is_priv_obj = TRUE;
1284 
1285     /* Get attributes values */
1286     find_bbool_attribute(attrs, attrs_len, CKA_TOKEN, &is_token_obj);
1287     find_bbool_attribute(attrs, attrs_len, CKA_PRIVATE, &is_priv_obj);
1288 
1289     /*
1290      * Check whether session has permissions to create the object, etc
1291      *
1292      * Object                  R/O      R/W      R/O     R/W    R/W
1293      * Type                   Public   Public    User    User   SO
1294      * -------------------------------------------------------------
1295      * Public session          R/W      R/W      R/W     R/W    R/W
1296      * Private session                           R/W     R/W
1297      * Public token            R/O      R/W      R/O     R/W    R/W
1298      * Private token                             R/O     R/W
1299      */
1300 
1301     if (sess->session_info.state == CKS_RO_PUBLIC_SESSION) {
1302         if (is_priv_obj) {
1303             TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN));
1304             rc = CKR_USER_NOT_LOGGED_IN;
1305             goto done;
1306         }
1307         if (is_token_obj) {
1308             TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY));
1309             rc = CKR_SESSION_READ_ONLY;
1310             goto done;
1311         }
1312     }
1313 
1314     if (sess->session_info.state == CKS_RO_USER_FUNCTIONS) {
1315         if (is_token_obj) {
1316             TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY));
1317             rc = CKR_SESSION_READ_ONLY;
1318             goto done;
1319         }
1320     }
1321 
1322     if (sess->session_info.state == CKS_RW_PUBLIC_SESSION) {
1323         if (is_priv_obj) {
1324             TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN));
1325             rc = CKR_USER_NOT_LOGGED_IN;
1326             goto done;
1327         }
1328     }
1329 
1330     if (sess->session_info.state == CKS_RW_SO_FUNCTIONS) {
1331         if (is_priv_obj) {
1332             TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN));
1333             rc = CKR_USER_NOT_LOGGED_IN;
1334             goto done;
1335         }
1336     }
1337 
1338 done:
1339     return rc;
1340 }
1341 
1342 /*
1343  * Copy an existing object.
1344  */
icsftok_copy_object(SESSION * session,CK_ATTRIBUTE_PTR attrs,CK_ULONG attrs_len,CK_OBJECT_HANDLE src,CK_OBJECT_HANDLE_PTR dst)1345 CK_RV icsftok_copy_object(SESSION * session, CK_ATTRIBUTE_PTR attrs,
1346                           CK_ULONG attrs_len, CK_OBJECT_HANDLE src,
1347                           CK_OBJECT_HANDLE_PTR dst)
1348 {
1349     CK_RV rc = CKR_OK;
1350     struct session_state *session_state;
1351     struct icsf_object_mapping *mapping_dst = NULL;
1352     struct icsf_object_mapping *mapping_src = NULL;
1353     CK_ULONG node_number;
1354     int reason = 0;
1355 
1356     CK_BBOOL is_priv;
1357     CK_BBOOL is_token;
1358     CK_RV rc_permission = CKR_OK;
1359 
1360     CK_ATTRIBUTE priv_attrs[] = {
1361         {CKA_PRIVATE, &is_priv, sizeof(is_priv)}
1362         ,
1363         {CKA_TOKEN, &is_token, sizeof(is_token)}
1364         ,
1365     };
1366 
1367     CK_ATTRIBUTE_PTR temp_attrs;
1368 
1369     /* Get session state */
1370     if (!(session_state = get_session_state(session->handle))) {
1371         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
1372         rc = CKR_SESSION_HANDLE_INVALID;
1373         goto done;
1374     }
1375 
1376     /* check ldap handle */
1377     if (session_state->ld == NULL) {
1378         TRACE_ERROR("No LDAP handle.\n");
1379         rc = CKR_FUNCTION_FAILED;
1380         goto done;
1381     }
1382 
1383     /* Allocate structure for new object */
1384     if (!(mapping_dst = malloc(sizeof(*mapping_dst)))) {
1385         TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
1386         rc = CKR_HOST_MEMORY;
1387         goto done;
1388     }
1389 
1390     mapping_src = bt_get_node_value(&objects, src);
1391     if (!mapping_src) {
1392         TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
1393         rc = CKR_OBJECT_HANDLE_INVALID;
1394         goto done;
1395     }
1396 
1397     rc = icsf_get_attribute(session_state->ld, &reason,
1398                             &mapping_src->icsf_object, priv_attrs, 2);
1399     if (rc != CKR_OK) {
1400         TRACE_ERROR("icsf_get_attribute failed\n");
1401         goto done;
1402     }
1403 
1404     if (attrs_len != 0) {
1405         /* looking for CKA_PRIVATE */
1406         temp_attrs = get_attribute_by_type(attrs, attrs_len, CKA_PRIVATE);
1407         if (temp_attrs != NULL) {
1408             priv_attrs[0].pValue = temp_attrs->pValue;
1409             priv_attrs[0].ulValueLen = temp_attrs->ulValueLen;
1410         }
1411 
1412         /* looking for CKA_TOKEN */
1413         temp_attrs = get_attribute_by_type(attrs, attrs_len, CKA_TOKEN);
1414         if (temp_attrs != NULL) {
1415             priv_attrs[1].pValue = temp_attrs->pValue;
1416             priv_attrs[1].ulValueLen = attrs->ulValueLen;
1417         }
1418     }
1419 
1420     /* Check permissions based on attributes and session */
1421     rc = check_session_permissions(session, priv_attrs, 2);
1422     if (rc_permission != CKR_OK) {
1423         TRACE_DEVEL("check_session_permissions failed\n");
1424         goto done;
1425     }
1426 
1427     /* Call ICSF service */
1428     rc = icsf_copy_object(session_state->ld, &reason, attrs, attrs_len,
1429                           &mapping_src->icsf_object, &mapping_dst->icsf_object);
1430     if (rc != 0) {
1431         TRACE_DEVEL("Failed to Copy object.\n");
1432         rc = icsf_to_ock_err(rc, reason);
1433         goto done;
1434     }
1435 
1436     /* Add info about object into session */
1437     if (!(node_number = bt_node_add(&objects, mapping_dst))) {
1438         TRACE_ERROR("Failed to add object to binary tree.\n");
1439         rc = CKR_FUNCTION_FAILED;
1440         goto done;
1441     }
1442 
1443     /* Use node number as handle */
1444     *dst = node_number;
1445 
1446 done:
1447     /* If allocated, object must be freed in case of failure */
1448     if (rc && mapping_dst)
1449         free(mapping_dst);
1450 
1451     return rc;
1452 }
1453 
1454 /*
1455  * Create a new object.
1456  */
icsftok_create_object(STDLL_TokData_t * tokdata,SESSION * session,CK_ATTRIBUTE_PTR attrs,CK_ULONG attrs_len,CK_OBJECT_HANDLE_PTR handle)1457 CK_RV icsftok_create_object(STDLL_TokData_t * tokdata, SESSION * session,
1458                             CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len,
1459                             CK_OBJECT_HANDLE_PTR handle)
1460 {
1461     CK_RV rc = CKR_OK;
1462     struct session_state *session_state;
1463     struct icsf_object_mapping *mapping;
1464     CK_ULONG node_number;
1465     char token_name[sizeof(tokdata->nv_token_data->token_info.label)];
1466     int reason = 0;
1467 
1468     /* Check permissions based on attributes and session */
1469     rc = check_session_permissions(session, attrs, attrs_len);
1470     if (rc != CKR_OK)
1471         return rc;
1472 
1473     /* Copy token name from shared memory */
1474     rc = XProcLock(tokdata);
1475     if (rc != CKR_OK) {
1476         TRACE_ERROR("Failed to get process lock.\n");
1477         return rc;
1478     }
1479 
1480     memcpy(token_name, tokdata->nv_token_data->token_info.label,
1481            sizeof(token_name));
1482 
1483     rc = XProcUnLock(tokdata);
1484     if (rc != CKR_OK) {
1485         TRACE_ERROR("Failed to release process lock.\n");
1486         return rc;
1487     }
1488 
1489     /* Allocate structure to keep ICSF object information */
1490     if (!(mapping = malloc(sizeof(*mapping)))) {
1491         TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
1492         return CKR_HOST_MEMORY;
1493     }
1494     memset(mapping, 0, sizeof(struct icsf_object_mapping));
1495     mapping->session_id = session->handle;
1496 
1497     /* Get session state */
1498     if (!(session_state = get_session_state(session->handle))) {
1499         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
1500         rc = CKR_SESSION_HANDLE_INVALID;
1501         goto done;
1502     }
1503 
1504     /* check ldap handle */
1505     if (session_state->ld == NULL) {
1506         TRACE_ERROR("No LDAP handle.\n");
1507         rc = CKR_FUNCTION_FAILED;
1508         goto done;
1509     }
1510 
1511     /* Call ICSF service */
1512     if ((rc = icsf_create_object(session_state->ld, &reason, token_name,
1513                                  attrs, attrs_len, &mapping->icsf_object))) {
1514         TRACE_DEVEL("icsf_create_object failed\n");
1515         rc = icsf_to_ock_err(rc, reason);
1516         goto done;
1517     }
1518 
1519     /* Add info about object into session */
1520     if (!(node_number = bt_node_add(&objects, mapping))) {
1521         TRACE_ERROR("Failed to add object to binary tree.\n");
1522         rc = CKR_FUNCTION_FAILED;
1523         goto done;
1524     }
1525 
1526     /* Use node number as handle */
1527     *handle = node_number;
1528 
1529 done:
1530     /* If allocated, object must be freed in case of failure */
1531     if (rc && mapping)
1532         free(mapping);
1533 
1534     return rc;
1535 }
1536 
1537 /*
1538  * Check if attribute values are valid and add default values for missing ones.
1539  *
1540  * It returns a new allocated array that must be freed with
1541  * free_attribute_array().
1542  */
check_key_attributes(CK_ULONG class,CK_ULONG key_type,CK_ATTRIBUTE_PTR attrs,CK_ULONG attrs_len,CK_ATTRIBUTE_PTR * p_attrs,CK_ULONG * p_attrs_len)1543 static CK_RV check_key_attributes(CK_ULONG class, CK_ULONG key_type,
1544                                   CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len,
1545                                   CK_ATTRIBUTE_PTR * p_attrs,
1546                                   CK_ULONG * p_attrs_len)
1547 {
1548 
1549     CK_RV rc;
1550     CK_ULONG i;
1551     CK_ULONG check_types[] = { CKA_CLASS, CKA_KEY_TYPE };
1552     CK_ULONG *check_values[] = { &class, &key_type };
1553 
1554     if ((rc = dup_attribute_array(attrs, attrs_len, p_attrs, p_attrs_len)))
1555         return rc;
1556 
1557     for (i = 0; i < sizeof(check_types) / sizeof(*check_types); i++) {
1558         /* Search for the attribute */
1559         CK_ATTRIBUTE_PTR attr = get_attribute_by_type(*p_attrs,
1560                                                       *p_attrs_len,
1561                                                       check_types[i]);
1562         if (attr) {
1563             /* Check the expected value */
1564             if (*((CK_ULONG *) attr->pValue) != *check_values[i]) {
1565                 TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
1566                 rc = CKR_ATTRIBUTE_VALUE_INVALID;
1567                 goto cleanup;
1568             }
1569         } else {
1570             /* Add default value */
1571             rc = add_to_attribute_array(p_attrs, p_attrs_len,
1572                                         check_types[i],
1573                                         (CK_BYTE *) check_values[i],
1574                                         sizeof(*check_values[i]));
1575             if (rc)
1576                 goto cleanup;
1577         }
1578     }
1579 
1580     rc = CKR_OK;
1581 
1582 cleanup:
1583     if (rc) {
1584         free_attribute_array(*p_attrs, *p_attrs_len);
1585         *p_attrs = NULL;
1586         *p_attrs_len = 0;
1587     }
1588 
1589     return rc;
1590 }
1591 
1592 /*
1593  * Get the type of the key that must be generated based on given mechanism.
1594  *
1595  * This functions is used by both symmetric and asymmetric key generation
1596  * functions.
1597  */
get_generate_key_type(CK_MECHANISM_PTR mech)1598 static CK_ULONG get_generate_key_type(CK_MECHANISM_PTR mech)
1599 {
1600     switch (mech->mechanism) {
1601         /* Symmetric keys */
1602     case CKM_AES_KEY_GEN:
1603         return CKK_AES;
1604     case CKM_DES_KEY_GEN:
1605         return CKK_DES;
1606     case CKM_DES2_KEY_GEN:
1607         return CKK_DES2;
1608     case CKM_DES3_KEY_GEN:
1609         return CKK_DES3;
1610     case CKM_SSL3_PRE_MASTER_KEY_GEN:
1611         return CKK_GENERIC_SECRET;
1612         /* Asymmetric keys */
1613     case CKM_RSA_PKCS_KEY_PAIR_GEN:
1614         return CKK_RSA;
1615     case CKM_DSA_KEY_PAIR_GEN:
1616         return CKK_DSA;
1617     case CKM_DH_PKCS_KEY_PAIR_GEN:
1618     case CKM_DH_PKCS_DERIVE:
1619         return CKK_DH;
1620     case CKM_EC_KEY_PAIR_GEN:
1621         return CKK_EC;
1622     case CKM_SSL3_MASTER_KEY_DERIVE:
1623     case CKM_SSL3_KEY_AND_MAC_DERIVE:
1624     case CKM_TLS_KEY_AND_MAC_DERIVE:
1625     case CKM_GENERIC_SECRET_KEY_GEN:
1626         return CKK_GENERIC_SECRET;
1627     }
1628 
1629     return -1;
1630 }
1631 
1632 /*
1633  * Generate a key pair.
1634  */
icsftok_generate_key_pair(STDLL_TokData_t * tokdata,SESSION * session,CK_MECHANISM_PTR mech,CK_ATTRIBUTE_PTR pub_attrs,CK_ULONG pub_attrs_len,CK_ATTRIBUTE_PTR priv_attrs,CK_ULONG priv_attrs_len,CK_OBJECT_HANDLE_PTR p_pub_key,CK_OBJECT_HANDLE_PTR p_priv_key)1635 CK_RV icsftok_generate_key_pair(STDLL_TokData_t * tokdata, SESSION * session,
1636                                 CK_MECHANISM_PTR mech,
1637                                 CK_ATTRIBUTE_PTR pub_attrs,
1638                                 CK_ULONG pub_attrs_len,
1639                                 CK_ATTRIBUTE_PTR priv_attrs,
1640                                 CK_ULONG priv_attrs_len,
1641                                 CK_OBJECT_HANDLE_PTR p_pub_key,
1642                                 CK_OBJECT_HANDLE_PTR p_priv_key)
1643 {
1644     CK_RV rc;
1645     char token_name[sizeof(tokdata->nv_token_data->token_info.label)];
1646     struct session_state *session_state;
1647     struct icsf_object_mapping *pub_key_mapping = NULL;
1648     struct icsf_object_mapping *priv_key_mapping = NULL;
1649     int reason = 0;
1650     int pub_node_number, priv_node_number;
1651     CK_ATTRIBUTE_PTR new_pub_attrs = NULL;
1652     CK_ULONG new_pub_attrs_len = 0;
1653     CK_ATTRIBUTE_PTR new_priv_attrs = NULL;
1654     CK_ULONG new_priv_attrs_len = 0;
1655     CK_ULONG key_type;
1656 
1657     /* Check and set default attributes based on mech */
1658     if ((key_type = get_generate_key_type(mech)) == (CK_ULONG)-1) {
1659         TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
1660         rc = CKR_MECHANISM_INVALID;
1661         goto done;
1662     }
1663     rc = check_key_attributes(CKO_PUBLIC_KEY, key_type, pub_attrs,
1664                               pub_attrs_len, &new_pub_attrs,
1665                               &new_pub_attrs_len);
1666     if (rc != CKR_OK)
1667         goto done;
1668 
1669     rc = check_key_attributes(CKO_PRIVATE_KEY, key_type, priv_attrs,
1670                               priv_attrs_len, &new_priv_attrs,
1671                               &new_priv_attrs_len);
1672     if (rc != CKR_OK)
1673         goto done;
1674 
1675     /* Check permissions based on attributes and session */
1676     rc = check_session_permissions(session, new_pub_attrs, new_pub_attrs_len);
1677     if (rc != CKR_OK)
1678         goto done;
1679     rc = check_session_permissions(session, new_priv_attrs, new_priv_attrs_len);
1680     if (rc != CKR_OK)
1681         goto done;
1682 
1683     /* Get session state */
1684     if (!(session_state = get_session_state(session->handle))) {
1685         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
1686         rc = CKR_SESSION_HANDLE_INVALID;
1687         goto done;
1688     }
1689 
1690     /* check ldap handle */
1691     if (session_state->ld == NULL) {
1692         TRACE_ERROR("No LDAP handle.\n");
1693         rc = CKR_FUNCTION_FAILED;
1694         goto done;
1695     }
1696 
1697     /* Copy token name from shared memory */
1698     rc = XProcLock(tokdata);
1699     if (rc != CKR_OK) {
1700         TRACE_ERROR("Failed to get process lock.\n");
1701         goto done;
1702     }
1703 
1704     memcpy(token_name, tokdata->nv_token_data->token_info.label,
1705            sizeof(token_name));
1706 
1707     rc = XProcUnLock(tokdata);
1708     if (rc != CKR_OK) {
1709         TRACE_ERROR("Failed to release process lock.\n");
1710         goto done;
1711     }
1712 
1713     /* Allocate structure to keep ICSF objects information */
1714     if (!(pub_key_mapping = malloc(sizeof(*pub_key_mapping))) ||
1715         !(priv_key_mapping = malloc(sizeof(*priv_key_mapping)))) {
1716         TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
1717         rc = CKR_HOST_MEMORY;
1718         goto done;
1719     }
1720 
1721     /* Call ICSF service */
1722     if ((rc = icsf_generate_key_pair(session_state->ld, &reason, token_name,
1723                                      new_pub_attrs, new_pub_attrs_len,
1724                                      new_priv_attrs, new_priv_attrs_len,
1725                                      &pub_key_mapping->icsf_object,
1726                                      &priv_key_mapping->icsf_object))) {
1727         TRACE_DEVEL("icsf_generate_key_pair failed\n");
1728         rc = icsf_to_ock_err(rc, reason);
1729         goto done;
1730     }
1731 
1732     /* Add info about objects into session */
1733     if (!(pub_node_number = bt_node_add(&objects, pub_key_mapping)) ||
1734         !(priv_node_number = bt_node_add(&objects, priv_key_mapping))) {
1735         TRACE_ERROR("Failed to add object to binary tree.\n");
1736         rc = CKR_FUNCTION_FAILED;
1737         goto done;
1738     }
1739 
1740     /* Use node numbers as handles */
1741     *p_pub_key = pub_node_number;
1742     *p_priv_key = priv_node_number;
1743 
1744 done:
1745     free_attribute_array(new_pub_attrs, new_pub_attrs_len);
1746     free_attribute_array(new_priv_attrs, new_priv_attrs_len);
1747 
1748     /* Object mappings must be freed in case of failure */
1749     if (rc && pub_key_mapping)
1750         free(pub_key_mapping);
1751     if (rc && priv_key_mapping)
1752         free(priv_key_mapping);
1753 
1754     return rc;
1755 }
1756 
1757 /*
1758  * Generate a symmetric key.
1759  */
icsftok_generate_key(STDLL_TokData_t * tokdata,SESSION * session,CK_MECHANISM_PTR mech,CK_ATTRIBUTE_PTR attrs,CK_ULONG attrs_len,CK_OBJECT_HANDLE_PTR handle)1760 CK_RV icsftok_generate_key(STDLL_TokData_t * tokdata, SESSION * session,
1761                            CK_MECHANISM_PTR mech, CK_ATTRIBUTE_PTR attrs,
1762                            CK_ULONG attrs_len, CK_OBJECT_HANDLE_PTR handle)
1763 {
1764     CK_RV rc = CKR_OK;
1765     struct session_state *session_state;
1766     struct icsf_object_mapping *mapping = NULL;
1767     CK_ULONG node_number;
1768     char token_name[sizeof(tokdata->nv_token_data->token_info.label)];
1769     CK_ATTRIBUTE_PTR new_attrs = NULL;
1770     CK_ULONG new_attrs_len = 0;
1771     CK_ULONG class = CKO_SECRET_KEY;
1772     CK_ULONG key_type = 0;
1773     int reason = 0;
1774 
1775     /* Check attributes */
1776     if ((key_type = get_generate_key_type(mech)) == (CK_ULONG)-1) {
1777         TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
1778         rc = CKR_MECHANISM_INVALID;
1779         goto done;
1780     }
1781 
1782     rc = check_key_attributes(class, key_type, attrs, attrs_len, &new_attrs,
1783                               &new_attrs_len);
1784     if (rc != CKR_OK)
1785         goto done;
1786 
1787     /* Check permissions based on attributes and session */
1788     rc = check_session_permissions(session, new_attrs, new_attrs_len);
1789     if (rc != CKR_OK)
1790         goto done;
1791 
1792     /* Copy token name from shared memory */
1793     rc = XProcLock(tokdata);
1794     if (rc != CKR_OK) {
1795         TRACE_ERROR("Failed to get process lock.\n");
1796         goto done;
1797     }
1798 
1799     memcpy(token_name, tokdata->nv_token_data->token_info.label,
1800            sizeof(token_name));
1801 
1802     rc = XProcUnLock(tokdata);
1803     if (rc != CKR_OK) {
1804         TRACE_ERROR("Failed to release process lock.\n");
1805         goto done;
1806     }
1807 
1808     /* Allocate structure to keep ICSF object information */
1809     if (!(mapping = malloc(sizeof(*mapping)))) {
1810         TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
1811         goto done;
1812     }
1813     memset(mapping, 0, sizeof(struct icsf_object_mapping));
1814     mapping->session_id = session->handle;
1815 
1816     /* Get session state */
1817     if (!(session_state = get_session_state(session->handle))) {
1818         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
1819         rc = CKR_SESSION_HANDLE_INVALID;
1820         goto done;
1821     }
1822 
1823     /* check ldap handle */
1824     if (session_state->ld == NULL) {
1825         TRACE_ERROR("No LDAP handle.\n");
1826         rc = CKR_FUNCTION_FAILED;
1827         goto done;
1828     }
1829 
1830     /* Call ICSF service */
1831     if ((rc = icsf_generate_secret_key(session_state->ld, &reason, token_name,
1832                                        mech, new_attrs, new_attrs_len,
1833                                        &mapping->icsf_object))) {
1834         TRACE_DEVEL("icsf_generate_secret_key failed\n");
1835         rc = icsf_to_ock_err(rc, reason);
1836         goto done;
1837     }
1838 
1839     /* Add info about object into session */
1840     if (!(node_number = bt_node_add(&objects, mapping))) {
1841         TRACE_ERROR("Failed to add object to binary tree.\n");
1842         rc = CKR_FUNCTION_FAILED;
1843         goto done;
1844     }
1845 
1846     /* Use node number as handle */
1847     *handle = node_number;
1848 
1849 done:
1850     if (new_attrs)
1851         free_attribute_array(new_attrs, new_attrs_len);
1852 
1853     /* If allocated, object must be freed in case of failure */
1854     if (rc && mapping)
1855         free(mapping);
1856 
1857     return rc;
1858 }
1859 
1860 /*
1861  * Free all data pointed by an encryption context and set everything to zero.
1862  */
free_encr_ctx(ENCR_DECR_CONTEXT * encr_ctx)1863 static void free_encr_ctx(ENCR_DECR_CONTEXT * encr_ctx)
1864 {
1865     struct icsf_multi_part_context *multi_part_ctx;
1866 
1867     if (!encr_ctx)
1868         return;
1869 
1870     /* Initialize encryption context */
1871     multi_part_ctx = (struct icsf_multi_part_context *) encr_ctx->context;
1872     if (multi_part_ctx) {
1873         if (multi_part_ctx->data)
1874             free(multi_part_ctx->data);
1875         free(multi_part_ctx);
1876     }
1877     if (encr_ctx->mech.pParameter)
1878         free(encr_ctx->mech.pParameter);
1879     memset(encr_ctx, 0, sizeof(*encr_ctx));
1880 }
1881 
1882 /*
1883  * Return if the algorithm used by a mechanism is asymmetric or symmetric.
1884  */
get_crypt_type(CK_MECHANISM_PTR mech,int * p_symmetric)1885 static CK_RV get_crypt_type(CK_MECHANISM_PTR mech, int *p_symmetric)
1886 {
1887     switch (mech->mechanism) {
1888     case CKM_AES_ECB:
1889     case CKM_AES_CBC:
1890     case CKM_AES_CBC_PAD:
1891     case CKM_DES_ECB:
1892     case CKM_DES_CBC:
1893     case CKM_DES_CBC_PAD:
1894     case CKM_DES3_ECB:
1895     case CKM_DES3_CBC:
1896     case CKM_DES3_CBC_PAD:
1897         *p_symmetric = 1;
1898         break;
1899     case CKM_RSA_PKCS:
1900     case CKM_RSA_X_509:
1901         *p_symmetric = 0;
1902         break;
1903     default:
1904         return CKR_MECHANISM_INVALID;
1905     }
1906 
1907     return CKR_OK;
1908 }
1909 
1910 /**
1911  * Validate mechanism parameter length here for the applicable
1912  * encryption/decryption mechanisms supported by icsf token
1913  */
validate_mech_parameters(CK_MECHANISM_PTR mech)1914 static CK_RV validate_mech_parameters(CK_MECHANISM_PTR mech)
1915 {
1916     CK_RV rc = CKR_OK;
1917     size_t expected_block_size = 0;
1918 
1919     /* Verify the mechanisms that has a parameter length
1920      * specification per pkcs11#v2.2 spec
1921      * */
1922     switch (mech->mechanism) {
1923     case CKM_DES_CBC:
1924     case CKM_DES_CBC_PAD:
1925     case CKM_DES3_CBC:
1926     case CKM_DES3_CBC_PAD:
1927     case CKM_AES_CBC:
1928     case CKM_AES_CBC_PAD:
1929         /* Get the expected block size. This check needs to be here as
1930          * CKM_RSA_X_509 and CKM_RSA_PKCS does not have a block size */
1931         if ((rc = icsf_block_size(mech->mechanism, &expected_block_size)))
1932             return rc;
1933 
1934         if (mech->ulParameterLen != expected_block_size) {
1935             TRACE_ERROR("Invalid mechanism parameter length: %lu "
1936                         "(expected %lu)\n",
1937                         (unsigned long) mech->ulParameterLen,
1938                         (unsigned long) expected_block_size);
1939             return CKR_MECHANISM_PARAM_INVALID;
1940         }
1941         break;
1942     case CKM_DES_ECB:
1943     case CKM_DES3_ECB:
1944     case CKM_RSA_X_509:
1945     case CKM_RSA_PKCS:
1946     case CKM_AES_ECB:
1947         if (mech->ulParameterLen != 0) {
1948             TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
1949             return CKR_MECHANISM_PARAM_INVALID;
1950         }
1951         break;
1952     default:
1953         /** Encryption/decryption mechanism not supported by icsf token */
1954         TRACE_ERROR("icsf invalid mechanism %lu\n", mech->mechanism);
1955         return CKR_MECHANISM_INVALID;
1956     }
1957 
1958     return rc;
1959 }
1960 
1961 
1962 /*
1963  * Initialize an encryption operation.
1964  */
icsftok_encrypt_init(SESSION * session,CK_MECHANISM_PTR mech,CK_OBJECT_HANDLE key)1965 CK_RV icsftok_encrypt_init(SESSION * session, CK_MECHANISM_PTR mech,
1966                            CK_OBJECT_HANDLE key)
1967 {
1968     CK_RV rc = CKR_OK;
1969     ENCR_DECR_CONTEXT *encr_ctx = &session->encr_ctx;
1970     struct icsf_multi_part_context *multi_part_ctx = NULL;
1971     size_t block_size = 0;
1972     int symmetric = 0;
1973 
1974     /* Check session */
1975     if (!get_session_state(session->handle)) {
1976         rc = CKR_SESSION_HANDLE_INVALID;
1977         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
1978         goto done;
1979     }
1980 
1981     /* Get algorithm type */
1982     if ((rc = get_crypt_type(mech, &symmetric)))
1983         goto done;
1984 
1985     /* Check if key exists */
1986     if (!bt_get_node_value(&objects, key)) {
1987         rc = CKR_KEY_HANDLE_INVALID;
1988         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
1989     }
1990     if (rc != CKR_OK)
1991         goto done;
1992 
1993         /** validate the mechanism parameter length here */
1994     if ((rc = validate_mech_parameters(mech)))
1995         goto done;
1996 
1997     /* Initialize encryption context */
1998     free_encr_ctx(encr_ctx);
1999     encr_ctx->key = key;
2000     encr_ctx->active = TRUE;
2001     encr_ctx->multi = FALSE;
2002 
2003     /* Copy mechanism */
2004     if (mech->pParameter == NULL || mech->ulParameterLen == 0) {
2005         encr_ctx->mech.ulParameterLen = 0;
2006         encr_ctx->mech.pParameter = NULL;
2007     } else {
2008         encr_ctx->mech.pParameter = malloc(mech->ulParameterLen);
2009         if (!encr_ctx->mech.pParameter) {
2010             TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
2011             rc = CKR_HOST_MEMORY;
2012             goto done;
2013         }
2014         encr_ctx->mech.ulParameterLen = mech->ulParameterLen;
2015         memcpy(encr_ctx->mech.pParameter, mech->pParameter,
2016                mech->ulParameterLen);
2017     }
2018     encr_ctx->mech.mechanism = mech->mechanism;
2019 
2020     /*
2021      * Asymmetric algorithms don't support multi-part and then there's no
2022      * need to allocate context.
2023      */
2024     if (!symmetric)
2025         goto done;
2026 
2027     /* Allocate context for multi-part operations */
2028     if (!(multi_part_ctx = malloc(sizeof(*multi_part_ctx)))) {
2029         TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
2030         rc = CKR_HOST_MEMORY;
2031         goto done;
2032     }
2033     encr_ctx->context = (void *) multi_part_ctx;
2034 
2035     /* Chained data has always a fixed length */
2036     memset(multi_part_ctx, 0, sizeof(*multi_part_ctx));
2037 
2038     /* Check mechanism and get block size */
2039     rc = icsf_block_size(mech->mechanism, &block_size);
2040     if (rc != CKR_OK)
2041         goto done;
2042 
2043     /*
2044      * data is used to retain data until at least the block size is reached.
2045      */
2046     multi_part_ctx->data_len = block_size;
2047     multi_part_ctx->data = malloc(multi_part_ctx->data_len);
2048     if (!multi_part_ctx->data) {
2049         TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
2050         rc = CKR_HOST_MEMORY;
2051         goto done;
2052     }
2053 
2054 done:
2055     if (rc != CKR_OK)
2056         free_encr_ctx(encr_ctx);
2057 
2058     return rc;
2059 }
2060 
2061 /*
2062  * Encrypt data and finalize an encryption operation.
2063  */
icsftok_encrypt(SESSION * session,CK_BYTE_PTR input_data,CK_ULONG input_data_len,CK_BYTE_PTR output_data,CK_ULONG_PTR p_output_data_len)2064 CK_RV icsftok_encrypt(SESSION * session, CK_BYTE_PTR input_data,
2065                       CK_ULONG input_data_len, CK_BYTE_PTR output_data,
2066                       CK_ULONG_PTR p_output_data_len)
2067 {
2068     CK_RV rc = CKR_OK;
2069     CK_BBOOL is_length_only = (output_data == NULL);
2070     ENCR_DECR_CONTEXT *encr_ctx = &session->encr_ctx;
2071     struct session_state *session_state;
2072     struct icsf_object_mapping *mapping;
2073     char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, };
2074     size_t chain_data_len = sizeof(chain_data);
2075     int reason = 0;
2076     int symmetric = 0;
2077 
2078     /* Get algorithm type */
2079     if ((rc = get_crypt_type(&encr_ctx->mech, &symmetric)))
2080         goto done;
2081 
2082     /* Check if there's a multi-part encryption in progress */
2083     if (encr_ctx->multi) {
2084         TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE));
2085         rc = CKR_OPERATION_ACTIVE;
2086         goto done;
2087     }
2088 
2089     /* Check session */
2090     if (!(session_state = get_session_state(session->handle))) {
2091         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
2092         rc = CKR_SESSION_HANDLE_INVALID;
2093         goto done;
2094     }
2095 
2096     /* check ldap handle */
2097     if (session_state->ld == NULL) {
2098         TRACE_ERROR("No LDAP handle.\n");
2099         rc = CKR_FUNCTION_FAILED;
2100         goto done;
2101     }
2102 
2103     /* Check if key exists */
2104     if (!(mapping = bt_get_node_value(&objects, encr_ctx->key))) {
2105         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
2106         rc = CKR_KEY_HANDLE_INVALID;
2107     }
2108     if (rc != CKR_OK)
2109         goto done;
2110 
2111     /* Encrypt data using remote token. */
2112     if (symmetric) {
2113         rc = icsf_secret_key_encrypt(session_state->ld, &reason,
2114                                      &mapping->icsf_object,
2115                                      &encr_ctx->mech,
2116                                      ICSF_CHAINING_ONLY, (char *)input_data,
2117                                      input_data_len, (char *)output_data,
2118                                      p_output_data_len, chain_data,
2119                                      &chain_data_len);
2120     } else {
2121         rc = icsf_public_key_verify(session_state->ld, &reason, TRUE,
2122                                     &mapping->icsf_object,
2123                                     &encr_ctx->mech, (char *)input_data,
2124                                     input_data_len, (char *)output_data,
2125                                     p_output_data_len);
2126     }
2127     if (rc) {
2128         if (reason == ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT) {
2129             if (is_length_only) {
2130                 /*
2131                  * Parameter too short is not a problem when
2132                  * querying the expect output size.
2133                  */
2134                 rc = CKR_OK;
2135             } else {
2136                 TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL));
2137                 rc = CKR_BUFFER_TOO_SMALL;
2138             }
2139         } else {
2140             TRACE_ERROR("Failed to encrypt data. reason = %d\n", reason);
2141             rc = icsf_to_ock_err(rc, reason);
2142         }
2143         goto done;
2144     }
2145 
2146 done:
2147     if (rc != CKR_BUFFER_TOO_SMALL && !(rc == CKR_OK && is_length_only))
2148         free_encr_ctx(encr_ctx);
2149 
2150     return rc;
2151 }
2152 
2153 /*
2154  * Multi-part encryption.
2155  */
icsftok_encrypt_update(SESSION * session,CK_BYTE_PTR input_part,CK_ULONG input_part_len,CK_BYTE_PTR output_part,CK_ULONG_PTR p_output_part_len)2156 CK_RV icsftok_encrypt_update(SESSION * session, CK_BYTE_PTR input_part,
2157                              CK_ULONG input_part_len, CK_BYTE_PTR output_part,
2158                              CK_ULONG_PTR p_output_part_len)
2159 {
2160     CK_RV rc = CKR_OK;
2161     CK_BBOOL is_length_only = (output_part == NULL);
2162     ENCR_DECR_CONTEXT *encr_ctx = &session->encr_ctx;
2163     struct icsf_multi_part_context *multi_part_ctx;
2164     struct session_state *session_state;
2165     struct icsf_object_mapping *mapping;
2166     char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, };
2167     size_t chain_data_len = sizeof(chain_data);
2168     CK_ULONG total, remaining;
2169     char *buffer = NULL;
2170     int chaining;
2171     int reason = 0;
2172     int symmetric = 0;
2173 
2174     /* Multi-part is not supported for asymmetric algorithms. */
2175     if ((rc = get_crypt_type(&encr_ctx->mech, &symmetric)))
2176         goto done;
2177     if (!symmetric) {
2178         TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
2179         rc = CKR_MECHANISM_INVALID;
2180         goto done;
2181     }
2182 
2183     /* Check session */
2184     if (!(session_state = get_session_state(session->handle))) {
2185         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
2186         rc = CKR_SESSION_HANDLE_INVALID;
2187         goto done;
2188     }
2189 
2190     /* check ldap handle */
2191     if (session_state->ld == NULL) {
2192         TRACE_ERROR("No LDAP handle.\n");
2193         rc = CKR_FUNCTION_FAILED;
2194         goto done;
2195     }
2196 
2197     /* Check if key exists */
2198     if (!(mapping = bt_get_node_value(&objects, encr_ctx->key))) {
2199         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
2200         rc = CKR_KEY_HANDLE_INVALID;
2201         goto done;
2202     }
2203 
2204     multi_part_ctx = (struct icsf_multi_part_context *) encr_ctx->context;
2205 
2206     /* Define the type of the call */
2207     switch (encr_ctx->mech.mechanism) {
2208     case CKM_DES_ECB:
2209     case CKM_DES3_ECB:
2210     case CKM_AES_ECB:
2211         /* ICSF just support the chaining mode ONLY for ECB. */
2212         chaining = ICSF_CHAINING_ONLY;
2213         break;
2214     default:
2215         if (multi_part_ctx->initiated) {
2216             chaining = ICSF_CHAINING_CONTINUE;
2217             memcpy(chain_data, multi_part_ctx->chain_data, chain_data_len);
2218         } else {
2219             chaining = ICSF_CHAINING_INITIAL;
2220         }
2221     }
2222 
2223     /*
2224      * Data needs to be sent to ICSF in chucks with size that is multiple of
2225      * block size. Any remaining data is kept in the multi-part context and
2226      * can be sent in a further call of the update function or when the
2227      * finalize function is called.
2228      */
2229     total = multi_part_ctx->used_data_len + input_part_len;
2230     remaining = total % multi_part_ctx->data_len;
2231 
2232     /*
2233      * If there's no enough data to make a call, skip it.
2234      */
2235     if (total < multi_part_ctx->data_len) {
2236         *p_output_part_len = 0;
2237         goto keep_remaining_data;
2238     }
2239 
2240     /*
2241      * The data to be encrypted should have length that is multiple of the
2242      * block size. It is composed by data kept in the multi-part context
2243      * concatenated with part of the data given.
2244      */
2245     if (!(buffer = malloc(total - remaining))) {
2246         TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
2247         rc = CKR_HOST_MEMORY;
2248         goto done;
2249     }
2250     memcpy(buffer, multi_part_ctx->data, multi_part_ctx->used_data_len);
2251     memcpy(buffer + multi_part_ctx->used_data_len, input_part,
2252            input_part_len - remaining);
2253 
2254     /* Encrypt data using remote token. */
2255     rc = icsf_secret_key_encrypt(session_state->ld, &reason,
2256                                  &mapping->icsf_object,
2257                                  &encr_ctx->mech, chaining,
2258                                  buffer, total - remaining,
2259                                  (char *)output_part, p_output_part_len,
2260                                  chain_data, &chain_data_len);
2261     if (rc) {
2262         if (reason == ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT) {
2263             if (is_length_only) {
2264                 /*
2265                  * Parameter too short is not a problem when
2266                  * querying the expect output size.
2267                  */
2268                 rc = CKR_OK;
2269             } else {
2270                 TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL));
2271                 rc = CKR_BUFFER_TOO_SMALL;
2272             }
2273         } else {
2274             TRACE_DEVEL("Failed to encrypt data. reason = %d\n", reason);
2275             rc = icsf_to_ock_err(rc, reason);
2276         }
2277         goto done;
2278     }
2279 
2280     /** If this is the first block for multi-part operation, also set
2281      *  the encr_ctx->context_len here. This is needed for
2282      *  C_GetOperationState to work correctly */
2283     if (!multi_part_ctx->initiated)
2284         encr_ctx->context_len = sizeof(*multi_part_ctx);
2285 
2286     /*
2287      * When blocks are sent it's necessary to keep the chain data returned
2288      * to be used in a subsequent call.
2289      */
2290     if (!is_length_only) {
2291         /* Copy chain data into context */
2292         memcpy(multi_part_ctx->chain_data, chain_data, chain_data_len);
2293 
2294         /* Mark multi-part operation as initiated */
2295         multi_part_ctx->initiated = TRUE;
2296 
2297         /* Mark the multi-part operation in encr_ctx */
2298         encr_ctx->multi = TRUE;
2299 
2300         /* Data stored in cache was used */
2301         multi_part_ctx->used_data_len = 0;
2302     }
2303 
2304 keep_remaining_data:
2305     /* Keep the remaining data to a next call */
2306     if (!is_length_only) {
2307         /* Copy remaining part of input_part into context */
2308         if (total < multi_part_ctx->data_len) {
2309             memcpy(multi_part_ctx->data +
2310                    multi_part_ctx->used_data_len, input_part, input_part_len);
2311         } else {
2312             memcpy(multi_part_ctx->data,
2313                    input_part + input_part_len - remaining, remaining);
2314         }
2315         multi_part_ctx->used_data_len = remaining;
2316     }
2317 
2318 done:
2319     /* Free resources */
2320     if (buffer)
2321         free(buffer);
2322 
2323     if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL)
2324         free_encr_ctx(encr_ctx);
2325 
2326     return rc;
2327 }
2328 
2329 /*
2330  * Finalize a multi-part encryption.
2331  */
icsftok_encrypt_final(SESSION * session,CK_BYTE_PTR output_part,CK_ULONG_PTR p_output_part_len)2332 CK_RV icsftok_encrypt_final(SESSION * session, CK_BYTE_PTR output_part,
2333                             CK_ULONG_PTR p_output_part_len)
2334 {
2335     CK_RV rc = CKR_OK;
2336     CK_BBOOL is_length_only = (output_part == NULL);
2337     ENCR_DECR_CONTEXT *encr_ctx = &session->encr_ctx;
2338     struct icsf_multi_part_context *multi_part_ctx;
2339     struct session_state *session_state;
2340     struct icsf_object_mapping *mapping;
2341     char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, };
2342     size_t chain_data_len = sizeof(chain_data);
2343     int chaining;
2344     int reason = 0;
2345     int symmetric = 0;
2346 
2347     /* Multi-part is not supported for asymmetric algorithms. */
2348     if ((rc = get_crypt_type(&encr_ctx->mech, &symmetric)))
2349         goto done;
2350     if (!symmetric) {
2351         TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
2352         rc = CKR_MECHANISM_INVALID;
2353         goto done;
2354     }
2355 
2356     /* Check session */
2357     if (!(session_state = get_session_state(session->handle))) {
2358         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
2359         rc = CKR_SESSION_HANDLE_INVALID;
2360         goto done;
2361     }
2362 
2363     /* check ldap handle */
2364     if (session_state->ld == NULL) {
2365         TRACE_ERROR("No LDAP handle.\n");
2366         rc = CKR_FUNCTION_FAILED;
2367         goto done;
2368     }
2369 
2370     /* Check if key exists */
2371     if (!(mapping = bt_get_node_value(&objects, encr_ctx->key))) {
2372         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
2373         rc = CKR_KEY_HANDLE_INVALID;
2374         goto done;
2375     }
2376 
2377     /* Define the type of the call */
2378     multi_part_ctx = (struct icsf_multi_part_context *) encr_ctx->context;
2379     switch (encr_ctx->mech.mechanism) {
2380     case CKM_DES_ECB:
2381     case CKM_DES3_ECB:
2382     case CKM_AES_ECB:
2383         /*
2384          * When not using a chained algorithm and there's no remaining
2385          * data, don't call ICSF.
2386          */
2387         *p_output_part_len = 0;
2388         if (!multi_part_ctx->used_data_len)
2389             goto done;
2390 
2391         /* ICSF just support the chaining mode ONLY for ECB. */
2392         chaining = ICSF_CHAINING_ONLY;
2393         break;
2394     default:
2395         if (multi_part_ctx->initiated) {
2396             chaining = ICSF_CHAINING_FINAL;
2397             memcpy(chain_data, multi_part_ctx->chain_data, chain_data_len);
2398         } else {
2399             chaining = ICSF_CHAINING_ONLY;
2400         }
2401     }
2402 
2403     /*
2404      * Encrypt data using remote token.
2405      *
2406      * All the data in multi-part context should be sent.
2407      */
2408     rc = icsf_secret_key_encrypt(session_state->ld, &reason,
2409                                  &mapping->icsf_object,
2410                                  &encr_ctx->mech, chaining,
2411                                  multi_part_ctx->data,
2412                                  multi_part_ctx->used_data_len,
2413                                  (char *)output_part, p_output_part_len,
2414                                  chain_data, &chain_data_len);
2415     if (rc) {
2416         if (reason == ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT) {
2417             if (is_length_only) {
2418                 /*
2419                  * Parameter too short is not a problem when
2420                  * querying the expect output size.
2421                  */
2422                 rc = CKR_OK;
2423             } else {
2424                 TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL));
2425                 rc = CKR_BUFFER_TOO_SMALL;
2426             }
2427         } else {
2428             TRACE_DEVEL("Failed to encrypt data. reason = %d\n", reason);
2429             rc = icsf_to_ock_err(rc, reason);
2430         }
2431         goto done;
2432     }
2433 
2434 done:
2435     if ((is_length_only && rc != CKR_OK) ||
2436         (!is_length_only && rc != CKR_BUFFER_TOO_SMALL))
2437         free_encr_ctx(encr_ctx);
2438 
2439     return rc;
2440 }
2441 
2442 /*
2443  * Initialize a decryption operation.
2444  */
icsftok_decrypt_init(SESSION * session,CK_MECHANISM_PTR mech,CK_OBJECT_HANDLE key)2445 CK_RV icsftok_decrypt_init(SESSION * session, CK_MECHANISM_PTR mech,
2446                            CK_OBJECT_HANDLE key)
2447 {
2448     CK_RV rc = CKR_OK;
2449     ENCR_DECR_CONTEXT *decr_ctx = &session->decr_ctx;
2450     struct icsf_multi_part_context *multi_part_ctx = NULL;
2451     size_t block_size = 0;
2452     int symmetric = 0;
2453 
2454     /* Check session */
2455     if (!get_session_state(session->handle)) {
2456         rc = CKR_SESSION_HANDLE_INVALID;
2457         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
2458         goto done;
2459     }
2460 
2461     /* Get algorithm type */
2462     if ((rc = get_crypt_type(mech, &symmetric)))
2463         goto done;
2464 
2465     /* Check if key exists */
2466     if (!bt_get_node_value(&objects, key)) {
2467         rc = CKR_KEY_HANDLE_INVALID;
2468         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
2469         goto done;
2470     }
2471 
2472         /** validate the mechanism parameter length here */
2473     if ((rc = validate_mech_parameters(mech)))
2474         goto done;
2475 
2476     /* Initialize decryption context */
2477     free_encr_ctx(decr_ctx);
2478     decr_ctx->key = key;
2479     decr_ctx->active = TRUE;
2480     decr_ctx->multi = FALSE;
2481 
2482     /* Copy mechanism */
2483     if (mech->pParameter == NULL || mech->ulParameterLen == 0) {
2484         decr_ctx->mech.ulParameterLen = 0;
2485         decr_ctx->mech.pParameter = NULL;
2486     } else {
2487         decr_ctx->mech.pParameter = malloc(mech->ulParameterLen);
2488         if (!decr_ctx->mech.pParameter) {
2489             TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
2490             rc = CKR_HOST_MEMORY;
2491             goto done;
2492         }
2493         decr_ctx->mech.ulParameterLen = mech->ulParameterLen;
2494         memcpy(decr_ctx->mech.pParameter, mech->pParameter,
2495                mech->ulParameterLen);
2496     }
2497     decr_ctx->mech.mechanism = mech->mechanism;
2498 
2499     /*
2500      * Asymmetric algorithms don't support multi-part and then there's no
2501      * need to allocate context.
2502      */
2503     if (!symmetric)
2504         goto done;
2505 
2506     /* Allocate context for multi-part operations */
2507     if (!(multi_part_ctx = malloc(sizeof(*multi_part_ctx)))) {
2508         TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
2509         rc = CKR_HOST_MEMORY;
2510         goto done;
2511     }
2512     decr_ctx->context = (void *) multi_part_ctx;
2513 
2514     /* Chained data has always a fixed length */
2515     memset(multi_part_ctx, 0, sizeof(*multi_part_ctx));
2516 
2517     /* Check mechanism and get block size */
2518     rc = icsf_block_size(mech->mechanism, &block_size);
2519     if (rc != CKR_OK)
2520         goto done;
2521 
2522     /*
2523      * data is used to retain data until at least the block size is reached.
2524      */
2525     multi_part_ctx->data_len = block_size;
2526     multi_part_ctx->data = malloc(multi_part_ctx->data_len);
2527     if (!multi_part_ctx->data) {
2528         TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
2529         rc = CKR_HOST_MEMORY;
2530         goto done;
2531     }
2532 
2533 done:
2534     if (rc != CKR_OK)
2535         free_encr_ctx(decr_ctx);
2536 
2537     return rc;
2538 }
2539 
2540 /*
2541  * Decrypt data and finalize a decryption operation.
2542  */
icsftok_decrypt(SESSION * session,CK_BYTE_PTR input_data,CK_ULONG input_data_len,CK_BYTE_PTR output_data,CK_ULONG_PTR p_output_data_len)2543 CK_RV icsftok_decrypt(SESSION * session, CK_BYTE_PTR input_data,
2544                       CK_ULONG input_data_len, CK_BYTE_PTR output_data,
2545                       CK_ULONG_PTR p_output_data_len)
2546 {
2547     CK_RV rc = CKR_OK;
2548     CK_BBOOL is_length_only = (output_data == NULL);
2549     ENCR_DECR_CONTEXT *decr_ctx = &session->decr_ctx;
2550     struct session_state *session_state;
2551     struct icsf_object_mapping *mapping;
2552     char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, };
2553     size_t chain_data_len = sizeof(chain_data);
2554     int reason = 0;
2555     int symmetric = 0;
2556 
2557     /* Get algorithm type */
2558     if ((rc = get_crypt_type(&decr_ctx->mech, &symmetric)))
2559         goto done;
2560 
2561     /* Check if there's a multi-part decryption in progress */
2562     if (decr_ctx->multi) {
2563         TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE));
2564         rc = CKR_OPERATION_ACTIVE;
2565         goto done;
2566     }
2567 
2568     /* Check session */
2569     if (!(session_state = get_session_state(session->handle))) {
2570         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
2571         rc = CKR_SESSION_HANDLE_INVALID;
2572         goto done;
2573     }
2574 
2575     /* check ldap handle */
2576     if (session_state->ld == NULL) {
2577         TRACE_ERROR("No LDAP handle.\n");
2578         rc = CKR_FUNCTION_FAILED;
2579         goto done;
2580     }
2581 
2582     /* Check if key exists */
2583     if (!(mapping = bt_get_node_value(&objects, decr_ctx->key))) {
2584         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
2585         rc = CKR_KEY_HANDLE_INVALID;
2586         goto done;
2587     }
2588 
2589     /* Decrypt data using remote token. */
2590     if (symmetric) {
2591         rc = icsf_secret_key_decrypt(session_state->ld, &reason,
2592                                      &mapping->icsf_object,
2593                                      &decr_ctx->mech,
2594                                      ICSF_CHAINING_ONLY, (char *)input_data,
2595                                      input_data_len, (char *)output_data,
2596                                      p_output_data_len, chain_data,
2597                                      &chain_data_len);
2598     } else {
2599         rc = icsf_private_key_sign(session_state->ld, &reason, TRUE,
2600                                    &mapping->icsf_object,
2601                                    &decr_ctx->mech, (char *)input_data,
2602                                    input_data_len, (char *)output_data,
2603                                    p_output_data_len);
2604     }
2605     if (rc) {
2606         if (reason == ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT) {
2607             if (is_length_only) {
2608                 /*
2609                  * Parameter too short is not a problem when
2610                  * querying the expect output size.
2611                  */
2612                 rc = CKR_OK;
2613             } else {
2614                 TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL));
2615                 rc = CKR_BUFFER_TOO_SMALL;
2616             }
2617         } else {
2618             TRACE_DEVEL("Failed to decrypt data. reason = %d\n", reason);
2619             rc = icsf_to_ock_err(rc, reason);
2620         }
2621         goto done;
2622     }
2623 
2624 done:
2625     if (rc != CKR_BUFFER_TOO_SMALL && !(rc == CKR_OK && is_length_only))
2626         free_encr_ctx(decr_ctx);
2627 
2628     return rc;
2629 }
2630 
2631 /*
2632  * Multi-part decryption.
2633  */
icsftok_decrypt_update(SESSION * session,CK_BYTE_PTR input_part,CK_ULONG input_part_len,CK_BYTE_PTR output_part,CK_ULONG_PTR p_output_part_len)2634 CK_RV icsftok_decrypt_update(SESSION * session, CK_BYTE_PTR input_part,
2635                              CK_ULONG input_part_len, CK_BYTE_PTR output_part,
2636                              CK_ULONG_PTR p_output_part_len)
2637 {
2638     CK_RV rc = CKR_OK;
2639     CK_BBOOL is_length_only = (output_part == NULL);
2640     ENCR_DECR_CONTEXT *decr_ctx = &session->decr_ctx;
2641     struct icsf_multi_part_context *multi_part_ctx;
2642     struct session_state *session_state;
2643     struct icsf_object_mapping *mapping;
2644     char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, };
2645     size_t chain_data_len = sizeof(chain_data);
2646     CK_ULONG total, remaining;
2647     char *buffer = NULL;
2648     int chaining;
2649     int reason = 0;
2650     int padding = 0;
2651     int symmetric = 0;
2652 
2653     /* Multi-part is not supported for asymmetric algorithms. */
2654     if ((rc = get_crypt_type(&decr_ctx->mech, &symmetric)))
2655         goto done;
2656     if (!symmetric) {
2657         TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
2658         rc = CKR_MECHANISM_INVALID;
2659         goto done;
2660     }
2661 
2662     /* Check session */
2663     if (!(session_state = get_session_state(session->handle))) {
2664         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
2665         rc = CKR_SESSION_HANDLE_INVALID;
2666         goto done;
2667     }
2668 
2669     /* check ldap handle */
2670     if (session_state->ld == NULL) {
2671         TRACE_ERROR("No LDAP handle.\n");
2672         rc = CKR_FUNCTION_FAILED;
2673         goto done;
2674     }
2675 
2676     /* Check if key exists */
2677     if (!(mapping = bt_get_node_value(&objects, decr_ctx->key))) {
2678         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
2679         rc = CKR_KEY_HANDLE_INVALID;
2680         goto done;
2681     }
2682 
2683     multi_part_ctx = (struct icsf_multi_part_context *) decr_ctx->context;
2684 
2685     /* Define the type of the call */
2686     switch (decr_ctx->mech.mechanism) {
2687     case CKM_AES_ECB:
2688     case CKM_DES_ECB:
2689     case CKM_DES3_ECB:
2690         /* ICSF just support the chaining mode ONLY for ECB. */
2691         chaining = ICSF_CHAINING_ONLY;
2692         break;
2693     case CKM_AES_CBC_PAD:
2694     case CKM_DES_CBC_PAD:
2695     case CKM_DES3_CBC_PAD:
2696         padding = 1;
2697         /* fallthrough */
2698     default:
2699         if (multi_part_ctx->initiated) {
2700             chaining = ICSF_CHAINING_CONTINUE;
2701             memcpy(chain_data, multi_part_ctx->chain_data, chain_data_len);
2702         } else {
2703             chaining = ICSF_CHAINING_INITIAL;
2704         }
2705     }
2706 
2707     /*
2708      * Data needs to be sent to ICSF in chucks with size that is multiple of
2709      * block size. Any remaining data is kept in the multi-part context and
2710      * can be sent in a further call of the update function or when the
2711      * finalize function is called.
2712      *
2713      * When padding is used, there's no way to know if the current block of
2714      * data is the one that contains the padding, So a block is kept in
2715      * multi-part context when the data available is exactly multiple of the
2716      * block size.
2717      */
2718     total = multi_part_ctx->used_data_len + input_part_len;
2719     if (!padding) {
2720         remaining = total % multi_part_ctx->data_len;
2721     } else {
2722         remaining = MIN(((total - 1) % multi_part_ctx->data_len) + 1, total);
2723     }
2724 
2725     /*
2726      * If there's no enough data to make a call, skip it.
2727      */
2728     if (total < multi_part_ctx->data_len ||
2729         (padding && total == multi_part_ctx->data_len)) {
2730         *p_output_part_len = 0;
2731         goto keep_remaining_data;
2732     }
2733 
2734 
2735     /*
2736      * The data to be decrypted should have length that is multiple of the
2737      * block size. It is composed by data kept in the multi-part context
2738      * concatenated with part of the data given.
2739      */
2740     if (!(buffer = malloc(total - remaining))) {
2741         TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
2742         rc = CKR_HOST_MEMORY;
2743         goto done;
2744     }
2745     memcpy(buffer, multi_part_ctx->data, multi_part_ctx->used_data_len);
2746     memcpy(buffer + multi_part_ctx->used_data_len, input_part,
2747            input_part_len - remaining);
2748 
2749     /* Decrypt data using remote token. */
2750     rc = icsf_secret_key_decrypt(session_state->ld, &reason,
2751                                  &mapping->icsf_object,
2752                                  &decr_ctx->mech, chaining,
2753                                  buffer, total - remaining,
2754                                  (char *)output_part, p_output_part_len,
2755                                  chain_data, &chain_data_len);
2756     if (rc) {
2757         if (reason == ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT) {
2758             if (is_length_only) {
2759                 /*
2760                  * Parameter too short is not a problem when
2761                  * querying the expect output size.
2762                  */
2763                 rc = CKR_OK;
2764             } else {
2765                 TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL));
2766                 rc = CKR_BUFFER_TOO_SMALL;
2767             }
2768         } else {
2769             TRACE_DEVEL("Failed to decrypt data. reason = %d\n", reason);
2770             rc = icsf_to_ock_err(rc, reason);
2771         }
2772         goto done;
2773     }
2774 
2775     /* If this is the first block sent for multi-part set the context_len */
2776     if (!multi_part_ctx->initiated)
2777         decr_ctx->context_len = sizeof(*multi_part_ctx);
2778 
2779     /*
2780      * When blocks are sent it's necessary to keep the chain data returned
2781      * to be used in a subsequent call.
2782      */
2783     if (!is_length_only) {
2784         /* Copy chain data into context */
2785         memcpy(multi_part_ctx->chain_data, chain_data, chain_data_len);
2786 
2787         /* Mark multi-part operation as initiated */
2788         multi_part_ctx->initiated = TRUE;
2789 
2790         /* Mark multi-part operation in decr_ctx in session */
2791         decr_ctx->multi = TRUE;
2792 
2793         /* Data stored in cache was used */
2794         multi_part_ctx->used_data_len = 0;
2795     }
2796 
2797 keep_remaining_data:
2798     /* Keep the remaining data to a next call */
2799     if (!is_length_only) {
2800         /* Copy remaining part of input_part into context */
2801         if (total < multi_part_ctx->data_len ||
2802             (padding && total == multi_part_ctx->data_len)) {
2803             memcpy(multi_part_ctx->data +
2804                    multi_part_ctx->used_data_len, input_part, input_part_len);
2805         } else {
2806             memcpy(multi_part_ctx->data,
2807                    input_part + input_part_len - remaining, remaining);
2808         }
2809         multi_part_ctx->used_data_len = remaining;
2810     }
2811 
2812 done:
2813     /* Free resources */
2814     if (buffer)
2815         free(buffer);
2816 
2817     if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL)
2818         free_encr_ctx(decr_ctx);
2819 
2820     return rc;
2821 }
2822 
2823 /*
2824  * Finalize a multi-part decryption.
2825  */
icsftok_decrypt_final(SESSION * session,CK_BYTE_PTR output_part,CK_ULONG_PTR p_output_part_len)2826 CK_RV icsftok_decrypt_final(SESSION * session, CK_BYTE_PTR output_part,
2827                             CK_ULONG_PTR p_output_part_len)
2828 {
2829     CK_RV rc = CKR_OK;
2830     CK_BBOOL is_length_only = (output_part == NULL);
2831     ENCR_DECR_CONTEXT *decr_ctx = &session->decr_ctx;
2832     struct icsf_multi_part_context *multi_part_ctx;
2833     struct session_state *session_state;
2834     struct icsf_object_mapping *mapping;
2835     char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, };
2836     size_t chain_data_len = sizeof(chain_data);
2837     int chaining;
2838     int reason = 0;
2839     int symmetric = 0;
2840 
2841     /* Multi-part is not supported for asymmetric algorithms. */
2842     if ((rc = get_crypt_type(&decr_ctx->mech, &symmetric)))
2843         goto done;
2844     if (!symmetric) {
2845         TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
2846         rc = CKR_MECHANISM_INVALID;
2847         goto done;
2848     }
2849 
2850     /* Check session */
2851     if (!(session_state = get_session_state(session->handle))) {
2852         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
2853         rc = CKR_SESSION_HANDLE_INVALID;
2854         goto done;
2855     }
2856 
2857     /* check ldap handle */
2858     if (session_state->ld == NULL) {
2859         TRACE_ERROR("No LDAP handle.\n");
2860         rc = CKR_FUNCTION_FAILED;
2861         goto done;
2862     }
2863 
2864     /* Check if key exists */
2865     if (!(mapping = bt_get_node_value(&objects, decr_ctx->key))) {
2866         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
2867         rc = CKR_KEY_HANDLE_INVALID;
2868         goto done;
2869     }
2870 
2871     /* Define the type of the call */
2872     multi_part_ctx = (struct icsf_multi_part_context *) decr_ctx->context;
2873     switch (decr_ctx->mech.mechanism) {
2874     case CKM_AES_ECB:
2875     case CKM_DES_ECB:
2876     case CKM_DES3_ECB:
2877         /*
2878          * When not using a chained algorithm and there's no remaining
2879          * data, don't call ICSF.
2880          */
2881         *p_output_part_len = 0;
2882         if (!multi_part_ctx->used_data_len)
2883             goto done;
2884 
2885         /* ICSF just support the chaining mode ONLY for ECB. */
2886         chaining = ICSF_CHAINING_ONLY;
2887         break;
2888     default:
2889         if (multi_part_ctx->initiated) {
2890             chaining = ICSF_CHAINING_FINAL;
2891             memcpy(chain_data, multi_part_ctx->chain_data, chain_data_len);
2892         } else {
2893             chaining = ICSF_CHAINING_ONLY;
2894         }
2895     }
2896 
2897     /*
2898      * Decrypt data using remote token.
2899      *
2900      * All the data in multi-part context should be sent.
2901      */
2902     rc = icsf_secret_key_decrypt(session_state->ld, &reason,
2903                                  &mapping->icsf_object,
2904                                  &decr_ctx->mech, chaining,
2905                                  multi_part_ctx->data,
2906                                  multi_part_ctx->used_data_len,
2907                                  (char *)output_part, p_output_part_len,
2908                                  chain_data, &chain_data_len);
2909     if (rc) {
2910         if (reason == ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT) {
2911             if (is_length_only) {
2912                 /*
2913                  * Parameter too short is not a problem when
2914                  * querying the expect output size.
2915                  */
2916                 rc = CKR_OK;
2917             } else {
2918                 TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL));
2919                 rc = CKR_BUFFER_TOO_SMALL;
2920             }
2921         } else {
2922             TRACE_DEVEL("Failed to decrypt data. reason = %d\n", reason);
2923             rc = icsf_to_ock_err(rc, reason);
2924         }
2925         goto done;
2926     }
2927 
2928 done:
2929     if ((is_length_only && rc != CKR_OK) ||
2930         (!is_length_only && rc != CKR_BUFFER_TOO_SMALL))
2931         free_encr_ctx(decr_ctx);
2932 
2933     return rc;
2934 }
2935 
2936 /*
2937  * Get the attribute values for a list of attributes.
2938  */
icsftok_get_attribute_value(SESSION * sess,CK_OBJECT_HANDLE handle,CK_ATTRIBUTE * pTemplate,CK_ULONG ulCount,CK_ULONG * obj_size)2939 CK_RV icsftok_get_attribute_value(SESSION * sess, CK_OBJECT_HANDLE handle,
2940                                   CK_ATTRIBUTE * pTemplate, CK_ULONG ulCount,
2941                                   CK_ULONG * obj_size)
2942 {
2943     CK_RV rc = CKR_OK;
2944     CK_BBOOL priv_obj;
2945     struct session_state *session_state;
2946     struct icsf_object_mapping *mapping = NULL;
2947     int reason = 0;
2948 
2949     CK_ATTRIBUTE priv_attr[] = {
2950         {CKA_PRIVATE, &priv_obj, sizeof(priv_obj)}
2951         ,
2952     };
2953 
2954     /* Get session state */
2955     if (!(session_state = get_session_state(sess->handle))) {
2956         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
2957         return CKR_SESSION_HANDLE_INVALID;
2958     }
2959 
2960     /* check ldap handle */
2961     if (session_state->ld == NULL) {
2962         TRACE_ERROR("No LDAP handle.\n");
2963         return CKR_FUNCTION_FAILED;
2964     }
2965 
2966     /* get the object handle */
2967     mapping = bt_get_node_value(&objects, handle);
2968 
2969     if (!mapping) {
2970         TRACE_ERROR("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID));
2971         rc = CKR_OBJECT_HANDLE_INVALID;
2972         goto done;
2973     }
2974 
2975     /* get the private attribute so we can check the permissions */
2976     rc = icsf_get_attribute(session_state->ld, &reason,
2977                             &mapping->icsf_object, priv_attr, 1);
2978     if (rc != CKR_OK) {
2979         TRACE_DEVEL("icsf_get_attribute failed\n");
2980         rc = icsf_to_ock_err(rc, reason);
2981         goto done;
2982     }
2983 
2984     if (priv_obj == TRUE) {
2985         if (sess->session_info.state == CKS_RO_PUBLIC_SESSION ||
2986             sess->session_info.state == CKS_RW_PUBLIC_SESSION) {
2987             TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN));
2988             rc = CKR_USER_NOT_LOGGED_IN;
2989             goto done;
2990         }
2991     }
2992     // get requested attributes and values if the obj_size ptr is not set
2993     if (!obj_size) {
2994         /* Now call icsf to get the attribute values */
2995         rc = icsf_get_attribute(session_state->ld, &reason,
2996                                 &mapping->icsf_object, pTemplate, ulCount);
2997 
2998         if (rc != CKR_OK) {
2999             TRACE_DEVEL("icsf_get_attribute failed\n");
3000             rc = icsf_to_ock_err(rc, reason);
3001         }
3002     } else {
3003         /* if size is specified get the object size from remote end */
3004         rc = icsf_get_object_size(session_state->ld, &reason,
3005                                   &mapping->icsf_object, ulCount, obj_size);
3006 
3007         if (rc != CKR_OK) {
3008             TRACE_DEVEL("icsf_get_object_size failed\n");
3009             rc = icsf_to_ock_err(rc, reason);
3010         }
3011     }
3012 
3013 done:
3014     return rc;
3015 }
3016 
3017 /*
3018  * Set attribute values for a list of attributes.
3019  */
icsftok_set_attribute_value(SESSION * sess,CK_OBJECT_HANDLE handle,CK_ATTRIBUTE * pTemplate,CK_ULONG ulCount)3020 CK_RV icsftok_set_attribute_value(SESSION * sess, CK_OBJECT_HANDLE handle,
3021                                   CK_ATTRIBUTE * pTemplate, CK_ULONG ulCount)
3022 {
3023     struct session_state *session_state;
3024     struct icsf_object_mapping *mapping = NULL;
3025     CK_BBOOL is_priv;
3026     CK_BBOOL is_token;
3027     CK_RV rc = CKR_OK;
3028     int reason = 0;
3029 
3030     CK_ATTRIBUTE priv_attrs[] = {
3031         {CKA_PRIVATE, &is_priv, sizeof(is_priv)}
3032         ,
3033         {CKA_TOKEN, &is_token, sizeof(is_token)}
3034         ,
3035     };
3036 
3037     /* Get session state */
3038     if (!(session_state = get_session_state(sess->handle))) {
3039         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
3040         return CKR_SESSION_HANDLE_INVALID;
3041     }
3042 
3043     /* check ldap handle */
3044     if (session_state->ld == NULL) {
3045         TRACE_ERROR("No LDAP handle.\n");
3046         return CKR_FUNCTION_FAILED;
3047     }
3048 
3049     /* get the object handle */
3050     mapping = bt_get_node_value(&objects, handle);
3051 
3052     if (!mapping) {
3053         TRACE_ERROR("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID));
3054         rc = CKR_OBJECT_HANDLE_INVALID;
3055         goto done;
3056     }
3057 
3058     /* check permissions :
3059      * first get CKA_PRIVATE since we need to check againse session
3060      * icsf will check if the attributes are modifiable
3061      */
3062     rc = icsf_get_attribute(session_state->ld, &reason,
3063                             &mapping->icsf_object, priv_attrs, 2);
3064     if (rc != CKR_OK) {
3065         TRACE_DEVEL("icsf_get_attribute failed\n");
3066         rc = icsf_to_ock_err(rc, reason);
3067         goto done;
3068     }
3069 
3070     /* Check permissions based on attributes and session */
3071     rc = check_session_permissions(sess, priv_attrs, 2);
3072     if (rc != CKR_OK) {
3073         TRACE_DEVEL("check_session_permissions failed\n");
3074         goto done;
3075     }
3076 
3077     /* Now call into icsf to set the attribute values */
3078     rc = icsf_set_attribute(session_state->ld, &reason,
3079                             &mapping->icsf_object, pTemplate, ulCount);
3080     if (rc != CKR_OK) {
3081         TRACE_ERROR("icsf_set_attribute failed\n");
3082         rc = icsf_to_ock_err(rc, reason);
3083         goto done;
3084     }
3085 
3086 done:
3087     return rc;
3088 }
3089 
3090 /*
3091  * Initialize a search for token and session objects that match a template.
3092  */
icsftok_find_objects_init(STDLL_TokData_t * tokdata,SESSION * sess,CK_ATTRIBUTE * pTemplate,CK_ULONG ulCount)3093 CK_RV icsftok_find_objects_init(STDLL_TokData_t * tokdata, SESSION * sess,
3094                                 CK_ATTRIBUTE * pTemplate, CK_ULONG ulCount)
3095 {
3096     char token_name[sizeof(tokdata->nv_token_data->token_info.label)];
3097     struct session_state *session_state;
3098     struct icsf_object_record records[MAX_RECORDS];
3099     struct icsf_object_record *previous = NULL;
3100     size_t records_len;
3101     unsigned int i, j;
3102     int node_number, rc;
3103     int reason = 0;
3104     CK_RV rv = CKR_OK;
3105 
3106     /* Whether we retrieve public or private objects is determined by
3107      * the caller's SAF authority on the token, something ock doesn't
3108      * control.
3109      * Since an app MUST have authenticated to ICSF token to use it,
3110      * we can always assume it is an authenticated session and anything else
3111      * is an error.
3112      */
3113     if (sess->session_info.state == CKS_RO_PUBLIC_SESSION ||
3114         sess->session_info.state == CKS_RW_PUBLIC_SESSION ||
3115         sess->session_info.state == CKS_RW_SO_FUNCTIONS) {
3116         TRACE_ERROR("You must authenticate to access ICSF token.\n");
3117         return CKR_FUNCTION_FAILED;
3118     }
3119 
3120     /* Initialize the found object list. In keeping with other tokens,
3121      * if the list does not exist, allocate list big enough for MAX_RECORD
3122      * handles. reallocate later if more needed.
3123      */
3124     if (sess->find_list == NULL) {
3125         sess->find_list =
3126             (CK_OBJECT_HANDLE *) malloc(10 * sizeof(CK_OBJECT_HANDLE));
3127         if (!sess->find_list) {
3128             TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
3129             return CKR_HOST_MEMORY;
3130         }
3131         sess->find_len = 10;
3132     }
3133     memset(sess->find_list, 0x0, sess->find_len * sizeof(CK_OBJECT_HANDLE));
3134     sess->find_count = 0;
3135     sess->find_idx = 0;
3136 
3137     /* Prepare to query ICSF for list objects
3138      * Copy token name from shared memory
3139      */
3140     rc = XProcLock(tokdata);
3141     if (rc != CKR_OK) {
3142         TRACE_ERROR("Failed to get process lock.\n");
3143         return rc;
3144     }
3145 
3146     memcpy(token_name, tokdata->nv_token_data->token_info.label,
3147            sizeof(token_name));
3148 
3149     rc = XProcUnLock(tokdata);
3150     if (rc != CKR_OK) {
3151         TRACE_ERROR("Failed to release process lock.\n");
3152         return rc;
3153     }
3154 
3155     /* Get session state */
3156     if (!(session_state = get_session_state(sess->handle))) {
3157         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
3158         return CKR_SESSION_HANDLE_INVALID;
3159     }
3160 
3161     /* check ldap handle */
3162     if (session_state->ld == NULL) {
3163         TRACE_ERROR("No LDAP handle.\n");
3164         return CKR_FUNCTION_FAILED;
3165     }
3166 
3167     /* clear out records */
3168     memset(records, 0, MAX_RECORDS * (sizeof(struct icsf_object_record)));
3169 
3170     do {
3171         records_len = sizeof(records) / sizeof(struct icsf_object_record);
3172         rc = icsf_list_objects(session_state->ld, &reason, token_name,
3173                                ulCount, pTemplate, previous, records,
3174                                &records_len, 0);
3175         if (ICSF_RC_IS_ERROR(rc)) {
3176             TRACE_DEVEL("Failed to list objects.\n");
3177             rv = icsf_to_ock_err(rc, reason);
3178             goto done;
3179         }
3180 
3181         /* Now step thru the object btree so we can find the node
3182          * value for any matching objects we retrieved from ICSF.
3183          * If we cannot find a matching object in the btree,
3184          * then add it so we can get a node value.
3185          * And also because ICSF object database is authoritative.
3186          */
3187 
3188         for (i = 0; i < records_len; i++) {
3189 
3190             /* mark not found */
3191             node_number = 0;
3192 
3193             for (j = 1; j <= objects.size; j++) {
3194                 struct icsf_object_mapping *mapping = NULL;
3195 
3196                 /* skip missing ids */
3197                 mapping = bt_get_node_value(&objects, j);
3198                 if (mapping) {
3199                     if (memcmp(&records[i],
3200                                &mapping->icsf_object,
3201                                sizeof(struct icsf_object_record)) == 0) {
3202                         node_number = j;
3203                         break;
3204                     }
3205                 } else {
3206                     continue;
3207                 }
3208             }
3209             /* if could not find in our object tree, then add it
3210              * since ICSF object database is authoritative.
3211              */
3212             if (!node_number) {
3213                 struct icsf_object_mapping *new_mapping;
3214 
3215                 if (!(new_mapping = malloc(sizeof(*new_mapping)))) {
3216                     TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
3217                     rv = CKR_HOST_MEMORY;
3218                     goto done;
3219                 }
3220                 new_mapping->session_id = sess->handle;
3221                 new_mapping->icsf_object = records[i];
3222 
3223                 if (!(node_number = bt_node_add(&objects, new_mapping))) {
3224                     TRACE_ERROR("Failed to add object to " "binary tree.\n");
3225                     rv = CKR_FUNCTION_FAILED;
3226                     goto done;
3227                 }
3228             }
3229 
3230             /* Add to our findobject list */
3231             if (node_number) {
3232                 sess->find_list[sess->find_count] = node_number;
3233                 sess->find_count++;
3234 
3235                 if (sess->find_count >= sess->find_len) {
3236                     void *find_list;
3237                     size_t find_len = sess->find_len + MAX_RECORDS;
3238                     find_list = realloc(sess->find_list,
3239                                         find_len * sizeof(CK_OBJECT_HANDLE));
3240                     if (!find_list) {
3241                         TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
3242                         rv = CKR_HOST_MEMORY;
3243                         goto done;
3244                     }
3245                     sess->find_list = find_list;
3246                     sess->find_len = find_len;
3247                 }
3248             }
3249         }
3250 
3251         if (records_len)
3252             previous = &records[records_len - 1];
3253     } while (records_len);
3254 
3255     sess->find_active = TRUE;
3256 
3257 done:
3258     return rv;
3259 }
3260 
3261 /*
3262  * Destroy an object.
3263  */
icsftok_destroy_object(STDLL_TokData_t * tokdata,SESSION * sess,CK_OBJECT_HANDLE handle)3264 CK_RV icsftok_destroy_object(STDLL_TokData_t * tokdata, SESSION * sess,
3265                              CK_OBJECT_HANDLE handle)
3266 {
3267     struct session_state *session_state;
3268     struct icsf_object_mapping *mapping = NULL;
3269     int reason;
3270     CK_RV rc = CKR_OK;
3271 
3272     UNUSED(tokdata);
3273 
3274     /* Get session state */
3275     if (!(session_state = get_session_state(sess->handle))) {
3276         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
3277         return CKR_SESSION_HANDLE_INVALID;;
3278     }
3279 
3280     /* check ldap handle */
3281     if (session_state->ld == NULL) {
3282         TRACE_ERROR("No LDAP handle.\n");
3283         return CKR_FUNCTION_FAILED;
3284     }
3285 
3286     /* get the object handle */
3287     mapping = bt_get_node_value(&objects, handle);
3288 
3289     if (!mapping) {
3290         TRACE_ERROR("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID));
3291         rc = CKR_OBJECT_HANDLE_INVALID;
3292         goto done;
3293     }
3294 
3295     /* Now remove the object from ICSF */
3296     rc = icsf_destroy_object(session_state->ld, &reason, &mapping->icsf_object);
3297     if (rc != 0) {
3298         TRACE_DEVEL("icsf_destroy_object failed\n");
3299         rc = CKR_FUNCTION_FAILED;
3300         goto done;
3301     }
3302 
3303     /* Now remove the object from the object btree */
3304     bt_node_free(&objects, handle, free);
3305 
3306 done:
3307     return rc;
3308 }
3309 
3310 /*
3311  * Free all data pointed by SIGN_VERIFY_CONTEXT and set everything to zero.
3312  */
free_sv_ctx(SIGN_VERIFY_CONTEXT * ctx)3313 static void free_sv_ctx(SIGN_VERIFY_CONTEXT * ctx)
3314 {
3315     struct icsf_multi_part_context *multi_part_ctx;
3316 
3317     if (!ctx)
3318         return;
3319 
3320     /* Initialize encryption context */
3321     multi_part_ctx = (struct icsf_multi_part_context *) ctx->context;
3322     if (multi_part_ctx) {
3323         if (multi_part_ctx->data)
3324             free(multi_part_ctx->data);
3325         free(multi_part_ctx);
3326     }
3327     if (ctx->mech.pParameter)
3328         free(ctx->mech.pParameter);
3329 
3330     memset(ctx, 0, sizeof(*ctx));
3331 }
3332 
3333 /*
3334  * get the hash size for hmacs.
3335  */
get_signverify_len(CK_MECHANISM mech)3336 int get_signverify_len(CK_MECHANISM mech)
3337 {
3338     switch (mech.mechanism) {
3339     case CKM_MD5_HMAC:
3340     case CKM_SSL3_MD5_MAC:
3341         return MD5_HASH_SIZE;
3342     case CKM_SHA_1_HMAC:
3343     case CKM_SSL3_SHA1_MAC:
3344         return SHA1_HASH_SIZE;
3345     case CKM_SHA256_HMAC:
3346         return SHA256_HASH_SIZE;
3347     case CKM_SHA384_HMAC:
3348         return SHA384_HASH_SIZE;
3349     case CKM_SHA512_HMAC:
3350         return SHA512_HASH_SIZE;
3351     }
3352 
3353     return -1;
3354 }
3355 
icsftok_sign_init(SESSION * session,CK_MECHANISM * mech,CK_OBJECT_HANDLE key)3356 CK_RV icsftok_sign_init(SESSION * session, CK_MECHANISM * mech,
3357                         CK_OBJECT_HANDLE key)
3358 {
3359     struct session_state *session_state;
3360     SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx;
3361     struct icsf_multi_part_context *multi_part_ctx = NULL;
3362     struct icsf_object_mapping *mapping = NULL;
3363     CK_RV rc = CKR_OK;
3364     CK_BBOOL multi = FALSE;
3365     CK_BBOOL datacaching = FALSE;
3366     CK_MAC_GENERAL_PARAMS *param;
3367 
3368     /* Check session */
3369     if (!(session_state = get_session_state(session->handle))) {
3370         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
3371         return CKR_SESSION_HANDLE_INVALID;
3372     }
3373 
3374     /* Check if key exists */
3375     if (!(mapping = bt_get_node_value(&objects, key))) {
3376         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
3377         rc = CKR_KEY_HANDLE_INVALID;
3378         return rc;
3379     }
3380 
3381     /* Check the mechanism info */
3382     switch (mech->mechanism) {
3383     case CKM_RSA_X_509:
3384     case CKM_RSA_PKCS:
3385     case CKM_DSA:
3386     case CKM_ECDSA:
3387         /* these do not do multipart and do not require
3388          * a mechanism parameter.
3389          */
3390         if (mech->ulParameterLen != 0) {
3391             TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
3392             return CKR_MECHANISM_PARAM_INVALID;
3393         }
3394         multi = FALSE;
3395         break;
3396     case CKM_MD5_HMAC:
3397     case CKM_SHA_1_HMAC:
3398     case CKM_SHA256_HMAC:
3399     case CKM_SHA384_HMAC:
3400     case CKM_SHA512_HMAC:
3401         /* hmacs can do mulitpart and do not require a
3402          *  mechanism parameter.
3403          */
3404         if (mech->ulParameterLen != 0) {
3405             TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
3406             return CKR_MECHANISM_PARAM_INVALID;
3407         }
3408         multi = TRUE;
3409         break;
3410     case CKM_SSL3_MD5_MAC:
3411     case CKM_SSL3_SHA1_MAC:
3412         /* can do mulitpart and take a mech parameter */
3413 
3414         param = (CK_MAC_GENERAL_PARAMS *) mech->pParameter;
3415 
3416         if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) {
3417             TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
3418             return CKR_MECHANISM_PARAM_INVALID;
3419         }
3420         if (((mech->mechanism == CKM_SSL3_MD5_MAC) && (*param != 16)) ||
3421             ((mech->mechanism == CKM_SSL3_SHA1_MAC) && (*param != 20))) {
3422             TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
3423             return CKR_MECHANISM_PARAM_INVALID;
3424         }
3425 
3426         multi = TRUE;
3427         break;
3428     case CKM_MD5_RSA_PKCS:
3429     case CKM_SHA1_RSA_PKCS:
3430     case CKM_SHA256_RSA_PKCS:
3431     case CKM_SHA384_RSA_PKCS:
3432     case CKM_SHA512_RSA_PKCS:
3433     case CKM_DSA_SHA1:
3434     case CKM_ECDSA_SHA1:
3435         /* these can do mulitpart and require data caching
3436          * and do not require a mechanism parameter.
3437          */
3438         if (mech->ulParameterLen != 0) {
3439             TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
3440             return CKR_MECHANISM_PARAM_INVALID;
3441         }
3442         multi = TRUE;
3443         datacaching = TRUE;
3444         break;
3445     default:
3446         TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
3447         return CKR_MECHANISM_INVALID;
3448     }
3449 
3450     /* Initialize sign context */
3451     free_sv_ctx(ctx);
3452 
3453     /* Copy mechanism */
3454     if (mech->pParameter == NULL || mech->ulParameterLen == 0) {
3455         ctx->mech.ulParameterLen = 0;
3456         ctx->mech.pParameter = NULL;
3457     } else {
3458         ctx->mech.pParameter = malloc(mech->ulParameterLen);
3459         if (!ctx->mech.pParameter) {
3460             TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
3461             rc = CKR_HOST_MEMORY;
3462             goto done;
3463         }
3464         ctx->mech.ulParameterLen = mech->ulParameterLen;
3465         memcpy(ctx->mech.pParameter, mech->pParameter, mech->ulParameterLen);
3466     }
3467     ctx->mech.mechanism = mech->mechanism;
3468 
3469     /* If the mechanism supports multipart, prepare ctx */
3470     if (multi) {
3471         /* Allocate context for multi-part operations */
3472         if (!(multi_part_ctx = malloc(sizeof(*multi_part_ctx)))) {
3473             TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
3474             rc = CKR_HOST_MEMORY;
3475             goto done;
3476         }
3477         ctx->context_len = sizeof(*multi_part_ctx);
3478         ctx->context = (void *) multi_part_ctx;
3479         memset(multi_part_ctx, 0, sizeof(*multi_part_ctx));
3480 
3481         /* keep a cache to ensure multiple of blocksize
3482          * is sent to ICSF.
3483          */
3484 
3485         if (datacaching) {
3486             size_t blocksize;
3487 
3488             rc = icsf_block_size(mech->mechanism, &blocksize);
3489             if (rc != CKR_OK)
3490                 goto done;
3491             multi_part_ctx->data_len = blocksize;
3492             multi_part_ctx->data = malloc(multi_part_ctx->data_len);
3493             if (!multi_part_ctx->data) {
3494                 TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
3495                 rc = CKR_HOST_MEMORY;
3496                 goto done;
3497             }
3498             memset(multi_part_ctx->data, 0, blocksize);
3499         }
3500     } else {
3501         ctx->context_len = 0;
3502         ctx->context = NULL;
3503     }
3504 
3505     ctx->key = key;
3506     ctx->multi = FALSE;
3507     ctx->active = TRUE;
3508 
3509 done:
3510     if (rc != CKR_OK)
3511         free_sv_ctx(ctx);
3512 
3513     return rc;
3514 }
3515 
icsftok_sign(SESSION * session,CK_BYTE * in_data,CK_ULONG in_data_len,CK_BYTE * signature,CK_ULONG * sig_len)3516 CK_RV icsftok_sign(SESSION * session, CK_BYTE * in_data, CK_ULONG in_data_len,
3517                    CK_BYTE * signature, CK_ULONG * sig_len)
3518 {
3519     struct session_state *session_state;
3520     SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx;
3521     struct icsf_object_mapping *mapping = NULL;
3522     char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, };
3523     size_t chain_data_len = sizeof(chain_data);
3524     CK_RV rc = CKR_OK;
3525     int hlen, reason;
3526     CK_BBOOL length_only = (signature == NULL);
3527 
3528     if (ctx->multi == TRUE) {
3529         TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE));
3530         rc = CKR_OPERATION_ACTIVE;
3531         goto done;
3532     }
3533 
3534     /* Check session */
3535     if (!(session_state = get_session_state(session->handle))) {
3536         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
3537         rc = CKR_SESSION_HANDLE_INVALID;
3538         goto done;
3539     }
3540 
3541     /* check ldap handle */
3542     if (session_state->ld == NULL) {
3543         TRACE_ERROR("No LDAP handle.\n");
3544         rc = CKR_FUNCTION_FAILED;
3545         goto done;
3546     }
3547 
3548     /* Check if key exists */
3549     if (!(mapping = bt_get_node_value(&objects, ctx->key))) {
3550         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
3551         rc = CKR_KEY_HANDLE_INVALID;
3552         goto done;
3553     }
3554 
3555     switch (ctx->mech.mechanism) {
3556     case CKM_MD5_HMAC:
3557     case CKM_SHA_1_HMAC:
3558     case CKM_SHA256_HMAC:
3559     case CKM_SHA384_HMAC:
3560     case CKM_SHA512_HMAC:
3561     case CKM_SSL3_MD5_MAC:
3562     case CKM_SSL3_SHA1_MAC:
3563         if (length_only) {
3564             hlen = get_signverify_len(ctx->mech);
3565             if (hlen < 0) {
3566                 TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
3567                 rc = CKR_MECHANISM_INVALID;
3568                 goto done;
3569             }
3570             *sig_len = hlen;
3571             rc = CKR_OK;
3572             goto done;
3573         }
3574 
3575         rc = icsf_hmac_sign(session_state->ld, &reason,
3576                             &mapping->icsf_object, &ctx->mech, "ONLY",
3577                             (char *)in_data, in_data_len,
3578                             (char *)signature, sig_len,
3579                             chain_data, &chain_data_len);
3580         if (rc != 0)
3581             rc = icsf_to_ock_err(rc, reason);
3582         break;
3583     case CKM_RSA_X_509:
3584     case CKM_RSA_PKCS:
3585     case CKM_DSA:
3586     case CKM_ECDSA:
3587         rc = icsf_private_key_sign(session_state->ld, &reason, FALSE,
3588                                    &mapping->icsf_object, &ctx->mech,
3589                                    (char *)in_data, in_data_len,
3590                                    (char *)signature, sig_len);
3591         if (rc != 0) {
3592             if (reason == ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT &&
3593                 length_only) {
3594                 rc = CKR_OK;
3595             } else {
3596                 TRACE_DEVEL("icsf_private_key_sign failed\n");
3597                 rc = icsf_to_ock_err(rc, reason);
3598             }
3599         }
3600         break;
3601     case CKM_MD5_RSA_PKCS:
3602     case CKM_SHA1_RSA_PKCS:
3603     case CKM_SHA256_RSA_PKCS:
3604     case CKM_SHA384_RSA_PKCS:
3605     case CKM_SHA512_RSA_PKCS:
3606     case CKM_DSA_SHA1:
3607     case CKM_ECDSA_SHA1:
3608         if (length_only) {
3609             rc = CKR_OK;
3610             goto done;
3611         }
3612 
3613         rc = icsf_hash_signverify(session_state->ld, &reason,
3614                                   &mapping->icsf_object, &ctx->mech,
3615                                   "ONLY", (char *)in_data, in_data_len,
3616                                   (char *)signature, sig_len,
3617                                   chain_data, &chain_data_len, 0);
3618         if (rc != 0) {
3619             if (reason == ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT &&
3620                 length_only) {
3621                 rc = CKR_OK;
3622             } else {
3623                 TRACE_DEVEL("icsf_hash_signverify failed\n");
3624                 rc = icsf_to_ock_err(rc, reason);
3625             }
3626         }
3627         break;
3628     default:
3629         TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
3630         rc = CKR_MECHANISM_INVALID;
3631     }
3632 
3633 done:
3634     if (rc != CKR_BUFFER_TOO_SMALL && !(rc == CKR_OK && length_only))
3635         free_sv_ctx(ctx);
3636 
3637     return rc;
3638 }
3639 
icsftok_sign_update(SESSION * session,CK_BYTE * in_data,CK_ULONG in_data_len)3640 CK_RV icsftok_sign_update(SESSION * session, CK_BYTE * in_data,
3641                           CK_ULONG in_data_len)
3642 {
3643     struct session_state *session_state;
3644     SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx;
3645     struct icsf_object_mapping *mapping = NULL;
3646     struct icsf_multi_part_context *multi_part_ctx = NULL;
3647     char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, };
3648     size_t chain_data_len = sizeof(chain_data);
3649     CK_RV rc = CKR_OK;
3650     int reason;
3651     size_t siglen = 0;
3652     CK_ULONG total, remain, out_len = 0;
3653     char *buffer = NULL;
3654 
3655     /* Check session */
3656     if (!(session_state = get_session_state(session->handle))) {
3657         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
3658         rc = CKR_SESSION_HANDLE_INVALID;
3659         goto done;
3660     }
3661 
3662     /* check ldap handle */
3663     if (session_state->ld == NULL) {
3664         TRACE_ERROR("No LDAP handle.\n");
3665         rc = CKR_FUNCTION_FAILED;
3666         goto done;
3667     }
3668 
3669     /* Check if key exists */
3670     if (!(mapping = bt_get_node_value(&objects, ctx->key))) {
3671         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
3672         rc = CKR_KEY_HANDLE_INVALID;
3673         goto done;
3674     }
3675 
3676     /* indicate this is multipart operation and get chain info from ctx.
3677      * if any mechanisms that cannot do multipart sign come here, they
3678      * will not have had ctx->context allocated and will
3679      * get an error in switch below.
3680      */
3681     ctx->multi = TRUE;
3682     if (ctx->context) {
3683         multi_part_ctx = (struct icsf_multi_part_context *) ctx->context;
3684         if (multi_part_ctx->initiated)
3685             memcpy(chain_data, multi_part_ctx->chain_data, chain_data_len);
3686     } else {
3687         TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD));
3688         rc = ERR_ARGUMENTS_BAD;
3689         goto done;
3690     }
3691 
3692     switch (ctx->mech.mechanism) {
3693     case CKM_MD5_HMAC:
3694     case CKM_SHA_1_HMAC:
3695     case CKM_SHA256_HMAC:
3696     case CKM_SHA384_HMAC:
3697     case CKM_SHA512_HMAC:
3698     case CKM_SSL3_MD5_MAC:
3699     case CKM_SSL3_SHA1_MAC:
3700         rc = icsf_hmac_sign(session_state->ld, &reason,
3701                             &mapping->icsf_object, &ctx->mech,
3702                             (multi_part_ctx->initiated) ? "MIDDLE" : "FIRST",
3703                             (char *)in_data, in_data_len, NULL, &siglen,
3704                             chain_data, &chain_data_len);
3705 
3706         if (rc != 0) {
3707             TRACE_DEVEL("icsf_hmac_sign failed\n");
3708             rc = icsf_to_ock_err(rc, reason);
3709         } else {
3710             multi_part_ctx->initiated = TRUE;
3711             memcpy(multi_part_ctx->chain_data, chain_data, chain_data_len);
3712         }
3713         break;
3714     case CKM_MD5_RSA_PKCS:
3715     case CKM_SHA1_RSA_PKCS:
3716     case CKM_SHA256_RSA_PKCS:
3717     case CKM_SHA384_RSA_PKCS:
3718     case CKM_SHA512_RSA_PKCS:
3719     case CKM_DSA_SHA1:
3720     case CKM_ECDSA_SHA1:
3721         /* caching data since ICSF wants in multiple of blocksize */
3722         if (multi_part_ctx && multi_part_ctx->data) {
3723 
3724             total = multi_part_ctx->used_data_len + in_data_len;
3725             remain = total % multi_part_ctx->data_len;;
3726 
3727             /* if not enough to meet blocksize, cache and exit. */
3728             if (total < multi_part_ctx->data_len) {
3729                 memcpy(multi_part_ctx->data + multi_part_ctx->used_data_len,
3730                        (char *)in_data, in_data_len);
3731                 multi_part_ctx->used_data_len += in_data_len;
3732 
3733                 rc = CKR_OK;
3734                 goto done;
3735             } else {
3736                 /* there is at least 1 block */
3737 
3738                 out_len = total - remain;
3739 
3740                 /* prepare a buffer to send data in */
3741                 if (!(buffer = malloc(out_len))) {
3742                     TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
3743                     rc = CKR_HOST_MEMORY;
3744                     goto done;
3745                 }
3746                 memcpy(buffer, multi_part_ctx->data,
3747                        multi_part_ctx->used_data_len);
3748                 memcpy(buffer + multi_part_ctx->used_data_len,
3749                        (char *)in_data,
3750                        out_len - multi_part_ctx->used_data_len);
3751 
3752                 /* copy remainder of data to ctx
3753                  * for next time. caching.
3754                  */
3755                 if (remain != 0)
3756                     memcpy(multi_part_ctx->data,
3757                            in_data + (in_data_len - remain), remain);
3758 
3759                 multi_part_ctx->used_data_len = remain;
3760             }
3761         }
3762 
3763         rc = icsf_hash_signverify(session_state->ld, &reason,
3764                                   &mapping->icsf_object, &ctx->mech,
3765                                   (multi_part_ctx->
3766                                    initiated) ? "MIDDLE" : "FIRST", buffer,
3767                                   out_len, NULL, NULL, chain_data,
3768                                   &chain_data_len, 0);
3769 
3770         if (rc != 0) {
3771             TRACE_DEVEL("icsf_hash_signverify failed\n");
3772             rc = icsf_to_ock_err(rc, reason);
3773         } else {
3774             multi_part_ctx->initiated = TRUE;
3775             memcpy(multi_part_ctx->chain_data, chain_data, chain_data_len);
3776         }
3777 
3778         if (buffer)
3779             free(buffer);
3780 
3781         break;
3782     default:
3783         TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
3784         rc = CKR_MECHANISM_INVALID;
3785     }
3786 
3787 done:
3788     if (rc != CKR_OK)
3789         free_sv_ctx(ctx);
3790 
3791     return rc;
3792 }
3793 
icsftok_sign_final(SESSION * session,CK_BYTE * signature,CK_ULONG * sig_len)3794 CK_RV icsftok_sign_final(SESSION * session, CK_BYTE * signature,
3795                          CK_ULONG * sig_len)
3796 {
3797     struct session_state *session_state;
3798     SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx;
3799     struct icsf_object_mapping *mapping = NULL;
3800     struct icsf_multi_part_context *multi_part_ctx = NULL;
3801     char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, };
3802     size_t chain_data_len = sizeof(chain_data);
3803     char *buffer = NULL;
3804     CK_RV rc = CKR_OK;
3805     int hlen, reason;
3806     CK_BBOOL length_only = (signature == NULL);
3807 
3808     /* Check session */
3809     if (!(session_state = get_session_state(session->handle))) {
3810         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
3811         rc = CKR_SESSION_HANDLE_INVALID;
3812         goto done;
3813     }
3814 
3815     /* check ldap handle */
3816     if (session_state->ld == NULL) {
3817         TRACE_ERROR("No LDAP handle.\n");
3818         rc = CKR_FUNCTION_FAILED;
3819         goto done;
3820     }
3821 
3822     /* Check if key exists */
3823     if (!(mapping = bt_get_node_value(&objects, ctx->key))) {
3824         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
3825         rc = CKR_KEY_HANDLE_INVALID;
3826         goto done;
3827     }
3828 
3829     /* get the chain data from ctx */
3830     if (ctx->context) {
3831         multi_part_ctx = (struct icsf_multi_part_context *) ctx->context;
3832         memcpy(chain_data, multi_part_ctx->chain_data, chain_data_len);
3833     } else {
3834         TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD));
3835         rc = ERR_ARGUMENTS_BAD;
3836         goto done;
3837     }
3838 
3839     switch (ctx->mech.mechanism) {
3840     case CKM_MD5_HMAC:
3841     case CKM_SHA_1_HMAC:
3842     case CKM_SHA256_HMAC:
3843     case CKM_SHA384_HMAC:
3844     case CKM_SHA512_HMAC:
3845     case CKM_SSL3_MD5_MAC:
3846     case CKM_SSL3_SHA1_MAC:
3847         if (length_only) {
3848             hlen = get_signverify_len(ctx->mech);
3849             if (hlen < 0) {
3850                 TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
3851                 return CKR_MECHANISM_INVALID;
3852             }
3853 
3854             *sig_len = hlen;
3855             return CKR_OK;
3856         }
3857 
3858         rc = icsf_hmac_sign(session_state->ld, &reason,
3859                             &mapping->icsf_object, &ctx->mech,
3860                             multi_part_ctx->initiated ? "LAST" : "ONLY", "",
3861                             0, (char *)signature, sig_len,
3862                             chain_data, &chain_data_len);
3863         if (rc != 0)
3864             rc = icsf_to_ock_err(rc, reason);
3865         break;
3866     case CKM_MD5_RSA_PKCS:
3867     case CKM_SHA1_RSA_PKCS:
3868     case CKM_SHA256_RSA_PKCS:
3869     case CKM_SHA384_RSA_PKCS:
3870     case CKM_SHA512_RSA_PKCS:
3871     case CKM_DSA_SHA1:
3872     case CKM_ECDSA_SHA1:
3873         if (length_only) {
3874             rc = CKR_OK;
3875             goto done;
3876         }
3877 
3878         /* see if any data left in the cache */
3879         if (multi_part_ctx && multi_part_ctx->used_data_len) {
3880             if (!(buffer = malloc(multi_part_ctx->used_data_len))) {
3881                 TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
3882                 rc = CKR_HOST_MEMORY;
3883                 goto done;
3884             }
3885             memcpy(buffer, multi_part_ctx->data, multi_part_ctx->used_data_len);
3886         }
3887 
3888         rc = icsf_hash_signverify(session_state->ld, &reason,
3889                                   &mapping->icsf_object, &ctx->mech,
3890                                   multi_part_ctx->initiated ? "LAST" : "ONLY",
3891                                   (buffer) ? buffer : NULL,
3892                                   multi_part_ctx->used_data_len,
3893                                   (char *)signature, sig_len,
3894                                   chain_data, &chain_data_len, 0);
3895 
3896         if (rc != 0) {
3897             if (length_only && reason == 3003) {
3898                 rc = CKR_OK;
3899             } else {
3900                 TRACE_DEVEL("icsf_hash_signverify failed\n");
3901                 rc = icsf_to_ock_err(rc, reason);
3902             }
3903         }
3904 
3905         if (buffer)
3906             free(buffer);
3907         break;
3908     default:
3909         TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
3910         rc = CKR_MECHANISM_INVALID;
3911     }
3912 
3913 done:
3914     if (rc != CKR_BUFFER_TOO_SMALL && !(rc == CKR_OK && length_only))
3915         free_sv_ctx(ctx);
3916 
3917     return rc;
3918 }
3919 
icsftok_verify_init(SESSION * session,CK_MECHANISM * mech,CK_OBJECT_HANDLE key)3920 CK_RV icsftok_verify_init(SESSION * session, CK_MECHANISM * mech,
3921                           CK_OBJECT_HANDLE key)
3922 {
3923     struct session_state *session_state;
3924     SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx;
3925     struct icsf_multi_part_context *multi_part_ctx = NULL;
3926     struct icsf_object_mapping *mapping = NULL;
3927     CK_RV rc = CKR_OK;
3928     CK_BBOOL multi = FALSE;
3929     CK_BBOOL datacaching = FALSE;
3930     CK_MAC_GENERAL_PARAMS *param;
3931 
3932     /* Check session */
3933     if (!(session_state = get_session_state(session->handle))) {
3934         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
3935         return CKR_SESSION_HANDLE_INVALID;
3936     }
3937 
3938     /* Check if key exists */
3939     if (!(mapping = bt_get_node_value(&objects, key))) {
3940         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
3941         rc = CKR_KEY_HANDLE_INVALID;
3942         return rc;
3943     }
3944 
3945     /* Check the mechanism info */
3946     switch (mech->mechanism) {
3947     case CKM_RSA_X_509:
3948     case CKM_RSA_PKCS:
3949     case CKM_DSA:
3950     case CKM_ECDSA:
3951         /* these do not do multipart and do not require
3952          * a mechanism parameter.
3953          */
3954         if (mech->ulParameterLen != 0) {
3955             TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
3956             return CKR_MECHANISM_PARAM_INVALID;
3957         }
3958         multi = FALSE;
3959         break;
3960     case CKM_MD5_HMAC:
3961     case CKM_SHA_1_HMAC:
3962     case CKM_SHA256_HMAC:
3963     case CKM_SHA384_HMAC:
3964     case CKM_SHA512_HMAC:
3965         /* hmacs can do mulitpart and do not require a
3966          *  mechanism parameter.
3967          */
3968         if (mech->ulParameterLen != 0) {
3969             TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
3970             return CKR_MECHANISM_PARAM_INVALID;
3971         }
3972         multi = TRUE;
3973         break;
3974     case CKM_SSL3_MD5_MAC:
3975     case CKM_SSL3_SHA1_MAC:
3976         /* can do mulitpart and take a mech parameter */
3977         param = (CK_MAC_GENERAL_PARAMS *) mech->pParameter;
3978 
3979         if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) {
3980             TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
3981             return CKR_MECHANISM_PARAM_INVALID;
3982         }
3983         if (((mech->mechanism == CKM_SSL3_MD5_MAC) && (*param != 16)) ||
3984             ((mech->mechanism == CKM_SSL3_SHA1_MAC) && (*param != 20))) {
3985             TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
3986             return CKR_MECHANISM_PARAM_INVALID;
3987         }
3988 
3989         multi = TRUE;
3990         break;
3991     case CKM_MD5_RSA_PKCS:
3992     case CKM_SHA1_RSA_PKCS:
3993     case CKM_SHA256_RSA_PKCS:
3994     case CKM_SHA384_RSA_PKCS:
3995     case CKM_SHA512_RSA_PKCS:
3996     case CKM_DSA_SHA1:
3997     case CKM_ECDSA_SHA1:
3998         /* these can do mulitpart and require data caching
3999          * but do not require a mechanism parameter
4000          */
4001         if (mech->ulParameterLen != 0) {
4002             TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
4003             return CKR_MECHANISM_PARAM_INVALID;
4004         }
4005         multi = TRUE;
4006         datacaching = TRUE;
4007         break;
4008     default:
4009         TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
4010         return CKR_MECHANISM_INVALID;
4011     }
4012 
4013     /* Initialize ctx */
4014     free_sv_ctx(ctx);
4015 
4016     /* Copy mechanism */
4017     if (mech->pParameter == NULL || mech->ulParameterLen == 0) {
4018         ctx->mech.ulParameterLen = 0;
4019         ctx->mech.pParameter = NULL;
4020     } else {
4021         ctx->mech.pParameter = malloc(mech->ulParameterLen);
4022         if (!ctx->mech.pParameter) {
4023             TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
4024             rc = CKR_HOST_MEMORY;
4025             goto done;
4026         }
4027         ctx->mech.ulParameterLen = mech->ulParameterLen;
4028         memcpy(ctx->mech.pParameter, mech->pParameter, mech->ulParameterLen);
4029     }
4030     ctx->mech.mechanism = mech->mechanism;
4031 
4032     /* If the mechanism supports multipart, prepare ctx */
4033     if (multi) {
4034         /* Allocate context for multi-part operations */
4035         if (!(multi_part_ctx = malloc(sizeof(*multi_part_ctx)))) {
4036             TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
4037             rc = CKR_HOST_MEMORY;
4038             goto done;
4039         }
4040         ctx->context_len = sizeof(*multi_part_ctx);
4041         ctx->context = (void *) multi_part_ctx;
4042         memset(multi_part_ctx, 0, sizeof(*multi_part_ctx));
4043 
4044         /* keep a cache to ensure multiple of blocksize
4045          * is sent to ICSF.
4046          */
4047 
4048         if (datacaching) {
4049             size_t blocksize;
4050 
4051             rc = icsf_block_size(mech->mechanism, &blocksize);
4052             if (rc != CKR_OK)
4053                 goto done;
4054             multi_part_ctx->data_len = blocksize;
4055             multi_part_ctx->data = malloc(multi_part_ctx->data_len);
4056             if (!multi_part_ctx->data) {
4057                 TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
4058                 rc = CKR_HOST_MEMORY;
4059                 goto done;
4060             }
4061             memset(multi_part_ctx->data, 0, blocksize);
4062         }
4063     } else {
4064         ctx->context_len = 0;
4065         ctx->context = NULL;
4066     }
4067 
4068     ctx->key = key;
4069     ctx->multi = FALSE;
4070     ctx->active = TRUE;
4071 
4072 done:
4073     if (rc != CKR_OK)
4074         free_sv_ctx(ctx);
4075 
4076     return rc;
4077 }
4078 
icsftok_verify(SESSION * session,CK_BYTE * in_data,CK_ULONG in_data_len,CK_BYTE * signature,CK_ULONG sig_len)4079 CK_RV icsftok_verify(SESSION * session, CK_BYTE * in_data, CK_ULONG in_data_len,
4080                      CK_BYTE * signature, CK_ULONG sig_len)
4081 {
4082     struct session_state *session_state;
4083     SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx;
4084     struct icsf_object_mapping *mapping = NULL;
4085     char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, };
4086     size_t chain_data_len = sizeof(chain_data);
4087     CK_RV rc = CKR_OK;
4088     int reason;
4089 
4090     if (ctx->multi == TRUE) {
4091         TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE));
4092         rc = CKR_OPERATION_ACTIVE;
4093         goto done;
4094     }
4095 
4096     /* Check session */
4097     if (!(session_state = get_session_state(session->handle))) {
4098         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
4099         rc = CKR_SESSION_HANDLE_INVALID;
4100         goto done;
4101     }
4102 
4103     /* check ldap handle */
4104     if (session_state->ld == NULL) {
4105         TRACE_ERROR("No LDAP handle.\n");
4106         rc = CKR_FUNCTION_FAILED;
4107         goto done;
4108     }
4109 
4110     /* Check if key exists */
4111     if (!(mapping = bt_get_node_value(&objects, ctx->key))) {
4112         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
4113         rc = CKR_KEY_HANDLE_INVALID;
4114         goto done;
4115     }
4116 
4117     switch (ctx->mech.mechanism) {
4118     case CKM_MD5_HMAC:
4119     case CKM_SHA_1_HMAC:
4120     case CKM_SHA256_HMAC:
4121     case CKM_SHA384_HMAC:
4122     case CKM_SHA512_HMAC:
4123     case CKM_SSL3_MD5_MAC:
4124     case CKM_SSL3_SHA1_MAC:
4125         rc = icsf_hmac_verify(session_state->ld, &reason,
4126                               &mapping->icsf_object, &ctx->mech, "ONLY",
4127                               (char *)in_data, in_data_len,
4128                               (char *)signature, sig_len,
4129                               chain_data, &chain_data_len);
4130         if (rc != 0)
4131             rc = icsf_to_ock_err(rc, reason);
4132 
4133         break;
4134     case CKM_RSA_X_509:
4135     case CKM_RSA_PKCS:
4136     case CKM_DSA:
4137     case CKM_ECDSA:
4138         rc = icsf_public_key_verify(session_state->ld, &reason, FALSE,
4139                                     &mapping->icsf_object, &ctx->mech,
4140                                     (char *)in_data, in_data_len,
4141                                     (char *)signature, &sig_len);
4142         if (rc != 0)
4143             rc = icsf_to_ock_err(rc, reason);
4144         break;
4145     case CKM_MD5_RSA_PKCS:
4146     case CKM_SHA1_RSA_PKCS:
4147     case CKM_SHA256_RSA_PKCS:
4148     case CKM_SHA384_RSA_PKCS:
4149     case CKM_SHA512_RSA_PKCS:
4150     case CKM_DSA_SHA1:
4151     case CKM_ECDSA_SHA1:
4152         rc = icsf_hash_signverify(session_state->ld, &reason,
4153                                   &mapping->icsf_object, &ctx->mech,
4154                                   "ONLY", (char *)in_data, in_data_len,
4155                                   (char *)signature, &sig_len,
4156                                   chain_data, &chain_data_len, 1);
4157         if (rc != 0)
4158             rc = icsf_to_ock_err(rc, reason);
4159 
4160         break;
4161     default:
4162         TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
4163         rc = CKR_MECHANISM_INVALID;
4164     }
4165 
4166 done:
4167     free_sv_ctx(ctx);
4168     return rc;
4169 }
4170 
icsftok_verify_update(SESSION * session,CK_BYTE * in_data,CK_ULONG in_data_len)4171 CK_RV icsftok_verify_update(SESSION * session, CK_BYTE * in_data,
4172                             CK_ULONG in_data_len)
4173 {
4174     struct session_state *session_state;
4175     SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx;
4176     struct icsf_object_mapping *mapping = NULL;
4177     struct icsf_multi_part_context *multi_part_ctx = NULL;
4178     char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, };
4179     size_t chain_data_len = sizeof(chain_data);
4180     CK_RV rc = CKR_OK;
4181     int reason;
4182     CK_ULONG total, remain, out_len = 0;
4183     char *buffer = NULL;
4184 
4185     /* Check session */
4186     if (!(session_state = get_session_state(session->handle))) {
4187         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
4188         rc = CKR_SESSION_HANDLE_INVALID;
4189         goto done;
4190     }
4191 
4192     /* check ldap handle */
4193     if (session_state->ld == NULL) {
4194         TRACE_ERROR("No LDAP handle.\n");
4195         rc = CKR_FUNCTION_FAILED;
4196         goto done;
4197     }
4198 
4199     /* Check if key exists */
4200     if (!(mapping = bt_get_node_value(&objects, ctx->key))) {
4201         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
4202         rc = CKR_KEY_HANDLE_INVALID;
4203         goto done;
4204     }
4205 
4206     /* indicate this is multipart operation and get chain info from ctx.
4207      * if any mechanisms that cannot do multipart verify come here, they
4208      * will get an error in switch below.
4209      */
4210     ctx->multi = TRUE;
4211     if (ctx->context) {
4212         multi_part_ctx = (struct icsf_multi_part_context *) ctx->context;
4213         if (multi_part_ctx->initiated)
4214             memcpy(chain_data, multi_part_ctx->chain_data, chain_data_len);
4215     } else {
4216         TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD));
4217         rc = ERR_ARGUMENTS_BAD;
4218         goto done;
4219     }
4220 
4221     switch (ctx->mech.mechanism) {
4222     case CKM_MD5_HMAC:
4223     case CKM_SHA_1_HMAC:
4224     case CKM_SHA256_HMAC:
4225     case CKM_SHA384_HMAC:
4226     case CKM_SHA512_HMAC:
4227     case CKM_SSL3_MD5_MAC:
4228     case CKM_SSL3_SHA1_MAC:
4229         rc = icsf_hmac_verify(session_state->ld, &reason,
4230                               &mapping->icsf_object, &ctx->mech,
4231                               (multi_part_ctx->initiated) ? "MIDDLE" : "FIRST",
4232                               (char *)in_data, in_data_len, "", 0,
4233                               chain_data, &chain_data_len);
4234 
4235         if (rc != 0) {
4236             TRACE_DEVEL("icsf_hmac_verify failed\n");
4237             rc = icsf_to_ock_err(rc, reason);
4238         } else {
4239             multi_part_ctx->initiated = TRUE;
4240             memcpy(multi_part_ctx->chain_data, chain_data, chain_data_len);
4241         }
4242         break;
4243     case CKM_MD5_RSA_PKCS:
4244     case CKM_SHA1_RSA_PKCS:
4245     case CKM_SHA256_RSA_PKCS:
4246     case CKM_SHA384_RSA_PKCS:
4247     case CKM_SHA512_RSA_PKCS:
4248     case CKM_DSA_SHA1:
4249     case CKM_ECDSA_SHA1:
4250         /* caching data since ICSF wants in multiple of blocksize */
4251         if (multi_part_ctx && multi_part_ctx->data) {
4252 
4253             total = multi_part_ctx->used_data_len + in_data_len;
4254             remain = total % multi_part_ctx->data_len;;
4255 
4256             /* if not enough to meet blocksize, cache and exit. */
4257             if (total < multi_part_ctx->data_len) {
4258                 memcpy(multi_part_ctx->data + multi_part_ctx->used_data_len,
4259                        (char *)in_data, in_data_len);
4260                 multi_part_ctx->used_data_len += in_data_len;
4261 
4262                 rc = CKR_OK;
4263                 goto done;
4264             } else {
4265                 /* there is at least 1 block */
4266 
4267                 out_len = total - remain;
4268 
4269                 /* prepare a buffer to send data in */
4270                 if (!(buffer = malloc(out_len))) {
4271                     TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
4272                     rc = CKR_HOST_MEMORY;
4273                     goto done;
4274                 }
4275                 memcpy(buffer, multi_part_ctx->data,
4276                        multi_part_ctx->used_data_len);
4277                 memcpy(buffer + multi_part_ctx->used_data_len,
4278                        (char *)in_data,
4279                        out_len - multi_part_ctx->used_data_len);
4280 
4281                 /* copy remainder of data to ctx
4282                  * for next time. caching.
4283                  */
4284                 if (remain != 0)
4285                     memcpy(multi_part_ctx->data,
4286                            (char *)in_data + (in_data_len - remain), remain);
4287 
4288                 multi_part_ctx->used_data_len = remain;
4289             }
4290         }
4291 
4292         rc = icsf_hash_signverify(session_state->ld, &reason,
4293                                   &mapping->icsf_object, &ctx->mech,
4294                                   (multi_part_ctx->
4295                                    initiated) ? "MIDDLE" : "FIRST", buffer,
4296                                   out_len, NULL, NULL, chain_data,
4297                                   &chain_data_len, 1);
4298 
4299         if (rc != 0) {
4300             TRACE_DEVEL("icsf_hash_signverify failed\n");
4301             rc = icsf_to_ock_err(rc, reason);
4302         } else {
4303             multi_part_ctx->initiated = TRUE;
4304             memcpy(multi_part_ctx->chain_data, chain_data, chain_data_len);
4305         }
4306 
4307         if (buffer)
4308             free(buffer);
4309 
4310         break;
4311     default:
4312         TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
4313         rc = CKR_MECHANISM_INVALID;
4314     }
4315 
4316 done:
4317     if (rc != CKR_OK)
4318         free_sv_ctx(ctx);
4319 
4320     return rc;
4321 }
4322 
icsftok_verify_final(SESSION * session,CK_BYTE * signature,CK_ULONG sig_len)4323 CK_RV icsftok_verify_final(SESSION * session, CK_BYTE * signature,
4324                            CK_ULONG sig_len)
4325 {
4326     struct session_state *session_state;
4327     SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx;
4328     struct icsf_object_mapping *mapping = NULL;
4329     struct icsf_multi_part_context *multi_part_ctx = NULL;
4330     char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, };
4331     size_t chain_data_len = sizeof(chain_data);
4332     CK_RV rc = CKR_OK;
4333     int reason;
4334     char *buffer = NULL;
4335 
4336     if (!sig_len) {
4337         TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD));
4338         rc = CKR_ARGUMENTS_BAD;
4339         goto done;
4340     }
4341 
4342     /* Check session */
4343     if (!(session_state = get_session_state(session->handle))) {
4344         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
4345         rc = CKR_SESSION_HANDLE_INVALID;
4346         goto done;
4347     }
4348 
4349     /* check ldap handle */
4350     if (session_state->ld == NULL) {
4351         TRACE_ERROR("No LDAP handle.\n");
4352         rc = CKR_FUNCTION_FAILED;
4353         goto done;
4354     }
4355 
4356     /* Check if key exists */
4357     if (!(mapping = bt_get_node_value(&objects, ctx->key))) {
4358         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
4359         rc = CKR_KEY_HANDLE_INVALID;
4360         goto done;
4361     }
4362 
4363     /* get the chain data from ctx */
4364     if (ctx->context) {
4365         multi_part_ctx = (struct icsf_multi_part_context *) ctx->context;
4366         memcpy(chain_data, multi_part_ctx->chain_data, chain_data_len);
4367     } else {
4368         TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD));
4369         rc = ERR_ARGUMENTS_BAD;
4370         goto done;
4371     }
4372 
4373     switch (ctx->mech.mechanism) {
4374     case CKM_MD5_HMAC:
4375     case CKM_SHA_1_HMAC:
4376     case CKM_SHA256_HMAC:
4377     case CKM_SHA384_HMAC:
4378     case CKM_SHA512_HMAC:
4379     case CKM_SSL3_MD5_MAC:
4380     case CKM_SSL3_SHA1_MAC:
4381         /* get the chain data */
4382         rc = icsf_hmac_verify(session_state->ld, &reason,
4383                               &mapping->icsf_object, &ctx->mech,
4384                               multi_part_ctx->initiated ? "LAST" : "ONLY", "",
4385                               0, (char *)signature, sig_len,
4386                               chain_data, &chain_data_len);
4387         if (rc != 0)
4388             rc = icsf_to_ock_err(rc, reason);
4389 
4390         break;
4391     case CKM_MD5_RSA_PKCS:
4392     case CKM_SHA1_RSA_PKCS:
4393     case CKM_SHA256_RSA_PKCS:
4394     case CKM_SHA384_RSA_PKCS:
4395     case CKM_SHA512_RSA_PKCS:
4396     case CKM_DSA_SHA1:
4397     case CKM_ECDSA_SHA1:
4398         /* see if any data left in the cache */
4399         if (multi_part_ctx && multi_part_ctx->used_data_len) {
4400             if (!(buffer = malloc(multi_part_ctx->used_data_len))) {
4401                 TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
4402                 rc = CKR_HOST_MEMORY;
4403                 goto done;
4404             }
4405             memcpy(buffer, multi_part_ctx->data, multi_part_ctx->used_data_len);
4406         }
4407 
4408         rc = icsf_hash_signverify(session_state->ld, &reason,
4409                                   &mapping->icsf_object, &ctx->mech,
4410                                   multi_part_ctx->initiated ? "LAST" : "ONLY",
4411                                   (buffer) ? buffer : NULL,
4412                                   multi_part_ctx->used_data_len,
4413                                   (char *)signature, &sig_len,
4414                                   chain_data, &chain_data_len, 1);
4415 
4416         if (rc != 0)
4417             rc = icsf_to_ock_err(rc, reason);
4418 
4419         if (buffer)
4420             free(buffer);
4421         break;
4422     default:
4423         TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
4424         rc = CKR_MECHANISM_INVALID;
4425     }
4426 
4427 done:
4428     free_sv_ctx(ctx);
4429 
4430     return rc;
4431 }
4432 
4433 /*
4434  * Wrap a key and return it as binary data.
4435  */
icsftok_wrap_key(SESSION * session,CK_MECHANISM_PTR mech,CK_OBJECT_HANDLE wrapping_key,CK_OBJECT_HANDLE key,CK_BYTE_PTR wrapped_key,CK_ULONG_PTR p_wrapped_key_len)4436 CK_RV icsftok_wrap_key(SESSION * session, CK_MECHANISM_PTR mech,
4437                        CK_OBJECT_HANDLE wrapping_key, CK_OBJECT_HANDLE key,
4438                        CK_BYTE_PTR wrapped_key, CK_ULONG_PTR p_wrapped_key_len)
4439 {
4440     int rc;
4441     int reason = 0;
4442     struct session_state *session_state;
4443     struct icsf_object_mapping *wrapping_key_mapping = NULL;
4444     struct icsf_object_mapping *key_mapping = NULL;
4445     size_t expected_block_size = 0;
4446 
4447     /* Check session */
4448     if (!(session_state = get_session_state(session->handle))) {
4449         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
4450         return CKR_SESSION_HANDLE_INVALID;
4451     }
4452 
4453     /* check ldap handle */
4454     if (session_state->ld == NULL) {
4455         TRACE_ERROR("No LDAP handle.\n");
4456         return CKR_FUNCTION_FAILED;
4457     }
4458 
4459     /* Check if keys exist */
4460     wrapping_key_mapping = bt_get_node_value(&objects, wrapping_key);
4461     key_mapping = bt_get_node_value(&objects, key);
4462     if (!wrapping_key_mapping || !key_mapping) {
4463         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
4464         return CKR_KEY_HANDLE_INVALID;
4465     }
4466 
4467     /* validate mechanism parameters. Only 4 mechanisms support
4468      * key wrapping in icsf token */
4469     switch (mech->mechanism) {
4470     case CKM_DES_CBC_PAD:
4471     case CKM_DES3_CBC_PAD:
4472     case CKM_AES_CBC_PAD:
4473         if ((rc = icsf_block_size(mech->mechanism, &expected_block_size)))
4474             return rc;
4475 
4476         if (mech->ulParameterLen != expected_block_size) {
4477             TRACE_ERROR("Invalid mechanism parameter length: %lu "
4478                         "(expected %lu)\n",
4479                         (unsigned long) mech->ulParameterLen,
4480                         (unsigned long) expected_block_size);
4481             return CKR_MECHANISM_PARAM_INVALID;
4482         }
4483         break;
4484     case CKM_RSA_PKCS:
4485         if (mech->ulParameterLen != 0) {
4486             TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
4487             return CKR_MECHANISM_PARAM_INVALID;
4488         }
4489         break;
4490     default:
4491         TRACE_ERROR("icsf invalid %lu mechanism for key wrapping\n",
4492                     mech->mechanism);
4493         return CKR_MECHANISM_INVALID;
4494     }
4495 
4496     /* Call ICSF service */
4497     rc = icsf_wrap_key(session_state->ld, &reason, mech,
4498                        &wrapping_key_mapping->icsf_object,
4499                        &key_mapping->icsf_object, wrapped_key,
4500                        p_wrapped_key_len);
4501     if (rc) {
4502         TRACE_DEVEL("icsf_wrap_key failed\n");
4503         return icsf_to_ock_err(rc, reason);
4504     }
4505 
4506     return CKR_OK;
4507 }
4508 
4509 /*
4510  * Unwrap a key from binary data and create a new key object.
4511  */
icsftok_unwrap_key(SESSION * session,CK_MECHANISM_PTR mech,CK_ATTRIBUTE_PTR attrs,CK_ULONG attrs_len,CK_BYTE_PTR wrapped_key,CK_ULONG wrapped_key_len,CK_OBJECT_HANDLE wrapping_key,CK_OBJECT_HANDLE_PTR p_key)4512 CK_RV icsftok_unwrap_key(SESSION * session, CK_MECHANISM_PTR mech,
4513                          CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len,
4514                          CK_BYTE_PTR wrapped_key, CK_ULONG wrapped_key_len,
4515                          CK_OBJECT_HANDLE wrapping_key,
4516                          CK_OBJECT_HANDLE_PTR p_key)
4517 {
4518     int rc;
4519     int reason = 0;
4520     struct session_state *session_state;
4521     struct icsf_object_mapping *wrapping_key_mapping = NULL;
4522     struct icsf_object_mapping *key_mapping = NULL;
4523     CK_ULONG node_number;
4524     size_t expected_block_size = 0;
4525 
4526     /* Check session */
4527     if (!(session_state = get_session_state(session->handle))) {
4528         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
4529         return CKR_SESSION_HANDLE_INVALID;
4530     }
4531 
4532     /* check ldap handle */
4533     if (session_state->ld == NULL) {
4534         TRACE_ERROR("No LDAP handle.\n");
4535         return CKR_FUNCTION_FAILED;
4536     }
4537 
4538     /* Check if key exists */
4539     wrapping_key_mapping = bt_get_node_value(&objects, wrapping_key);
4540     if (!wrapping_key_mapping) {
4541         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
4542         return CKR_KEY_HANDLE_INVALID;
4543     }
4544 
4545     /* Allocate structure to keep ICSF object information */
4546     if (!(key_mapping = malloc(sizeof(*key_mapping)))) {
4547         TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
4548         return CKR_HOST_MEMORY;
4549     }
4550     memset(key_mapping, 0, sizeof(*key_mapping));
4551     key_mapping->session_id = session->handle;
4552 
4553     /* validate mechanism parameters. Only 4 mechanisms support
4554      * key wrapping in icsf token */
4555     switch (mech->mechanism) {
4556     case CKM_DES_CBC_PAD:
4557     case CKM_DES3_CBC_PAD:
4558     case CKM_AES_CBC_PAD:
4559         if ((rc = icsf_block_size(mech->mechanism, &expected_block_size))) {
4560             free(key_mapping);
4561             return rc;
4562         }
4563 
4564         if (mech->ulParameterLen != expected_block_size) {
4565             TRACE_ERROR("Invalid mechanism parameter length: %lu "
4566                         "(expected %lu)\n",
4567                         (unsigned long) mech->ulParameterLen,
4568                         (unsigned long) expected_block_size);
4569             free(key_mapping);
4570             return CKR_MECHANISM_PARAM_INVALID;
4571         }
4572         break;
4573     case CKM_RSA_PKCS:
4574         if (mech->ulParameterLen != 0) {
4575             TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
4576             free(key_mapping);
4577             return CKR_MECHANISM_PARAM_INVALID;
4578         }
4579         break;
4580     default:
4581         TRACE_ERROR("icsf invalid %lu mechanism for key wrapping\n",
4582                     mech->mechanism);
4583         free(key_mapping);
4584         return CKR_MECHANISM_INVALID;
4585     }
4586 
4587     /* Call ICSF service */
4588     rc = icsf_unwrap_key(session_state->ld, &reason, mech,
4589                          &wrapping_key_mapping->icsf_object,
4590                          wrapped_key, wrapped_key_len,
4591                          attrs, attrs_len, &key_mapping->icsf_object);
4592     if (rc) {
4593         TRACE_DEVEL("icsf_unwrap_key failed\n");
4594         rc = icsf_to_ock_err(rc, reason);
4595         goto done;
4596     }
4597 
4598     /* Add info about object into session */
4599     if (!(node_number = bt_node_add(&objects, key_mapping))) {
4600         TRACE_ERROR("Failed to add object to binary tree.\n");
4601         rc = CKR_FUNCTION_FAILED;
4602         goto done;
4603     }
4604 
4605     /* Use node number as handle */
4606     *p_key = node_number;
4607 
4608 done:
4609     /* If allocated, object must be freed in case of failure */
4610     if (rc && key_mapping)
4611         free(key_mapping);
4612 
4613     return rc;
4614 }
4615 
4616 /*
4617  * Derive a key from a base key, creating a new key object.
4618  */
icsftok_derive_key(STDLL_TokData_t * tokdata,SESSION * session,CK_MECHANISM_PTR mech,CK_OBJECT_HANDLE hBaseKey,CK_OBJECT_HANDLE_PTR handle,CK_ATTRIBUTE_PTR attrs,CK_ULONG attrs_len)4619 CK_RV icsftok_derive_key(STDLL_TokData_t * tokdata, SESSION * session,
4620                          CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE hBaseKey,
4621                          CK_OBJECT_HANDLE_PTR handle, CK_ATTRIBUTE_PTR attrs,
4622                          CK_ULONG attrs_len)
4623 {
4624     CK_RV rc = CKR_OK;
4625     struct session_state *session_state;
4626     struct icsf_object_mapping *base_key_mapping;
4627     CK_ULONG node_number;
4628     char token_name[sizeof(tokdata->nv_token_data->token_info.label)];
4629     CK_SSL3_KEY_MAT_PARAMS *params = { 0 };
4630     unsigned int i;
4631     int reason = 0;
4632 
4633     /* Variable for multiple keys derivation */
4634     int multiple = 0;
4635     struct icsf_object_mapping *mappings[4] = { NULL, };
4636     CK_OBJECT_HANDLE *keys[4] = { NULL, };
4637 
4638     /* Check type of derivation */
4639     if (mech->mechanism == CKM_SSL3_KEY_AND_MAC_DERIVE ||
4640         mech->mechanism == CKM_TLS_KEY_AND_MAC_DERIVE) {
4641         multiple = 1;
4642         params = (CK_SSL3_KEY_MAT_PARAMS *) mech->pParameter;
4643         keys[0] = &params->pReturnedKeyMaterial->hClientMacSecret;
4644         keys[1] = &params->pReturnedKeyMaterial->hServerMacSecret;
4645         keys[2] = &params->pReturnedKeyMaterial->hClientKey;
4646         keys[3] = &params->pReturnedKeyMaterial->hServerKey;
4647     } else {
4648         keys[0] = handle;
4649     }
4650 
4651     /* Check permissions based on attributes and session */
4652     rc = check_session_permissions(session, attrs, attrs_len);
4653     if (rc != CKR_OK)
4654         return rc;
4655 
4656     /* Copy token name from shared memory */
4657     rc = XProcLock(tokdata);
4658     if (rc != CKR_OK) {
4659         TRACE_ERROR("Failed to get process lock.\n");
4660         return rc;
4661     }
4662 
4663     memcpy(token_name, tokdata->nv_token_data->token_info.label,
4664            sizeof(token_name));
4665 
4666     rc = XProcUnLock(tokdata);
4667     if (rc != CKR_OK) {
4668         TRACE_ERROR("Failed to release process lock.\n");
4669         return rc;
4670     }
4671 
4672     /* Allocate structure to keep ICSF object information */
4673     for (i = 0; i < sizeof(mappings) / sizeof(*mappings); i++) {
4674         if (!(mappings[i] = malloc(sizeof(*mappings[i])))) {
4675             TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
4676             rc = CKR_HOST_MEMORY;
4677             goto done;
4678         }
4679         memset(mappings[i], 0, sizeof(*mappings[i]));
4680         mappings[i]->session_id = session->handle;
4681 
4682         /* If not deriving multiple keys, just one key is needed */
4683         if (!multiple)
4684             break;
4685     }
4686 
4687     /* Get session state */
4688     if (!(session_state = get_session_state(session->handle))) {
4689         TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID));
4690         rc = CKR_SESSION_HANDLE_INVALID;
4691         goto done;
4692     }
4693 
4694     /* check ldap handle */
4695     if (session_state->ld == NULL) {
4696         TRACE_ERROR("No LDAP handle.\n");
4697         rc = CKR_FUNCTION_FAILED;
4698         goto done;
4699     }
4700 
4701     /* Convert the OCK_CK_OBJECT_HANDLE_PTR to ICSF */
4702     base_key_mapping = bt_get_node_value(&objects, hBaseKey);
4703     if (!base_key_mapping) {
4704         TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
4705         rc = CKR_KEY_HANDLE_INVALID;
4706         goto done;
4707     }
4708 
4709     /* Call ICSF service */
4710     if (!multiple)
4711         rc = icsf_derive_key(session_state->ld, &reason, mech,
4712                              &base_key_mapping->icsf_object,
4713                              &mappings[0]->icsf_object, attrs, attrs_len);
4714     else
4715         rc = icsf_derive_multiple_keys(session_state->ld, &reason,
4716                                        mech, &base_key_mapping->icsf_object,
4717                                        attrs, attrs_len,
4718                                        &mappings[0]->icsf_object,
4719                                        &mappings[1]->icsf_object,
4720                                        &mappings[2]->icsf_object,
4721                                        &mappings[3]->icsf_object,
4722                                        params->pReturnedKeyMaterial->pIVClient,
4723                                        params->pReturnedKeyMaterial->pIVServer);
4724     if (rc) {
4725         rc = icsf_to_ock_err(rc, reason);
4726         goto done;
4727     }
4728 
4729     for (i = 0; i < sizeof(mappings) / sizeof(*mappings); i++) {
4730         /* Add info about object into session */
4731         if (!(node_number = bt_node_add(&objects, mappings[i]))) {
4732             TRACE_ERROR("Failed to add object to binary tree.\n");
4733             rc = CKR_FUNCTION_FAILED;
4734             goto done;
4735         }
4736 
4737         /* Use node number as handle */
4738         *keys[i] = node_number;
4739 
4740         /* If not deriving multiple keys, just one key is returned */
4741         if (!multiple)
4742             break;
4743     }
4744 
4745 done:
4746     /* If allocated, object must be freed in case of failure */
4747     if (rc) {
4748         for (i = 0; i < sizeof(mappings) / sizeof(*mappings); i++)
4749             if (mappings[i])
4750                 free(mappings[i]);
4751     }
4752 
4753     return rc;
4754 }
4755