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