Commit 17a9ffb8 authored by Michael Rauh's avatar Michael Rauh
Browse files

Remove obsolete reflection code

parent 150f9daf
/****************************************************************************
* Copyright (C) 2015-2018 ecsec GmbH.
* Copyright (C) 2015-2019 ecsec GmbH.
* All rights reserved.
* Contact: ecsec GmbH (info@ecsec.de)
*
......@@ -24,9 +24,8 @@ package org.openecard.scio;
import javax.annotation.Nonnull;
import javax.smartcardio.CardException;
import jnasmartcardio.Smartcardio.JnaPCSCException;
import org.openecard.common.ifd.scio.SCIOErrorCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
......@@ -36,50 +35,20 @@ import org.slf4j.LoggerFactory;
*/
public class PCSCExceptionExtractor {
private static final Logger LOG = LoggerFactory.getLogger(PCSCExceptionExtractor.class);
public static SCIOErrorCode getCode(@Nonnull CardException mainException) {
return getCode((Exception) mainException);
return getCode((JnaPCSCException) mainException);
}
/**
* Gets the actual error code from the given CardException.
* This method uses reflections to access the actual error code which is hidden in the Java SmartcardIO. In case no
* error code can be found, {@link SCIOErrorCode#SCARD_F_UNKNOWN_ERROR} is returned.
* Gets the actual error code from the given JnaPCSCException.
* In case no error code can be found, {@link SCIOErrorCode#SCARD_F_UNKNOWN_ERROR} is returned.
*
* @param mainException The exception coming from the Java SmartcardIO.
* @return The code extracted from the exception, or {@link SCIOErrorCode#SCARD_F_UNKNOWN_ERROR} if no code could be
* extracted.
*/
public static SCIOErrorCode getCode(@Nonnull Exception mainException) {
Throwable cause = getPCSCException(mainException);
// check the type of the cause over reflections because these classes might not be available (sun internal)
if (cause != null) {
try {
return SCIOErrorCode.valueOf(cause.getMessage());
} catch (IllegalArgumentException ex) {
return SCIOErrorCode.SCARD_F_UNKNOWN_ERROR;
}
} else {
return SCIOErrorCode.SCARD_F_UNKNOWN_ERROR;
}
}
public static boolean hasPCSCException(Exception mainException) {
return getPCSCException(mainException) != null;
}
private static Throwable getPCSCException(Exception mainException) {
Throwable cause = mainException.getCause();
// check the type of the cause over reflections because these classes might not be available (sun internal)
if (cause != null) {
Class<?> c = cause.getClass();
if ("sun.security.smartcardio.PCSCException".equals(c.getName())) {
return cause;
}
}
return null;
public static SCIOErrorCode getCode(@Nonnull JnaPCSCException mainException) {
return SCIOErrorCode.getErrorCode(Math.toIntExact(mainException.code));
}
}
/****************************************************************************
* Copyright (C) 2012-2018 ecsec GmbH.
* Copyright (C) 2012-2019 ecsec GmbH.
* All rights reserved.
* Contact: ecsec GmbH (info@ecsec.de)
*
......@@ -24,27 +24,10 @@ package org.openecard.scio;
import java.io.File;
import java.io.FileNotFoundException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.smartcardio.CardTerminals;
import javax.smartcardio.TerminalFactory;
import org.openecard.common.ifd.scio.NoSuchTerminal;
import org.openecard.common.ifd.scio.SCIOErrorCode;
import org.openecard.common.ifd.scio.SCIOException;
import org.openecard.common.ifd.scio.SCIOTerminal;
import jnasmartcardio.Smartcardio;
import org.openecard.common.ifd.scio.SCIOTerminals;
import org.openecard.common.ifd.scio.TerminalState;
import org.openecard.common.ifd.scio.TerminalWatcher;
import org.openecard.common.util.LinuxLibraryFinder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -64,8 +47,6 @@ public class PCSCFactory implements org.openecard.common.ifd.scio.TerminalFactor
private final String osName;
private TerminalFactory terminalFactory;
private final CompletableFuture<Void> initLock;
/**
* Default constructor with fixes for the faulty SmartcardIO library.
*
......@@ -79,41 +60,13 @@ public class PCSCFactory implements org.openecard.common.ifd.scio.TerminalFactor
System.setProperty("sun.security.smartcardio.library", libFile.getAbsolutePath());
}
this.initLock = new CompletableFuture<>();
try {
LOG.info("Trying to initialize PCSC subsystem.");
loadPCSC();
initLock.complete(null);
LOG.info("Successfully initialized PCSC subsystem");
terminalFactory = TerminalFactory.getInstance(ALGORITHM, null, new Smartcardio());
LOG.info("Successfully initialized PCSC subsystem.");
} catch (NoSuchAlgorithmException ex) {
LOG.error("Failed to initialize smartcard system.", ex);
if (isNoServiceException(ex)) {
new Thread(() -> {
while (! initLock.isDone()) {
try {
LOG.debug("Trying to initialize PCSC subsystem again.");
loadPCSC();
initLock.complete(null);
LOG.info("Successfully initialized PCSC subsystem");
} catch (NoSuchAlgorithmException exInner) {
if (isNoServiceException(exInner)) {
try {
LOG.debug("Retrying PCSC initialization in 5 seconds.");
Thread.sleep(5000);
} catch (InterruptedException ex2) {
return;
}
} else {
LOG.error("Failed to initialize smartcard system.", exInner);
throw new RuntimeException(exInner);
}
}
}
}).start();
} else {
throw ex;
}
LOG.error("Failed to initialize smartcard system.");
throw ex;
}
}
......@@ -128,150 +81,11 @@ public class PCSCFactory implements org.openecard.common.ifd.scio.TerminalFactor
@Override
public SCIOTerminals terminals() {
if (terminalFactory != null) {
return new PCSCTerminals(this);
} else {
// dummy for use while the initialization is not working properly
return new SCIOTerminals() {
@Override
public List<SCIOTerminal> list(SCIOTerminals.State state) throws SCIOException {
return Collections.emptyList();
}
@Override
public List<SCIOTerminal> list() throws SCIOException {
return Collections.emptyList();
}
@Override
public SCIOTerminal getTerminal(String name) throws NoSuchTerminal {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public TerminalWatcher getWatcher() throws SCIOException {
return new TerminalWatcher() {
@Override
public SCIOTerminals getTerminals() {
return terminals();
}
@Override
public List<TerminalState> start() throws SCIOException {
return Collections.emptyList();
}
@Override
public TerminalWatcher.StateChangeEvent waitForChange(long timeout) throws SCIOException {
try {
LOG.debug("Fake waiting for terminal changes during PCSC initialization phase.");
initLock.get(timeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException ex) {
// ignore
}
LOG.debug("Returning from fake terminal change wait.");
return new StateChangeEvent();
}
@Override
public TerminalWatcher.StateChangeEvent waitForChange() throws SCIOException {
return waitForChange(Long.MAX_VALUE);
}
};
}
};
}
return new PCSCTerminals(this);
}
TerminalFactory getRawFactory() {
return terminalFactory;
}
private static Integer versionCompare(String str1, String str2) {
// code taken from http://stackoverflow.com/a/6702029
String[] vals1 = str1.split("\\.");
String[] vals2 = str2.split("\\.");
int i = 0;
while (i < vals1.length && i < vals2.length && vals1[i].equals(vals2[i])) {
i++;
}
if (i < vals1.length && i < vals2.length) {
return Integer.signum(Integer.valueOf(vals1[i]).compareTo(Integer.valueOf(vals2[i])));
}
return Integer.signum(vals1.length - vals2.length);
}
final void loadPCSC() throws NoSuchAlgorithmException {
terminalFactory = TerminalFactory.getInstance(ALGORITHM, null);
}
void reloadPCSC() {
try {
reloadPCSCInt();
} catch (NoSuchAlgorithmException ex) {
// if it worked once it will work again
String msg = "PCSC changed it's algorithm. There is something really wrong.";
LOG.error(msg, ex);
throw new RuntimeException("PCSC changed it's algorithm. There is something really wrong.");
} catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException | NoSuchMethodException |
SecurityException ex) {
LOG.error("Failed to perform reflection magic to reload TerminalFactory.", ex);
} catch (InvocationTargetException ex) {
if (isNoServiceException(ex)) {
// silent drop after giving the system some time to recover for themselves
try {
Thread.sleep(5000);
} catch (InterruptedException ignore) {
Thread.currentThread().interrupt();
}
return;
}
LOG.error("Error while invoking PCSC restart functionality.");
}
}
private void reloadPCSCInt() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException,
NoSuchMethodException, InvocationTargetException, NoSuchAlgorithmException {
// code taken from http://stackoverflow.com/questions/16921785/
Class pcscterminal = Class.forName("sun.security.smartcardio.PCSCTerminals");
Field contextId = pcscterminal.getDeclaredField("contextId");
contextId.setAccessible(true);
if (contextId.getLong(pcscterminal) != 0L) {
// First get a new context value
Class pcsc = Class.forName("sun.security.smartcardio.PCSC");
Method SCardEstablishContext = pcsc.getDeclaredMethod("SCardEstablishContext", Integer.TYPE);
SCardEstablishContext.setAccessible(true);
Field SCARD_SCOPE_USER = pcsc.getDeclaredField("SCARD_SCOPE_USER");
SCARD_SCOPE_USER.setAccessible(true);
long newId = ((Long) SCardEstablishContext.invoke(pcsc, SCARD_SCOPE_USER.getInt(pcsc)));
contextId.setLong(pcscterminal, newId);
loadPCSC();
// Then clear the terminals in cache
CardTerminals terminals = terminalFactory.terminals();
Field fieldTerminals = pcscterminal.getDeclaredField("terminals");
fieldTerminals.setAccessible(true);
Map termObj = (Map) fieldTerminals.get(terminals);
termObj.clear();
}
}
private boolean isNoServiceException(Exception mainException) {
if (PCSCExceptionExtractor.hasPCSCException(mainException)) {
SCIOErrorCode code = PCSCExceptionExtractor.getCode(mainException);
if (code == SCIOErrorCode.SCARD_E_NO_SERVICE) {
return true;
}
}
return false;
}
}
/****************************************************************************
* Copyright (C) 2014-2015 TU Darmstadt.
* Copyright (C) 2014-2019 TU Darmstadt.
* All rights reserved.
* Contact: ecsec GmbH (info@ecsec.de)
*
......@@ -66,7 +66,6 @@ public class PCSCTerminals implements SCIOTerminals {
}
private void reloadFactory() {
terminalFactory.reloadPCSC();
loadTerminals();
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment