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] = ¶ms->pReturnedKeyMaterial->hClientMacSecret;
4644 keys[1] = ¶ms->pReturnedKeyMaterial->hServerMacSecret;
4645 keys[2] = ¶ms->pReturnedKeyMaterial->hClientKey;
4646 keys[3] = ¶ms->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