Path: blob/master/src/java.smartcardio/share/native/libj2pcsc/pcsc.c
41149 views
/*1* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/* disable asserts in product mode */26#ifndef DEBUG27#ifndef NDEBUG28#define NDEBUG29#endif30#endif3132#include <stdio.h>33#include <stdlib.h>34#include <string.h>35#include <assert.h>3637#include <winscard.h>3839// #define J2PCSC_DEBUG4041#ifdef J2PCSC_DEBUG42#define dprintf(s) printf(s)43#define dprintf1(s, p1) printf(s, p1)44#define dprintf2(s, p1, p2) printf(s, p1, p2)45#define dprintf3(s, p1, p2, p3) printf(s, p1, p2, p3)46#else47#define dprintf(s)48#define dprintf1(s, p1)49#define dprintf2(s, p1, p2)50#define dprintf3(s, p1, p2, p3)51#endif5253#include "sun_security_smartcardio_PCSC.h"5455#include "pcsc_md.h"5657#include "jni_util.h"5859#define MAX_STACK_BUFFER_SIZE 81926061// make the buffers larger than what should be necessary, just in case62#define ATR_BUFFER_SIZE 12863#define READERNAME_BUFFER_SIZE 12864#define RECEIVE_BUFFER_SIZE MAX_STACK_BUFFER_SIZE6566#define J2PCSC_EXCEPTION_NAME "sun/security/smartcardio/PCSCException"6768void throwOutOfMemoryError(JNIEnv *env, const char *msg) {69jclass cls = (*env)->FindClass(env, "java/lang/OutOfMemoryError");7071if (cls != NULL) /* Otherwise an exception has already been thrown */72(*env)->ThrowNew(env, cls, msg);7374}7576void throwPCSCException(JNIEnv* env, LONG code) {77jclass pcscClass;78jmethodID constructor;79jthrowable pcscException;8081pcscClass = (*env)->FindClass(env, J2PCSC_EXCEPTION_NAME);82if (pcscClass == NULL) {83return;84}85constructor = (*env)->GetMethodID(env, pcscClass, "<init>", "(I)V");86if (constructor == NULL) {87return;88}89pcscException = (jthrowable) (*env)->NewObject(env, pcscClass,90constructor, (jint)code);91if (pcscException != NULL) {92(*env)->Throw(env, pcscException);93}94}9596jboolean handleRV(JNIEnv* env, LONG code) {97if (code == SCARD_S_SUCCESS) {98return JNI_FALSE;99} else {100throwPCSCException(env, code);101return JNI_TRUE;102}103}104105JNIEXPORT jint JNICALL DEF_JNI_OnLoad(JavaVM *vm, void *reserved) {106return JNI_VERSION_1_4;107}108109JNIEXPORT jlong JNICALL Java_sun_security_smartcardio_PCSC_SCardEstablishContext110(JNIEnv *env, jclass thisClass, jint dwScope)111{112SCARDCONTEXT context = 0;113LONG rv;114dprintf("-establishContext\n");115rv = CALL_SCardEstablishContext(dwScope, NULL, NULL, &context);116if (handleRV(env, rv)) {117return 0;118}119// note: SCARDCONTEXT is typedef'd as long, so this works120return (jlong)context;121}122123/**124* Convert a multi string to a java string array,125*/126jobjectArray pcsc_multi2jstring(JNIEnv *env, char *spec) {127jobjectArray result;128jclass stringClass;129char *cp, **tab = NULL;130jstring js;131int cnt = 0;132133cp = spec;134while (*cp != 0) {135cp += (strlen(cp) + 1);136++cnt;137}138139tab = (char **)malloc(cnt * sizeof(char *));140if (tab == NULL) {141throwOutOfMemoryError(env, NULL);142return NULL;143}144145cnt = 0;146cp = spec;147while (*cp != 0) {148tab[cnt++] = cp;149cp += (strlen(cp) + 1);150}151152stringClass = (*env)->FindClass(env, "java/lang/String");153if (stringClass == NULL) {154free(tab);155return NULL;156}157158result = (*env)->NewObjectArray(env, cnt, stringClass, NULL);159if (result != NULL) {160while (cnt-- > 0) {161js = (*env)->NewStringUTF(env, tab[cnt]);162if ((*env)->ExceptionCheck(env)) {163free(tab);164return NULL;165}166(*env)->SetObjectArrayElement(env, result, cnt, js);167if ((*env)->ExceptionCheck(env)) {168free(tab);169return NULL;170}171(*env)->DeleteLocalRef(env, js);172}173}174free(tab);175return result;176}177178JNIEXPORT jobjectArray JNICALL Java_sun_security_smartcardio_PCSC_SCardListReaders179(JNIEnv *env, jclass thisClass, jlong jContext)180{181SCARDCONTEXT context = (SCARDCONTEXT)jContext;182LONG rv;183LPSTR mszReaders = NULL;184DWORD size = 0;185jobjectArray result;186187dprintf1("-context: %x\n", context);188rv = CALL_SCardListReaders(context, NULL, NULL, &size);189if (handleRV(env, rv)) {190return NULL;191}192dprintf1("-size: %d\n", size);193194if (size != 0) {195mszReaders = malloc(size);196if (mszReaders == NULL) {197throwOutOfMemoryError(env, NULL);198return NULL;199}200201rv = CALL_SCardListReaders(context, NULL, mszReaders, &size);202if (handleRV(env, rv)) {203free(mszReaders);204return NULL;205}206dprintf1("-String: %s\n", mszReaders);207} else {208return NULL;209}210211result = pcsc_multi2jstring(env, mszReaders);212free(mszReaders);213return result;214}215216JNIEXPORT jlong JNICALL Java_sun_security_smartcardio_PCSC_SCardConnect217(JNIEnv *env, jclass thisClass, jlong jContext, jstring jReaderName,218jint jShareMode, jint jPreferredProtocols)219{220SCARDCONTEXT context = (SCARDCONTEXT)jContext;221LONG rv;222LPCSTR readerName;223SCARDHANDLE card = 0;224DWORD proto = 0;225226readerName = (*env)->GetStringUTFChars(env, jReaderName, NULL);227if (readerName == NULL) {228return 0;229}230rv = CALL_SCardConnect(context, readerName, jShareMode, jPreferredProtocols, &card, &proto);231(*env)->ReleaseStringUTFChars(env, jReaderName, readerName);232dprintf1("-cardhandle: %x\n", card);233dprintf1("-protocol: %d\n", proto);234if (handleRV(env, rv)) {235return 0;236}237238return (jlong)card;239}240241JNIEXPORT jbyteArray JNICALL Java_sun_security_smartcardio_PCSC_SCardTransmit242(JNIEnv *env, jclass thisClass, jlong jCard, jint protocol,243jbyteArray jBuf, jint jOfs, jint jLen)244{245SCARDHANDLE card = (SCARDHANDLE)jCard;246LONG rv;247SCARD_IO_REQUEST sendPci;248unsigned char *sbuf;249unsigned char rbuf[RECEIVE_BUFFER_SIZE];250DWORD rlen = RECEIVE_BUFFER_SIZE;251int ofs = (int)jOfs;252int len = (int)jLen;253jbyteArray jOut;254255sendPci.dwProtocol = protocol;256sendPci.cbPciLength = sizeof(SCARD_IO_REQUEST);257258sbuf = (unsigned char *) ((*env)->GetByteArrayElements(env, jBuf, NULL));259if (sbuf == NULL) {260return NULL;261}262rv = CALL_SCardTransmit(card, &sendPci, sbuf + ofs, len, NULL, rbuf, &rlen);263(*env)->ReleaseByteArrayElements(env, jBuf, (jbyte *)sbuf, JNI_ABORT);264265if (handleRV(env, rv)) {266return NULL;267}268269jOut = (*env)->NewByteArray(env, rlen);270if (jOut != NULL) {271(*env)->SetByteArrayRegion(env, jOut, 0, rlen, (jbyte *)rbuf);272if ((*env)->ExceptionCheck(env)) {273return NULL;274}275}276return jOut;277}278279JNIEXPORT jbyteArray JNICALL Java_sun_security_smartcardio_PCSC_SCardStatus280(JNIEnv *env, jclass thisClass, jlong jCard, jbyteArray jStatus)281{282SCARDHANDLE card = (SCARDHANDLE)jCard;283LONG rv;284char readerName[READERNAME_BUFFER_SIZE];285DWORD readerLen = READERNAME_BUFFER_SIZE;286unsigned char atr[ATR_BUFFER_SIZE];287DWORD atrLen = ATR_BUFFER_SIZE;288DWORD state = 0;289DWORD protocol = 0;290jbyteArray jArray;291jbyte status[2];292293rv = CALL_SCardStatus(card, readerName, &readerLen, &state, &protocol, atr, &atrLen);294if (handleRV(env, rv)) {295return NULL;296}297dprintf1("-reader: %s\n", readerName);298dprintf1("-status: %d\n", state);299dprintf1("-protocol: %d\n", protocol);300301jArray = (*env)->NewByteArray(env, atrLen);302if (jArray == NULL) {303return NULL;304}305(*env)->SetByteArrayRegion(env, jArray, 0, atrLen, (jbyte *)atr);306if ((*env)->ExceptionCheck(env)) {307return NULL;308}309status[0] = (jbyte) state;310status[1] = (jbyte) protocol;311(*env)->SetByteArrayRegion(env, jStatus, 0, 2, status);312if ((*env)->ExceptionCheck(env)) {313return NULL;314}315return jArray;316}317318JNIEXPORT void JNICALL Java_sun_security_smartcardio_PCSC_SCardDisconnect319(JNIEnv *env, jclass thisClass, jlong jCard, jint jDisposition)320{321SCARDHANDLE card = (SCARDHANDLE)jCard;322LONG rv;323324rv = CALL_SCardDisconnect(card, jDisposition);325dprintf1("-disconnect: 0x%X\n", rv);326handleRV(env, rv);327return;328}329330JNIEXPORT jintArray JNICALL Java_sun_security_smartcardio_PCSC_SCardGetStatusChange331(JNIEnv *env, jclass thisClass, jlong jContext, jlong jTimeout,332jintArray jCurrentState, jobjectArray jReaderNames)333{334SCARDCONTEXT context = (SCARDCONTEXT)jContext;335LONG rv;336int readers = (*env)->GetArrayLength(env, jReaderNames);337SCARD_READERSTATE *readerState;338int i;339jintArray jEventState = NULL;340int *currentState = NULL;341const char *readerName;342343readerState = calloc(readers, sizeof(SCARD_READERSTATE));344if (readerState == NULL && readers > 0) {345throwOutOfMemoryError(env, NULL);346return NULL;347}348349currentState = (*env)->GetIntArrayElements(env, jCurrentState, NULL);350if (currentState == NULL) {351free(readerState);352return NULL;353}354355for (i = 0; i < readers; i++) {356readerState[i].szReader = NULL;357}358359for (i = 0; i < readers; i++) {360jobject jReaderName = (*env)->GetObjectArrayElement(env, jReaderNames, i);361if ((*env)->ExceptionCheck(env)) {362goto cleanup;363}364readerName = (*env)->GetStringUTFChars(env, jReaderName, NULL);365if (readerName == NULL) {366goto cleanup;367}368readerState[i].szReader = strdup(readerName);369(*env)->ReleaseStringUTFChars(env, jReaderName, readerName);370if (readerState[i].szReader == NULL) {371throwOutOfMemoryError(env, NULL);372goto cleanup;373}374readerState[i].pvUserData = NULL;375readerState[i].dwCurrentState = currentState[i];376readerState[i].dwEventState = SCARD_STATE_UNAWARE;377readerState[i].cbAtr = 0;378(*env)->DeleteLocalRef(env, jReaderName);379}380381if (readers > 0) {382rv = CALL_SCardGetStatusChange(context, (DWORD)jTimeout, readerState, readers);383if (handleRV(env, rv)) {384goto cleanup;385}386}387388jEventState = (*env)->NewIntArray(env, readers);389if (jEventState == NULL) {390goto cleanup;391}392for (i = 0; i < readers; i++) {393jint eventStateTmp;394dprintf3("-reader status %s: 0x%X, 0x%X\n", readerState[i].szReader,395readerState[i].dwCurrentState, readerState[i].dwEventState);396eventStateTmp = (jint)readerState[i].dwEventState;397(*env)->SetIntArrayRegion(env, jEventState, i, 1, &eventStateTmp);398if ((*env)->ExceptionCheck(env)) {399jEventState = NULL;400goto cleanup;401}402}403cleanup:404(*env)->ReleaseIntArrayElements(env, jCurrentState, currentState, JNI_ABORT);405for (i = 0; i < readers; i++) {406free((char *)readerState[i].szReader);407}408free(readerState);409return jEventState;410}411412JNIEXPORT void JNICALL Java_sun_security_smartcardio_PCSC_SCardBeginTransaction413(JNIEnv *env, jclass thisClass, jlong jCard)414{415SCARDHANDLE card = (SCARDHANDLE)jCard;416LONG rv;417418rv = CALL_SCardBeginTransaction(card);419dprintf1("-beginTransaction: 0x%X\n", rv);420handleRV(env, rv);421return;422}423424JNIEXPORT void JNICALL Java_sun_security_smartcardio_PCSC_SCardEndTransaction425(JNIEnv *env, jclass thisClass, jlong jCard, jint jDisposition)426{427SCARDHANDLE card = (SCARDHANDLE)jCard;428LONG rv;429430rv = CALL_SCardEndTransaction(card, jDisposition);431dprintf1("-endTransaction: 0x%X\n", rv);432handleRV(env, rv);433return;434}435436JNIEXPORT jbyteArray JNICALL Java_sun_security_smartcardio_PCSC_SCardControl437(JNIEnv *env, jclass thisClass, jlong jCard, jint jControlCode, jbyteArray jSendBuffer)438{439SCARDHANDLE card = (SCARDHANDLE)jCard;440LONG rv;441jbyte* sendBuffer;442jint sendBufferLength = (*env)->GetArrayLength(env, jSendBuffer);443jbyte receiveBuffer[MAX_STACK_BUFFER_SIZE];444jint receiveBufferLength = MAX_STACK_BUFFER_SIZE;445ULONG returnedLength = 0;446jbyteArray jReceiveBuffer;447448sendBuffer = (*env)->GetByteArrayElements(env, jSendBuffer, NULL);449if (sendBuffer == NULL) {450return NULL;451}452453#ifdef J2PCSC_DEBUG454{455int k;456printf("-control: 0x%X\n", jControlCode);457printf("-send: ");458for (k = 0; k < sendBufferLength; k++) {459printf("%02x ", sendBuffer[k]);460}461printf("\n");462}463#endif464465rv = CALL_SCardControl(card, jControlCode, sendBuffer, sendBufferLength,466receiveBuffer, receiveBufferLength, &returnedLength);467468(*env)->ReleaseByteArrayElements(env, jSendBuffer, sendBuffer, JNI_ABORT);469if (handleRV(env, rv)) {470return NULL;471}472473#ifdef J2PCSC_DEBUG474{475int k;476printf("-recv: ");477for (k = 0; k < returnedLength; k++) {478printf("%02x ", receiveBuffer[k]);479}480printf("\n");481}482#endif483484jReceiveBuffer = (*env)->NewByteArray(env, returnedLength);485if (jReceiveBuffer == NULL) {486return NULL;487}488(*env)->SetByteArrayRegion(env, jReceiveBuffer, 0, returnedLength, receiveBuffer);489if ((*env)->ExceptionCheck(env)) {490return NULL;491}492return jReceiveBuffer;493}494495496