blob: 17cf8513a5a5d50f54e4b7d464ebdf86ebb91285 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26/* disable asserts in product mode */
27#ifndef DEBUG
28 #ifndef NDEBUG
29 #define NDEBUG
30 #endif
31#endif
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <assert.h>
37
38#include <winscard.h>
39
40// #define J2PCSC_DEBUG
41
42#ifdef J2PCSC_DEBUG
43#define dprintf(s) printf(s)
44#define dprintf1(s, p1) printf(s, p1)
45#define dprintf2(s, p1, p2) printf(s, p1, p2)
46#define dprintf3(s, p1, p2, p3) printf(s, p1, p2, p3)
47#else
48#define dprintf(s)
49#define dprintf1(s, p1)
50#define dprintf2(s, p1, p2)
51#define dprintf3(s, p1, p2, p3)
52#endif
53
54#include "sun_security_smartcardio_PCSC.h"
55
56#include "pcsc_md.h"
57
58#define MAX_STACK_BUFFER_SIZE 8192
59
60// make the buffers larger than what should be necessary, just in case
61#define ATR_BUFFER_SIZE 128
62#define READERNAME_BUFFER_SIZE 128
63#define RECEIVE_BUFFER_SIZE MAX_STACK_BUFFER_SIZE
64
65#define J2PCSC_EXCEPTION_NAME "sun/security/smartcardio/PCSCException"
66
67void throwPCSCException(JNIEnv* env, LONG code) {
68 jclass pcscClass;
69 jmethodID constructor;
70 jthrowable pcscException;
71
72 pcscClass = (*env)->FindClass(env, J2PCSC_EXCEPTION_NAME);
73 assert(pcscClass != NULL);
74 constructor = (*env)->GetMethodID(env, pcscClass, "<init>", "(I)V");
75 assert(constructor != NULL);
76 pcscException = (jthrowable) (*env)->NewObject(env, pcscClass, constructor, (jint)code);
77 (*env)->Throw(env, pcscException);
78}
79
80jboolean handleRV(JNIEnv* env, LONG code) {
81 if (code == SCARD_S_SUCCESS) {
82 return JNI_FALSE;
83 } else {
84 throwPCSCException(env, code);
85 return JNI_TRUE;
86 }
87}
88
89JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
90 return JNI_VERSION_1_4;
91}
92
93JNIEXPORT jlong JNICALL Java_sun_security_smartcardio_PCSC_SCardEstablishContext
94 (JNIEnv *env, jclass thisClass, jint dwScope)
95{
96 SCARDCONTEXT context;
97 LONG rv;
98 dprintf("-establishContext\n");
99 rv = CALL_SCardEstablishContext(dwScope, NULL, NULL, &context);
100 if (handleRV(env, rv)) {
101 return 0;
102 }
103 // note: SCARDCONTEXT is typedef'd as long, so this works
104 return (jlong)context;
105}
106
107/**
108 * Convert a multi string to a java string array,
109 */
110jobjectArray pcsc_multi2jstring(JNIEnv *env, char *spec) {
111 jobjectArray result;
112 jclass stringClass;
113 char *cp, **tab;
114 jstring js;
115 int cnt = 0;
116
117 cp = spec;
118 while (*cp != 0) {
119 cp += (strlen(cp) + 1);
120 ++cnt;
121 }
122
123 tab = (char **)malloc(cnt * sizeof(char *));
124
125 cnt = 0;
126 cp = spec;
127 while (*cp != 0) {
128 tab[cnt++] = cp;
129 cp += (strlen(cp) + 1);
130 }
131
132 stringClass = (*env)->FindClass(env, "java/lang/String");
133 assert(stringClass != NULL);
134
135 result = (*env)->NewObjectArray(env, cnt, stringClass, NULL);
136 while (cnt-- > 0) {
137 js = (*env)->NewStringUTF(env, tab[cnt]);
138 (*env)->SetObjectArrayElement(env, result, cnt, js);
139 }
140 free(tab);
141 return result;
142}
143
144JNIEXPORT jobjectArray JNICALL Java_sun_security_smartcardio_PCSC_SCardListReaders
145 (JNIEnv *env, jclass thisClass, jlong jContext)
146{
147 SCARDCONTEXT context = (SCARDCONTEXT)jContext;
148 LONG rv;
149 LPTSTR mszReaders;
150 DWORD size;
151 jobjectArray result;
152
153 dprintf1("-context: %x\n", context);
154 rv = CALL_SCardListReaders(context, NULL, NULL, &size);
155 if (handleRV(env, rv)) {
156 return NULL;
157 }
158 dprintf1("-size: %d\n", size);
159
160 mszReaders = malloc(size);
161 rv = CALL_SCardListReaders(context, NULL, mszReaders, &size);
162 if (handleRV(env, rv)) {
163 free(mszReaders);
164 return NULL;
165 }
166 dprintf1("-String: %s\n", mszReaders);
167
168 result = pcsc_multi2jstring(env, mszReaders);
169 free(mszReaders);
170 return result;
171}
172
173JNIEXPORT jlong JNICALL Java_sun_security_smartcardio_PCSC_SCardConnect
174 (JNIEnv *env, jclass thisClass, jlong jContext, jstring jReaderName,
175 jint jShareMode, jint jPreferredProtocols)
176{
177 SCARDCONTEXT context = (SCARDCONTEXT)jContext;
178 LONG rv;
179 LPCTSTR readerName;
180 SCARDHANDLE card;
181 DWORD proto;
182
183 readerName = (*env)->GetStringUTFChars(env, jReaderName, NULL);
184 rv = CALL_SCardConnect(context, readerName, jShareMode, jPreferredProtocols, &card, &proto);
185 (*env)->ReleaseStringUTFChars(env, jReaderName, readerName);
186 dprintf1("-cardhandle: %x\n", card);
187 dprintf1("-protocol: %d\n", proto);
188 if (handleRV(env, rv)) {
189 return 0;
190 }
191
192 return (jlong)card;
193}
194
195JNIEXPORT jbyteArray JNICALL Java_sun_security_smartcardio_PCSC_SCardTransmit
196 (JNIEnv *env, jclass thisClass, jlong jCard, jint protocol,
197 jbyteArray jBuf, jint jOfs, jint jLen)
198{
199 SCARDHANDLE card = (SCARDHANDLE)jCard;
200 LONG rv;
201 SCARD_IO_REQUEST sendPci;
202 unsigned char *sbuf;
203 unsigned char rbuf[RECEIVE_BUFFER_SIZE];
204 DWORD rlen = RECEIVE_BUFFER_SIZE;
205 int ofs = (int)jOfs;
206 int len = (int)jLen;
207 jbyteArray jOut;
208
209 sendPci.dwProtocol = protocol;
210 sendPci.cbPciLength = sizeof(SCARD_IO_REQUEST);
211
212 sbuf = (unsigned char *) ((*env)->GetByteArrayElements(env, jBuf, NULL));
213 rv = CALL_SCardTransmit(card, &sendPci, sbuf + ofs, len, NULL, rbuf, &rlen);
214 (*env)->ReleaseByteArrayElements(env, jBuf, (jbyte *)sbuf, JNI_ABORT);
215
216 if (handleRV(env, rv)) {
217 return NULL;
218 }
219
220 jOut = (*env)->NewByteArray(env, rlen);
221 (*env)->SetByteArrayRegion(env, jOut, 0, rlen, (jbyte *)rbuf);
222 return jOut;
223}
224
225JNIEXPORT jbyteArray JNICALL Java_sun_security_smartcardio_PCSC_SCardStatus
226 (JNIEnv *env, jclass thisClass, jlong jCard, jbyteArray jStatus)
227{
228 SCARDHANDLE card = (SCARDHANDLE)jCard;
229 LONG rv;
230 char readerName[READERNAME_BUFFER_SIZE];
231 DWORD readerLen = READERNAME_BUFFER_SIZE;
232 unsigned char atr[ATR_BUFFER_SIZE];
233 DWORD atrLen = ATR_BUFFER_SIZE;
234 DWORD state;
235 DWORD protocol;
236 jbyteArray jArray;
237 jbyte tmp;
238
239 rv = CALL_SCardStatus(card, readerName, &readerLen, &state, &protocol, atr, &atrLen);
240 if (handleRV(env, rv)) {
241 return NULL;
242 }
243 dprintf1("-reader: %s\n", readerName);
244 dprintf1("-status: %d\n", state);
245 dprintf1("-protocol: %d\n", protocol);
246
247 jArray = (*env)->NewByteArray(env, atrLen);
248 (*env)->SetByteArrayRegion(env, jArray, 0, atrLen, (jbyte *)atr);
249
250 tmp = (jbyte)state;
251 (*env)->SetByteArrayRegion(env, jStatus, 0, 1, &tmp);
252 tmp = (jbyte)protocol;
253 (*env)->SetByteArrayRegion(env, jStatus, 1, 1, &tmp);
254
255 return jArray;
256}
257
258JNIEXPORT void JNICALL Java_sun_security_smartcardio_PCSC_SCardDisconnect
259 (JNIEnv *env, jclass thisClass, jlong jCard, jint jDisposition)
260{
261 SCARDHANDLE card = (SCARDHANDLE)jCard;
262 LONG rv;
263
264 rv = CALL_SCardDisconnect(card, jDisposition);
265 dprintf1("-disconnect: 0x%X\n", rv);
266 handleRV(env, rv);
267 return;
268}
269
270JNIEXPORT jintArray JNICALL Java_sun_security_smartcardio_PCSC_SCardGetStatusChange
271 (JNIEnv *env, jclass thisClass, jlong jContext, jlong jTimeout,
272 jintArray jCurrentState, jobjectArray jReaderNames)
273{
274 SCARDCONTEXT context = (SCARDCONTEXT)jContext;
275 LONG rv;
276 int readers = (*env)->GetArrayLength(env, jReaderNames);
277 SCARD_READERSTATE *readerState = malloc(readers * sizeof(SCARD_READERSTATE));
278 int i;
279 jintArray jEventState;
280 int *currentState = (*env)->GetIntArrayElements(env, jCurrentState, NULL);
281
282 for (i = 0; i < readers; i++) {
283 jobject jReaderName = (*env)->GetObjectArrayElement(env, jReaderNames, i);
284 readerState[i].szReader = (*env)->GetStringUTFChars(env, jReaderName, NULL);
285 readerState[i].pvUserData = NULL;
286 readerState[i].dwCurrentState = currentState[i];
287 readerState[i].dwEventState = SCARD_STATE_UNAWARE;
288 readerState[i].cbAtr = 0;
289 }
290 (*env)->ReleaseIntArrayElements(env, jCurrentState, currentState, JNI_ABORT);
291
292 rv = CALL_SCardGetStatusChange(context, (DWORD)jTimeout, readerState, readers);
293
294 jEventState = (*env)->NewIntArray(env, readers);
295 for (i = 0; i < readers; i++) {
296 jint eventStateTmp;
297 jobject jReaderName = (*env)->GetObjectArrayElement(env, jReaderNames, i);
298 dprintf3("-reader status %s: 0x%X, 0x%X\n", readerState[i].szReader,
299 readerState[i].dwCurrentState, readerState[i].dwEventState);
300 (*env)->ReleaseStringUTFChars(env, jReaderName, readerState[i].szReader);
301 eventStateTmp = (jint)readerState[i].dwEventState;
302 (*env)->SetIntArrayRegion(env, jEventState, i, 1, &eventStateTmp);
303 }
304 free(readerState);
305
306 handleRV(env, rv);
307 return jEventState;
308}
309
310JNIEXPORT void JNICALL Java_sun_security_smartcardio_PCSC_SCardBeginTransaction
311 (JNIEnv *env, jclass thisClass, jlong jCard)
312{
313 SCARDHANDLE card = (SCARDHANDLE)jCard;
314 LONG rv;
315
316 rv = CALL_SCardBeginTransaction(card);
317 dprintf1("-beginTransaction: 0x%X\n", rv);
318 handleRV(env, rv);
319 return;
320}
321
322JNIEXPORT void JNICALL Java_sun_security_smartcardio_PCSC_SCardEndTransaction
323 (JNIEnv *env, jclass thisClass, jlong jCard, jint jDisposition)
324{
325 SCARDHANDLE card = (SCARDHANDLE)jCard;
326 LONG rv;
327
328 rv = CALL_SCardEndTransaction(card, jDisposition);
329 dprintf1("-endTransaction: 0x%X\n", rv);
330 handleRV(env, rv);
331 return;
332}
333
334JNIEXPORT jbyteArray JNICALL Java_sun_security_smartcardio_PCSC_SCardControl
335 (JNIEnv *env, jclass thisClass, jlong jCard, jint jControlCode, jbyteArray jSendBuffer)
336{
337 SCARDHANDLE card = (SCARDHANDLE)jCard;
338 LONG rv;
339 jbyte* sendBuffer = (*env)->GetByteArrayElements(env, jSendBuffer, NULL);
340 jint sendBufferLength = (*env)->GetArrayLength(env, jSendBuffer);
341 jbyte receiveBuffer[MAX_STACK_BUFFER_SIZE];
342 jint receiveBufferLength = MAX_STACK_BUFFER_SIZE;
343 ULONG returnedLength = 0;
344 jbyteArray jReceiveBuffer;
345
346#ifdef J2PCSC_DEBUG
347{
348 int k;
349 printf("-control: 0x%X\n", jControlCode);
350 printf("-send: ");
351 for (k = 0; k < sendBufferLength; k++) {
352 printf("%02x ", sendBuffer[k]);
353 }
354 printf("\n");
355}
356#endif
357
358 rv = CALL_SCardControl(card, jControlCode, sendBuffer, sendBufferLength,
359 receiveBuffer, receiveBufferLength, &returnedLength);
360
361 (*env)->ReleaseByteArrayElements(env, jSendBuffer, sendBuffer, JNI_ABORT);
362 if (handleRV(env, rv)) {
363 return NULL;
364 }
365
366#ifdef J2PCSC_DEBUG
367{
368 int k;
369 printf("-recv: ");
370 for (k = 0; k < returnedLength; k++) {
371 printf("%02x ", receiveBuffer[k]);
372 }
373 printf("\n");
374}
375#endif
376
377 jReceiveBuffer = (*env)->NewByteArray(env, returnedLength);
378 (*env)->SetByteArrayRegion(env, jReceiveBuffer, 0, returnedLength, receiveBuffer);
379
380 return jReceiveBuffer;
381}