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 |
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 | */ |
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) ¬ifyCallback; |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | |