diff options
| author | clemenso <clemenso@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4> | 2009-03-27 17:33:11 +0000 | 
|---|---|---|
| committer | clemenso <clemenso@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4> | 2009-03-27 17:33:11 +0000 | 
| commit | 616e06910051528674165319a1d6d161dff5859c (patch) | |
| tree | c5295e32d65bf5895b2b6c1e9662d5fe358091ce | |
| parent | 2a1df5e58e44f8d77f34eb80df74e8c0d27caceb (diff) | |
| download | mocca-616e06910051528674165319a1d6d161dff5859c.tar.gz mocca-616e06910051528674165319a1d6d161dff5859c.tar.bz2 mocca-616e06910051528674165319a1d6d161dff5859c.zip | |
1.1-RC6 (pinpad, pinmgmt, secureviewer)
git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@323 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4
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.pngBinary files differ new file mode 100644 index 00000000..eee4be4f --- /dev/null +++ b/BKUCommonGUI/src/main/resources/images/ChipperlingLogo.png 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;
    }
 | 
