summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletBKUWorker.java5
-rw-r--r--BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java79
-rw-r--r--BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/BKUApplet.java10
-rw-r--r--BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINManagementGUI.java26
-rw-r--r--BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINManagementGUIFacade.java9
-rw-r--r--BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINStatusRenderer.java2
-rw-r--r--BKUAppletExt/src/main/java/at/gv/egiz/bku/smccstal/ext/ManagementPINProviderFactory.java13
-rw-r--r--BKUAppletExt/src/main/java/at/gv/egiz/bku/smccstal/ext/PinpadPINProviderFactory.java45
-rw-r--r--BKUAppletExt/src/main/resources/at/gv/egiz/bku/gui/ActivationMessages.properties6
-rw-r--r--BKUAppletExt/src/main/resources/at/gv/egiz/bku/gui/ActivationMessages_en.properties6
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java40
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java603
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HashDataViewer.java293
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SecureViewerDialog.java371
-rw-r--r--BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties3
-rw-r--r--BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_en.properties1
-rw-r--r--BKUCommonGUI/src/main/resources/images/ChipperlingLogo.pngbin0 -> 4035 bytes
-rw-r--r--BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUITest.java5
-rw-r--r--BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java4
-rw-r--r--BKULocal/src/main/java/at/gv/egiz/bku/local/stal/BKUGuiProxy.java8
-rw-r--r--BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalBKUWorker.java3
-rw-r--r--BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalSecureViewer.java109
-rw-r--r--BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalSignRequestHandler.java83
-rw-r--r--BKUOnline/src/main/resources/at/gv/egiz/bku/online/conf/defaultConf.properties3
-rw-r--r--BKUOnline/src/main/resources/log4j.properties2
-rw-r--r--BKUOnline/src/main/webapp/SLRequestForm.html27
-rw-r--r--bkucommon/src/test/java/at/gv/egiz/bku/binding/ExpiryRemoverTest.java101
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java130
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java220
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java234
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/SWCard.java49
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java15
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ccid/CCID.java77
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java264
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ccid/GemplusGemPCPinpad.java65
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ccid/ReaderFactory.java35
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/ACOSCardTest.java135
-rw-r--r--smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java267
-rw-r--r--smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/AbstractPINProvider.java2
-rw-r--r--smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/PINProviderFactory.java3
-rw-r--r--smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/PinpadPINProviderFactory.java131
-rw-r--r--smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SecureViewer.java11
-rw-r--r--smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SignRequestHandler.java14
-rw-r--r--smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SoftwarePINProviderFactory.java25
-rw-r--r--smccSTAL/src/test/java/at/gv/egiz/smcc/AbstractSMCCSTALTest.java7
45 files changed, 2364 insertions, 1177 deletions
diff --git a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletBKUWorker.java b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletBKUWorker.java
index 9b9735f6..e8d8976d 100644
--- a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletBKUWorker.java
+++ b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletBKUWorker.java
@@ -18,6 +18,7 @@ package at.gv.egiz.bku.online.applet;
import at.gv.egiz.bku.smccstal.AbstractBKUWorker;
import at.gv.egiz.bku.gui.BKUGUIFacade;
+import at.gv.egiz.bku.smccstal.SignRequestHandler;
import at.gv.egiz.stal.STALRequest;
import at.gv.egiz.stal.STALResponse;
import at.gv.egiz.stal.SignRequest;
@@ -67,8 +68,10 @@ public class AppletBKUWorker extends AbstractBKUWorker implements Runnable {
STALPortType stalPort = applet.getSTALPort();
STALTranslator stalTranslator = applet.getSTALTranslator();
+ AppletSecureViewer secureViewer =
+ new AppletSecureViewer(gui, stalPort, sessionId);
addRequestHandler(SignRequest.class,
- new AppletSecureViewer(stalPort, sessionId));
+ new SignRequestHandler(secureViewer));
GetNextRequestResponseType nextRequestResp = stalPort.connect(sessionId);
diff --git a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java
index e2551e2d..929cecb1 100644
--- a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java
+++ b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java
@@ -16,17 +16,8 @@
*/
package at.gv.egiz.bku.online.applet;
+import at.gv.egiz.bku.gui.BKUGUIFacade;
import at.gv.egiz.bku.smccstal.SecureViewer;
-import java.security.DigestException;
-import java.security.MessageDigest;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import at.gv.egiz.bku.smccstal.SignRequestHandler;
import at.gv.egiz.stal.HashDataInput;
import at.gv.egiz.stal.impl.ByteArrayHashDataInput;
import at.gv.egiz.stal.service.GetHashDataInputFault;
@@ -34,49 +25,73 @@ import at.gv.egiz.stal.service.STALPortType;
import at.gv.egiz.stal.service.types.GetHashDataInputResponseType;
import at.gv.egiz.stal.service.types.GetHashDataInputType;
import at.gv.egiz.stal.signedinfo.ReferenceType;
+import at.gv.egiz.stal.signedinfo.SignedInfoType;
+import java.awt.event.ActionListener;
+import java.security.DigestException;
+import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
/**
- * A SignRequesthandler that obtains hashdata inputs from a STAL webservice and
- * displays these either within the applet or in a separate frame.
- * The internal viewer displays plaintext data only, other mimetypes can be saved to disk.
- * The standalone (frame) viewer displays all mimetypes.
- *
- * (This class depends on STALService and therefore is not part of BKUCommonGUI.)
- *
+ *
* @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
*/
-public class AppletSecureViewer extends SignRequestHandler {
+public class AppletSecureViewer implements SecureViewer {
private static final Log log = LogFactory.getLog(AppletSecureViewer.class);
+
+ protected BKUGUIFacade gui;
protected STALPortType stalPort;
protected String sessId;
+ protected List<HashDataInput> verifiedDataToBeSigned;
- public AppletSecureViewer(STALPortType stalPort, String sessId) {
- if (stalPort == null || sessId == null) {
+ public AppletSecureViewer(BKUGUIFacade gui, STALPortType stalPort,
+ String sessId) {
+ if (gui == null) {
+ throw new NullPointerException("GUI must not be null");
+ }
+ if (stalPort == null) {
throw new NullPointerException("STAL port must not be null");
}
- this.sessId = sessId;
+ if (sessId == null) {
+ throw new NullPointerException("session id must not be null");
+ }
+ this.gui = gui;
this.stalPort = stalPort;
+ this.sessId = sessId;
}
/**
- * TODO don't throw exceptions
+ * retrieves the data to be signed for
* @param signedReferences
+ * @param okListener
+ * @param okCommand
+ * @param cancelListener
+ * @param cancelCommand
* @throws java.security.DigestException
* @throws java.lang.Exception
*/
@Override
- public void displayDataToBeSigned(List<ReferenceType> signedReferences)
+ public void displayDataToBeSigned(SignedInfoType signedInfo,
+ ActionListener okListener, String okCommand)
throws DigestException, Exception {
-
- List<GetHashDataInputResponseType.Reference> hdi = getHashDataInput(signedReferences);
- List<HashDataInput> verifiedHashDataInputs = verifyHashDataInput(signedReferences, hdi);
-
- if (verifiedHashDataInputs.size() > 0) {
- gui.showSecureViewer(verifiedHashDataInputs, this, "hashDataDone");
+
+ if (verifiedDataToBeSigned == null) {
+ log.info("retrieve data to be signed for dsig:SignedInfo " +
+ signedInfo.getId());
+ List<GetHashDataInputResponseType.Reference> hdi =
+ getHashDataInput(signedInfo.getReference());
+ verifiedDataToBeSigned = verifyHashDataInput(signedInfo.getReference(),
+ hdi);
+ }
+ if (verifiedDataToBeSigned.size() > 0) {
+ gui.showSecureViewer(verifiedDataToBeSigned, okListener, okCommand);
} else {
- throw new Exception("No signature data (apart from any QualifyingProperties or a Manifest)");
+ throw new Exception("No data to be signed (apart from any QualifyingProperties or a Manifest)");
}
}
@@ -110,7 +125,7 @@ public class AppletSecureViewer extends SignRequestHandler {
}
}
}
-
+
if (request.getReference().size() < 1) {
log.error("No signature data (apart from any QualifyingProperties or a Manifest) for session " + sessId);
throw new Exception("No signature data (apart from any QualifyingProperties or a Manifest)");
@@ -187,7 +202,7 @@ public class AppletSecureViewer extends SignRequestHandler {
verifiedHashDataInputs.add(new ByteArrayHashDataInput(hdi, signedRefId, mimeType, encoding));
}
}
-
+
return verifiedHashDataInputs;
}
diff --git a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/BKUApplet.java b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/BKUApplet.java
index a4337bbd..0ddb6dc6 100644
--- a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/BKUApplet.java
+++ b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/BKUApplet.java
@@ -34,6 +34,7 @@ import at.gv.egiz.bku.gui.BKUGUIFacade;
import at.gv.egiz.bku.gui.BKUGUIImpl;
import at.gv.egiz.stal.service.STALPortType;
import at.gv.egiz.stal.service.STALService;
+import java.applet.AppletContext;
import java.awt.Container;
import javax.xml.namespace.QName;
@@ -207,14 +208,19 @@ public class BKUApplet extends JApplet {
*/
protected void sendRedirect(String sessionId) {
try {
+ AppletContext ctx = getAppletContext();
+ if (ctx == null) {
+ log.error("no applet context (applet might already have been destroyed)");
+ return;
+ }
URL redirectURL = getURLParameter(REDIRECT_URL, sessionId);
String redirectTarget = getParameter(REDIRECT_TARGET);
if (redirectTarget == null) {
log.info("Done. Redirecting to " + redirectURL + " ...");
- getAppletContext().showDocument(redirectURL);
+ ctx.showDocument(redirectURL);
} else {
log.info("Done. Redirecting to " + redirectURL + " (target=" + redirectTarget + ") ...");
- getAppletContext().showDocument(redirectURL, redirectTarget);
+ ctx.showDocument(redirectURL, redirectTarget);
}
} catch (MalformedURLException ex) {
log.warn("Failed to redirect: " + ex.getMessage(), ex);
diff --git a/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINManagementGUI.java b/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINManagementGUI.java
index 159dd29d..d1ca6c00 100644
--- a/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINManagementGUI.java
+++ b/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINManagementGUI.java
@@ -118,18 +118,18 @@ public class PINManagementGUI extends CardMgmtGUI implements PINManagementGUIFac
pinStatusTable.setDefaultRenderer(PINSpec.class, new PINSpecRenderer());
pinStatusTable.setDefaultRenderer(STATUS.class, new PINStatusRenderer(cardmgmtMessages));
pinStatusTable.setTableHeader(null);
-
- pinStatusTable.addMouseMotionListener(new MouseMotionAdapter() {
-
- @Override
- public void mouseMoved(MouseEvent e) {
- if (pinStatusTable.columnAtPoint(e.getPoint()) == 0) {
- pinStatusTable.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
- } else {
- pinStatusTable.setCursor(Cursor.getDefaultCursor());
- }
- }
- });
+ pinStatusTable.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+// pinStatusTable.addMouseMotionListener(new MouseMotionAdapter() {
+//
+// @Override
+// public void mouseMoved(MouseEvent e) {
+// if (pinStatusTable.columnAtPoint(e.getPoint()) == 0) {
+// pinStatusTable.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+// } else {
+// pinStatusTable.setCursor(Cursor.getDefaultCursor());
+// }
+// }
+// });
final JButton activateButton = new JButton();
activateButton.setFont(activateButton.getFont().deriveFont(activateButton.getFont().getStyle() & ~java.awt.Font.BOLD));
@@ -392,7 +392,7 @@ public class PINManagementGUI extends CardMgmtGUI implements PINManagementGUIFac
if (pinpad) {
JLabel pinpadLabel = new JLabel();
pinpadLabel.setFont(mgmtLabel.getFont().deriveFont(mgmtLabel.getFont().getStyle() & ~Font.BOLD));
- String pinpadPattern = getMessage(MESSAGE_PINPAD);
+ String pinpadPattern = getMessage(MESSAGE_VERIFYPIN_PINPAD);
pinpadLabel.setText(MessageFormat.format(pinpadPattern,
new Object[] { pinSpec.getLocalizedName(), pinSize }));
diff --git a/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINManagementGUIFacade.java b/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINManagementGUIFacade.java
index 45313f42..f0cc0a27 100644
--- a/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINManagementGUIFacade.java
+++ b/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINManagementGUIFacade.java
@@ -40,13 +40,16 @@ public interface PINManagementGUIFacade extends BKUGUIFacade {
public static final String MESSAGE_ACTIVATE_SUCCESS = "activate.success";
public static final String MESSAGE_CHANGE_SUCCESS = "change.success";
public static final String MESSAGE_PINMGMT = "pin.mgmt";
- public static final String MESSAGE_PINPAD = "pinpad";
- public static final String MESSAGE_CHANGEPIN_PINPAD = "pinpad.change";
+// public static final String MESSAGE_PINPAD = "pinpad";
public static final String MESSAGE_ACTIVATE_PIN = "activate.pin";
public static final String MESSAGE_CHANGE_PIN = "change.pin";
public static final String MESSAGE_VERIFY_PIN = "verify.pin";
public static final String MESSAGE_UNBLOCK_PIN = "unblock.pin";
-
+ public static final String MESSAGE_ACTIVATEPIN_PINPAD = "activate.pinpad";
+ public static final String MESSAGE_CHANGEPIN_PINPAD = "change.pinpad";
+ public static final String MESSAGE_VERIFYPIN_PINPAD = "verify.pinpad";
+ public static final String MESSAGE_UNBLOCKPIN_PINPAD = "unblock.pinpad";
+
public static final String LABEL_OLD_PIN = "label.old.pin";
public static final String LABEL_NEW_PIN = "label.new.pin";
public static final String LABEL_REPEAT_PIN = "label.repeat.pin";
diff --git a/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINStatusRenderer.java b/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINStatusRenderer.java
index 4cb84b77..83ff74f2 100644
--- a/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINStatusRenderer.java
+++ b/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINStatusRenderer.java
@@ -22,8 +22,6 @@ import java.awt.Color;
import java.awt.Font;
import java.util.ResourceBundle;
import javax.swing.table.DefaultTableCellRenderer;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
/**
*
diff --git a/BKUAppletExt/src/main/java/at/gv/egiz/bku/smccstal/ext/ManagementPINProviderFactory.java b/BKUAppletExt/src/main/java/at/gv/egiz/bku/smccstal/ext/ManagementPINProviderFactory.java
index b0dd8766..d635b8df 100644
--- a/BKUAppletExt/src/main/java/at/gv/egiz/bku/smccstal/ext/ManagementPINProviderFactory.java
+++ b/BKUAppletExt/src/main/java/at/gv/egiz/bku/smccstal/ext/ManagementPINProviderFactory.java
@@ -19,6 +19,7 @@ package at.gv.egiz.bku.smccstal.ext;
import at.gv.egiz.smcc.ChangePINProvider;
import at.gv.egiz.bku.gui.PINManagementGUIFacade;
+import at.gv.egiz.smcc.ccid.CCID;
import at.gv.egiz.smcc.PINProvider;
import at.gv.egiz.smcc.SignatureCard;
@@ -33,13 +34,13 @@ public abstract class ManagementPINProviderFactory {
public static ManagementPINProviderFactory getInstance(SignatureCard forCard,
PINManagementGUIFacade gui) {
-// if (forCard.ifdSupportsFeature(SignatureCard.FEATURE_VERIFY_PIN_DIRECT)) {
-//// forCard.ifdSupportsFeature(SignatureCard.FEATURE_MODIFY_PIN_DIRECT)
-// return new PinpadPINProviderFactory(gui);
-//
-// } else {
+ if (forCard.getReader().hasFeature(CCID.FEATURE_VERIFY_PIN_DIRECT)) {
+// forCard.ifdSupportsFeature(SignatureCard.FEATURE_MODIFY_PIN_DIRECT)
+ return new PinpadPINProviderFactory(gui);
+
+ } else {
return new SoftwarePINProviderFactory(gui);
-// }
+ }
}
public abstract PINProvider getVerifyPINProvider();
diff --git a/BKUAppletExt/src/main/java/at/gv/egiz/bku/smccstal/ext/PinpadPINProviderFactory.java b/BKUAppletExt/src/main/java/at/gv/egiz/bku/smccstal/ext/PinpadPINProviderFactory.java
index 4176e0a9..a9ad5ef8 100644
--- a/BKUAppletExt/src/main/java/at/gv/egiz/bku/smccstal/ext/PinpadPINProviderFactory.java
+++ b/BKUAppletExt/src/main/java/at/gv/egiz/bku/smccstal/ext/PinpadPINProviderFactory.java
@@ -73,23 +73,6 @@ public class PinpadPINProviderFactory extends ManagementPINProviderFactory {
showPinpadPINDialog(retries, spec);
retry = true;
return null;
-
-// gui.showPINDialog(type, spec, (retry) ? retries : -1,
-// this, "exec",
-// this, "back");
-//
-// waitForAction();
-//
-// if ("exec".equals(action)) {
-// gui.showWaitDialog(null);
-// retry = true;
-// return gui.getPin();
-// } else if ("back".equals(action)) {
-// throw new CancelledException();
-// } else {
-// log.error("unsupported command " + action);
-// throw new CancelledException();
-// }
}
/**
@@ -111,14 +94,38 @@ public class PinpadPINProviderFactory extends ManagementPINProviderFactory {
title = BKUGUIFacade.TITLE_RETRY;
message = BKUGUIFacade.MESSAGE_RETRIES;
params = new Object[]{String.valueOf(retries)};
- } else {
- title = BKUGUIFacade.TITLE_SIGN;
+ } else if (type == DIALOG.VERIFY) {
+ title = PINManagementGUIFacade.TITLE_VERIFY_PIN;
message = BKUGUIFacade.MESSAGE_ENTERPIN_PINPAD;
String pinSize = String.valueOf(pinSpec.getMinLength());
if (pinSpec.getMinLength() != pinSpec.getMaxLength()) {
pinSize += "-" + pinSpec.getMaxLength();
}
params = new Object[]{pinSpec.getLocalizedName(), pinSize};
+ } else if (type == DIALOG.ACTIVATE) {
+ title = PINManagementGUIFacade.TITLE_ACTIVATE_PIN;
+ message = PINManagementGUIFacade.MESSAGE_ACTIVATEPIN_PINPAD;
+ String pinSize = String.valueOf(pinSpec.getMinLength());
+ if (pinSpec.getMinLength() != pinSpec.getMaxLength()) {
+ pinSize += "-" + pinSpec.getMaxLength();
+ }
+ params = new Object[]{pinSpec.getLocalizedName(), pinSize};
+ } else if (type == DIALOG.CHANGE) {
+ title = PINManagementGUIFacade.TITLE_CHANGE_PIN;
+ message = PINManagementGUIFacade.MESSAGE_CHANGEPIN_PINPAD;
+ String pinSize = String.valueOf(pinSpec.getMinLength());
+ if (pinSpec.getMinLength() != pinSpec.getMaxLength()) {
+ pinSize += "-" + pinSpec.getMaxLength();
+ }
+ params = new Object[]{pinSpec.getLocalizedName(), pinSize};
+ } else { //if (type == DIALOG.UNBLOCK) {
+ title = PINManagementGUIFacade.TITLE_UNBLOCK_PIN;
+ message = PINManagementGUIFacade.MESSAGE_UNBLOCKPIN_PINPAD;
+ String pinSize = String.valueOf(pinSpec.getMinLength());
+ if (pinSpec.getMinLength() != pinSpec.getMaxLength()) {
+ pinSize += "-" + pinSpec.getMaxLength();
+ }
+ params = new Object[]{pinSpec.getLocalizedName(), pinSize};
}
gui.showMessageDialog(title, message, params);
}
diff --git a/BKUAppletExt/src/main/resources/at/gv/egiz/bku/gui/ActivationMessages.properties b/BKUAppletExt/src/main/resources/at/gv/egiz/bku/gui/ActivationMessages.properties
index 4ceacb21..c6d219d4 100644
--- a/BKUAppletExt/src/main/resources/at/gv/egiz/bku/gui/ActivationMessages.properties
+++ b/BKUAppletExt/src/main/resources/at/gv/egiz/bku/gui/ActivationMessages.properties
@@ -24,12 +24,14 @@ title.change.success=<html>Erfolg</html>
# removed message.* prefix to reuse keys as help keys
pin.mgmt=<html>Die Karte verf\u00FCgt \u00FCber {0} PINs</html>
-pinpad=<html>{0} ({1} stellig) am Kartenleser eingeben und best\u00E4tigen.</html>
-pinpad.change=<html>{0} ({1} stellig) am Kartenleser eingeben und best\u00E4tigen.</html>
activate.pin=<html>{0} eingeben und best\u00E4tigen</html>
change.pin=<html>{0} eingeben und best\u00E4tigen</html>
unblock.pin=<html>PUK zu {0} eingeben</html>
verify.pin=<html>{0} eingeben (TODO: Warning not activated)</html>
+verify.pinpad=<html>{0} ({1} stellig) am Kartenleser eingeben (und best\u00E4tigen).</html>
+activate.pinpad=<html>{0} ({1} stellig) am Kartenleser eingeben und wiederholen (jeweils best\u00E4tigen).</html>
+change.pinpad=<html>Alte {0} ({1} stellig) am Kartenleser eingeben, danach neue {0} eingeben und wiederholen (jeweils best\u00E4tigen). </html>
+unblock.pinpad=<html>{0} ({1} stellig) am Kartenleser eingeben (und best\u00E4tigen).</html>
activate.success=<html>{0} wurde erfolgreich aktiviert.</html>
change.success=<html>{0} wurde erfolgreich ge\u00E4ndert.</html>
diff --git a/BKUAppletExt/src/main/resources/at/gv/egiz/bku/gui/ActivationMessages_en.properties b/BKUAppletExt/src/main/resources/at/gv/egiz/bku/gui/ActivationMessages_en.properties
index 9178d65c..b4bededf 100644
--- a/BKUAppletExt/src/main/resources/at/gv/egiz/bku/gui/ActivationMessages_en.properties
+++ b/BKUAppletExt/src/main/resources/at/gv/egiz/bku/gui/ActivationMessages_en.properties
@@ -23,11 +23,13 @@ title.change.success=<html>Success</html>
# removed message.* prefix to reuse keys as help keys
pin.mgmt=<html>The smartcard has {0} PINs</html>
-pinpad=<html>Enter {0} ({1} digits) on pinpad and confirm.</html>
-pinpad.change=<html>Enter {0} ({1} digits) on pinpad and confirm.</html>
activate.pin=<html>Enter and confirm {0}</html>
change.pin=<html>Enter and confirm {0}</html>
unblock.pin=<html>Enter PUK for {0}</html>
+verify.pinpad=<html>Enter {0} ({1} digits) on cardreader (and confirm).</html>
+activate.pinpad=<html>Enter {0} ({1} digits) on cardreader and repeat (confirm in each case).</html>
+change.pinpad=<html>Enter old {0} ({1} digits) on cardreader, then enter new {0} and repeat (confirm in each case).</html>
+unblock.pinpad=<html>Enter {0} ({1} digits) on cardreader (and confirm).</html>
activate.success=<html>{0} successfully activated</html>
change.success=<html>{0} successfully changed</html>
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java
index 1043b6a1..4b079428 100644
--- a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java
@@ -43,6 +43,7 @@ public interface BKUGUIFacade {
public static final String MESSAGES_BUNDLE = "at/gv/egiz/bku/gui/Messages";
public static final String DEFAULT_BACKGROUND = "/images/BackgroundChipperling.png";
+ public static final String DEFAULT_ICON = "/images/ChipperlingLogo.png";
public static final String HELP_IMG = "/images/help.png";
public static final String HASHDATA_FONT = "Monospaced";
public static final Color ERROR_COLOR = Color.RED;
@@ -58,6 +59,7 @@ public interface BKUGUIFacade {
public static final String TITLE_WAIT = "title.wait";
public static final String TITLE_HASHDATA = "title.hashdata";
public static final String WINDOWTITLE_SAVE = "windowtitle.save";
+ public static final String WINDOWTITLE_ERROR = "windowtitle.error";
public static final String WINDOWTITLE_SAVEDIR = "windowtitle.savedir";
public static final String WINDOWTITLE_OVERWRITE = "windowtitle.overwrite";
public static final String WINDOWTITLE_VIEWER = "windowtitle.viewer";
@@ -102,42 +104,36 @@ public interface BKUGUIFacade {
public enum Style { tiny, simple, advanced };
-// public void init(Container contentPane, Locale locale, Style guiStyle, URL background, ActionListener helpListener);
-
/**
* BKUWorker needs to init signature card with locale
* @return
*/
public Locale getLocale();
-// public void showWelcomeDialog();
-
- /**
- *
- * @param waitMessage if null, a simple 'please wait' text is displayed
- */
-// public void showWaitDialog(String waitMessage);
-
-// public void showInsertCardDialog(ActionListener cancelListener, String actionCommand);
-
-// public void showCardNotSupportedDialog(ActionListener cancelListener, String actionCommand);
-
public void showCardPINDialog(PINSpec pinSpec, int numRetries,
ActionListener okListener, String okCommand,
ActionListener cancelListener, String cancelCommand);
-// public void showCardPINRetryDialog(PINSpec pinSpec, int numRetries, ActionListener okListener, String okCommand, ActionListener cancelListener, String cancelCommand);
-
- public void showSignaturePINDialog(PINSpec pinSpec, int numRetries, ActionListener signListener, String signCommand, ActionListener cancelListener, String cancelCommand, ActionListener hashdataListener, String hashdataCommand);
-
-// public void showSignaturePINRetryDialog(PINSpec pinSpec, int numRetries, ActionListener okListener, String okCommand, ActionListener cancelListener, String cancelCommand, ActionListener hashdataListener, String hashdataCommand);
+ public void showSignaturePINDialog(PINSpec pinSpec, int numRetries,
+ ActionListener signListener, String signCommand,
+ ActionListener cancelListener, String cancelCommand,
+ ActionListener viewerListener, String viewerCommand);
-// public void showPinpadSignaturePINDialog(PINSpec pinSpec, int retries);
+ public void showPinpadSignaturePINDialog(PINSpec pinSpec, int numRetries,
+ ActionListener viewerListener, String viewerCommand);
public char[] getPin();
- public void showSecureViewer(List<HashDataInput> signedReferences,
- ActionListener okListener, String okCommand);
+ /**
+ *
+ * @param dataToBeSigned
+ * @param backListener if list of references hides pin dialog, backListener
+ * receives an action when user hits 'back' button (i.e. whenever the pin-dialog
+ * needs to be re-paint)
+ * @param backCommand
+ */
+ public void showSecureViewer(List<HashDataInput> dataToBeSigned,
+ ActionListener backListener, String backCommand);
public void showErrorDialog(String errorMsgKey, Object[] errorMsgParams,
ActionListener okListener, String okCommand);
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java
index 928be249..a7eebbfd 100644
--- a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java
@@ -71,6 +71,7 @@ public class BKUGUIImpl implements BKUGUIFacade {
}
protected HelpMouseListener helpListener;
+ protected SecureViewerDialog secureViewer;
protected Container contentPane;
protected ResourceBundle messages;
@@ -145,13 +146,16 @@ public class BKUGUIImpl implements BKUGUIFacade {
@Override
public void run() {
- log.debug("initializing gui");
+ log.debug("initializing gui [" + Thread.currentThread().getName() + "]");
if (renderIconPanel) {
initIconPanel(background);
initContentPanel(null);
} else {
- initContentPanel(background);
+ initContentPanel((background == null) ?
+ getClass().getResource(DEFAULT_BACKGROUND) :
+ background
+ );
}
GroupLayout layout = new GroupLayout(contentPane);
@@ -159,15 +163,27 @@ public class BKUGUIImpl implements BKUGUIFacade {
if (renderIconPanel) {
layout.setHorizontalGroup(layout.createSequentialGroup()
- .addComponent(iconPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
- .addComponent(contentPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE));
- layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
- .addComponent(iconPanel, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addComponent(contentPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE));
+ .addContainerGap()
+ .addComponent(iconPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(contentPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addContainerGap());
+ layout.setVerticalGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(iconPanel, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(contentPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addContainerGap());
} else {
- layout.setHorizontalGroup(layout.createSequentialGroup().addComponent(contentPanel));
- layout.setVerticalGroup(layout.createSequentialGroup().addComponent(contentPanel));
+ layout.setHorizontalGroup(layout.createSequentialGroup()
+ // left border
+ .addContainerGap()
+ .addComponent(contentPanel)
+ .addContainerGap());
+ layout.setVerticalGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(contentPanel)
+ .addContainerGap());
}
}
});
@@ -178,11 +194,12 @@ public class BKUGUIImpl implements BKUGUIFacade {
protected void initIconPanel(URL background) {
if (background == null) {
- background = getClass().getResource(DEFAULT_BACKGROUND);
+ background = getClass().getResource(DEFAULT_ICON);
}
if ("file".equals(background.getProtocol())) {
- log.warn("file:// background images not permitted: " + background);
- background = getClass().getResource(DEFAULT_BACKGROUND);
+ log.warn("file:// background images not permitted: " + background +
+ ", loading default background");
+ background = getClass().getResource(DEFAULT_ICON);
}
log.debug("loading icon panel background " + background);
@@ -194,26 +211,24 @@ public class BKUGUIImpl implements BKUGUIFacade {
iconPanel.setLayout(iconPanelLayout);
iconPanelLayout.setHorizontalGroup(
iconPanelLayout.createSequentialGroup()
- .addContainerGap()
.addComponent(iconLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE));
- // no gap here (contentPanel has containerGap)
iconPanelLayout.setVerticalGroup(
iconPanelLayout.createSequentialGroup()
- .addContainerGap()
- .addComponent(iconLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
- .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE));
+ .addComponent(iconLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE));
}
protected void initContentPanel(URL background) {
+// if (background == null) {
+// background = getClass().getResource(DEFAULT_BACKGROUND);
+// }
if (background == null) {
- background = getClass().getResource(DEFAULT_BACKGROUND);
- }
- if (background == null) {
+ log.debug("no background image set");
contentPanel = new JPanel();
} else {
if ("file".equals(background.getProtocol())) {
- log.warn("file:// background images not permitted: " + background);
+ log.warn("file:// background images not permitted: " + background +
+ ", loading default background");
background = getClass().getResource(DEFAULT_BACKGROUND);
}
log.debug("loading background " + background);
@@ -257,34 +272,29 @@ public class BKUGUIImpl implements BKUGUIFacade {
GroupLayout contentPanelLayout = new GroupLayout(contentPanel);
contentPanel.setLayout(contentPanelLayout);
- GroupLayout.ParallelGroup horizontalContentInner = contentPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING);
+ // align header, main and button to the right
+ GroupLayout.ParallelGroup horizontalContent =
+ contentPanelLayout.createParallelGroup(GroupLayout.Alignment.TRAILING); //LEADING);
+ GroupLayout.SequentialGroup verticalContent =
+ contentPanelLayout.createSequentialGroup();
+
if (renderHeaderPanel) {
- horizontalContentInner
+ horizontalContent
.addComponent(headerPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE);
+ verticalContent
+ .addComponent(headerPanel, 0, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED);
+
}
- horizontalContentInner
+ horizontalContent
.addComponent(mainPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addComponent(buttonPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE);
- GroupLayout.SequentialGroup horizontalContentOuter = contentPanelLayout.createSequentialGroup();
- if (!renderIconPanel) {
- horizontalContentOuter
- .addContainerGap();
- }
- horizontalContentOuter
- .addGroup(horizontalContentInner)
- .addContainerGap();
- contentPanelLayout.setHorizontalGroup(horizontalContentOuter);
-
- GroupLayout.SequentialGroup verticalContent = contentPanelLayout.createSequentialGroup();
- verticalContent.addContainerGap();
- if (renderHeaderPanel) {
- verticalContent.addComponent(headerPanel, 0, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED);
- }
- verticalContent.addComponent(mainPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
- .addComponent(buttonPanel, 0, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
- .addContainerGap();
+ .addComponent(buttonPanel, 0, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE); //Short.MAX_VALUE);
+ verticalContent
+ .addComponent(mainPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(buttonPanel, 0, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
+
+ contentPanelLayout.setHorizontalGroup(horizontalContent); //Outer);
contentPanelLayout.setVerticalGroup(verticalContent);
}
@@ -521,7 +531,7 @@ public class BKUGUIImpl implements BKUGUIFacade {
@Override
public void run() {
- log.debug("show card-pin dialog");
+ log.debug("show card-pin dialog [" + Thread.currentThread().getName() + "]");
mainPanel.removeAll();
buttonPanel.removeAll();
@@ -653,7 +663,6 @@ public class BKUGUIImpl implements BKUGUIFacade {
buttonPanel.setLayout(buttonPanelLayout);
GroupLayout.SequentialGroup buttonHorizontal = buttonPanelLayout.createSequentialGroup()
- .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(okButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE);
GroupLayout.Group buttonVertical;
@@ -701,6 +710,128 @@ public class BKUGUIImpl implements BKUGUIFacade {
// }
@Override
+ public void showPinpadSignaturePINDialog(final PINSpec pinSpec, final int numRetries,
+// final ActionListener cancelListener, final String cancelCommand,
+ final ActionListener hashdataListener, final String hashdataCommand) {
+
+ log.debug("scheduling pinpad signature-pin dialog");
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+
+ log.debug("show pinpad signature-pin dialog [" + Thread.currentThread().getName() + "]");
+
+ mainPanel.removeAll();
+ buttonPanel.removeAll();
+
+ if (renderHeaderPanel) {
+ if (numRetries < 0) {
+ titleLabel.setText(getMessage(TITLE_SIGN));
+ } else {
+ titleLabel.setText(getMessage(TITLE_RETRY));
+ }
+ }
+
+ JLabel infoLabel = new JLabel();
+ if (numRetries < 0) {
+ infoLabel.setFont(infoLabel.getFont().deriveFont(infoLabel.getFont().getStyle() & ~java.awt.Font.BOLD));
+ if (shortText) {
+ infoLabel.setText(getMessage(MESSAGE_HASHDATALINK_TINY));
+ } else {
+ infoLabel.setText(getMessage(MESSAGE_HASHDATALINK));
+ }
+ infoLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+ infoLabel.setForeground(HYPERLINK_COLOR);
+ infoLabel.addMouseListener(new MouseAdapter() {
+
+ @Override
+ public void mouseClicked(MouseEvent me) {
+ ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, hashdataCommand);
+ hashdataListener.actionPerformed(e);
+ }
+ });
+ helpListener.setHelpTopic(HELP_SIGNPIN);
+ } else {
+ String retryPattern;
+ if (numRetries < 2) {
+ retryPattern = getMessage(MESSAGE_LAST_RETRY);
+ } else {
+ retryPattern = getMessage(MESSAGE_RETRIES);
+ }
+ infoLabel.setText(MessageFormat.format(retryPattern, new Object[]{String.valueOf(numRetries)}));
+ infoLabel.setFont(infoLabel.getFont().deriveFont(infoLabel.getFont().getStyle() | java.awt.Font.BOLD));
+ infoLabel.setForeground(ERROR_COLOR);
+ helpListener.setHelpTopic(HELP_RETRY);
+ }
+
+ String pinSize = String.valueOf(pinSpec.getMinLength());
+ if (pinSpec.getMinLength() != pinSpec.getMaxLength()) {
+ pinSize += "-" + pinSpec.getMaxLength();
+ }
+
+ String msgPattern = getMessage(MESSAGE_ENTERPIN_PINPAD);
+ String msg = MessageFormat.format(msgPattern, new Object[] {
+ pinSpec.getLocalizedName(), pinSize });
+
+ JLabel msgLabel = new JLabel();
+ msgLabel.setFont(msgLabel.getFont().deriveFont(msgLabel.getFont().getStyle() & ~Font.BOLD));
+ msgLabel.setText(msg);
+
+ GroupLayout mainPanelLayout = new GroupLayout(mainPanel);
+ mainPanel.setLayout(mainPanelLayout);
+
+ GroupLayout.SequentialGroup infoHorizontal = mainPanelLayout.createSequentialGroup()
+ .addComponent(infoLabel);
+ GroupLayout.ParallelGroup infoVertical = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(infoLabel);
+
+ if (!renderHeaderPanel) {
+ infoHorizontal
+ .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 0, Short.MAX_VALUE)
+ .addComponent(helpLabel);
+ infoVertical
+ .addComponent(helpLabel);
+ }
+
+ mainPanelLayout.setHorizontalGroup(
+ mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(infoHorizontal)
+ .addComponent(msgLabel));
+
+ mainPanelLayout.setVerticalGroup(
+ mainPanelLayout.createSequentialGroup()
+ .addGroup(infoVertical)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(msgLabel));
+
+ //no cancel button (cancel via pinpad)
+// if (renderCancelButton) {
+// JButton cancelButton = new JButton();
+// cancelButton.setFont(cancelButton.getFont().deriveFont(cancelButton.getFont().getStyle() & ~java.awt.Font.BOLD));
+// cancelButton.setText(getMessage(BUTTON_CANCEL));
+// cancelButton.setActionCommand(cancelCommand);
+// cancelButton.addActionListener(cancelListener);
+//
+// GroupLayout buttonPanelLayout = new GroupLayout(buttonPanel);
+// buttonPanel.setLayout(buttonPanelLayout);
+//
+// GroupLayout.SequentialGroup buttonHorizontal = buttonPanelLayout.createSequentialGroup()
+// .addComponent(cancelButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE);
+// GroupLayout.SequentialGroup buttonVertical = buttonPanelLayout.createSequentialGroup()
+// .addComponent(cancelButton);
+//
+// buttonPanelLayout.setHorizontalGroup(buttonHorizontal);
+// buttonPanelLayout.setVerticalGroup(buttonVertical);
+// }
+
+ contentPanel.validate();
+ }
+ });
+ }
+
+ @Override
public void showSignaturePINDialog(final PINSpec pinSpec, final int numRetries,
final ActionListener signListener, final String signCommand,
final ActionListener cancelListener, final String cancelCommand,
@@ -717,7 +848,7 @@ public class BKUGUIImpl implements BKUGUIFacade {
@Override
public void run() {
- log.debug("show signature-pin dialog");
+ log.debug("show signature-pin dialog [" + Thread.currentThread().getName() + "]");
mainPanel.removeAll();
buttonPanel.removeAll();
@@ -730,6 +861,38 @@ public class BKUGUIImpl implements BKUGUIFacade {
}
}
+ JLabel infoLabel = new JLabel();
+ if (numRetries < 0) {
+ infoLabel.setFont(infoLabel.getFont().deriveFont(infoLabel.getFont().getStyle() & ~java.awt.Font.BOLD));
+ if (shortText) {
+ infoLabel.setText(getMessage(MESSAGE_HASHDATALINK_TINY));
+ } else {
+ infoLabel.setText(getMessage(MESSAGE_HASHDATALINK));
+ }
+ infoLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+ infoLabel.setForeground(HYPERLINK_COLOR);
+ infoLabel.addMouseListener(new MouseAdapter() {
+
+ @Override
+ public void mouseClicked(MouseEvent me) {
+ ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, hashdataCommand);
+ hashdataListener.actionPerformed(e);
+ }
+ });
+ helpListener.setHelpTopic(HELP_SIGNPIN);
+ } else {
+ String retryPattern;
+ if (numRetries < 2) {
+ retryPattern = getMessage(MESSAGE_LAST_RETRY);
+ } else {
+ retryPattern = getMessage(MESSAGE_RETRIES);
+ }
+ infoLabel.setText(MessageFormat.format(retryPattern, new Object[]{String.valueOf(numRetries)}));
+ infoLabel.setFont(infoLabel.getFont().deriveFont(infoLabel.getFont().getStyle() | java.awt.Font.BOLD));
+ infoLabel.setForeground(ERROR_COLOR);
+ helpListener.setHelpTopic(HELP_RETRY);
+ }
+
JButton signButton = new JButton();
signButton.setFont(signButton.getFont().deriveFont(signButton.getFont().getStyle() & ~java.awt.Font.BOLD));
signButton.setText(getMessage(BUTTON_SIGN));
@@ -765,46 +928,14 @@ public class BKUGUIImpl implements BKUGUIFacade {
}
pinsizeLabel.setText(MessageFormat.format(pinsizePattern, new Object[]{pinSize}));
- JLabel infoLabel = new JLabel();
- if (numRetries < 0) {
- infoLabel.setFont(infoLabel.getFont().deriveFont(infoLabel.getFont().getStyle() & ~java.awt.Font.BOLD));
- if (shortText) {
- infoLabel.setText(getMessage(MESSAGE_HASHDATALINK_TINY));
- } else {
- infoLabel.setText(getMessage(MESSAGE_HASHDATALINK));
- }
- infoLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
- infoLabel.setForeground(HYPERLINK_COLOR);
- infoLabel.addMouseListener(new MouseAdapter() {
-
- @Override
- public void mouseClicked(MouseEvent me) {
- ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, hashdataCommand);
- hashdataListener.actionPerformed(e);
- }
- });
- helpListener.setHelpTopic(HELP_SIGNPIN);
- } else {
- String retryPattern;
- if (numRetries < 2) {
- retryPattern = getMessage(MESSAGE_LAST_RETRY);
- } else {
- retryPattern = getMessage(MESSAGE_RETRIES);
- }
- infoLabel.setText(MessageFormat.format(retryPattern, new Object[]{String.valueOf(numRetries)}));
- infoLabel.setFont(infoLabel.getFont().deriveFont(infoLabel.getFont().getStyle() | java.awt.Font.BOLD));
- infoLabel.setForeground(ERROR_COLOR);
- helpListener.setHelpTopic(HELP_RETRY);
- }
-
GroupLayout mainPanelLayout = new GroupLayout(mainPanel);
mainPanel.setLayout(mainPanelLayout);
-
+
GroupLayout.SequentialGroup infoHorizontal = mainPanelLayout.createSequentialGroup()
.addComponent(infoLabel);
GroupLayout.ParallelGroup infoVertical = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(infoLabel);
-
+
if (!renderHeaderPanel) {
infoHorizontal
.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 0, Short.MAX_VALUE)
@@ -814,8 +945,8 @@ public class BKUGUIImpl implements BKUGUIFacade {
}
// align pinfield and pinsize to the right
- GroupLayout.ParallelGroup pinHorizontal = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.TRAILING);
- GroupLayout.Group pinVertical;
+ GroupLayout.Group pinHorizontal = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.TRAILING);
+ GroupLayout.SequentialGroup pinVertical = mainPanelLayout.createSequentialGroup();
if (pinLabelPos == PinLabelPosition.ABOVE) {
pinHorizontal
@@ -823,20 +954,25 @@ public class BKUGUIImpl implements BKUGUIFacade {
.addComponent(signPinLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(pinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(pinsizeLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
- pinVertical = mainPanelLayout.createSequentialGroup()
+ pinVertical
.addComponent(signPinLabel)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(pinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
- } else {
+ .addComponent(pinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(pinsizeLabel);
+ } else { // PinLabelPosition.LEFT
pinHorizontal
.addGroup(mainPanelLayout.createSequentialGroup()
.addComponent(signPinLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(pinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(pinsizeLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
- pinVertical = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE)
- .addComponent(signPinLabel)
- .addComponent(pinField);
+ pinVertical
+ .addGroup(mainPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(signPinLabel)
+ .addComponent(pinField))
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(pinsizeLabel);
}
mainPanelLayout.setHorizontalGroup(
@@ -848,18 +984,14 @@ public class BKUGUIImpl implements BKUGUIFacade {
mainPanelLayout.createSequentialGroup()
.addGroup(infoVertical)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
- .addGroup(pinVertical)
- .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(pinsizeLabel));
+ .addGroup(pinVertical));
GroupLayout buttonPanelLayout = new GroupLayout(buttonPanel);
buttonPanel.setLayout(buttonPanelLayout);
- GroupLayout.SequentialGroup buttonHorizontal = buttonPanelLayout.createSequentialGroup()
- .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addComponent(signButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE);
+ GroupLayout.SequentialGroup buttonHorizontal = buttonPanelLayout.createSequentialGroup();
GroupLayout.Group buttonVertical;
-
+
if (renderCancelButton) {
JButton cancelButton = new JButton();
cancelButton.setFont(cancelButton.getFont().deriveFont(cancelButton.getFont().getStyle() & ~java.awt.Font.BOLD));
@@ -868,17 +1000,19 @@ public class BKUGUIImpl implements BKUGUIFacade {
cancelButton.addActionListener(cancelListener);
buttonHorizontal
+ .addComponent(signButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE);
-
buttonVertical = buttonPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(signButton)
- .addComponent(cancelButton);
+ .addComponent(cancelButton);
} else {
+ buttonHorizontal
+ .addComponent(signButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE);
buttonVertical = buttonPanelLayout.createSequentialGroup()
.addComponent(signButton);
}
-
+
buttonPanelLayout.setHorizontalGroup(buttonHorizontal);
buttonPanelLayout.setVerticalGroup(buttonVertical);
@@ -951,7 +1085,7 @@ public class BKUGUIImpl implements BKUGUIFacade {
@Override
public void run() {
- log.debug("show message dialog");
+ log.debug("show message dialog [" + Thread.currentThread().getName() + "]");
mainPanel.removeAll();
buttonPanel.removeAll();
@@ -1011,7 +1145,6 @@ public class BKUGUIImpl implements BKUGUIFacade {
buttonPanelLayout.setHorizontalGroup(
buttonPanelLayout.createSequentialGroup()
- .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(okButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE));
buttonPanelLayout.setVerticalGroup(
buttonPanelLayout.createSequentialGroup()
@@ -1084,68 +1217,69 @@ public class BKUGUIImpl implements BKUGUIFacade {
}
return null;
}
+
+
+ ////////////////////////////////////////////////////////////////////////////
+ // SECURE VIEWER
+ ////////////////////////////////////////////////////////////////////////////
+
/**
- * TODO handle multiple references in HashDataViewer
* @param signedReferences
- * @param okListener
+ * @param backListener gets notified if pin-dialog has to be redrawn
+ * (signedRefencesList returns via BACK button)
* @param okCommand
*/
@Override
- public void showSecureViewer(final List<HashDataInput> signedReferences,
- final ActionListener okListener,
- final String okCommand) {
-
- if (signedReferences == null) {
- showErrorDialog(getMessage(ERR_NO_HASHDATA), new Object[] {"No SignedReferences provided"}, okListener, okCommand);
- return;
- }
+ public void showSecureViewer(final List<HashDataInput> dataToBeSigned,
+ final ActionListener backListener, final String backCommand) {
- if (signedReferences.size() == 1) {
+ if (dataToBeSigned == null) {
+ showErrorDialog(getMessage(ERR_NO_HASHDATA),
+ new Object[] {"no signature data provided"},
+ backListener, backCommand);
+ } else if (dataToBeSigned.size() == 1) {
try {
- log.debug("scheduling hashdata viewer");
+ log.debug("scheduling secure viewer");
- SwingUtilities.invokeAndWait(new Runnable() {
+ SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
- ActionListener saveHashDataListener = new ActionListener() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- HashDataInput hdi = signedReferences.get(0);
- showSaveHashDataInputDialog(Collections.singletonList(hdi), okListener, okCommand);
- }
- };
- showHashDataViewer(signedReferences.get(0), saveHashDataListener, "save");
+ showSecureViewer(dataToBeSigned.get(0));
}
});
- } catch (InterruptedException ex) {
- log.error("Failed to display HashDataViewer: " + ex.getMessage());
- } catch (InvocationTargetException ex) {
- log.error("Failed to display HashDataViewer: " + ex.getMessage());
+ } catch (Exception ex) { //InterruptedException InvocationTargetException
+ log.error("Failed to display secure viewer: " + ex.getMessage());
+ log.trace(ex);
+ showErrorDialog(ERR_UNKNOWN, null, backListener, backCommand);
}
} else {
- showSignedReferencesListDialog(signedReferences, okListener, okCommand);
+ showSignedReferencesListDialog(dataToBeSigned, backListener, backCommand);
}
}
/**
* has to be called from event dispatcher thread
+ * This method blocks until the dialog's close button is pressed.
* @param hashDataText
* @param saveListener
* @param saveCommand
*/
- private void showHashDataViewer(final HashDataInput hashDataInput, final ActionListener saveListener, final String saveCommand) {
+ private void showSecureViewer(HashDataInput dataToBeSigned) {
- log.debug("show hashdata viewer");
-
- ActionListener l = helpListener.getActionListener();
- HashDataViewer.showHashDataInput(contentPane, hashDataInput, messages, saveListener, saveCommand, l);
+ log.debug("show secure viewer [" + Thread.currentThread().getName() + "]");
+ if (secureViewer == null) {
+ secureViewer = new SecureViewerDialog(null, messages,
+ helpListener.getActionListener());
+ }
+ secureViewer.setContent(dataToBeSigned);
+ log.trace("show secure viewer returned");
}
- private void showSignedReferencesListDialog(final List<HashDataInput> signedReferences, final ActionListener backListener, final String backCommand) {
+ private void showSignedReferencesListDialog(final List<HashDataInput> signedReferences,
+ final ActionListener backListener, final String backCommand) {
log.debug("scheduling signed references list dialog");
@@ -1154,7 +1288,7 @@ public class BKUGUIImpl implements BKUGUIFacade {
@Override
public void run() {
- log.debug("show signed references list dialog");
+ log.debug("show signed references list dialog [" + Thread.currentThread().getName() + "]");
mainPanel.removeAll();
buttonPanel.removeAll();
@@ -1202,13 +1336,7 @@ public class BKUGUIImpl implements BKUGUIFacade {
int selectionIdx = lsm.getMinSelectionIndex();
if (selectionIdx >= 0) {
final HashDataInput selection = signedReferences.get(selectionIdx);
- showHashDataViewer(selection, new ActionListener() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- showSaveHashDataInputDialog(Collections.singletonList(selection), null, null);
- }
- }, "save");
+ showSecureViewer(selection);
}
}
});
@@ -1255,9 +1383,8 @@ public class BKUGUIImpl implements BKUGUIFacade {
buttonPanel.setLayout(buttonPanelLayout);
buttonPanelLayout.setHorizontalGroup(buttonPanelLayout.createSequentialGroup()
- .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(backButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE));
- buttonPanelLayout.setVerticalGroup(buttonPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ buttonPanelLayout.setVerticalGroup(buttonPanelLayout.createSequentialGroup()
.addComponent(backButton));
contentPanel.validate();
@@ -1266,96 +1393,101 @@ public class BKUGUIImpl implements BKUGUIFacade {
}
/**
- *
- * @param signedRefs
* @param okListener may be null
- * @param okCommand
*/
- private void showSaveHashDataInputDialog(final List<HashDataInput> signedRefs, final ActionListener okListener, final String okCommand) {
-
- log.debug("scheduling save hashdatainput dialog");
-
- SwingUtilities.invokeLater(new Runnable() {
+// private void showSaveDialog(final List<HashDataInput> signedRefs,
+// final ActionListener okListener, final String okCommand) {
+//
+// log.debug("scheduling save dialog");
+//
+// SwingUtilities.invokeLater(new Runnable() {
+//
+// @Override
+// public void run() {
+//
+// log.debug("show save dialog");
+//
+// String userHome = System.getProperty("user.home");
+//
+// JFileChooser fileDialog = new JFileChooser(userHome);
+// fileDialog.setMultiSelectionEnabled(false);
+// fileDialog.setDialogType(JFileChooser.SAVE_DIALOG);
+// fileDialog.setFileHidingEnabled(true);
+// if (signedRefs.size() == 1) {
+// fileDialog.setDialogTitle(getMessage(WINDOWTITLE_SAVE));
+// fileDialog.setFileSelectionMode(JFileChooser.FILES_ONLY);
+// String mimeType = signedRefs.get(0).getMimeType();
+// MimeFilter mimeFilter = new MimeFilter(mimeType, messages);
+// fileDialog.setFileFilter(mimeFilter);
+// String filename = getMessage(SAVE_HASHDATAINPUT_PREFIX) + MimeFilter.getExtension(mimeType);
+// fileDialog.setSelectedFile(new File(userHome, filename));
+// } else {
+// fileDialog.setDialogTitle(getMessage(WINDOWTITLE_SAVEDIR));
+// fileDialog.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+// }
+//
+// //parent contentPane -> placed over applet
+// switch (fileDialog.showSaveDialog(fileDialog)) {
+// case JFileChooser.APPROVE_OPTION:
+// File f = fileDialog.getSelectedFile();
+// for (HashDataInput hashDataInput : signedRefs) {
+// String mimeType = hashDataInput.getMimeType();
+// String id = hashDataInput.getReferenceId();
+// File file;
+// if (f.isDirectory()) {
+// String filename = getMessage(SAVE_HASHDATAINPUT_PREFIX) + '_' + id + MimeFilter.getExtension(mimeType);
+// file = new File(f, filename);
+// } else {
+// file = f;
+// }
+// if (file.exists()) {
+// String ovrwrt = getMessage(MESSAGE_OVERWRITE);
+// int overwrite = JOptionPane.showConfirmDialog(fileDialog, MessageFormat.format(ovrwrt, file), getMessage(WINDOWTITLE_OVERWRITE), JOptionPane.OK_CANCEL_OPTION);
+// if (overwrite != JOptionPane.OK_OPTION) {
+// continue;
+// }
+// }
+// if (log.isDebugEnabled()) {
+// log.debug("writing hashdata input " + id + " (" + mimeType + ") to file " + file);
+// }
+// FileOutputStream fos = null;
+// try {
+// fos = new FileOutputStream(file);
+// BufferedOutputStream bos = new BufferedOutputStream(fos);
+// InputStream hdi = hashDataInput.getHashDataInput();
+// int b;
+// while ((b = hdi.read()) != -1) {
+// bos.write(b);
+// }
+// bos.flush();
+// bos.close();
+// } catch (IOException ex) {
+// log.error("Failed to write " + file + ": " + ex.getMessage());
+// showErrorDialog(ERR_WRITE_HASHDATA, new Object[] {ex.getMessage()}, null, null);
+// ex.printStackTrace();
+// } finally {
+// try {
+// fos.close();
+// } catch (IOException ex) {
+// }
+// }
+// }
+// break;
+// case JFileChooser.CANCEL_OPTION :
+// log.debug("cancelled save dialog");
+// break;
+// }
+// if (okListener != null) {
+// okListener.actionPerformed(new ActionEvent(fileDialog, ActionEvent.ACTION_PERFORMED, okCommand));
+// }
+// }
+// });
+// }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // UTILITY METHODS
+ ////////////////////////////////////////////////////////////////////////////
- @Override
- public void run() {
-
- log.debug("show save hashdatainput dialog");
-
- String userHome = System.getProperty("user.home");
-
- JFileChooser fileDialog = new JFileChooser(userHome);
- fileDialog.setMultiSelectionEnabled(false);
- fileDialog.setDialogType(JFileChooser.SAVE_DIALOG);
- fileDialog.setFileHidingEnabled(true);
- if (signedRefs.size() == 1) {
- fileDialog.setDialogTitle(getMessage(WINDOWTITLE_SAVE));
- fileDialog.setFileSelectionMode(JFileChooser.FILES_ONLY);
- String mimeType = signedRefs.get(0).getMimeType();
- MimeFilter mimeFilter = new MimeFilter(mimeType, messages);
- fileDialog.setFileFilter(mimeFilter);
- String filename = getMessage(SAVE_HASHDATAINPUT_PREFIX) + MimeFilter.getExtension(mimeType);
- fileDialog.setSelectedFile(new File(userHome, filename));
- } else {
- fileDialog.setDialogTitle(getMessage(WINDOWTITLE_SAVEDIR));
- fileDialog.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
- }
-
- //parent contentPane -> placed over applet
- switch (fileDialog.showSaveDialog(fileDialog)) {
- case JFileChooser.APPROVE_OPTION:
- File f = fileDialog.getSelectedFile();
- for (HashDataInput hashDataInput : signedRefs) {
- String mimeType = hashDataInput.getMimeType();
- String id = hashDataInput.getReferenceId();
- File file;
- if (f.isDirectory()) {
- String filename = getMessage(SAVE_HASHDATAINPUT_PREFIX) + '_' + id + MimeFilter.getExtension(mimeType);
- file = new File(f, filename);
- } else {
- file = f;
- }
- if (file.exists()) {
- String ovrwrt = getMessage(MESSAGE_OVERWRITE);
- int overwrite = JOptionPane.showConfirmDialog(fileDialog, MessageFormat.format(ovrwrt, file), getMessage(WINDOWTITLE_OVERWRITE), JOptionPane.OK_CANCEL_OPTION);
- if (overwrite != JOptionPane.OK_OPTION) {
- continue;
- }
- }
- if (log.isDebugEnabled()) {
- log.debug("Writing HashDataInput " + id + " (" + mimeType + ") to file " + file);
- }
- FileOutputStream fos = null;
- try {
- fos = new FileOutputStream(file);
- BufferedOutputStream bos = new BufferedOutputStream(fos);
- InputStream hdi = hashDataInput.getHashDataInput();
- int b;
- while ((b = hdi.read()) != -1) {
- bos.write(b);
- }
- bos.flush();
- bos.close();
- } catch (IOException ex) {
- log.error("Failed to write HashDataInput to file " + file + ": " + ex.getMessage());
- showErrorDialog(ERR_WRITE_HASHDATA, new Object[] {ex.getMessage()}, null, null);
- ex.printStackTrace();
- } finally {
- try {
- fos.close();
- } catch (IOException ex) {
- }
- }
- }
- }
- log.debug("done saving hashdatainput");
- if (okListener != null) {
- okListener.actionPerformed(new ActionEvent(fileDialog, ActionEvent.ACTION_PERFORMED, okCommand));
- }
- }
- });
- }
-
private void registerHelpListener(ActionListener helpListener) {
if (helpListener != null) {
this.helpListener = new HelpMouseListener(helpListener);
@@ -1371,6 +1503,11 @@ public class BKUGUIImpl implements BKUGUIFacade {
}
}
+
+ ////////////////////////////////////////////////////////////////////////////
+ // INITIALIZERS (MAY BE OVERRIDDEN BY SUBCLASSES)
+ ////////////////////////////////////////////////////////////////////////////
+
/**
* Called from constructor.
* Subclasses may override this method to ensure the message bundle is loaded
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HashDataViewer.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HashDataViewer.java
deleted file mode 100644
index 6c097b2a..00000000
--- a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HashDataViewer.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright 2008 Federal Chancellery Austria and
- * Graz University of Technology
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package at.gv.egiz.bku.gui;
-
-import at.gv.egiz.bku.gui.html.RestrictedHTMLEditorKit;
-import at.gv.egiz.stal.HashDataInput;
-import java.awt.Component;
-import java.awt.Container;
-import java.awt.Cursor;
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.Frame;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.nio.charset.Charset;
-import java.text.MessageFormat;
-import java.util.ResourceBundle;
-import javax.swing.GroupLayout;
-import javax.swing.ImageIcon;
-import javax.swing.JButton;
-import javax.swing.JDialog;
-import javax.swing.JEditorPane;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.LayoutStyle;
-import javax.swing.text.Document;
-import javax.swing.text.EditorKit;
-import javax.swing.text.StyledEditorKit;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- *
- * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
- */
-public class HashDataViewer extends JDialog
- implements ActionListener {
-
- public static final String PLAINTEXT_FONT = "Monospaced";
- protected static final Log log = LogFactory.getLog(HashDataViewer.class);
-
- private static HashDataViewer dialog;
-
- protected ResourceBundle messages;
-
- /**
- *
- * @param signedReferences currently, only one hashdata input (the first in the list) is displayed
- */
- public static void showHashDataInput(HashDataInput hashDataInput,
- ResourceBundle messages,
- ActionListener saveListener,
- String saveCommand,
- ActionListener helpListener) {
- showHashDataInput(null, hashDataInput, messages, saveListener, saveCommand, helpListener);
- }
-
- /**
- *
- * @param frameComp owner
- */
- public static void showHashDataInput(Component frameComp,
- HashDataInput hashDataInput,
- ResourceBundle messages,
- ActionListener saveListener,
- String saveCommand,
- ActionListener helpListener) {
-
- Frame frame = null;
- if (frameComp != null) {
- JOptionPane.getFrameForComponent(frameComp);
- }
- dialog = new HashDataViewer(frame,
- messages,
- hashDataInput,
- saveListener,
- saveCommand,
- helpListener);
- dialog.setVisible(true);
- }
-
- private HashDataViewer(Frame frame,
- ResourceBundle messages,
- HashDataInput hashDataInput,
- ActionListener saveListener,
- String saveCommand,
- ActionListener helpListener) {
- super(frame, messages.getString(BKUGUIFacade.WINDOWTITLE_VIEWER), true);
- this.messages = messages;
-
- Charset cs;
- if (hashDataInput.getEncoding() == null) {
- cs = Charset.forName("UTF-8");
- } else {
- try {
- cs = Charset.forName(hashDataInput.getEncoding());
- } catch (Exception ex) {
- log.debug("charset " + hashDataInput.getEncoding() + " not supported, assuming UTF-8: " + ex.getMessage());
- cs = Charset.forName("UTF-8");
- }
- }
-
-
- InputStreamReader isr = new InputStreamReader(hashDataInput.getHashDataInput(), cs);
- Reader content = new BufferedReader(isr);
-
- JPanel hashDataPanel = createViewerPanel(content,
- hashDataInput.getMimeType(),
- helpListener);
- JPanel buttonPanel = createButtonPanel(saveListener, saveCommand);
- initContentPane(new Dimension(600, 400), hashDataPanel, buttonPanel);
-
- pack();
- if (frame != null) {
- setLocationRelativeTo(frame);
- } else {
- setLocationByPlatform(true);
- }
- }
-
- private void initContentPane(Dimension preferredSize, JPanel viewerPanel, JPanel buttonPanel) {
- Container contentPane = getContentPane();
- contentPane.setPreferredSize(preferredSize);
-
- GroupLayout mainLayout = new GroupLayout(contentPane);
- contentPane.setLayout(mainLayout);
-
- mainLayout.setHorizontalGroup(
- mainLayout.createSequentialGroup().addContainerGap().addGroup(
- mainLayout.createParallelGroup(GroupLayout.Alignment.LEADING).addComponent(viewerPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addComponent(buttonPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)).addContainerGap());
- mainLayout.setVerticalGroup(
- mainLayout.createSequentialGroup()
- .addContainerGap()
- .addComponent(viewerPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
- .addComponent(buttonPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
- .addContainerGap());
- }
-
- /**
- *
- * @param messages
- * @param content
- * @param mimeType defaults to text/plain if null
- * @param encoding must be null if document contains charset declaration (e.g. HTML page), otherwise the parser crashes
- * @param helpListener may be null
- * @return
- */
- private JPanel createViewerPanel(Reader content,
- String mimeType,
- final ActionListener helpListener) {
-
- if (mimeType == null) {
- mimeType = "text/plain";
- }
- log.debug("viewer dialog: " + mimeType);
-
- JEditorPane viewer = new JEditorPane();
- viewer.setEditable(false);
- viewer.setContentType(mimeType);
-
- if ("text/plain".equals(mimeType)) {
- viewer.setEditorKit(new StyledEditorKit());
- viewer.setFont(new Font(PLAINTEXT_FONT, viewer.getFont().getStyle(), viewer.getFont().getSize()));
-// } else if ("text/html".equals(mimeType)) {
-// viewer.setEditorKit(new RestrictedHTMLEditorKit());
- } else if ("application/xhtml+xml".equals(mimeType)) {
- viewer.setContentType("text/html");
- }
-
- EditorKit editorKit = viewer.getEditorKit();
- Document document = editorKit.createDefaultDocument();
-// document.putProperty("IgnoreCharsetDirective", new Boolean(true));
-
- try {
- viewer.read(content, document);
- content.close();
- } catch (Exception ex) {
- log.error(ex.getMessage(), ex);
- String p = messages.getString(BKUGUIFacade.ERR_VIEWER);
- viewer.setText(MessageFormat.format(p, ex.getMessage()));
- }
-
- JScrollPane scrollPane = new JScrollPane(viewer);
- scrollPane.setPreferredSize(viewer.getPreferredSize());
- scrollPane.setAlignmentX(LEFT_ALIGNMENT);
- viewer.setCaretPosition(0);
-
- JPanel viewerPanel = new JPanel();
- GroupLayout viewerPanelLayout = new GroupLayout(viewerPanel);
- viewerPanel.setLayout(viewerPanelLayout);
-
- GroupLayout.SequentialGroup infoHorizontal = viewerPanelLayout.createSequentialGroup();
- GroupLayout.ParallelGroup infoVertical = viewerPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING);
-
- if ("application/xhtml+xml".equals(mimeType)) {
- JLabel viewerLabel = new JLabel();
- viewerLabel.setText(messages.getString(BKUGUIFacade.WARNING_XHTML));
- viewerLabel.setFont(viewerLabel.getFont().deriveFont(viewerLabel.getFont().getStyle() | java.awt.Font.BOLD));
- viewerLabel.setLabelFor(viewer);
-
- infoHorizontal.addComponent(viewerLabel);
- infoVertical.addComponent(viewerLabel);
- }
-
- if (helpListener != null) {
- JLabel helpLabel = new JLabel();
- helpLabel.setIcon(new ImageIcon(getClass().getResource(BKUGUIFacade.HELP_IMG)));
- helpLabel.getAccessibleContext().setAccessibleName(messages.getString(BKUGUIFacade.ALT_HELP));
- helpLabel.addMouseListener(new MouseAdapter() {
-
- @Override
- public void mouseClicked(MouseEvent arg0) {
- ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, BKUGUIFacade.HELP_HASHDATAVIEWER);
- helpListener.actionPerformed(e);
- }
- });
- helpLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
-
- infoHorizontal
- .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 0, Short.MAX_VALUE)
- .addComponent(helpLabel);
- infoVertical
- .addComponent(helpLabel);
- }
-
- viewerPanelLayout.setHorizontalGroup(
- viewerPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
- .addGroup(infoHorizontal)
- .addComponent(scrollPane));
- viewerPanelLayout.setVerticalGroup(
- viewerPanelLayout.createSequentialGroup()
- .addGroup(infoVertical)
- .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(scrollPane));
-
-
- return viewerPanel;
- }
-
- private JPanel createButtonPanel(ActionListener saveListener, String saveCommand) {
- JButton closeButton = new JButton();
- closeButton.setText(messages.getString(BKUGUIFacade.BUTTON_CLOSE));
- closeButton.addActionListener(this);
-
- JButton saveButton = new JButton();
- saveButton.setText(messages.getString(BKUGUIFacade.BUTTON_SAVE));
- saveButton.setActionCommand(saveCommand);
- saveButton.addActionListener(saveListener);
-
- int buttonSize = closeButton.getPreferredSize().width;
- if (saveButton.getPreferredSize().width > buttonSize) {
- buttonSize = saveButton.getPreferredSize().width;
- }
-
- JPanel buttonPanel = new JPanel();
- GroupLayout buttonPanelLayout = new GroupLayout(buttonPanel);
- buttonPanel.setLayout(buttonPanelLayout);
-
- buttonPanelLayout.setHorizontalGroup(
- buttonPanelLayout.createSequentialGroup().addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addComponent(saveButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE).addPreferredGap(LayoutStyle.ComponentPlacement.RELATED).addComponent(closeButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE));
- buttonPanelLayout.setVerticalGroup(
- buttonPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE).addComponent(saveButton).addComponent(closeButton));
-
- return buttonPanel;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- HashDataViewer.dialog.setVisible(false);
- }
-}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SecureViewerDialog.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SecureViewerDialog.java
new file mode 100644
index 00000000..6a16306b
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SecureViewerDialog.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package at.gv.egiz.bku.gui;
+
+import at.gv.egiz.stal.HashDataInput;
+import java.awt.Container;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.text.MessageFormat;
+import java.util.ResourceBundle;
+import javax.swing.GroupLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JEditorPane;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.LayoutStyle;
+import javax.swing.SwingUtilities;
+import javax.swing.text.Document;
+import javax.swing.text.EditorKit;
+import javax.swing.text.StyledEditorKit;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class SecureViewerDialog extends JDialog implements ActionListener {
+
+ public static final String PLAINTEXT_FONT = "Monospaced";
+ public static final Dimension VIEWER_DIMENSION = new Dimension(600, 400);
+ protected static final Log log = LogFactory.getLog(SecureViewerDialog.class);
+
+// private static SecureViewerDialog dialog;
+ protected ResourceBundle messages;
+ protected JEditorPane viewer;
+ protected JLabel viewerLabel;
+ protected JScrollPane scrollPane;
+ protected HashDataInput content; //remember for save dialog
+
+ /**
+ * Create and display a modal SecureViewer dialog.
+ * This method blocks until the dialog's close button is pressed.
+ *
+ * @param owner, dialog is positioned relative to its owner
+ * (if null, at default location of native windowing system)
+ */
+// public static void showDataToBeSigned(HashDataInput dataToBeSigned,
+// ResourceBundle messages,
+// ActionListener saveListener, String saveCommand,
+// ActionListener helpListener) {
+//
+//// Frame ownerFrame = (owner != null) ?
+//// JOptionPane.getFrameForComponent(owner) :
+//// null;
+// dialog = new SecureViewerDialog(null, messages,
+// saveListener, saveCommand, helpListener);
+// dialog.setContent(dataToBeSigned);
+// dialog.setVisible(true);
+// }
+ public SecureViewerDialog(Frame owner, ResourceBundle messages,
+// ActionListener saveListener, String saveCommand,
+ ActionListener helpListener) {
+ super(owner, messages.getString(BKUGUIFacade.WINDOWTITLE_VIEWER), true);
+ this.messages = messages;
+
+ initContentPane(VIEWER_DIMENSION,
+ createViewerPanel(helpListener),
+ createButtonPanel()); //saveListener, saveCommand));
+
+ pack();
+ if (owner != null) {
+ setLocationRelativeTo(owner);
+ } else {
+ setLocationByPlatform(true);
+ }
+ }
+
+ private void initContentPane(Dimension preferredSize,
+ JPanel viewerPanel, JPanel buttonPanel) {
+ Container contentPane = getContentPane();
+ contentPane.setPreferredSize(preferredSize);
+
+ GroupLayout mainLayout = new GroupLayout(contentPane);
+ contentPane.setLayout(mainLayout);
+
+ mainLayout.setHorizontalGroup(
+ mainLayout.createSequentialGroup().addContainerGap().addGroup(
+ mainLayout.createParallelGroup(GroupLayout.Alignment.LEADING).addComponent(viewerPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addComponent(buttonPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)).addContainerGap());
+ mainLayout.setVerticalGroup(
+ mainLayout.createSequentialGroup().addContainerGap().addComponent(viewerPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED).addComponent(buttonPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE).addContainerGap());
+ }
+
+ /**
+ * @param helpListener may be null
+ */
+ private JPanel createViewerPanel(final ActionListener helpListener) {
+ viewer = new JEditorPane();
+ viewer.setEditable(false);
+
+ scrollPane = new JScrollPane();
+
+ JPanel viewerPanel = new JPanel();
+ GroupLayout viewerPanelLayout = new GroupLayout(viewerPanel);
+ viewerPanel.setLayout(viewerPanelLayout);
+
+ GroupLayout.SequentialGroup infoHorizontal = viewerPanelLayout.createSequentialGroup();
+ GroupLayout.ParallelGroup infoVertical = viewerPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING);
+
+ viewerLabel = new JLabel();
+ viewerLabel.setFont(viewerLabel.getFont().deriveFont(viewerLabel.getFont().getStyle() | java.awt.Font.BOLD));
+// viewerLabel.setLabelFor(viewer);
+
+ infoHorizontal.addComponent(viewerLabel);
+ infoVertical.addComponent(viewerLabel);
+
+ if (helpListener != null) {
+ JLabel helpLabel = new JLabel();
+ helpLabel.setIcon(new ImageIcon(getClass().getResource(BKUGUIFacade.HELP_IMG)));
+ helpLabel.getAccessibleContext().setAccessibleName(messages.getString(BKUGUIFacade.ALT_HELP));
+ helpLabel.addMouseListener(new MouseAdapter() {
+
+ @Override
+ public void mouseClicked(MouseEvent arg0) {
+ ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, BKUGUIFacade.HELP_HASHDATAVIEWER);
+ helpListener.actionPerformed(e);
+ }
+ });
+ helpLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+
+ infoHorizontal.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 0, Short.MAX_VALUE).addComponent(helpLabel);
+ infoVertical.addComponent(helpLabel);
+ }
+
+ viewerPanelLayout.setHorizontalGroup(
+ viewerPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING).addGroup(infoHorizontal).addComponent(scrollPane));
+ viewerPanelLayout.setVerticalGroup(
+ viewerPanelLayout.createSequentialGroup().addGroup(infoVertical).addPreferredGap(LayoutStyle.ComponentPlacement.RELATED).addComponent(scrollPane));
+
+ return viewerPanel;
+ }
+
+ /**
+ * Sets the hashdataInput to be displayed and makes the dialog visible.
+ * This method blocks until the dialog's close button is pressed.
+ *
+ * @param mimeType defaults to text/plain if null
+ * @param encoding must be null if document contains charset declaration (e.g. HTML page), otherwise the parser crashes
+
+ * @param hashDataInput
+ */
+ public void setContent(HashDataInput hashDataInput) {
+
+ this.content = null;
+
+ String mimeType = hashDataInput.getMimeType();
+ if (mimeType == null) {
+ mimeType = "text/plain";
+ }
+ log.debug("secure viewer mime type: " + mimeType);
+ // loads editorkit for text/plain if unrecognized
+ viewer.setContentType(mimeType);
+
+ if ("text/plain".equals(mimeType)) {
+ viewer.setEditorKit(new StyledEditorKit());
+ viewer.setFont(new Font(PLAINTEXT_FONT, viewer.getFont().getStyle(), viewer.getFont().getSize()));
+// } else if ("text/html".equals(mimeType)) {
+// viewer.setEditorKit(new RestrictedHTMLEditorKit());
+ } else if ("application/xhtml+xml".equals(mimeType)) {
+ viewer.setContentType("text/html");
+ }
+
+ EditorKit editorKit = viewer.getEditorKit();
+ Document document = editorKit.createDefaultDocument();
+// document.putProperty("IgnoreCharsetDirective", new Boolean(true));
+
+ try {
+ Charset cs = (hashDataInput.getEncoding() == null) ? Charset.forName("UTF-8") : Charset.forName(hashDataInput.getEncoding());
+ log.debug("secure viewer encoding: " + cs.toString());
+
+ InputStreamReader isr = new InputStreamReader(hashDataInput.getHashDataInput(), cs);
+ Reader contentReader = new BufferedReader(isr);
+ viewer.read(contentReader, document);
+ contentReader.close();
+
+ this.content = hashDataInput;
+
+// } catch (IllegalCharsetNameException ex) {
+// } catch (UnsupportedCharsetException ex) {
+ } catch (Exception ex) {
+ log.error(ex.getMessage(), ex);
+ String p = messages.getString(BKUGUIFacade.ERR_VIEWER);
+ viewer.setText(MessageFormat.format(p, ex.getMessage()));
+ }
+ viewer.setCaretPosition(0);
+
+ scrollPane.setViewportView(viewer);
+ scrollPane.setPreferredSize(viewer.getPreferredSize());
+ scrollPane.setAlignmentX(LEFT_ALIGNMENT);
+
+ if ("application/xhtml+xml".equals(mimeType)) {
+ viewerLabel.setText(messages.getString(BKUGUIFacade.WARNING_XHTML));
+ } else {
+ viewerLabel.setText("");
+ }
+
+ setVisible(true);
+ }
+
+ private JPanel createButtonPanel() { //ActionListener saveListener, String saveCommand) {
+ JButton closeButton = new JButton();
+ closeButton.setText(messages.getString(BKUGUIFacade.BUTTON_CLOSE));
+ closeButton.setActionCommand("close");
+ closeButton.addActionListener(this);
+
+ JButton saveButton = new JButton();
+ saveButton.setText(messages.getString(BKUGUIFacade.BUTTON_SAVE));
+ saveButton.setActionCommand("save");
+ saveButton.addActionListener(this);
+
+ int buttonSize = closeButton.getPreferredSize().width;
+ if (saveButton.getPreferredSize().width > buttonSize) {
+ buttonSize = saveButton.getPreferredSize().width;
+ }
+
+ JPanel buttonPanel = new JPanel();
+ GroupLayout buttonPanelLayout = new GroupLayout(buttonPanel);
+ buttonPanel.setLayout(buttonPanelLayout);
+
+ buttonPanelLayout.setHorizontalGroup(
+ buttonPanelLayout.createSequentialGroup().addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addComponent(saveButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE).addPreferredGap(LayoutStyle.ComponentPlacement.RELATED).addComponent(closeButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE));
+ buttonPanelLayout.setVerticalGroup(
+ buttonPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE).addComponent(saveButton).addComponent(closeButton));
+
+ return buttonPanel;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if ("close".equals(e.getActionCommand())) {
+// SecureViewerDialog.dialog.setVisible(false);
+ log.trace("closing secure viewer");
+ setVisible(false);
+ log.trace("secure viewer closed");
+ } else if ("save".equals(e.getActionCommand())) {
+ log.trace("display secure viewer save dialog");
+ showSaveDialog(content, null, null);
+ log.trace("done secure viewer save");
+ } else {
+ log.warn("unknown action command " + e.getActionCommand());
+ }
+ }
+
+ private void showSaveDialog(final HashDataInput hashDataInput,
+ final ActionListener okListener, final String okCommand) {
+
+ log.debug("scheduling save dialog [" + Thread.currentThread().getName() + "]");
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+
+ log.debug("show save dialog [" + Thread.currentThread().getName() + "]");
+
+ String userHome = System.getProperty("user.home");
+
+ JFileChooser fileDialog = new JFileChooser(userHome);
+ fileDialog.setMultiSelectionEnabled(false);
+ fileDialog.setDialogType(JFileChooser.SAVE_DIALOG);
+ fileDialog.setFileHidingEnabled(true);
+ fileDialog.setDialogTitle(messages.getString(BKUGUIFacade.WINDOWTITLE_SAVE));
+ fileDialog.setFileSelectionMode(JFileChooser.FILES_ONLY);
+ String mimeType = hashDataInput.getMimeType();
+ MimeFilter mimeFilter = new MimeFilter(mimeType, messages);
+ fileDialog.setFileFilter(mimeFilter);
+ String filename = messages.getString(BKUGUIFacade.SAVE_HASHDATAINPUT_PREFIX) +
+ MimeFilter.getExtension(mimeType);
+ fileDialog.setSelectedFile(new File(userHome, filename));
+
+ //parent contentPane -> placed over applet
+ switch (fileDialog.showSaveDialog(fileDialog)) {
+ case JFileChooser.APPROVE_OPTION:
+ File file = fileDialog.getSelectedFile();
+ String id = hashDataInput.getReferenceId();
+ if (file.exists()) {
+ String msgPattern = messages.getString(BKUGUIFacade.MESSAGE_OVERWRITE);
+ int overwrite = JOptionPane.showConfirmDialog(fileDialog,
+ MessageFormat.format(msgPattern, file),
+ messages.getString(BKUGUIFacade.WINDOWTITLE_OVERWRITE),
+ JOptionPane.OK_CANCEL_OPTION);
+ if (overwrite != JOptionPane.OK_OPTION) {
+ return;
+ }
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("writing hashdata input " + id + " (" + mimeType + ") to file " + file);
+ }
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(file);
+ BufferedOutputStream bos = new BufferedOutputStream(fos);
+ InputStream hdi = hashDataInput.getHashDataInput();
+ int b;
+ while ((b = hdi.read()) != -1) {
+ bos.write(b);
+ }
+ bos.flush();
+ bos.close();
+ } catch (IOException ex) {
+ log.error("Failed to write " + file + ": " + ex.getMessage());
+ log.debug(ex);
+ String errPattern = messages.getString(BKUGUIFacade.ERR_WRITE_HASHDATA);
+ JOptionPane.showMessageDialog(fileDialog,
+ MessageFormat.format(errPattern, ex.getMessage()),
+ messages.getString(BKUGUIFacade.WINDOWTITLE_ERROR),
+ JOptionPane.ERROR_MESSAGE);
+ } finally {
+ try {
+ if (fos != null) {
+ fos.close();
+ }
+ } catch (IOException ex) {
+ }
+ }
+ break;
+ case JFileChooser.CANCEL_OPTION:
+ log.debug("cancelled save dialog");
+ break;
+ }
+ if (okListener != null) {
+ okListener.actionPerformed(new ActionEvent(fileDialog, ActionEvent.ACTION_PERFORMED, okCommand));
+ }
+ }
+ });
+ }
+}
diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties
index 6d651b2d..9bfe8fb1 100644
--- a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties
+++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties
@@ -25,6 +25,7 @@ title.retry=<html>Falsche PIN</html>
title.wait=<html>Bitte warten</html>
title.hashdata=<html>Signaturdaten</html>
windowtitle.save=Signaturdaten speichern
+windowtitle.error=Fehler
windowtitle.savedir=Signaturdaten in Verzeichnis speichern
windowtitle.overwrite=Datei \u00FCberschreiben?
windowtitle.viewer=Signaturdaten
@@ -79,7 +80,7 @@ error.unknown.param=<html>Ein Fehler trat auf: {0}</html>
error.unknown=<html>Ein Fehler trat auf</html>
error.test=<html>Fehler1 {0} - Fehler2 {1}</html>
error.card.locked=<html>B\u00FCrgerkarte ist gesperrt</html>
-error.card.notactivated=<html>B\u00FCrgerkartenfunktion ist nicht aktiviert</html>
+error.card.notactivated=<html>Die B\u00FCrgerkarte ist nicht aktiviert</html>
error.pin.timeout=<html>Zeit\u00FCberschreitung bei Eingabe der PIN</html>
error.viewer=Der Inhalt kann nicht dargestellt werden: {0}
error.external.link=<html>Externer Link {0} wird nicht ge\u00F6ffnet</html>
diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_en.properties b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_en.properties
index 2fb66969..a36f9b83 100644
--- a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_en.properties
+++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_en.properties
@@ -25,6 +25,7 @@ title.retry=<html>Wrong PIN</html>
title.wait=<html>Please wait</html>
title.hashdata=<html>Signature data</html>
windowtitle.save=Save signature data
+windowtitle.error=Error
windowtitle.savedir=Save signature data to directory
windowtitle.overwrite=Overwrite file?
windowtitle.viewer=Signature data
diff --git a/BKUCommonGUI/src/main/resources/images/ChipperlingLogo.png b/BKUCommonGUI/src/main/resources/images/ChipperlingLogo.png
new file mode 100644
index 00000000..eee4be4f
--- /dev/null
+++ b/BKUCommonGUI/src/main/resources/images/ChipperlingLogo.png
Binary files differ
diff --git a/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUITest.java b/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUITest.java
index c8cff617..b3eaf8c7 100644
--- a/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUITest.java
+++ b/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUITest.java
@@ -39,8 +39,9 @@ public class BKUGUITest {
public void testBKUGUI() {
JFrame testFrame = new JFrame("BKUGUITest");
Container contentPane = testFrame.getContentPane();
- contentPane.setPreferredSize(new Dimension(170, 150));
- BKUGUIFacade gui = new BKUGUIImpl(contentPane, null, BKUGUIFacade.Style.tiny, null, null);
+// contentPane.setPreferredSize(new Dimension(170, 150));
+ contentPane.setPreferredSize(new Dimension(290, 190));
+ BKUGUIFacade gui = new BKUGUIImpl(contentPane, null, BKUGUIFacade.Style.advanced, null, null);
BKUGUIWorker worker = new BKUGUIWorker();
worker.init(gui);
testFrame.pack();
diff --git a/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java b/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java
index 194e18b0..5475a45b 100644
--- a/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java
+++ b/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java
@@ -149,7 +149,9 @@ public class BKUGUIWorker implements Runnable {
//
// Thread.sleep(2000);
//
- gui.showSignaturePINDialog(signPinSpec, -1, signListener, "sign", cancelListener, "cancel", hashdataListener, "hashdata");
+// gui.showSignaturePINDialog(signPinSpec, -1, signListener, "sign", cancelListener, "cancel", hashdataListener, "hashdata");
+
+ gui.showPinpadSignaturePINDialog(signPinSpec, -1, hashdataListener, "hashdata");
//
// Thread.sleep(4000);
//
diff --git a/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/BKUGuiProxy.java b/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/BKUGuiProxy.java
index 5a0ba84a..3f560967 100644
--- a/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/BKUGuiProxy.java
+++ b/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/BKUGuiProxy.java
@@ -144,4 +144,12 @@ public class BKUGuiProxy implements BKUGUIFacade {
showDialog();
delegate.showMessageDialog(titleKey, msgKey);
}
+
+ @Override
+ public void showPinpadSignaturePINDialog(PINSpec pinSpec, int numRetries,
+ ActionListener viewerListener, String viewerCommand) {
+ showDialog();
+ delegate.showPinpadSignaturePINDialog(pinSpec, numRetries,
+ viewerListener, viewerCommand);
+ }
}
diff --git a/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalBKUWorker.java b/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalBKUWorker.java
index 61cc7c4c..a782de1a 100644
--- a/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalBKUWorker.java
+++ b/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalBKUWorker.java
@@ -37,7 +37,8 @@ public class LocalBKUWorker extends AbstractBKUWorker {
public LocalBKUWorker(BKUGUIFacade gui, JDialog container) {
super(gui);
this.container = container;
- addRequestHandler(SignRequest.class, new LocalSignRequestHandler());
+ addRequestHandler(SignRequest.class,
+ new LocalSignRequestHandler(new LocalSecureViewer(gui)));
}
@Override
diff --git a/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalSecureViewer.java b/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalSecureViewer.java
new file mode 100644
index 00000000..cbe5af7a
--- /dev/null
+++ b/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalSecureViewer.java
@@ -0,0 +1,109 @@
+
+package at.gv.egiz.bku.local.stal;
+
+import at.gv.egiz.bku.slcommands.impl.DataObjectHashDataInput;
+import at.gv.egiz.bku.smccstal.SecureViewer;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import at.gv.egiz.bku.gui.BKUGUIFacade;
+import at.gv.egiz.stal.HashDataInput;
+import at.gv.egiz.stal.impl.ByteArrayHashDataInput;
+import at.gv.egiz.stal.signedinfo.ReferenceType;
+import at.gv.egiz.stal.signedinfo.SignedInfoType;
+import java.awt.event.ActionListener;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.List;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class LocalSecureViewer implements SecureViewer {
+
+ private static final Log log = LogFactory.getLog(LocalSignRequestHandler.class);
+ private List<HashDataInput> hashDataInputs = Collections.EMPTY_LIST;
+
+ protected BKUGUIFacade gui;
+
+ public LocalSecureViewer(BKUGUIFacade gui) {
+ this.gui = gui;
+ }
+
+ public void setDataToBeSigned(List<HashDataInput> dataToBeSigned) {
+ this.hashDataInputs = dataToBeSigned;
+ }
+
+ /**
+ *
+ * @param dsigReferences
+ * @throws java.lang.Exception
+ */
+ @Override
+ public void displayDataToBeSigned(SignedInfoType signedInfo,
+ ActionListener okListener, String okCommand)
+ throws Exception {
+ if (signedInfo.getReference().size() == 0) {
+ log.error("No hashdata input selected to be displayed: null");
+ throw new Exception("No HashData Input selected to be displayed");
+ }
+
+ ArrayList<HashDataInput> selectedHashDataInputs = new ArrayList<HashDataInput>();
+ for (ReferenceType dsigRef : signedInfo.getReference()) {
+ // don't get Manifest, QualifyingProperties, ...
+ if (dsigRef.getType() == null) {
+ String dsigRefId = dsigRef.getId();
+ if (dsigRefId != null) {
+ boolean hdiAvailable = false;
+ for (HashDataInput hashDataInput : hashDataInputs) {
+ if (dsigRefId.equals(hashDataInput.getReferenceId())) {
+ log.debug("display hashdata input for dsig:SignedReference " +
+ dsigRefId);
+ selectedHashDataInputs.add(
+ ensureCachedHashDataInput(hashDataInput));
+ hdiAvailable = true;
+ break;
+ }
+ }
+ if (!hdiAvailable) {
+ log.error("no hashdata input for dsig:SignedReference " + dsigRefId);
+ throw new Exception(
+ "No HashDataInput available for dsig:SignedReference " + dsigRefId);
+ }
+ } else {
+ throw new Exception(
+ "Cannot get HashDataInput for dsig:Reference without Id attribute");
+ }
+ }
+ }
+
+ if (selectedHashDataInputs.size() < 1) {
+ log.error("dsig:SignedInfo does not contain a data reference");
+ throw new Exception("dsig:SignedInfo does not contain a data reference");
+ }
+ gui.showSecureViewer(selectedHashDataInputs, okListener, okCommand);
+ }
+
+
+ private HashDataInput ensureCachedHashDataInput(HashDataInput hashDataInput)
+ throws IOException {
+ if (!(hashDataInput instanceof DataObjectHashDataInput)) {
+
+ log.warn("expected DataObjectHashDataInput for LocalSignRequestHandler, got " +
+ hashDataInput.getClass().getName());
+
+ InputStream hdIs = hashDataInput.getHashDataInput();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(hdIs.available());
+ int b;
+ while ((b = hdIs.read()) != -1) {
+ baos.write(b);
+ }
+ hashDataInput = new ByteArrayHashDataInput(baos.toByteArray(),
+ hashDataInput.getReferenceId(),
+ hashDataInput.getMimeType(),
+ hashDataInput.getEncoding());
+ }
+ return hashDataInput;
+ }
+
+}
diff --git a/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalSignRequestHandler.java b/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalSignRequestHandler.java
index 531e6591..492b8a05 100644
--- a/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalSignRequestHandler.java
+++ b/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalSignRequestHandler.java
@@ -16,9 +16,7 @@
*/
package at.gv.egiz.bku.local.stal;
-import at.gv.egiz.bku.slcommands.impl.DataObjectHashDataInput;
-import java.io.IOException;
-import java.util.ArrayList;
+import at.gv.egiz.bku.smccstal.SecureViewer;
import java.util.Collections;
import java.util.List;
@@ -40,9 +38,16 @@ import java.io.InputStream;
* @author clemens
*/
public class LocalSignRequestHandler extends SignRequestHandler {
+// implements SecureViewer {
private static final Log log = LogFactory.getLog(LocalSignRequestHandler.class);
- private List<HashDataInput> hashDataInputs = Collections.EMPTY_LIST;
+
+ protected LocalSecureViewer secureViewer;
+
+ public LocalSignRequestHandler(LocalSecureViewer secureViewer) {
+ super(secureViewer);
+ }
+
/**
* If the request is a SIGN request, it contains a list of DataObjectHashDataInput
@@ -53,75 +58,13 @@ public class LocalSignRequestHandler extends SignRequestHandler {
*/
@SuppressWarnings("unchecked")
@Override
- public STALResponse handleRequest(STALRequest request) throws InterruptedException {
+ public STALResponse handleRequest(STALRequest request)
+ throws InterruptedException {
+
if (request instanceof SignRequest) {
SignRequest signReq = (SignRequest) request;
- hashDataInputs = signReq.getHashDataInput();
+ secureViewer.setDataToBeSigned(signReq.getHashDataInput());
}
return super.handleRequest(request);
}
-
- /**
- *
- * @param dsigReferences
- * @throws java.lang.Exception
- */
- @Override
- public void displayDataToBeSigned(List<ReferenceType> dsigReferences) throws Exception {
- if (dsigReferences == null || dsigReferences.size() < 1) {
- log.error("No hashdata input selected to be displayed: null");
- throw new Exception("No HashData Input selected to be displayed");
- }
-
- ArrayList<HashDataInput> selectedHashDataInputs = new ArrayList<HashDataInput>();
- for (ReferenceType dsigRef : dsigReferences) {
- // don't get Manifest, QualifyingProperties, ...
- if (dsigRef.getType() == null) {
- String dsigRefId = dsigRef.getId();
- if (dsigRefId != null) {
- boolean hdiAvailable = false;
- for (HashDataInput hashDataInput : hashDataInputs) {
- if (dsigRefId.equals(hashDataInput.getReferenceId())) {
- log.debug("display hashdata input for dsig:SignedReference " + dsigRefId);
- if (!(hashDataInput instanceof DataObjectHashDataInput)) {
- log.warn(
- "expected DataObjectHashDataInput for LocalSignRequestHandler, got " + hashDataInput.getClass().getName());
- hashDataInput = getByteArrayHashDataInput(hashDataInput);
- }
- selectedHashDataInputs.add(hashDataInput);
- hdiAvailable = true;
- break;
- }
- }
- if (!hdiAvailable) {
- log.error("no hashdata input for dsig:SignedReference " + dsigRefId);
- throw new Exception(
- "No HashDataInput available for dsig:SignedReference " + dsigRefId);
- }
- } else {
- throw new Exception(
- "Cannot get HashDataInput for dsig:Reference without Id attribute");
- }
- }
- }
-
- if (selectedHashDataInputs.size() < 1) {
- log.error("dsig:SignedInfo does not contain a data reference");
- throw new Exception("dsig:SignedInfo does not contain a data reference");
- }
- gui.showSecureViewer(selectedHashDataInputs, this, "hashDataDone");
- }
-
- private ByteArrayHashDataInput getByteArrayHashDataInput(HashDataInput hashDataInput) throws IOException {
-
- InputStream hdIs = hashDataInput.getHashDataInput();
- ByteArrayOutputStream baos = new ByteArrayOutputStream(hdIs.available());
- int b;
- while ((b = hdIs.read()) != -1) {
- baos.write(b);
- }
- ByteArrayHashDataInput hdi = new ByteArrayHashDataInput(baos.toByteArray(), hashDataInput.getReferenceId(), hashDataInput.getMimeType(), hashDataInput.getEncoding());
-
- return hdi;
- }
}
diff --git a/BKUOnline/src/main/resources/at/gv/egiz/bku/online/conf/defaultConf.properties b/BKUOnline/src/main/resources/at/gv/egiz/bku/online/conf/defaultConf.properties
index e2f07481..04c9c7bf 100644
--- a/BKUOnline/src/main/resources/at/gv/egiz/bku/online/conf/defaultConf.properties
+++ b/BKUOnline/src/main/resources/at/gv/egiz/bku/online/conf/defaultConf.properties
@@ -40,9 +40,12 @@ SSL.sslProtocol=TLS
# warning do not set the following property to true
# its intended for debugging and testing only
SSL.disableAllChecks=false
+#SSL.disableHostnameVerification=true
# ------------ END SSL Config --------------------
+#UserAgent=citizen-card-environment/1.2 MOCCA/1.0
+
ValidateHashDataInputs=true
AppletTimeout=300000
diff --git a/BKUOnline/src/main/resources/log4j.properties b/BKUOnline/src/main/resources/log4j.properties
index f608c83d..25ea9faa 100644
--- a/BKUOnline/src/main/resources/log4j.properties
+++ b/BKUOnline/src/main/resources/log4j.properties
@@ -30,7 +30,7 @@ log4j.appender.STDOUT.layout.ConversionPattern=%-5p | %t | %c %x - %m%n
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.maxFileSize=500KB
log4j.appender.file.maxBackupIndex=9
-log4j.appender.file.File=${catalina.home}/logs/bkuonline.log
+log4j.appender.file.File=${catalina.base}/logs/bkuonline.log
log4j.appender.file.threshold=trace
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p | %t | %c{1}:%L - %m%n \ No newline at end of file
diff --git a/BKUOnline/src/main/webapp/SLRequestForm.html b/BKUOnline/src/main/webapp/SLRequestForm.html
index 9ff7b68a..4714e82f 100644
--- a/BKUOnline/src/main/webapp/SLRequestForm.html
+++ b/BKUOnline/src/main/webapp/SLRequestForm.html
@@ -103,6 +103,33 @@
</sl:InfoboxReadRequest>
-->
<!--
+<?xml version="1.0" encoding="UTF-8"?>
+<sl:CreateXMLSignatureRequest
+ xmlns:sl="http://www.buergerkarte.at/namespaces/securitylayer/1.2#">
+ <sl:KeyboxIdentifier>SecureSignatureKeypair</sl:KeyboxIdentifier>
+ <sl:DataObjectInfo Structure="enveloping">
+ <sl:DataObject>
+ <sl:XMLContent>Ich bin ein einfacher Text.</sl:XMLContent>
+ </sl:DataObject>
+ <sl:TransformsInfo>
+ <sl:FinalDataMetaInfo>
+ <sl:MimeType>text/plain</sl:MimeType>
+ </sl:FinalDataMetaInfo>
+ </sl:TransformsInfo>
+ </sl:DataObjectInfo>
+ <sl:DataObjectInfo Structure="enveloping">
+ <sl:DataObject>
+ <sl:XMLContent><html xmlns="http://www.w3.org/1999/xhtml"><head><title>TestXHTML</title><style/></head><body><p>Ich bin ein einfacher Text.</p></body></html></sl:XMLContent>
+ </sl:DataObject>
+ <sl:TransformsInfo>
+ <sl:FinalDataMetaInfo>
+ <sl:MimeType>application/xhtml+xml</sl:MimeType>
+ </sl:FinalDataMetaInfo>
+ </sl:TransformsInfo>
+ </sl:DataObjectInfo>
+</sl:CreateXMLSignatureRequest>
+-->
+<!--
<?xml version='1.0' encoding='UTF-8'?>
<sl10:InfoboxUpdateRequest xmlns:sl10='http://www.buergerkarte.at/namespaces/securitylayer/1.2#'>
<sl10:InfoboxIdentifier>CardChannel</sl10:InfoboxIdentifier>
diff --git a/bkucommon/src/test/java/at/gv/egiz/bku/binding/ExpiryRemoverTest.java b/bkucommon/src/test/java/at/gv/egiz/bku/binding/ExpiryRemoverTest.java
index 61729567..0e64e7a2 100644
--- a/bkucommon/src/test/java/at/gv/egiz/bku/binding/ExpiryRemoverTest.java
+++ b/bkucommon/src/test/java/at/gv/egiz/bku/binding/ExpiryRemoverTest.java
@@ -14,54 +14,57 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package at.gv.egiz.bku.binding;
-
+package at.gv.egiz.bku.binding;
+
import java.net.MalformedURLException;
-import org.junit.Test;
-import static org.junit.Assert.*;
-
-public class ExpiryRemoverTest {
-
- @Test
- public void testMe() throws InterruptedException, MalformedURLException {
- BindingProcessorManager manager = new BindingProcessorManagerImpl(new DummyStalFactory(),
- new SLCommandInvokerImpl());
- BindingProcessor bp = manager.createBindingProcessor("http://www.at", null);
- ExpiryRemover remover = new ExpiryRemover();
- remover.setBindingProcessorManager(manager);
- remover.execute();
- manager.process(bp);
- remover.execute();
- assertTrue(manager.getManagedIds().size() == 1);
- remover.setMaxAcceptedAge(1000);
- Thread.sleep(500);
- remover.execute();
- assertTrue(manager.getManagedIds().size() == 1);
- Thread.sleep(510);
- remover.execute();
- assertTrue(manager.getManagedIds().size() == 0);
- }
-
- @Test
- public void testMe2() throws InterruptedException, MalformedURLException {
- BindingProcessorManager manager = new BindingProcessorManagerImpl(new DummyStalFactory(),
- new SLCommandInvokerImpl());
- BindingProcessor bp = manager.createBindingProcessor("http://www.iaik.at", null);
- ExpiryRemover remover = new ExpiryRemover();
- remover.setBindingProcessorManager(manager);
- remover.execute();
- manager.process(bp);
- remover.execute();
- assertTrue(manager.getManagedIds().size() == 1);
- remover.setMaxAcceptedAge(1000);
- Thread.sleep(500);
- remover.execute();
- assertTrue(manager.getManagedIds().size() == 1);
- bp.updateLastAccessTime();
- Thread.sleep(510);
- remover.execute();
- assertTrue(manager.getManagedIds().size() == 1);
- }
-
-}
+import org.junit.Ignore;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class ExpiryRemoverTest {
+
+ @Test
+ @Ignore
+ public void testMe() throws InterruptedException, MalformedURLException {
+ BindingProcessorManager manager = new BindingProcessorManagerImpl(new DummyStalFactory(),
+ new SLCommandInvokerImpl());
+ BindingProcessor bp = manager.createBindingProcessor("http://www.at", null);
+ ExpiryRemover remover = new ExpiryRemover();
+ remover.setBindingProcessorManager(manager);
+ remover.execute();
+ manager.process(bp);
+ remover.execute();
+ assertTrue(manager.getManagedIds().size() == 1);
+ remover.setMaxAcceptedAge(1000);
+ Thread.sleep(500);
+ remover.execute();
+ assertTrue(manager.getManagedIds().size() == 1);
+ Thread.sleep(510);
+ remover.execute();
+ assertTrue(manager.getManagedIds().size() == 0);
+ }
+
+ @Test
+ @Ignore
+ public void testMe2() throws InterruptedException, MalformedURLException {
+ BindingProcessorManager manager = new BindingProcessorManagerImpl(new DummyStalFactory(),
+ new SLCommandInvokerImpl());
+ BindingProcessor bp = manager.createBindingProcessor("http://www.iaik.at", null);
+ ExpiryRemover remover = new ExpiryRemover();
+ remover.setBindingProcessorManager(manager);
+ remover.execute();
+ manager.process(bp);
+ remover.execute();
+ assertTrue(manager.getManagedIds().size() == 1);
+ remover.setMaxAcceptedAge(1000);
+ Thread.sleep(500);
+ remover.execute();
+ assertTrue(manager.getManagedIds().size() == 1);
+ bp.updateLastAccessTime();
+ Thread.sleep(510);
+ remover.execute();
+ assertTrue(manager.getManagedIds().size() == 1);
+ }
+
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java
index 01b9155b..06e4a018 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java
@@ -28,6 +28,7 @@
//
package at.gv.egiz.smcc;
+import at.gv.egiz.smcc.ccid.CCID;
import at.gv.egiz.smcc.util.SMCCHelper;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
@@ -41,7 +42,7 @@ import javax.smartcardio.ResponseAPDU;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
+public class ACOSCard extends AbstractSignatureCard {
private static Log log = LogFactory.getLog(ACOSCard.class);
@@ -180,22 +181,23 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
//new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("inf.pin.name"));
int retries = -1;
- char[] pin = null;
- boolean pinRequiered = false;
+ boolean pinRequired = false;
do {
- if (pinRequiered) {
- pin = provider.providePIN(spec, retries);
- }
try {
getCard().beginExclusive();
- return readTLVFile(AID_DEC, EF_INFOBOX, pin, KID_PIN_INF, EF_INFOBOX_MAX_SIZE);
+ if (pinRequired) {
+ char[] pin = provider.providePIN(spec, retries);
+ return readTLVFile(AID_DEC, EF_INFOBOX, pin, spec.getKID(), EF_INFOBOX_MAX_SIZE);
+ } else {
+ return readTLVFile(AID_DEC, EF_INFOBOX, EF_INFOBOX_MAX_SIZE);
+ }
} catch (FileNotFoundException e) {
throw new NotActivatedException();
} catch (SecurityStatusNotSatisfiedException e) {
- pinRequiered = true;
+ pinRequired = true;
} catch (VerificationFailedException e) {
- pinRequiered = true;
+ pinRequired = true;
retries = e.getRetries();
} finally {
getCard().endExclusive();
@@ -402,10 +404,10 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException {
try {
byte[] sw;
- if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) {
+ if (reader.hasFeature(CCID.FEATURE_VERIFY_PIN_DIRECT)) {
log.debug("verify PIN on IFD");
- sw = transmitControlCommand(
- ifdCtrlCmds.get(FEATURE_VERIFY_PIN_DIRECT),
+ sw = reader.transmitControlCommand(
+ CCID.FEATURE_VERIFY_PIN_DIRECT,
getPINVerifyStructure(kid));
// int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff;
} else {
@@ -466,10 +468,10 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException {
try {
byte[] sw;
- if (ifdSupportsFeature(FEATURE_MODIFY_PIN_DIRECT)) {
+ if (reader.hasFeature(CCID.FEATURE_MODIFY_PIN_DIRECT)) {
log.debug("modify PIN on IFD");
- sw = transmitControlCommand(
- ifdCtrlCmds.get(FEATURE_MODIFY_PIN_DIRECT),
+ sw = reader.transmitControlCommand(
+ CCID.FEATURE_MODIFY_PIN_DIRECT,
getPINModifyStructure(kid));
// int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff;
} else {
@@ -543,34 +545,37 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
}
private byte[] getPINVerifyStructure(byte kid) {
-
- byte bTimeOut = (byte) 00; // Default time out
- byte bTimeOut2 = (byte) 00; // Default time out
- byte bmFormatString = (byte) 0x82; // 1 0001 0 01
+
+ byte bTimeOut = reader.getbTimeOut();
+ byte bTimeOut2 = reader.getbTimeOut2();
+ byte bmFormatString = (byte) 0x82; // 1 0000 0 10
// ^------------ System unit = byte
// ^^^^------- PIN position in the frame = 1 byte
// ^----- PIN justification left
- // ^^-- BCD format
- // 1 0000 0 10
// ^^-- ASCII format
- byte bmPINBlockString = (byte) 0x08; // 0100 0111
- // ^^^^--------- PIN length size: 4 bits
- // ^^^^---- Length PIN = 7 bytes
- byte bmPINLengthFormat = (byte) 0x04; // 000 0 0100
+ byte bmPINBlockString = (byte) 0x08; // 0000 1000
+ // ^^^^--------- PIN length size: 0 bits
+ // ^^^^---- Length PIN = 8 bytes
+ byte bmPINLengthFormat = (byte) 0x00; // 000 0 0000
// ^-------- System bit units is bit
- // ^^^^--- PIN length is at the 4th position bit
- byte wPINMaxExtraDigitL = (byte) 0x04; // Max=4 digits
- byte wPINMaxExtraDigitH = (byte) 0x04; // Min=4 digits
- byte bEntryValidationCondition = 0x02; // Max size reach or Validation key pressed
+ // ^^^^--- no PIN length
+ byte wPINMaxExtraDigitL =
+ (reader.getwPINMaxExtraDigitL() < (byte) 0x08) ?
+ reader.getwPINMaxExtraDigitL() : (byte) 0x08;
+ byte wPINMaxExtraDigitH =
+ (reader.getwPINMaxExtraDigitH() > (byte) 0x00) ?
+ reader.getwPINMaxExtraDigitH() : (byte) 0x00;
+ byte bEntryValidationCondition =
+ reader.getbEntryValidationCondition();
byte bNumberMessage = (byte) 0x00; // No message
- byte wLangIdL = (byte) 0x0C; // - English?
- byte wLangIdH = (byte) 0x04; // \
- byte bMsgIndex = (byte) 0x00; // Default Msg
+ byte wLangIdL = (byte) 0x0C;
+ byte wLangIdH = (byte) 0x04;
+ byte bMsgIndex = (byte) 0x00;
byte[] apdu = new byte[] {
- (byte) 0x00, (byte) 0x20, (byte) 0x00, kid, (byte) 0x08, // CLA INS P1 P2 LC
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // Data
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 // Data
+ (byte) 0x00, (byte) 0x20, (byte) 0x00, kid, (byte) 0x08,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
};
int offset = 0;
@@ -603,40 +608,43 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
public byte[] getPINModifyStructure(byte kid) {
- byte bTimeOut = (byte) 00; // Default time out
- byte bTimeOut2 = (byte) 00; // Default time out
- byte bmFormatString = (byte) 0x82; // 1 0001 0 01
+ byte bTimeOut = reader.getbTimeOut();
+ byte bTimeOut2 = reader.getbTimeOut2();
+ byte bmFormatString = (byte) 0x82; // 1 0000 0 10
// ^------------ System unit = byte
// ^^^^------- PIN position in the frame = 1 byte
// ^----- PIN justification left
- // ^^-- BCD format
- // 1 0000 0 10
// ^^-- ASCII format
- byte bmPINBlockString = (byte) 0x08; // 0100 0111
- // ^^^^--------- PIN length size: 4 bits
- // ^^^^---- Length PIN = 7 bytes
- byte bmPINLengthFormat = (byte) 0x00; // 000 0 0100
+ byte bmPINBlockString = (byte) 0x08; // 0000 1000
+ // ^^^^--------- PIN length size: 0 bits
+ // ^^^^---- Length PIN = 8 bytes
+ byte bmPINLengthFormat = (byte) 0x00; // 000 0 0000
// ^-------- System bit units is bit
- // ^^^^--- PIN length is at the 4th position bit
+ // ^^^^--- no PIN length
byte bInsertionOffsetOld = (byte) 0x00; // insertion position offset in bytes
- byte bInsertionOffsetNew = (byte) 0x00; // insertion position offset in bytes
- byte wPINMaxExtraDigitL = (byte) 0x04; // Min=4 digits
- byte wPINMaxExtraDigitH = (byte) 0x04; // Max=12 digits
- byte bConfirmPIN = (byte) 0x00; // ??? need for confirm pin
- byte bEntryValidationCondition = 0x02; // Max size reach or Validation key pressed
- byte bNumberMessage = (byte) 0x00; // No message
- byte wLangIdL = (byte) 0x0C; // - English?
- byte wLangIdH = (byte) 0x04; // \
- byte bMsgIndex1 = (byte) 0x00; // Default Msg
- byte bMsgIndex2 = (byte) 0x00; // Default Msg
- byte bMsgIndex3 = (byte) 0x00; // Default Msg
+ byte bInsertionOffsetNew = (byte) 0x08;
+ byte wPINMaxExtraDigitL =
+ (reader.getwPINMaxExtraDigitL() < (byte) 0x08) ?
+ reader.getwPINMaxExtraDigitL() : (byte) 0x08;
+ byte wPINMaxExtraDigitH =
+ (reader.getwPINMaxExtraDigitH() > (byte) 0x00) ?
+ reader.getwPINMaxExtraDigitH() : (byte) 0x00;
+ byte bConfirmPIN = (byte) 0x03;
+ byte bEntryValidationCondition =
+ reader.getbEntryValidationCondition();
+ byte bNumberMessage = (byte) 0x03;
+ byte wLangIdL = (byte) 0x0C;
+ byte wLangIdH = (byte) 0x04;
+ byte bMsgIndex1 = (byte) 0x00;
+ byte bMsgIndex2 = (byte) 0x01;
+ byte bMsgIndex3 = (byte) 0x02;
byte[] apdu = new byte[] {
- (byte) 0x00, (byte) 0x24, (byte) 0x00, kid, (byte) 0x10, // CLA INS P1 P2 LC
- (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, // Data
- (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, // ...
- (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, // Data
- (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff // ...
+ (byte) 0x00, (byte) 0x24, (byte) 0x00, kid, (byte) 0x10,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
};
int offset = 0;
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java
index 6587aaf9..47c27369 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java
@@ -28,6 +28,9 @@
//
package at.gv.egiz.smcc;
+import at.gv.egiz.smcc.ccid.CCID;
+import at.gv.egiz.smcc.ccid.DefaultReader;
+import at.gv.egiz.smcc.ccid.ReaderFactory;
import at.gv.egiz.smcc.util.SMCCHelper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -39,6 +42,8 @@ import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import javax.smartcardio.ATR;
import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
@@ -54,14 +59,6 @@ public abstract class AbstractSignatureCard implements SignatureCard {
private static Log log = LogFactory.getLog(AbstractSignatureCard.class);
- static final short GET_FEATURE_REQUEST = 3400;
-
- private static int getCtrlCode(short function) {
- return 0x310000 | ((0xFFFF & function) << 2);
- }
-
- protected Map<Byte, Long> ifdCtrlCmds;
-
protected List<PINSpec> pinSpecs = new ArrayList<PINSpec>();
private ResourceBundle i18n;
@@ -76,7 +73,8 @@ public abstract class AbstractSignatureCard implements SignatureCard {
/**
* The card terminal that connects the {@link #card_}.
*/
- private CardTerminal cardTerminal;
+// private CardTerminal cardTerminal;
+ protected CCID reader;
protected AbstractSignatureCard(String resourceBundleName) {
this.resourceBundleName = resourceBundleName;
@@ -341,16 +339,34 @@ public abstract class AbstractSignatureCard implements SignatureCard {
*/
protected byte[] readTLVFile(byte[] aid, byte[] ef, int maxLength)
throws SignatureCardException, InterruptedException, CardException {
- return readTLVFile(aid, ef, null, (byte) 0, maxLength);
+ // SELECT FILE (AID)
+ selectFileAID(aid);
+
+ // SELECT FILE (EF)
+ ResponseAPDU resp = selectFileFID(ef);
+ if (resp.getSW() == 0x6a82) {
+ // EF not found
+ throw new FileNotFoundException("EF " + toString(ef) + " not found.");
+ } else if (resp.getSW() != 0x9000) {
+ throw new SignatureCardException("SELECT FILE with "
+ + "FID="
+ + toString(ef)
+ + " failed ("
+ + "SW="
+ + Integer.toHexString(resp.getSW()) + ").");
+ }
+
+ return readBinaryTLV(maxLength, (byte) 0x30);
+// return readTLVFile(aid, ef, null, (byte) 0, maxLength);
}
/**
- * Read the content of a TLV file wich may require a PIN.
+ * Read the content of a TLV file wich requires a PIN.
*
* @param aid the application ID (AID)
* @param ef the elementary file (EF)
* @param kid the key ID (KID) of the corresponding PIN
- * @param provider the PINProvider
+ * @param pin the pin or null if VERIFY on pinpad
* @param spec the PINSpec
* @param maxLength the maximum length of the file
*
@@ -381,12 +397,10 @@ public abstract class AbstractSignatureCard implements SignatureCard {
}
// VERIFY
- if (pin != null) {
int retries = verifyPIN(kid, pin);
if (retries != -1) {
throw new VerificationFailedException(retries);
}
- }
return readBinaryTLV(maxLength, (byte) 0x30);
@@ -443,16 +457,16 @@ public abstract class AbstractSignatureCard implements SignatureCard {
}
+ @Override
public void init(Card card, CardTerminal cardTerminal) {
- card_ = card;
- this.cardTerminal = cardTerminal;
+ this.card_ = card;
+ this.reader = ReaderFactory.getReader(card, cardTerminal);
ATR atr = card.getATR();
byte[] atrBytes = atr.getBytes();
if (atrBytes.length >= 6) {
ifs_ = 0xFF & atr.getBytes()[6];
log.trace("Setting IFS (information field size) to " + ifs_);
}
- ifdCtrlCmds = queryIFDFeatures();
}
@Override
@@ -465,6 +479,11 @@ public abstract class AbstractSignatureCard implements SignatureCard {
}
@Override
+ public CCID getReader() {
+ return reader;
+ }
+
+ @Override
public void setLocale(Locale locale) {
if (locale == null) {
throw new NullPointerException("Locale must not be set to null");
@@ -497,9 +516,7 @@ public abstract class AbstractSignatureCard implements SignatureCard {
log.debug("Disconnect and reset smart card.");
card_.disconnect(true);
log.debug("Reconnect smart card.");
- if (cardTerminal != null) {
- card_ = cardTerminal.connect("*");
- }
+ card_ = reader.connect();
} catch (CardException e) {
throw new SignatureCardException("Failed to reset card.", e);
}
@@ -520,6 +537,7 @@ public abstract class AbstractSignatureCard implements SignatureCard {
selectFileAID(pinSpec.getContextAID());
}
+ // -1 if ok or unknown
int retries = verifyPIN(pinSpec.getKID());
do {
char[] pin = pinProvider.providePIN(pinSpec, retries);
@@ -611,166 +629,4 @@ public abstract class AbstractSignatureCard implements SignatureCard {
throws CancelledException, SignatureCardException, InterruptedException {
throw new SignatureCardException("Unblock not supported yet");
}
-
- /////////////////////////////////////////////////////////////////////////////
- // IFD related code
- /////////////////////////////////////////////////////////////////////////////
-
- /**
- * TODO implement VERIFY_PIN_START/FINISH (feature 0x01/0x02)
- * @return
- */
- @Override
- public boolean ifdSupportsFeature(byte feature) {
- if (ifdCtrlCmds != null) {
- return ifdCtrlCmds.containsKey(feature);
- }
- return false;
- }
-
- protected Map<Byte, Long> queryIFDFeatures() {
-
- if (card_ == null) {
- throw new NullPointerException("Need connected smart card to query IFD features");
- }
-
- Map<Byte, Long> ifdFeatures = new HashMap<Byte, Long>();
-
- try {
- if (log.isTraceEnabled()) {
- log.trace("GET_FEATURE_REQUEST CtrlCode " + Integer.toHexString(getCtrlCode(GET_FEATURE_REQUEST)));
- }
- byte[] resp = card_.transmitControlCommand(getCtrlCode(GET_FEATURE_REQUEST), new byte[]{});
-
- if (log.isTraceEnabled()) {
- log.trace("GET_FEATURE_REQUEST Response " + SMCCHelper.toString(resp));
- }
-
- for (int i = 0; i + 5 < resp.length; i += 6) {
- Byte feature = new Byte(resp[i]);
- Long ctrlCode = new Long(
- ((0xFF & resp[i + 2]) << 24) |
- ((0xFF & resp[i + 3]) << 16) |
- ((0xFF & resp[i + 4]) << 8) |
- (0xFF & resp[i + 5]));
- if (log.isInfoEnabled()) {
- log.info("IFD supports feature " + Integer.toHexString(feature.byteValue()) +
- ": " + Long.toHexString(ctrlCode.longValue()));
- }
- ifdFeatures.put(feature, ctrlCode);
- }
-
- } catch (CardException ex) {
- log.debug("Failed to query IFD features: " + ex.getMessage());
- log.trace(ex);
- log.info("IFD does not support PINPad");
- return null;
- }
- return ifdFeatures;
- }
-
-
- protected byte ifdGetKeyPressed() throws CardException {
- if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) {
-
- Long controlCode = (Long) ifdCtrlCmds.get(new Byte((byte) 0x05));
-
- byte key = 0x00;
- while (key == 0x00) {
-
- byte[] resp = card_.transmitControlCommand(controlCode.intValue(), new byte[] {});
-
- if (resp != null && resp.length > 0) {
- key = resp[0];
- }
- }
-
- System.out.println("Key: " + key);
-
- }
-
- return 0x00;
- }
-
- protected byte[] ifdVerifyPINFinish() throws CardException {
- if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) {
-
- Long controlCode = (Long) ifdCtrlCmds.get(new Byte((byte) 0x02));
-
- byte[] resp = card_.transmitControlCommand(controlCode.intValue(), new byte[] {});
-
- System.out.println("CommandResp: " + toString(resp));
-
- return resp;
-
- }
-
- return null;
- }
-
-
- /**
- * assumes ifdSupportsVerifyPIN() == true
- * @param pinVerifyStructure
- * @return
- * @throws javax.smartcardio.CardException
- */
-// protected byte[] ifdVerifyPIN(byte[] pinVerifyStructure) throws CardException {
-//
-//// Long ctrlCode = (Long) ifdFeatures.get(FEATURE_IFD_PIN_PROPERTIES);
-//// if (ctrlCode != null) {
-//// if (log.isTraceEnabled()) {
-//// log.trace("PIN_PROPERTIES CtrlCode " + Integer.toHexString(ctrlCode.intValue()));
-//// }
-//// byte[] resp = card_.transmitControlCommand(ctrlCode.intValue(), new byte[] {});
-////
-//// if (log.isTraceEnabled()) {
-//// log.trace("PIN_PROPERTIES Response " + SMCCHelper.toString(resp));
-//// }
-//// }
-//
-//
-// Long ctrlCode = (Long) ifdFeatures.get(FEATURE_VERIFY_PIN_DIRECT);
-// if (ctrlCode == null) {
-// throw new NullPointerException("no CtrlCode for FEATURE_VERIFY_PIN_DIRECT");
-// }
-//
-// if (log.isTraceEnabled()) {
-// log.trace("VERIFY_PIN_DIRECT CtrlCode " + Integer.toHexString(ctrlCode.intValue()) +
-// ", PIN_VERIFY_STRUCTURE " + SMCCHelper.toString(pinVerifyStructure));
-// }
-// byte[] resp = card_.transmitControlCommand(ctrlCode.intValue(), pinVerifyStructure);
-//
-// if (log.isTraceEnabled()) {
-// log.trace("VERIFY_PIN_DIRECT Response " + SMCCHelper.toString(resp));
-// }
-// return resp;
-// }
-
-// protected Long getControlCode(Byte feature) {
-// if (ifdFeatures != null) {
-// return ifdFeatures.get(feature);
-// }
-// return null;
-// }
-
- protected byte[] transmitControlCommand(Long ctrlCode, byte[] ctrlCommand)
- throws CardException {
-// Long ctrlCode = (Long) ifdFeatures.get(feature);
- if (ctrlCode == null) {
- throw new NullPointerException("ControlCode " +
- Integer.toHexString(ctrlCode.intValue()) + " not supported");
- }
- if (log.isTraceEnabled()) {
- log.trace("CtrlCommand (" + Integer.toHexString(ctrlCode.intValue()) +
- ") " + SMCCHelper.toString(ctrlCommand));
- }
- byte[] resp = card_.transmitControlCommand(ctrlCode.intValue(), ctrlCommand);
-
- if (log.isTraceEnabled()) {
- log.trace("CtrlCommand Response " + SMCCHelper.toString(resp));
- }
- return resp;
- }
-
}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
index 91245c50..bc6a2316 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
@@ -28,6 +28,7 @@
//
package at.gv.egiz.smcc;
+import at.gv.egiz.smcc.ccid.DefaultReader;
import at.gv.egiz.smcc.util.SMCCHelper;
import java.util.Arrays;
import javax.smartcardio.CardChannel;
@@ -38,7 +39,7 @@ import javax.smartcardio.ResponseAPDU;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-public class STARCOSCard extends AbstractSignatureCard implements SignatureCard {
+public class STARCOSCard extends AbstractSignatureCard {
/**
* Logging facility.
@@ -153,8 +154,8 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
public static final byte KID_PIN_CARD = (byte) 0x01;
- private static final int PINSPEC_CARD = 0;
- private static final int PINSPEC_SS = 1;
+ public static final int PINSPEC_CARD = 0;
+ public static final int PINSPEC_SS = 1;
/**
* Creates an new instance.
@@ -217,28 +218,29 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
try {
if ("IdentityLink".equals(infobox)) {
-
+
PINSpec spec = pinSpecs.get(PINSPEC_CARD);
//new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name"));
-
+
int retries = -1;
- char[] pin = null;
- boolean pinRequiered = false;
+ boolean pinRequired = false;
do {
- if (pinRequiered) {
- pin = provider.providePIN(spec, retries);
- }
try {
getCard().beginExclusive();
- return readTLVFile(AID_INFOBOX, EF_INFOBOX, pin, KID_PIN_CARD, 2000);
+ if (pinRequired) {
+ char[] pin = provider.providePIN(spec, retries);
+ return readTLVFile(AID_INFOBOX, EF_INFOBOX, pin, spec.getKID(), 2000);
+ } else {
+ return readTLVFile(AID_INFOBOX, EF_INFOBOX, 2000);
+ }
} catch (FileNotFoundException e) {
throw new NotActivatedException();
} catch (SecurityStatusNotSatisfiedException e) {
- pinRequiered = true;
+ pinRequired = true;
retries = verifyPIN(KID_PIN_CARD);
} catch (VerificationFailedException e) {
- pinRequiered = true;
+ pinRequired = true;
retries = e.getRetries();
} finally {
getCard().endExclusive();
@@ -246,54 +248,43 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
} while (retries != 0);
throw new LockedException();
-
} else if ("EHIC".equals(infobox)) {
-
try {
getCard().beginExclusive();
return readTLVFile(AID_SV_PERSONENDATEN, FID_EHIC, 126);
} finally {
getCard().endExclusive();
}
-
} else if ("Grunddaten".equals(infobox)) {
-
try {
getCard().beginExclusive();
return readTLVFile(AID_SV_PERSONENDATEN, FID_GRUNDDATEN, 550);
} finally {
getCard().endExclusive();
}
-
} else if ("SV-Personenbindung".equals(infobox)) {
-
try {
getCard().beginExclusive();
return readTLVFile(AID_SV_PERSONENDATEN, FID_SV_PERSONENBINDUNG, 500);
} finally {
getCard().endExclusive();
}
-
} else if ("Status".equals(infobox)) {
-
try {
getCard().beginExclusive();
return readRecords(AID_SV_PERSONENDATEN, FID_STATUS, 1, 5);
} finally {
getCard().endExclusive();
}
-
} else {
throw new IllegalArgumentException("Infobox '" + infobox
+ "' not supported.");
}
-
} catch (CardException e) {
log.warn(e);
throw new SignatureCardException("Failed to access card.", e);
}
-
}
@Override
@@ -466,10 +457,10 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
throws LockedException, NotActivatedException, SignatureCardException {
try {
byte[] sw;
- if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) {
+ if (reader.hasFeature(DefaultReader.FEATURE_VERIFY_PIN_DIRECT)) {
log.debug("verify PIN on IFD");
- sw = transmitControlCommand(
- ifdCtrlCmds.get(FEATURE_VERIFY_PIN_DIRECT),
+ sw = reader.transmitControlCommand(
+ DefaultReader.FEATURE_VERIFY_PIN_DIRECT,
getPINVerifyStructure(kid));
// int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff;
} else {
@@ -551,10 +542,10 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException {
try {
byte[] sw;
- if (ifdSupportsFeature(FEATURE_MODIFY_PIN_DIRECT)) {
+ if (reader.hasFeature(DefaultReader.FEATURE_MODIFY_PIN_DIRECT)) {
log.debug("modify PIN on IFD");
- sw = transmitControlCommand(
- ifdCtrlCmds.get(FEATURE_MODIFY_PIN_DIRECT),
+ sw = reader.transmitControlCommand(
+ DefaultReader.FEATURE_MODIFY_PIN_DIRECT,
getPINModifyStructure(kid));
// int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff;
} else {
@@ -606,31 +597,43 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
protected void activatePIN(byte kid, char[] pin)
throws CancelledException, TimeoutException, SignatureCardException {
try {
- CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel,
- new CommandAPDU(0x00, 0x24, 0x01, kid, encodePINBlock(pin)), false);
+ byte[] sw;
+ if (reader.hasFeature(DefaultReader.FEATURE_MODIFY_PIN_DIRECT)) {
+ log.debug("activate PIN on IFD");
+ sw = reader.transmitControlCommand(
+ DefaultReader.FEATURE_MODIFY_PIN_DIRECT,
+ getActivatePINModifyStructure(kid));
+// int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff;
+ } else {
+ CardChannel channel = getCardChannel();
+ ResponseAPDU resp = transmit(channel,
+ new CommandAPDU(0x00, 0x24, 0x01, kid, encodePINBlock(pin)), false);
- log.trace("activate pin returned SW=" + Integer.toHexString(resp.getSW()));
+ sw = new byte[2];
+ sw[0] = (byte) resp.getSW1();
+ sw[1] = (byte) resp.getSW2();
+ log.trace("activate pin returned SW=" + Integer.toHexString(resp.getSW()));
+ }
- if (resp.getSW1() == 0x9000) {
+ if (sw[0] == (byte) 0x90 && sw[1] == (byte) 0x00) {
return;
- } else if (resp.getSW() == 0x6983) {
+ } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x83) {
//Authentisierungsmethode gesperrt
throw new LockedException("[69:83]");
- } else if (resp.getSW() == 0x6984) {
- //referenzierte Daten sind reversibel gesperrt (invalidated)
- throw new NotActivatedException("[69:84]");
- } else if (resp.getSW() == 0x6985) {
- //Benutzungsbedingungen nicht erfüllt
- throw new NotActivatedException("[69:85]");
- } else if (resp.getSW() == 0x6400) {
+// } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x84) {
+// //referenzierte Daten sind reversibel gesperrt (invalidated)
+// throw new NotActivatedException("[69:84]");
+// } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x85) {
+// //Benutzungsbedingungen nicht erfüllt
+// throw new NotActivatedException("[69:85]");
+ } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x00) {
throw new TimeoutException("[64:00]");
- } else if (resp.getSW() == 0x6401) {
+ } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) {
throw new CancelledException("[64:01]");
}
- log.error("Failed to activate pin: SW=" +
- Integer.toHexString(resp.getSW()));
- throw new SignatureCardException("[" + Integer.toHexString(resp.getSW()) + "]");
+ log.error("Failed to activate pin: SW="
+ + SMCCHelper.toString(sw));
+ throw new SignatureCardException(SMCCHelper.toString(sw));
} catch (CardException ex) {
log.error("smart card communication failed: " + ex.getMessage());
@@ -667,9 +670,8 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
}
private byte[] getPINVerifyStructure(byte kid) {
-
- byte bTimeOut = (byte) 00; // Default time out
- byte bTimeOut2 = (byte) 00; // Default time out
+ byte bTimeOut = reader.getbTimeOut();
+ byte bTimeOut2 = reader.getbTimeOut2(); // time out after first entry
byte bmFormatString = (byte) 0x89; // 1 0001 0 01
// ^------------ System unit = byte
// ^^^^------- PIN position in the frame = 1 byte
@@ -681,9 +683,14 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
byte bmPINLengthFormat = (byte) 0x04; // 000 0 0100
// ^-------- System bit units is bit
// ^^^^--- PIN length is at the 4th position bit
- byte wPINMaxExtraDigitL = (byte) 0x04; // Max=4 digits
- byte wPINMaxExtraDigitH = (byte) 0x04; // Min=4 digits
- byte bEntryValidationCondition = 0x02; // Max size reach or Validation key pressed
+ byte wPINMaxExtraDigitL = // Max=12 digits (Gemplus support max 8)
+ (reader.getwPINMaxExtraDigitL() < (byte) 0x12) ?
+ reader.getwPINMaxExtraDigitL() : (byte) 0x12;
+ byte wPINMaxExtraDigitH = // Min=4/6 digits TODO card/ss pin (min: 4/6)
+ (reader.getwPINMaxExtraDigitH() > (byte) 0x04) ?
+ reader.getwPINMaxExtraDigitH() : (byte) 0x04;
+ byte bEntryValidationCondition =
+ reader.getbEntryValidationCondition();
byte bNumberMessage = (byte) 0x00; // No message
byte wLangIdL = (byte) 0x0C; // - English?
byte wLangIdH = (byte) 0x04; // \
@@ -725,38 +732,99 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
private byte[] getPINModifyStructure(byte kid) {
- byte bTimeOut = (byte) 00; // Default time out
- byte bTimeOut2 = (byte) 00; // Default time out
- byte bmFormatString = (byte) 0x89; // 1 0001 0 01
- // ^------------ System unit = byte
- // ^^^^------- PIN position in the frame = 1 byte
- // ^----- PIN justification left
- // ^^-- BCD format
- byte bmPINBlockString = (byte) 0x47; // 0100 0111
- // ^^^^--------- PIN length size: 4 bits
- // ^^^^---- Length PIN = 7 bytes
- byte bmPINLengthFormat = (byte) 0x04; // 000 0 0100
- // ^-------- System bit units is bit
- // ^^^^--- PIN length is at the 4th position bit
- byte bInsertionOffsetOld = (byte) 0x01; // insertion position offset in bytes
- byte bInsertionOffsetNew = (byte) 0x08; // insertion position offset in bytes
- byte wPINMaxExtraDigitL = (byte) 0x04; // Min=4 digits
- byte wPINMaxExtraDigitH = (byte) 0x04; // Max=12 digits
- byte bConfirmPIN = (byte) 0x00; // ??? need for confirm pin
- byte bEntryValidationCondition = 0x02; // Max size reach or Validation key pressed
- byte bNumberMessage = (byte) 0x00; // No message
- byte wLangIdL = (byte) 0x0C; // - English?
- byte wLangIdH = (byte) 0x04; // \
- byte bMsgIndex1 = (byte) 0x00; // Default Msg
- byte bMsgIndex2 = (byte) 0x00; // Default Msg
- byte bMsgIndex3 = (byte) 0x00; // Default Msg
+ byte bTimeOut = reader.getbTimeOut(); // s.o.
+ byte bTimeOut2 = reader.getbTimeOut2(); // s.o.
+ byte bmFormatString = (byte) 0x89; // s.o.
+ byte bmPINBlockString = (byte) 0x47; // s.o.
+ byte bmPINLengthFormat = (byte) 0x04; // s.o.
+ byte bInsertionOffsetOld = (byte) 0x00; // insertion position offset in bytes
+ byte bInsertionOffsetNew = (byte) 0x08; // (add 1 from bmFormatString b3)
+ byte wPINMaxExtraDigitL =
+ (reader.getwPINMaxExtraDigitL() < (byte) 0x12) ?
+ reader.getwPINMaxExtraDigitL() : (byte) 0x12;
+ byte wPINMaxExtraDigitH = // Min=4/6 digits TODO card/ss pin (min: 4/6)
+ (reader.getwPINMaxExtraDigitH() > (byte) 0x04) ?
+ reader.getwPINMaxExtraDigitH() : (byte) 0x04;
+ byte bConfirmPIN = (byte) 0x03; // current pin entry + confirmation
+ byte bEntryValidationCondition =
+ reader.getbEntryValidationCondition();
+ byte bNumberMessage = (byte) 0x03; // 3 messages
+ byte wLangIdL = (byte) 0x0C;
+ byte wLangIdH = (byte) 0x04;
+ byte bMsgIndex1 = (byte) 0x00; // insertion
+ byte bMsgIndex2 = (byte) 0x01; // modification
+ byte bMsgIndex3 = (byte) 0x02; // confirmation
byte[] apdu = new byte[] {
- (byte) 0x00, (byte) 0x24, (byte) 0x00, kid, (byte) 0x10, // CLA INS P1 P2 LC
- (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, // Data
- (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, // ...
- (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, // Data
- (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff // ...
+ (byte) 0x00, (byte) 0x24, (byte) 0x00, kid, (byte) 0x10,
+ (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff
+ };
+
+ int offset = 0;
+ byte[] pinModifyStructure = new byte[offset + 24 + apdu.length];
+ pinModifyStructure[offset++] = bTimeOut;
+ pinModifyStructure[offset++] = bTimeOut2;
+ pinModifyStructure[offset++] = bmFormatString;
+ pinModifyStructure[offset++] = bmPINBlockString;
+ pinModifyStructure[offset++] = bmPINLengthFormat;
+ pinModifyStructure[offset++] = bInsertionOffsetOld;
+ pinModifyStructure[offset++] = bInsertionOffsetNew;
+ pinModifyStructure[offset++] = wPINMaxExtraDigitL;
+ pinModifyStructure[offset++] = wPINMaxExtraDigitH;
+ pinModifyStructure[offset++] = bConfirmPIN;
+ pinModifyStructure[offset++] = bEntryValidationCondition;
+ pinModifyStructure[offset++] = bNumberMessage;
+ pinModifyStructure[offset++] = wLangIdL;
+ pinModifyStructure[offset++] = wLangIdH;
+ pinModifyStructure[offset++] = bMsgIndex1;
+ pinModifyStructure[offset++] = bMsgIndex2;
+ pinModifyStructure[offset++] = bMsgIndex3;
+
+ pinModifyStructure[offset++] = 0x00;
+ pinModifyStructure[offset++] = 0x00;
+ pinModifyStructure[offset++] = 0x00;
+
+ pinModifyStructure[offset++] = (byte) apdu.length;
+ pinModifyStructure[offset++] = 0x00;
+ pinModifyStructure[offset++] = 0x00;
+ pinModifyStructure[offset++] = 0x00;
+ System.arraycopy(apdu, 0, pinModifyStructure, offset, apdu.length);
+
+// log.debug("PIN MODIFY " + SMCCHelper.toString(pinModifyStructure));
+ return pinModifyStructure;
+ }
+ private byte[] getActivatePINModifyStructure(byte kid) {
+
+ byte bTimeOut = reader.getbTimeOut();
+ byte bTimeOut2 = reader.getbTimeOut2();
+ byte bmFormatString = (byte) 0x89;
+ byte bmPINBlockString = (byte) 0x47;
+ byte bmPINLengthFormat = (byte) 0x04;
+ byte bInsertionOffsetOld = (byte) 0x00; // ignored
+ byte bInsertionOffsetNew = (byte) 0x00;
+ byte wPINMaxExtraDigitL =
+ (reader.getwPINMaxExtraDigitL() < (byte) 0x12) ?
+ reader.getwPINMaxExtraDigitL() : (byte) 0x12;
+ byte wPINMaxExtraDigitH = // Min=4/6 digits TODO card/ss pin (min: 4/6)
+ (reader.getwPINMaxExtraDigitH() > (byte) 0x04) ?
+ reader.getwPINMaxExtraDigitH() : (byte) 0x04;
+ byte bConfirmPIN = (byte) 0x01; // confirm, no current pin entry
+ byte bEntryValidationCondition =
+ reader.getbEntryValidationCondition();
+ byte bNumberMessage = (byte) 0x02; // 2 messages
+ byte wLangIdL = (byte) 0x0c;
+ byte wLangIdH = (byte) 0x04;
+ byte bMsgIndex1 = (byte) 0x01; // modification prompt
+ byte bMsgIndex2 = (byte) 0x02; // confirmation prompt
+ byte bMsgIndex3 = (byte) 0x00;
+
+ byte[] apdu = new byte[] {
+ (byte) 0x00, (byte) 0x24, (byte) 0x01, kid, (byte) 0x08,
+ (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff
};
int offset = 0;
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java
index 293b9c71..253ac7a0 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java
@@ -17,6 +17,7 @@
package at.gv.egiz.smcc;
+import at.gv.egiz.smcc.ccid.CCID;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -44,6 +45,7 @@ import java.util.Locale;
import java.util.Map;
import javax.smartcardio.Card;
+import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import org.apache.commons.logging.Log;
@@ -419,7 +421,50 @@ public class SWCard implements SignatureCard {
}
@Override
- public boolean ifdSupportsFeature(byte feature) {
- return false;
+ public CCID getReader() {
+ return new CCID() {
+
+ @Override
+ public boolean hasFeature(Byte feature) {
+ return false;
+ }
+
+ @Override
+ public byte[] transmitControlCommand(Byte feature, byte[] ctrlCommand)
+ throws SignatureCardException {
+ throw new SignatureCardException(CCID.FEATURES[feature.intValue()] +
+ " not supported");
+ }
+
+ @Override
+ public byte getbTimeOut() {
+ return 0;
+ }
+
+ @Override
+ public byte getbTimeOut2() {
+ return 0;
+ }
+
+ @Override
+ public byte getwPINMaxExtraDigitL() {
+ return 0x12;
+ }
+
+ @Override
+ public byte getwPINMaxExtraDigitH() {
+ return 0x00;
+ }
+
+ @Override
+ public byte getbEntryValidationCondition() {
+ return 0x02;
+ }
+
+ @Override
+ public Card connect() {
+ return null;
+ }
+ };
}
}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java
index 2097e6d3..ad530ad5 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java
@@ -28,6 +28,7 @@
//
package at.gv.egiz.smcc;
+import at.gv.egiz.smcc.ccid.CCID;
import java.util.List;
import java.util.Locale;
@@ -36,14 +37,6 @@ import javax.smartcardio.CardTerminal;
public interface SignatureCard {
- /**
- * IFD FEATURES
- */
- static final Byte FEATURE_VERIFY_PIN_DIRECT = new Byte((byte) 0x06);
- static final Byte FEATURE_MODIFY_PIN_DIRECT = new Byte((byte) 0x07);
- static final Byte FEATURE_MCT_READER_DIRECT = new Byte((byte) 0x08);
- static final Byte FEATURE_IFD_PIN_PROPERTIES = new Byte((byte) 0x0a);
-
public static class KeyboxName {
public static KeyboxName SECURE_SIGNATURE_KEYPAIR = new KeyboxName(
@@ -143,11 +136,7 @@ public interface SignatureCard {
public void unblockPIN(PINSpec pinSpec, PINProvider pukProvider)
throws CancelledException, SignatureCardException, InterruptedException;
- /**
- * TODO
- * @return
- */
- public boolean ifdSupportsFeature(byte feature);
+ public CCID getReader();
/**
* Sets the local for evtl. required callbacks (e.g. PINSpec)
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ccid/CCID.java b/smcc/src/main/java/at/gv/egiz/smcc/ccid/CCID.java
new file mode 100644
index 00000000..2c56ce98
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ccid/CCID.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package at.gv.egiz.smcc.ccid;
+
+import at.gv.egiz.smcc.*;
+import javax.smartcardio.Card;
+import javax.smartcardio.CardException;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public interface CCID {
+
+
+ String[] FEATURES = new String[]{"NO_FEATURE",
+ "FEATURE_VERIFY_PIN_START",
+ "FEATURE_VERIFY_PIN_FINISH",
+ "FEATURE_MODIFY_PIN_START",
+ "FEATURE_MODIFY_PIN_FINISH",
+ "FEATURE_GET_KEY_PRESSED",
+ "FEATURE_VERIFY_PIN_DIRECT",
+ "FEATURE_MODIFY_PIN_DIRECT",
+ "FEATURE_MCT_READER_DIRECT",
+ "FEATURE_MCT_UNIVERSAL",
+ "FEATURE_IFD_PIN_PROPERTIES",
+ "FEATURE_ABORT",
+ "FEATURE_SET_SPE_MESSAGE",
+ "FEATURE_VERIFY_PIN_DIRECT_APP_ID",
+ "FEATURE_MODIFY_PIN_DIRECT_APP_ID",
+ "FEATURE_WRITE_DISPLAY",
+ "FEATURE_GET_KEY",
+ "FEATURE_IFD_DISPLAY_PROPERTIES"};
+
+ Byte FEATURE_IFD_PIN_PROPERTIES = new Byte((byte) 10);
+ Byte FEATURE_MCT_READER_DIRECT = new Byte((byte) 8);
+ Byte FEATURE_MODIFY_PIN_DIRECT = new Byte((byte) 7);
+ Byte FEATURE_VERIFY_PIN_DIRECT = new Byte((byte) 6);
+
+ Card connect() throws CardException;
+
+ boolean hasFeature(Byte feature);
+
+ /**
+ *
+ * @param feature the corresponding control code will be transmitted
+ * @param ctrlCommand
+ * @return
+ * @throws at.gv.egiz.smcc.SignatureCardException if feature is not supported
+ * or card communication fails
+ */
+ byte[] transmitControlCommand(Byte feature, byte[] ctrlCommand) throws SignatureCardException;
+
+ /**
+ * allow subclasses to override default (deal with reader bugs)
+ * @return
+ */
+ byte getbTimeOut();
+ byte getbTimeOut2();
+ byte getwPINMaxExtraDigitL();
+ byte getwPINMaxExtraDigitH();
+ byte getbEntryValidationCondition();
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java b/smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java
new file mode 100644
index 00000000..2cc77dc9
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package at.gv.egiz.smcc.ccid;
+
+import at.gv.egiz.smcc.*;
+import at.gv.egiz.smcc.util.SMCCHelper;
+import java.util.HashMap;
+import java.util.Map;
+import javax.smartcardio.Card;
+import javax.smartcardio.CardException;
+import javax.smartcardio.CardTerminal;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class DefaultReader implements CCID {
+
+ protected final static Log log = LogFactory.getLog(DefaultReader.class);
+
+ private static int CTL_CODE(int code) {
+ return 0x42000000 + code;
+ }
+
+ int IOCTL_GET_FEATURE_REQUEST = CTL_CODE(3400);
+
+
+ protected Card icc;
+ protected CardTerminal ct;
+
+ /**
+ * supported features and respective control codes
+ */
+ protected Map<Byte, Integer> features;
+
+ public DefaultReader(Card icc, CardTerminal ct) {
+ if (icc == null || ct == null) {
+ throw new NullPointerException("no card or card terminal provided");
+ }
+ this.icc = icc;
+ this.ct = ct;
+ features = queryFeatures();
+ }
+
+ public Card connect() throws CardException { //SignatureCardException {
+// try {
+ icc = ct.connect("*");
+ return icc;
+// } catch (CardException ex) {
+// log.error(ex.getMessage(), ex);
+// throw new SignatureCardException("Failed to connect to card: " + ex.getMessage());
+// }
+ }
+
+ Map<Byte, Integer> queryFeatures() {
+ Map<Byte, Integer> features = new HashMap<Byte, Integer>();
+
+ if (icc == null) {
+ log.warn("invalid card handle, cannot query ifd features");
+ } else {
+ try {
+ if (log.isTraceEnabled()) {
+ log.trace("GET_FEATURE_REQUEST " +
+ Integer.toHexString(IOCTL_GET_FEATURE_REQUEST) +
+ " on " + ct.getName());
+ }
+ byte[] resp = icc.transmitControlCommand(IOCTL_GET_FEATURE_REQUEST,
+ new byte[]{});
+
+ if (log.isTraceEnabled()) {
+ log.trace("Response TLV " + SMCCHelper.toString(resp));
+ }
+ // tag
+ // length in bytes (always 4)
+ // control code value for supported feature (in big endian)
+ for (int i = 0; i < resp.length; i += 6) {
+ Byte feature = new Byte(resp[i]);
+ int ioctlBigEndian = (resp[i + 2] << 24) |
+ (resp[i + 3] << 16) | (resp[i + 4] << 8) | resp[i + 5];
+ Integer ioctl = new Integer(ioctlBigEndian);
+ if (log.isInfoEnabled()) {
+ log.info("CCID supports " + FEATURES[feature.intValue()] +
+ ": " + Integer.toHexString(ioctl.intValue()));
+ }
+ features.put(feature, ioctl);
+ }
+ } catch (CardException ex) {
+ log.debug("Failed to query CCID features: " + ex.getMessage());
+ log.trace(ex);
+ log.info("CCID does not support PINPad");
+ }
+ }
+ return features;
+ }
+
+ @Override
+ public boolean hasFeature(Byte feature) {
+ if (features != null) {
+ return features.containsKey(feature);
+ }
+ return false;
+ }
+
+// public Integer getIOCTL(Byte feature) {
+// if (features != null) {
+// return features.get(feature);
+// }
+// return null;
+// }
+
+ @Override
+ public byte[] transmitControlCommand(Byte feature, byte[] ctrlCommand)
+ throws SignatureCardException {
+ try {
+ if (!features.containsKey(feature)) {
+ throw new SignatureCardException(FEATURES[feature.intValue()] + " not supported");
+ }
+ int ioctl = features.get(feature);
+ if (log.isTraceEnabled()) {
+ log.trace("CtrlCommand (" + Integer.toHexString(ioctl) +
+ ") " + SMCCHelper.toString(ctrlCommand));
+ }
+ byte[] resp = icc.transmitControlCommand(ioctl, ctrlCommand);
+ if (log.isTraceEnabled()) {
+ log.trace("CtrlCommand Response " + SMCCHelper.toString(resp));
+ }
+ return resp;
+ } catch (CardException ex) {
+ log.error(ex.getMessage());
+ throw new SignatureCardException("Failed to transmit CtrlCommand for " +
+ FEATURES[feature.intValue()]);
+ }
+ }
+
+
+ @Override
+ public byte getbTimeOut() {
+ return (byte) 0x3c; // (max 1min on ReinerSCT),
+ // 0x00=default, 0x1e = 30sec
+ }
+
+ @Override
+ public byte getbTimeOut2() {
+ return (byte) 0x00; // default
+ }
+
+ @Override
+ public byte getwPINMaxExtraDigitL() {
+ return (byte) 0x12;
+ }
+
+ @Override
+ public byte getwPINMaxExtraDigitH() {
+ return (byte) 0x00;
+ }
+
+ @Override
+ public byte getbEntryValidationCondition() {
+ return (byte) 0x02; // validation key pressed
+ }
+
+
+ // protected byte ifdGetKeyPressed() throws CardException {
+// if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) {
+//
+// Long controlCode = (Long) IFD_IOCTL.get(new Byte((byte) 0x05));
+//
+// byte key = 0x00;
+// while (key == 0x00) {
+//
+// byte[] resp = card_.transmitControlCommand(controlCode.intValue(), new byte[] {});
+//
+// if (resp != null && resp.length > 0) {
+// key = resp[0];
+// }
+// }
+//
+// System.out.println("Key: " + key);
+//
+// }
+//
+// return 0x00;
+// }
+//
+// protected byte[] ifdVerifyPINFinish() throws CardException {
+// if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) {
+//
+// Long controlCode = (Long) IFD_IOCTL.get(new Byte((byte) 0x02));
+//
+// byte[] resp = card_.transmitControlCommand(controlCode.intValue(), new byte[] {});
+//
+// System.out.println("CommandResp: " + toString(resp));
+//
+// return resp;
+//
+// }
+//
+// return null;
+// }
+
+
+ /**
+ * assumes ifdSupportsVerifyPIN() == true
+ * @param pinVerifyStructure
+ * @return
+ * @throws javax.smartcardio.CardException
+ */
+// protected byte[] ifdVerifyPIN(byte[] pinVerifyStructure) throws CardException {
+//
+//// Long ctrlCode = (Long) ifdFeatures.get(FEATURE_IFD_PIN_PROPERTIES);
+//// if (ctrlCode != null) {
+//// if (log.isTraceEnabled()) {
+//// log.trace("PIN_PROPERTIES CtrlCode " + Integer.toHexString(ctrlCode.intValue()));
+//// }
+//// byte[] resp = card_.transmitControlCommand(ctrlCode.intValue(), new byte[] {});
+////
+//// if (log.isTraceEnabled()) {
+//// log.trace("PIN_PROPERTIES Response " + SMCCHelper.toString(resp));
+//// }
+//// }
+//
+//
+// Long ctrlCode = (Long) ifdFeatures.get(FEATURE_VERIFY_PIN_DIRECT);
+// if (ctrlCode == null) {
+// throw new NullPointerException("no CtrlCode for FEATURE_VERIFY_PIN_DIRECT");
+// }
+//
+// if (log.isTraceEnabled()) {
+// log.trace("VERIFY_PIN_DIRECT CtrlCode " + Integer.toHexString(ctrlCode.intValue()) +
+// ", PIN_VERIFY_STRUCTURE " + SMCCHelper.toString(pinVerifyStructure));
+// }
+// byte[] resp = card_.transmitControlCommand(ctrlCode.intValue(), pinVerifyStructure);
+//
+// if (log.isTraceEnabled()) {
+// log.trace("VERIFY_PIN_DIRECT Response " + SMCCHelper.toString(resp));
+// }
+// return resp;
+// }
+
+// protected Long getControlCode(Byte feature) {
+// if (ifdFeatures != null) {
+// return ifdFeatures.get(feature);
+// }
+// return null;
+// }
+
+
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ccid/GemplusGemPCPinpad.java b/smcc/src/main/java/at/gv/egiz/smcc/ccid/GemplusGemPCPinpad.java
new file mode 100644
index 00000000..903b11fc
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ccid/GemplusGemPCPinpad.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package at.gv.egiz.smcc.ccid;
+
+import javax.smartcardio.Card;
+import javax.smartcardio.CardTerminal;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class GemplusGemPCPinpad extends DefaultReader {
+
+ protected final static Log log = LogFactory.getLog(GemplusGemPCPinpad.class);
+
+ public GemplusGemPCPinpad(Card icc, CardTerminal ct) {
+ super(icc, ct);
+ log.info("Initializing Gemplus GemPC Pinpad reader");
+ log.info("Gemplus GemPC Pinpad allows PINs to have 4-8 digits");
+
+ }
+
+ @Override
+ public byte getbTimeOut() {
+ return (byte) 0x3c; // 0x00 default = 15sec
+ // max 40sec (?)
+ }
+
+ @Override
+ public byte getbTimeOut2() {
+ return (byte) 0x00; // 0x00 default = 15sec
+ }
+
+ @Override
+ public byte getwPINMaxExtraDigitL() {
+ return (byte) 0x08;
+ }
+
+ @Override
+ public byte getwPINMaxExtraDigitH() {
+ return (byte) 0x04;
+ }
+
+ @Override
+ public byte getbEntryValidationCondition() {
+ return (byte) 0x02; // validation key pressed
+ }
+
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ccid/ReaderFactory.java b/smcc/src/main/java/at/gv/egiz/smcc/ccid/ReaderFactory.java
new file mode 100644
index 00000000..2cfcef19
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ccid/ReaderFactory.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package at.gv.egiz.smcc.ccid;
+
+import javax.smartcardio.Card;
+import javax.smartcardio.CardTerminal;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class ReaderFactory {
+
+ public static CCID getReader(Card icc, CardTerminal ct) {
+ if ("Gemplus GemPC Pinpad 00 00".equals(ct.getName())) {
+ return new GemplusGemPCPinpad(icc, ct);
+ }
+ return new DefaultReader(icc, ct);
+ }
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/ACOSCardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/ACOSCardTest.java
new file mode 100644
index 00000000..5839d14a
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/ACOSCardTest.java
@@ -0,0 +1,135 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package at.gv.egiz.smcc;
+
+import at.gv.egiz.smcc.SignatureCard.KeyboxName;
+import at.gv.egiz.smcc.util.SMCCHelper;
+import java.util.List;
+import java.util.Locale;
+import javax.smartcardio.ResponseAPDU;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author clemens
+ */
+@Ignore
+public class ACOSCardTest {
+
+ static ACOSCard card;
+ static PINSpec infPin, decPin, sigPin;
+
+ public ACOSCardTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ SMCCHelper smccHelper = new SMCCHelper();
+ switch (smccHelper.getResultCode()) {
+ case SMCCHelper.CARD_FOUND:
+ SignatureCard sigCard = smccHelper.getSignatureCard(Locale.GERMAN);
+ if (sigCard instanceof ACOSCard) {
+ System.out.println("ACOS card found");
+ card = (ACOSCard) sigCard;
+ List<PINSpec> pinSpecs = card.getPINSpecs();
+ infPin = pinSpecs.get(ACOSCard.PINSPEC_INF);
+ decPin = pinSpecs.get(ACOSCard.PINSPEC_DEC);
+ sigPin = pinSpecs.get(ACOSCard.PINSPEC_SIG);
+ } else {
+ throw new Exception("not STARCOS card: " + sigCard.toString());
+ }
+ break;
+ default:
+ throw new Exception("no card found");
+ }
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+
+
+ /**
+ * Test of verifyPIN method, of class STARCOSCard.
+ */
+ @Test
+ @Ignore
+ public void testVerifyPIN_pinpad() throws Exception {
+ System.out.println("verifyPIN (pinpad)");
+ assertNotNull(card);
+
+ card.verifyPIN(decPin, new PINProvider() {
+
+ @Override
+ public char[] providePIN(PINSpec spec, int retries) {
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Test of verifyPIN method, of class STARCOSCard.
+ */
+ @Test
+ @Ignore
+ public void testVerifyPIN_internal() throws Exception {
+ System.out.println("verifyPIN (internal)");
+ assertNotNull(card);
+
+ card.reset();
+
+ card.getCard().beginExclusive();
+
+ // 0x6700 without sending an APDU prior to send CtrlCmd
+ System.out.println("WARNING: this command will fail if no card " +
+ "communication took place prior to sending the CtrlCommand");
+ int retries = card.verifyPIN(decPin.getKID(), null); //"1397".toCharArray());
+
+ System.out.println("VERIFY PIN returned " + retries);
+ card.getCard().endExclusive();
+ }
+
+ /**
+ * Test of changePIN method, of class STARCOSCard.
+ */
+ @Test
+ @Ignore
+ public void testChangePIN() throws Exception {
+ System.out.println("changePIN");
+ assertNotNull(card);
+
+ card.reset();
+ int retries = card.changePIN(decPin.getKID(), null, null);
+
+ System.out.println("CHANGE PIN returned " + retries);
+ }
+
+ /**
+ * Test of reset method, of class STARCOSCard.
+ */
+ @Test
+ public void testReset() throws Exception {
+ System.out.println("reset");
+ assertNotNull(card);
+ card.reset();
+ }
+
+} \ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java
new file mode 100644
index 00000000..9be8db00
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java
@@ -0,0 +1,267 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package at.gv.egiz.smcc;
+
+import at.gv.egiz.smcc.SignatureCard.KeyboxName;
+import at.gv.egiz.smcc.util.SMCCHelper;
+import java.util.List;
+import java.util.Locale;
+import javax.smartcardio.ResponseAPDU;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author clemens
+ */
+@Ignore
+public class STARCOSCardTest {
+
+ static STARCOSCard card;
+ static PINSpec cardPin, ssPin;
+
+ public STARCOSCardTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ SMCCHelper smccHelper = new SMCCHelper();
+ switch (smccHelper.getResultCode()) {
+ case SMCCHelper.CARD_FOUND:
+ SignatureCard sigCard = smccHelper.getSignatureCard(Locale.GERMAN);
+ if (sigCard instanceof STARCOSCard) {
+ System.out.println("STARCOS card found");
+ card = (STARCOSCard) sigCard;
+ List<PINSpec> pinSpecs = card.getPINSpecs();
+ cardPin = pinSpecs.get(STARCOSCard.PINSPEC_CARD);
+ ssPin = pinSpecs.get(STARCOSCard.PINSPEC_SS);
+
+ } else {
+ throw new Exception("not STARCOS card: " + sigCard.toString());
+ }
+ break;
+ default:
+ throw new Exception("no card found");
+ }
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of getCertificate method, of class STARCOSCard.
+ */
+ @Test
+ @Ignore
+ public void testGetCertificate() throws Exception {
+ System.out.println("getCertificate");
+ KeyboxName keyboxName = null;
+ STARCOSCard instance = new STARCOSCard();
+ byte[] expResult = null;
+ byte[] result = instance.getCertificate(keyboxName);
+ assertEquals(expResult, result);
+ // TODO review the generated test code and remove the default call to fail.
+ fail("The test case is a prototype.");
+ }
+
+ /**
+ * Test of getInfobox method, of class STARCOSCard.
+ */
+ @Test
+ @Ignore
+ public void testGetInfobox() throws Exception {
+ System.out.println("getInfobox");
+ String infobox = "";
+ PINProvider provider = null;
+ String domainId = "";
+ STARCOSCard instance = new STARCOSCard();
+ byte[] expResult = null;
+ byte[] result = instance.getInfobox(infobox, provider, domainId);
+ assertEquals(expResult, result);
+ // TODO review the generated test code and remove the default call to fail.
+ fail("The test case is a prototype.");
+ }
+
+ /**
+ * Test of createSignature method, of class STARCOSCard.
+ */
+ @Test
+ @Ignore
+ public void testCreateSignature() throws Exception {
+ System.out.println("createSignature");
+ byte[] hash = null;
+ KeyboxName keyboxName = null;
+ PINProvider provider = null;
+ STARCOSCard instance = new STARCOSCard();
+ byte[] expResult = null;
+ byte[] result = instance.createSignature(hash, keyboxName, provider);
+ assertEquals(expResult, result);
+ // TODO review the generated test code and remove the default call to fail.
+ fail("The test case is a prototype.");
+ }
+
+ /**
+ * Test of selectFileFID method, of class STARCOSCard.
+ */
+ @Test
+ @Ignore
+ public void testSelectFileFID() throws Exception {
+ System.out.println("selectFileFID");
+ byte[] fid = null;
+ STARCOSCard instance = new STARCOSCard();
+ ResponseAPDU expResult = null;
+ ResponseAPDU result = instance.selectFileFID(fid);
+ assertEquals(expResult, result);
+ // TODO review the generated test code and remove the default call to fail.
+ fail("The test case is a prototype.");
+ }
+
+ /**
+ * Test of verifyPIN method, of class STARCOSCard.
+ */
+ @Test
+ @Ignore
+ public void testVerifyPIN_pinpad() throws Exception {
+ System.out.println("verifyPIN (pinpad)");
+ assertNotNull(card);
+
+ card.verifyPIN(cardPin, new PINProvider() {
+
+ @Override
+ public char[] providePIN(PINSpec spec, int retries) {
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Test of verifyPIN method, of class STARCOSCard.
+ */
+ @Test
+ @Ignore
+ public void testVerifyPIN_internal() throws Exception {
+ System.out.println("verifyPIN (internal)");
+ assertNotNull(card);
+
+ card.reset();
+
+ card.getCard().beginExclusive();
+
+ // 0x6700 without sending an APDU prior to send CtrlCmd
+ System.out.println("WARNING: this command will fail if no card " +
+ "communication took place prior to sending the CtrlCommand");
+ int retries = card.verifyPIN(cardPin.getKID(), null); //"1397".toCharArray());
+
+ System.out.println("VERIFY PIN returned " + retries);
+ card.getCard().endExclusive();
+ }
+
+ /**
+ * Test of verifyPIN method, of class STARCOSCard.
+ */
+ @Test
+ @Ignore
+ public void testVerifyPIN_byte() throws Exception {
+ System.out.println("verifyPIN");
+ byte kid = 0;
+ STARCOSCard instance = new STARCOSCard();
+ int expResult = 0;
+ int result = instance.verifyPIN(kid);
+ assertEquals(expResult, result);
+ // TODO review the generated test code and remove the default call to fail.
+ fail("The test case is a prototype.");
+ }
+
+ /**
+ * Test of changePIN method, of class STARCOSCard.
+ */
+ @Test
+ @Ignore
+ public void testChangePIN() throws Exception {
+ System.out.println("changePIN");
+ assertNotNull(card);
+
+ card.reset();
+ int retries = card.changePIN(cardPin.getKID(), null, null);
+
+ System.out.println("CHANGE PIN returned " + retries);
+ }
+
+ /**
+ * Test of activatePIN method, of class STARCOSCard.
+ */
+ @Test
+ @Ignore
+ public void testActivatePIN() throws Exception {
+ System.out.println("activatePIN");
+ assertNotNull(card);
+
+ card.reset();
+ card.activatePIN(cardPin, new PINProvider() {
+
+ @Override
+ public char[] providePIN(PINSpec spec, int retries) throws CancelledException, InterruptedException {
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Test of encodePINBlock method, of class STARCOSCard.
+ */
+ @Test
+ @Ignore
+ public void testEncodePINBlock() throws Exception {
+ System.out.println("encodePINBlock");
+ char[] pin = null;
+ STARCOSCard instance = new STARCOSCard();
+ byte[] expResult = null;
+ byte[] result = instance.encodePINBlock(pin);
+ assertEquals(expResult, result);
+ // TODO review the generated test code and remove the default call to fail.
+ fail("The test case is a prototype.");
+ }
+
+ /**
+ * Test of reset method, of class STARCOSCard.
+ */
+ @Test
+ public void testReset() throws Exception {
+ System.out.println("reset");
+ assertNotNull(card);
+ card.reset();
+ }
+
+ /**
+ * Test of toString method, of class STARCOSCard.
+ */
+ @Test
+ @Ignore
+ public void testToString() {
+ System.out.println("toString");
+ STARCOSCard instance = new STARCOSCard();
+ String expResult = "";
+ String result = instance.toString();
+ assertEquals(expResult, result);
+ // TODO review the generated test code and remove the default call to fail.
+ fail("The test case is a prototype.");
+ }
+
+} \ No newline at end of file
diff --git a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/AbstractPINProvider.java b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/AbstractPINProvider.java
index e32f08d4..e2499023 100644
--- a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/AbstractPINProvider.java
+++ b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/AbstractPINProvider.java
@@ -35,7 +35,7 @@ public abstract class AbstractPINProvider implements PINProvider, ActionListener
protected String action;
- private boolean actionPerformed;
+ protected boolean actionPerformed;
// protected void waitForAction() throws InterruptedException {
// super.wait();
diff --git a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/PINProviderFactory.java b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/PINProviderFactory.java
index 670b71dc..ce1b2d00 100644
--- a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/PINProviderFactory.java
+++ b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/PINProviderFactory.java
@@ -18,6 +18,7 @@
package at.gv.egiz.bku.smccstal;
import at.gv.egiz.bku.gui.BKUGUIFacade;
+import at.gv.egiz.smcc.ccid.CCID;
import at.gv.egiz.smcc.PINProvider;
import at.gv.egiz.smcc.SignatureCard;
import at.gv.egiz.stal.signedinfo.SignedInfoType;
@@ -32,7 +33,7 @@ public abstract class PINProviderFactory {
public static PINProviderFactory getInstance(SignatureCard forCard,
BKUGUIFacade gui) {
- if (forCard.ifdSupportsFeature(SignatureCard.FEATURE_VERIFY_PIN_DIRECT)) {
+ if (forCard.getReader().hasFeature(CCID.FEATURE_VERIFY_PIN_DIRECT)) {
return new PinpadPINProviderFactory(gui);
} else {
return new SoftwarePINProviderFactory(gui);
diff --git a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/PinpadPINProviderFactory.java b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/PinpadPINProviderFactory.java
index 55321b72..c109ceba 100644
--- a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/PinpadPINProviderFactory.java
+++ b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/PinpadPINProviderFactory.java
@@ -21,9 +21,8 @@ import at.gv.egiz.bku.gui.BKUGUIFacade;
import at.gv.egiz.smcc.CancelledException;
import at.gv.egiz.smcc.PINProvider;
import at.gv.egiz.smcc.PINSpec;
-import at.gv.egiz.stal.HashDataInput;
import at.gv.egiz.stal.signedinfo.SignedInfoType;
-import java.util.List;
+import java.security.DigestException;
/**
*
@@ -51,8 +50,9 @@ public class PinpadPINProviderFactory extends PINProviderFactory {
// protected BKUGUIFacade gui;
protected SecureViewer viewer;
+ protected ViewerThread viewerThread;
protected SignedInfoType signedInfo;
- protected List<HashDataInput> hashDataInputs;
+
private SignaturePinProvider(SecureViewer viewer,
SignedInfoType signedInfo) {
@@ -60,61 +60,92 @@ public class PinpadPINProviderFactory extends PINProviderFactory {
this.signedInfo = signedInfo;
}
+ protected class ViewerThread extends Thread {
+
+ PINSpec pinSpec;
+ int retries;
+
+ public ViewerThread(PINSpec pinSpec, int retries) {
+ this.pinSpec = pinSpec;
+ this.retries = retries;
+ }
+
+ @Override
+ public void run() {
+
+ try {
+
+ gui.showPinpadSignaturePINDialog(pinSpec, retries,
+ SignaturePinProvider.this, "secureViewer");
+
+ while (true) {
+ waitForAction();
+
+ if ("secureViewer".equals(action)) {
+ viewer.displayDataToBeSigned(signedInfo,
+ SignaturePinProvider.this, "pinEntry");
+ } else if ("pinEntry".equals(action)) {
+ gui.showPinpadSignaturePINDialog(pinSpec, retries,
+ SignaturePinProvider.this, "secureViewer");
+ } else {
+ log.error("unsupported action command: " + action);
+ }
+ }
+
+ } catch (DigestException ex) {
+ log.error("Bad digest value: " + ex.getMessage());
+ gui.showErrorDialog(BKUGUIFacade.ERR_INVALID_HASH,
+ new Object[]{ex.getMessage()});
+ } catch (InterruptedException ex) {
+ log.info("pinpad secure viewer thread interrupted");
+ } catch (Exception ex) {
+ log.error("Could not display hashdata inputs: " +
+ ex.getMessage());
+ gui.showErrorDialog(BKUGUIFacade.ERR_DISPLAY_HASHDATA,
+ new Object[]{ex.getMessage()});
+ }
+ }
+ }
+
@Override
public char[] providePIN(PINSpec spec, int retries)
throws CancelledException, InterruptedException {
- showPinpadPINDialog(retries, spec);
+ if (viewerThread != null) {
+ updateViewerThread(retries);
+ } else {
+ viewerThread = new ViewerThread(spec, -1);
+ viewerThread.start();
+ }
+// if (viewerThread != null) {
+// log.trace("interrupt old secure viewer thread");
+// viewerThread.interrupt();
+// }
+// viewerThread = new ViewerThread(spec, (retry) ? retries : -1);
+// log.trace("start new secure viewer thread");
+// viewerThread.start();
+
retry = true;
return null;
-
-// do {
-// waitForAction();
-// gui.showWaitDialog(null);
-//
-// if ("hashData".equals(action)) {
-// // show pin dialog in background
-// gui.showSignaturePINDialog(spec, (retry) ? retries : -1,
-// this, "sign",
-// this, "cancel",
-// this, "hashData");
-//
-// viewer.displayDataToBeSigned(signedInfo.getReference());
-//
-// } else if ("sign".equals(action)) {
-// retry = true;
-// return gui.getPin();
-// } else if ("hashDataDone".equals(action)) {
-// gui.showSignaturePINDialog(spec, (retry) ? retries : -1,
-// this, "sign",
-// this, "cancel",
-// this, "hashData");
-// } else if ("cancel".equals(action) ||
-// "error".equals(action)) {
-// throw new CancelledException(spec.getLocalizedName() +
-// " entry cancelled");
-// }
-// } while (true);
}
- private void showPinpadPINDialog(int retries, PINSpec pinSpec) {
- String title, message;
- Object[] params;
- if (retry) {
- title = BKUGUIFacade.TITLE_RETRY;
- message = BKUGUIFacade.MESSAGE_RETRIES;
- params = new Object[]{String.valueOf(retries)};
- } else {
- title = BKUGUIFacade.TITLE_SIGN;
- message = BKUGUIFacade.MESSAGE_ENTERPIN_PINPAD;
- String pinSize = String.valueOf(pinSpec.getMinLength());
- if (pinSpec.getMinLength() != pinSpec.getMaxLength()) {
- pinSize += "-" + pinSpec.getMaxLength();
- }
- params = new Object[]{pinSpec.getLocalizedName(), pinSize};
- }
- gui.showMessageDialog(title, message, params);
+ private synchronized void updateViewerThread(int retries) {
+ log.trace("update viewer thread");
+ viewerThread.retries = retries;
+ action = "pinEntry";
+ actionPerformed = true;
+ notify();
}
+
+
+// @Override
+// protected void finalize() throws Throwable {
+// if (viewerThread != null) {
+// viewerThread.interrupt();
+// }
+// log.info("finalizing Pinpad SignaturePinProvider");
+// super.finalize();
+// }
}
class CardPinProvider extends AbstractPINProvider {
@@ -151,5 +182,5 @@ public class PinpadPINProviderFactory extends PINProviderFactory {
gui.showMessageDialog(title, message, params);
}
}
-}
+ }
diff --git a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SecureViewer.java b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SecureViewer.java
index c395679a..2ee37dc1 100644
--- a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SecureViewer.java
+++ b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SecureViewer.java
@@ -14,12 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package at.gv.egiz.bku.smccstal;
-import at.gv.egiz.stal.signedinfo.ReferenceType;
+import at.gv.egiz.stal.signedinfo.SignedInfoType;
+import java.awt.event.ActionListener;
import java.security.DigestException;
-import java.util.List;
/**
*
@@ -38,7 +37,7 @@ public interface SecureViewer {
* (or any other digest computation error occurs)
* @throws java.lang.Exception
*/
- void displayDataToBeSigned(List<ReferenceType> signedReferences)
- throws DigestException, Exception;
-
+ void displayDataToBeSigned(SignedInfoType signedInfo,
+ ActionListener okListener, String okCommand)
+ throws DigestException, Exception;
}
diff --git a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SignRequestHandler.java b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SignRequestHandler.java
index ac510f38..7a4f6572 100644
--- a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SignRequestHandler.java
+++ b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SignRequestHandler.java
@@ -33,7 +33,6 @@ import org.apache.commons.logging.LogFactory;
import at.gv.egiz.smcc.CancelledException;
import at.gv.egiz.smcc.LockedException;
import at.gv.egiz.smcc.NotActivatedException;
-import at.gv.egiz.smcc.PINProvider;
import at.gv.egiz.smcc.SignatureCard;
import at.gv.egiz.smcc.SignatureCardException;
import at.gv.egiz.smcc.SignatureCard.KeyboxName;
@@ -47,11 +46,12 @@ import at.gv.egiz.stal.signedinfo.ObjectFactory;
import at.gv.egiz.stal.signedinfo.SignedInfoType;
import at.gv.egiz.stal.util.JCEAlgorithmNames;
-public abstract class SignRequestHandler extends AbstractRequestHandler implements SecureViewer {
+public class SignRequestHandler extends AbstractRequestHandler {
private static Log log = LogFactory.getLog(SignRequestHandler.class);
private static JAXBContext jaxbContext;
private PINProviderFactory pinProviderFactory;
+ private SecureViewer secureViewer;
static {
try {
@@ -61,6 +61,10 @@ public abstract class SignRequestHandler extends AbstractRequestHandler implemen
}
}
+ public SignRequestHandler(SecureViewer secureViewer) {
+ this.secureViewer = secureViewer;
+ }
+
@SuppressWarnings("unchecked")
@Override
public STALResponse handleRequest(STALRequest request) throws InterruptedException {
@@ -85,10 +89,8 @@ public abstract class SignRequestHandler extends AbstractRequestHandler implemen
if (pinProviderFactory == null) {
pinProviderFactory = PINProviderFactory.getInstance(card, gui);
}
- PINProvider pinProvider = pinProviderFactory.
- getSignaturePINProvider(this, si.getValue());
-
- byte[] resp = card.createSignature(md.digest(), kb, pinProvider);
+ byte[] resp = card.createSignature(md.digest(), kb,
+ pinProviderFactory.getSignaturePINProvider(secureViewer, si.getValue()));
if (resp == null) {
return new ErrorResponse(6001);
}
diff --git a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SoftwarePINProviderFactory.java b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SoftwarePINProviderFactory.java
index 54a34280..7d36c2c3 100644
--- a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SoftwarePINProviderFactory.java
+++ b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SoftwarePINProviderFactory.java
@@ -49,7 +49,6 @@ public class SoftwarePINProviderFactory extends PINProviderFactory {
// protected BKUGUIFacade gui;
protected SecureViewer viewer;
protected SignedInfoType signedInfo;
- protected List<HashDataInput> hashDataInputs;
private SignaturePinProvider(SecureViewer viewer,
SignedInfoType signedInfo) {
@@ -64,22 +63,14 @@ public class SoftwarePINProviderFactory extends PINProviderFactory {
gui.showSignaturePINDialog(spec, (retry) ? retries : -1,
this, "sign",
this, "cancel",
- this, "hashData");
+ this, "secureViewer");
do {
waitForAction();
- gui.showMessageDialog(BKUGUIFacade.TITLE_WAIT,
- BKUGUIFacade.MESSAGE_WAIT);
-
- if ("hashData".equals(action)) {
- // show pin dialog in background
- gui.showSignaturePINDialog(spec, (retry) ? retries : -1,
- this, "sign",
- this, "cancel",
- this, "hashData");
+ if ("secureViewer".equals(action)) {
try {
- viewer.displayDataToBeSigned(signedInfo.getReference());
+ viewer.displayDataToBeSigned(signedInfo, this, "pinEntry");
} catch (DigestException ex) {
log.error("Bad digest value: " + ex.getMessage());
gui.showErrorDialog(BKUGUIFacade.ERR_INVALID_HASH,
@@ -93,17 +84,23 @@ public class SoftwarePINProviderFactory extends PINProviderFactory {
this, "error");
}
} else if ("sign".equals(action)) {
+ gui.showMessageDialog(BKUGUIFacade.TITLE_WAIT,
+ BKUGUIFacade.MESSAGE_WAIT);
retry = true;
return gui.getPin();
- } else if ("hashDataDone".equals(action)) {
+ } else if ("pinEntry".equals(action)) {
gui.showSignaturePINDialog(spec, (retry) ? retries : -1,
this, "sign",
this, "cancel",
- this, "hashData");
+ this, "secureViewer");
} else if ("cancel".equals(action) ||
"error".equals(action)) {
+ gui.showMessageDialog(BKUGUIFacade.TITLE_WAIT,
+ BKUGUIFacade.MESSAGE_WAIT);
throw new CancelledException(spec.getLocalizedName() +
" entry cancelled");
+ } else {
+ log.error("unknown action command " + action);
}
} while (true);
}
diff --git a/smccSTAL/src/test/java/at/gv/egiz/smcc/AbstractSMCCSTALTest.java b/smccSTAL/src/test/java/at/gv/egiz/smcc/AbstractSMCCSTALTest.java
index 51dfe0da..1c1cb833 100644
--- a/smccSTAL/src/test/java/at/gv/egiz/smcc/AbstractSMCCSTALTest.java
+++ b/smccSTAL/src/test/java/at/gv/egiz/smcc/AbstractSMCCSTALTest.java
@@ -1,5 +1,6 @@
package at.gv.egiz.smcc;
+import at.gv.egiz.smcc.ccid.CCID;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -109,10 +110,10 @@ public class AbstractSMCCSTALTest extends AbstractSMCCSTAL implements
}
@Override
- public boolean ifdSupportsFeature(byte feature) {
- return false;
+ public CCID getReader() {
+ throw new UnsupportedOperationException("Not supported yet.");
}
-
+
};
return false;
}