--- /dev/null 2017-01-18 09:30:05.425422781 -0800 +++ new/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_util.c 2017-01-18 23:07:39.939884685 -0800 @@ -0,0 +1,1157 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pkcs11wrapper.h" + +#include +#include +#include +#include + +/* declare file private functions */ + +ModuleData * getModuleEntry(JNIEnv *env, jobject pkcs11Implementation); +int isModulePresent(JNIEnv *env, jobject pkcs11Implementation); +void removeAllModuleEntries(JNIEnv *env); + + +/* ************************************************************************** */ +/* Functions for keeping track of currently active and loaded modules */ +/* ************************************************************************** */ + + +/* + * Create a new object for locking. + */ +jobject createLockObject(JNIEnv *env) { + jclass jObjectClass; + jobject jLockObject; + jmethodID jConstructor; + + jObjectClass = (*env)->FindClass(env, "java/lang/Object"); + if (jObjectClass == NULL) { return NULL; } + jConstructor = (*env)->GetMethodID(env, jObjectClass, "", "()V"); + if (jConstructor == NULL) { return NULL; } + jLockObject = (*env)->NewObject(env, jObjectClass, jConstructor); + if (jLockObject == NULL) { return NULL; } + jLockObject = (*env)->NewGlobalRef(env, jLockObject); + + return jLockObject ; +} + +/* + * Create a new object for locking. + */ +void destroyLockObject(JNIEnv *env, jobject jLockObject) { + if (jLockObject != NULL) { + (*env)->DeleteGlobalRef(env, jLockObject); + } +} + +/* + * Add the given pkcs11Implementation object to the list of present modules. + * Attach the given data to the entry. If the given pkcs11Implementation is + * already in the lsit, just override its old module data with the new one. + * None of the arguments can be NULL. If one of the arguments is NULL, this + * function does nothing. + */ +void putModuleEntry(JNIEnv *env, jobject pkcs11Implementation, ModuleData *moduleData) { + if (pkcs11Implementation == NULL_PTR) { + return ; + } + if (moduleData == NULL) { + return ; + } + (*env)->SetLongField(env, pkcs11Implementation, pNativeDataID, ptr_to_jlong(moduleData)); +} + + +/* + * Get the module data of the entry for the given pkcs11Implementation. Returns + * NULL, if the pkcs11Implementation is not in the list. + */ +ModuleData * getModuleEntry(JNIEnv *env, jobject pkcs11Implementation) { + jlong jData; + if (pkcs11Implementation == NULL) { + return NULL; + } + jData = (*env)->GetLongField(env, pkcs11Implementation, pNativeDataID); + return (ModuleData*)jlong_to_ptr(jData); +} + +CK_FUNCTION_LIST_PTR getFunctionList(JNIEnv *env, jobject pkcs11Implementation) { + ModuleData *moduleData; + CK_FUNCTION_LIST_PTR ckpFunctions; + + moduleData = getModuleEntry(env, pkcs11Implementation); + if (moduleData == NULL) { + throwDisconnectedRuntimeException(env); + return NULL; + } + ckpFunctions = moduleData->ckFunctionListPtr; + return ckpFunctions; +} + + +/* + * Returns 1, if the given pkcs11Implementation is in the list. + * 0, otherwise. + */ +int isModulePresent(JNIEnv *env, jobject pkcs11Implementation) { + int present; + + ModuleData *moduleData = getModuleEntry(env, pkcs11Implementation); + + present = (moduleData != NULL) ? 1 : 0; + + return present ; +} + + +/* + * Removes the entry for the given pkcs11Implementation from the list. Returns + * the module's data, after the node was removed. If this function returns NULL + * the pkcs11Implementation was not in the list. + */ +ModuleData * removeModuleEntry(JNIEnv *env, jobject pkcs11Implementation) { + ModuleData *moduleData = getModuleEntry(env, pkcs11Implementation); + if (moduleData == NULL) { + return NULL; + } + (*env)->SetLongField(env, pkcs11Implementation, pNativeDataID, 0); + return moduleData; +} + +/* + * Removes all present entries from the list of modules and frees all + * associated resources. This function is used for clean-up. + */ +void removeAllModuleEntries(JNIEnv *env) { + /* XXX empty */ +} + +/* ************************************************************************** */ +/* Below there follow the helper functions to support conversions between */ +/* Java and Cryptoki types */ +/* ************************************************************************** */ + +/* + * function to convert a PKCS#11 return value into a PKCS#11Exception + * + * This function generates a PKCS#11Exception with the returnValue as the errorcode + * if the returnValue is not CKR_OK. The functin returns 0, if the returnValue is + * CKR_OK. Otherwise, it returns the returnValue as a jLong. + * + * @param env - used to call JNI funktions and to get the Exception class + * @param returnValue - of the PKCS#11 function + */ +jlong ckAssertReturnValueOK(JNIEnv *env, CK_RV returnValue) +{ + jclass jPKCS11ExceptionClass; + jmethodID jConstructor; + jthrowable jPKCS11Exception; + jlong jErrorCode = 0L; + + if (returnValue != CKR_OK) { + jErrorCode = ckULongToJLong(returnValue); + jPKCS11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION); + if (jPKCS11ExceptionClass != NULL) { + jConstructor = (*env)->GetMethodID(env, jPKCS11ExceptionClass, "", "(J)V"); + if (jConstructor != NULL) { + jPKCS11Exception = (jthrowable) (*env)->NewObject(env, jPKCS11ExceptionClass, jConstructor, jErrorCode); + if (jPKCS11Exception != NULL) { + (*env)->Throw(env, jPKCS11Exception); + } + } + } + (*env)->DeleteLocalRef(env, jPKCS11ExceptionClass); + } + return jErrorCode ; +} + + +/* + * Throws a Java Exception by name + */ +void throwByName(JNIEnv *env, const char *name, const char *msg) +{ + jclass cls = (*env)->FindClass(env, name); + + if (cls != 0) /* Otherwise an exception has already been thrown */ + (*env)->ThrowNew(env, cls, msg); +} + +/* + * Throws java.lang.OutOfMemoryError + */ +void throwOutOfMemoryError(JNIEnv *env, const char *msg) +{ + throwByName(env, "java/lang/OutOfMemoryError", msg); +} + +/* + * Throws java.lang.NullPointerException + */ +void throwNullPointerException(JNIEnv *env, const char *msg) +{ + throwByName(env, "java/lang/NullPointerException", msg); +} + +/* + * Throws java.io.IOException + */ +void throwIOException(JNIEnv *env, const char *msg) +{ + throwByName(env, "java/io/IOException", msg); +} + +/* + * This function simply throws a PKCS#11RuntimeException with the given + * string as its message. + * + * @param env Used to call JNI funktions and to get the Exception class. + * @param jmessage The message string of the Exception object. + */ +void throwPKCS11RuntimeException(JNIEnv *env, const char *message) +{ + throwByName(env, CLASS_PKCS11RUNTIMEEXCEPTION, message); +} + +/* + * This function simply throws a PKCS#11RuntimeException. The message says that + * the object is not connected to the module. + * + * @param env Used to call JNI funktions and to get the Exception class. + */ +void throwDisconnectedRuntimeException(JNIEnv *env) +{ + throwPKCS11RuntimeException(env, "This object is not connected to a module."); +} + +/* This function frees the specified CK_ATTRIBUTE array. + * + * @param attrPtr pointer to the to-be-freed CK_ATTRIBUTE array. + * @param len the length of the array + */ +void freeCKAttributeArray(CK_ATTRIBUTE_PTR attrPtr, int len) +{ + int i; + + for (i=0; iArrayToCKArray(JNIEnv *env, + * const jArray jArray, + * CK__PTR *ckpArray, + * CK_ULONG_PTR ckLength); + * + * jArray ckArrayToJArray(JNIEnv *env, + * const CK__PTR ckpArray, + * CK_ULONG ckLength); + * + * PKCS#11 arrays consist always of a pointer to the beginning of the array and + * the array length whereas Java arrays carry their array length. + * + * The Functions to convert a Java array to a PKCS#11 array are void functions. + * Their arguments are the Java array object to convert, the reference to the + * array pointer, where the new PKCS#11 array should be stored and the reference + * to the array length where the PKCS#11 array length should be stored. These two + * references must not be NULL_PTR. + * + * The functions first obtain the array length of the Java array and then allocate + * the memory for the PKCS#11 array and set the array length. Then each element + * gets converted depending on their type. After use the allocated memory of the + * PKCS#11 array has to be explicitly freed. + * + * The Functions to convert a PKCS#11 array to a Java array get the PKCS#11 array + * pointer and the array length and they return the new Java array object. The + * Java array does not need to get freed after use. + */ + +/* + * converts a jbooleanArray to a CK_BBOOL array. The allocated memory has to be freed after use! + * + * @param env - used to call JNI funktions to get the array informtaion + * @param jArray - the Java array to convert + * @param ckpArray - the reference, where the pointer to the new CK_BBOOL array will be stored + * @param ckpLength - the reference, where the array length will be stored + */ +void jBooleanArrayToCKBBoolArray(JNIEnv *env, const jbooleanArray jArray, CK_BBOOL **ckpArray, CK_ULONG_PTR ckpLength) +{ + jboolean* jpTemp; + CK_ULONG i; + + if(jArray == NULL) { + *ckpArray = NULL_PTR; + *ckpLength = 0L; + return; + } + *ckpLength = (*env)->GetArrayLength(env, jArray); + jpTemp = (jboolean*) malloc((*ckpLength) * sizeof(jboolean)); + if (jpTemp == NULL) { + throwOutOfMemoryError(env, 0); + return; + } + (*env)->GetBooleanArrayRegion(env, jArray, 0, *ckpLength, jpTemp); + if ((*env)->ExceptionCheck(env)) { + free(jpTemp); + return; + } + + *ckpArray = (CK_BBOOL*) malloc ((*ckpLength) * sizeof(CK_BBOOL)); + if (*ckpArray == NULL) { + free(jpTemp); + throwOutOfMemoryError(env, 0); + return; + } + for (i=0; i<(*ckpLength); i++) { + (*ckpArray)[i] = jBooleanToCKBBool(jpTemp[i]); + } + free(jpTemp); +} + +/* + * converts a jbyteArray to a CK_BYTE array. The allocated memory has to be freed after use! + * + * @param env - used to call JNI funktions to get the array informtaion + * @param jArray - the Java array to convert + * @param ckpArray - the reference, where the pointer to the new CK_BYTE array will be stored + * @param ckpLength - the reference, where the array length will be stored + */ +void jByteArrayToCKByteArray(JNIEnv *env, const jbyteArray jArray, CK_BYTE_PTR *ckpArray, CK_ULONG_PTR ckpLength) +{ + jbyte* jpTemp; + CK_ULONG i; + + if(jArray == NULL) { + *ckpArray = NULL_PTR; + *ckpLength = 0L; + return; + } + *ckpLength = (*env)->GetArrayLength(env, jArray); + jpTemp = (jbyte*) malloc((*ckpLength) * sizeof(jbyte)); + if (jpTemp == NULL) { + throwOutOfMemoryError(env, 0); + return; + } + (*env)->GetByteArrayRegion(env, jArray, 0, *ckpLength, jpTemp); + if ((*env)->ExceptionCheck(env)) { + free(jpTemp); + return; + } + + /* if CK_BYTE is the same size as jbyte, we save an additional copy */ + if (sizeof(CK_BYTE) == sizeof(jbyte)) { + *ckpArray = (CK_BYTE_PTR) jpTemp; + } else { + *ckpArray = (CK_BYTE_PTR) malloc ((*ckpLength) * sizeof(CK_BYTE)); + if (*ckpArray == NULL) { + free(jpTemp); + throwOutOfMemoryError(env, 0); + return; + } + for (i=0; i<(*ckpLength); i++) { + (*ckpArray)[i] = jByteToCKByte(jpTemp[i]); + } + free(jpTemp); + } +} + +/* + * converts a jlongArray to a CK_ULONG array. The allocated memory has to be freed after use! + * + * @param env - used to call JNI funktions to get the array informtaion + * @param jArray - the Java array to convert + * @param ckpArray - the reference, where the pointer to the new CK_ULONG array will be stored + * @param ckpLength - the reference, where the array length will be stored + */ +void jLongArrayToCKULongArray(JNIEnv *env, const jlongArray jArray, CK_ULONG_PTR *ckpArray, CK_ULONG_PTR ckpLength) +{ + jlong* jTemp; + CK_ULONG i; + + if(jArray == NULL) { + *ckpArray = NULL_PTR; + *ckpLength = 0L; + return; + } + *ckpLength = (*env)->GetArrayLength(env, jArray); + jTemp = (jlong*) malloc((*ckpLength) * sizeof(jlong)); + if (jTemp == NULL) { + throwOutOfMemoryError(env, 0); + return; + } + (*env)->GetLongArrayRegion(env, jArray, 0, *ckpLength, jTemp); + if ((*env)->ExceptionCheck(env)) { + free(jTemp); + return; + } + + *ckpArray = (CK_ULONG_PTR) malloc (*ckpLength * sizeof(CK_ULONG)); + if (*ckpArray == NULL) { + free(jTemp); + throwOutOfMemoryError(env, 0); + return; + } + for (i=0; i<(*ckpLength); i++) { + (*ckpArray)[i] = jLongToCKULong(jTemp[i]); + } + free(jTemp); +} + +/* + * converts a jcharArray to a CK_CHAR array. The allocated memory has to be freed after use! + * + * @param env - used to call JNI funktions to get the array informtaion + * @param jArray - the Java array to convert + * @param ckpArray - the reference, where the pointer to the new CK_CHAR array will be stored + * @param ckpLength - the reference, where the array length will be stored + */ +void jCharArrayToCKCharArray(JNIEnv *env, const jcharArray jArray, CK_CHAR_PTR *ckpArray, CK_ULONG_PTR ckpLength) +{ + jchar* jpTemp; + CK_ULONG i; + + if(jArray == NULL) { + *ckpArray = NULL_PTR; + *ckpLength = 0L; + return; + } + *ckpLength = (*env)->GetArrayLength(env, jArray); + jpTemp = (jchar*) malloc((*ckpLength) * sizeof(jchar)); + if (jpTemp == NULL) { + throwOutOfMemoryError(env, 0); + return; + } + (*env)->GetCharArrayRegion(env, jArray, 0, *ckpLength, jpTemp); + if ((*env)->ExceptionCheck(env)) { + free(jpTemp); + return; + } + + *ckpArray = (CK_CHAR_PTR) malloc (*ckpLength * sizeof(CK_CHAR)); + if (*ckpArray == NULL) { + free(jpTemp); + throwOutOfMemoryError(env, 0); + return; + } + for (i=0; i<(*ckpLength); i++) { + (*ckpArray)[i] = jCharToCKChar(jpTemp[i]); + } + free(jpTemp); +} + +/* + * converts a jcharArray to a CK_UTF8CHAR array. The allocated memory has to be freed after use! + * + * @param env - used to call JNI funktions to get the array informtaion + * @param jArray - the Java array to convert + * @param ckpArray - the reference, where the pointer to the new CK_UTF8CHAR array will be stored + * @param ckpLength - the reference, where the array length will be stored + */ +void jCharArrayToCKUTF8CharArray(JNIEnv *env, const jcharArray jArray, CK_UTF8CHAR_PTR *ckpArray, CK_ULONG_PTR ckpLength) +{ + jchar* jTemp; + CK_ULONG i; + + if(jArray == NULL) { + *ckpArray = NULL_PTR; + *ckpLength = 0L; + return; + } + *ckpLength = (*env)->GetArrayLength(env, jArray); + jTemp = (jchar*) malloc((*ckpLength) * sizeof(jchar)); + if (jTemp == NULL) { + throwOutOfMemoryError(env, 0); + return; + } + (*env)->GetCharArrayRegion(env, jArray, 0, *ckpLength, jTemp); + if ((*env)->ExceptionCheck(env)) { + free(jTemp); + return; + } + + *ckpArray = (CK_UTF8CHAR_PTR) malloc (*ckpLength * sizeof(CK_UTF8CHAR)); + if (*ckpArray == NULL) { + free(jTemp); + throwOutOfMemoryError(env, 0); + return; + } + for (i=0; i<(*ckpLength); i++) { + (*ckpArray)[i] = jCharToCKUTF8Char(jTemp[i]); + } + free(jTemp); +} + +/* + * converts a jstring to a CK_CHAR array. The allocated memory has to be freed after use! + * + * @param env - used to call JNI funktions to get the array informtaion + * @param jArray - the Java array to convert + * @param ckpArray - the reference, where the pointer to the new CK_CHAR array will be stored + * @param ckpLength - the reference, where the array length will be stored + */ +void jStringToCKUTF8CharArray(JNIEnv *env, const jstring jArray, CK_UTF8CHAR_PTR *ckpArray, CK_ULONG_PTR ckpLength) +{ + const char* pCharArray; + jboolean isCopy; + + if(jArray == NULL) { + *ckpArray = NULL_PTR; + *ckpLength = 0L; + return; + } + + pCharArray = (*env)->GetStringUTFChars(env, jArray, &isCopy); + if (pCharArray == NULL) { return; } + + *ckpLength = (CK_ULONG) strlen(pCharArray); + *ckpArray = (CK_UTF8CHAR_PTR) malloc((*ckpLength + 1) * sizeof(CK_UTF8CHAR)); + if (*ckpArray == NULL) { + (*env)->ReleaseStringUTFChars(env, (jstring) jArray, pCharArray); + throwOutOfMemoryError(env, 0); + return; + } + strcpy((char*)*ckpArray, pCharArray); + (*env)->ReleaseStringUTFChars(env, (jstring) jArray, pCharArray); +} + +/* + * converts a jobjectArray with Java Attributes to a CK_ATTRIBUTE array. The allocated memory + * has to be freed after use! + * + * @param env - used to call JNI funktions to get the array informtaion + * @param jArray - the Java Attribute array (template) to convert + * @param ckpArray - the reference, where the pointer to the new CK_ATTRIBUTE array will be + * stored + * @param ckpLength - the reference, where the array length will be stored + */ +void jAttributeArrayToCKAttributeArray(JNIEnv *env, jobjectArray jArray, CK_ATTRIBUTE_PTR *ckpArray, CK_ULONG_PTR ckpLength) +{ + CK_ULONG i; + jlong jLength; + jobject jAttribute; + + TRACE0("\nDEBUG: jAttributeArrayToCKAttributeArray"); + if (jArray == NULL) { + *ckpArray = NULL_PTR; + *ckpLength = 0L; + return; + } + jLength = (*env)->GetArrayLength(env, jArray); + *ckpLength = jLongToCKULong(jLength); + *ckpArray = (CK_ATTRIBUTE_PTR) malloc(*ckpLength * sizeof(CK_ATTRIBUTE)); + if (*ckpArray == NULL) { + throwOutOfMemoryError(env, 0); + return; + } + TRACE1(", converting %d attributes", jLength); + for (i=0; i<(*ckpLength); i++) { + TRACE1(", getting %d. attribute", i); + jAttribute = (*env)->GetObjectArrayElement(env, jArray, i); + if ((*env)->ExceptionCheck(env)) { + freeCKAttributeArray(*ckpArray, i); + return; + } + TRACE1(", jAttribute = %d", jAttribute); + TRACE1(", converting %d. attribute", i); + (*ckpArray)[i] = jAttributeToCKAttribute(env, jAttribute); + if ((*env)->ExceptionCheck(env)) { + freeCKAttributeArray(*ckpArray, i); + return; + } + } + TRACE0("FINISHED\n"); +} + +/* + * converts a CK_BYTE array and its length to a jbyteArray. + * + * @param env - used to call JNI funktions to create the new Java array + * @param ckpArray - the pointer to the CK_BYTE array to convert + * @param ckpLength - the length of the array to convert + * @return - the new Java byte array or NULL if error occurred + */ +jbyteArray ckByteArrayToJByteArray(JNIEnv *env, const CK_BYTE_PTR ckpArray, CK_ULONG ckLength) +{ + CK_ULONG i; + jbyte* jpTemp; + jbyteArray jArray; + + /* if CK_BYTE is the same size as jbyte, we save an additional copy */ + if (sizeof(CK_BYTE) == sizeof(jbyte)) { + jpTemp = (jbyte*) ckpArray; + } else { + jpTemp = (jbyte*) malloc((ckLength) * sizeof(jbyte)); + if (jpTemp == NULL) { + throwOutOfMemoryError(env, 0); + return NULL; + } + for (i=0; iNewByteArray(env, ckULongToJSize(ckLength)); + if (jArray != NULL) { + (*env)->SetByteArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp); + } + + if (sizeof(CK_BYTE) != sizeof(jbyte)) { free(jpTemp); } + + return jArray ; +} + +/* + * converts a CK_ULONG array and its length to a jlongArray. + * + * @param env - used to call JNI funktions to create the new Java array + * @param ckpArray - the pointer to the CK_ULONG array to convert + * @param ckpLength - the length of the array to convert + * @return - the new Java long array + */ +jlongArray ckULongArrayToJLongArray(JNIEnv *env, const CK_ULONG_PTR ckpArray, CK_ULONG ckLength) +{ + CK_ULONG i; + jlong* jpTemp; + jlongArray jArray; + + jpTemp = (jlong*) malloc((ckLength) * sizeof(jlong)); + if (jpTemp == NULL) { + throwOutOfMemoryError(env, 0); + return NULL; + } + for (i=0; iNewLongArray(env, ckULongToJSize(ckLength)); + if (jArray != NULL) { + (*env)->SetLongArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp); + } + free(jpTemp); + + return jArray ; +} + +/* + * converts a CK_CHAR array and its length to a jcharArray. + * + * @param env - used to call JNI funktions to create the new Java array + * @param ckpArray - the pointer to the CK_CHAR array to convert + * @param ckpLength - the length of the array to convert + * @return - the new Java char array + */ +jcharArray ckCharArrayToJCharArray(JNIEnv *env, const CK_CHAR_PTR ckpArray, CK_ULONG ckLength) +{ + CK_ULONG i; + jchar* jpTemp; + jcharArray jArray; + + jpTemp = (jchar*) malloc(ckLength * sizeof(jchar)); + if (jpTemp == NULL) { + throwOutOfMemoryError(env, 0); + return NULL; + } + for (i=0; iNewCharArray(env, ckULongToJSize(ckLength)); + if (jArray != NULL) { + (*env)->SetCharArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp); + } + free(jpTemp); + + return jArray ; +} + +/* + * converts a CK_UTF8CHAR array and its length to a jcharArray. + * + * @param env - used to call JNI funktions to create the new Java array + * @param ckpArray - the pointer to the CK_UTF8CHAR array to convert + * @param ckpLength - the length of the array to convert + * @return - the new Java char array + */ +jcharArray ckUTF8CharArrayToJCharArray(JNIEnv *env, const CK_UTF8CHAR_PTR ckpArray, CK_ULONG ckLength) +{ + CK_ULONG i; + jchar* jpTemp; + jcharArray jArray; + + jpTemp = (jchar*) malloc(ckLength * sizeof(jchar)); + if (jpTemp == NULL) { + throwOutOfMemoryError(env, 0); + return NULL; + } + for (i=0; iNewCharArray(env, ckULongToJSize(ckLength)); + if (jArray != NULL) { + (*env)->SetCharArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp); + } + free(jpTemp); + + return jArray ; +} + +/* + * the following functions convert Java objects to PKCS#11 pointers and the + * length in bytes and vice versa + * + * CK__PTR jToCKPtr(JNIEnv *env, jobject jObject); + * + * jobject ckPtrToJ(JNIEnv *env, const CK__PTR ckpValue); + * + * The functions that convert a Java object to a PKCS#11 pointer first allocate + * the memory for the PKCS#11 pointer. Then they set each element corresponding + * to the fields in the Java object to convert. After use the allocated memory of + * the PKCS#11 pointer has to be explicitly freed. + * + * The functions to convert a PKCS#11 pointer to a Java object create a new Java + * object first and than they set all fields in the object depending on the values + * of the type or structure where the PKCS#11 pointer points to. + */ + +/* + * converts a CK_BBOOL pointer to a Java boolean Object. + * + * @param env - used to call JNI funktions to create the new Java object + * @param ckpValue - the pointer to the CK_BBOOL value + * @return - the new Java boolean object with the boolean value + */ +jobject ckBBoolPtrToJBooleanObject(JNIEnv *env, const CK_BBOOL *ckpValue) +{ + jclass jValueObjectClass; + jmethodID jConstructor; + jobject jValueObject; + jboolean jValue; + + jValueObjectClass = (*env)->FindClass(env, "java/lang/Boolean"); + if (jValueObjectClass == NULL) { return NULL; } + jConstructor = (*env)->GetMethodID(env, jValueObjectClass, "", "(Z)V"); + if (jConstructor == NULL) { return NULL; } + jValue = ckBBoolToJBoolean(*ckpValue); + jValueObject = (*env)->NewObject(env, jValueObjectClass, jConstructor, jValue); + + return jValueObject ; +} + +/* + * converts a CK_ULONG pointer to a Java long Object. + * + * @param env - used to call JNI funktions to create the new Java object + * @param ckpValue - the pointer to the CK_ULONG value + * @return - the new Java long object with the long value + */ +jobject ckULongPtrToJLongObject(JNIEnv *env, const CK_ULONG_PTR ckpValue) +{ + jclass jValueObjectClass; + jmethodID jConstructor; + jobject jValueObject; + jlong jValue; + + jValueObjectClass = (*env)->FindClass(env, "java/lang/Long"); + if (jValueObjectClass == NULL) { return NULL; } + jConstructor = (*env)->GetMethodID(env, jValueObjectClass, "", "(J)V"); + if (jConstructor == NULL) { return NULL; } + jValue = ckULongToJLong(*ckpValue); + jValueObject = (*env)->NewObject(env, jValueObjectClass, jConstructor, jValue); + + return jValueObject ; +} + +/* + * converts a Java boolean object into a pointer to a CK_BBOOL value. The memory has to be + * freed after use! + * + * @param env - used to call JNI funktions to get the value out of the Java object + * @param jObject - the "java/lang/Boolean" object to convert + * @return - the pointer to the new CK_BBOOL value + */ +CK_BBOOL* jBooleanObjectToCKBBoolPtr(JNIEnv *env, jobject jObject) +{ + jclass jObjectClass; + jmethodID jValueMethod; + jboolean jValue; + CK_BBOOL *ckpValue; + + jObjectClass = (*env)->FindClass(env, "java/lang/Boolean"); + if (jObjectClass == NULL) { return NULL; } + jValueMethod = (*env)->GetMethodID(env, jObjectClass, "booleanValue", "()Z"); + if (jValueMethod == NULL) { return NULL; } + jValue = (*env)->CallBooleanMethod(env, jObject, jValueMethod); + ckpValue = (CK_BBOOL *) malloc(sizeof(CK_BBOOL)); + if (ckpValue == NULL) { + throwOutOfMemoryError(env, 0); + return NULL; + } + *ckpValue = jBooleanToCKBBool(jValue); + + return ckpValue ; +} + +/* + * converts a Java byte object into a pointer to a CK_BYTE value. The memory has to be + * freed after use! + * + * @param env - used to call JNI funktions to get the value out of the Java object + * @param jObject - the "java/lang/Byte" object to convert + * @return - the pointer to the new CK_BYTE value + */ +CK_BYTE_PTR jByteObjectToCKBytePtr(JNIEnv *env, jobject jObject) +{ + jclass jObjectClass; + jmethodID jValueMethod; + jbyte jValue; + CK_BYTE_PTR ckpValue; + + jObjectClass = (*env)->FindClass(env, "java/lang/Byte"); + if (jObjectClass == NULL) { return NULL; } + jValueMethod = (*env)->GetMethodID(env, jObjectClass, "byteValue", "()B"); + if (jValueMethod == NULL) { return NULL; } + jValue = (*env)->CallByteMethod(env, jObject, jValueMethod); + ckpValue = (CK_BYTE_PTR) malloc(sizeof(CK_BYTE)); + if (ckpValue == NULL) { + throwOutOfMemoryError(env, 0); + return NULL; + } + *ckpValue = jByteToCKByte(jValue); + return ckpValue ; +} + +/* + * converts a Java integer object into a pointer to a CK_ULONG value. The memory has to be + * freed after use! + * + * @param env - used to call JNI funktions to get the value out of the Java object + * @param jObject - the "java/lang/Integer" object to convert + * @return - the pointer to the new CK_ULONG value + */ +CK_ULONG* jIntegerObjectToCKULongPtr(JNIEnv *env, jobject jObject) +{ + jclass jObjectClass; + jmethodID jValueMethod; + jint jValue; + CK_ULONG *ckpValue; + + jObjectClass = (*env)->FindClass(env, "java/lang/Integer"); + if (jObjectClass == NULL) { return NULL; } + jValueMethod = (*env)->GetMethodID(env, jObjectClass, "intValue", "()I"); + if (jValueMethod == NULL) { return NULL; } + jValue = (*env)->CallIntMethod(env, jObject, jValueMethod); + ckpValue = (CK_ULONG *) malloc(sizeof(CK_ULONG)); + if (ckpValue == NULL) { + throwOutOfMemoryError(env, 0); + return NULL; + } + *ckpValue = jLongToCKLong(jValue); + return ckpValue ; +} + +/* + * converts a Java long object into a pointer to a CK_ULONG value. The memory has to be + * freed after use! + * + * @param env - used to call JNI funktions to get the value out of the Java object + * @param jObject - the "java/lang/Long" object to convert + * @return - the pointer to the new CK_ULONG value + */ +CK_ULONG* jLongObjectToCKULongPtr(JNIEnv *env, jobject jObject) +{ + jclass jObjectClass; + jmethodID jValueMethod; + jlong jValue; + CK_ULONG *ckpValue; + + jObjectClass = (*env)->FindClass(env, "java/lang/Long"); + if (jObjectClass == NULL) { return NULL; } + jValueMethod = (*env)->GetMethodID(env, jObjectClass, "longValue", "()J"); + if (jValueMethod == NULL) { return NULL; } + jValue = (*env)->CallLongMethod(env, jObject, jValueMethod); + ckpValue = (CK_ULONG *) malloc(sizeof(CK_ULONG)); + if (ckpValue == NULL) { + throwOutOfMemoryError(env, 0); + return NULL; + } + *ckpValue = jLongToCKULong(jValue); + + return ckpValue ; +} + +/* + * converts a Java char object into a pointer to a CK_CHAR value. The memory has to be + * freed after use! + * + * @param env - used to call JNI funktions to get the value out of the Java object + * @param jObject - the "java/lang/Char" object to convert + * @return - the pointer to the new CK_CHAR value + */ +CK_CHAR_PTR jCharObjectToCKCharPtr(JNIEnv *env, jobject jObject) +{ + jclass jObjectClass; + jmethodID jValueMethod; + jchar jValue; + CK_CHAR_PTR ckpValue; + + jObjectClass = (*env)->FindClass(env, "java/lang/Char"); + if (jObjectClass == NULL) { return NULL; } + jValueMethod = (*env)->GetMethodID(env, jObjectClass, "charValue", "()C"); + if (jValueMethod == NULL) { return NULL; } + jValue = (*env)->CallCharMethod(env, jObject, jValueMethod); + ckpValue = (CK_CHAR_PTR) malloc(sizeof(CK_CHAR)); + if (ckpValue == NULL) { + throwOutOfMemoryError(env, 0); + return NULL; + } + *ckpValue = jCharToCKChar(jValue); + + return ckpValue ; +} + +/* + * converts a Java object into a pointer to CK-type or a CK-structure with the length in Bytes. + * The memory of *ckpObjectPtr to be freed after use! This function is only used by + * jAttributeToCKAttribute by now. + * + * @param env - used to call JNI funktions to get the Java classes and objects + * @param jObject - the Java object to convert + * @param ckpObjectPtr - the reference of the new pointer to the new CK-value or CK-structure + * @param ckpLength - the reference of the length in bytes of the new CK-value or CK-structure + */ +void jObjectToPrimitiveCKObjectPtrPtr(JNIEnv *env, jobject jObject, CK_VOID_PTR *ckpObjectPtr, CK_ULONG *ckpLength) +{ + jclass jLongClass, jBooleanClass, jByteArrayClass, jCharArrayClass; + jclass jByteClass, jDateClass, jCharacterClass, jIntegerClass; + jclass jBooleanArrayClass, jIntArrayClass, jLongArrayClass; + jclass jStringClass; + jclass jObjectClass, jClassClass; + CK_VOID_PTR ckpVoid = *ckpObjectPtr; + jmethodID jMethod; + jobject jClassObject; + jstring jClassNameString; + char *classNameString, *exceptionMsgPrefix, *exceptionMsg; + + TRACE0("\nDEBUG: jObjectToPrimitiveCKObjectPtrPtr"); + if (jObject == NULL) { + *ckpObjectPtr = NULL; + *ckpLength = 0; + return; + } + + jLongClass = (*env)->FindClass(env, "java/lang/Long"); + if (jLongClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jLongClass)) { + *ckpObjectPtr = jLongObjectToCKULongPtr(env, jObject); + *ckpLength = sizeof(CK_ULONG); + TRACE1("", *((CK_ULONG *) *ckpObjectPtr)); + return; + } + + jBooleanClass = (*env)->FindClass(env, "java/lang/Boolean"); + if (jBooleanClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jBooleanClass)) { + *ckpObjectPtr = jBooleanObjectToCKBBoolPtr(env, jObject); + *ckpLength = sizeof(CK_BBOOL); + TRACE0(" " : "FALSE>"); + return; + } + + jByteArrayClass = (*env)->FindClass(env, "[B"); + if (jByteArrayClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jByteArrayClass)) { + jByteArrayToCKByteArray(env, jObject, (CK_BYTE_PTR*)ckpObjectPtr, ckpLength); + return; + } + + jCharArrayClass = (*env)->FindClass(env, "[C"); + if (jCharArrayClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jCharArrayClass)) { + jCharArrayToCKUTF8CharArray(env, jObject, (CK_UTF8CHAR_PTR*)ckpObjectPtr, ckpLength); + return; + } + + jByteClass = (*env)->FindClass(env, "java/lang/Byte"); + if (jByteClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jByteClass)) { + *ckpObjectPtr = jByteObjectToCKBytePtr(env, jObject); + *ckpLength = sizeof(CK_BYTE); + TRACE1("", *((CK_BYTE *) *ckpObjectPtr)); + return; + } + + jDateClass = (*env)->FindClass(env, CLASS_DATE); + if (jDateClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jDateClass)) { + *ckpObjectPtr = jDateObjectPtrToCKDatePtr(env, jObject); + *ckpLength = sizeof(CK_DATE); + TRACE3("", (*((CK_DATE *) *ckpObjectPtr)).year, (*((CK_DATE *) *ckpObjectPtr)).month, (*((CK_DATE *) *ckpObjectPtr)).day); + return; + } + + jCharacterClass = (*env)->FindClass(env, "java/lang/Character"); + if (jCharacterClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jCharacterClass)) { + *ckpObjectPtr = jCharObjectToCKCharPtr(env, jObject); + *ckpLength = sizeof(CK_UTF8CHAR); + TRACE1("", *((CK_CHAR *) *ckpObjectPtr)); + return; + } + + jIntegerClass = (*env)->FindClass(env, "java/lang/Integer"); + if (jIntegerClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jIntegerClass)) { + *ckpObjectPtr = jIntegerObjectToCKULongPtr(env, jObject); + *ckpLength = sizeof(CK_ULONG); + TRACE1("", *((CK_ULONG *) *ckpObjectPtr)); + return; + } + + jBooleanArrayClass = (*env)->FindClass(env, "[Z"); + if (jBooleanArrayClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jBooleanArrayClass)) { + jBooleanArrayToCKBBoolArray(env, jObject, (CK_BBOOL**)ckpObjectPtr, ckpLength); + return; + } + + jIntArrayClass = (*env)->FindClass(env, "[I"); + if (jIntArrayClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jIntArrayClass)) { + jLongArrayToCKULongArray(env, jObject, (CK_ULONG_PTR*)ckpObjectPtr, ckpLength); + return; + } + + jLongArrayClass = (*env)->FindClass(env, "[J"); + if (jLongArrayClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jLongArrayClass)) { + jLongArrayToCKULongArray(env, jObject, (CK_ULONG_PTR*)ckpObjectPtr, ckpLength); + return; + } + + jStringClass = (*env)->FindClass(env, "java/lang/String"); + if (jStringClass == NULL) { return; } + if ((*env)->IsInstanceOf(env, jObject, jStringClass)) { + jStringToCKUTF8CharArray(env, jObject, (CK_UTF8CHAR_PTR*)ckpObjectPtr, ckpLength); + return; + } + + /* type of jObject unknown, throw PKCS11RuntimeException */ + jObjectClass = (*env)->FindClass(env, "java/lang/Object"); + if (jObjectClass == NULL) { return; } + jMethod = (*env)->GetMethodID(env, jObjectClass, "getClass", "()Ljava/lang/Class;"); + if (jMethod == NULL) { return; } + jClassObject = (*env)->CallObjectMethod(env, jObject, jMethod); + assert(jClassObject != 0); + jClassClass = (*env)->FindClass(env, "java/lang/Class"); + if (jClassClass == NULL) { return; } + jMethod = (*env)->GetMethodID(env, jClassClass, "getName", "()Ljava/lang/String;"); + if (jMethod == NULL) { return; } + jClassNameString = (jstring) + (*env)->CallObjectMethod(env, jClassObject, jMethod); + assert(jClassNameString != 0); + classNameString = (char*) + (*env)->GetStringUTFChars(env, jClassNameString, NULL); + if (classNameString == NULL) { return; } + exceptionMsgPrefix = "Java object of this class cannot be converted to native PKCS#11 type: "; + exceptionMsg = (char *) + malloc((strlen(exceptionMsgPrefix) + strlen(classNameString) + 1)); + if (exceptionMsg == NULL) { + (*env)->ReleaseStringUTFChars(env, jClassNameString, classNameString); + throwOutOfMemoryError(env, 0); + return; + } + strcpy(exceptionMsg, exceptionMsgPrefix); + strcat(exceptionMsg, classNameString); + (*env)->ReleaseStringUTFChars(env, jClassNameString, classNameString); + throwPKCS11RuntimeException(env, exceptionMsg); + free(exceptionMsg); + *ckpObjectPtr = NULL; + *ckpLength = 0; + + TRACE0("FINISHED\n"); +} + +#ifdef P11_MEMORYDEBUG + +#undef malloc +#undef free + +void *p11malloc(size_t c, char *file, int line) { + void *p = malloc(c); + printf("malloc\t%08x\t%d\t%s:%d\n", p, c, file, line); fflush(stdout); + return p; +} + +void p11free(void *p, char *file, int line) { + printf("free\t%08x\t\t%s:%d\n", p, file, line); fflush(stdout); + free(p); +} + +#endif + +// prints a message to stdout if debug output is enabled +void printDebug(const char *format, ...) { + if (debug == JNI_TRUE) { + va_list args; + fprintf(stdout, "sunpkcs11: "); + va_start(args, format); + vfprintf(stdout, format, args); + va_end(args); + fflush(stdout); + } +} +