1/*
2 * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
3 */
4
5/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 *
17 * 3. The end-user documentation included with the redistribution, if any, must
18 * include the following acknowledgment:
19 *
20 * "This product includes software developed by IAIK of Graz University of
21 * Technology."
22 *
23 * Alternately, this acknowledgment may appear in the software itself, if
24 * and wherever such third-party acknowledgments normally appear.
25 *
26 * 4. The names "Graz University of Technology" and "IAIK of Graz University of
27 * Technology" must not be used to endorse or promote products derived from
28 * this software without prior written permission.
29 *
30 * 5. Products derived from this software may not be called
31 * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior
32 * written permission of Graz University of Technology.
33 *
34 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
35 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
36 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
37 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE
38 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
39 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
40 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
41 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
42 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
43 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
45 * POSSIBILITY OF SUCH DAMAGE.
46 */
47
48#include "pkcs11wrapper.h"
49
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include <assert.h>
54
55/* declare file private functions */
56
57ModuleData * getModuleEntry(JNIEnv *env, jobject pkcs11Implementation);
58int isModulePresent(JNIEnv *env, jobject pkcs11Implementation);
59void 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 */
70jobject 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 */
89void 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 */
102void 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 */
117ModuleData * 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
126CK_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 */
144int 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 */
160ModuleData * 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 */
173void 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 */
192jlong 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 */
220void 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 */
231void throwOutOfMemoryError(JNIEnv *env, const char *msg)
232{
233 throwByName(env, "java/lang/OutOfMemoryError", msg);
234}
235
236/*
237 * Throws java.lang.NullPointerException
238 */
239void throwNullPointerException(JNIEnv *env, const char *msg)
240{
241 throwByName(env, "java/lang/NullPointerException", msg);
242}
243
244/*
245 * Throws java.io.IOException
246 */
247void 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 */
259void 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 */
270void 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 */
280void freeCKAttributeArray(CK_ATTRIBUTE_PTR attrPtr, int len) {
281 if (attrPtr != NULL) {
282 int i;
283 for (i=0; i<len; i++) {
284 if (attrPtr[i].pValue != NULL_PTR) {
285 free(attrPtr[i].pValue);
286 }
287 }
288 free(attrPtr);
289 }
290}
291
292/* This function frees the specified CK_MECHANISM_PTR pointer and its
293 * pParameter. NOTE: mechanism-specific memory allocations have to be
294 * freed before this call as this method only frees the generic
295 * memory associated with CK_MECHANISM structure.
296 *
297 * @param mechPtr pointer to the to-be-freed CK_MECHANISM structure.
298 */
299
300void freeCKMechanismPtr(CK_MECHANISM_PTR mechPtr) {
301 if (mechPtr != NULL) {
302 TRACE1("DEBUG: free CK_MECHANISM %x", mechPtr);
303 free(mechPtr->pParameter);
304 free(mechPtr);
305 }
306}
307
308/*
309 * the following functions convert Java arrays to PKCS#11 array pointers and
310 * their array length and vice versa
311 *
312 * void j<Type>ArrayToCK<Type>Array(JNIEnv *env,
313 * const j<Type>Array jArray,
314 * CK_<Type>_PTR *ckpArray,
315 * CK_ULONG_PTR ckLength);
316 *
317 * j<Type>Array ck<Type>ArrayToJ<Type>Array(JNIEnv *env,
318 * const CK_<Type>_PTR ckpArray,
319 * CK_ULONG ckLength);
320 *
321 * PKCS#11 arrays consist always of a pointer to the beginning of the array and
322 * the array length whereas Java arrays carry their array length.
323 *
324 * The Functions to convert a Java array to a PKCS#11 array are void functions.
325 * Their arguments are the Java array object to convert, the reference to the
326 * array pointer, where the new PKCS#11 array should be stored and the reference
327 * to the array length where the PKCS#11 array length should be stored. These two
328 * references must not be NULL_PTR.
329 *
330 * The functions first obtain the array length of the Java array and then allocate
331 * the memory for the PKCS#11 array and set the array length. Then each element
332 * gets converted depending on their type. After use the allocated memory of the
333 * PKCS#11 array has to be explicitly freed.
334 *
335 * The Functions to convert a PKCS#11 array to a Java array get the PKCS#11 array
336 * pointer and the array length and they return the new Java array object. The
337 * Java array does not need to get freed after use.
338 */
339
340/*
341 * converts a jbooleanArray to a CK_BBOOL array. The allocated memory has to be freed after use!
342 *
343 * @param env - used to call JNI funktions to get the array informtaion
344 * @param jArray - the Java array to convert
345 * @param ckpArray - the reference, where the pointer to the new CK_BBOOL array will be stored
346 * @param ckpLength - the reference, where the array length will be stored
347 */
348void jBooleanArrayToCKBBoolArray(JNIEnv *env, const jbooleanArray jArray, CK_BBOOL **ckpArray, CK_ULONG_PTR ckpLength)
349{
350 jboolean* jpTemp;
351 CK_ULONG i;
352
353 if(jArray == NULL) {
354 *ckpArray = NULL_PTR;
355 *ckpLength = 0L;
356 return;
357 }
358 *ckpLength = (*env)->GetArrayLength(env, jArray);
359 jpTemp = (jboolean*) malloc((*ckpLength) * sizeof(jboolean));
360 if (jpTemp == NULL) {
361 throwOutOfMemoryError(env, 0);
362 return;
363 }
364 (*env)->GetBooleanArrayRegion(env, jArray, 0, *ckpLength, jpTemp);
365 if ((*env)->ExceptionCheck(env)) {
366 free(jpTemp);
367 return;
368 }
369
370 *ckpArray = (CK_BBOOL*) malloc ((*ckpLength) * sizeof(CK_BBOOL));
371 if (*ckpArray == NULL) {
372 free(jpTemp);
373 throwOutOfMemoryError(env, 0);
374 return;
375 }
376 for (i=0; i<(*ckpLength); i++) {
377 (*ckpArray)[i] = jBooleanToCKBBool(jpTemp[i]);
378 }
379 free(jpTemp);
380}
381
382/*
383 * converts a jbyteArray to a CK_BYTE array. The allocated memory has to be freed after use!
384 *
385 * @param env - used to call JNI funktions to get the array informtaion
386 * @param jArray - the Java array to convert
387 * @param ckpArray - the reference, where the pointer to the new CK_BYTE array will be stored
388 * @param ckpLength - the reference, where the array length will be stored
389 */
390void jByteArrayToCKByteArray(JNIEnv *env, const jbyteArray jArray, CK_BYTE_PTR *ckpArray, CK_ULONG_PTR ckpLength)
391{
392 jbyte* jpTemp;
393 CK_ULONG i;
394
395 if(jArray == NULL) {
396 *ckpArray = NULL_PTR;
397 *ckpLength = 0L;
398 return;
399 }
400 *ckpLength = (*env)->GetArrayLength(env, jArray);
401 jpTemp = (jbyte*) malloc((*ckpLength) * sizeof(jbyte));
402 if (jpTemp == NULL) {
403 throwOutOfMemoryError(env, 0);
404 return;
405 }
406 (*env)->GetByteArrayRegion(env, jArray, 0, *ckpLength, jpTemp);
407 if ((*env)->ExceptionCheck(env)) {
408 free(jpTemp);
409 return;
410 }
411
412 /* if CK_BYTE is the same size as jbyte, we save an additional copy */
413 if (sizeof(CK_BYTE) == sizeof(jbyte)) {
414 *ckpArray = (CK_BYTE_PTR) jpTemp;
415 } else {
416 *ckpArray = (CK_BYTE_PTR) malloc ((*ckpLength) * sizeof(CK_BYTE));
417 if (*ckpArray == NULL) {
418 free(jpTemp);
419 throwOutOfMemoryError(env, 0);
420 return;
421 }
422 for (i=0; i<(*ckpLength); i++) {
423 (*ckpArray)[i] = jByteToCKByte(jpTemp[i]);
424 }
425 free(jpTemp);
426 }
427}
428
429/*
430 * converts a jlongArray to a CK_ULONG array. The allocated memory has to be freed after use!
431 *
432 * @param env - used to call JNI funktions to get the array informtaion
433 * @param jArray - the Java array to convert
434 * @param ckpArray - the reference, where the pointer to the new CK_ULONG array will be stored
435 * @param ckpLength - the reference, where the array length will be stored
436 */
437void jLongArrayToCKULongArray(JNIEnv *env, const jlongArray jArray, CK_ULONG_PTR *ckpArray, CK_ULONG_PTR ckpLength)
438{
439 jlong* jTemp;
440 CK_ULONG i;
441
442 if(jArray == NULL) {
443 *ckpArray = NULL_PTR;
444 *ckpLength = 0L;
445 return;
446 }
447 *ckpLength = (*env)->GetArrayLength(env, jArray);
448 jTemp = (jlong*) malloc((*ckpLength) * sizeof(jlong));
449 if (jTemp == NULL) {
450 throwOutOfMemoryError(env, 0);
451 return;
452 }
453 (*env)->GetLongArrayRegion(env, jArray, 0, *ckpLength, jTemp);
454 if ((*env)->ExceptionCheck(env)) {
455 free(jTemp);
456 return;
457 }
458
459 *ckpArray = (CK_ULONG_PTR) malloc (*ckpLength * sizeof(CK_ULONG));
460 if (*ckpArray == NULL) {
461 free(jTemp);
462 throwOutOfMemoryError(env, 0);
463 return;
464 }
465 for (i=0; i<(*ckpLength); i++) {
466 (*ckpArray)[i] = jLongToCKULong(jTemp[i]);
467 }
468 free(jTemp);
469}
470
471/*
472 * converts a jcharArray to a CK_CHAR array. The allocated memory has to be freed after use!
473 *
474 * @param env - used to call JNI funktions to get the array informtaion
475 * @param jArray - the Java array to convert
476 * @param ckpArray - the reference, where the pointer to the new CK_CHAR array will be stored
477 * @param ckpLength - the reference, where the array length will be stored
478 */
479void jCharArrayToCKCharArray(JNIEnv *env, const jcharArray jArray, CK_CHAR_PTR *ckpArray, CK_ULONG_PTR ckpLength)
480{
481 jchar* jpTemp;
482 CK_ULONG i;
483
484 if(jArray == NULL) {
485 *ckpArray = NULL_PTR;
486 *ckpLength = 0L;
487 return;
488 }
489 *ckpLength = (*env)->GetArrayLength(env, jArray);
490 jpTemp = (jchar*) malloc((*ckpLength) * sizeof(jchar));
491 if (jpTemp == NULL) {
492 throwOutOfMemoryError(env, 0);
493 return;
494 }
495 (*env)->GetCharArrayRegion(env, jArray, 0, *ckpLength, jpTemp);
496 if ((*env)->ExceptionCheck(env)) {
497 free(jpTemp);
498 return;
499 }
500
501 *ckpArray = (CK_CHAR_PTR) malloc (*ckpLength * sizeof(CK_CHAR));
502 if (*ckpArray == NULL) {
503 free(jpTemp);
504 throwOutOfMemoryError(env, 0);
505 return;
506 }
507 for (i=0; i<(*ckpLength); i++) {
508 (*ckpArray)[i] = jCharToCKChar(jpTemp[i]);
509 }
510 free(jpTemp);
511}
512
513/*
514 * converts a jcharArray to a CK_UTF8CHAR array. The allocated memory has to be freed after use!
515 *
516 * @param env - used to call JNI funktions to get the array informtaion
517 * @param jArray - the Java array to convert
518 * @param ckpArray - the reference, where the pointer to the new CK_UTF8CHAR array will be stored
519 * @param ckpLength - the reference, where the array length will be stored
520 */
521void jCharArrayToCKUTF8CharArray(JNIEnv *env, const jcharArray jArray, CK_UTF8CHAR_PTR *ckpArray, CK_ULONG_PTR ckpLength)
522{
523 jchar* jTemp;
524 CK_ULONG i;
525
526 if(jArray == NULL) {
527 *ckpArray = NULL_PTR;
528 *ckpLength = 0L;
529 return;
530 }
531 *ckpLength = (*env)->GetArrayLength(env, jArray);
532 jTemp = (jchar*) malloc((*ckpLength) * sizeof(jchar));
533 if (jTemp == NULL) {
534 throwOutOfMemoryError(env, 0);
535 return;
536 }
537 (*env)->GetCharArrayRegion(env, jArray, 0, *ckpLength, jTemp);
538 if ((*env)->ExceptionCheck(env)) {
539 free(jTemp);
540 return;
541 }
542
543 *ckpArray = (CK_UTF8CHAR_PTR) malloc (*ckpLength * sizeof(CK_UTF8CHAR));
544 if (*ckpArray == NULL) {
545 free(jTemp);
546 throwOutOfMemoryError(env, 0);
547 return;
548 }
549 for (i=0; i<(*ckpLength); i++) {
550 (*ckpArray)[i] = jCharToCKUTF8Char(jTemp[i]);
551 }
552 free(jTemp);
553}
554
555/*
556 * converts a jstring to a CK_CHAR array. The allocated memory has to be freed after use!
557 *
558 * @param env - used to call JNI funktions to get the array informtaion
559 * @param jArray - the Java array to convert
560 * @param ckpArray - the reference, where the pointer to the new CK_CHAR array will be stored
561 * @param ckpLength - the reference, where the array length will be stored
562 */
563void jStringToCKUTF8CharArray(JNIEnv *env, const jstring jArray, CK_UTF8CHAR_PTR *ckpArray, CK_ULONG_PTR ckpLength)
564{
565 const char* pCharArray;
566 jboolean isCopy;
567
568 if(jArray == NULL) {
569 *ckpArray = NULL_PTR;
570 *ckpLength = 0L;
571 return;
572 }
573
574 pCharArray = (*env)->GetStringUTFChars(env, jArray, &isCopy);
575 if (pCharArray == NULL) { return; }
576
577 *ckpLength = (CK_ULONG) strlen(pCharArray);
578 *ckpArray = (CK_UTF8CHAR_PTR) malloc((*ckpLength + 1) * sizeof(CK_UTF8CHAR));
579 if (*ckpArray == NULL) {
580 (*env)->ReleaseStringUTFChars(env, (jstring) jArray, pCharArray);
581 throwOutOfMemoryError(env, 0);
582 return;
583 }
584 strcpy((char*)*ckpArray, pCharArray);
585 (*env)->ReleaseStringUTFChars(env, (jstring) jArray, pCharArray);
586}
587
588/*
589 * converts a jobjectArray with Java Attributes to a CK_ATTRIBUTE array. The allocated memory
590 * has to be freed after use!
591 *
592 * @param env - used to call JNI funktions to get the array informtaion
593 * @param jArray - the Java Attribute array (template) to convert
594 * @param ckpArray - the reference, where the pointer to the new CK_ATTRIBUTE array will be
595 * stored
596 * @param ckpLength - the reference, where the array length will be stored
597 */
598void jAttributeArrayToCKAttributeArray(JNIEnv *env, jobjectArray jArray, CK_ATTRIBUTE_PTR *ckpArray, CK_ULONG_PTR ckpLength)
599{
600 CK_ULONG i;
601 jlong jLength;
602 jobject jAttribute;
603
604 TRACE0("\nDEBUG: jAttributeArrayToCKAttributeArray");
605 if (jArray == NULL) {
606 *ckpArray = NULL_PTR;
607 *ckpLength = 0L;
608 return;
609 }
610 jLength = (*env)->GetArrayLength(env, jArray);
611 *ckpLength = jLongToCKULong(jLength);
612 *ckpArray = (CK_ATTRIBUTE_PTR) malloc(*ckpLength * sizeof(CK_ATTRIBUTE));
613 if (*ckpArray == NULL) {
614 throwOutOfMemoryError(env, 0);
615 return;
616 }
617 TRACE1(", converting %d attributes", jLength);
618 for (i=0; i<(*ckpLength); i++) {
619 TRACE1(", getting %d. attribute", i);
620 jAttribute = (*env)->GetObjectArrayElement(env, jArray, i);
621 if ((*env)->ExceptionCheck(env)) {
622 freeCKAttributeArray(*ckpArray, i);
623 return;
624 }
625 TRACE1(", jAttribute = %d", jAttribute);
626 TRACE1(", converting %d. attribute", i);
627 (*ckpArray)[i] = jAttributeToCKAttribute(env, jAttribute);
628 if ((*env)->ExceptionCheck(env)) {
629 freeCKAttributeArray(*ckpArray, i);
630 return;
631 }
632 }
633 TRACE0("FINISHED\n");
634}
635
636/*
637 * converts a CK_BYTE array and its length to a jbyteArray.
638 *
639 * @param env - used to call JNI funktions to create the new Java array
640 * @param ckpArray - the pointer to the CK_BYTE array to convert
641 * @param ckpLength - the length of the array to convert
642 * @return - the new Java byte array or NULL if error occurred
643 */
644jbyteArray ckByteArrayToJByteArray(JNIEnv *env, const CK_BYTE_PTR ckpArray, CK_ULONG ckLength)
645{
646 CK_ULONG i;
647 jbyte* jpTemp;
648 jbyteArray jArray;
649
650 /* if CK_BYTE is the same size as jbyte, we save an additional copy */
651 if (sizeof(CK_BYTE) == sizeof(jbyte)) {
652 jpTemp = (jbyte*) ckpArray;
653 } else {
654 jpTemp = (jbyte*) malloc((ckLength) * sizeof(jbyte));
655 if (jpTemp == NULL) {
656 throwOutOfMemoryError(env, 0);
657 return NULL;
658 }
659 for (i=0; i<ckLength; i++) {
660 jpTemp[i] = ckByteToJByte(ckpArray[i]);
661 }
662 }
663
664 jArray = (*env)->NewByteArray(env, ckULongToJSize(ckLength));
665 if (jArray != NULL) {
666 (*env)->SetByteArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp);
667 }
668
669 if (sizeof(CK_BYTE) != sizeof(jbyte)) { free(jpTemp); }
670
671 return jArray ;
672}
673
674/*
675 * converts a CK_ULONG array and its length to a jlongArray.
676 *
677 * @param env - used to call JNI funktions to create the new Java array
678 * @param ckpArray - the pointer to the CK_ULONG array to convert
679 * @param ckpLength - the length of the array to convert
680 * @return - the new Java long array
681 */
682jlongArray ckULongArrayToJLongArray(JNIEnv *env, const CK_ULONG_PTR ckpArray, CK_ULONG ckLength)
683{
684 CK_ULONG i;
685 jlong* jpTemp;
686 jlongArray jArray;
687
688 jpTemp = (jlong*) malloc((ckLength) * sizeof(jlong));
689 if (jpTemp == NULL) {
690 throwOutOfMemoryError(env, 0);
691 return NULL;
692 }
693 for (i=0; i<ckLength; i++) {
694 jpTemp[i] = ckLongToJLong(ckpArray[i]);
695 }
696 jArray = (*env)->NewLongArray(env, ckULongToJSize(ckLength));
697 if (jArray != NULL) {
698 (*env)->SetLongArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp);
699 }
700 free(jpTemp);
701
702 return jArray ;
703}
704
705/*
706 * converts a CK_CHAR array and its length to a jcharArray.
707 *
708 * @param env - used to call JNI funktions to create the new Java array
709 * @param ckpArray - the pointer to the CK_CHAR array to convert
710 * @param ckpLength - the length of the array to convert
711 * @return - the new Java char array
712 */
713jcharArray ckCharArrayToJCharArray(JNIEnv *env, const CK_CHAR_PTR ckpArray, CK_ULONG ckLength)
714{
715 CK_ULONG i;
716 jchar* jpTemp;
717 jcharArray jArray;
718
719 jpTemp = (jchar*) malloc(ckLength * sizeof(jchar));
720 if (jpTemp == NULL) {
721 throwOutOfMemoryError(env, 0);
722 return NULL;
723 }
724 for (i=0; i<ckLength; i++) {
725 jpTemp[i] = ckCharToJChar(ckpArray[i]);
726 }
727 jArray = (*env)->NewCharArray(env, ckULongToJSize(ckLength));
728 if (jArray != NULL) {
729 (*env)->SetCharArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp);
730 }
731 free(jpTemp);
732
733 return jArray ;
734}
735
736/*
737 * converts a CK_UTF8CHAR array and its length to a jcharArray.
738 *
739 * @param env - used to call JNI funktions to create the new Java array
740 * @param ckpArray - the pointer to the CK_UTF8CHAR array to convert
741 * @param ckpLength - the length of the array to convert
742 * @return - the new Java char array
743 */
744jcharArray ckUTF8CharArrayToJCharArray(JNIEnv *env, const CK_UTF8CHAR_PTR ckpArray, CK_ULONG ckLength)
745{
746 CK_ULONG i;
747 jchar* jpTemp;
748 jcharArray jArray;
749
750 jpTemp = (jchar*) malloc(ckLength * sizeof(jchar));
751 if (jpTemp == NULL) {
752 throwOutOfMemoryError(env, 0);
753 return NULL;
754 }
755 for (i=0; i<ckLength; i++) {
756 jpTemp[i] = ckUTF8CharToJChar(ckpArray[i]);
757 }
758 jArray = (*env)->NewCharArray(env, ckULongToJSize(ckLength));
759 if (jArray != NULL) {
760 (*env)->SetCharArrayRegion(env, jArray, 0, ckULongToJSize(ckLength), jpTemp);
761 }
762 free(jpTemp);
763
764 return jArray ;
765}
766
767/*
768 * the following functions convert Java objects to PKCS#11 pointers and the
769 * length in bytes and vice versa
770 *
771 * CK_<Type>_PTR j<Object>ToCK<Type>Ptr(JNIEnv *env, jobject jObject);
772 *
773 * jobject ck<Type>PtrToJ<Object>(JNIEnv *env, const CK_<Type>_PTR ckpValue);
774 *
775 * The functions that convert a Java object to a PKCS#11 pointer first allocate
776 * the memory for the PKCS#11 pointer. Then they set each element corresponding
777 * to the fields in the Java object to convert. After use the allocated memory of
778 * the PKCS#11 pointer has to be explicitly freed.
779 *
780 * The functions to convert a PKCS#11 pointer to a Java object create a new Java
781 * object first and than they set all fields in the object depending on the values
782 * of the type or structure where the PKCS#11 pointer points to.
783 */
784
785/*
786 * converts a CK_BBOOL pointer to a Java boolean Object.
787 *
788 * @param env - used to call JNI funktions to create the new Java object
789 * @param ckpValue - the pointer to the CK_BBOOL value
790 * @return - the new Java boolean object with the boolean value
791 */
792jobject ckBBoolPtrToJBooleanObject(JNIEnv *env, const CK_BBOOL *ckpValue)
793{
794 jclass jValueObjectClass;
795 jmethodID jConstructor;
796 jobject jValueObject;
797 jboolean jValue;
798
799 jValueObjectClass = (*env)->FindClass(env, "java/lang/Boolean");
800 if (jValueObjectClass == NULL) { return NULL; }
801 jConstructor = (*env)->GetMethodID(env, jValueObjectClass, "<init>", "(Z)V");
802 if (jConstructor == NULL) { return NULL; }
803 jValue = ckBBoolToJBoolean(*ckpValue);
804 jValueObject = (*env)->NewObject(env, jValueObjectClass, jConstructor, jValue);
805
806 return jValueObject ;
807}
808
809/*
810 * converts a CK_ULONG pointer to a Java long Object.
811 *
812 * @param env - used to call JNI funktions to create the new Java object
813 * @param ckpValue - the pointer to the CK_ULONG value
814 * @return - the new Java long object with the long value
815 */
816jobject ckULongPtrToJLongObject(JNIEnv *env, const CK_ULONG_PTR ckpValue)
817{
818 jclass jValueObjectClass;
819 jmethodID jConstructor;
820 jobject jValueObject;
821 jlong jValue;
822
823 jValueObjectClass = (*env)->FindClass(env, "java/lang/Long");
824 if (jValueObjectClass == NULL) { return NULL; }
825 jConstructor = (*env)->GetMethodID(env, jValueObjectClass, "<init>", "(J)V");
826 if (jConstructor == NULL) { return NULL; }
827 jValue = ckULongToJLong(*ckpValue);
828 jValueObject = (*env)->NewObject(env, jValueObjectClass, jConstructor, jValue);
829
830 return jValueObject ;
831}
832
833/*
834 * converts a Java boolean object into a pointer to a CK_BBOOL value. The memory has to be
835 * freed after use!
836 *
837 * @param env - used to call JNI funktions to get the value out of the Java object
838 * @param jObject - the "java/lang/Boolean" object to convert
839 * @return - the pointer to the new CK_BBOOL value
840 */
841CK_BBOOL* jBooleanObjectToCKBBoolPtr(JNIEnv *env, jobject jObject)
842{
843 jclass jObjectClass;
844 jmethodID jValueMethod;
845 jboolean jValue;
846 CK_BBOOL *ckpValue;
847
848 jObjectClass = (*env)->FindClass(env, "java/lang/Boolean");
849 if (jObjectClass == NULL) { return NULL; }
850 jValueMethod = (*env)->GetMethodID(env, jObjectClass, "booleanValue", "()Z");
851 if (jValueMethod == NULL) { return NULL; }
852 jValue = (*env)->CallBooleanMethod(env, jObject, jValueMethod);
853 ckpValue = (CK_BBOOL *) malloc(sizeof(CK_BBOOL));
854 if (ckpValue == NULL) {
855 throwOutOfMemoryError(env, 0);
856 return NULL;
857 }
858 *ckpValue = jBooleanToCKBBool(jValue);
859
860 return ckpValue ;
861}
862
863/*
864 * converts a Java byte object into a pointer to a CK_BYTE value. The memory has to be
865 * freed after use!
866 *
867 * @param env - used to call JNI funktions to get the value out of the Java object
868 * @param jObject - the "java/lang/Byte" object to convert
869 * @return - the pointer to the new CK_BYTE value
870 */
871CK_BYTE_PTR jByteObjectToCKBytePtr(JNIEnv *env, jobject jObject)
872{
873 jclass jObjectClass;
874 jmethodID jValueMethod;
875 jbyte jValue;
876 CK_BYTE_PTR ckpValue;
877
878 jObjectClass = (*env)->FindClass(env, "java/lang/Byte");
879 if (jObjectClass == NULL) { return NULL; }
880 jValueMethod = (*env)->GetMethodID(env, jObjectClass, "byteValue", "()B");
881 if (jValueMethod == NULL) { return NULL; }
882 jValue = (*env)->CallByteMethod(env, jObject, jValueMethod);
883 ckpValue = (CK_BYTE_PTR) malloc(sizeof(CK_BYTE));
884 if (ckpValue == NULL) {
885 throwOutOfMemoryError(env, 0);
886 return NULL;
887 }
888 *ckpValue = jByteToCKByte(jValue);
889 return ckpValue ;
890}
891
892/*
893 * converts a Java integer object into a pointer to a CK_ULONG value. The memory has to be
894 * freed after use!
895 *
896 * @param env - used to call JNI funktions to get the value out of the Java object
897 * @param jObject - the "java/lang/Integer" object to convert
898 * @return - the pointer to the new CK_ULONG value
899 */
900CK_ULONG* jIntegerObjectToCKULongPtr(JNIEnv *env, jobject jObject)
901{
902 jclass jObjectClass;
903 jmethodID jValueMethod;
904 jint jValue;
905 CK_ULONG *ckpValue;
906
907 jObjectClass = (*env)->FindClass(env, "java/lang/Integer");
908 if (jObjectClass == NULL) { return NULL; }
909 jValueMethod = (*env)->GetMethodID(env, jObjectClass, "intValue", "()I");
910 if (jValueMethod == NULL) { return NULL; }
911 jValue = (*env)->CallIntMethod(env, jObject, jValueMethod);
912 ckpValue = (CK_ULONG *) malloc(sizeof(CK_ULONG));
913 if (ckpValue == NULL) {
914 throwOutOfMemoryError(env, 0);
915 return NULL;
916 }
917 *ckpValue = jLongToCKLong(jValue);
918 return ckpValue ;
919}
920
921/*
922 * converts a Java long object into a pointer to a CK_ULONG value. The memory has to be
923 * freed after use!
924 *
925 * @param env - used to call JNI funktions to get the value out of the Java object
926 * @param jObject - the "java/lang/Long" object to convert
927 * @return - the pointer to the new CK_ULONG value
928 */
929CK_ULONG* jLongObjectToCKULongPtr(JNIEnv *env, jobject jObject)
930{
931 jclass jObjectClass;
932 jmethodID jValueMethod;
933 jlong jValue;
934 CK_ULONG *ckpValue;
935
936 jObjectClass = (*env)->FindClass(env, "java/lang/Long");
937 if (jObjectClass == NULL) { return NULL; }
938 jValueMethod = (*env)->GetMethodID(env, jObjectClass, "longValue", "()J");
939 if (jValueMethod == NULL) { return NULL; }
940 jValue = (*env)->CallLongMethod(env, jObject, jValueMethod);
941 ckpValue = (CK_ULONG *) malloc(sizeof(CK_ULONG));
942 if (ckpValue == NULL) {
943 throwOutOfMemoryError(env, 0);
944 return NULL;
945 }
946 *ckpValue = jLongToCKULong(jValue);
947
948 return ckpValue ;
949}
950
951/*
952 * converts a Java char object into a pointer to a CK_CHAR value. The memory has to be
953 * freed after use!
954 *
955 * @param env - used to call JNI funktions to get the value out of the Java object
956 * @param jObject - the "java/lang/Char" object to convert
957 * @return - the pointer to the new CK_CHAR value
958 */
959CK_CHAR_PTR jCharObjectToCKCharPtr(JNIEnv *env, jobject jObject)
960{
961 jclass jObjectClass;
962 jmethodID jValueMethod;
963 jchar jValue;
964 CK_CHAR_PTR ckpValue;
965
966 jObjectClass = (*env)->FindClass(env, "java/lang/Char");
967 if (jObjectClass == NULL) { return NULL; }
968 jValueMethod = (*env)->GetMethodID(env, jObjectClass, "charValue", "()C");
969 if (jValueMethod == NULL) { return NULL; }
970 jValue = (*env)->CallCharMethod(env, jObject, jValueMethod);
971 ckpValue = (CK_CHAR_PTR) malloc(sizeof(CK_CHAR));
972 if (ckpValue == NULL) {
973 throwOutOfMemoryError(env, 0);
974 return NULL;
975 }
976 *ckpValue = jCharToCKChar(jValue);
977
978 return ckpValue ;
979}
980
981/*
982 * converts a Java object into a pointer to CK-type or a CK-structure with the length in Bytes.
983 * The memory of the returned pointer MUST BE FREED BY CALLER!
984 *
985 * @param env - used to call JNI funktions to get the Java classes and objects
986 * @param jObject - the Java object to convert
987 * @param ckpLength - pointer to the length (bytes) of the newly-allocated CK-value or CK-structure
988 * @return ckpObject - pointer to the newly-allocated CK-value or CK-structure
989 */
990CK_VOID_PTR jObjectToPrimitiveCKObjectPtr(JNIEnv *env, jobject jObject, CK_ULONG *ckpLength)
991{
992 jclass jLongClass, jBooleanClass, jByteArrayClass, jCharArrayClass;
993 jclass jByteClass, jDateClass, jCharacterClass, jIntegerClass;
994 jclass jBooleanArrayClass, jIntArrayClass, jLongArrayClass;
995 jclass jStringClass;
996 jclass jObjectClass, jClassClass;
997 CK_VOID_PTR ckpObject;
998 jmethodID jMethod;
999 jobject jClassObject;
1000 jstring jClassNameString;
1001 char *classNameString, *exceptionMsgPrefix, *exceptionMsg;
1002
1003 TRACE0("\nDEBUG: jObjectToPrimitiveCKObjectPtr");
1004 if (jObject == NULL) {
1005 *ckpLength = 0;
1006 return NULL;
1007 }
1008
1009 jLongClass = (*env)->FindClass(env, "java/lang/Long");
1010 if (jLongClass == NULL) { return NULL; }
1011 if ((*env)->IsInstanceOf(env, jObject, jLongClass)) {
1012 ckpObject = jLongObjectToCKULongPtr(env, jObject);
1013 *ckpLength = sizeof(CK_ULONG);
1014 TRACE1("<converted long value %X>", *((CK_ULONG *) ckpObject));
1015 return ckpObject;
1016 }
1017
1018 jBooleanClass = (*env)->FindClass(env, "java/lang/Boolean");
1019 if (jBooleanClass == NULL) { return NULL; }
1020 if ((*env)->IsInstanceOf(env, jObject, jBooleanClass)) {
1021 ckpObject = jBooleanObjectToCKBBoolPtr(env, jObject);
1022 *ckpLength = sizeof(CK_BBOOL);
1023 TRACE0(" <converted boolean value ");
1024 TRACE0((*((CK_BBOOL *) ckpObjectPtr) == TRUE) ? "TRUE>" : "FALSE>");
1025 return ckpObject;
1026 }
1027
1028 jByteArrayClass = (*env)->FindClass(env, "[B");
1029 if (jByteArrayClass == NULL) { return NULL; }
1030 if ((*env)->IsInstanceOf(env, jObject, jByteArrayClass)) {
1031 jByteArrayToCKByteArray(env, jObject, (CK_BYTE_PTR*) &ckpObject, ckpLength);
1032 return ckpObject;
1033 }
1034
1035 jCharArrayClass = (*env)->FindClass(env, "[C");
1036 if (jCharArrayClass == NULL) { return NULL; }
1037 if ((*env)->IsInstanceOf(env, jObject, jCharArrayClass)) {
1038 jCharArrayToCKUTF8CharArray(env, jObject, (CK_UTF8CHAR_PTR*) &ckpObject, ckpLength);
1039 return ckpObject;
1040 }
1041
1042 jByteClass = (*env)->FindClass(env, "java/lang/Byte");
1043 if (jByteClass == NULL) { return NULL; }
1044 if ((*env)->IsInstanceOf(env, jObject, jByteClass)) {
1045 ckpObject = jByteObjectToCKBytePtr(env, jObject);
1046 *ckpLength = sizeof(CK_BYTE);
1047 TRACE1("<converted byte value %X>", *((CK_BYTE *) ckpObject));
1048 return ckpObject;
1049 }
1050
1051 jDateClass = (*env)->FindClass(env, CLASS_DATE);
1052 if (jDateClass == NULL) { return NULL; }
1053 if ((*env)->IsInstanceOf(env, jObject, jDateClass)) {
1054 ckpObject = jDateObjectPtrToCKDatePtr(env, jObject);
1055 *ckpLength = sizeof(CK_DATE);
1056 TRACE3("<converted date value %.4s-%.2s-%.2s>", ((CK_DATE *) ckpObject)->year,
1057 ((CK_DATE *) ckpObject)->month, ((CK_DATE *) ckpObject)->day);
1058 return ckpObject;
1059 }
1060
1061 jCharacterClass = (*env)->FindClass(env, "java/lang/Character");
1062 if (jCharacterClass == NULL) { return NULL; }
1063 if ((*env)->IsInstanceOf(env, jObject, jCharacterClass)) {
1064 ckpObject = jCharObjectToCKCharPtr(env, jObject);
1065 *ckpLength = sizeof(CK_UTF8CHAR);
1066 TRACE1("<converted char value %c>", *((CK_CHAR *) ckpObject));
1067 return ckpObject;
1068 }
1069
1070 jIntegerClass = (*env)->FindClass(env, "java/lang/Integer");
1071 if (jIntegerClass == NULL) { return NULL; }
1072 if ((*env)->IsInstanceOf(env, jObject, jIntegerClass)) {
1073 ckpObject = jIntegerObjectToCKULongPtr(env, jObject);
1074 *ckpLength = sizeof(CK_ULONG);
1075 TRACE1("<converted integer value %X>", *((CK_ULONG *) ckpObject));
1076 return ckpObject;
1077 }
1078
1079 jBooleanArrayClass = (*env)->FindClass(env, "[Z");
1080 if (jBooleanArrayClass == NULL) { return NULL; }
1081 if ((*env)->IsInstanceOf(env, jObject, jBooleanArrayClass)) {
1082 jBooleanArrayToCKBBoolArray(env, jObject, (CK_BBOOL**) &ckpObject, ckpLength);
1083 return ckpObject;
1084 }
1085
1086 jIntArrayClass = (*env)->FindClass(env, "[I");
1087 if (jIntArrayClass == NULL) { return NULL; }
1088 if ((*env)->IsInstanceOf(env, jObject, jIntArrayClass)) {
1089 jLongArrayToCKULongArray(env, jObject, (CK_ULONG_PTR*) &ckpObject, ckpLength);
1090 return ckpObject;
1091 }
1092
1093 jLongArrayClass = (*env)->FindClass(env, "[J");
1094 if (jLongArrayClass == NULL) { return NULL; }
1095 if ((*env)->IsInstanceOf(env, jObject, jLongArrayClass)) {
1096 jLongArrayToCKULongArray(env, jObject, (CK_ULONG_PTR*) &ckpObject, ckpLength);
1097 return ckpObject;
1098 }
1099
1100 jStringClass = (*env)->FindClass(env, "java/lang/String");
1101 if (jStringClass == NULL) { return NULL; }
1102 if ((*env)->IsInstanceOf(env, jObject, jStringClass)) {
1103 jStringToCKUTF8CharArray(env, jObject, (CK_UTF8CHAR_PTR*) &ckpObject, ckpLength);
1104 return ckpObject;
1105 }
1106
1107 /* type of jObject unknown, throw PKCS11RuntimeException */
1108 jObjectClass = (*env)->FindClass(env, "java/lang/Object");
1109 if (jObjectClass == NULL) { return NULL; }
1110 jMethod = (*env)->GetMethodID(env, jObjectClass, "getClass", "()Ljava/lang/Class;");
1111 if (jMethod == NULL) { return NULL; }
1112 jClassObject = (*env)->CallObjectMethod(env, jObject, jMethod);
1113 assert(jClassObject != 0);
1114 jClassClass = (*env)->FindClass(env, "java/lang/Class");
1115 if (jClassClass == NULL) { return NULL; }
1116 jMethod = (*env)->GetMethodID(env, jClassClass, "getName", "()Ljava/lang/String;");
1117 if (jMethod == NULL) { return NULL; }
1118 jClassNameString = (jstring)
1119 (*env)->CallObjectMethod(env, jClassObject, jMethod);
1120 assert(jClassNameString != 0);
1121 classNameString = (char*)
1122 (*env)->GetStringUTFChars(env, jClassNameString, NULL);
1123 if (classNameString == NULL) { return NULL; }
1124 exceptionMsgPrefix = "Java object of this class cannot be converted to native PKCS#11 type: ";
1125 exceptionMsg = (char *)
1126 malloc((strlen(exceptionMsgPrefix) + strlen(classNameString) + 1));
1127 if (exceptionMsg == NULL) {
1128 (*env)->ReleaseStringUTFChars(env, jClassNameString, classNameString);
1129 throwOutOfMemoryError(env, 0);
1130 return NULL;
1131 }
1132 strcpy(exceptionMsg, exceptionMsgPrefix);
1133 strcat(exceptionMsg, classNameString);
1134 (*env)->ReleaseStringUTFChars(env, jClassNameString, classNameString);
1135 throwPKCS11RuntimeException(env, exceptionMsg);
1136 free(exceptionMsg);
1137 *ckpLength = 0;
1138
1139 TRACE0("FINISHED\n");
1140 return NULL;
1141}
1142
1143#ifdef P11_MEMORYDEBUG
1144
1145#undef malloc
1146#undef free
1147
1148void *p11malloc(size_t c, char *file, int line) {
1149 void *p = malloc(c);
1150 printf("malloc\t%08x\t%d\t%s:%d\n", p, c, file, line); fflush(stdout);
1151 return p;
1152}
1153
1154void p11free(void *p, char *file, int line) {
1155 printf("free\t%08x\t\t%s:%d\n", p, file, line); fflush(stdout);
1156 free(p);
1157}
1158
1159#endif
1160
1161// prints a message to stdout if debug output is enabled
1162void printDebug(const char *format, ...) {
1163 if (debug == JNI_TRUE) {
1164 va_list args;
1165 fprintf(stdout, "sunpkcs11: ");
1166 va_start(args, format);
1167 vfprintf(stdout, format, args);
1168 va_end(args);
1169 fflush(stdout);
1170 }
1171}
1172
1173