1 /* 2 * Copyright (c) 2005, 2014, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * 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 67 void throwOutOfMemoryError(JNIEnv *env, const char *msg) { 68 jclass cls = (*env)->FindClass(env, "java/lang/OutOfMemoryError"); 69 70 if (cls != NULL) /* Otherwise an exception has already been thrown */ 71 (*env)->ThrowNew(env, cls, msg); 72 73 } 74 75 void throwPCSCException(JNIEnv* env, LONG code) { 76 jclass pcscClass; 77 jmethodID constructor; 78 jthrowable pcscException; 79 80 pcscClass = (*env)->FindClass(env, J2PCSC_EXCEPTION_NAME); 81 if (pcscClass == NULL) { 82 return; 83 } 84 constructor = (*env)->GetMethodID(env, pcscClass, "<init>", "(I)V"); 85 if (constructor == NULL) { 86 return; 87 } 88 pcscException = (jthrowable) (*env)->NewObject(env, pcscClass, 89 constructor, (jint)code); 90 if (pcscException != NULL) { 91 (*env)->Throw(env, pcscException); 92 } 93 } 94 95 jboolean handleRV(JNIEnv* env, LONG code) { 96 if (code == SCARD_S_SUCCESS) { 97 return JNI_FALSE; 98 } else { 99 throwPCSCException(env, code); 100 return JNI_TRUE; 101 } 102 } 103 104 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { 105 return JNI_VERSION_1_4; 106 } 107 108 JNIEXPORT jlong JNICALL Java_sun_security_smartcardio_PCSC_SCardEstablishContext 109 (JNIEnv *env, jclass thisClass, jint dwScope) 110 { 111 SCARDCONTEXT context; 112 LONG rv; 113 dprintf("-establishContext\n"); 114 rv = CALL_SCardEstablishContext(dwScope, NULL, NULL, &context); 115 if (handleRV(env, rv)) { 116 return 0; 117 } 118 // note: SCARDCONTEXT is typedef'd as long, so this works 119 return (jlong)context; 120 } 121 122 /** 123 * Convert a multi string to a java string array, 124 */ 125 jobjectArray pcsc_multi2jstring(JNIEnv *env, char *spec) { 126 jobjectArray result; 127 jclass stringClass; 128 char *cp, **tab; 129 jstring js; 130 int cnt = 0; 131 132 cp = spec; 133 while (*cp != 0) { 134 cp += (strlen(cp) + 1); 135 ++cnt; 136 } 137 138 tab = (char **)malloc(cnt * sizeof(char *)); 139 if (tab == NULL) { 140 throwOutOfMemoryError(env, NULL); 141 return NULL; 142 } 143 144 cnt = 0; 145 cp = spec; 146 while (*cp != 0) { 147 tab[cnt++] = cp; 148 cp += (strlen(cp) + 1); 149 } 150 151 stringClass = (*env)->FindClass(env, "java/lang/String"); 152 if (stringClass == NULL) { 153 free(tab); 154 return NULL; 155 } 156 157 result = (*env)->NewObjectArray(env, cnt, stringClass, NULL); 158 if (result != NULL) { 159 while (cnt-- > 0) { 160 js = (*env)->NewStringUTF(env, tab[cnt]); 161 if ((*env)->ExceptionCheck(env)) { 162 free(tab); 163 return NULL; 164 } 165 (*env)->SetObjectArrayElement(env, result, cnt, js); 166 if ((*env)->ExceptionCheck(env)) { 167 free(tab); 168 return NULL; 169 } 170 (*env)->DeleteLocalRef(env, js); 171 } 172 } 173 free(tab); 174 return result; 175 } 176 177 JNIEXPORT jobjectArray JNICALL Java_sun_security_smartcardio_PCSC_SCardListReaders 178 (JNIEnv *env, jclass thisClass, jlong jContext) 179 { 180 SCARDCONTEXT context = (SCARDCONTEXT)jContext; 181 LONG rv; 182 LPTSTR mszReaders; 183 DWORD size; 184 jobjectArray result; 185 186 dprintf1("-context: %x\n", context); 187 rv = CALL_SCardListReaders(context, NULL, NULL, &size); 188 if (handleRV(env, rv)) { 189 return NULL; 190 } 191 dprintf1("-size: %d\n", size); 192 193 mszReaders = malloc(size); 194 if (mszReaders == NULL) { 195 throwOutOfMemoryError(env, NULL); 196 return NULL; 197 } 198 199 rv = CALL_SCardListReaders(context, NULL, mszReaders, &size); 200 if (handleRV(env, rv)) { 201 free(mszReaders); 202 return NULL; 203 } 204 dprintf1("-String: %s\n", mszReaders); 205 206 result = pcsc_multi2jstring(env, mszReaders); 207 free(mszReaders); 208 return result; 209 } 210 211 JNIEXPORT jlong JNICALL Java_sun_security_smartcardio_PCSC_SCardConnect 212 (JNIEnv *env, jclass thisClass, jlong jContext, jstring jReaderName, 213 jint jShareMode, jint jPreferredProtocols) 214 { 215 SCARDCONTEXT context = (SCARDCONTEXT)jContext; 216 LONG rv; 217 LPCTSTR readerName; 218 SCARDHANDLE card; 219 DWORD proto; 220 221 readerName = (*env)->GetStringUTFChars(env, jReaderName, NULL); 222 if (readerName == NULL) { 223 return 0; 224 } 225 rv = CALL_SCardConnect(context, readerName, jShareMode, jPreferredProtocols, &card, &proto); 226 (*env)->ReleaseStringUTFChars(env, jReaderName, readerName); 227 dprintf1("-cardhandle: %x\n", card); 228 dprintf1("-protocol: %d\n", proto); 229 if (handleRV(env, rv)) { 230 return 0; 231 } 232 233 return (jlong)card; 234 } 235 236 JNIEXPORT jbyteArray JNICALL Java_sun_security_smartcardio_PCSC_SCardTransmit 237 (JNIEnv *env, jclass thisClass, jlong jCard, jint protocol, 238 jbyteArray jBuf, jint jOfs, jint jLen) 239 { 240 SCARDHANDLE card = (SCARDHANDLE)jCard; 241 LONG rv; 242 SCARD_IO_REQUEST sendPci; 243 unsigned char *sbuf; 244 unsigned char rbuf[RECEIVE_BUFFER_SIZE]; 245 DWORD rlen = RECEIVE_BUFFER_SIZE; 246 int ofs = (int)jOfs; 247 int len = (int)jLen; 248 jbyteArray jOut; 249 250 sendPci.dwProtocol = protocol; 251 sendPci.cbPciLength = sizeof(SCARD_IO_REQUEST); 252 253 sbuf = (unsigned char *) ((*env)->GetByteArrayElements(env, jBuf, NULL)); 254 if (sbuf == NULL) { 255 return NULL; 256 } 257 rv = CALL_SCardTransmit(card, &sendPci, sbuf + ofs, len, NULL, rbuf, &rlen); 258 (*env)->ReleaseByteArrayElements(env, jBuf, (jbyte *)sbuf, JNI_ABORT); 259 260 if (handleRV(env, rv)) { 261 return NULL; 262 } 263 264 jOut = (*env)->NewByteArray(env, rlen); 265 if (jOut != NULL) { 266 (*env)->SetByteArrayRegion(env, jOut, 0, rlen, (jbyte *)rbuf); 267 if ((*env)->ExceptionCheck(env)) { 268 return NULL; 269 } 270 } 271 return jOut; 272 } 273 274 JNIEXPORT jbyteArray JNICALL Java_sun_security_smartcardio_PCSC_SCardStatus 275 (JNIEnv *env, jclass thisClass, jlong jCard, jbyteArray jStatus) 276 { 277 SCARDHANDLE card = (SCARDHANDLE)jCard; 278 LONG rv; 279 char readerName[READERNAME_BUFFER_SIZE]; 280 DWORD readerLen = READERNAME_BUFFER_SIZE; 281 unsigned char atr[ATR_BUFFER_SIZE]; 282 DWORD atrLen = ATR_BUFFER_SIZE; 283 DWORD state; 284 DWORD protocol; 285 jbyteArray jArray; 286 jbyte status[2]; 287 288 rv = CALL_SCardStatus(card, readerName, &readerLen, &state, &protocol, atr, &atrLen); 289 if (handleRV(env, rv)) { 290 return NULL; 291 } 292 dprintf1("-reader: %s\n", readerName); 293 dprintf1("-status: %d\n", state); 294 dprintf1("-protocol: %d\n", protocol); 295 296 jArray = (*env)->NewByteArray(env, atrLen); 297 if (jArray == NULL) { 298 return NULL; 299 } 300 (*env)->SetByteArrayRegion(env, jArray, 0, atrLen, (jbyte *)atr); 301 if ((*env)->ExceptionCheck(env)) { 302 return NULL; 303 } 304 status[0] = (jbyte) state; 305 status[1] = (jbyte) protocol; 306 (*env)->SetByteArrayRegion(env, jStatus, 0, 2, status); 307 if ((*env)->ExceptionCheck(env)) { 308 return NULL; 309 } 310 return jArray; 311 } 312 313 JNIEXPORT void JNICALL Java_sun_security_smartcardio_PCSC_SCardDisconnect 314 (JNIEnv *env, jclass thisClass, jlong jCard, jint jDisposition) 315 { 316 SCARDHANDLE card = (SCARDHANDLE)jCard; 317 LONG rv; 318 319 rv = CALL_SCardDisconnect(card, jDisposition); 320 dprintf1("-disconnect: 0x%X\n", rv); 321 handleRV(env, rv); 322 return; 323 } 324 325 JNIEXPORT jintArray JNICALL Java_sun_security_smartcardio_PCSC_SCardGetStatusChange 326 (JNIEnv *env, jclass thisClass, jlong jContext, jlong jTimeout, 327 jintArray jCurrentState, jobjectArray jReaderNames) 328 { 329 SCARDCONTEXT context = (SCARDCONTEXT)jContext; 330 LONG rv; 331 int readers = (*env)->GetArrayLength(env, jReaderNames); 332 SCARD_READERSTATE *readerState; 333 int i; 334 jintArray jEventState = NULL; 335 int *currentState = NULL; 336 const char *readerName; 337 338 readerState = calloc(readers, sizeof(SCARD_READERSTATE)); 339 if (readerState == NULL) { 340 throwOutOfMemoryError(env, NULL); 341 return NULL; 342 } 343 344 currentState = (*env)->GetIntArrayElements(env, jCurrentState, NULL); 345 if (currentState == NULL) { 346 free(readerState); 347 return NULL; 348 } 349 350 for (i = 0; i < readers; i++) { 351 jobject jReaderName = (*env)->GetObjectArrayElement(env, jReaderNames, i); 352 if ((*env)->ExceptionCheck(env)) { 353 goto cleanup; 354 } 355 readerName = (*env)->GetStringUTFChars(env, jReaderName, NULL); 356 if (readerName == NULL) { 357 goto cleanup; 358 } 359 readerState[i].szReader = strdup(readerName); 360 (*env)->ReleaseStringUTFChars(env, jReaderName, readerName); 361 if (readerState[i].szReader == NULL) { 362 throwOutOfMemoryError(env, NULL); 363 goto cleanup; 364 } 365 readerState[i].pvUserData = NULL; 366 readerState[i].dwCurrentState = currentState[i]; 367 readerState[i].dwEventState = SCARD_STATE_UNAWARE; 368 readerState[i].cbAtr = 0; 369 (*env)->DeleteLocalRef(env, jReaderName); 370 } 371 372 rv = CALL_SCardGetStatusChange(context, (DWORD)jTimeout, readerState, readers); 373 if (handleRV(env, rv)) { 374 goto cleanup; 375 } 376 377 jEventState = (*env)->NewIntArray(env, readers); 378 if (jEventState == NULL) { 379 goto cleanup; 380 } 381 for (i = 0; i < readers; i++) { 382 jint eventStateTmp; 383 dprintf3("-reader status %s: 0x%X, 0x%X\n", readerState[i].szReader, 384 readerState[i].dwCurrentState, readerState[i].dwEventState); 385 eventStateTmp = (jint)readerState[i].dwEventState; 386 (*env)->SetIntArrayRegion(env, jEventState, i, 1, &eventStateTmp); 387 if ((*env)->ExceptionCheck(env)) { 388 jEventState = NULL; 389 goto cleanup; 390 } 391 } 392 cleanup: 393 (*env)->ReleaseIntArrayElements(env, jCurrentState, currentState, JNI_ABORT); 394 for (i = 0; i < readers; i++) { 395 free((char *)readerState[i].szReader); 396 } 397 free(readerState); 398 return jEventState; 399 } 400 401 JNIEXPORT void JNICALL Java_sun_security_smartcardio_PCSC_SCardBeginTransaction 402 (JNIEnv *env, jclass thisClass, jlong jCard) 403 { 404 SCARDHANDLE card = (SCARDHANDLE)jCard; 405 LONG rv; 406 407 rv = CALL_SCardBeginTransaction(card); 408 dprintf1("-beginTransaction: 0x%X\n", rv); 409 handleRV(env, rv); 410 return; 411 } 412 413 JNIEXPORT void JNICALL Java_sun_security_smartcardio_PCSC_SCardEndTransaction 414 (JNIEnv *env, jclass thisClass, jlong jCard, jint jDisposition) 415 { 416 SCARDHANDLE card = (SCARDHANDLE)jCard; 417 LONG rv; 418 419 rv = CALL_SCardEndTransaction(card, jDisposition); 420 dprintf1("-endTransaction: 0x%X\n", rv); 421 handleRV(env, rv); 422 return; 423 } 424 425 JNIEXPORT jbyteArray JNICALL Java_sun_security_smartcardio_PCSC_SCardControl 426 (JNIEnv *env, jclass thisClass, jlong jCard, jint jControlCode, jbyteArray jSendBuffer) 427 { 428 SCARDHANDLE card = (SCARDHANDLE)jCard; 429 LONG rv; 430 jbyte* sendBuffer; 431 jint sendBufferLength = (*env)->GetArrayLength(env, jSendBuffer); 432 jbyte receiveBuffer[MAX_STACK_BUFFER_SIZE]; 433 jint receiveBufferLength = MAX_STACK_BUFFER_SIZE; 434 ULONG returnedLength = 0; 435 jbyteArray jReceiveBuffer; 436 437 sendBuffer = (*env)->GetByteArrayElements(env, jSendBuffer, NULL); 438 if (sendBuffer == NULL) { 439 return NULL; 440 } 441 442 #ifdef J2PCSC_DEBUG 443 { 444 int k; 445 printf("-control: 0x%X\n", jControlCode); 446 printf("-send: "); 447 for (k = 0; k < sendBufferLength; k++) { 448 printf("%02x ", sendBuffer[k]); 449 } 450 printf("\n"); 451 } 452 #endif 453 454 rv = CALL_SCardControl(card, jControlCode, sendBuffer, sendBufferLength, 455 receiveBuffer, receiveBufferLength, &returnedLength); 456 457 (*env)->ReleaseByteArrayElements(env, jSendBuffer, sendBuffer, JNI_ABORT); 458 if (handleRV(env, rv)) { 459 return NULL; 460 } 461 462 #ifdef J2PCSC_DEBUG 463 { 464 int k; 465 printf("-recv: "); 466 for (k = 0; k < returnedLength; k++) { 467 printf("%02x ", receiveBuffer[k]); 468 } 469 printf("\n"); 470 } 471 #endif 472 473 jReceiveBuffer = (*env)->NewByteArray(env, returnedLength); 474 if (jReceiveBuffer == NULL) { 475 return NULL; 476 } 477 (*env)->SetByteArrayRegion(env, jReceiveBuffer, 0, returnedLength, receiveBuffer); 478 if ((*env)->ExceptionCheck(env)) { 479 return NULL; 480 } 481 return jReceiveBuffer; 482 }