1/*
2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
3 */
4
5/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 *
17 * 3. The end-user documentation included with the redistribution, if any, must
18 * include the following acknowledgment:
19 *
20 * "This product includes software developed by IAIK of Graz University of
21 * Technology."
22 *
23 * Alternately, this acknowledgment may appear in the software itself, if
24 * and wherever such third-party acknowledgments normally appear.
25 *
26 * 4. The names "Graz University of Technology" and "IAIK of Graz University of
27 * Technology" must not be used to endorse or promote products derived from
28 * this software without prior written permission.
29 *
30 * 5. Products derived from this software may not be called
31 * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior
32 * written permission of Graz University of Technology.
33 *
34 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
35 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
36 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
37 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE
38 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
39 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
40 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
41 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
42 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
43 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
45 * POSSIBILITY OF SUCH DAMAGE.
46 */
47
48#include "pkcs11wrapper.h"
49
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include <assert.h>
54
55#include "sun_security_pkcs11_wrapper_PKCS11.h"
56
57/* The list of notify callback handles that are currently active and waiting
58 * for callbacks from their sessions.
59 */
60#ifndef NO_CALLBACKS
61NotifyListNode *notifyListHead = NULL;
62jobject notifyListLock = NULL;
63#endif /* NO_CALLBACKS */
64
65#ifdef P11_ENABLE_C_OPENSESSION
66/*
67 * Class: sun_security_pkcs11_wrapper_PKCS11
68 * Method: C_OpenSession
69 * Signature: (JJLjava/lang/Object;Lsun/security/pkcs11/wrapper/CK_NOTIFY;)J
70 * Parametermapping: *PKCS11*
71 * @param jlong jSlotID CK_SLOT_ID slotID
72 * @param jlong jFlags CK_FLAGS flags
73 * @param jobject jApplication CK_VOID_PTR pApplication
74 * @param jobject jNotify CK_NOTIFY Notify
75 * @return jlong jSessionHandle CK_SESSION_HANDLE_PTR phSession
76 */
77JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1OpenSession
78 (JNIEnv *env, jobject obj, jlong jSlotID, jlong jFlags, jobject jApplication, jobject jNotify)
79{
80 CK_SESSION_HANDLE ckSessionHandle;
81 CK_SLOT_ID ckSlotID;
82 CK_FLAGS ckFlags;
83 CK_VOID_PTR ckpApplication;
84 CK_NOTIFY ckNotify;
85 jlong jSessionHandle;
86 CK_RV rv;
87#ifndef NO_CALLBACKS
88 NotifyEncapsulation *notifyEncapsulation = NULL;
89#endif /* NO_CALLBACKS */
90
91 CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
92 if (ckpFunctions == NULL) { return 0L; }
93
94 ckSlotID = jLongToCKULong(jSlotID);
95 ckFlags = jLongToCKULong(jFlags);
96
97#ifndef NO_CALLBACKS
98 if (jNotify != NULL) {
99 notifyEncapsulation = (NotifyEncapsulation *) malloc(sizeof(NotifyEncapsulation));
100 if (notifyEncapsulation == NULL) {
101 throwOutOfMemoryError(env, 0);
102 return 0L;
103 }
104 notifyEncapsulation->jApplicationData = (jApplication != NULL)
105 ? (*env)->NewGlobalRef(env, jApplication)
106 : NULL;
107 notifyEncapsulation->jNotifyObject = (*env)->NewGlobalRef(env, jNotify);
108 ckpApplication = notifyEncapsulation;
109 ckNotify = (CK_NOTIFY) &notifyCallback;
110 } else {
111 ckpApplication = NULL_PTR;
112 ckNotify = NULL_PTR;
113 }
114#else
115 ckpApplication = NULL_PTR;
116 ckNotify = NULL_PTR;
117#endif /* NO_CALLBACKS */
118
119 TRACE0("DEBUG: C_OpenSession");
120 TRACE1(", slotID=%u", ckSlotID);
121 TRACE1(", flags=%x", ckFlags);
122 TRACE0(" ... ");
123
124 rv = (*ckpFunctions->C_OpenSession)(ckSlotID, ckFlags, ckpApplication, ckNotify, &ckSessionHandle);
125 if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) {
126#ifndef NO_CALLBACKS
127 if (notifyEncapsulation != NULL) {
128 if (notifyEncapsulation->jApplicationData != NULL) {
129 (*env)->DeleteGlobalRef(env, jApplication);
130 }
131 (*env)->DeleteGlobalRef(env, jNotify);
132 free(notifyEncapsulation);
133 }
134#endif /* NO_CALLBACKS */
135 return 0L;
136 }
137
138 TRACE0("got session");
139 TRACE1(", SessionHandle=%u", ckSessionHandle);
140 TRACE0(" ... ");
141
142 jSessionHandle = ckULongToJLong(ckSessionHandle);
143
144#ifndef NO_CALLBACKS
145 if (notifyEncapsulation != NULL) {
146 /* store the notifyEncapsulation to enable later cleanup */
147 putNotifyEntry(env, ckSessionHandle, notifyEncapsulation);
148 }
149#endif /* NO_CALLBACKS */
150
151 TRACE0("FINISHED\n");
152
153 return jSessionHandle ;
154}
155#endif
156
157#ifdef P11_ENABLE_C_CLOSESESSION
158/*
159 * Class: sun_security_pkcs11_wrapper_PKCS11
160 * Method: C_CloseSession
161 * Signature: (J)V
162 * Parametermapping: *PKCS11*
163 * @param jlong jSessionHandle CK_SESSION_HANDLE hSession
164 */
165JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1CloseSession
166 (JNIEnv *env, jobject obj, jlong jSessionHandle)
167{
168 CK_SESSION_HANDLE ckSessionHandle;
169 CK_RV rv;
170#ifndef NO_CALLBACKS
171 NotifyEncapsulation *notifyEncapsulation;
172 jobject jApplicationData;
173#endif /* NO_CALLBACKS */
174
175 CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
176 if (ckpFunctions == NULL) { return; }
177
178 ckSessionHandle = jLongToCKULong(jSessionHandle);
179
180 rv = (*ckpFunctions->C_CloseSession)(ckSessionHandle);
181 if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
182
183#ifndef NO_CALLBACKS
184 notifyEncapsulation = removeNotifyEntry(env, ckSessionHandle);
185
186 if (notifyEncapsulation != NULL) {
187 /* there was a notify object used with this session, now dump the
188 * encapsulation object
189 */
190 (*env)->DeleteGlobalRef(env, notifyEncapsulation->jNotifyObject);
191 jApplicationData = notifyEncapsulation->jApplicationData;
192 if (jApplicationData != NULL) {
193 (*env)->DeleteGlobalRef(env, jApplicationData);
194 }
195 free(notifyEncapsulation);
196 }
197#endif /* NO_CALLBACKS */
198
199}
200#endif
201
202#ifdef P11_ENABLE_C_CLOSEALLSESSIONS
203/*
204 * Class: sun_security_pkcs11_wrapper_PKCS11
205 * Method: C_CloseAllSessions
206 * Signature: (J)V
207 * Parametermapping: *PKCS11*
208 * @param jlong jSlotID CK_SLOT_ID slotID
209 */
210JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1CloseAllSessions
211 (JNIEnv *env, jobject obj, jlong jSlotID)
212{
213 CK_SLOT_ID ckSlotID;
214 CK_RV rv;
215#ifndef NO_CALLBACKS
216 NotifyEncapsulation *notifyEncapsulation;
217 jobject jApplicationData;
218#endif /* NO_CALLBACKS */
219
220 CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
221 if (ckpFunctions == NULL) { return; }
222
223 ckSlotID = jLongToCKULong(jSlotID);
224
225 rv = (*ckpFunctions->C_CloseAllSessions)(ckSlotID);
226 if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
227
228#ifndef NO_CALLBACKS
229 /* Remove all notify callback helper objects. */
230 while ((notifyEncapsulation = removeFirstNotifyEntry(env)) != NULL) {
231 /* there was a notify object used with this session, now dump the
232 * encapsulation object
233 */
234 (*env)->DeleteGlobalRef(env, notifyEncapsulation->jNotifyObject);
235 jApplicationData = notifyEncapsulation->jApplicationData;
236 if (jApplicationData != NULL) {
237 (*env)->DeleteGlobalRef(env, jApplicationData);
238 }
239 free(notifyEncapsulation);
240 }
241#endif /* NO_CALLBACKS */
242}
243#endif
244
245#ifdef P11_ENABLE_C_GETSESSIONINFO
246/*
247 * Class: sun_security_pkcs11_wrapper_PKCS11
248 * Method: C_GetSessionInfo
249 * Signature: (J)Lsun/security/pkcs11/wrapper/CK_SESSION_INFO;
250 * Parametermapping: *PKCS11*
251 * @param jlong jSessionHandle CK_SESSION_HANDLE hSession
252 * @return jobject jSessionInfo CK_SESSION_INFO_PTR pInfo
253 */
254JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetSessionInfo
255 (JNIEnv *env, jobject obj, jlong jSessionHandle)
256{
257 CK_SESSION_HANDLE ckSessionHandle;
258 CK_SESSION_INFO ckSessionInfo;
259 jobject jSessionInfo=NULL;
260 CK_RV rv;
261
262 CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
263 if (ckpFunctions == NULL) { return NULL; }
264
265 ckSessionHandle = jLongToCKULong(jSessionHandle);
266
267 rv = (*ckpFunctions->C_GetSessionInfo)(ckSessionHandle, &ckSessionInfo);
268 if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) {
269 jSessionInfo = ckSessionInfoPtrToJSessionInfo(env, &ckSessionInfo);
270 }
271 return jSessionInfo ;
272}
273#endif
274
275#ifdef P11_ENABLE_C_GETOPERATIONSTATE
276/*
277 * Class: sun_security_pkcs11_wrapper_PKCS11
278 * Method: C_GetOperationState
279 * Signature: (J)[B
280 * Parametermapping: *PKCS11*
281 * @param jlong jSessionHandle CK_SESSION_HANDLE hSession
282 * @return jbyteArray jState CK_BYTE_PTR pOperationState
283 * CK_ULONG_PTR pulOperationStateLen
284 */
285JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetOperationState
286 (JNIEnv *env, jobject obj, jlong jSessionHandle)
287{
288 CK_SESSION_HANDLE ckSessionHandle;
289 CK_BYTE_PTR ckpState;
290 CK_ULONG ckStateLength;
291 jbyteArray jState = NULL;
292 CK_RV rv;
293
294 CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
295 if (ckpFunctions == NULL) { return NULL; }
296
297 ckSessionHandle = jLongToCKULong(jSessionHandle);
298
299 rv = (*ckpFunctions->C_GetOperationState)(ckSessionHandle, NULL_PTR, &ckStateLength);
300 if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; }
301
302 ckpState = (CK_BYTE_PTR) malloc(ckStateLength);
303 if (ckpState == NULL) {
304 throwOutOfMemoryError(env, 0);
305 return NULL;
306 }
307
308 rv = (*ckpFunctions->C_GetOperationState)(ckSessionHandle, ckpState, &ckStateLength);
309 if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) {
310 jState = ckByteArrayToJByteArray(env, ckpState, ckStateLength);
311 }
312 free(ckpState);
313
314 return jState ;
315}
316#endif
317
318#ifdef P11_ENABLE_C_SETOPERATIONSTATE
319/*
320 * Class: sun_security_pkcs11_wrapper_PKCS11
321 * Method: C_SetOperationState
322 * Signature: (J[BJJ)V
323 * Parametermapping: *PKCS11*
324 * @param jlong jSessionHandle CK_SESSION_HANDLE hSession
325 * @param jbyteArray jOperationState CK_BYTE_PTR pOperationState
326 * CK_ULONG ulOperationStateLen
327 * @param jlong jEncryptionKeyHandle CK_OBJECT_HANDLE hEncryptionKey
328 * @param jlong jAuthenticationKeyHandle CK_OBJECT_HANDLE hAuthenticationKey
329 */
330JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1SetOperationState
331 (JNIEnv *env, jobject obj, jlong jSessionHandle, jbyteArray jOperationState, jlong jEncryptionKeyHandle, jlong jAuthenticationKeyHandle)
332{
333 CK_SESSION_HANDLE ckSessionHandle;
334 CK_BYTE_PTR ckpState = NULL_PTR;
335 CK_ULONG ckStateLength;
336 CK_OBJECT_HANDLE ckEncryptionKeyHandle;
337 CK_OBJECT_HANDLE ckAuthenticationKeyHandle;
338 CK_RV rv;
339
340 CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
341 if (ckpFunctions == NULL) { return; }
342
343 ckSessionHandle = jLongToCKULong(jSessionHandle);
344 jByteArrayToCKByteArray(env, jOperationState, &ckpState, &ckStateLength);
345 if ((*env)->ExceptionCheck(env)) { return; }
346
347 ckEncryptionKeyHandle = jLongToCKULong(jEncryptionKeyHandle);
348 ckAuthenticationKeyHandle = jLongToCKULong(jAuthenticationKeyHandle);
349
350 rv = (*ckpFunctions->C_SetOperationState)(ckSessionHandle, ckpState, ckStateLength, ckEncryptionKeyHandle, ckAuthenticationKeyHandle);
351
352 free(ckpState);
353
354 if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
355}
356#endif
357
358#ifdef P11_ENABLE_C_LOGIN
359/*
360 * Class: sun_security_pkcs11_wrapper_PKCS11
361 * Method: C_Login
362 * Signature: (JJ[C)V
363 * Parametermapping: *PKCS11*
364 * @param jlong jSessionHandle CK_SESSION_HANDLE hSession
365 * @param jlong jUserType CK_USER_TYPE userType
366 * @param jcharArray jPin CK_CHAR_PTR pPin
367 * CK_ULONG ulPinLen
368 */
369JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1Login
370 (JNIEnv *env, jobject obj, jlong jSessionHandle, jlong jUserType, jcharArray jPin)
371{
372 CK_SESSION_HANDLE ckSessionHandle;
373 CK_USER_TYPE ckUserType;
374 CK_CHAR_PTR ckpPinArray = NULL_PTR;
375 CK_ULONG ckPinLength;
376 CK_RV rv;
377
378 CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
379 if (ckpFunctions == NULL) { return; }
380
381 ckSessionHandle = jLongToCKULong(jSessionHandle);
382 ckUserType = jLongToCKULong(jUserType);
383 jCharArrayToCKCharArray(env, jPin, &ckpPinArray, &ckPinLength);
384 if ((*env)->ExceptionCheck(env)) { return; }
385
386 rv = (*ckpFunctions->C_Login)(ckSessionHandle, ckUserType, ckpPinArray, ckPinLength);
387
388 free(ckpPinArray);
389
390 if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
391}
392#endif
393
394#ifdef P11_ENABLE_C_LOGOUT
395/*
396 * Class: sun_security_pkcs11_wrapper_PKCS11
397 * Method: C_Logout
398 * Signature: (J)V
399 * Parametermapping: *PKCS11*
400 * @param jlong jSessionHandle CK_SESSION_HANDLE hSession
401 */
402JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1Logout
403 (JNIEnv *env, jobject obj, jlong jSessionHandle)
404{
405 CK_SESSION_HANDLE ckSessionHandle;
406 CK_RV rv;
407
408 CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
409 if (ckpFunctions == NULL) { return; }
410
411 ckSessionHandle = jLongToCKULong(jSessionHandle);
412
413 rv = (*ckpFunctions->C_Logout)(ckSessionHandle);
414 if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
415}
416#endif
417
418/* ************************************************************************** */
419/* Functions for keeping track of notify callbacks */
420/* ************************************************************************** */
421
422#ifndef NO_CALLBACKS
423
424/*
425 * Add the given notify encapsulation object to the list of active notify
426 * objects.
427 * If notifyEncapsulation is NULL, this function does nothing.
428 */
429void putNotifyEntry(JNIEnv *env, CK_SESSION_HANDLE hSession, NotifyEncapsulation *notifyEncapsulation) {
430 NotifyListNode *currentNode, *newNode;
431
432 if (notifyEncapsulation == NULL) {
433 return;
434 }
435
436 newNode = (NotifyListNode *) malloc(sizeof(NotifyListNode));
437 if (newNode == NULL) {
438 throwOutOfMemoryError(env, 0);
439 return;
440 }
441 newNode->hSession = hSession;
442 newNode->notifyEncapsulation = notifyEncapsulation;
443 newNode->next = NULL;
444
445 (*env)->MonitorEnter(env, notifyListLock); /* synchronize access to list */
446
447 if (notifyListHead == NULL) {
448 /* this is the first entry */
449 notifyListHead = newNode;
450 } else {
451 /* go to the last entry; i.e. the first node which's 'next' is NULL.
452 */
453 currentNode = notifyListHead;
454 while (currentNode->next != NULL) {
455 currentNode = currentNode->next;
456 }
457 currentNode->next = newNode;
458 }
459
460 (*env)->MonitorExit(env, notifyListLock); /* synchronize access to list */
461}
462
463/*
464 * Removes the active notifyEncapsulation object used with the given session and
465 * returns it. If there is no notifyEncapsulation active for this session, this
466 * function returns NULL.
467 */
468NotifyEncapsulation * removeNotifyEntry(JNIEnv *env, CK_SESSION_HANDLE hSession) {
469 NotifyEncapsulation *notifyEncapsulation;
470 NotifyListNode *currentNode, *previousNode;
471
472 (*env)->MonitorEnter(env, notifyListLock); /* synchronize access to list */
473
474 if (notifyListHead == NULL) {
475 /* this is the first entry */
476 notifyEncapsulation = NULL;
477 } else {
478 /* Find the node with the wanted session handle. Also stop, when we reach
479 * the last entry; i.e. the first node which's 'next' is NULL.
480 */
481 currentNode = notifyListHead;
482 previousNode = NULL;
483
484 while ((currentNode->hSession != hSession) && (currentNode->next != NULL)) {
485 previousNode = currentNode;
486 currentNode = currentNode->next;
487 }
488
489 if (currentNode->hSession == hSession) {
490 /* We found a entry for the wanted session, now remove it. */
491 if (previousNode == NULL) {
492 /* it's the first node */
493 notifyListHead = currentNode->next;
494 } else {
495 previousNode->next = currentNode->next;
496 }
497 notifyEncapsulation = currentNode->notifyEncapsulation;
498 free(currentNode);
499 } else {
500 /* We did not find a entry for this session */
501 notifyEncapsulation = NULL;
502 }
503 }
504
505 (*env)->MonitorExit(env, notifyListLock); /* synchronize access to list */
506
507 return notifyEncapsulation ;
508}
509
510/*
511
512 * Removes the first notifyEncapsulation object. If there is no notifyEncapsulation,
513 * this function returns NULL.
514 */
515NotifyEncapsulation * removeFirstNotifyEntry(JNIEnv *env) {
516 NotifyEncapsulation *notifyEncapsulation;
517 NotifyListNode *currentNode;
518
519 (*env)->MonitorEnter(env, notifyListLock); /* synchronize access to list */
520
521 if (notifyListHead == NULL) {
522 /* this is the first entry */
523 notifyEncapsulation = NULL;
524 } else {
525 /* Remove the first entry. */
526 currentNode = notifyListHead;
527 notifyListHead = notifyListHead->next;
528 notifyEncapsulation = currentNode->notifyEncapsulation;
529 free(currentNode);
530 }
531
532 (*env)->MonitorExit(env, notifyListLock); /* synchronize access to list */
533
534 return notifyEncapsulation ;
535}
536
537#endif /* NO_CALLBACKS */
538
539#ifndef NO_CALLBACKS
540
541/*
542 * The function handling notify callbacks. It casts the pApplication parameter
543 * back to a NotifyEncapsulation structure and retrieves the Notify object and
544 * the application data from it.
545 *
546 * @param hSession The session, this callback is comming from.
547 * @param event The type of event that occurred.
548 * @param pApplication The application data as passed in upon OpenSession. In
549 this wrapper we always pass in a NotifyEncapsulation
550 object, which holds necessary information for delegating
551 the callback to the Java VM.
552 * @return
553 */
554CK_RV notifyCallback(
555 CK_SESSION_HANDLE hSession, /* the session's handle */
556 CK_NOTIFICATION event,
557 CK_VOID_PTR pApplication /* passed to C_OpenSession */
558)
559{
560 NotifyEncapsulation *notifyEncapsulation;
561 extern JavaVM *jvm;
562 JNIEnv *env;
563 jint returnValue;
564 jlong jSessionHandle;
565 jlong jEvent;
566 jclass ckNotifyClass;
567 jmethodID jmethod;
568 jthrowable pkcs11Exception;
569 jclass pkcs11ExceptionClass;
570 jlong errorCode;
571 CK_RV rv = CKR_OK;
572 int wasAttached = 1;
573
574 if (pApplication == NULL) { return rv ; } /* This should not occur in this wrapper. */
575
576 notifyEncapsulation = (NotifyEncapsulation *) pApplication;
577
578 /* Get the currently running Java VM */
579 if (jvm == NULL) { return rv ; } /* there is no VM running */
580
581 /* Determine, if current thread is already attached */
582 returnValue = (*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION_1_2);
583 if (returnValue == JNI_EDETACHED) {
584 /* thread detached, so attach it */
585 wasAttached = 0;
586 returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
587 } else if (returnValue == JNI_EVERSION) {
588 /* this version of JNI is not supported, so just try to attach */
589 /* we assume it was attached to ensure that this thread is not detached
590 * afterwards even though it should not
591 */
592 wasAttached = 1;
593 returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
594 } else {
595 /* attached */
596 wasAttached = 1;
597 }
598
599 jSessionHandle = ckULongToJLong(hSession);
600 jEvent = ckULongToJLong(event);
601
602 ckNotifyClass = (*env)->FindClass(env, CLASS_NOTIFY);
603 if (ckNotifyClass == NULL) { return rv; }
604 jmethod = (*env)->GetMethodID(env, ckNotifyClass, "CK_NOTIFY", "(JJLjava/lang/Object;)V");
605 if (jmethod == NULL) { return rv; }
606
607 (*env)->CallVoidMethod(env, notifyEncapsulation->jNotifyObject, jmethod,
608 jSessionHandle, jEvent, notifyEncapsulation->jApplicationData);
609
610 /* check, if callback threw an exception */
611 pkcs11Exception = (*env)->ExceptionOccurred(env);
612
613 if (pkcs11Exception != NULL) {
614 /* TBD: clear the pending exception with ExceptionClear? */
615 /* The was an exception thrown, now we get the error-code from it */
616 pkcs11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION);
617 if (pkcs11ExceptionClass == NULL) { return rv; }
618
619 jmethod = (*env)->GetMethodID(env, pkcs11ExceptionClass, "getErrorCode", "()J");
620 if (jmethod == NULL) { return rv; }
621
622 errorCode = (*env)->CallLongMethod(env, pkcs11Exception, jmethod);
623 rv = jLongToCKULong(errorCode);
624 }
625
626 /* if we attached this thread to the VM just for callback, we detach it now */
627 if (wasAttached) {
628 returnValue = (*jvm)->DetachCurrentThread(jvm);
629 }
630
631 return rv ;
632}
633
634#endif /* NO_CALLBACKS */
635