1 /* 2 * Copyright (c) 2003, 2016, 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 /* declare file private functions */ 56 57 ModuleData * getModuleEntry(JNIEnv *env, jobject pkcs11Implementation); 58 int isModulePresent(JNIEnv *env, jobject pkcs11Implementation); 59 void removeAllModuleEntries(JNIEnv *env); 60 61 62 /* ************************************************************************** */ 63 /* Functions for keeping track of currently active and loaded modules */ 64 /* ************************************************************************** */ 65 66 67 /* 68 * Create a new object for locking. 69 */ 70 jobject createLockObject(JNIEnv *env) { 71 jclass jObjectClass; 72 jobject jLockObject; 73 jmethodID jConstructor; 74 75 jObjectClass = (*env)->FindClass(env, "java/lang/Object"); 76 if (jObjectClass == NULL) { return NULL; } 77 jConstructor = (*env)->GetMethodID(env, jObjectClass, "<init>", "()V"); 78 if (jConstructor == NULL) { return NULL; } 79 jLockObject = (*env)->NewObject(env, jObjectClass, jConstructor); 80 if (jLockObject == NULL) { return NULL; } 81 jLockObject = (*env)->NewGlobalRef(env, jLockObject); 82 83 return jLockObject ; 84 } 85 86 /* 87 * Create a new object for locking. 88 */ 89 void destroyLockObject(JNIEnv *env, jobject jLockObject) { 90 if (jLockObject != NULL) { 91 (*env)->DeleteGlobalRef(env, jLockObject); 92 } 93 } 94 95 /* 96 * Add the given pkcs11Implementation object to the list of present modules. 97 * Attach the given data to the entry. If the given pkcs11Implementation is 98 * already in the lsit, just override its old module data with the new one. 99 * None of the arguments can be NULL. If one of the arguments is NULL, this 100 * function does nothing. 101 */ 102 void putModuleEntry(JNIEnv *env, jobject pkcs11Implementation, ModuleData *moduleData) { 103 if (pkcs11Implementation == NULL_PTR) { 104 return ; 105 } 106 if (moduleData == NULL) { 107 return ; 108 } 109 (*env)->SetLongField(env, pkcs11Implementation, pNativeDataID, ptr_to_jlong(moduleData)); 110 } 111 112 113 /* 114 * Get the module data of the entry for the given pkcs11Implementation. Returns 115 * NULL, if the pkcs11Implementation is not in the list. 116 */ 117 ModuleData * getModuleEntry(JNIEnv *env, jobject pkcs11Implementation) { 118 jlong jData; 119 if (pkcs11Implementation == NULL) { 120 return NULL; 121 } 122 jData = (*env)->GetLongField(env, pkcs11Implementation, pNativeDataID); 123 return (ModuleData*)jlong_to_ptr(jData); 124 } 125 126 CK_FUNCTION_LIST_PTR getFunctionList(JNIEnv *env, jobject pkcs11Implementation) { 127 ModuleData *moduleData; 128 CK_FUNCTION_LIST_PTR ckpFunctions; 129 130 moduleData = getModuleEntry(env, pkcs11Implementation); 131 if (moduleData == NULL) { 132 throwDisconnectedRuntimeException(env); 133 return NULL; 134 } 135 ckpFunctions = moduleData->ckFunctionListPtr; 136 return ckpFunctions; 137 } 138 139 140 /* 141 * Returns 1, if the given pkcs11Implementation is in the list. 142 * 0, otherwise. 143 */ 144 int isModulePresent(JNIEnv *env, jobject pkcs11Implementation) { 145 int present; 146 147 ModuleData *moduleData = getModuleEntry(env, pkcs11Implementation); 148 149 present = (moduleData != NULL) ? 1 : 0; 150 151 return present ; 152 } 153 154 155 /* 156 * Removes the entry for the given pkcs11Implementation from the list. Returns 157 * the module's data, after the node was removed. If this function returns NULL 158 * the pkcs11Implementation was not in the list. 159 */ 160 ModuleData * removeModuleEntry(JNIEnv *env, jobject pkcs11Implementation) { 161 ModuleData *moduleData = getModuleEntry(env, pkcs11Implementation); 162 if (moduleData == NULL) { 163 return NULL; 164 } 165 (*env)->SetLongField(env, pkcs11Implementation, pNativeDataID, 0); 166 return moduleData; 167 } 168 169 /* 170 * Removes all present entries from the list of modules and frees all 171 * associated resources. This function is used for clean-up. 172 */ 173 void removeAllModuleEntries(JNIEnv *env) { 174 /* XXX empty */ 175 } 176 177 /* ************************************************************************** */ 178 /* Below there follow the helper functions to support conversions between */ 179 /* Java and Cryptoki types */ 180 /* ************************************************************************** */ 181 182 /* 183 * function to convert a PKCS#11 return value into a PKCS#11Exception 184 * 185 * This function generates a PKCS#11Exception with the returnValue as the errorcode 186 * if the returnValue is not CKR_OK. The functin returns 0, if the returnValue is 187 * CKR_OK. Otherwise, it returns the returnValue as a jLong. 188 * 189 * @param env - used to call JNI funktions and to get the Exception class 190 * @param returnValue - of the PKCS#11 function 191 */ 192 jlong ckAssertReturnValueOK(JNIEnv *env, CK_RV returnValue) 193 { 194 jclass jPKCS11ExceptionClass; 195 jmethodID jConstructor; 196 jthrowable jPKCS11Exception; 197 jlong jErrorCode = 0L; 198 199 if (returnValue != CKR_OK) { 200 jErrorCode = ckULongToJLong(returnValue); 201 jPKCS11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION); 202 if (jPKCS11ExceptionClass != NULL) { 203 jConstructor = (*env)->GetMethodID(env, jPKCS11ExceptionClass, "<init>", "(J)V"); 204 if (jConstructor != NULL) { 205 jPKCS11Exception = (jthrowable) (*env)->NewObject(env, jPKCS11ExceptionClass, jConstructor, jErrorCode); 206 if (jPKCS11Exception != NULL) { 207 (*env)->Throw(env, jPKCS11Exception); 208 } 209 } 210 } 211 (*env)->DeleteLocalRef(env, jPKCS11ExceptionClass); 212 } 213 return jErrorCode ; 214 } 215 216 217 /* 218 * Throws a Java Exception by name 219 */ 220 void throwByName(JNIEnv *env, const char *name, const char *msg) 221 { 222 jclass cls = (*env)->FindClass(env, name); 223 224 if (cls != 0) /* Otherwise an exception has already been thrown */ 225 (*env)->ThrowNew(env, cls, msg); 226 } 227 228 /* 229 * Throws java.lang.OutOfMemoryError 230 */ 231 void throwOutOfMemoryError(JNIEnv *env, const char *msg) 232 { 233 throwByName(env, "java/lang/OutOfMemoryError", msg); 234 } 235 236 /* 237 * Throws java.lang.NullPointerException 238 */ 239 void throwNullPointerException(JNIEnv *env, const char *msg) 240 { 241 throwByName(env, "java/lang/NullPointerException", msg); 242 } 243 244 /* 245 * Throws java.io.IOException 246 */ 247 void throwIOException(JNIEnv *env, const char *msg) 248 { 249 throwByName(env, "java/io/IOException", msg); 250 } 251 252 /* 253 * This function simply throws a PKCS#11RuntimeException with the given 254 * string as its message. 255 * 256 * @param env Used to call JNI funktions and to get the Exception class. 257 * @param jmessage The message string of the Exception object. 258 */ 259 void throwPKCS11RuntimeException(JNIEnv *env, const char *message) 260 { 261 throwByName(env, CLASS_PKCS11RUNTIMEEXCEPTION, message); 262 } 263 264 /* 265 * This function simply throws a PKCS#11RuntimeException. The message says that 266 * the object is not connected to the module. 267 * 268 * @param env Used to call JNI funktions and to get the Exception class. 269 */ 270 void throwDisconnectedRuntimeException(JNIEnv *env) 271 { 272 throwPKCS11RuntimeException(env, "This object is not connected to a module."); 273 } 274 275 /* This function frees the specified CK_ATTRIBUTE array. 276 * 277 * @param attrPtr pointer to the to-be-freed CK_ATTRIBUTE array. 278 * @param len the length of the array 279 */ 280 void freeCKAttributeArray(CK_ATTRIBUTE_PTR attrPtr, int len) 281 { 282 int i; 283 284 for (i=0; i<len; i++) { 285 if (attrPtr[i].pValue != NULL_PTR) { 286 free(attrPtr[i].pValue); 287 } 288 } 289 free(attrPtr); 290 } 291 292 /* 293 * the following functions convert Java arrays to PKCS#11 array pointers and 294 * their array length and vice versa 295 * 296 * void j<Type>ArrayToCK<Type>Array(JNIEnv *env, 297 * const j<Type>Array jArray, 298 * CK_<Type>_PTR *ckpArray, 299 * CK_ULONG_PTR ckLength); 300 * 301 * j<Type>Array ck<Type>ArrayToJ<Type>Array(JNIEnv *env, 302 * const CK_<Type>_PTR ckpArray, 303 * CK_ULONG ckLength); 304 * 305 * PKCS#11 arrays consist always of a pointer to the beginning of the array and 306 * the array length whereas Java arrays carry their array length. 307 * 308 * The Functions to convert a Java array to a PKCS#11 array are void functions. 309 * Their arguments are the Java array object to convert, the reference to the 310 * array pointer, where the new PKCS#11 array should be stored and the reference 311 * to the array length where the PKCS#11 array length should be stored. These two 312 * references must not be NULL_PTR. 313 * 314 * The functions first obtain the array length of the Java array and then allocate 315 * the memory for the PKCS#11 array and set the array length. Then each element 316 * gets converted depending on their type. After use the allocated memory of the 317 * PKCS#11 array has to be explicitly freed. 318 * 319 * The Functions to convert a PKCS#11 array to a Java array get the PKCS#11 array 320 * pointer and the array length and they return the new Java array object. The 321 * Java array does not need to get freed after use. 322 */ 323 324 /* 325 * converts a jbooleanArray to a CK_BBOOL array. The allocated memory has to be freed after use! 326 * 327 * @param env - used to call JNI funktions to get the array informtaion 328 * @param jArray - the Java array to convert 329 * @param ckpArray - the reference, where the pointer to the new CK_BBOOL array will be stored 330 * @param ckpLength - the reference, where the array length will be stored 331 */ 332 void jBooleanArrayToCKBBoolArray(JNIEnv *env, const jbooleanArray jArray, CK_BBOOL **ckpArray, CK_ULONG_PTR ckpLength) 333 { 334 jboolean* jpTemp; 335 CK_ULONG i; 336 337 if(jArray == NULL) { 338 *ckpArray = NULL_PTR; 339 *ckpLength = 0L; 340 return; 341 } 342 *ckpLength = (*env)->GetArrayLength(env, jArray); 343 jpTemp = (jboolean*) malloc((*ckpLength) * sizeof(jboolean)); 344 if (jpTemp == NULL) { 345 throwOutOfMemoryError(env, 0); 346 return; 347 } 348 (*env)->GetBooleanArrayRegion(env, jArray, 0, *ckpLength, jpTemp); 349 if ((*env)->ExceptionCheck(env)) { 350 free(jpTemp); 351 return; 352 } 353 354 *ckpArray = (CK_BBOOL*) malloc ((*ckpLength) * sizeof(CK_BBOOL)); 355 if (*ckpArray == NULL) { 356 free(jpTemp); 357 throwOutOfMemoryError(env, 0); 358 return; 359 } 360 for (i=0; i<(*ckpLength); i++) { 361 (*ckpArray)[i] = jBooleanToCKBBool(jpTemp[i]); 362 } 363 free(jpTemp); 364 } 365 366 /* 367 * converts a jbyteArray to a CK_BYTE array. The allocated memory has to be freed after use! 368 * 369 * @param env - used to call JNI funktions to get the array informtaion 370 * @param jArray - the Java array to convert 371 * @param ckpArray - the reference, where the pointer to the new CK_BYTE array will be stored 372 * @param ckpLength - the reference, where the array length will be stored 373 */ 374 void jByteArrayToCKByteArray(JNIEnv *env, const jbyteArray jArray, CK_BYTE_PTR *ckpArray, CK_ULONG_PTR ckpLength) 375 { 376 jbyte* jpTemp; 377 CK_ULONG i; 378 379 if(jArray == NULL) { 380 *ckpArray = NULL_PTR; 381 *ckpLength = 0L; 382 return; 383 } 384 *ckpLength = (*env)->GetArrayLength(env, jArray); 385 jpTemp = (jbyte*) malloc((*ckpLength) * sizeof(jbyte)); 386 if (jpTemp == NULL) { 387 throwOutOfMemoryError(env, 0); 388 return; 389 } 390 (*env)->GetByteArrayRegion(env, jArray, 0, *ckpLength, jpTemp); 391 if ((*env)->ExceptionCheck(env)) { 392 free(jpTemp); 393 return; 394 } 395 396 /* if CK_BYTE is the same size as jbyte, we save an additional copy */ 397 if (sizeof(CK_BYTE) == sizeof(jbyte)) { 398 *ckpArray = (CK_BYTE_PTR) jpTemp; 399 } else { 400 *ckpArray = (CK_BYTE_PTR) malloc ((*ckpLength) * sizeof(CK_BYTE)); 401 if (*ckpArray == NULL) { 402 free(jpTemp); 403 throwOutOfMemoryError(env, 0); 404 return; 405 } 406 for (i=0; i<(*ckpLength); i++) { 407 (*ckpArray)[i] = jByteToCKByte(jpTemp[i]); 408 } 409 free(jpTemp); 410 } 411 } 412 413 /* 414 * converts a jlongArray to a CK_ULONG array. The allocated memory has to be freed after use! 415 * 416 * @param env - used to call JNI funktions to get the array informtaion 417 * @param jArray - the Java array to convert 418 * @param ckpArray - the reference, where the pointer to the new CK_ULONG array will be stored 419 * @param ckpLength - the reference, where the array length will be stored 420 */ 421 void jLongArrayToCKULongArray(JNIEnv *env, const jlongArray jArray, CK_ULONG_PTR *ckpArray, CK_ULONG_PTR ckpLength) 422 { 423 jlong* jTemp; 424 CK_ULONG i; 425 426 if(jArray == NULL) { 427 *ckpArray = NULL_PTR; 428 *ckpLength = 0L; 429 return; 430 } 431 *ckpLength = (*env)->GetArrayLength(env, jArray); 432 jTemp = (jlong*) malloc((*ckpLength) * sizeof(jlong)); 433 if (jTemp == NULL) { 434 throwOutOfMemoryError(env, 0); 435 return; 436 } 437 (*env)->GetLongArrayRegion(env, jArray, 0, *ckpLength, jTemp); 438 if ((*env)->ExceptionCheck(env)) { 439 free(jTemp); 440 return; 441 } 442 443 *ckpArray = (CK_ULONG_PTR) malloc (*ckpLength * sizeof(CK_ULONG)); 444 if (*ckpArray == NULL) { 445 free(jTemp); 446 throwOutOfMemoryError(env, 0); 447 return; 448 } 449 for (i=0; i<(*ckpLength); i++) { 450 (*ckpArray)[i] = jLongToCKULong(jTemp[i]); 451 } 452 free(jTemp); 453 } 454 455 /* 456 * converts a jcharArray to a CK_CHAR array. The allocated memory has to be freed after use! 457 * 458 * @param env - used to call JNI funktions to get the array informtaion 459 * @param jArray - the Java array to convert 460 * @param ckpArray - the reference, where the pointer to the new CK_CHAR array will be stored 461 * @param ckpLength - the reference, where the array length will be stored 462 */ 463 void jCharArrayToCKCharArray(JNIEnv *env, const jcharArray jArray, CK_CHAR_PTR *ckpArray, CK_ULONG_PTR ckpLength) 464 { 465 jchar* jpTemp; 466 CK_ULONG i; 467 468 if(jArray == NULL) { 469 *ckpArray = NULL_PTR; 470 *ckpLength = 0L; 471 return; 472 } 473 *ckpLength = (*env)->GetArrayLength(env, jArray); 474 jpTemp = (jchar*) malloc((*ckpLength) * sizeof(jchar)); 475 if (jpTemp == NULL) { 476 throwOutOfMemoryError(env, 0); 477 return; 478 } 479 (*env)->GetCharArrayRegion(env, jArray, 0, *ckpLength, jpTemp); 480 if ((*env)->ExceptionCheck(env)) { 481 free(jpTemp); 482 return; 483 } 484 485 *ckpArray = (CK_CHAR_PTR) malloc (*ckpLength * sizeof(CK_CHAR)); 486 if (*ckpArray == NULL) { 487 free(jpTemp); 488 throwOutOfMemoryError(env, 0); 489 return; 490 } 491 for (i=0; i<(*ckpLength); i++) { 492 (*ckpArray)[i] = jCharToCKChar(jpTemp[i]); 493 } 494 free(jpTemp); 495 } 496 497 /* 498 * converts a jcharArray to a CK_UTF8CHAR array. The allocated memory has to be freed after use! 499 * 500 * @param env - used to call JNI funktions to get the array informtaion 501 * @param jArray - the Java array to convert 502 * @param ckpArray - the reference, where the pointer to the new CK_UTF8CHAR array will be stored 503 * @param ckpLength - the reference, where the array length will be stored 504 */ 505 void jCharArrayToCKUTF8CharArray(JNIEnv *env, const jcharArray jArray, CK_UTF8CHAR_PTR *ckpArray, CK_ULONG_PTR ckpLength) 506 { 507 jchar* jTemp; 508 CK_ULONG i; 509 510 if(jArray == NULL) { 511 *ckpArray = NULL_PTR; 512 *ckpLength = 0L; 513 return; 514 } 515 *ckpLength = (*env)->GetArrayLength(env, jArray); 516 jTemp = (jchar*) malloc((*ckpLength) * sizeof(jchar)); 517 if (jTemp == NULL) { 518 throwOutOfMemoryError(env, 0); 519 return; 520 } 521 (*env)->GetCharArrayRegion(env, jArray, 0, *ckpLength, jTemp); 522 if ((*env)->ExceptionCheck(env)) { 523 free(jTemp); 524 return; 525 } 526 527 *ckpArray = (CK_UTF8CHAR_PTR) malloc (*ckpLength * sizeof(CK_UTF8CHAR)); 528 if (*ckpArray == NULL) { 529 free(jTemp); 530 throwOutOfMemoryError(env, 0); 531 return; 532 } 533 for (i=0; i<(*ckpLength); i++) { 534 (*ckpArray)[i] = jCharToCKUTF8Char(jTemp[i]); 535 } 536 free(jTemp); 537 } 538 539 /* 540 * converts a jstring to a CK_CHAR array. The allocated memory has to be freed after use! 541 * 542 * @param env - used to call JNI funktions to get the array informtaion 543 * @param jArray - the Java array to convert 544 * @param ckpArray - the reference, where the pointer to the new CK_CHAR array will be stored 545 * @param ckpLength - the reference, where the array length will be stored 546 */ 547 void jStringToCKUTF8CharArray(JNIEnv *env, const jstring jArray, CK_UTF8CHAR_PTR *ckpArray, CK_ULONG_PTR ckpLength) 548 { 549 const char* pCharArray; 550 jboolean isCopy; 551 552 if(jArray == NULL) { 553 *ckpArray = NULL_PTR; 554 *ckpLength = 0L; 555 return; 556 } 557 558 pCharArray = (*env)->GetStringUTFChars(env, jArray, &isCopy); 559 if (pCharArray == NULL) { return; } 560 561 *ckpLength = (CK_ULONG) strlen(pCharArray); 562 *ckpArray = (CK_UTF8CHAR_PTR) malloc((*ckpLength + 1) * sizeof(CK_UTF8CHAR)); 563 if (*ckpArray == NULL) { 564 (*env)->ReleaseStringUTFChars(env, (jstring) jArray, pCharArray); 565 throwOutOfMemoryError(env, 0); 566 return; 567 } 568 strcpy((char*)*ckpArray, pCharArray); 569 (*env)->ReleaseStringUTFChars(env, (jstring) jArray, pCharArray); 570 } 571 572 /* 573 * converts a jobjectArray with Java Attributes to a CK_ATTRIBUTE array. The allocated memory 574 * has to be freed after use! 575 * 576 * @param env - used to call JNI funktions to get the array informtaion 577 * @param jArray - the Java Attribute array (template) to convert 578 * @param ckpArray - the reference, where the pointer to the new CK_ATTRIBUTE array will be 579 * stored 580 * @param ckpLength - the reference, where the array length will be stored 581 */ 582 void jAttributeArrayToCKAttributeArray(JNIEnv *env, jobjectArray jArray, CK_ATTRIBUTE_PTR *ckpArray, CK_ULONG_PTR ckpLength) 583 { 584 CK_ULONG i; 585 jlong jLength; 586 jobject jAttribute; 587 588 TRACE0("\nDEBUG: jAttributeArrayToCKAttributeArray"); 589 if (jArray == NULL) { 590 *ckpArray = NULL_PTR; 591 *ckpLength = 0L; 592 return; 593 } 594 jLength = (*env)->GetArrayLength(env, jArray); 595 *ckpLength = jLongToCKULong(jLength); 596 *ckpArray = (CK_ATTRIBUTE_PTR) malloc(*ckpLength * sizeof(CK_ATTRIBUTE)); 597 if (*ckpArray == NULL) { 598 throwOutOfMemoryError(env, 0); 599 return; 600 } 601 TRACE1(", converting %d attributes", jLength); 602 for (i=0; i<(*ckpLength); i++) { 603 TRACE1(", getting %d. attribute", i); 604 jAttribute = (*env)->GetObjectArrayElement(env, jArray, i); 605 if ((*env)->ExceptionCheck(env)) { 606 freeCKAttributeArray(*ckpArray, i); 607 return; 608 } 609 TRACE1(", jAttribute = %d", jAttribute); 610 TRACE1(", converting %d. attribute", i); 611 (*ckpArray)[i] = jAttributeToCKAttribute(env, jAttribute); 612 if ((*env)->ExceptionCheck(env)) { 613 freeCKAttributeArray(*ckpArray, i); 614 return; 615 } 616 } 617 TRACE0("FINISHED\n"); 618 } 619 620 /* 621 * converts a CK_BYTE array and its length to a jbyteArray. 622 * 623 * @param env - used to call JNI funktions to create the new Java array 624 * @param ckpArray - the pointer to the CK_BYTE array to convert 625 * @param ckpLength - the length of the array to convert 626 * @return - the new Java byte array or NULL if error occurred 627 */ 628 jbyteArray ckByteArrayToJByteArray(JNIEnv *env, const CK_BYTE_PTR ckpArray, CK_ULONG ckLength) 629 { 630 CK_ULONG i; 631 jbyte* jpTemp; 632 jbyteArray jArray; 633 634 /* if CK_BYTE is the same size as jbyte, we save an additional copy */ 635 if (sizeof(CK_BYTE) == sizeof(jbyte)) { 636 jpTemp = (jbyte*) ckpArray; 637 } else { 638 jpTemp = (jbyte*) malloc((ckLength) * sizeof(jbyte)); 639 if (jpTemp == NULL) { 640 throwOutOfMemoryError(env, 0); 641 return NULL; 642 } 643 for (i=0; i<ckLength; i++) { 644 jpTemp[i] = ckByteToJByte(ckpArray[i]); 645 } 646 } 647 648 jArray = (*env)->NewByteArray(env, ckULongToJSize(ckLength)); 649 if (jArray != NULL) { 650 (*env)->SetByteArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp); 651 } 652 653 if (sizeof(CK_BYTE) != sizeof(jbyte)) { free(jpTemp); } 654 655 return jArray ; 656 } 657 658 /* 659 * converts a CK_ULONG array and its length to a jlongArray. 660 * 661 * @param env - used to call JNI funktions to create the new Java array 662 * @param ckpArray - the pointer to the CK_ULONG array to convert 663 * @param ckpLength - the length of the array to convert 664 * @return - the new Java long array 665 */ 666 jlongArray ckULongArrayToJLongArray(JNIEnv *env, const CK_ULONG_PTR ckpArray, CK_ULONG ckLength) 667 { 668 CK_ULONG i; 669 jlong* jpTemp; 670 jlongArray jArray; 671 672 jpTemp = (jlong*) malloc((ckLength) * sizeof(jlong)); 673 if (jpTemp == NULL) { 674 throwOutOfMemoryError(env, 0); 675 return NULL; 676 } 677 for (i=0; i<ckLength; i++) { 678 jpTemp[i] = ckLongToJLong(ckpArray[i]); 679 } 680 jArray = (*env)->NewLongArray(env, ckULongToJSize(ckLength)); 681 if (jArray != NULL) { 682 (*env)->SetLongArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp); 683 } 684 free(jpTemp); 685 686 return jArray ; 687 } 688 689 /* 690 * converts a CK_CHAR array and its length to a jcharArray. 691 * 692 * @param env - used to call JNI funktions to create the new Java array 693 * @param ckpArray - the pointer to the CK_CHAR array to convert 694 * @param ckpLength - the length of the array to convert 695 * @return - the new Java char array 696 */ 697 jcharArray ckCharArrayToJCharArray(JNIEnv *env, const CK_CHAR_PTR ckpArray, CK_ULONG ckLength) 698 { 699 CK_ULONG i; 700 jchar* jpTemp; 701 jcharArray jArray; 702 703 jpTemp = (jchar*) malloc(ckLength * sizeof(jchar)); 704 if (jpTemp == NULL) { 705 throwOutOfMemoryError(env, 0); 706 return NULL; 707 } 708 for (i=0; i<ckLength; i++) { 709 jpTemp[i] = ckCharToJChar(ckpArray[i]); 710 } 711 jArray = (*env)->NewCharArray(env, ckULongToJSize(ckLength)); 712 if (jArray != NULL) { 713 (*env)->SetCharArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp); 714 } 715 free(jpTemp); 716 717 return jArray ; 718 } 719 720 /* 721 * converts a CK_UTF8CHAR array and its length to a jcharArray. 722 * 723 * @param env - used to call JNI funktions to create the new Java array 724 * @param ckpArray - the pointer to the CK_UTF8CHAR array to convert 725 * @param ckpLength - the length of the array to convert 726 * @return - the new Java char array 727 */ 728 jcharArray ckUTF8CharArrayToJCharArray(JNIEnv *env, const CK_UTF8CHAR_PTR ckpArray, CK_ULONG ckLength) 729 { 730 CK_ULONG i; 731 jchar* jpTemp; 732 jcharArray jArray; 733 734 jpTemp = (jchar*) malloc(ckLength * sizeof(jchar)); 735 if (jpTemp == NULL) { 736 throwOutOfMemoryError(env, 0); 737 return NULL; 738 } 739 for (i=0; i<ckLength; i++) { 740 jpTemp[i] = ckUTF8CharToJChar(ckpArray[i]); 741 } 742 jArray = (*env)->NewCharArray(env, ckULongToJSize(ckLength)); 743 if (jArray != NULL) { 744 (*env)->SetCharArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp); 745 } 746 free(jpTemp); 747 748 return jArray ; 749 } 750 751 /* 752 * the following functions convert Java objects to PKCS#11 pointers and the 753 * length in bytes and vice versa 754 * 755 * CK_<Type>_PTR j<Object>ToCK<Type>Ptr(JNIEnv *env, jobject jObject); 756 * 757 * jobject ck<Type>PtrToJ<Object>(JNIEnv *env, const CK_<Type>_PTR ckpValue); 758 * 759 * The functions that convert a Java object to a PKCS#11 pointer first allocate 760 * the memory for the PKCS#11 pointer. Then they set each element corresponding 761 * to the fields in the Java object to convert. After use the allocated memory of 762 * the PKCS#11 pointer has to be explicitly freed. 763 * 764 * The functions to convert a PKCS#11 pointer to a Java object create a new Java 765 * object first and than they set all fields in the object depending on the values 766 * of the type or structure where the PKCS#11 pointer points to. 767 */ 768 769 /* 770 * converts a CK_BBOOL pointer to a Java boolean Object. 771 * 772 * @param env - used to call JNI funktions to create the new Java object 773 * @param ckpValue - the pointer to the CK_BBOOL value 774 * @return - the new Java boolean object with the boolean value 775 */ 776 jobject ckBBoolPtrToJBooleanObject(JNIEnv *env, const CK_BBOOL *ckpValue) 777 { 778 jclass jValueObjectClass; 779 jmethodID jConstructor; 780 jobject jValueObject; 781 jboolean jValue; 782 783 jValueObjectClass = (*env)->FindClass(env, "java/lang/Boolean"); 784 if (jValueObjectClass == NULL) { return NULL; } 785 jConstructor = (*env)->GetMethodID(env, jValueObjectClass, "<init>", "(Z)V"); 786 if (jConstructor == NULL) { return NULL; } 787 jValue = ckBBoolToJBoolean(*ckpValue); 788 jValueObject = (*env)->NewObject(env, jValueObjectClass, jConstructor, jValue); 789 790 return jValueObject ; 791 } 792 793 /* 794 * converts a CK_ULONG pointer to a Java long Object. 795 * 796 * @param env - used to call JNI funktions to create the new Java object 797 * @param ckpValue - the pointer to the CK_ULONG value 798 * @return - the new Java long object with the long value 799 */ 800 jobject ckULongPtrToJLongObject(JNIEnv *env, const CK_ULONG_PTR ckpValue) 801 { 802 jclass jValueObjectClass; 803 jmethodID jConstructor; 804 jobject jValueObject; 805 jlong jValue; 806 807 jValueObjectClass = (*env)->FindClass(env, "java/lang/Long"); 808 if (jValueObjectClass == NULL) { return NULL; } 809 jConstructor = (*env)->GetMethodID(env, jValueObjectClass, "<init>", "(J)V"); 810 if (jConstructor == NULL) { return NULL; } 811 jValue = ckULongToJLong(*ckpValue); 812 jValueObject = (*env)->NewObject(env, jValueObjectClass, jConstructor, jValue); 813 814 return jValueObject ; 815 } 816 817 /* 818 * converts a Java boolean object into a pointer to a CK_BBOOL value. The memory has to be 819 * freed after use! 820 * 821 * @param env - used to call JNI funktions to get the value out of the Java object 822 * @param jObject - the "java/lang/Boolean" object to convert 823 * @return - the pointer to the new CK_BBOOL value 824 */ 825 CK_BBOOL* jBooleanObjectToCKBBoolPtr(JNIEnv *env, jobject jObject) 826 { 827 jclass jObjectClass; 828 jmethodID jValueMethod; 829 jboolean jValue; 830 CK_BBOOL *ckpValue; 831 832 jObjectClass = (*env)->FindClass(env, "java/lang/Boolean"); 833 if (jObjectClass == NULL) { return NULL; } 834 jValueMethod = (*env)->GetMethodID(env, jObjectClass, "booleanValue", "()Z"); 835 if (jValueMethod == NULL) { return NULL; } 836 jValue = (*env)->CallBooleanMethod(env, jObject, jValueMethod); 837 ckpValue = (CK_BBOOL *) malloc(sizeof(CK_BBOOL)); 838 if (ckpValue == NULL) { 839 throwOutOfMemoryError(env, 0); 840 return NULL; 841 } 842 *ckpValue = jBooleanToCKBBool(jValue); 843 844 return ckpValue ; 845 } 846 847 /* 848 * converts a Java byte object into a pointer to a CK_BYTE value. The memory has to be 849 * freed after use! 850 * 851 * @param env - used to call JNI funktions to get the value out of the Java object 852 * @param jObject - the "java/lang/Byte" object to convert 853 * @return - the pointer to the new CK_BYTE value 854 */ 855 CK_BYTE_PTR jByteObjectToCKBytePtr(JNIEnv *env, jobject jObject) 856 { 857 jclass jObjectClass; 858 jmethodID jValueMethod; 859 jbyte jValue; 860 CK_BYTE_PTR ckpValue; 861 862 jObjectClass = (*env)->FindClass(env, "java/lang/Byte"); 863 if (jObjectClass == NULL) { return NULL; } 864 jValueMethod = (*env)->GetMethodID(env, jObjectClass, "byteValue", "()B"); 865 if (jValueMethod == NULL) { return NULL; } 866 jValue = (*env)->CallByteMethod(env, jObject, jValueMethod); 867 ckpValue = (CK_BYTE_PTR) malloc(sizeof(CK_BYTE)); 868 if (ckpValue == NULL) { 869 throwOutOfMemoryError(env, 0); 870 return NULL; 871 } 872 *ckpValue = jByteToCKByte(jValue); 873 return ckpValue ; 874 } 875 876 /* 877 * converts a Java integer object into a pointer to a CK_ULONG value. The memory has to be 878 * freed after use! 879 * 880 * @param env - used to call JNI funktions to get the value out of the Java object 881 * @param jObject - the "java/lang/Integer" object to convert 882 * @return - the pointer to the new CK_ULONG value 883 */ 884 CK_ULONG* jIntegerObjectToCKULongPtr(JNIEnv *env, jobject jObject) 885 { 886 jclass jObjectClass; 887 jmethodID jValueMethod; 888 jint jValue; 889 CK_ULONG *ckpValue; 890 891 jObjectClass = (*env)->FindClass(env, "java/lang/Integer"); 892 if (jObjectClass == NULL) { return NULL; } 893 jValueMethod = (*env)->GetMethodID(env, jObjectClass, "intValue", "()I"); 894 if (jValueMethod == NULL) { return NULL; } 895 jValue = (*env)->CallIntMethod(env, jObject, jValueMethod); 896 ckpValue = (CK_ULONG *) malloc(sizeof(CK_ULONG)); 897 if (ckpValue == NULL) { 898 throwOutOfMemoryError(env, 0); 899 return NULL; 900 } 901 *ckpValue = jLongToCKLong(jValue); 902 return ckpValue ; 903 } 904 905 /* 906 * converts a Java long object into a pointer to a CK_ULONG value. The memory has to be 907 * freed after use! 908 * 909 * @param env - used to call JNI funktions to get the value out of the Java object 910 * @param jObject - the "java/lang/Long" object to convert 911 * @return - the pointer to the new CK_ULONG value 912 */ 913 CK_ULONG* jLongObjectToCKULongPtr(JNIEnv *env, jobject jObject) 914 { 915 jclass jObjectClass; 916 jmethodID jValueMethod; 917 jlong jValue; 918 CK_ULONG *ckpValue; 919 920 jObjectClass = (*env)->FindClass(env, "java/lang/Long"); 921 if (jObjectClass == NULL) { return NULL; } 922 jValueMethod = (*env)->GetMethodID(env, jObjectClass, "longValue", "()J"); 923 if (jValueMethod == NULL) { return NULL; } 924 jValue = (*env)->CallLongMethod(env, jObject, jValueMethod); 925 ckpValue = (CK_ULONG *) malloc(sizeof(CK_ULONG)); 926 if (ckpValue == NULL) { 927 throwOutOfMemoryError(env, 0); 928 return NULL; 929 } 930 *ckpValue = jLongToCKULong(jValue); 931 932 return ckpValue ; 933 } 934 935 /* 936 * converts a Java char object into a pointer to a CK_CHAR value. The memory has to be 937 * freed after use! 938 * 939 * @param env - used to call JNI funktions to get the value out of the Java object 940 * @param jObject - the "java/lang/Char" object to convert 941 * @return - the pointer to the new CK_CHAR value 942 */ 943 CK_CHAR_PTR jCharObjectToCKCharPtr(JNIEnv *env, jobject jObject) 944 { 945 jclass jObjectClass; 946 jmethodID jValueMethod; 947 jchar jValue; 948 CK_CHAR_PTR ckpValue; 949 950 jObjectClass = (*env)->FindClass(env, "java/lang/Char"); 951 if (jObjectClass == NULL) { return NULL; } 952 jValueMethod = (*env)->GetMethodID(env, jObjectClass, "charValue", "()C"); 953 if (jValueMethod == NULL) { return NULL; } 954 jValue = (*env)->CallCharMethod(env, jObject, jValueMethod); 955 ckpValue = (CK_CHAR_PTR) malloc(sizeof(CK_CHAR)); 956 if (ckpValue == NULL) { 957 throwOutOfMemoryError(env, 0); 958 return NULL; 959 } 960 *ckpValue = jCharToCKChar(jValue); 961 962 return ckpValue ; 963 } 964 965 /* 966 * converts a Java object into a pointer to CK-type or a CK-structure with the length in Bytes. 967 * The memory of *ckpObjectPtr to be freed after use! This function is only used by 968 * jAttributeToCKAttribute by now. 969 * 970 * @param env - used to call JNI funktions to get the Java classes and objects 971 * @param jObject - the Java object to convert 972 * @param ckpObjectPtr - the reference of the new pointer to the new CK-value or CK-structure 973 * @param ckpLength - the reference of the length in bytes of the new CK-value or CK-structure 974 */ 975 void jObjectToPrimitiveCKObjectPtrPtr(JNIEnv *env, jobject jObject, CK_VOID_PTR *ckpObjectPtr, CK_ULONG *ckpLength) 976 { 977 jclass jLongClass, jBooleanClass, jByteArrayClass, jCharArrayClass; 978 jclass jByteClass, jDateClass, jCharacterClass, jIntegerClass; 979 jclass jBooleanArrayClass, jIntArrayClass, jLongArrayClass; 980 jclass jStringClass; 981 jclass jObjectClass, jClassClass; 982 CK_VOID_PTR ckpVoid = *ckpObjectPtr; 983 jmethodID jMethod; 984 jobject jClassObject; 985 jstring jClassNameString; 986 char *classNameString, *exceptionMsgPrefix, *exceptionMsg; 987 988 TRACE0("\nDEBUG: jObjectToPrimitiveCKObjectPtrPtr"); 989 if (jObject == NULL) { 990 *ckpObjectPtr = NULL; 991 *ckpLength = 0; 992 return; 993 } 994 995 jLongClass = (*env)->FindClass(env, "java/lang/Long"); 996 if (jLongClass == NULL) { return; } 997 if ((*env)->IsInstanceOf(env, jObject, jLongClass)) { 998 *ckpObjectPtr = jLongObjectToCKULongPtr(env, jObject); 999 *ckpLength = sizeof(CK_ULONG); 1000 TRACE1("<converted long value %X>", *((CK_ULONG *) *ckpObjectPtr)); 1001 return; 1002 } 1003 1004 jBooleanClass = (*env)->FindClass(env, "java/lang/Boolean"); 1005 if (jBooleanClass == NULL) { return; } 1006 if ((*env)->IsInstanceOf(env, jObject, jBooleanClass)) { 1007 *ckpObjectPtr = jBooleanObjectToCKBBoolPtr(env, jObject); 1008 *ckpLength = sizeof(CK_BBOOL); 1009 TRACE0(" <converted boolean value "); 1010 TRACE0((*((CK_BBOOL *) *ckpObjectPtr) == TRUE) ? "TRUE>" : "FALSE>"); 1011 return; 1012 } 1013 1014 jByteArrayClass = (*env)->FindClass(env, "[B"); 1015 if (jByteArrayClass == NULL) { return; } 1016 if ((*env)->IsInstanceOf(env, jObject, jByteArrayClass)) { 1017 jByteArrayToCKByteArray(env, jObject, (CK_BYTE_PTR*)ckpObjectPtr, ckpLength); 1018 return; 1019 } 1020 1021 jCharArrayClass = (*env)->FindClass(env, "[C"); 1022 if (jCharArrayClass == NULL) { return; } 1023 if ((*env)->IsInstanceOf(env, jObject, jCharArrayClass)) { 1024 jCharArrayToCKUTF8CharArray(env, jObject, (CK_UTF8CHAR_PTR*)ckpObjectPtr, ckpLength); 1025 return; 1026 } 1027 1028 jByteClass = (*env)->FindClass(env, "java/lang/Byte"); 1029 if (jByteClass == NULL) { return; } 1030 if ((*env)->IsInstanceOf(env, jObject, jByteClass)) { 1031 *ckpObjectPtr = jByteObjectToCKBytePtr(env, jObject); 1032 *ckpLength = sizeof(CK_BYTE); 1033 TRACE1("<converted byte value %X>", *((CK_BYTE *) *ckpObjectPtr)); 1034 return; 1035 } 1036 1037 jDateClass = (*env)->FindClass(env, CLASS_DATE); 1038 if (jDateClass == NULL) { return; } 1039 if ((*env)->IsInstanceOf(env, jObject, jDateClass)) { 1040 *ckpObjectPtr = jDateObjectPtrToCKDatePtr(env, jObject); 1041 *ckpLength = sizeof(CK_DATE); 1042 TRACE3("<converted date value %.4s-%.2s-%.2s>", (*((CK_DATE *) *ckpObjectPtr)).year, (*((CK_DATE *) *ckpObjectPtr)).month, (*((CK_DATE *) *ckpObjectPtr)).day); 1043 return; 1044 } 1045 1046 jCharacterClass = (*env)->FindClass(env, "java/lang/Character"); 1047 if (jCharacterClass == NULL) { return; } 1048 if ((*env)->IsInstanceOf(env, jObject, jCharacterClass)) { 1049 *ckpObjectPtr = jCharObjectToCKCharPtr(env, jObject); 1050 *ckpLength = sizeof(CK_UTF8CHAR); 1051 TRACE1("<converted char value %c>", *((CK_CHAR *) *ckpObjectPtr)); 1052 return; 1053 } 1054 1055 jIntegerClass = (*env)->FindClass(env, "java/lang/Integer"); 1056 if (jIntegerClass == NULL) { return; } 1057 if ((*env)->IsInstanceOf(env, jObject, jIntegerClass)) { 1058 *ckpObjectPtr = jIntegerObjectToCKULongPtr(env, jObject); 1059 *ckpLength = sizeof(CK_ULONG); 1060 TRACE1("<converted integer value %X>", *((CK_ULONG *) *ckpObjectPtr)); 1061 return; 1062 } 1063 1064 jBooleanArrayClass = (*env)->FindClass(env, "[Z"); 1065 if (jBooleanArrayClass == NULL) { return; } 1066 if ((*env)->IsInstanceOf(env, jObject, jBooleanArrayClass)) { 1067 jBooleanArrayToCKBBoolArray(env, jObject, (CK_BBOOL**)ckpObjectPtr, ckpLength); 1068 return; 1069 } 1070 1071 jIntArrayClass = (*env)->FindClass(env, "[I"); 1072 if (jIntArrayClass == NULL) { return; } 1073 if ((*env)->IsInstanceOf(env, jObject, jIntArrayClass)) { 1074 jLongArrayToCKULongArray(env, jObject, (CK_ULONG_PTR*)ckpObjectPtr, ckpLength); 1075 return; 1076 } 1077 1078 jLongArrayClass = (*env)->FindClass(env, "[J"); 1079 if (jLongArrayClass == NULL) { return; } 1080 if ((*env)->IsInstanceOf(env, jObject, jLongArrayClass)) { 1081 jLongArrayToCKULongArray(env, jObject, (CK_ULONG_PTR*)ckpObjectPtr, ckpLength); 1082 return; 1083 } 1084 1085 jStringClass = (*env)->FindClass(env, "java/lang/String"); 1086 if (jStringClass == NULL) { return; } 1087 if ((*env)->IsInstanceOf(env, jObject, jStringClass)) { 1088 jStringToCKUTF8CharArray(env, jObject, (CK_UTF8CHAR_PTR*)ckpObjectPtr, ckpLength); 1089 return; 1090 } 1091 1092 /* type of jObject unknown, throw PKCS11RuntimeException */ 1093 jObjectClass = (*env)->FindClass(env, "java/lang/Object"); 1094 if (jObjectClass == NULL) { return; } 1095 jMethod = (*env)->GetMethodID(env, jObjectClass, "getClass", "()Ljava/lang/Class;"); 1096 if (jMethod == NULL) { return; } 1097 jClassObject = (*env)->CallObjectMethod(env, jObject, jMethod); 1098 assert(jClassObject != 0); 1099 jClassClass = (*env)->FindClass(env, "java/lang/Class"); 1100 if (jClassClass == NULL) { return; } 1101 jMethod = (*env)->GetMethodID(env, jClassClass, "getName", "()Ljava/lang/String;"); 1102 if (jMethod == NULL) { return; } 1103 jClassNameString = (jstring) 1104 (*env)->CallObjectMethod(env, jClassObject, jMethod); 1105 assert(jClassNameString != 0); 1106 classNameString = (char*) 1107 (*env)->GetStringUTFChars(env, jClassNameString, NULL); 1108 if (classNameString == NULL) { return; } 1109 exceptionMsgPrefix = "Java object of this class cannot be converted to native PKCS#11 type: "; 1110 exceptionMsg = (char *) 1111 malloc((strlen(exceptionMsgPrefix) + strlen(classNameString) + 1)); 1112 if (exceptionMsg == NULL) { 1113 (*env)->ReleaseStringUTFChars(env, jClassNameString, classNameString); 1114 throwOutOfMemoryError(env, 0); 1115 return; 1116 } 1117 strcpy(exceptionMsg, exceptionMsgPrefix); 1118 strcat(exceptionMsg, classNameString); 1119 (*env)->ReleaseStringUTFChars(env, jClassNameString, classNameString); 1120 throwPKCS11RuntimeException(env, exceptionMsg); 1121 free(exceptionMsg); 1122 *ckpObjectPtr = NULL; 1123 *ckpLength = 0; 1124 1125 TRACE0("FINISHED\n"); 1126 } 1127 1128 #ifdef P11_MEMORYDEBUG 1129 1130 #undef malloc 1131 #undef free 1132 1133 void *p11malloc(size_t c, char *file, int line) { 1134 void *p = malloc(c); 1135 printf("malloc\t%08x\t%d\t%s:%d\n", p, c, file, line); fflush(stdout); 1136 return p; 1137 } 1138 1139 void p11free(void *p, char *file, int line) { 1140 printf("free\t%08x\t\t%s:%d\n", p, file, line); fflush(stdout); 1141 free(p); 1142 } 1143 1144 #endif 1145 1146 // prints a message to stdout if debug output is enabled 1147 void printDebug(const char *format, ...) { 1148 if (debug == JNI_TRUE) { 1149 va_list args; 1150 fprintf(stdout, "sunpkcs11: "); 1151 va_start(args, format); 1152 vfprintf(stdout, format, args); 1153 va_end(args); 1154 fflush(stdout); 1155 } 1156 } 1157