Commit c9f98d46 authored by Tobias Wich's avatar Tobias Wich
Browse files

Merge branch 'win-init'

parents bed826fa 9781639b
/****************************************************************************
* Copyright (C) 2015 ecsec GmbH.
* Copyright (C) 2015-2019 ecsec GmbH.
* All rights reserved.
* Contact: ecsec GmbH (info@ecsec.de)
*
......@@ -154,9 +154,9 @@ public enum SCIOErrorCode {
/** No PIN was presented to the smart card. */
SCARD_W_CARD_NOT_AUTHENTICATED (0x8010006F);
private final int[] codes;
private final long[] codes;
private SCIOErrorCode(int... codes) {
private SCIOErrorCode(long... codes) {
this.codes = codes;
}
......@@ -166,8 +166,8 @@ public enum SCIOErrorCode {
* @param code Code to test.
* @return {@code true} if the code represents this enum instance, {@code false} otherwise.
*/
public boolean matchesCode(int code) {
for (int c : codes) {
public boolean matchesCode(long code) {
for (long c : codes) {
if (c == code) {
return true;
}
......@@ -181,15 +181,25 @@ public enum SCIOErrorCode {
* @param code The code for which to look up the enum entry.
* @return The entry matching the given code, or {@link #SCARD_F_UNKNOWN_ERROR} if no known code has been given.
*/
public static SCIOErrorCode getErrorCode(int code) {
public static SCIOErrorCode getErrorCode(long code) {
// no index, just walk over each code, doesn't happen so often that performance should be a problem
for (SCIOErrorCode next : SCIOErrorCode.values()) {
if (next.matchesCode(code)) {
return next;
}
}
// no match found, unkown error
// no match found, unknown error
return SCARD_F_UNKNOWN_ERROR;
}
public static long getLong(SCIOErrorCode code) {
for (SCIOErrorCode next : SCIOErrorCode.values()) {
if (next.name().equals(code.name())) {
return next.codes[0];
}
}
// no match found, unknown error (SCARD_F_UNKNOWN_ERROR)
return -2146435052;
}
}
......@@ -24,6 +24,11 @@
<artifactId>wsdef-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.github.jnasmartcardio</groupId>
<artifactId>jnasmartcardio</artifactId>
<version>0.2.7</version>
</dependency>
</dependencies>
</project>
/****************************************************************************
* 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(mainException.code);
}
}
/****************************************************************************
* Copyright (C) 2012-2018 ecsec GmbH.
* Copyright (C) 2012-2019 ecsec GmbH.
* All rights reserved.
* Contact: ecsec GmbH (info@ecsec.de)
*
......@@ -24,13 +24,9 @@ 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 javax.smartcardio.CardTerminals;
import javax.smartcardio.TerminalFactory;
import org.openecard.common.ifd.scio.SCIOErrorCode;
import jnasmartcardio.Smartcardio;
import org.openecard.common.ifd.scio.SCIOTerminals;
import org.openecard.common.util.LinuxLibraryFinder;
import org.slf4j.Logger;
......@@ -63,12 +59,24 @@ public class PCSCFactory implements org.openecard.common.ifd.scio.TerminalFactor
File libFile = LinuxLibraryFinder.getLibraryPath("pcsclite", "1");
System.setProperty("sun.security.smartcardio.library", libFile.getAbsolutePath());
}
loadPCSC();
try {
LOG.info("Trying to initialize 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.");
throw ex;
}
}
@Override
public String getType() {
return terminalFactory.getType();
if (terminalFactory != null) {
return terminalFactory.getType();
} else {
return "PC/SC";
}
}
@Override
......@@ -80,80 +88,4 @@ public class PCSCFactory implements org.openecard.common.ifd.scio.TerminalFactor
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 {
// 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);
// Then clear the terminals in cache
loadPCSC();
CardTerminals terminals = terminalFactory.terminals();
Field fieldTerminals = pcscterminal.getDeclaredField("terminals");
fieldTerminals.setAccessible(true);
Class classMap = Class.forName("java.util.Map");
Method clearMap = classMap.getDeclaredMethod("clear");
clearMap.invoke(fieldTerminals.get(terminals));
}
} 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 (PCSCExceptionExtractor.hasPCSCException(ex)) {
SCIOErrorCode code = PCSCExceptionExtractor.getCode(ex);
if (code == SCIOErrorCode.SCARD_E_NO_SERVICE) {
// 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.");
}
}
}
/****************************************************************************
* Copyright (C) 2014-2015 TU Darmstadt.
* Copyright (C) 2014-2019 TU Darmstadt.
* All rights reserved.
* Contact: ecsec GmbH (info@ecsec.de)
*
......@@ -33,6 +33,7 @@ import javax.annotation.Nonnull;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.CardTerminals;
import jnasmartcardio.Smartcardio;
import org.openecard.common.ifd.scio.NoSuchTerminal;
import org.openecard.common.ifd.scio.SCIOErrorCode;
import org.openecard.common.ifd.scio.SCIOException;
......@@ -62,16 +63,36 @@ public class PCSCTerminals implements SCIOTerminals {
PCSCTerminals(@Nonnull PCSCFactory terminalFactory) {
this.terminalFactory = terminalFactory;
loadTerminals();
}
private void reloadFactory() {
terminalFactory.reloadPCSC();
loadTerminals();
terminals = new CardTerminals() {
@Override
public List<CardTerminal> list(CardTerminals.State arg0) throws CardException {
if (loadTerminals()) {
return terminals.list(arg0);
} else {
throw new Smartcardio.JnaPCSCException(SCIOErrorCode.getLong(SCIOErrorCode.SCARD_E_NO_SERVICE), "Error loading PCSC subsystem.");
}
}
@Override
public boolean waitForChange(long arg0) throws CardException {
if (loadTerminals()) {
return terminals.waitForChange(arg0);
} else {
throw new Smartcardio.JnaPCSCException(SCIOErrorCode.getLong(SCIOErrorCode.SCARD_E_NO_SERVICE), "Error loading PCSC subsystem.");
}
}
};
}
private void loadTerminals() {
terminals = terminalFactory.getRawFactory().terminals();
private boolean loadTerminals() {
try {
terminals = terminalFactory.getRawFactory().terminals();
return true;
} catch (Smartcardio.EstablishContextException ex) {
LOG.debug("Failed to load PCSC terminals.", ex);
return false;
}
}
@Override
......@@ -101,7 +122,7 @@ public class PCSCTerminals implements SCIOTerminals {
} else if (code == SCIOErrorCode.SCARD_E_NO_SERVICE || code == SCIOErrorCode.SCARD_E_SERVICE_STOPPED) {
if (firstTry) {
LOG.debug("No service available exception, reloading PCSC and trying again.");
reloadFactory();
loadTerminals();
return list(state, false);
} else {
LOG.debug("No service available exception, returning empty list.");
......@@ -222,11 +243,9 @@ public class PCSCTerminals implements SCIOTerminals {
return Collections.emptyList();
} else if (code == SCIOErrorCode.SCARD_E_NO_SERVICE || code == SCIOErrorCode.SCARD_E_SERVICE_STOPPED || code == SCIOErrorCode.SCARD_E_INVALID_HANDLE) {
LOG.debug("No service available exception, reloading PCSC and returning empty list.");
parent.reloadFactory();
parent.loadTerminals();
own.loadTerminals();
return Collections.emptyList();
} else if (code == SCIOErrorCode.SCARD_E_INVALID_HANDLE) {
// don't log in order to prevent flooding
} else {
LOG.error(msg, ex);
}
......@@ -405,7 +424,7 @@ public class PCSCTerminals implements SCIOTerminals {
case SCARD_E_NO_SERVICE:
case SCARD_E_SERVICE_STOPPED:
LOG.debug("No service available exception, reloading PCSC.");
parent.reloadFactory();
parent.loadTerminals();
own.loadTerminals();
case SCARD_E_NO_READERS_AVAILABLE:
// send events that everything is removed if there are any terminals connected right now
......
......@@ -61,4 +61,6 @@ module org.openecard.richclient {
opens org.openecard.mdlw.sal.config to java.xml.bind;
opens org.openecard.addon.manifest to java.xml.bind;
opens jnasmartcardio to java.base;
}
......@@ -297,7 +297,7 @@
<compress>2</compress>
<noHeaderFiles>true</noHeaderFiles>
<noManPages>true</noManPages>
<stripDebug>true</stripDebug>
<stripDebug>false</stripDebug>
<ignoreSigningInformation>true</ignoreSigningInformation>
<outputDirectoryImage>${project.build.directory}/open-ecard</outputDirectoryImage>
<jdkToolchain>
......
......@@ -206,6 +206,7 @@
<iso:Date>2017-11-17</iso:Date>
<ATR>3B7D95000080318065B0831100C883009000</ATR>
<CardImage>portuguese-eid.png</CardImage>
<SkipContextSpecificLogin>true</SkipContextSpecificLogin>
</CardSpec>
</CardConfig>
......
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