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