1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Session Management Functions
28 * (as defined in PKCS#11 spec spection 11.6)
29 */
30
31 #include <string.h>
32 #include "metaGlobal.h"
33
34 extern meta_session_t *meta_sessionlist_head;
35 extern pthread_rwlock_t meta_sessionlist_lock;
36 extern CK_ULONG num_meta_sessions;
37 extern CK_ULONG num_rw_meta_sessions;
38
39 /*
40 * meta_OpenSession
41 *
42 * NOTES:
43 * 1) The pApplication and Notify args are not used, as the metaslot does not
44 * support application callbacks.
45 * 2) the slotID argument is not checked or used because this function
46 * is only called from the framework.
47 */
48 /* ARGSUSED */
49 CK_RV
meta_OpenSession(CK_SLOT_ID slotID,CK_FLAGS flags,CK_VOID_PTR pApplication,CK_NOTIFY Notify,CK_SESSION_HANDLE_PTR phSession)50 meta_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication,
51 CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession)
52 {
53 meta_session_t *new_session;
54 CK_RV rv;
55
56 if (!metaslot_enabled) {
57 return (CKR_SLOT_ID_INVALID);
58 }
59
60 if (phSession == NULL) {
61 return (CKR_ARGUMENTS_BAD);
62 }
63
64 /* Check for any unknown flags. */
65 if (flags & ~(CKF_SERIAL_SESSION | CKF_RW_SESSION)) {
66 return (CKR_ARGUMENTS_BAD);
67 }
68
69 if (!(flags & CKF_SERIAL_SESSION)) {
70 return (CKR_SESSION_PARALLEL_NOT_SUPPORTED);
71 }
72
73 if (meta_slotManager_token_write_protected() &&
74 (flags & CKF_RW_SESSION)) {
75 return (CKR_TOKEN_WRITE_PROTECTED);
76 }
77
78 rv = meta_session_alloc(&new_session);
79 if (rv != CKR_OK)
80 return (rv);
81
82 new_session->session_flags = flags;
83
84 rv = meta_session_activate(new_session);
85 if (rv != CKR_OK) {
86 meta_session_dealloc(new_session);
87 return (rv);
88 }
89
90 *phSession = (CK_SESSION_HANDLE) new_session;
91
92 num_meta_sessions++;
93 if (flags & CKF_RW_SESSION) {
94 num_rw_meta_sessions++;
95 }
96
97 return (CKR_OK);
98 }
99
100
101 /*
102 * meta_CloseSession
103 *
104 */
105 CK_RV
meta_CloseSession(CK_SESSION_HANDLE hSession)106 meta_CloseSession(CK_SESSION_HANDLE hSession)
107 {
108 CK_RV rv;
109 meta_session_t *session;
110 CK_FLAGS flags;
111
112 rv = meta_handle2session(hSession, &session);
113 if (rv != CKR_OK)
114 return (rv);
115
116 /* save info about session flags before they are destroyed */
117 flags = session->session_flags;
118
119 rv = meta_session_deactivate(session, B_FALSE);
120
121 if (rv == CKR_OK)
122 meta_session_dealloc(session);
123
124 num_meta_sessions--;
125 if (flags & CKF_RW_SESSION) {
126 num_rw_meta_sessions--;
127 }
128
129 return (rv);
130 }
131
132
133 /*
134 * meta_CloseAllSessions
135 *
136 * This is a simple loop that closes the sessionlist head (resulting in a
137 * new list head) until the list is empty.
138 *
139 */
140 CK_RV
meta_CloseAllSessions(CK_SLOT_ID slotID)141 meta_CloseAllSessions(CK_SLOT_ID slotID)
142 {
143 CK_RV rv;
144 meta_session_t *session;
145
146 if (!metaslot_enabled) {
147 return (CKR_SLOT_ID_INVALID);
148 }
149
150 if (slotID != METASLOT_SLOTID)
151 return (CKR_SLOT_ID_INVALID);
152
153 (void) pthread_rwlock_wrlock(&meta_sessionlist_lock);
154 while ((session = meta_sessionlist_head) != NULL) {
155 rv = meta_handle2session((CK_SESSION_HANDLE)session, &session);
156 if (rv != CKR_OK) {
157 /*NOTREACHED*/
158 (void) pthread_rwlock_unlock(&meta_sessionlist_lock);
159 return (CKR_FUNCTION_FAILED);
160 }
161
162 (void) meta_session_deactivate(session, B_TRUE);
163 meta_session_dealloc(session);
164 }
165 (void) pthread_rwlock_unlock(&meta_sessionlist_lock);
166
167 /* All open sessions should be closed, just reset the variables */
168 num_meta_sessions = 0;
169 num_rw_meta_sessions = 0;
170
171 return (CKR_OK);
172 }
173
174
175 /*
176 * meta_GetSessionInfo
177 *
178 */
179 CK_RV
meta_GetSessionInfo(CK_SESSION_HANDLE hSession,CK_SESSION_INFO_PTR pInfo)180 meta_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo)
181 {
182 CK_RV rv;
183 meta_session_t *session;
184
185 if (pInfo == NULL)
186 return (CKR_ARGUMENTS_BAD);
187
188 rv = meta_handle2session(hSession, &session);
189 if (rv != CKR_OK)
190 return (rv);
191
192 pInfo->slotID = METASLOT_SLOTID;
193 pInfo->flags = session->session_flags;
194
195 if (metaslot_logged_in()) {
196 if (IS_READ_ONLY_SESSION(session->session_flags)) {
197 pInfo->state = CKS_RO_USER_FUNCTIONS;
198 } else {
199 pInfo->state = CKS_RW_USER_FUNCTIONS;
200 }
201 } else {
202 if (IS_READ_ONLY_SESSION(session->session_flags)) {
203 pInfo->state = CKS_RO_PUBLIC_SESSION;
204 } else {
205 pInfo->state = CKS_RW_PUBLIC_SESSION;
206 }
207 }
208
209 pInfo->ulDeviceError = 0;
210
211 REFRELEASE(session);
212
213 return (CKR_OK);
214 }
215
216 CK_RV
meta_getopstatelen(meta_session_t * session,CK_ULONG * out_length)217 meta_getopstatelen(meta_session_t *session, CK_ULONG *out_length)
218 {
219 CK_RV rv = CKR_OK;
220 slot_session_t *slot_session;
221 CK_ULONG length;
222
223 *out_length = sizeof (meta_opstate_t);
224 if (session->op1.type != 0) {
225 slot_session = session->op1.session;
226 rv = FUNCLIST(slot_session->fw_st_id)->C_GetOperationState(
227 slot_session->hSession, NULL, &length);
228 if (rv == CKR_OK)
229 *out_length += length;
230 }
231 return (rv);
232 }
233
234 /*
235 * meta_GetOperationState
236 *
237 */
238 CK_RV
meta_GetOperationState(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pOperationState,CK_ULONG_PTR pulOperationStateLen)239 meta_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState,
240 CK_ULONG_PTR pulOperationStateLen)
241 {
242 CK_RV rv;
243 meta_session_t *session;
244 slot_session_t *slot_session = NULL;
245 meta_opstate_t opstate;
246
247 if (pulOperationStateLen == NULL)
248 return (CKR_ARGUMENTS_BAD);
249
250 rv = meta_handle2session(hSession, &session);
251 if (rv != CKR_OK)
252 return (rv);
253
254 /*
255 * If no operation is active, then bail out.
256 */
257 if (session->op1.type == 0) {
258 rv = CKR_OPERATION_NOT_INITIALIZED;
259 goto endgetopstate;
260 }
261
262 /*
263 * If the caller did not give an OpState buffer,
264 * shortcut and just return the size needed to hold
265 * a metaslot OpState record later.
266 * The actual size of the returned state will be the
267 * sizeof(meta_opstate_t) + SIZE (op1 state),
268 * so we have to get the size of
269 * the operation states now.
270 */
271 if (pOperationState == NULL) {
272 rv = meta_getopstatelen(session, pulOperationStateLen);
273 REFRELEASE(session);
274 return (rv);
275 }
276
277 /*
278 * To be here, the caller must have supplied an
279 * already initialized meta_opstate_t pointer.
280 * Use it to get the real state info from the operation(s).
281 *
282 * The format of the Metaslot Opstate record:
283 * {
284 * struct metaopstate
285 * [ op1 state data ]
286 * }
287 */
288
289 /*
290 * If the buffer is not even big enough for the metaslot
291 * opstate data, return error and set the returned
292 * state length to indicate the minimum needed.
293 */
294 if (*pulOperationStateLen < sizeof (meta_opstate_t)) {
295 rv = meta_getopstatelen(session, pulOperationStateLen);
296 /*
297 * Remap the error so the caller knows that they
298 * used an invalid buffer size in the first place.
299 */
300 if (rv == CKR_OK)
301 rv = CKR_BUFFER_TOO_SMALL;
302 goto endgetopstate;
303 }
304
305 (void) memset(&opstate, 0, sizeof (meta_opstate_t));
306 opstate.magic_marker = METASLOT_OPSTATE_MAGIC;
307
308 if (session->op1.type != 0) {
309 slot_session = session->op1.session;
310 opstate.state[0].op_type = session->op1.type;
311 opstate.state[0].op_slotnum = slot_session->slotnum;
312 opstate.state[0].op_state_len = *pulOperationStateLen -
313 sizeof (meta_opstate_t);
314 opstate.state[0].op_init_app = session->init.app;
315 opstate.state[0].op_init_done = session->init.done;
316 rv = FUNCLIST(slot_session->fw_st_id)->C_GetOperationState(
317 slot_session->hSession,
318 pOperationState + sizeof (meta_opstate_t),
319 &(opstate.state[0].op_state_len));
320
321 if (rv == CKR_BUFFER_TOO_SMALL) {
322 /*
323 * This should not happen, but if it does,
324 * recalculate the entire size needed
325 * and return the error.
326 */
327 rv = meta_getopstatelen(session, pulOperationStateLen);
328 if (rv == CKR_OK)
329 rv = CKR_BUFFER_TOO_SMALL;
330 }
331
332 if (rv != CKR_OK)
333 goto endgetopstate;
334 }
335
336 endgetopstate:
337 if (rv == CKR_OK && pOperationState != NULL) {
338 (void) memcpy(pOperationState, (void *)&opstate,
339 sizeof (meta_opstate_t));
340
341 *pulOperationStateLen = sizeof (meta_opstate_t) +
342 opstate.state[0].op_state_len;
343 }
344
345 REFRELEASE(session);
346 return (rv);
347 }
348
349 static CK_RV
meta_set_opstate(slot_session_t * slot_session,meta_object_t * meta_enc_key,meta_object_t * meta_auth_key,struct opstate_data * state,CK_BYTE * databuf)350 meta_set_opstate(slot_session_t *slot_session,
351 meta_object_t *meta_enc_key,
352 meta_object_t *meta_auth_key,
353 struct opstate_data *state,
354 CK_BYTE *databuf)
355 {
356 CK_RV rv;
357 static CK_ULONG encrypt_optypes = (CKF_ENCRYPT | CKF_DECRYPT);
358 static CK_ULONG sign_optypes = (CKF_SIGN | CKF_VERIFY |
359 CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER);
360 slot_object_t *enc_key_obj = NULL, *auth_key_obj = NULL;
361
362 if (state->op_type & encrypt_optypes) {
363 rv = meta_object_get_clone(meta_enc_key, slot_session->slotnum,
364 slot_session, &enc_key_obj);
365 if (rv != CKR_OK) {
366 return (rv);
367 }
368 }
369 if (state->op_type & sign_optypes) {
370 rv = meta_object_get_clone(meta_auth_key, slot_session->slotnum,
371 slot_session, &auth_key_obj);
372 if (rv != CKR_OK) {
373 return (rv);
374 }
375 }
376
377 /*
378 * Check to see if the keys are needed to restore the
379 * state on the first operation.
380 */
381 rv = FUNCLIST(slot_session->fw_st_id)->C_SetOperationState(
382 slot_session->hSession, databuf, state->op_state_len,
383 enc_key_obj ? enc_key_obj->hObject : CK_INVALID_HANDLE,
384 auth_key_obj ? auth_key_obj->hObject : CK_INVALID_HANDLE);
385 /*
386 * If the operation did not need a key, try again.
387 */
388 if (rv == CKR_KEY_NOT_NEEDED) {
389 rv = FUNCLIST(slot_session->fw_st_id)->C_SetOperationState(
390 slot_session->hSession, databuf, state->op_state_len,
391 CK_INVALID_HANDLE, CK_INVALID_HANDLE);
392 /*
393 * Strange case... If the first try returned
394 * KEY_NOT_NEEDED, and this one returns KEY_NEEDED,
395 * we want to remap the return so the caller sees
396 * the original "CKR_KEY_NOT_NEEDED" return value.
397 * This ensures that a correct caller will retry
398 * without the unnecessary key argument and this
399 * 2nd attempt will not happen again.
400 */
401 if (rv == CKR_KEY_NEEDED) {
402 rv = CKR_KEY_NOT_NEEDED;
403 }
404 }
405
406 return (rv);
407 }
408
409 /*
410 * meta_SetOperationState
411 *
412 */
413 CK_RV
meta_SetOperationState(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pOperationState,CK_ULONG ulOperationStateLen,CK_OBJECT_HANDLE hEncryptionKey,CK_OBJECT_HANDLE hAuthenticationKey)414 meta_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState,
415 CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey,
416 CK_OBJECT_HANDLE hAuthenticationKey)
417 {
418 CK_RV rv = CKR_OK;
419 meta_session_t *session;
420 slot_session_t *slot_session = NULL;
421 meta_opstate_t opstate;
422 meta_object_t *meta_enc_key = NULL, *meta_auth_key = NULL;
423
424 /*
425 * Make sure the opstate info buffer is big enough to be valid.
426 */
427 if (ulOperationStateLen < sizeof (meta_opstate_t) ||
428 pOperationState == NULL)
429 return (CKR_ARGUMENTS_BAD);
430
431 /* Copy the opstate info into the structure */
432 (void) memcpy(&opstate, pOperationState, sizeof (meta_opstate_t));
433
434 /* verify that a metaslot operation state was supplied */
435 if (opstate.magic_marker != METASLOT_OPSTATE_MAGIC)
436 return (CKR_SAVED_STATE_INVALID);
437
438 /*
439 * Now, check the size again to make sure the "real" state
440 * data is present. Length of state provided must be exact.
441 */
442 if (ulOperationStateLen != (sizeof (meta_opstate_t) +
443 opstate.state[0].op_state_len))
444 return (CKR_SAVED_STATE_INVALID);
445
446 rv = meta_handle2session(hSession, &session);
447 if (rv != CKR_OK)
448 return (rv);
449
450 if (hEncryptionKey != CK_INVALID_HANDLE) {
451 rv = meta_handle2object(hEncryptionKey, &meta_enc_key);
452 if (rv != CKR_OK)
453 goto cleanup;
454 }
455 if (hAuthenticationKey != CK_INVALID_HANDLE) {
456 rv = meta_handle2object(hAuthenticationKey, &meta_auth_key);
457 if (rv != CKR_OK)
458 goto cleanup;
459 }
460
461 if (opstate.state[0].op_type != 0) {
462 if (session->op1.type != 0)
463 meta_operation_cleanup(session, session->op1.type,
464 B_FALSE);
465
466 if (session->op1.session != NULL) {
467 slot_session = session->op1.session;
468 } else {
469 rv = meta_get_slot_session(opstate.state[0].op_slotnum,
470 &slot_session, session->session_flags);
471 if (rv != CKR_OK)
472 goto cleanup;
473 }
474
475 session->op1.type = opstate.state[0].op_type;
476 session->op1.session = slot_session;
477 session->init.app = opstate.state[0].op_init_app;
478 session->init.done = opstate.state[0].op_init_done;
479
480 rv = meta_set_opstate(slot_session, meta_enc_key,
481 meta_auth_key, &(opstate.state[0]),
482 pOperationState + sizeof (meta_opstate_t));
483
484 if (rv != CKR_OK) {
485 meta_operation_cleanup(session, session->op1.type,
486 FALSE);
487 goto cleanup;
488 }
489 }
490
491 cleanup:
492 if (meta_enc_key != NULL)
493 OBJRELEASE(meta_enc_key);
494 if (meta_auth_key != NULL)
495 OBJRELEASE(meta_auth_key);
496 REFRELEASE(session);
497 return (rv);
498 }
499
500 /*
501 * meta_Login
502 *
503 * This allows the user to login to the object token. The metaslot itself
504 * does not have any kind of PIN.
505 *
506 */
507 CK_RV
meta_Login(CK_SESSION_HANDLE hSession,CK_USER_TYPE userType,CK_UTF8CHAR_PTR pPin,CK_ULONG ulPinLen)508 meta_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType,
509 CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
510 {
511 CK_RV rv;
512 meta_session_t *session;
513 slot_session_t *login_session = NULL;
514 CK_TOKEN_INFO token_info;
515 CK_SLOT_ID true_id, fw_st_id;
516
517 rv = meta_handle2session(hSession, &session);
518 if (rv != CKR_OK)
519 return (rv);
520
521 if (metaslot_logged_in()) {
522 rv = CKR_USER_ALREADY_LOGGED_IN;
523 goto finish;
524 }
525
526 /* Note: CKU_SO is not supported. */
527 if (userType != CKU_USER) {
528 rv = CKR_USER_TYPE_INVALID;
529 goto finish;
530 }
531
532 rv = meta_get_slot_session(get_keystore_slotnum(), &login_session,
533 session->session_flags);
534 if (rv != CKR_OK)
535 goto finish;
536
537
538 fw_st_id = login_session->fw_st_id;
539 rv = FUNCLIST(fw_st_id)->C_Login(login_session->hSession, userType,
540 pPin, ulPinLen);
541
542 if (rv != CKR_OK) {
543 goto finish;
544 }
545
546 /*
547 * Note:
548 *
549 * For some slots (eg: the pkcs11_softtoken.so), C_Login()
550 * returning OK don't mean that the login is truely
551 * successful. For pkcs11_softtoken.so, the CKF_USER_PIN_TO_BE_CHANGED
552 * is set to indicate that the pin needs to be changed, and
553 * the login is not really successful. We will check
554 * that flag for this special condition. Checking for
555 * this flag shouldn't be harmful for other slots that doesn't
556 * behave like pkcs11_softtoken.so.
557 */
558
559 true_id = TRUEID(fw_st_id);
560 rv = FUNCLIST(fw_st_id)->C_GetTokenInfo(true_id, &token_info);
561 if (rv != CKR_OK) {
562 goto finish;
563 }
564
565 metaslot_set_logged_in_flag(B_TRUE);
566 if (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED) {
567 metaslot_set_logged_in_flag(B_FALSE);
568 }
569 finish:
570 if (login_session)
571 meta_release_slot_session(login_session);
572
573 REFRELEASE(session);
574
575 return (rv);
576 }
577
578 /*
579 * meta_Logout
580 *
581 */
582 CK_RV
meta_Logout(CK_SESSION_HANDLE hSession)583 meta_Logout(CK_SESSION_HANDLE hSession)
584 {
585 CK_RV rv = CKR_OK;
586 meta_session_t *session;
587 slot_session_t *logout_session = NULL;
588
589 rv = meta_handle2session(hSession, &session);
590 if (rv != CKR_OK)
591 return (rv);
592
593 if (!metaslot_logged_in()) {
594 rv = CKR_USER_NOT_LOGGED_IN;
595 goto finish;
596 }
597
598 rv = meta_get_slot_session(get_keystore_slotnum(), &logout_session,
599 session->session_flags);
600 if (rv != CKR_OK)
601 goto finish;
602
603 rv = FUNCLIST(logout_session->fw_st_id)->C_Logout(
604 logout_session->hSession);
605
606 /* If the C_Logout fails, just ignore the error. */
607 metaslot_set_logged_in_flag(B_FALSE);
608 (void) meta_token_object_deactivate(PRIVATE_TOKEN);
609
610 finish:
611 if (logout_session)
612 meta_release_slot_session(logout_session);
613
614 REFRELEASE(session);
615
616 return (rv);
617 }
618