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 = 0; 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 = NULL; 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 = NULL; 183 DWORD size = 0; 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 if (size) { 194 mszReaders = malloc(size); 195 if (mszReaders == NULL) { 196 throwOutOfMemoryError(env, NULL); 197 return NULL; 198 } 199 200 rv = CALL_SCardListReaders(context, NULL, mszReaders, &size); 201 if (handleRV(env, rv)) { 202 free(mszReaders); 203 return NULL; 204 } 205 dprintf1("-String: %s\n", mszReaders); 206 } 207 208 result = pcsc_multi2jstring(env, mszReaders); 209 free(mszReaders); 210 return result; 211 } 212 213 JNIEXPORT jlong JNICALL Java_sun_security_smartcardio_PCSC_SCardConnect 214 (JNIEnv *env, jclass thisClass, jlong jContext, jstring jReaderName, 215 jint jShareMode, jint jPreferredProtocols) 216 { 217 SCARDCONTEXT context = (SCARDCONTEXT)jContext; 218 LONG rv; 219 LPCTSTR readerName; 220 SCARDHANDLE card = 0; 221 DWORD proto = 0; 222 223 readerName = (*env)->GetStringUTFChars(env, jReaderName, NULL); 224 if (readerName == NULL) { 225 return 0; 226 } 227 rv = CALL_SCardConnect(context, readerName, jShareMode, jPreferredProtocols, &card, &proto); 228 (*env)->ReleaseStringUTFChars(env, jReaderName, readerName); 229 dprintf1("-cardhandle: %x\n", card); 230 dprintf1("-protocol: %d\n", proto); 231 if (handleRV(env, rv)) { 232 return 0; 233 } 234 235 return (jlong)card; 236 } 237 238 JNIEXPORT jbyteArray JNICALL Java_sun_security_smartcardio_PCSC_SCardTransmit 239 (JNIEnv *env, jclass thisClass, jlong jCard, jint protocol, 240 jbyteArray jBuf, jint jOfs, jint jLen) 241 { 242 SCARDHANDLE card = (SCARDHANDLE)jCard; 243 LONG rv; 244 SCARD_IO_REQUEST sendPci; 245 unsigned char *sbuf; 246 unsigned char rbuf[RECEIVE_BUFFER_SIZE]; 247 DWORD rlen = RECEIVE_BUFFER_SIZE; 248 int ofs = (int)jOfs; 249 int len = (int)jLen; 250 jbyteArray jOut; 251 252 sendPci.dwProtocol = protocol; 253 sendPci.cbPciLength = sizeof(SCARD_IO_REQUEST); 254 255 sbuf = (unsigned char *) ((*env)->GetByteArrayElements(env, jBuf, NULL)); 256 if (sbuf == NULL) { 257 return NULL; 258 } 259 rv = CALL_SCardTransmit(card, &sendPci, sbuf + ofs, len, NULL, rbuf, &rlen); 260 (*env)->ReleaseByteArrayElements(env, jBuf, (jbyte *)sbuf, JNI_ABORT); 261 262 if (handleRV(env, rv)) { 263 return NULL; 264 } 265 266 jOut = (*env)->NewByteArray(env, rlen); 267 if (jOut != NULL) { 268 (*env)->SetByteArrayRegion(env, jOut, 0, rlen, (jbyte *)rbuf); 269 if ((*env)->ExceptionCheck(env)) { 270 return NULL; 271 } 272 } 273 return jOut; 274 } 275 276 JNIEXPORT jbyteArray JNICALL Java_sun_security_smartcardio_PCSC_SCardStatus 277 (JNIEnv *env, jclass thisClass, jlong jCard, jbyteArray jStatus) 278 { 279 SCARDHANDLE card = (SCARDHANDLE)jCard; 280 LONG rv; 281 char readerName[READERNAME_BUFFER_SIZE]; 282 DWORD readerLen = READERNAME_BUFFER_SIZE; 283 unsigned char atr[ATR_BUFFER_SIZE]; 284 DWORD atrLen = ATR_BUFFER_SIZE; 285 DWORD state = 0; 286 DWORD protocol = 0; 287 jbyteArray jArray; 288 jbyte status[2]; 289 290 rv = CALL_SCardStatus(card, readerName, &readerLen, &state, &protocol, atr, &atrLen); 291 if (handleRV(env, rv)) { 292 return NULL; 293 } 294 dprintf1("-reader: %s\n", readerName); 295 dprintf1("-status: %d\n", state); 296 dprintf1("-protocol: %d\n", protocol); 297 298 jArray = (*env)->NewByteArray(env, atrLen); 299 if (jArray == NULL) { 300 return NULL; 301 } 302 (*env)->SetByteArrayRegion(env, jArray, 0, atrLen, (jbyte *)atr); 303 if ((*env)->ExceptionCheck(env)) { 304 return NULL; 305 } 306 status[0] = (jbyte) state; 307 status[1] = (jbyte) protocol; 308 (*env)->SetByteArrayRegion(env, jStatus, 0, 2, status); 309 if ((*env)->ExceptionCheck(env)) { 310 return NULL; 311 } 312 return jArray; 313 } 314 315 JNIEXPORT void JNICALL Java_sun_security_smartcardio_PCSC_SCardDisconnect 316 (JNIEnv *env, jclass thisClass, jlong jCard, jint jDisposition) 317 { 318 SCARDHANDLE card = (SCARDHANDLE)jCard; 319 LONG rv; 320 321 rv = CALL_SCardDisconnect(card, jDisposition); 322 dprintf1("-disconnect: 0x%X\n", rv); 323 handleRV(env, rv); 324 return; 325 } 326 327 JNIEXPORT jintArray JNICALL Java_sun_security_smartcardio_PCSC_SCardGetStatusChange 328 (JNIEnv *env, jclass thisClass, jlong jContext, jlong jTimeout, 329 jintArray jCurrentState, jobjectArray jReaderNames) 330 { 331 SCARDCONTEXT context = (SCARDCONTEXT)jContext; 332 LONG rv; 333 int readers = (*env)->GetArrayLength(env, jReaderNames); 334 SCARD_READERSTATE *readerState; 335 int i; 336 jintArray jEventState = NULL; 337 int *currentState = NULL; 338 const char *readerName; 339 340 readerState = calloc(readers, sizeof(SCARD_READERSTATE)); 341 if (readerState == NULL && readers > 0) { 342 throwOutOfMemoryError(env, NULL); 343 return NULL; 344 } 345 346 currentState = (*env)->GetIntArrayElements(env, jCurrentState, NULL); 347 if (currentState == NULL) { 348 free(readerState); 349 return NULL; 350 } 351 352 for (i = 0; i < readers; i++) { 353 readerState[i].szReader = NULL; 354 } 355 356 for (i = 0; i < readers; i++) { 357 jobject jReaderName = (*env)->GetObjectArrayElement(env, jReaderNames, i); 358 if ((*env)->ExceptionCheck(env)) { 359 goto cleanup; 360 } 361 readerName = (*env)->GetStringUTFChars(env, jReaderName, NULL); 362 if (readerName == NULL) { 363 goto cleanup; 364 } 365 readerState[i].szReader = strdup(readerName); 366 (*env)->ReleaseStringUTFChars(env, jReaderName, readerName); 367 if (readerState[i].szReader == NULL) { 368 throwOutOfMemoryError(env, NULL); 369 goto cleanup; 370 } 371 readerState[i].pvUserData = NULL; 372 readerState[i].dwCurrentState = currentState[i]; 373 readerState[i].dwEventState = SCARD_STATE_UNAWARE; 374 readerState[i].cbAtr = 0; 375 (*env)->DeleteLocalRef(env, jReaderName); 376 } 377 378 if (readers > 0) { 379 rv = CALL_SCardGetStatusChange(context, (DWORD)jTimeout, readerState, readers); 380 if (handleRV(env, rv)) { 381 goto cleanup; 382 } 383 } 384 385 jEventState = (*env)->NewIntArray(env, readers); 386 if (jEventState == NULL) { 387 goto cleanup; 388 } 389 for (i = 0; i < readers; i++) { 390 jint eventStateTmp; 391 dprintf3("-reader status %s: 0x%X, 0x%X\n", readerState[i].szReader, 392 readerState[i].dwCurrentState, readerState[i].dwEventState); 393 eventStateTmp = (jint)readerState[i].dwEventState; 394 (*env)->SetIntArrayRegion(env, jEventState, i, 1, &eventStateTmp); 395 if ((*env)->ExceptionCheck(env)) { 396 jEventState = NULL; 397 goto cleanup; 398 } 399 } 400 cleanup: 401 (*env)->ReleaseIntArrayElements(env, jCurrentState, currentState, JNI_ABORT); 402 for (i = 0; i < readers; i++) { 403 free((char *)readerState[i].szReader); 404 } 405 free(readerState); 406 return jEventState; 407 } 408 409 JNIEXPORT void JNICALL Java_sun_security_smartcardio_PCSC_SCardBeginTransaction 410 (JNIEnv *env, jclass thisClass, jlong jCard) 411 { 412 SCARDHANDLE card = (SCARDHANDLE)jCard; 413 LONG rv; 414 415 rv = CALL_SCardBeginTransaction(card); 416 dprintf1("-beginTransaction: 0x%X\n", rv); 417 handleRV(env, rv); 418 return; 419 } 420 421 JNIEXPORT void JNICALL Java_sun_security_smartcardio_PCSC_SCardEndTransaction 422 (JNIEnv *env, jclass thisClass, jlong jCard, jint jDisposition) 423 { 424 SCARDHANDLE card = (SCARDHANDLE)jCard; 425 LONG rv; 426 427 rv = CALL_SCardEndTransaction(card, jDisposition); 428 dprintf1("-endTransaction: 0x%X\n", rv); 429 handleRV(env, rv); 430 return; 431 } 432 433 JNIEXPORT jbyteArray JNICALL Java_sun_security_smartcardio_PCSC_SCardControl 434 (JNIEnv *env, jclass thisClass, jlong jCard, jint jControlCode, jbyteArray jSendBuffer) 435 { 436 SCARDHANDLE card = (SCARDHANDLE)jCard; 437 LONG rv; 438 jbyte* sendBuffer; 439 jint sendBufferLength = (*env)->GetArrayLength(env, jSendBuffer); 440 jbyte receiveBuffer[MAX_STACK_BUFFER_SIZE]; 441 jint receiveBufferLength = MAX_STACK_BUFFER_SIZE; 442 ULONG returnedLength = 0; 443 jbyteArray jReceiveBuffer; 444 445 sendBuffer = (*env)->GetByteArrayElements(env, jSendBuffer, NULL); 446 if (sendBuffer == NULL) { 447 return NULL; 448 } 449 450 #ifdef J2PCSC_DEBUG 451 { 452 int k; 453 printf("-control: 0x%X\n", jControlCode); 454 printf("-send: "); 455 for (k = 0; k < sendBufferLength; k++) { 456 printf("%02x ", sendBuffer[k]); 457 } 458 printf("\n"); 459 } 460 #endif 461 462 rv = CALL_SCardControl(card, jControlCode, sendBuffer, sendBufferLength, 463 receiveBuffer, receiveBufferLength, &returnedLength); 464 465 (*env)->ReleaseByteArrayElements(env, jSendBuffer, sendBuffer, JNI_ABORT); 466 if (handleRV(env, rv)) { 467 return NULL; 468 } 469 470 #ifdef J2PCSC_DEBUG 471 { 472 int k; 473 printf("-recv: "); 474 for (k = 0; k < returnedLength; k++) { 475 printf("%02x ", receiveBuffer[k]); 476 } 477 printf("\n"); 478 } 479 #endif 480 481 jReceiveBuffer = (*env)->NewByteArray(env, returnedLength); 482 if (jReceiveBuffer == NULL) { 483 return NULL; 484 } 485 (*env)->SetByteArrayRegion(env, jReceiveBuffer, 0, returnedLength, receiveBuffer); 486 if ((*env)->ExceptionCheck(env)) { 487 return NULL; 488 } 489 return jReceiveBuffer; 490 }