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 */