1 /*
2  * Copyright (c) 2003, 2019, 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
61 NotifyListNode *notifyListHead = NULL;
62 jobject 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  */
Java_sun_security_pkcs11_wrapper_PKCS11_C_1OpenSession(JNIEnv * env,jobject obj,jlong jSlotID,jlong jFlags,jobject jApplication,jobject jNotify)77 JNIEXPORT 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=%lu", ckSlotID);
121     TRACE1(", flags=%lu", (unsigned long) 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=%lu", (unsigned long) 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  */
Java_sun_security_pkcs11_wrapper_PKCS11_C_1CloseSession(JNIEnv * env,jobject obj,jlong jSessionHandle)165 JNIEXPORT 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  */
Java_sun_security_pkcs11_wrapper_PKCS11_C_1CloseAllSessions(JNIEnv * env,jobject obj,jlong jSlotID)210 JNIEXPORT 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  */
Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetSessionInfo(JNIEnv * env,jobject obj,jlong jSessionHandle)254 JNIEXPORT 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  */
Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetOperationState(JNIEnv * env,jobject obj,jlong jSessionHandle)285 JNIEXPORT 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  */
Java_sun_security_pkcs11_wrapper_PKCS11_C_1SetOperationState(JNIEnv * env,jobject obj,jlong jSessionHandle,jbyteArray jOperationState,jlong jEncryptionKeyHandle,jlong jAuthenticationKeyHandle)330 JNIEXPORT 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  */
Java_sun_security_pkcs11_wrapper_PKCS11_C_1Login(JNIEnv * env,jobject obj,jlong jSessionHandle,jlong jUserType,jcharArray jPin)369 JNIEXPORT 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  */
Java_sun_security_pkcs11_wrapper_PKCS11_C_1Logout(JNIEnv * env,jobject obj,jlong jSessionHandle)402 JNIEXPORT 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  */
putNotifyEntry(JNIEnv * env,CK_SESSION_HANDLE hSession,NotifyEncapsulation * notifyEncapsulation)429 void 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  */
removeNotifyEntry(JNIEnv * env,CK_SESSION_HANDLE hSession)468 NotifyEncapsulation * 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  */
removeFirstNotifyEntry(JNIEnv * env)515 NotifyEncapsulation * 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  */
notifyCallback(CK_SESSION_HANDLE hSession,CK_NOTIFICATION event,CK_VOID_PTR pApplication)554 CK_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