From 3da4655d011dfc2f04f9e4ac28b38aee42d01bc0 Mon Sep 17 00:00:00 2001
From: clemenso <clemenso@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4>
Date: Tue, 5 Jan 2010 10:06:47 +0000
Subject: Features [#437] Handle pinpad [64:03] response apdu correctly [#445]
 pin entry feedback for VERIFY_PIN_START/FINISH [#471] Provide SecureViewer
 Link before Pinpad PinEntry timeout starts

Bugs
[#479] PIN Managment Applet allows unmatching new pin and pin confirmation
[#480] PIN Management displays blocked PINs as ACTIVE
[#486] Not possible to select 3 times in series the same item from signedReferencesList for display in secureViewer
[#506] change pin dialog (gui) issues
[#508] e-card G3 PIN activation (with TransportPIN) not supported
[#509] closing secure viewer window (WINDOW_CLOSING) leaves "signature data is displayed in viewer" dialog in applet


git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@565 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4
---
 smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java   |  44 +-
 .../at/gv/egiz/smcc/AbstractSignatureCard.java     |  14 +-
 smcc/src/main/java/at/gv/egiz/smcc/BELPICCard.java |  11 +-
 .../java/at/gv/egiz/smcc/ChangePINProvider.java    |  36 --
 smcc/src/main/java/at/gv/egiz/smcc/ITCard.java     |  11 +-
 .../at/gv/egiz/smcc/PINConfirmationException.java  |  19 -
 .../java/at/gv/egiz/smcc/PINFormatException.java   |  19 -
 .../java/at/gv/egiz/smcc/PINMgmtSignatureCard.java |  11 +-
 .../src/main/java/at/gv/egiz/smcc/PINProvider.java |  45 --
 .../at/gv/egiz/smcc/ResetRetryCounterAPDUSpec.java |  38 ++
 .../src/main/java/at/gv/egiz/smcc/STARCOSCard.java | 208 +++---
 smcc/src/main/java/at/gv/egiz/smcc/SWCard.java     | 106 +---
 .../main/java/at/gv/egiz/smcc/SignatureCard.java   |   9 +-
 .../java/at/gv/egiz/smcc/pin/gui/ModifyPINGUI.java |  36 ++
 .../at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java |  48 ++
 .../main/java/at/gv/egiz/smcc/pin/gui/PINGUI.java  |  42 ++
 .../java/at/gv/egiz/smcc/pin/gui/PINProvider.java  |  49 ++
 .../java/at/gv/egiz/smcc/reader/CardReader.java    |  92 +++
 .../at/gv/egiz/smcc/reader/DefaultCardReader.java  | 106 ++++
 .../at/gv/egiz/smcc/reader/PinpadCardReader.java   | 703 +++++++++++++++++++++
 .../java/at/gv/egiz/smcc/reader/ReaderFactory.java | 128 ++++
 .../test/java/at/gv/egiz/smcc/AbstractAppl.java    |   1 +
 smcc/src/test/java/at/gv/egiz/smcc/CardEmul.java   |  14 +-
 smcc/src/test/java/at/gv/egiz/smcc/CardTest.java   | 171 +----
 smcc/src/test/java/at/gv/egiz/smcc/PIN.java        |  10 +-
 .../test/java/at/gv/egiz/smcc/acos/A03ApplDEC.java |   2 +-
 .../java/at/gv/egiz/smcc/acos/A03CardEmul.java     |   7 +-
 .../java/at/gv/egiz/smcc/acos/A03CardTest.java     |   9 +-
 .../java/at/gv/egiz/smcc/acos/A04CardEmul.java     |   7 +-
 .../java/at/gv/egiz/smcc/acos/A04CardTest.java     |  12 +-
 .../java/at/gv/egiz/smcc/acos/ACOSApplDEC.java     |   2 +-
 .../java/at/gv/egiz/smcc/acos/ACOSApplSIG.java     |   2 +-
 .../java/at/gv/egiz/smcc/acos/ACOSCardTest.java    |  21 +-
 .../egiz/smcc/pin/gui/CancelChangePINProvider.java |  39 ++
 .../at/gv/egiz/smcc/pin/gui/CancelPINProvider.java |  29 +
 .../at/gv/egiz/smcc/pin/gui/ChangePINProvider.java |  49 ++
 .../at/gv/egiz/smcc/pin/gui/DummyChangePINGUI.java |  68 ++
 .../java/at/gv/egiz/smcc/pin/gui/DummyPINGUI.java  |  48 ++
 .../gv/egiz/smcc/pin/gui/InterruptPINProvider.java |  34 +
 .../smcc/pin/gui/InvalidChangePINProvider.java     |  56 ++
 .../gv/egiz/smcc/pin/gui/InvalidPINProvider.java   |  48 ++
 .../gv/egiz/smcc/pin/gui/SMCCTestPINProvider.java  |  43 ++
 .../java/at/gv/egiz/smcc/starcos/STARCOSAppl.java  |  23 -
 .../starcos/STARCOSApplGewoehnlicheSignatur.java   |  27 +-
 .../gv/egiz/smcc/starcos/STARCOSApplInfobox.java   |   5 +
 .../smcc/starcos/STARCOSApplSichereSignatur.java   |  36 +-
 .../egiz/smcc/starcos/STARCOSCardChannelEmul.java  | 105 ++-
 .../at/gv/egiz/smcc/starcos/STARCOSCardEmul.java   |  24 +-
 .../at/gv/egiz/smcc/starcos/STARCOSCardTest.java   | 132 ++--
 .../smcc/starcos/STARCOSG3CardChannelEmul.java     |  46 ++
 .../at/gv/egiz/smcc/starcos/STARCOSG3CardEmul.java |  57 ++
 .../at/gv/egiz/smcc/starcos/STARCOSG3CardTest.java | 119 ++++
 52 files changed, 2337 insertions(+), 684 deletions(-)
 delete mode 100644 smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java
 delete mode 100644 smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java
 create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/ResetRetryCounterAPDUSpec.java
 create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINGUI.java
 create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java
 create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINGUI.java
 create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java
 create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/reader/CardReader.java
 create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/reader/DefaultCardReader.java
 create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java
 create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/reader/ReaderFactory.java
 create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelChangePINProvider.java
 create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelPINProvider.java
 create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/pin/gui/ChangePINProvider.java
 create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/pin/gui/DummyChangePINGUI.java
 create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/pin/gui/DummyPINGUI.java
 create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InterruptPINProvider.java
 create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidChangePINProvider.java
 create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidPINProvider.java
 create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/pin/gui/SMCCTestPINProvider.java
 create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardChannelEmul.java
 create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardEmul.java
 create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardTest.java

(limited to 'smcc')

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 1ed5a177..b8cdb208 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java
@@ -16,6 +16,8 @@
 */
 package at.gv.egiz.smcc;
 
+import at.gv.egiz.smcc.pin.gui.ModifyPINGUI;
+import at.gv.egiz.smcc.pin.gui.PINGUI;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -79,10 +81,16 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC
 
   public static final byte KID_PIN_SIG = (byte) 0x81;
 
+  public static final byte KID_PUK_SIG = (byte) 0x83;
+
   public static final byte KID_PIN_DEC = (byte) 0x81;
 
+  public static final byte KID_PUK_DEC = (byte) 0x82;
+
   public static final byte KID_PIN_INF = (byte) 0x83;
 
+  public static final byte KID_PUK_INF = (byte) 0x84;
+
   public static final byte[] DST_SIG = new byte[] { (byte) 0x84, (byte) 0x01, // tag
       // ,
       // length
@@ -217,7 +225,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC
 
   @Override
   @Exclusive
-  public byte[] getInfobox(String infobox, PINProvider provider, String domainId)
+  public byte[] getInfobox(String infobox, PINGUI provider, String domainId)
       throws SignatureCardException, InterruptedException {
     
     if ("IdentityLink".equals(infobox)) {
@@ -233,7 +241,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC
   
   }
 
-  protected byte[] getIdentityLinkV1(PINProvider provider, String domainId) 
+  protected byte[] getIdentityLinkV1(PINGUI provider, String domainId)
       throws SignatureCardException, InterruptedException {
     
     try {
@@ -262,7 +270,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC
     
   }
   
-  protected byte[] getIdentityLinkV2(PINProvider provider, String domainId)
+  protected byte[] getIdentityLinkV2(PINGUI provider, String domainId)
       throws SignatureCardException, InterruptedException {
     
     try {
@@ -388,7 +396,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC
   @Override
   @Exclusive
   public byte[] createSignature(InputStream input, KeyboxName keyboxName,
-      PINProvider provider, String alg) throws SignatureCardException, InterruptedException, IOException {
+      PINGUI provider, String alg) throws SignatureCardException, InterruptedException, IOException {
   
     ByteArrayOutputStream dst = new ByteArrayOutputStream();
     // key ID
@@ -487,7 +495,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC
    * @see at.gv.egiz.smcc.AbstractSignatureCard#verifyPIN(at.gv.egiz.smcc.PINSpec, at.gv.egiz.smcc.PINProvider)
    */
   @Override
-  public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider)
+  public void verifyPIN(PINSpec pinSpec, PINGUI pinProvider)
       throws LockedException, NotActivatedException, CancelledException,
       TimeoutException, SignatureCardException, InterruptedException {
 
@@ -509,7 +517,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC
    * @see at.gv.egiz.smcc.AbstractSignatureCard#changePIN(at.gv.egiz.smcc.PINSpec, at.gv.egiz.smcc.ChangePINProvider)
    */
   @Override
-  public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider)
+  public void changePIN(PINSpec pinSpec, ModifyPINGUI pinProvider)
       throws LockedException, NotActivatedException, CancelledException,
       TimeoutException, SignatureCardException, InterruptedException {
 
@@ -528,7 +536,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC
   }
 
   @Override
-  public void activatePIN(PINSpec pinSpec, PINProvider pinProvider)
+  public void activatePIN(PINSpec pinSpec, ModifyPINGUI pinGUI)
       throws CancelledException, SignatureCardException, CancelledException,
       TimeoutException, InterruptedException {
     log.error("ACTIVATE PIN not supported by ACOS");
@@ -536,7 +544,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC
   }
 
   @Override
-  public void unblockPIN(PINSpec pinSpec, PINProvider pinProvider)
+  public void unblockPIN(PINSpec pinSpec, ModifyPINGUI pinGUI)
       throws CancelledException, SignatureCardException, InterruptedException {
     throw new SignatureCardException("Unblock PIN not supported.");
   }
@@ -570,10 +578,8 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC
   // PROTECTED METHODS (assume exclusive card access)
   ////////////////////////////////////////////////////////////////////////
 
-  protected void verifyPINLoop(CardChannel channel, PINSpec spec, PINProvider provider)
-      throws InterruptedException, LockedException, NotActivatedException,
-      TimeoutException, PINFormatException, PINOperationAbortedException,
-      SignatureCardException, CardException {
+  protected void verifyPINLoop(CardChannel channel, PINSpec spec, PINGUI provider)
+      throws InterruptedException, CardException, SignatureCardException {
     
     int retries = -1;
     do {
@@ -581,10 +587,8 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC
     } while (retries > 0);
   }
 
-  protected void changePINLoop(CardChannel channel, PINSpec spec, ChangePINProvider provider)
-      throws InterruptedException, LockedException, NotActivatedException,
-      TimeoutException, PINFormatException, PINOperationAbortedException,
-      SignatureCardException, CardException {
+  protected void changePINLoop(CardChannel channel, PINSpec spec, ModifyPINGUI provider)
+      throws InterruptedException, CardException, SignatureCardException {
 
     int retries = -1;
     do {
@@ -593,7 +597,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC
   }
 
   protected int verifyPIN(CardChannel channel, PINSpec pinSpec,
-      PINProvider provider, int retries) throws InterruptedException, CardException, SignatureCardException {
+      PINGUI provider, int retries) throws InterruptedException, CardException, SignatureCardException {
     
     VerifyAPDUSpec apduSpec = new VerifyAPDUSpec(
         new byte[] {
@@ -602,7 +606,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC
             (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }, 
         0, VerifyAPDUSpec.PIN_FORMAT_ASCII, 8);
     
-    ResponseAPDU resp = reader.verify(channel, apduSpec, pinSpec, provider, retries);
+    ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinSpec, retries);
     
     if (resp.getSW() == 0x9000) {
       return -1;
@@ -625,7 +629,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC
   }
 
   protected int changePIN(CardChannel channel, PINSpec pinSpec,
-      ChangePINProvider pinProvider, int retries) throws CancelledException, InterruptedException, CardException, SignatureCardException {
+      ModifyPINGUI pinProvider, int retries) throws CancelledException, InterruptedException, CardException, SignatureCardException {
 
     ChangeReferenceDataAPDUSpec apduSpec = new ChangeReferenceDataAPDUSpec(
         new byte[] {
@@ -639,7 +643,7 @@ public class ACOSCard extends AbstractSignatureCard implements PINMgmtSignatureC
     
     
     
-    ResponseAPDU resp = reader.modify(channel, apduSpec, pinSpec, pinProvider, retries);
+    ResponseAPDU resp = reader.modify(channel, apduSpec, pinProvider, pinSpec, retries);
     
     if (resp.getSW() == 0x9000) {
       return -1;
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 54b4c7fe..fcb94fc6 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java
@@ -16,6 +16,8 @@
 */
 package at.gv.egiz.smcc;
 
+import at.gv.egiz.smcc.reader.CardReader;
+import at.gv.egiz.smcc.reader.ReaderFactory;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
@@ -29,9 +31,6 @@ import javax.smartcardio.CardTerminal;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
-import at.gv.egiz.smcc.ccid.CCID;
-import at.gv.egiz.smcc.ccid.ReaderFactory;
-
 public abstract class AbstractSignatureCard implements SignatureCard {
 
   private static Log log = LogFactory.getLog(AbstractSignatureCard.class);
@@ -45,7 +44,7 @@ public abstract class AbstractSignatureCard implements SignatureCard {
 
   private Card card_;
   
-  protected CCID reader;
+  protected CardReader reader;
 
   protected AbstractSignatureCard(String resourceBundleName) {
     this.resourceBundleName = resourceBundleName;
@@ -68,7 +67,7 @@ public abstract class AbstractSignatureCard implements SignatureCard {
   @Override
   public void init(Card card, CardTerminal cardTerminal) {
     this.card_ = card;
-    this.reader = ReaderFactory.getInstance().getReader(card, cardTerminal);
+    this.reader = ReaderFactory.getReader(card, cardTerminal);
   }
   
   @Override
@@ -80,11 +79,6 @@ public abstract class AbstractSignatureCard implements SignatureCard {
     return new LogCardChannel(card_.getBasicChannel());
   }
 
-  @Override
-  public CCID getReader() {
-    return reader;
-  }
-
   @Override
   public void setLocale(Locale locale) {
     if (locale == null) {
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/BELPICCard.java b/smcc/src/main/java/at/gv/egiz/smcc/BELPICCard.java
index e02a55d4..41358bb5 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/BELPICCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/BELPICCard.java
@@ -18,6 +18,7 @@
 
 package at.gv.egiz.smcc;
 
+import at.gv.egiz.smcc.pin.gui.PINGUI;
 import java.io.IOException;
 import java.io.InputStream;
 import java.security.MessageDigest;
@@ -110,7 +111,7 @@ public class BELPICCard extends AbstractSignatureCard implements SignatureCard {
 
   @Override
   @Exclusive
-  public byte[] getInfobox(String infobox, PINProvider provider, String domainId)
+  public byte[] getInfobox(String infobox, PINGUI provider, String domainId)
       throws SignatureCardException, InterruptedException {
       
     throw new IllegalArgumentException("Infobox '" + infobox
@@ -120,7 +121,7 @@ public class BELPICCard extends AbstractSignatureCard implements SignatureCard {
   @Override
   @Exclusive
   public byte[] createSignature(InputStream input, KeyboxName keyboxName,
-      PINProvider provider, String alg) throws SignatureCardException, InterruptedException, IOException {
+      PINGUI provider, String alg) throws SignatureCardException, InterruptedException, IOException {
     
     if (KeyboxName.SECURE_SIGNATURE_KEYPAIR != keyboxName) {
       throw new SignatureCardException("Card does not support key " + keyboxName + ".");
@@ -176,7 +177,7 @@ public class BELPICCard extends AbstractSignatureCard implements SignatureCard {
   }
   
   protected void verifyPINLoop(CardChannel channel, PINSpec spec,
-      PINProvider provider) throws LockedException, NotActivatedException,
+      PINGUI provider) throws LockedException, NotActivatedException,
       SignatureCardException, InterruptedException, CardException {
     
     int retries = -1; //verifyPIN(channel, spec, null, -1);
@@ -186,7 +187,7 @@ public class BELPICCard extends AbstractSignatureCard implements SignatureCard {
   }
 
   protected int verifyPIN(CardChannel channel, PINSpec pinSpec,
-      PINProvider provider, int retries) throws SignatureCardException,
+      PINGUI provider, int retries) throws SignatureCardException,
       LockedException, NotActivatedException, InterruptedException,
       CardException {
     
@@ -197,7 +198,7 @@ public class BELPICCard extends AbstractSignatureCard implements SignatureCard {
             (byte) 0xff, (byte) 0xff, (byte) 0xff }, 
         1, VerifyAPDUSpec.PIN_FORMAT_BCD, 7, 4, 4);
     
-    ResponseAPDU resp = reader.verify(channel, apduSpec, pinSpec, provider, retries);
+    ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinSpec, retries);
     
     if (resp.getSW() == 0x9000) {
       return -1;
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java
deleted file mode 100644
index 41010551..00000000
--- a/smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java
+++ /dev/null
@@ -1,36 +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.smcc;
-
-/**
- *
- * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
- */
-public interface ChangePINProvider extends PINProvider {
-
-  /**
-   *
-   * @param spec
-   * @param retries
-   * @return null if no old value for this pin
-   * @throws at.gv.egiz.smcc.CancelledException if cancelled by user
-   * @throws java.lang.InterruptedException
-   */
-  public char[] provideOldPIN(PINSpec spec, int retries)
-          throws CancelledException, InterruptedException;
-
-}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ITCard.java b/smcc/src/main/java/at/gv/egiz/smcc/ITCard.java
index 831a1f9b..64389190 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/ITCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ITCard.java
@@ -17,6 +17,7 @@
 
 package at.gv.egiz.smcc;
 
+import at.gv.egiz.smcc.pin.gui.PINGUI;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -96,7 +97,7 @@ public class ITCard extends AbstractSignatureCard {
 
   @Override
   @Exclusive
-  public byte[] getInfobox(String infobox, PINProvider provider, String domainId)
+  public byte[] getInfobox(String infobox, PINGUI provider, String domainId)
       throws SignatureCardException, InterruptedException {
       
     throw new IllegalArgumentException("Infobox '" + infobox
@@ -106,7 +107,7 @@ public class ITCard extends AbstractSignatureCard {
   @Override
   @Exclusive
   public byte[] createSignature(InputStream input, KeyboxName keyboxName,
-      PINProvider provider, String alg) throws SignatureCardException,
+      PINGUI provider, String alg) throws SignatureCardException,
       InterruptedException, IOException {
 
     if (KeyboxName.SECURE_SIGNATURE_KEYPAIR != keyboxName) {
@@ -159,7 +160,7 @@ public class ITCard extends AbstractSignatureCard {
   }
 
   protected void verifyPINLoop(CardChannel channel, PINSpec spec,
-      PINProvider provider) throws LockedException, NotActivatedException,
+      PINGUI provider) throws LockedException, NotActivatedException,
       SignatureCardException, InterruptedException, CardException {
     
     int retries = -1;
@@ -169,7 +170,7 @@ public class ITCard extends AbstractSignatureCard {
   }
 
   protected int verifyPIN(CardChannel channel, PINSpec pinSpec,
-      PINProvider provider, int retries) throws SignatureCardException,
+      PINGUI provider, int retries) throws SignatureCardException,
       LockedException, NotActivatedException, InterruptedException,
       CardException {
     
@@ -180,7 +181,7 @@ public class ITCard extends AbstractSignatureCard {
             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }, 
         0, VerifyAPDUSpec.PIN_FORMAT_ASCII, 8);
     
-    ResponseAPDU resp = reader.verify(channel, apduSpec, pinSpec, provider, retries);
+    ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinSpec, retries);
     
     if (resp.getSW() == 0x9000) {
       return -2;
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java b/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java
index eaf38435..24dfa53c 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java
@@ -23,23 +23,4 @@ package at.gv.egiz.smcc;
  * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
  */
 public class PINConfirmationException extends SignatureCardException {
-
-  private static final long serialVersionUID = 1L;
-
-  public PINConfirmationException() {
-    super();
-  }
-
-  public PINConfirmationException(String message, Throwable cause) {
-    super(message, cause);
-  }
-
-  public PINConfirmationException(String message) {
-    super(message);
-  }
-
-  public PINConfirmationException(Throwable cause) {
-    super(cause);
-  }
-
 }
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java b/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java
index 774fcdf5..721c63e2 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java
@@ -23,23 +23,4 @@ package at.gv.egiz.smcc;
  * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
  */
 public class PINFormatException extends SignatureCardException {
-
-  private static final long serialVersionUID = 1L;
-
-  public PINFormatException() {
-    super();
-  }
-
-  public PINFormatException(String message, Throwable cause) {
-    super(message, cause);
-  }
-
-  public PINFormatException(String message) {
-    super(message);
-  }
-
-  public PINFormatException(Throwable cause) {
-    super(cause);
-  }
-
 }
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java b/smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java
index 53738612..5091c10f 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/PINMgmtSignatureCard.java
@@ -16,6 +16,9 @@
 */
 package at.gv.egiz.smcc;
 
+import at.gv.egiz.smcc.pin.gui.ModifyPINGUI;
+
+import at.gv.egiz.smcc.pin.gui.PINGUI;
 import java.util.List;
 
 public interface PINMgmtSignatureCard extends SignatureCard {
@@ -26,16 +29,16 @@ public interface PINMgmtSignatureCard extends SignatureCard {
 
   public PIN_STATE getPINState(PINSpec pinSpec) throws SignatureCardException;
   
-  public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider)
+  public void verifyPIN(PINSpec pinSpec, PINGUI pinGUI)
   throws LockedException, NotActivatedException, CancelledException, SignatureCardException, InterruptedException;
 
-  public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider)
+  public void changePIN(PINSpec pinSpec, ModifyPINGUI changePINGUI)
   throws LockedException, NotActivatedException, CancelledException, PINFormatException, SignatureCardException, InterruptedException;
 
-  public void activatePIN(PINSpec pinSpec, PINProvider pinProvider)
+  public void activatePIN(PINSpec pinSpec, ModifyPINGUI activatePINGUI)
   throws CancelledException, SignatureCardException, InterruptedException;
 
-  public void unblockPIN(PINSpec pinSpec, PINProvider pukProvider)
+  public void unblockPIN(PINSpec pinSpec, ModifyPINGUI pukGUI)
   throws CancelledException, SignatureCardException, InterruptedException;
 
 }
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java
deleted file mode 100644
index 5c294b5b..00000000
--- a/smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java
+++ /dev/null
@@ -1,45 +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.smcc;
-
-/**
- * The number of retries is not fixed and there is no way (?) to obtain this value.
- * A PINProvider should therefore maintain an internal retry counter or flag
- * to decide whether or not to warn the user (num retries passed in providePIN).
- *
- * Therefore PINProvider objects should not be reused.
- *
- * (ACOS: reload counter: between 0 and 15, where 15 meens deactivated)
- *
- * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
- */
-public interface PINProvider {
-
-  /**
-   *
-   * @param spec
-   * @param retries num of remaining retries or -1 if unknown
-   * (a positive value does <em>not</em> necessarily signify that there was
-   * already an unsuccessful PIN verification)
-   * @return pin != null
-   * @throws at.gv.egiz.smcc.CancelledException
-   * @throws java.lang.InterruptedException
-   */
-  public char[] providePIN(PINSpec spec, int retries)
-          throws CancelledException, InterruptedException;
-
-}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ResetRetryCounterAPDUSpec.java b/smcc/src/main/java/at/gv/egiz/smcc/ResetRetryCounterAPDUSpec.java
new file mode 100644
index 00000000..7e71eb7e
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ResetRetryCounterAPDUSpec.java
@@ -0,0 +1,38 @@
+/*
+* 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;
+
+public class ResetRetryCounterAPDUSpec extends ChangeReferenceDataAPDUSpec {
+
+  /**
+   * @param apdu
+   * @param pukPosition
+   * @param pukFormat
+   * @param pukLength
+   * @param pukLengthSize
+   * @param pukLengthPos
+   * @param pinInsertionOffsetNew
+   */
+  public ResetRetryCounterAPDUSpec(byte[] apdu, int pukPosition,
+      int pukFormat, int pukLength, int pukLengthSize, int pukLengthPos,
+      int pinInsertionOffsetNew) {
+    super(apdu, pukPosition, pukFormat, pukLength, pukLengthSize, pukLengthPos);
+    this.pinInsertionOffsetNew = pinInsertionOffsetNew;
+  }
+
+  
+}
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 79a4cc69..ad05352f 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
@@ -17,6 +17,8 @@
 
 package at.gv.egiz.smcc;
 
+import at.gv.egiz.smcc.pin.gui.ModifyPINGUI;
+import at.gv.egiz.smcc.pin.gui.PINGUI;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -225,7 +227,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu
   
   @Override
   @Exclusive
-  public byte[] getInfobox(String infobox, PINProvider provider, String domainId)
+  public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId)
       throws SignatureCardException, InterruptedException {
   
     try {
@@ -243,7 +245,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu
           try {
             return ISO7816Utils.readTransparentFileTLV(channel, -1, (byte) 0x30);
           } catch (SecurityStatusNotSatisfiedException e) {
-            verifyPINLoop(channel, spec, provider);
+            verifyPINLoop(channel, spec, pinGUI);
           }
         }
         
@@ -301,7 +303,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu
   @Override
   @Exclusive
   public byte[] createSignature(InputStream input, KeyboxName keyboxName,
-      PINProvider provider, String alg) throws SignatureCardException, InterruptedException, IOException {
+      PINGUI provider, String alg) throws SignatureCardException, InterruptedException, IOException {
   
     ByteArrayOutputStream dst = new ByteArrayOutputStream();
     byte[] ht = null;
@@ -431,7 +433,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu
    */
   @Override
   @Exclusive
-  public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider)
+  public void verifyPIN(PINSpec pinSpec, PINGUI pinProvider)
       throws LockedException, NotActivatedException, CancelledException,
       TimeoutException, SignatureCardException, InterruptedException {
     
@@ -442,12 +444,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu
         // SELECT application
         execSELECT_AID(channel, pinSpec.getContextAID());
       }
-      log.debug("*** verifyPIN loop");
       verifyPINLoop(channel, pinSpec, pinProvider);
-//      log.debug("*** verifyPIN 0");
-//      int retries = verifyPIN(channel, pinSpec, null, 0);
-//      log.debug("*** verifyPIN " + retries + " tries");
-//      verifyPIN(channel, pinSpec, pinProvider, retries);
     } catch (CardException e) {
       log.info("Failed to verify PIN.", e);
       throw new SignatureCardException("Failed to verify PIN.", e);
@@ -460,7 +457,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu
    */
   @Override
   @Exclusive
-  public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider)
+  public void changePIN(PINSpec pinSpec, ModifyPINGUI pinGUI)
       throws LockedException, NotActivatedException, CancelledException,
       TimeoutException, SignatureCardException, InterruptedException {
     
@@ -471,9 +468,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu
         // SELECT application
         execSELECT_AID(channel, pinSpec.getContextAID());
       }
-      changePINLoop(channel, pinSpec, pinProvider);
-//      int retries = verifyPIN(channel, pinSpec, null, 0);
-//      changePIN(channel, pinSpec, pinProvider, retries);
+      changePINLoop(channel, pinSpec, pinGUI);
     } catch (CardException e) {
       log.info("Failed to change PIN.", e);
       throw new SignatureCardException("Failed to change PIN.", e);
@@ -486,7 +481,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu
    */
   @Override
   @Exclusive
-  public void activatePIN(PINSpec pinSpec, PINProvider pinProvider)
+  public void activatePIN(PINSpec pinSpec, ModifyPINGUI activatePINGUI)
       throws CancelledException, SignatureCardException, CancelledException,
       TimeoutException, InterruptedException {
 
@@ -497,7 +492,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu
         // SELECT application
         execSELECT_AID(channel, pinSpec.getContextAID());
       }
-      activatePIN(channel, pinSpec, pinProvider);
+      activatePIN(channel, pinSpec, activatePINGUI);
     } catch (CardException e) {
       log.info("Failed to activate PIN.", e);
       throw new SignatureCardException("Failed to activate PIN.", e);
@@ -509,9 +504,16 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu
    * @see at.gv.egiz.smcc.PINMgmtSignatureCard#unblockPIN(at.gv.egiz.smcc.PINSpec, at.gv.egiz.smcc.PINProvider)
    */
   @Override
-  public void unblockPIN(PINSpec pinSpec, PINProvider pukProvider)
+  public void unblockPIN(PINSpec pinSpec, ModifyPINGUI pukProvider)
       throws CancelledException, SignatureCardException, InterruptedException {
-    throw new SignatureCardException("Unblock PIN is not supported.");
+    CardChannel channel = getCardChannel();
+
+    try {
+      unblockPINLoop(channel, pinSpec, pukProvider);
+    } catch (CardException e) {
+      log.info("Failed to activate PIN.", e);
+      throw new SignatureCardException("Failed to activate PIN.", e);
+    }
   }
 
   @Override
@@ -574,7 +576,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu
   // PROTECTED METHODS (assume exclusive card access)
   ////////////////////////////////////////////////////////////////////////
   
-  protected void verifyPINLoop(CardChannel channel, PINSpec spec, PINProvider provider)
+  protected void verifyPINLoop(CardChannel channel, PINSpec spec, PINGUI provider)
       throws LockedException, NotActivatedException, SignatureCardException,
       InterruptedException, CardException {
     
@@ -584,7 +586,7 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu
     } while (retries > 0);
   }
 
-  protected void changePINLoop(CardChannel channel, PINSpec spec, ChangePINProvider provider)
+  protected void changePINLoop(CardChannel channel, PINSpec spec, ModifyPINGUI provider)
       throws LockedException, NotActivatedException, SignatureCardException,
       InterruptedException, CardException {
 
@@ -594,8 +596,19 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu
     } while (retries > 0);
   }
   
+  protected void unblockPINLoop(CardChannel channel, PINSpec spec, ModifyPINGUI provider)
+      throws LockedException, NotActivatedException, SignatureCardException,
+      InterruptedException, CardException {
+
+    //TODO get PUK retry counter from EF FID 0036 in MF
+    int retries = -1;
+    do {
+      retries = unblockPIN(channel, spec, provider, retries);
+    } while (retries > 0);
+  }
+
   protected int verifyPIN(CardChannel channel, PINSpec pinSpec,
-      PINProvider provider, int retries) throws SignatureCardException,
+      PINGUI provider, int retries) throws SignatureCardException,
       LockedException, NotActivatedException, InterruptedException,
       CardException {
     
@@ -608,108 +621,135 @@ public class STARCOSCard extends AbstractSignatureCard implements PINMgmtSignatu
     
     ResponseAPDU resp;
     if (provider != null) {
-      resp = reader.verify(channel, apduSpec, pinSpec, provider, retries);
+      resp = reader.verify(channel, apduSpec, provider, pinSpec, retries);
     } else {
       resp = channel.transmit(new CommandAPDU(0x00, 0x20, 0x00, pinSpec.getKID()));
     }
-    
+
+
     if (resp.getSW() == 0x9000) {
       return -1;
-    }
-    if (resp.getSW() == 0x63c0) {
-      // returned by the 'short' VERIFY
+    } else if (resp.getSW() == 0x6983 || resp.getSW() == 0x63c0) {
+      // authentication method blocked (0x63c0 returned by 'short' VERIFY)
       throw new LockedException();
-    }
-    if (resp.getSW() >> 4 == 0x63c) {
-      return 0x0f & resp.getSW();
-    }
-    
-    switch (resp.getSW()) {
-    case 0x6983:
-      // authentication method blocked
-      // returned by the 'long' VERIFY
-      throw new LockedException();
-    case 0x6984:
-      // reference data not usable
+    } else if (resp.getSW() == 0x6984 || resp.getSW() == 0x6985) {
+      // reference data not usable; conditions of use not satisfied
       throw new NotActivatedException();
-    case 0x6985:
-      // conditions of use not satisfied
+    } else if (resp.getSW() >> 4 == 0x63c) {
+      return 0x0f & resp.getSW();
+    } else if (version > 1.2 && resp.getSW() == 0x6400) {
+      log.warn("cannot query pin status prior to card activation");
       throw new NotActivatedException();
-  
-    default:
+    } else {
       String msg = "VERIFY failed. SW=" + Integer.toHexString(resp.getSW()); 
       log.info(msg);
       throw new SignatureCardException(msg);
     }
-    
   }
   
   protected int changePIN(CardChannel channel, PINSpec pinSpec,
-      ChangePINProvider pinProvider, int retries) throws CancelledException,
+      ModifyPINGUI pinProvider, int retries) throws CancelledException,
       InterruptedException, CardException, SignatureCardException {
-    
-    ChangeReferenceDataAPDUSpec apduSpec = new ChangeReferenceDataAPDUSpec(
-        new byte[] { 
-            (byte) 0x00, (byte) 0x24, (byte) 0x00, pinSpec.getKID(), (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 }, 
+
+      ChangeReferenceDataAPDUSpec apduSpec = new ChangeReferenceDataAPDUSpec(
+        new byte[] {
+            (byte) 0x00, (byte) 0x24, (byte) 0x00, pinSpec.getKID(), (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 },
         1, VerifyAPDUSpec.PIN_FORMAT_BCD, 7, 4, 4, 8);
-    
-    ResponseAPDU resp = reader.modify(channel, apduSpec, pinSpec, pinProvider, retries);
-    
+
+    ResponseAPDU resp = reader.modify(channel, apduSpec, pinProvider, pinSpec, retries);
+
     if (resp.getSW() == 0x9000) {
       return -1;
-    }
-    if (resp.getSW() >> 4 == 0x63c) {
-      return 0x0f & resp.getSW();
-    }
-    
-    switch (resp.getSW()) {
-    case 0x6983:
+    } else if (resp.getSW() == 0x6983) {
       // authentication method blocked
       throw new LockedException();
-  
-    default:
+    } else if (resp.getSW() == 0x6984) {
+      throw new NotActivatedException();
+    } else if (resp.getSW() >> 4 == 0x63c) {
+      return 0x0f & resp.getSW();
+    } else {
       String msg = "CHANGE REFERENCE DATA failed. SW=" + Integer.toHexString(resp.getSW()); 
       log.info(msg);
       throw new SignatureCardException(msg);
     }
-   
-    
   }
 
   protected int activatePIN(CardChannel channel, PINSpec pinSpec,
-      PINProvider provider) throws SignatureCardException,
+      ModifyPINGUI provider) throws SignatureCardException,
       InterruptedException, CardException {
     
-    NewReferenceDataAPDUSpec apduSpec = new NewReferenceDataAPDUSpec(
+    ResponseAPDU resp;
+    if (version < 1.2) {
+      NewReferenceDataAPDUSpec apduSpec = new NewReferenceDataAPDUSpec(
+          new byte[] {
+              (byte) 0x00, (byte) 0x24, (byte) 0x01, pinSpec.getKID(), (byte) 0x08,
+              (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+              (byte) 0xff, (byte) 0xff, (byte) 0xff },
+          1, VerifyAPDUSpec.PIN_FORMAT_BCD, 7, 4, 4);
+
+      resp = reader.modify(channel, apduSpec, provider, pinSpec);
+    } else {
+      NewReferenceDataAPDUSpec apduSpec = new NewReferenceDataAPDUSpec(
+          new byte[] {
+              (byte) 0x00, (byte) 0x24, (byte) 0x00, pinSpec.getKID(), (byte) 0x10,
+              (byte) 0x26, (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0xff,
+              (byte) 0xff, (byte) 0xff, (byte) 0xff, 
+              (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+              (byte) 0xff, (byte) 0xff, (byte) 0xff },
+          1, VerifyAPDUSpec.PIN_FORMAT_BCD, 7, 4, 4);
+      apduSpec.setPinInsertionOffsetNew(8);
+      resp = reader.modify(channel, apduSpec, provider, pinSpec);
+    }
+
+    if (resp.getSW() == 0x9000) {
+      return -1;
+    } else {
+      String msg = "CHANGE REFERENCE DATA failed. SW=" + Integer.toHexString(resp.getSW());
+      log.info(msg);
+      throw new SignatureCardException(msg);
+    }
+  }
+  
+  protected int unblockPIN(CardChannel channel, PINSpec pinSpec,
+      ModifyPINGUI provider, int retries) throws SignatureCardException,
+      InterruptedException, CardException {
+
+    if (version < 1.2) {
+      // would return 0x6982 (Security status not satisfied)
+      throw new SignatureCardException("RESET RETRY COUNTER is not supported by this card.");
+    }
+
+    ResetRetryCounterAPDUSpec apduSpec = new ResetRetryCounterAPDUSpec(
         new byte[] {
-            (byte) 0x00, (byte) 0x24, (byte) 0x01, pinSpec.getKID(), (byte) 0x08,
+            (byte) 0x00, (byte) 0x2c, (byte) 0x00, pinSpec.getKID(), (byte) 0x10,
             (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
-            (byte) 0xff, (byte) 0xff, (byte) 0xff }, 
-        1, VerifyAPDUSpec.PIN_FORMAT_BCD, 7, 4, 4);
-    
-    ResponseAPDU resp = reader.activate(channel, apduSpec, pinSpec, provider);
-    
-    switch (resp.getSW()) {
-    
-    case 0x9000:
-      return -1;
+            (byte) 0xff, (byte) 0xff, (byte) 0xff,
+            (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+            (byte) 0xff, (byte) 0xff, (byte) 0xff },
+        1, VerifyAPDUSpec.PIN_FORMAT_BCD, 7, 4, 4, 8);
 
-    case 0x6983:
-      // authentication method blocked
-      throw new LockedException();
+    ResponseAPDU resp = reader.modify(channel, apduSpec, provider, pinSpec, retries);
 
-    default:
-      String msg = "CHANGE REFERENCE DATA failed. SW=" + Integer.toHexString(resp.getSW()); 
+    if (resp.getSW() == 0x9000) {
+      return -1;
+    } else if (resp.getSW() == 0x6983) {
+      // PUK blocked
+      throw new LockedException();
+    } else if (resp.getSW() == 0x6984) {
+      throw new NotActivatedException();
+    } else if (resp.getSW() >> 4 == 0x63c) {
+      return 0x0f & resp.getSW();
+    } else {
+      String msg = "RESET RETRY COUNTER failed. SW=" + Integer.toHexString(resp.getSW());
       log.info(msg);
       throw new SignatureCardException(msg);
     }
-    
   }
-  
+
   protected void execSELECT_MF(CardChannel channel) throws CardException, SignatureCardException {
     ResponseAPDU resp = channel.transmit(
         new CommandAPDU(0x00, 0xA4, 0x00, 0x0C));
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 670704d5..73c7faa8 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java
@@ -40,15 +40,12 @@ import java.util.Enumeration;
 import java.util.Locale;
 
 import javax.smartcardio.Card;
-import javax.smartcardio.CardChannel;
-import javax.smartcardio.CardException;
 import javax.smartcardio.CardTerminal;
-import javax.smartcardio.ResponseAPDU;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
-import at.gv.egiz.smcc.ccid.CCID;
+import at.gv.egiz.smcc.pin.gui.PINGUI;
 
 /**
  *
@@ -280,7 +277,7 @@ public class SWCard implements SignatureCard {
     
   }
 
-  public byte[] getInfobox(String infobox, PINProvider provider, String domainId) throws SignatureCardException {
+  public byte[] getInfobox(String infobox, PINGUI provider, String domainId) throws SignatureCardException {
     
     String fileName = getFileName(infobox + ".ibx");
     FileInputStream file;
@@ -309,7 +306,7 @@ public class SWCard implements SignatureCard {
   }
 
   @Override
-  public byte[] createSignature(InputStream input, KeyboxName keyboxName, PINProvider provider, String alg) throws SignatureCardException, InterruptedException, IOException {
+  public byte[] createSignature(InputStream input, KeyboxName keyboxName, PINGUI provider, String alg) throws SignatureCardException, InterruptedException, IOException {
 
     // KeyStore password
     char[] password = getPassword(keyboxName);
@@ -396,101 +393,4 @@ public class SWCard implements SignatureCard {
   @Override
   public void reset() throws SignatureCardException {
   }
-
-  @Override
-  public CCID getReader() {
-    return new CCID() {
-
-      @Override
-      public boolean hasFeature(Byte feature) {
-        return false;
-      }
-
-      @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;
-      }
-
-      @Override
-      public String getName() {
-        return "Software CardReader";
-      }
-
-      @Override
-      public byte[] verifyPin(byte[] PIN_VERIFY) throws CardException {
-        throw new UnsupportedOperationException("Not supported yet.");
-      }
-
-      @Override
-      public byte[] verifyPinDirect(byte[] PIN_VERIFY) throws CardException {
-        throw new UnsupportedOperationException("Not supported yet.");
-      }
-
-      @Override
-      public byte[] modifyPin(byte[] PIN_MODIFY) throws CardException {
-        throw new UnsupportedOperationException("Not supported yet.");
-      }
-
-      @Override
-      public byte[] modifyPinDirect(byte[] PIN_MODIFY) throws CardException {
-        throw new UnsupportedOperationException("Not supported yet.");
-      }
-
-      @Override
-      public void setDisablePinpad(boolean disable) {
-        throw new UnsupportedOperationException("Not supported yet.");
-      }
-
-      @Override
-      public ResponseAPDU verify(CardChannel channel, VerifyAPDUSpec apduSpec,
-          PINSpec pinSpec, PINProvider provider, int retries)
-          throws CancelledException, InterruptedException, CardException,
-          SignatureCardException {
-        throw new UnsupportedOperationException("Not supported yet.");
-      }
-
-      @Override
-      public ResponseAPDU activate(CardChannel channel,
-          NewReferenceDataAPDUSpec apduSpec, PINSpec pinSpec,
-          PINProvider provider) throws CancelledException,
-          InterruptedException, CardException, SignatureCardException {
-        // TODO Auto-generated method stub
-        return null;
-      }
-
-      @Override
-      public ResponseAPDU modify(CardChannel channel,
-          ChangeReferenceDataAPDUSpec apduSpec, PINSpec pinSpec,
-          ChangePINProvider provider, int retries) throws CancelledException,
-          InterruptedException, CardException, SignatureCardException {
-        // TODO Auto-generated method stub
-        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 3d56f97b..fa589b84 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java
@@ -17,8 +17,7 @@
 
 package at.gv.egiz.smcc;
 
-import at.gv.egiz.smcc.ccid.CCID;
-
+import at.gv.egiz.smcc.pin.gui.PINGUI;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Locale;
@@ -99,7 +98,7 @@ public interface SignatureCard {
    * @throws SignatureCardException
    * @throws InterruptedException if applet is destroyed while in pin dialog
    */
-  public byte[] getInfobox(String infobox, PINProvider provider, String domainId)
+  public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId)
       throws SignatureCardException, InterruptedException;
 
   /**
@@ -114,9 +113,7 @@ public interface SignatureCard {
    * @throws IOException 
    */
   public byte[] createSignature(InputStream input, KeyboxName keyboxName,
-      PINProvider provider, String alg) throws SignatureCardException, InterruptedException, IOException;
-
-  public CCID getReader();
+      PINGUI pinGUI, String alg) throws SignatureCardException, InterruptedException, IOException;
 
   /**
    * Sets the local for evtl. required callbacks (e.g. PINSpec)
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINGUI.java b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINGUI.java
new file mode 100644
index 00000000..00dc2d0e
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINGUI.java
@@ -0,0 +1,36 @@
+/*
+* 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.pin.gui;
+
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.PINSpec;
+
+
+public interface ModifyPINGUI extends ModifyPINProvider {
+
+  void modifyPINDirect(PINSpec spec, int retries) throws CancelledException, InterruptedException;
+  void finishDirect();
+
+  void enterCurrentPIN(PINSpec spec, int retries);
+  void enterNewPIN(PINSpec spec);
+  void confirmNewPIN(PINSpec spec);
+  void validKeyPressed();
+  void correctionButtonPressed();
+  void allKeysCleared();
+  /** called prior to MODIFY_PIN_FINISH control command transmission (clear display or display wait message) */
+  void finish();
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java
new file mode 100644
index 00000000..36f0097d
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java
@@ -0,0 +1,48 @@
+/*
+* 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.pin.gui;
+
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.PINSpec;
+
+
+/**
+ * user interface for "software pin-entry" of
+ * <ul>
+ * <li> current pin and new pin (change pin)
+ * <li> new pin (pin activation, no current pin)
+ * <li> puk and new pin (probably verify only?)
+ * </ul>
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public interface ModifyPINProvider {
+
+  /**
+   *
+   * @param spec
+   * @param retries
+   * @return null if no old value for this pin
+   * @throws at.gv.egiz.smcc.CancelledException if cancelled by user
+   * @throws java.lang.InterruptedException
+   */
+  public char[] provideCurrentPIN(PINSpec spec, int retries)
+          throws CancelledException, InterruptedException;
+
+  public char[] provideNewPIN(PINSpec spec)
+          throws CancelledException, InterruptedException;
+
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINGUI.java b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINGUI.java
new file mode 100644
index 00000000..5199977b
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINGUI.java
@@ -0,0 +1,42 @@
+/*
+* 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.pin.gui;
+
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.PINSpec;
+
+
+/**
+ * Display messages for pinpad pin-entry.
+ * Provides an interface for two types of pinpad pin-entry: pinpad-direct and pinpad-start/finish
+ * @author clemens.orthacker@iaik.tugraz.at
+ */
+public interface PINGUI extends PINProvider {
+
+  void enterPINDirect(PINSpec spec, int retries)
+          throws CancelledException, InterruptedException;
+  
+  /**
+   * @throws CancelledException, InterruptedException if signature-data dialog is interrupted or cancelled
+   */
+  void enterPIN(PINSpec spec, int retries)
+          throws CancelledException, InterruptedException;
+  void validKeyPressed();
+  void correctionButtonPressed();
+  void allKeysCleared();
+  
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java
new file mode 100644
index 00000000..3bf49888
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java
@@ -0,0 +1,49 @@
+/*
+* 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.pin.gui;
+
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.PINSpec;
+
+
+/**
+ * The number of retries is not fixed and there is no way (?) to obtain this value.
+ * A PINProvider should therefore maintain an internal retry counter or flag
+ * to decide whether or not to warn the user (num retries passed in providePIN).
+ *
+ * Therefore PINProvider objects should not be reused.
+ *
+ * (ACOS: reload counter: between 0 and 15, where 15 meens deactivated)
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public interface PINProvider {
+
+  /**
+   *
+   * @param spec
+   * @param retries num of remaining retries or -1 if unknown
+   * (a positive value does <em>not</em> necessarily signify that there was
+   * already an unsuccessful PIN verification)
+   * @return pin != null
+   * @throws at.gv.egiz.smcc.CancelledException
+   * @throws java.lang.InterruptedException
+   */
+  char[] providePIN(PINSpec pinSpec, int retries)
+          throws CancelledException, InterruptedException;
+
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/reader/CardReader.java b/smcc/src/main/java/at/gv/egiz/smcc/reader/CardReader.java
new file mode 100644
index 00000000..a1246dd6
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/reader/CardReader.java
@@ -0,0 +1,92 @@
+/*
+ * 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.reader;
+
+import javax.smartcardio.CardChannel;
+import javax.smartcardio.CardException;
+import javax.smartcardio.ResponseAPDU;
+
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.ChangeReferenceDataAPDUSpec;
+import at.gv.egiz.smcc.NewReferenceDataAPDUSpec;
+import at.gv.egiz.smcc.PINSpec;
+import at.gv.egiz.smcc.ResetRetryCounterAPDUSpec;
+import at.gv.egiz.smcc.SignatureCardException;
+import at.gv.egiz.smcc.VerifyAPDUSpec;
+import at.gv.egiz.smcc.pin.gui.ModifyPINGUI;
+import at.gv.egiz.smcc.pin.gui.PINGUI;
+import javax.smartcardio.Card;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public interface CardReader {
+
+
+  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_VERIFY_PIN_START = new Byte((byte) 0x01);
+  Byte FEATURE_VERIFY_PIN_FINISH = new Byte((byte) 0x02);
+  Byte FEATURE_MODIFY_PIN_START = new Byte((byte) 0x03);
+  Byte FEATURE_MODIFY_PIN_FINISH = new Byte((byte) 0x04);
+  Byte FEATURE_GET_KEY_PRESSED = new Byte((byte) 0x05);
+  Byte FEATURE_VERIFY_PIN_DIRECT = new Byte((byte) 0x06);
+  Byte FEATURE_MODIFY_PIN_DIRECT = new Byte((byte) 0x07);
+  Byte FEATURE_MCT_READER_DIRECT = new Byte((byte) 0x08);
+  Byte FEATURE_MCT_UNIVERSAL = new Byte((byte) 0x09);
+  Byte FEATURE_IFD_PIN_PROPERTIES = new Byte((byte) 0x0a);
+  //TODO continue list
+
+
+  Card connect() throws CardException;
+
+  boolean hasFeature(Byte feature);
+
+  ResponseAPDU verify(CardChannel channel, VerifyAPDUSpec apduSpec,
+          PINGUI pinGUI, PINSpec pinSpec, int retries)
+      throws CancelledException, InterruptedException, CardException, SignatureCardException;
+
+  ResponseAPDU modify(CardChannel channel, ChangeReferenceDataAPDUSpec apduSpec,
+          ModifyPINGUI pinGUI, PINSpec pinSpec, int retries)
+      throws CancelledException, InterruptedException, CardException, SignatureCardException;
+
+  ResponseAPDU modify(CardChannel channel, NewReferenceDataAPDUSpec apduSpec,
+          ModifyPINGUI pinGUI, PINSpec pinSpec)
+      throws CancelledException, InterruptedException, CardException, SignatureCardException;
+
+  ResponseAPDU modify(CardChannel channel, ResetRetryCounterAPDUSpec apduSpec,
+          ModifyPINGUI pinGUI, PINSpec pinSpec, int retries)
+      throws CancelledException, InterruptedException, CardException, SignatureCardException;
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/reader/DefaultCardReader.java b/smcc/src/main/java/at/gv/egiz/smcc/reader/DefaultCardReader.java
new file mode 100644
index 00000000..45ea7a5a
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/reader/DefaultCardReader.java
@@ -0,0 +1,106 @@
+/*
+ * 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.reader;
+
+
+import javax.smartcardio.Card;
+import javax.smartcardio.CardChannel;
+import javax.smartcardio.CardException;
+import javax.smartcardio.CardTerminal;
+import javax.smartcardio.ResponseAPDU;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.smcc.ChangeReferenceDataAPDUSpec;
+import at.gv.egiz.smcc.NewReferenceDataAPDUSpec;
+import at.gv.egiz.smcc.PINSpec;
+import at.gv.egiz.smcc.ResetRetryCounterAPDUSpec;
+import at.gv.egiz.smcc.SignatureCardException;
+import at.gv.egiz.smcc.VerifyAPDUSpec;
+import at.gv.egiz.smcc.pin.gui.ModifyPINGUI;
+import at.gv.egiz.smcc.pin.gui.PINGUI;
+import at.gv.egiz.smcc.util.ISO7816Utils;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class DefaultCardReader implements CardReader {
+
+  protected final static Log log = LogFactory.getLog(DefaultCardReader.class);
+
+  protected CardTerminal ct;
+  protected String name;
+
+  public DefaultCardReader(CardTerminal ct) {
+    if (ct == null) {
+      throw new NullPointerException("no card or card terminal provided");
+    }
+    this.ct = ct;
+    this.name = ct.getName();
+  }
+
+  @Override
+  public ResponseAPDU verify(CardChannel channel, VerifyAPDUSpec apduSpec,
+          PINGUI pinGUI, PINSpec pinSpec, int retries)
+        throws SignatureCardException, CardException, InterruptedException {
+
+    log.debug("VERIFY");
+    return channel.transmit(ISO7816Utils.createVerifyAPDU(apduSpec, pinGUI.providePIN(pinSpec, retries)));
+  }
+
+  @Override
+  public ResponseAPDU modify(CardChannel channel, ChangeReferenceDataAPDUSpec apduSpec,
+          ModifyPINGUI pinGUI, PINSpec pinSpec, int retries)
+        throws SignatureCardException, CardException, InterruptedException {
+    log.debug("MODIFY (CHANGE_REFERENCE_DATA)");
+    char[] oldPin = pinGUI.provideCurrentPIN(pinSpec, retries);
+    char[] newPin = pinGUI.provideNewPIN(pinSpec);
+    return channel.transmit(ISO7816Utils.createChangeReferenceDataAPDU(apduSpec, oldPin, newPin));
+  }
+
+  @Override
+  public ResponseAPDU modify(CardChannel channel, NewReferenceDataAPDUSpec apduSpec,
+          ModifyPINGUI pinGUI, PINSpec pinSpec)
+        throws SignatureCardException, CardException, InterruptedException {
+    log.debug("MODIFY (NEW_REFERENCE_DATA)");
+    char[] newPIN = pinGUI.provideNewPIN(pinSpec);
+    return channel.transmit(ISO7816Utils.createNewReferenceDataAPDU(apduSpec, newPIN));
+  }
+
+  @Override
+  public ResponseAPDU modify(CardChannel channel, ResetRetryCounterAPDUSpec apduSpec,
+          ModifyPINGUI pinGUI, PINSpec pinSpec, int retries)
+          throws InterruptedException, CardException, SignatureCardException {
+    log.debug("MODIFY (RESET_RETRY_COUNTER)");
+    //TODO
+    return modify(channel, (ChangeReferenceDataAPDUSpec) apduSpec, pinGUI, pinSpec, retries);
+  }
+
+  @Override
+  public Card connect() throws CardException {
+    log.debug("connect icc");
+    return ct.connect("*");
+  }
+
+  @Override
+  public boolean hasFeature(Byte feature) {
+    return false;
+  }
+
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java b/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java
new file mode 100644
index 00000000..c2537af8
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java
@@ -0,0 +1,703 @@
+/*
+ * 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.reader;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Map;
+
+import javax.smartcardio.Card;
+import javax.smartcardio.CardChannel;
+import javax.smartcardio.CardException;
+import javax.smartcardio.CardTerminal;
+import javax.smartcardio.ResponseAPDU;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.ChangeReferenceDataAPDUSpec;
+import at.gv.egiz.smcc.NewReferenceDataAPDUSpec;
+import at.gv.egiz.smcc.PINConfirmationException;
+import at.gv.egiz.smcc.PINFormatException;
+import at.gv.egiz.smcc.PINOperationAbortedException;
+import at.gv.egiz.smcc.PINSpec;
+import at.gv.egiz.smcc.ResetRetryCounterAPDUSpec;
+import at.gv.egiz.smcc.SignatureCardException;
+import at.gv.egiz.smcc.TimeoutException;
+import at.gv.egiz.smcc.VerifyAPDUSpec;
+import at.gv.egiz.smcc.pin.gui.ModifyPINGUI;
+import at.gv.egiz.smcc.pin.gui.PINGUI;
+import at.gv.egiz.smcc.util.SMCCHelper;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class PinpadCardReader extends DefaultCardReader {
+
+  public static final int PIN_ENTRY_POLLING_INTERVAL = 10;
+
+  protected final static Log log = LogFactory.getLog(PinpadCardReader.class);
+
+  protected byte bEntryValidationCondition = 0x02;  // validation key pressed
+  protected byte bTimeOut = 0x3c;                   // 60sec (= max on ReinerSCT)
+  protected byte bTimeOut2 = 0x00;                  // default (attention with SCM)
+  protected byte wPINMaxExtraDigitH = 0x00;         // min pin length zero digits
+  protected byte wPINMaxExtraDigitL = 0x0c;         // max pin length 12 digits
+
+  /**
+   * supported features and respective control codes
+   */
+  protected Map<Byte, Integer> features;
+  protected boolean VERIFY, MODIFY, VERIFY_DIRECT, MODIFY_DIRECT;
+
+  public PinpadCardReader(CardTerminal ct, Map<Byte, Integer> features) {
+    super(ct);
+    if (features == null) {
+      throw new NullPointerException("Pinpad card reader does not support any features");
+    }
+    this.features = features;
+
+    if (features.containsKey(FEATURE_VERIFY_PIN_START) &&
+        features.containsKey(FEATURE_GET_KEY_PRESSED) &&
+        features.containsKey(FEATURE_VERIFY_PIN_FINISH)) {
+      VERIFY = true;
+    }
+    if (features.containsKey(FEATURE_MODIFY_PIN_START) &&
+        features.containsKey(FEATURE_GET_KEY_PRESSED) &&
+        features.containsKey(FEATURE_MODIFY_PIN_FINISH)) {
+      MODIFY = true;
+    }
+    if (features.containsKey(FEATURE_VERIFY_PIN_DIRECT)) {
+      VERIFY_DIRECT = true;
+    }
+    if (features.containsKey(FEATURE_MODIFY_PIN_DIRECT)) {
+      MODIFY_DIRECT = true;
+    }
+
+    if (name != null) {
+      name = name.toLowerCase();
+      //ReinerSCT: http://support.reiner-sct.de/downloads/LINUX
+      //           http://www.linux-club.de/viewtopic.php?f=61&t=101287&start=0
+      //old: REINER SCT CyberJack 00 00
+      //new (CCID): 0C4B/0300 Reiner-SCT cyberJack pinpad(a) 00 00
+      //Snow Leopard: Reiner-SCT cyberJack pinpad(a) 00 00
+      //display: REINER SCT CyberJack 00 00
+      if(name.startsWith("gemplus gempc pinpad") || name.startsWith("gemalto gempc pinpad")) {
+        log.debug("setting custom wPINMaxExtraDigitH (0x04) for " + name);
+        wPINMaxExtraDigitH = 0x04;
+        log.debug("setting custom wPINMaxExtraDigitL (0x08) for " + name);
+        wPINMaxExtraDigitL = 0x08;
+      } else if (name.startsWith("omnikey cardman 3621")) {
+        log.debug("setting custom wPINMaxExtraDigitH (0x01) for " + name);
+        wPINMaxExtraDigitH = 0x01;
+      } else if (name.startsWith("scm spr 532") || name.startsWith("scm microsystems inc. sprx32 usb smart card reader")) {
+        log.debug("setting custom bTimeOut (0x3c) for " + name);
+        bTimeOut = 0x3c;
+        log.debug("setting custom bTimeOut2 (0x0f) for " + name);
+        bTimeOut2 = 0x0f;
+      } else if (name.startsWith("cherry smartboard xx44")) {
+        log.debug("setting custom wPINMaxExtraDigitH (0x01) for " + name);
+        wPINMaxExtraDigitH = 0x01;
+      }
+    }
+
+  }
+
+  @Override
+  public boolean hasFeature(Byte feature) {
+    return features.containsKey(feature);
+  }
+  
+  private void VERIFY_PIN_START(Card icc, byte[] PIN_VERIFY) throws CardException {
+    int ioctl = features.get(FEATURE_VERIFY_PIN_START);
+    if (log.isTraceEnabled()) {
+      log.trace("VERIFY_PIN_START (" + Integer.toHexString(ioctl) +
+              ")  " + SMCCHelper.toString(PIN_VERIFY));
+    }
+    byte[] resp = icc.transmitControlCommand(ioctl, PIN_VERIFY);
+    if (resp != null && resp.length > 0) {
+      if (resp[0] == (byte) 0x57) {
+        log.error("Invalid parameter in PIN_VERIFY structure");
+        throw new CardException("ERROR_INVALID_PARAMETER");
+      } else {
+        log.error("unexpected response to VERIFY_PIN_START: " +
+                SMCCHelper.toString(resp));
+        throw new CardException("unexpected response to VERIFY_PIN_START: " +
+                SMCCHelper.toString(resp));
+      }
+    }
+  }
+
+  private byte GET_KEY_PRESSED(Card icc) throws CardException {
+    int ioctl = features.get(FEATURE_GET_KEY_PRESSED);
+    byte[] resp = icc.transmitControlCommand(ioctl, new byte[0]);
+    if (resp != null && resp.length == 1) {
+//      if (log.isTraceEnabled()) {
+//        log.trace("response " + SMCCHelper.toString(resp));
+//      }
+      return resp[0];
+    }
+    log.error("unexpected response to GET_KEY_PRESSED: " +
+            SMCCHelper.toString(resp));
+    throw new CardException("unexpected response to GET_KEY_PRESSED: " +
+            SMCCHelper.toString(resp));
+  }
+
+  private byte[] VERIFY_PIN_FINISH(Card icc) throws CardException {
+    int ioctl = features.get(FEATURE_VERIFY_PIN_FINISH);
+    if (log.isTraceEnabled()) {
+      log.trace("VERIFY_PIN_FINISH (" + Integer.toHexString(ioctl) + ")");
+    }
+    byte[] resp = icc.transmitControlCommand(ioctl, new byte[0]);
+    if (resp != null && resp.length == 2) {
+      if (log.isTraceEnabled()) {
+        log.trace("response " + SMCCHelper.toString(resp));
+      }
+      return resp;
+    }
+    log.error("unexpected response to VERIFY_PIN_FINISH: " +
+            SMCCHelper.toString(resp));
+    throw new CardException("unexpected response to VERIFY_PIN_FINISH: " +
+            SMCCHelper.toString(resp));
+  }
+
+  private void MODIFY_PIN_START(Card icc, byte[] PIN_MODIFY) throws CardException {
+    int ioctl = features.get(FEATURE_MODIFY_PIN_START);
+    if (log.isTraceEnabled()) {
+      log.trace("MODFIY_PIN_START (" + Integer.toHexString(ioctl) +
+              ")  " + SMCCHelper.toString(PIN_MODIFY));
+    }
+    byte[] resp = icc.transmitControlCommand(ioctl, PIN_MODIFY);
+    if (resp != null && resp.length > 0) {
+      if (resp[0] == (byte) 0x57) {
+        log.error("Invalid parameter in PIN_MODIFY structure");
+        throw new CardException("ERROR_INVALID_PARAMETER");
+      } else {
+        log.error("unexpected response to MODIFY_PIN_START: " +
+                SMCCHelper.toString(resp));
+        throw new CardException("unexpected response to MODIFY_PIN_START: " +
+                SMCCHelper.toString(resp));
+      }
+    }
+  }
+
+  private byte[] MODIFY_PIN_FINISH(Card icc) throws CardException {
+    int ioctl = features.get(FEATURE_MODIFY_PIN_FINISH);
+    if (log.isTraceEnabled()) {
+      log.trace("MODIFY_PIN_FINISH (" + Integer.toHexString(ioctl) + ")");
+    }
+    byte[] resp = icc.transmitControlCommand(ioctl, new byte[0]);
+    if (resp != null && resp.length == 2) {
+      if (log.isTraceEnabled()) {
+        log.trace("response " + SMCCHelper.toString(resp));
+      }
+      return resp;
+    }
+    log.error("unexpected response to MODIFY_PIN_FINISH: " +
+            SMCCHelper.toString(resp));
+    throw new CardException("unexpected response to MODIFY_PIN_FINISH: " +
+            SMCCHelper.toString(resp));
+  }
+
+  private byte[] VERIFY_PIN_DIRECT(Card icc, byte[] PIN_VERIFY) throws CardException {
+    int ioctl = features.get(FEATURE_VERIFY_PIN_DIRECT);
+    if (log.isTraceEnabled()) {
+      log.trace("VERIFY_PIN_DIRECT (" + Integer.toHexString(ioctl) +
+              ")  " + SMCCHelper.toString(PIN_VERIFY));
+    }
+    byte[] resp = icc.transmitControlCommand(ioctl, PIN_VERIFY);
+    if (log.isTraceEnabled()) {
+      log.trace("response " + SMCCHelper.toString(resp));
+    }
+    return resp;
+  }
+
+  private byte[] verifyPin(Card icc, byte[] PIN_VERIFY, PINGUI pinGUI) 
+          throws SignatureCardException, CardException, InterruptedException {
+
+//    pinGUI.enterPIN(pinSpec, retries);
+
+    log.debug("VERIFY_PIN_START [" + FEATURES[FEATURE_VERIFY_PIN_START] + "]");
+    VERIFY_PIN_START(icc, PIN_VERIFY);
+
+    byte resp;
+    do {
+      resp = GET_KEY_PRESSED(icc);
+      if (resp == (byte) 0x00) {
+        synchronized(this) {
+          try {
+            wait(PIN_ENTRY_POLLING_INTERVAL);
+          } catch (InterruptedException ex) {
+            log.error("interrupted in VERIFY_PIN");
+          }
+        }
+      } else if (resp == (byte) 0x0d) {
+        log.debug("GET_KEY_PRESSED: 0x0d (user confirmed)");
+        break;
+      } else if (resp == (byte) 0x2b) {
+        log.trace("GET_KEY_PRESSED: 0x2b (user entered valid key 0-9)");
+        pinGUI.validKeyPressed();
+      } else if (resp == (byte) 0x1b) {
+        log.debug("GET_KEY_PRESSED: 0x1b (user cancelled VERIFY_PIN via cancel button)");
+        break; // returns 0x6401
+      } else if (resp == (byte) 0x08) {
+        log.debug("GET_KEY_PRESSED: 0x08 (user pressed correction/backspace button)");
+        pinGUI.correctionButtonPressed();
+      } else if (resp == (byte) 0x0e) {
+        log.debug("GET_KEY_PRESSED: 0x0e (timeout occured)");
+        break; // return 0x6400
+      } else if (resp == (byte) 0x40) {
+        log.debug("GET_KEY_PRESSED: 0x40 (PIN_Operation_Aborted)");
+        throw new PINOperationAbortedException("PIN_Operation_Aborted (0x40)");
+      } else if (resp == (byte) 0x0a) {
+        log.debug("GET_KEY_PRESSED: 0x0a (all keys cleared");
+        pinGUI.allKeysCleared();
+      } else {
+        log.error("unexpected response to GET_KEY_PRESSED: " +
+            Integer.toHexString(resp));
+        throw new CardException("unexpected response to GET_KEY_PRESSED: " +
+            Integer.toHexString(resp));
+      }
+    } while (true); 
+
+    return VERIFY_PIN_FINISH(icc);
+  }
+
+  /**
+   * does not display the first pin dialog (enterCurrentPIN or enterNewPIN, depends on bConfirmPIN),
+   * since this is easier to do in calling modify()
+   */
+  private byte[] modifyPin(Card icc, byte[] PIN_MODIFY, ModifyPINGUI pinGUI, PINSpec pINSpec)
+          throws PINOperationAbortedException, CardException {
+
+    byte pinConfirmations = (byte) 0x00; //b0: new pin not entered (0) / entered (1)
+                                         //b1: current pin not entered (0) / entered (1)
+    byte bConfirmPIN = PIN_MODIFY[9];
+    
+//    if ((bConfirmPIN & (byte) 0x02) == 0) {
+//      log.debug("no current PIN entry requested");
+//      pinGUI.enterNewPIN(pINSpec);
+//    } else {
+//      log.debug("current PIN entry requested");
+//      pinGUI.enterCurrentPIN(pINSpec, retries);
+//    }
+
+    log.debug("MODIFY_PIN_START [" + FEATURES[FEATURE_MODIFY_PIN_START] + "]");
+    MODIFY_PIN_START(icc, PIN_MODIFY);
+
+    byte resp;
+    while (true) {
+      resp = GET_KEY_PRESSED(icc);
+      if (resp == (byte) 0x00) {
+        synchronized(this) {
+          try {
+            wait(PIN_ENTRY_POLLING_INTERVAL);
+          } catch (InterruptedException ex) {
+            log.error("interrupted in MODIFY_PIN");
+          }
+        }
+      } else if (resp == (byte) 0x0d) {
+        if (log.isTraceEnabled()) {
+          log.trace("requested pin confirmations: 0b" + Integer.toBinaryString(bConfirmPIN & 0xff));
+          log.trace("performed pin confirmations: 0b" + Integer.toBinaryString(pinConfirmations & 0xff));
+        }
+        log.debug("GET_KEY_PRESSED: 0x0d (user confirmed)");
+        if (pinConfirmations == bConfirmPIN) {
+          break;
+        } else if ((bConfirmPIN & (byte) 0x02) == 0 ||
+            (pinConfirmations & (byte) 0x02) == (byte) 0x02) {
+          // no current pin entry or current pin entry already performed
+          if ((pinConfirmations & (byte) 0x01) == 0) {
+            // new pin
+            pinConfirmations |= (byte) 0x01;
+            pinGUI.confirmNewPIN(pINSpec);
+          } // else: new pin confirmed
+        } else {
+          // current pin entry
+          pinConfirmations |= (byte) 0x02;
+          pinGUI.enterNewPIN(pINSpec);
+        }
+      } else if (resp == (byte) 0x2b) {
+        log.trace("GET_KEY_PRESSED: 0x2b (user entered valid key 0-9)");
+        pinGUI.validKeyPressed();
+      } else if (resp == (byte) 0x1b) {
+        log.debug("GET_KEY_PRESSED: 0x1b (user cancelled VERIFY_PIN via cancel button)");
+        break; // returns 0x6401
+      } else if (resp == (byte) 0x08) {
+        log.debug("GET_KEY_PRESSED: 0x08 (user pressed correction/backspace button)");
+        pinGUI.correctionButtonPressed();
+      } else if (resp == (byte) 0x0e) {
+        log.debug("GET_KEY_PRESSED: 0x0e (timeout occured)");
+        break; // return 0x6400
+      } else if (resp == (byte) 0x40) {
+        log.debug("GET_KEY_PRESSED: 0x40 (PIN_Operation_Aborted)");
+        throw new PINOperationAbortedException("PIN_Operation_Aborted (0x40)");
+      } else if (resp == (byte) 0x0a) {
+        log.debug("GET_KEY_PRESSED: 0x0a (all keys cleared");
+        pinGUI.allKeysCleared();
+      } else {
+        log.error("unexpected response to GET_KEY_PRESSED: " +
+            Integer.toHexString(resp));
+        throw new CardException("unexpected response to GET_KEY_PRESSED: " +
+            Integer.toHexString(resp));
+      }
+
+    }
+
+    pinGUI.finish();
+    return MODIFY_PIN_FINISH(icc);
+  }
+
+  private byte[] MODIFY_PIN_DIRECT(Card icc, byte[] PIN_MODIFY) throws CardException {
+    int ioctl = features.get(FEATURE_MODIFY_PIN_DIRECT);
+    if (log.isTraceEnabled()) {
+      log.trace("MODIFY_PIN_DIRECT (" + Integer.toHexString(ioctl) +
+              ")  " + SMCCHelper.toString(PIN_MODIFY));
+    }
+    byte[] resp = icc.transmitControlCommand(ioctl, PIN_MODIFY);
+    if (log.isTraceEnabled()) {
+      log.trace("response " + SMCCHelper.toString(resp));
+    }
+    return resp;
+  }
+  
+  protected byte[] createPINModifyStructure(NewReferenceDataAPDUSpec apduSpec, PINSpec pinSpec) {
+
+    ByteArrayOutputStream s = new ByteArrayOutputStream();
+    // bTimeOut
+    s.write(bTimeOut);
+    // bTimeOut2
+    s.write(bTimeOut2);
+    // bmFormatString
+    s.write(1 << 7 // system unit = byte
+        | (0xF & apduSpec.getPinPosition()) << 3
+        | (0x1 & apduSpec.getPinJustification() << 2)
+        | (0x3 & apduSpec.getPinFormat()));
+    // bmPINBlockString
+    s.write((0xF & apduSpec.getPinLengthSize()) << 4
+        | (0xF & apduSpec.getPinLength()));
+    // bmPINLengthFormat
+    s.write(// system unit = bit
+        (0xF & apduSpec.getPinLengthPos()));
+    // bInsertionOffsetOld
+    s.write(0x00);
+    // bInsertionOffsetNew
+    s.write(apduSpec.getPinInsertionOffsetNew());
+    // wPINMaxExtraDigit
+    s.write(Math.min(pinSpec.getMaxLength(), wPINMaxExtraDigitL));
+    s.write(Math.max(pinSpec.getMinLength(), wPINMaxExtraDigitH));
+    // bConfirmPIN
+    s.write(0x01);
+    // bEntryValidationCondition
+    s.write(bEntryValidationCondition);
+    // bNumberMessage
+    s.write(0x02);
+    // wLangId English (United States), see http://www.usb.org/developers/docs/USB_LANGIDs.pdf
+    s.write(0x09);
+    s.write(0x04);
+    // bMsgIndex1
+    s.write(0x01);
+    // bMsgIndex2
+    s.write(0x02);
+    // bMsgIndex3
+    s.write(0x00);
+
+    // bTeoPrologue
+    s.write(0x00);
+    s.write(0x00);
+    s.write(0x00);
+    // ulDataLength
+    s.write(apduSpec.getApdu().length);
+    s.write(0x00);
+    s.write(0x00);
+    s.write(0x00);
+    // abData
+    try {
+      s.write(apduSpec.getApdu());
+    } catch (IOException e) {
+      // As we are dealing with ByteArrayOutputStreams no exception is to be
+      // expected.
+      throw new RuntimeException(e);
+    }
+
+    return s.toByteArray();
+
+  }
+  
+  protected byte[] createPINModifyStructure(ChangeReferenceDataAPDUSpec apduSpec, PINSpec pinSpec) {
+    //TODO bInsertionOffsetOld (0x00), bConfirmPIN (0x01), bNumberMessage (0x02), bMsgIndex1/2/3
+
+    ByteArrayOutputStream s = new ByteArrayOutputStream();
+    // bTimeOut
+    s.write(bTimeOut);
+    // bTimeOut2
+    s.write(bTimeOut2);
+    // bmFormatString
+    s.write(1 << 7 // system unit = byte
+        | (0xF & apduSpec.getPinPosition()) << 3
+        | (0x1 & apduSpec.getPinJustification() << 2)
+        | (0x3 & apduSpec.getPinFormat()));
+    // bmPINBlockString
+    s.write((0xF & apduSpec.getPinLengthSize()) << 4
+        | (0xF & apduSpec.getPinLength()));
+    // bmPINLengthFormat
+    s.write(// system unit = bit
+        (0xF & apduSpec.getPinLengthPos()));
+    // bInsertionOffsetOld (0x00 for no old pin?)
+    s.write(apduSpec.getPinInsertionOffsetOld());
+    // bInsertionOffsetNew
+    s.write(apduSpec.getPinInsertionOffsetNew());
+    // wPINMaxExtraDigit
+    s.write(Math.min(pinSpec.getMaxLength(), wPINMaxExtraDigitL));
+    s.write(Math.max(pinSpec.getMinLength(), wPINMaxExtraDigitH));
+    // bConfirmPIN
+    s.write(0x03);
+    // bEntryValidationCondition
+    s.write(bEntryValidationCondition);
+    // bNumberMessage
+    s.write(0x03);
+    // wLangId English (United States), see http://www.usb.org/developers/docs/USB_LANGIDs.pdf
+    s.write(0x09);
+    s.write(0x04);
+    // bMsgIndex1
+    s.write(0x00);
+    // bMsgIndex2
+    s.write(0x01);
+    // bMsgIndex3
+    s.write(0x02);
+    
+    // bTeoPrologue
+    s.write(0x00);
+    s.write(0x00);
+    s.write(0x00);
+    // ulDataLength
+    s.write(apduSpec.getApdu().length);
+    s.write(0x00);
+    s.write(0x00);
+    s.write(0x00);
+    // abData
+    try {
+      s.write(apduSpec.getApdu());
+    } catch (IOException e) {
+      // As we are dealing with ByteArrayOutputStreams no exception is to be
+      // expected.
+      throw new RuntimeException(e);
+    }
+    
+    return s.toByteArray();
+
+  }
+  
+  protected byte[] createPINVerifyStructure(VerifyAPDUSpec apduSpec, PINSpec pinSpec) {
+    
+    ByteArrayOutputStream s = new ByteArrayOutputStream();
+    // bTimeOut
+    s.write(bTimeOut);
+    // bTimeOut2
+    s.write(bTimeOut2);
+    // bmFormatString
+    s.write(1 << 7 // system unit = byte
+        | (0xF & apduSpec.getPinPosition()) << 3
+        | (0x1 & apduSpec.getPinJustification() << 2)
+        | (0x3 & apduSpec.getPinFormat()));
+    // bmPINBlockString
+    s.write((0xF & apduSpec.getPinLengthSize()) << 4
+        | (0xF & apduSpec.getPinLength()));
+    // bmPINLengthFormat
+    s.write(// system unit = bit
+        (0xF & apduSpec.getPinLengthPos()));
+    // wPINMaxExtraDigit
+    s.write(Math.min(pinSpec.getMaxLength(), wPINMaxExtraDigitL)); // max PIN length
+    s.write(Math.max(pinSpec.getMinLength(), wPINMaxExtraDigitH)); // min PIN length
+    // bEntryValidationCondition
+    s.write(bEntryValidationCondition);
+    // bNumberMessage
+    s.write(0x01);
+    // wLangId
+    s.write(0x09);
+    s.write(0x04);
+    // bMsgIndex
+    s.write(0x00);
+    // bTeoPrologue
+    s.write(0x00);
+    s.write(0x00);
+    s.write(0x00);
+    // ulDataLength
+    s.write(apduSpec.getApdu().length);
+    s.write(0x00);
+    s.write(0x00);
+    s.write(0x00);
+    // abData
+    try {
+      s.write(apduSpec.getApdu());
+    } catch (IOException e) {
+      // As we are dealing with ByteArrayOutputStreams no exception is to be
+      // expected.
+      throw new RuntimeException(e);
+    }
+    
+    return s.toByteArray();
+    
+  }
+
+  @Override
+  public ResponseAPDU verify(CardChannel channel, VerifyAPDUSpec apduSpec,
+          PINGUI pinGUI, PINSpec pinSpec, int retries)
+        throws SignatureCardException, CardException, InterruptedException {
+
+    ResponseAPDU resp = null;
+
+    byte[] s = createPINVerifyStructure(apduSpec, pinSpec);
+    Card icc = channel.getCard();
+
+    if (VERIFY) {
+      pinGUI.enterPIN(pinSpec, retries);
+      resp = new ResponseAPDU(verifyPin(icc, s, pinGUI));
+    } else if (VERIFY_DIRECT) {
+      pinGUI.enterPINDirect(pinSpec, retries);
+      log.debug("VERIFY_PIN_DIRECT [" + FEATURES[FEATURE_VERIFY_PIN_DIRECT] + "]");
+      resp = new ResponseAPDU(VERIFY_PIN_DIRECT(icc, s));
+    } else {
+      log.warn("falling back to default pin-entry");
+      return super.verify(channel, apduSpec, pinGUI, pinSpec, retries);
+    }
+
+    switch (resp.getSW()) {
+      case 0x6400:
+        log.debug("SPE operation timed out.");
+        throw new TimeoutException();
+      case 0x6401:
+        log.debug("SPE operation was cancelled by the 'Cancel' button.");
+        throw new CancelledException();
+      case 0x6403:
+          log.debug("User entered too short or too long PIN "
+              + "regarding MIN/MAX PIN length.");
+          throw new PINFormatException();
+      case 0x6480:
+        log.debug("SPE operation was aborted by the 'Cancel' operation "
+            + "at the host system.");
+      case 0x6b80:
+        log.info("Invalid parameter in passed structure.");
+      default:
+        return resp;
+    }
+  }
+
+  @Override
+  public ResponseAPDU modify(CardChannel channel, ChangeReferenceDataAPDUSpec apduSpec,
+          ModifyPINGUI pinGUI, PINSpec pinSpec, int retries)
+        throws SignatureCardException, CardException, InterruptedException {
+    
+    ResponseAPDU resp = null;
+
+    byte[] s = createPINModifyStructure(apduSpec, pinSpec);
+    Card icc = channel.getCard();
+    
+    if (MODIFY) {
+      pinGUI.enterCurrentPIN(pinSpec, retries);
+      resp = new ResponseAPDU(modifyPin(icc, s, pinGUI, pinSpec));
+    } else if (MODIFY_DIRECT) {
+      pinGUI.modifyPINDirect(pinSpec, retries);
+      log.debug("MODIFY_PIN_DIRECT [" + FEATURES[FEATURE_MODIFY_PIN_DIRECT] + "]");
+      resp = new ResponseAPDU(MODIFY_PIN_DIRECT(icc, s));
+    } else {
+      log.warn("falling back to default pin-entry");
+      return super.modify(channel, apduSpec, pinGUI, pinSpec, retries);
+    }
+
+    switch (resp.getSW()) {
+      case 0x6400:
+        log.debug("SPE operation timed out.");
+        throw new TimeoutException();
+      case 0x6401:
+        log.debug("SPE operation was cancelled by the 'Cancel' button.");
+        throw new CancelledException();
+      case 0x6402:
+        log.debug("Modify PIN operation failed because two 'new PIN' " +
+                "entries do not match");
+        throw new PINConfirmationException();
+      case 0x6403:
+        log.debug("User entered too short or too long PIN "
+              + "regarding MIN/MAX PIN length.");
+        throw new PINFormatException();
+      case 0x6480:
+        log.debug("SPE operation was aborted by the 'Cancel' operation "
+            + "at the host system.");
+      case 0x6b80:
+        log.info("Invalid parameter in passed structure.");
+      default:
+        return resp;
+    }
+  }
+
+  @Override
+  public ResponseAPDU modify(CardChannel channel, NewReferenceDataAPDUSpec apduSpec,
+          ModifyPINGUI pinGUI, PINSpec pinSpec)
+        throws SignatureCardException, CardException, InterruptedException {
+
+    ResponseAPDU resp = null;
+
+    byte[] s = createPINModifyStructure(apduSpec, pinSpec);
+    Card icc = channel.getCard();
+
+    if (MODIFY) {
+      pinGUI.enterNewPIN(pinSpec);
+      resp = new ResponseAPDU(modifyPin(icc, s, pinGUI, pinSpec));
+    } else if (MODIFY_DIRECT) {
+      pinGUI.modifyPINDirect(pinSpec, -1);
+      log.debug("MODIFY_PIN_DIRECT [" + FEATURES[FEATURE_MODIFY_PIN_DIRECT] + "]");
+      resp = new ResponseAPDU(MODIFY_PIN_DIRECT(icc, s));
+    } else {
+      log.warn("falling back to default pin-entry");
+      return super.modify(channel, apduSpec, pinGUI, pinSpec);
+    }
+
+    switch (resp.getSW()) {
+      case 0x6400:
+        log.debug("SPE operation timed out.");
+        throw new TimeoutException();
+      case 0x6401:
+        log.debug("SPE operation was cancelled by the 'Cancel' button.");
+        throw new CancelledException();
+      case 0x6402:
+        log.debug("Modify PIN operation failed because two 'new PIN' " +
+                "entries do not match");
+        throw new PINConfirmationException();
+      case 0x6403:
+        log.debug("User entered too short or too long PIN "
+              + "regarding MIN/MAX PIN length.");
+        throw new PINFormatException();
+      case 0x6480:
+        log.debug("SPE operation was aborted by the 'Cancel' operation "
+            + "at the host system.");
+      case 0x6b80:
+        log.info("Invalid parameter in passed structure.");
+      default:
+        return resp;
+    }
+  }
+
+  @Override
+  public ResponseAPDU modify(CardChannel channel, ResetRetryCounterAPDUSpec apduSpec,
+          ModifyPINGUI pinGUI, PINSpec pinSpec, int retries)
+          throws InterruptedException, CardException, SignatureCardException {
+    //TODO
+    return modify(channel, (ChangeReferenceDataAPDUSpec) apduSpec, pinGUI, pinSpec, retries);
+  }
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/reader/ReaderFactory.java b/smcc/src/main/java/at/gv/egiz/smcc/reader/ReaderFactory.java
new file mode 100644
index 00000000..eb197d9f
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/reader/ReaderFactory.java
@@ -0,0 +1,128 @@
+/*
+ * 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.reader;
+
+import at.gv.egiz.smcc.conf.SMCCConfiguration;
+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 ReaderFactory {
+
+  protected final static Log log = LogFactory.getLog(ReaderFactory.class);
+  
+  protected SMCCConfiguration configuration;
+
+  private ReaderFactory() {
+  }
+
+  /**
+   * @param configuration the configuration to set
+   */
+  public void setConfiguration(SMCCConfiguration configuration) {
+    this.configuration = configuration;
+  }
+
+  public static CardReader getReader(Card icc, CardTerminal ct) {
+
+    String name = ct.getName();
+    log.info("creating reader " + name);
+
+    Map<Byte, Integer> features = queryFeatures(icc);
+    boolean disablePinpad = false;
+    CardReader reader;
+
+        //TODO query application context for reader config
+//    if (configuration != null) {
+//      String disablePinpad = configuration.getProperty(SMCCConfiguration.DISABLE_PINPAD_P);
+//      log.debug("setting disablePinpad to " + Boolean.parseBoolean(disablePinpad));
+//      reader.setDisablePinpad(Boolean.parseBoolean(disablePinpad));
+//    }
+    log.warn("card reader configuration is not considered");
+
+    if (features.isEmpty() || disablePinpad) {
+      reader = new DefaultCardReader(ct);
+    } else {
+      reader = new PinpadCardReader(ct, features);
+    }
+
+    return reader;
+  }
+
+  private static int CTL_CODE(int code) {
+    String os_name = System.getProperty("os.name").toLowerCase();
+    if (os_name.indexOf("windows") > -1) {
+      // cf. WinIOCTL.h
+      return (0x31 << 16 | (code) << 2);
+    }
+    // cf. reader.h
+    return 0x42000000 + (code);
+  }
+
+  static int IOCTL_GET_FEATURE_REQUEST = CTL_CODE(3400);
+
+  private static Map<Byte, Integer> queryFeatures(Card icc) {
+    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));
+        }
+        byte[] resp = icc.transmitControlCommand(IOCTL_GET_FEATURE_REQUEST,
+                new byte[0]);
+
+        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]);
+          Integer ioctl = new Integer((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 " + CardReader.FEATURES[feature.intValue()] +
+                    ": " + Integer.toHexString(ioctl.intValue()));
+          }
+          features.put(feature, ioctl);
+        }
+      } catch (CardException ex) {
+        log.debug("Failed to query IFD features: " + ex.getMessage());
+        log.trace(ex);
+        log.info("IFD does not support secure pin entry");
+      }
+    }
+    return features;
+  }
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/AbstractAppl.java b/smcc/src/test/java/at/gv/egiz/smcc/AbstractAppl.java
index 137de509..affb06ff 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/AbstractAppl.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/AbstractAppl.java
@@ -51,6 +51,7 @@ public abstract class AbstractAppl implements CardAppl {
     return files;
   }
 
+  @Override
   public abstract void setPin(int kid, char[] value);
   
 }
\ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/CardEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/CardEmul.java
index 6017bcce..3dfc8510 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/CardEmul.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/CardEmul.java
@@ -28,15 +28,15 @@ import javax.smartcardio.CardException;
 @SuppressWarnings("restriction")
 public abstract class CardEmul extends Card {
 
-  protected Thread exclThread = null;
-  protected CardChannel channel = newCardChannel(this);
+  protected Thread exclThread; // = null;
+  protected CardChannel channel; // = newCardChannel(this);
   protected List<AbstractAppl> applications = new ArrayList<AbstractAppl>();
 
   public CardEmul() {
     super();
   }
 
-  protected abstract CardChannelEmul newCardChannel(CardEmul cardEmul);
+//  protected abstract CardChannelEmul newCardChannel(CardEmul cardEmul);
 
   @Override
   public void beginExclusive() throws CardException {
@@ -71,9 +71,9 @@ public abstract class CardEmul extends Card {
 
   @Override
   public void disconnect(boolean reset) throws CardException {
-    if (reset) {
-      channel = newCardChannel(this);
-    }
+//    if (reset) {
+//      channel = newCardChannel(this);
+//    }
   }
 
   @Override
@@ -93,7 +93,7 @@ public abstract class CardEmul extends Card {
       }
 
   public AbstractAppl getApplication(byte[] fid) {
-    
+
     for(AbstractAppl appl : applications) {
       if (Arrays.equals(appl.getAID(), fid) || Arrays.equals(appl.getFID(), fid)) {
         return appl;
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/CardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/CardTest.java
index b3bd07ab..44e48836 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/CardTest.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/CardTest.java
@@ -16,12 +16,14 @@
 */
 package at.gv.egiz.smcc;
 
+import at.gv.egiz.smcc.pin.gui.CancelPINProvider;
+import at.gv.egiz.smcc.pin.gui.InterruptPINProvider;
+import at.gv.egiz.smcc.pin.gui.CancelChangePINProvider;
 import static org.junit.Assert.*;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
-import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.Arrays;
 import java.util.List;
@@ -32,119 +34,15 @@ import org.junit.Test;
 
 import at.gv.egiz.smcc.SignatureCard.KeyboxName;
 import at.gv.egiz.smcc.acos.A04ApplDEC;
+import at.gv.egiz.smcc.pin.gui.DummyPINGUI;
+import at.gv.egiz.smcc.pin.gui.ModifyPINGUI;
+import at.gv.egiz.smcc.pin.gui.PINGUI;
+import at.gv.egiz.smcc.pin.gui.SMCCTestPINProvider;
+import org.junit.Ignore;
 
 @SuppressWarnings("restriction")
 public abstract class CardTest {
 
-  public class TestPINProvider implements PINProvider {
-    
-    int provided = 0;
-  
-    char[] pin;
-  
-    public TestPINProvider(char[] pin) {
-      super();
-      this.pin = pin;
-    }
-  
-    @Override
-    public char[] providePIN(PINSpec spec, int retries)
-        throws CancelledException, InterruptedException {
-      provided++;
-      return pin;
-    }
-
-    public int getProvided() {
-      return provided;
-    }
-  
-  }
-
-  public class TestChangePINProvider extends TestPINProvider implements
-      ChangePINProvider {
-  
-    char[] oldPin;
-  
-    public TestChangePINProvider(char[] oldPin, char[] pin) {
-      super(pin);
-      this.oldPin = oldPin;
-    }
-  
-    @Override
-    public char[] provideOldPIN(PINSpec spec, int retries)
-        throws CancelledException, InterruptedException {
-      return oldPin;
-    }
-  
-  }
-
-  public class TestInvalidPINProvider implements PINProvider {
-
-    int provided = 0;
-    int numWrongTries = 0;
-
-    char[] pin;
-
-    public TestInvalidPINProvider(char[] pin, int numWrongTries) {
-      super();
-      this.pin = pin;
-      this.numWrongTries = numWrongTries;
-    }
-
-    @Override
-    public char[] providePIN(PINSpec spec, int retries)
-        throws CancelledException, InterruptedException {
-      if (provided >= numWrongTries) {
-        throw new CancelledException("Number of wrong tries reached: " + provided);
-      } else {
-        provided++;
-        return pin;
-      }
-    }
-
-    public int getProvided() {
-      return provided;
-    }
-  }
-
-  public class TestInvalidChangePINProvider implements ChangePINProvider {
-
-    int provided = 0;
-    int numWrongTries = 0;
-
-    char[] pin;
-    char[] oldPin;
-
-    /** emulate ChangePinProvider */
-    public TestInvalidChangePINProvider(char[] oldPin, char[] newPin, int numWrongTries) {
-      super();
-      this.pin = newPin;
-      this.oldPin = oldPin;
-      this.numWrongTries = numWrongTries;
-    }
-
-    @Override
-    public char[] providePIN(PINSpec spec, int retries)
-        throws CancelledException, InterruptedException {
-      return pin;
-    }
-
-    public int getProvided() {
-      return provided;
-    }
-
-    @Override
-    public char[] provideOldPIN(PINSpec spec, int retries)
-        throws CancelledException, InterruptedException {
-      if (provided >= numWrongTries) {
-        throw new CancelledException("Number of wrong tries reached: " + provided);
-      } else {
-        provided++;
-        return oldPin;
-      }
-    }
-  }
-
   public CardTest() {
     super();
   }
@@ -167,7 +65,7 @@ public abstract class CardTest {
     
     SignatureCard signatureCard = createSignatureCard();
     
-    TestPINProvider pinProvider = new TestPINProvider(pin);
+    SMCCTestPINProvider pinProvider = new SMCCTestPINProvider(pin);
 
     byte[] idlink = signatureCard.getInfobox("IdentityLink",
         pinProvider, null);
@@ -184,13 +82,7 @@ public abstract class CardTest {
       
         SignatureCard signatureCard = createSignatureCard();
       
-        PINProvider pinProvider = new PINProvider() {
-          @Override
-          public char[] providePIN(PINSpec spec, int retries)
-              throws CancelledException, InterruptedException {
-            throw new CancelledException();
-          }
-        };
+        PINGUI pinProvider = new CancelPINProvider();
       
     signatureCard.createSignature(new ByteArrayInputStream("MOCCA"
         .getBytes("ASCII")), KeyboxName.SECURE_SIGNATURE_KEYPAIR, pinProvider,
@@ -205,13 +97,7 @@ public abstract class CardTest {
       
         SignatureCard signatureCard = createSignatureCard();
       
-        PINProvider pinProvider = new PINProvider() {
-          @Override
-          public char[] providePIN(PINSpec spec, int retries)
-              throws CancelledException, InterruptedException {
-            throw new CancelledException();
-          }
-        };
+        PINGUI pinProvider = new CancelPINProvider();
       
         signatureCard.createSignature(new ByteArrayInputStream("MOCCA"
             .getBytes("ASCII")), KeyboxName.CERITIFIED_KEYPAIR,
@@ -226,13 +112,7 @@ public abstract class CardTest {
       
         SignatureCard signatureCard = createSignatureCard();
       
-        PINProvider pinProvider = new PINProvider() {
-          @Override
-          public char[] providePIN(PINSpec spec, int retries)
-              throws CancelledException, InterruptedException {
-            throw new InterruptedException();
-          }
-        };
+        PINGUI pinProvider = new InterruptPINProvider();
       
         signatureCard.createSignature(new ByteArrayInputStream("MOCCA"
             .getBytes("ASCII")), KeyboxName.SECURE_SIGNATURE_KEYPAIR,
@@ -247,13 +127,7 @@ public abstract class CardTest {
       
         SignatureCard signatureCard = createSignatureCard();
       
-        PINProvider pinProvider = new PINProvider() {
-          @Override
-          public char[] providePIN(PINSpec spec, int retries)
-              throws CancelledException, InterruptedException {
-            throw new InterruptedException();
-          }
-        };
+        PINGUI pinProvider = new InterruptPINProvider();
       
         signatureCard.createSignature(new ByteArrayInputStream("MOCCA"
             .getBytes("ASCII")), KeyboxName.CERITIFIED_KEYPAIR,
@@ -268,11 +142,11 @@ public abstract class CardTest {
       
         final SignatureCard signatureCard = createSignatureCard();
       
-        PINProvider pinProvider = new PINProvider() {
+        PINGUI pinProvider = new DummyPINGUI() {
           @Override
           public char[] providePIN(PINSpec spec, int retries)
               throws CancelledException, InterruptedException {
-      
+
             try {
               signatureCard.getCertificate(KeyboxName.SECURE_SIGNATURE_KEYPAIR);
               assertTrue(false);
@@ -281,10 +155,10 @@ public abstract class CardTest {
               // expected
               throw new CancelledException();
             }
-      
+
           }
         };
-      
+
         signatureCard.createSignature(new ByteArrayInputStream("MOCCA"
             .getBytes("ASCII")), KeyboxName.SECURE_SIGNATURE_KEYPAIR,
             pinProvider, null);
@@ -298,7 +172,7 @@ public abstract class CardTest {
       
         final SignatureCard signatureCard = createSignatureCard();
       
-        PINProvider pinProvider = new PINProvider() {
+        PINGUI pinProvider = new DummyPINGUI() {
           @Override
           public char[] providePIN(PINSpec spec, int retries)
               throws CancelledException, InterruptedException {
@@ -311,7 +185,6 @@ public abstract class CardTest {
               // expected
               throw new CancelledException();
             }
-      
           }
         };
       
@@ -339,13 +212,7 @@ public abstract class CardTest {
       
         PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard();
       
-        PINProvider pinProvider = new PINProvider() {
-          @Override
-          public char[] providePIN(PINSpec spec, int retries)
-              throws CancelledException, InterruptedException {
-            throw new CancelledException();
-          }
-        };
+        ModifyPINGUI pinProvider = new CancelChangePINProvider();
       
         List<PINSpec> specs = signatureCard.getPINSpecs();
       
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/PIN.java b/smcc/src/test/java/at/gv/egiz/smcc/PIN.java
index ae883727..2cda0c2f 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/PIN.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/PIN.java
@@ -23,19 +23,23 @@ public class PIN {
   public static final int STATE_PIN_VERIFIED = 1;
   
   public static final int STATE_PIN_BLOCKED = -1;
+
+  public static final int STATE_PIN_NOTACTIVE = 2;
   
   public byte[] pin;
   
   public int kid;
   
-  public int state = STATE_RESET;
+  public int state; // = STATE_RESET;
   
-  public int kfpc = 10;
+  public int kfpc; // = 10;
 
-  public PIN(byte[] pin, int kid, int kfpc) {
+  //TODO also provde default constructor without state param
+  public PIN(byte[] pin, int kid, int kfpc, int state) {
     this.pin = pin;
     this.kid = kid;
     this.kfpc = kfpc;
+    this.state = state;
   }
 
 }
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A03ApplDEC.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03ApplDEC.java
index 9fd96d73..f4ac5c35 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/acos/A03ApplDEC.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03ApplDEC.java
@@ -40,7 +40,7 @@ public class A03ApplDEC extends ACOSApplDEC {
     putFile(new File(FID_EF_INFOBOX, EF_INFOBOX, FCI_EF_INFOBOX, KID_PIN_INF));
 
     try {
-      pins.put(KID_PIN_INF, new PIN("0000\0\0\0\0".getBytes("ASCII"), KID_PIN_INF, 10));
+      pins.put(KID_PIN_INF, new PIN("0000\0\0\0\0".getBytes("ASCII"), KID_PIN_INF, 10, PIN.STATE_RESET));
     } catch (UnsupportedEncodingException e) {
       throw new RuntimeException(e);
     }
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardEmul.java
index 58216b6b..7394bae7 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardEmul.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardEmul.java
@@ -24,13 +24,8 @@ import at.gv.egiz.smcc.CardEmul;
 public class A03CardEmul extends ACOSCardEmul {
 
   public A03CardEmul(A03ApplSIG applSIG, A03ApplDEC applDEC) {
+    channel = new A03CardChannelEmul(this);
     applications.add(applSIG);
     applications.add(applDEC);
   }
-
-  @Override
-  protected CardChannelEmul newCardChannel(CardEmul cardEmul) {
-    return new A03CardChannelEmul(this);
-  }
-
 }
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardTest.java
index 776c0370..3a8ac41c 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardTest.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A03CardTest.java
@@ -22,15 +22,16 @@ import java.util.Arrays;
 
 import org.junit.Test;
 
-import at.gv.egiz.smcc.ACOSCard;
 import at.gv.egiz.smcc.CancelledException;
 import at.gv.egiz.smcc.CardEmul;
 import at.gv.egiz.smcc.CardNotSupportedException;
 import at.gv.egiz.smcc.CardTerminalEmul;
+import at.gv.egiz.smcc.pin.gui.ChangePINProvider;
 import at.gv.egiz.smcc.LockedException;
 import at.gv.egiz.smcc.NotActivatedException;
 import at.gv.egiz.smcc.PINFormatException;
 import at.gv.egiz.smcc.PINMgmtSignatureCard;
+import at.gv.egiz.smcc.pin.gui.SMCCTestPINProvider;
 import at.gv.egiz.smcc.PINSpec;
 import at.gv.egiz.smcc.SignatureCard;
 import at.gv.egiz.smcc.SignatureCardException;
@@ -74,12 +75,12 @@ public class A03CardTest extends ACOSCardTest {
       char[] pin = defaultPin;
 
       for (int i = pinSpec.getMinLength(); i <= pinSpec.getMaxLength(); i++) {
-        signatureCard.verifyPIN(pinSpec, new TestPINProvider(pin));
+        signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(pin));
         char[] newPin = new char[i];
         Arrays.fill(newPin, '0');
         signatureCard
-            .changePIN(pinSpec, new TestChangePINProvider(pin, newPin));
-        signatureCard.verifyPIN(pinSpec, new TestPINProvider(newPin));
+            .changePIN(pinSpec, new ChangePINProvider(pin, newPin));
+        signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(newPin));
         pin = newPin;
       }
 
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardEmul.java
index 70925aa6..dd44d05b 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardEmul.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardEmul.java
@@ -24,14 +24,9 @@ import at.gv.egiz.smcc.CardEmul;
 public class A04CardEmul extends ACOSCardEmul {
 
   public A04CardEmul(A04ApplSIG applSIG, A04ApplDEC applDEC) {
+    channel = new A04CardChannelEmul(this);
     applications.add(applSIG);
     applications.add(applDEC);
   }
-
-  @Override
-  protected CardChannelEmul newCardChannel(CardEmul cardEmul) {
-    return new A04CardChannelEmul(this);
-  }
-
   
 }
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardTest.java
index d15e80d7..1cbea1b3 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardTest.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/A04CardTest.java
@@ -28,7 +28,6 @@ import java.util.Arrays;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import at.gv.egiz.smcc.ACOSCard;
 import at.gv.egiz.smcc.CancelledException;
 import at.gv.egiz.smcc.CardEmul;
 import at.gv.egiz.smcc.CardNotSupportedException;
@@ -41,7 +40,8 @@ import at.gv.egiz.smcc.PINSpec;
 import at.gv.egiz.smcc.SignatureCard;
 import at.gv.egiz.smcc.SignatureCardException;
 import at.gv.egiz.smcc.SignatureCardFactory;
-import at.gv.egiz.smcc.CardTest.TestPINProvider;
+import at.gv.egiz.smcc.pin.gui.ChangePINProvider;
+import at.gv.egiz.smcc.pin.gui.SMCCTestPINProvider;
 
 public class A04CardTest extends ACOSCardTest {
 
@@ -88,8 +88,8 @@ public class A04CardTest extends ACOSCardTest {
         char[] newPin = new char[i];
         Arrays.fill(newPin, '0');
         signatureCard
-            .changePIN(pinSpec, new TestChangePINProvider(pin, newPin));
-        signatureCard.verifyPIN(pinSpec, new TestPINProvider(newPin));
+            .changePIN(pinSpec, new ChangePINProvider(pin, newPin));
+        signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(newPin));
         pin = newPin;
       }
 
@@ -111,7 +111,7 @@ public class A04CardTest extends ACOSCardTest {
     SignatureCard signatureCard = factory.createSignatureCard(card,
         new CardTerminalEmul(card));
 
-    TestPINProvider pinProvider = new TestPINProvider(pin);
+    SMCCTestPINProvider pinProvider = new SMCCTestPINProvider(pin);
 
     byte[] idlink = signatureCard.getInfobox("IdentityLink",
         pinProvider, null);
@@ -129,7 +129,7 @@ public class A04CardTest extends ACOSCardTest {
     
     SignatureCard signatureCard = createSignatureCard();
     
-    TestPINProvider pinProvider = new TestPINProvider(pin);
+    SMCCTestPINProvider pinProvider = new SMCCTestPINProvider(pin);
 
     byte[] idlink = signatureCard.getInfobox("IdentityLink",
         pinProvider, null);
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplDEC.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplDEC.java
index 08979536..09a754f3 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplDEC.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplDEC.java
@@ -297,7 +297,7 @@ public abstract class ACOSApplDEC extends ACOSAppl {
     System.arraycopy(C_CH_EKEY, 0, EF_C_CH_EKEY, 0, C_CH_EKEY.length);
     putFile(new File(FID_EF_C_CH_EKEY, EF_C_CH_EKEY, FCI_EF_C_CH_EKEY));
     try {
-      pins.put(KID_PIN_DEC, new PIN("1234\0\0\0\0".getBytes("ASCII"), KID_PIN_DEC, 10));
+      pins.put(KID_PIN_DEC, new PIN("1234\0\0\0\0".getBytes("ASCII"), KID_PIN_DEC, 10, PIN.STATE_RESET));
     } catch (UnsupportedEncodingException e) {
       throw new RuntimeException(e);
     }
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplSIG.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplSIG.java
index e476b434..6ab5903a 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplSIG.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSApplSIG.java
@@ -221,7 +221,7 @@ public abstract class ACOSApplSIG extends ACOSAppl {
     
     // PINs
     try {
-      pins.put(KID_PIN_SIG, new PIN(Arrays.copyOf("123456".getBytes("ASCII"), 8), KID_PIN_SIG, 3));
+      pins.put(KID_PIN_SIG, new PIN(Arrays.copyOf("123456".getBytes("ASCII"), 8), KID_PIN_SIG, 3, PIN.STATE_RESET));
     } catch (UnsupportedEncodingException e) {
       throw new RuntimeException(e);
     }
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardTest.java
index 56d1e4b2..4f012739 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardTest.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/acos/ACOSCardTest.java
@@ -16,26 +16,23 @@
 */
 package at.gv.egiz.smcc.acos;
 
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.Arrays;
 
 import org.junit.Test;
 
-import at.gv.egiz.smcc.ACOSCard;
 import at.gv.egiz.smcc.CardEmul;
 import at.gv.egiz.smcc.CardNotSupportedException;
 import at.gv.egiz.smcc.CardTest;
 import at.gv.egiz.smcc.LockedException;
 import at.gv.egiz.smcc.NotActivatedException;
+import at.gv.egiz.smcc.pin.gui.SMCCTestPINProvider;
 import at.gv.egiz.smcc.SignatureCard;
 import at.gv.egiz.smcc.SignatureCardException;
 import at.gv.egiz.smcc.SignatureCard.KeyboxName;
@@ -60,7 +57,7 @@ public abstract class ACOSCardTest extends CardTest {
     appl.clearInfobox();
 
     byte[] idlink = signatureCard.getInfobox("IdentityLink",
-        new TestPINProvider(pin), null);
+        new SMCCTestPINProvider(pin), null);
     assertNull(idlink);
 
   }
@@ -76,7 +73,7 @@ public abstract class ACOSCardTest extends CardTest {
     ACOSApplDEC appl = (ACOSApplDEC) card.getApplication(ACOSAppl.AID_DEC);
     appl.setInfoboxHeader((byte) 0xFF);
 
-    signatureCard.getInfobox("IdentityLink", new TestPINProvider(pin), null);
+    signatureCard.getInfobox("IdentityLink", new SMCCTestPINProvider(pin), null);
 
   }
 
@@ -138,7 +135,7 @@ public abstract class ACOSCardTest extends CardTest {
 
     byte[] signature = signatureCard.createSignature(new ByteArrayInputStream("MOCCA"
         .getBytes("ASCII")),
-        KeyboxName.SECURE_SIGNATURE_KEYPAIR, new TestPINProvider(pin), null);
+        KeyboxName.SECURE_SIGNATURE_KEYPAIR, new SMCCTestPINProvider(pin), null);
 
     assertNotNull(signature);
 
@@ -158,7 +155,7 @@ public abstract class ACOSCardTest extends CardTest {
 
     byte[] signature = signatureCard.createSignature(new ByteArrayInputStream("MOCCA"
         .getBytes("ASCII")),
-        KeyboxName.CERITIFIED_KEYPAIR, new TestPINProvider(pin), null);
+        KeyboxName.CERITIFIED_KEYPAIR, new SMCCTestPINProvider(pin), null);
 
     assertNotNull(signature);
 
@@ -171,7 +168,7 @@ public abstract class ACOSCardTest extends CardTest {
 
     SignatureCard signatureCard = createSignatureCard();
 
-    TestPINProvider pinProvider = new TestPINProvider("000000".toCharArray());
+    SMCCTestPINProvider pinProvider = new SMCCTestPINProvider("000000".toCharArray());
 
     signatureCard.createSignature(new ByteArrayInputStream("MOCCA"
         .getBytes("ASCII")), KeyboxName.SECURE_SIGNATURE_KEYPAIR,
@@ -186,7 +183,7 @@ public abstract class ACOSCardTest extends CardTest {
 
     SignatureCard signatureCard = createSignatureCard();
 
-    TestPINProvider pinProvider = new TestPINProvider("0000".toCharArray());
+    SMCCTestPINProvider pinProvider = new SMCCTestPINProvider("0000".toCharArray());
 
     signatureCard.createSignature(new ByteArrayInputStream("MOCCA"
         .getBytes("ASCII")), KeyboxName.CERITIFIED_KEYPAIR,
@@ -204,7 +201,7 @@ public abstract class ACOSCardTest extends CardTest {
     ACOSApplSIG appl = (ACOSApplSIG) card.getApplication(ACOSAppl.AID_SIG);
     appl.setPin(ACOSApplSIG.KID_PIN_SIG, null);
 
-    TestPINProvider pinProvider = new TestPINProvider("000000".toCharArray());
+    SMCCTestPINProvider pinProvider = new SMCCTestPINProvider("000000".toCharArray());
 
     signatureCard.createSignature(new ByteArrayInputStream("MOCCA"
         .getBytes("ASCII")), KeyboxName.SECURE_SIGNATURE_KEYPAIR,
@@ -222,7 +219,7 @@ public abstract class ACOSCardTest extends CardTest {
     ACOSApplDEC appl = (ACOSApplDEC) card.getApplication(ACOSAppl.AID_DEC);
     appl.setPin(ACOSApplDEC.KID_PIN_DEC, null);
 
-    TestPINProvider pinProvider = new TestPINProvider("0000".toCharArray());
+    SMCCTestPINProvider pinProvider = new SMCCTestPINProvider("0000".toCharArray());
 
     signatureCard.createSignature(new ByteArrayInputStream("MOCCA"
         .getBytes("ASCII")), KeyboxName.CERITIFIED_KEYPAIR,
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelChangePINProvider.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelChangePINProvider.java
new file mode 100644
index 00000000..dffe7e29
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelChangePINProvider.java
@@ -0,0 +1,39 @@
+/*
+ * 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.pin.gui;
+
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.PINSpec;
+
+public class CancelChangePINProvider extends DummyChangePINGUI implements ModifyPINGUI {
+
+  public CancelChangePINProvider() {
+  }
+
+  @Override
+  public char[] provideCurrentPIN(PINSpec spec, int retries)
+          throws CancelledException, InterruptedException {
+    throw new CancelledException("cancelled by cancelPINProvider");
+  }
+
+  @Override
+  public char[] provideNewPIN(PINSpec spec)
+          throws CancelledException, InterruptedException {
+    throw new CancelledException("cancelled by cancelPINProvider");
+  }
+
+}
\ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelPINProvider.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelPINProvider.java
new file mode 100644
index 00000000..77f19345
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelPINProvider.java
@@ -0,0 +1,29 @@
+/*
+ * 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.pin.gui;
+
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.PINSpec;
+
+public class CancelPINProvider extends DummyPINGUI implements PINGUI {
+
+  @Override
+  public char[] providePIN(PINSpec spec, int retries)
+          throws CancelledException, InterruptedException {
+    throw new CancelledException("cancelled by cancelPINProvider");
+  }
+}
\ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/ChangePINProvider.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/ChangePINProvider.java
new file mode 100644
index 00000000..5eb8b9a1
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/ChangePINProvider.java
@@ -0,0 +1,49 @@
+/*
+ * 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.pin.gui;
+
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.PINSpec;
+
+public class ChangePINProvider extends DummyChangePINGUI implements ModifyPINGUI {
+
+  int provided = 0;
+  char[] pin;
+  char[] oldPin;
+
+  public ChangePINProvider(char[] oldPin, char[] pin) {
+    this.pin = pin;
+    this.oldPin = oldPin;
+  }
+
+  public int getProvided() {
+    return provided;
+  }
+
+  @Override
+  public char[] provideCurrentPIN(PINSpec spec, int retries)
+          throws CancelledException, InterruptedException {
+    provided++;
+    return oldPin;
+  }
+
+  @Override
+  public char[] provideNewPIN(PINSpec spec) {
+    return pin;
+  }
+
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/DummyChangePINGUI.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/DummyChangePINGUI.java
new file mode 100644
index 00000000..fff89409
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/DummyChangePINGUI.java
@@ -0,0 +1,68 @@
+/*
+ * 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.pin.gui;
+
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.PINSpec;
+
+public abstract class DummyChangePINGUI implements ModifyPINGUI {
+
+  @Override
+  public void validKeyPressed() {
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
+
+  @Override
+  public void correctionButtonPressed() {
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
+
+  @Override
+  public void allKeysCleared() {
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
+
+  @Override
+  public void finish() {
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
+
+  @Override
+  public void finishDirect() {
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
+
+  @Override
+  public void modifyPINDirect(PINSpec spec, int retries) throws CancelledException, InterruptedException {
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
+
+  @Override
+  public void enterCurrentPIN(PINSpec spec, int retries) {
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
+
+  @Override
+  public void enterNewPIN(PINSpec spec) {
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
+
+  @Override
+  public void confirmNewPIN(PINSpec spec) {
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
+}
\ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/DummyPINGUI.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/DummyPINGUI.java
new file mode 100644
index 00000000..4d99b5c1
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/DummyPINGUI.java
@@ -0,0 +1,48 @@
+/*
+ * 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.pin.gui;
+
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.PINSpec;
+
+public abstract class DummyPINGUI implements PINGUI {
+
+   @Override
+  public void enterPINDirect(PINSpec spec, int retries) throws CancelledException, InterruptedException {
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
+
+  @Override
+  public void enterPIN(PINSpec spec, int retries) throws CancelledException, InterruptedException {
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
+
+  @Override
+  public void validKeyPressed() {
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
+
+  @Override
+  public void correctionButtonPressed() {
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
+
+  @Override
+  public void allKeysCleared() {
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
+}
\ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InterruptPINProvider.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InterruptPINProvider.java
new file mode 100644
index 00000000..5706b888
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InterruptPINProvider.java
@@ -0,0 +1,34 @@
+/*
+ * 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.pin.gui;
+
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.PINSpec;
+
+@SuppressWarnings("restriction")
+public class InterruptPINProvider extends DummyPINGUI implements PINGUI {
+
+  public InterruptPINProvider() {
+  }
+
+  @Override
+  public char[] providePIN(PINSpec spec, int retries)
+          throws CancelledException, InterruptedException {
+    throw new InterruptedException("interrupted by cancelPINProvider");
+  }
+
+}
\ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidChangePINProvider.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidChangePINProvider.java
new file mode 100644
index 00000000..69c9f42a
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidChangePINProvider.java
@@ -0,0 +1,56 @@
+/*
+ * 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.pin.gui;
+
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.PINSpec;
+
+public class InvalidChangePINProvider extends DummyChangePINGUI implements ModifyPINGUI {
+
+  int provided = 0;
+  int numWrongTries = 0;
+  char[] pin;
+  char[] oldPin;
+
+  /** emulate ChangePinProvider */
+  public InvalidChangePINProvider(char[] oldPin, char[] newPin, int numWrongTries) {
+    super();
+    this.pin = newPin;
+    this.oldPin = oldPin;
+    this.numWrongTries = numWrongTries;
+  }
+
+  @Override
+  public char[] provideCurrentPIN(PINSpec spec, int retries)
+          throws CancelledException, InterruptedException {
+    if (provided >= numWrongTries) {
+      throw new CancelledException("Number of wrong tries reached: " + provided);
+    } else {
+      provided++;
+      return oldPin;
+    }
+  }
+
+  public int getProvided() {
+    return provided;
+  }
+
+  @Override
+  public char[] provideNewPIN(PINSpec spec) {
+    return pin;
+  }
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidPINProvider.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidPINProvider.java
new file mode 100644
index 00000000..db01fd0d
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidPINProvider.java
@@ -0,0 +1,48 @@
+/*
+ * 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.pin.gui;
+
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.PINSpec;
+
+public class InvalidPINProvider extends DummyPINGUI implements PINGUI {
+
+  int provided = 0;
+  int numWrongTries = 0;
+  char[] pin;
+
+  public InvalidPINProvider(char[] pin, int numWrongTries) {
+    super();
+    this.pin = pin;
+    this.numWrongTries = numWrongTries;
+  }
+
+  @Override
+  public char[] providePIN(PINSpec spec, int retries)
+          throws CancelledException, InterruptedException {
+    if (provided >= numWrongTries) {
+      throw new CancelledException("Number of wrong tries reached: " + provided);
+    } else {
+      provided++;
+      return pin;
+    }
+  }
+
+  public int getProvided() {
+    return provided;
+  }
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/SMCCTestPINProvider.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/SMCCTestPINProvider.java
new file mode 100644
index 00000000..dffc90d7
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/SMCCTestPINProvider.java
@@ -0,0 +1,43 @@
+/*
+ * 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.pin.gui;
+
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.PINSpec;
+
+public class SMCCTestPINProvider extends DummyPINGUI implements PINGUI {
+
+  public int provided = 0;
+  char[] pin;
+
+  public SMCCTestPINProvider(char[] pin) {
+    this.pin = pin;
+  }
+
+  @Override
+  public char[] providePIN(PINSpec spec, int retries)
+          throws CancelledException, InterruptedException {
+    provided++;
+    return pin;
+  }
+
+  public int getProvided() {
+    return provided;
+  }
+
+ 
+}
\ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSAppl.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSAppl.java
index 2ca63eea..62528e6e 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSAppl.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSAppl.java
@@ -69,27 +69,4 @@ public abstract class STARCOSAppl extends AbstractAppl implements CardAppl {
       pin.next().state = PIN.STATE_RESET;
     }
   }
-  
-  public void setPin(int kid, char[] value) {
-    PIN pin = pins.get(kid);
-    if (pin != null) {
-      if (value == null) {
-        pin.pin = null;
-      } else {
-        byte[] b = new byte[8];
-        b[0] = (byte) (0x20 | value.length);
-        for(int i = 1, j = 0; i < b.length; i++) {
-          int h = ((j < value.length) 
-                  ? Character.digit(value[j++], 10) 
-                  : 0x0F);
-          int l = ((j < value.length) 
-                  ? Character.digit(value[j++], 10) 
-                  : 0x0F);
-          b[i] = (byte) ((h << 4) | l);
-        }
-        pin.pin = b;
-      }
-    }
-  }
-
 }
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplGewoehnlicheSignatur.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplGewoehnlicheSignatur.java
index cec305da..8741dd2d 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplGewoehnlicheSignatur.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplGewoehnlicheSignatur.java
@@ -16,7 +16,6 @@
 */
 package at.gv.egiz.smcc.starcos;
 
-import java.io.UnsupportedEncodingException;
 import java.util.Arrays;
 import java.util.Random;
 
@@ -200,12 +199,18 @@ public class STARCOSApplGewoehnlicheSignatur extends STARCOSAppl {
   
 
   protected byte[] EF_C_X509_CH_AUT = new byte[2000];
-  
-  public STARCOSApplGewoehnlicheSignatur(STARCOSCardChannelEmul channel) {
+
+  protected byte[] dst;
+
+  public static final byte[] DST = new byte[] { (byte) 0x84, (byte) 0x03, (byte) 0x80, (byte) 0x02, (byte) 0x00, (byte) 0x89, (byte) 0x03, (byte) 0x13, (byte) 0x35, (byte) 0x10};
+  public static final byte[] DST_G3 = new byte[] { (byte) 0x84, (byte) 0x03, (byte) 0x80, (byte) 0x02, (byte) 0x00, (byte) 0x80, (byte) 0x01, (byte) 0x04 };
+
+  public STARCOSApplGewoehnlicheSignatur(STARCOSCardChannelEmul channel, byte[] dst) {
     super(channel);
     // Files
     System.arraycopy(C_X509_CH_AUT, 0, EF_C_X509_CH_AUT, 0, C_X509_CH_AUT.length);
     putFile(new File(FID_EF_C_X509_CH_AUT, EF_C_X509_CH_AUT, FCI_EF_C_X509_CH_AUT));
+    this.dst = dst;
   }
 
   @Override
@@ -240,12 +245,19 @@ public class STARCOSApplGewoehnlicheSignatur extends STARCOSAppl {
       case 0x81:
         // EXTERNAL AUTHENTICATE
       }
+    case 0xAA:
+      switch (command.getP1()) {
+      case 0x41: 
+        if (Arrays.equals(new byte[] {(byte) 0x80, (byte) 0x01, (byte) 0x10}, command.getData())) {
+          return new ResponseAPDU(new byte[] {(byte) 0x90, (byte) 0x00});
+        }
+      default:
+        return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x80});
+      }
     case 0xB6:
       switch (command.getP1()) {
       case 0x41: {
         // PSO - COMPUTE DIGITAL SIGNATURE
-        byte[] dst = new byte[] { (byte) 0x84, (byte) 0x03, (byte) 0x80,
-            (byte) 0x02, (byte) 0x00, (byte) 0x89, (byte) 0x03, (byte) 0x13, (byte) 0x35, (byte) 0x10};
         if (Arrays.equals(dst, command.getData())) {
           securityEnv = command.getData();
           return new ResponseAPDU(new byte[] {(byte) 0x90, (byte) 0x00});
@@ -328,5 +340,10 @@ public class STARCOSApplGewoehnlicheSignatur extends STARCOSAppl {
     
   }
 
+  @Override
+  public void setPin(int kid, char[] value) {
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
+
   
 }
\ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplInfobox.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplInfobox.java
index b7835a43..c470351a 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplInfobox.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplInfobox.java
@@ -156,5 +156,10 @@ public class STARCOSApplInfobox extends STARCOSAppl {
     throw new CardException("Not supported.");
   }
 
+  @Override
+  public void setPin(int kid, char[] value) {
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
+
   
 }
\ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplSichereSignatur.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplSichereSignatur.java
index 9fb5ad37..4036ca41 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplSichereSignatur.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSApplSichereSignatur.java
@@ -213,16 +213,14 @@ public class STARCOSApplSichereSignatur extends STARCOSAppl {
 
   protected byte[] EF_C_X509_CH_DS = new byte[2000];
   
-  public STARCOSApplSichereSignatur(STARCOSCardChannelEmul channel) {
+  public STARCOSApplSichereSignatur(STARCOSCardChannelEmul channel, byte[] SS_pin, int pinState) {
     super(channel);
     // Files
     System.arraycopy(C_X509_CH_DS, 0, EF_C_X509_CH_DS, 0, C_X509_CH_DS.length);
     putFile(new File(FID_EF_C_X509_CH_DS, EF_C_X509_CH_DS, FCI_EF_C_X509_CH_DS));
     
     // PINs
-    pins.put(KID_PIN_SS, new PIN(new byte[] { (byte) 0x24, (byte) 0x12,
-        (byte) 0x34, (byte) 0x56, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
-        (byte) 0xFF }, KID_PIN_SS, 3));
+    pins.put(KID_PIN_SS, new PIN(SS_pin, KID_PIN_SS, 3, pinState));
   }
 
   @Override
@@ -344,4 +342,34 @@ public class STARCOSApplSichereSignatur extends STARCOSAppl {
   
   }
 
+  /**
+   * set and activate pin
+   * @param value if null, pin will be set to NOTACTIVE
+   */
+  @Override
+  public void setPin(int kid, char[] value) {
+    PIN pin = pins.get(kid);
+    if (pin != null) {
+      if (value == null) {
+//        pin.pin = null;
+        //TransportPIN
+//        pin.pin = new byte[] { (byte) 0x26, (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
+        pin.state = PIN.STATE_PIN_NOTACTIVE;
+      } else {
+        byte[] b = new byte[8];
+        b[0] = (byte) (0x20 | value.length);
+        for(int i = 1, j = 0; i < b.length; i++) {
+          int h = ((j < value.length)
+                  ? Character.digit(value[j++], 10)
+                  : 0x0F);
+          int l = ((j < value.length)
+                  ? Character.digit(value[j++], 10)
+                  : 0x0F);
+          b[i] = (byte) ((h << 4) | l);
+        }
+        pin.pin = b;
+        pin.state = PIN.STATE_RESET;
+      }
+    }
+  }
 }
\ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardChannelEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardChannelEmul.java
index 89030894..2e0c54eb 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardChannelEmul.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardChannelEmul.java
@@ -16,7 +16,6 @@
 */
 package at.gv.egiz.smcc.starcos;
 
-import java.io.UnsupportedEncodingException;
 import java.util.Arrays;
 import java.util.HashMap;
 
@@ -30,6 +29,8 @@ import at.gv.egiz.smcc.CardChannelEmul;
 import at.gv.egiz.smcc.CardEmul;
 import at.gv.egiz.smcc.File;
 import at.gv.egiz.smcc.PIN;
+import java.util.ArrayList;
+import java.util.List;
 
 @SuppressWarnings("restriction")
 public class STARCOSCardChannelEmul extends CardChannelEmul {
@@ -40,14 +41,13 @@ public class STARCOSCardChannelEmul extends CardChannelEmul {
    * 
    */
   protected CardEmul cardEmul;
-  
+
+  public final List<File> globalFiles = new ArrayList<File>();
   public final HashMap<Integer, PIN> globalPins = new HashMap<Integer, PIN>();
 
-  public STARCOSCardChannelEmul(CardEmul cardEmul) {
+  public STARCOSCardChannelEmul(CardEmul cardEmul, byte[] Glob_PIN, int PIN_STATE) {
     this.cardEmul = cardEmul;
-    globalPins.put(KID_PIN_Glob, new PIN(new byte[] { (byte) 0x24, (byte) 0x00,
-        (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
-        (byte) 0xFF }, KID_PIN_Glob, 10));
+    globalPins.put(KID_PIN_Glob, new PIN(Glob_PIN, KID_PIN_Glob, 10, PIN_STATE));
  }
 
   @Override
@@ -88,6 +88,21 @@ public class STARCOSCardChannelEmul extends CardChannelEmul {
           }
         }
         return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x82});
+      } else if (globalFiles != null) {
+        if (command.getP2() != 0x04) {
+          throw new CardException("Not supported.");
+        }
+        for (File file : globalFiles) {
+          if (Arrays.equals(fid, file.fid)) {
+            currentFile = file;
+            byte[] response = new byte[file.fcx.length + 2];
+            System.arraycopy(file.fcx, 0, response, 0, file.fcx.length);
+            response[file.fcx.length] = (byte) 0x90;
+            response[file.fcx.length + 1] = (byte) 0x00;
+            return new ResponseAPDU(response);
+          }
+        }
+        return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x82});
       } else {
         throw new CardException("Not supported.");
       }
@@ -121,6 +136,23 @@ public class STARCOSCardChannelEmul extends CardChannelEmul {
     
   }
   
+  protected ResponseAPDU cmdREAD_RECORD(CommandAPDU command) throws CardException {
+    if (command.getINS() != 0xB2) {
+      throw new IllegalArgumentException("INS has to be 0xB2");
+    }
+    if (currentFile == null) {
+      return new ResponseAPDU(new byte[]{ (byte) 0x69, (byte) 0x86 });
+    }
+    if (command.getP1() != 0x01 || command.getP2() != 0x04) {
+      throw new CardException("Not implemented.");
+    }
+    byte[] response = new byte[currentFile.file.length + 2];
+    System.arraycopy(currentFile.file, 0, response, 0, currentFile.file.length);
+    response[currentFile.file.length] = (byte) 0x90;
+    response[currentFile.file.length + 1] = (byte) 0x00;
+    return new ResponseAPDU(response);
+  }
+
   protected ResponseAPDU cmdREAD_BINARY(CommandAPDU command) throws CardException {
 
     if (command.getINS() != 0xB0) {
@@ -192,6 +224,10 @@ public class STARCOSCardChannelEmul extends CardChannelEmul {
       case 0xB0:
         return cmdREAD_BINARY(command);
       
+      // READ RECORD
+      case 0xB2:
+        return cmdREAD_RECORD(command);
+
       // VERIFY
       case 0x20:
         return cmdVERIFY(command);
@@ -248,9 +284,15 @@ public class STARCOSCardChannelEmul extends CardChannelEmul {
     }
     
     if (pin != null) {
-  
-      if (reference.length == 0) {
-        return new ResponseAPDU(new byte[] { (byte) 0x63, (byte) (pin.kfpc | 0xC0)});
+
+      if (reference == null || reference.length == 0) {
+        if (pin.state == PIN.STATE_PIN_NOTACTIVE) {
+          return new ResponseAPDU(new byte[] { (byte) 0x69, (byte) 0x84 });
+        } else if (pin.state == PIN.STATE_PIN_BLOCKED) {
+          return new ResponseAPDU(new byte[] { (byte) 0x63, (byte) 0xc0 });
+        } else {
+          return new ResponseAPDU(new byte[] { (byte) 0x63, (byte) (pin.kfpc | 0xC0)});
+        }
       }
       
       if (reference.length != 8) {
@@ -264,7 +306,7 @@ public class STARCOSCardChannelEmul extends CardChannelEmul {
   
         case PIN.STATE_RESET:
           pin.state = PIN.STATE_PIN_VERIFIED;
-          
+
         default:
           pin.kfpc = 10;
           return new ResponseAPDU(new byte[] { (byte) 0x90, (byte) 0x00 });
@@ -321,7 +363,20 @@ public class STARCOSCardChannelEmul extends CardChannelEmul {
         return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00});
       }
       
-      response = verifyPin(0xFF & command.getP2(), data);
+      PIN pin;
+      if (currentAppl != null) {
+        pin = currentAppl.pins.get(command.getP2());
+      } else {
+        pin = globalPins.get(command.getP2());
+      }
+      if (pin.state == PIN.STATE_PIN_NOTACTIVE) {
+        pin.pin = data;
+        pin.state = PIN.STATE_RESET;
+        response = new ResponseAPDU(new byte[] { (byte) 0x90, (byte) 0x00 });
+      } else {
+        // P1 == 0x01 not allowed on active pin (?)
+        response = new ResponseAPDU(new byte[] { (byte) 0x6A, (byte) 0x86});
+      }
 
     } else if (command.getP1() == 0x00) {
       
@@ -330,21 +385,22 @@ public class STARCOSCardChannelEmul extends CardChannelEmul {
       }
   
       response = verifyPin(0xFF & command.getP2(), Arrays.copyOf(data, 8));
-    
+
+      if (response.getSW() == 0x9000) {
+        PIN pin;
+        if (currentAppl != null) {
+          pin = currentAppl.pins.get(command.getP2());
+        } else {
+          pin = globalPins.get(command.getP2());
+        }
+        pin.pin = Arrays.copyOfRange(data, 8, 16);
+        pin.state = PIN.STATE_PIN_VERIFIED;
+      }
+
     } else {
       return new ResponseAPDU(new byte[] { (byte) 0x6A, (byte) 0x81 });
     }
      
-    if (response.getSW() == 0x9000) {
-      PIN pin;
-      if (currentAppl != null) {
-        pin = currentAppl.pins.get(command.getP2());
-      } else {
-        pin = globalPins.get(command.getP2());
-      }
-      pin.pin = Arrays.copyOfRange(data, 8, 16);
-    }
-
     return response;
     
   }
@@ -353,7 +409,10 @@ public class STARCOSCardChannelEmul extends CardChannelEmul {
     PIN pin = globalPins.get(kid);
     if (pin != null) {
       if (value == null) {
-        pin.pin = null;
+//        pin.pin = null;
+        //TransportPIN
+//        pin.pin = new byte[] { (byte) 0x24, (byte) 0x12, (byte) 0x34, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
+        pin.state = PIN.STATE_PIN_NOTACTIVE;
       } else {
         byte[] b = new byte[8];
         b[0] = (byte) (0x20 | value.length);
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardEmul.java
index 7b2f3fbe..5963fb63 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardEmul.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardEmul.java
@@ -21,30 +21,34 @@ import javax.smartcardio.ATR;
 
 import at.gv.egiz.smcc.CardChannelEmul;
 import at.gv.egiz.smcc.CardEmul;
+import at.gv.egiz.smcc.PIN;
 
 @SuppressWarnings("restriction")
 public class STARCOSCardEmul extends CardEmul {
-  
+
+  public static byte[] DEFAULT_SS_PIN = new byte[] { (byte) 0x26, (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
+  public static byte[] DEFAULT_Glob_PIN = new byte[] { (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
+
   protected static ATR ATR = new ATR(new byte[] {
       (byte) 0x3b, (byte) 0xbd, (byte) 0x18, (byte) 0x00, (byte) 0x81, (byte) 0x31, (byte) 0xfe, (byte) 0x45, 
       (byte) 0x80, (byte) 0x51, (byte) 0x02, (byte) 0x67, (byte) 0x05, (byte) 0x18, (byte) 0xb1, (byte) 0x02, 
       (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x81, (byte) 0x05, (byte) 0x31
   });
-  
+
   public STARCOSCardEmul() {
-    applications.add(new STARCOSApplSichereSignatur((STARCOSCardChannelEmul) channel));
+    this(DEFAULT_SS_PIN, DEFAULT_Glob_PIN, PIN.STATE_RESET);
+  }
+
+  public STARCOSCardEmul(byte[] SS_PIN, byte[] Glob_PIN, int PIN_STATE) {
+    channel = new STARCOSCardChannelEmul(this, Glob_PIN, PIN_STATE);
+    applications.add(new STARCOSApplSichereSignatur((STARCOSCardChannelEmul) channel, SS_PIN, PIN_STATE));
     applications.add(new STARCOSApplInfobox((STARCOSCardChannelEmul) channel));
-    applications.add(new STARCOSApplGewoehnlicheSignatur((STARCOSCardChannelEmul) channel));
+    applications.add(new STARCOSApplGewoehnlicheSignatur((STARCOSCardChannelEmul) channel,
+            STARCOSApplGewoehnlicheSignatur.DST));
   }
 
   @Override
   public ATR getATR() {
     return ATR;
   }
-
-  @Override
-  protected CardChannelEmul newCardChannel(CardEmul cardEmul) {
-    return new STARCOSCardChannelEmul(this);
-  }
-
 }
\ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardTest.java
index b7dc9a0c..154884d4 100644
--- a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardTest.java
+++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardTest.java
@@ -22,12 +22,9 @@ import static org.junit.Assert.assertTrue;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.Arrays;
 
-import javax.smartcardio.CardChannel;
 
 import org.junit.Test;
 
@@ -36,25 +33,20 @@ import at.gv.egiz.smcc.CardEmul;
 import at.gv.egiz.smcc.CardNotSupportedException;
 import at.gv.egiz.smcc.CardTerminalEmul;
 import at.gv.egiz.smcc.CardTest;
+import at.gv.egiz.smcc.pin.gui.ChangePINProvider;
+import at.gv.egiz.smcc.pin.gui.InvalidChangePINProvider;
+import at.gv.egiz.smcc.pin.gui.InvalidPINProvider;
 import at.gv.egiz.smcc.LockedException;
 import at.gv.egiz.smcc.NotActivatedException;
+import at.gv.egiz.smcc.PIN;
 import at.gv.egiz.smcc.PINFormatException;
 import at.gv.egiz.smcc.PINMgmtSignatureCard;
 import at.gv.egiz.smcc.PINSpec;
-import at.gv.egiz.smcc.STARCOSCard;
 import at.gv.egiz.smcc.SignatureCard;
 import at.gv.egiz.smcc.SignatureCardException;
 import at.gv.egiz.smcc.SignatureCardFactory;
-import at.gv.egiz.smcc.CardTest.TestChangePINProvider;
-import at.gv.egiz.smcc.CardTest.TestPINProvider;
-import at.gv.egiz.smcc.PINProvider;
+import at.gv.egiz.smcc.pin.gui.SMCCTestPINProvider;
 import at.gv.egiz.smcc.SignatureCard.KeyboxName;
-import at.gv.egiz.smcc.acos.A03ApplDEC;
-import at.gv.egiz.smcc.acos.A04ApplDEC;
-import at.gv.egiz.smcc.acos.A04ApplSIG;
-import at.gv.egiz.smcc.acos.ACOSAppl;
-import at.gv.egiz.smcc.acos.ACOSApplDEC;
-import at.gv.egiz.smcc.acos.ACOSApplSIG;
 import org.junit.Ignore;
 
 public class STARCOSCardTest extends CardTest {
@@ -69,7 +61,17 @@ public class STARCOSCardTest extends CardTest {
     assertTrue(signatureCard instanceof PINMgmtSignatureCard);
     return signatureCard;
   }
-  
+
+  protected SignatureCard createSignatureCard(byte[] SS_PIN, byte[] Glob_PIN, int pinState)
+      throws CardNotSupportedException {
+    SignatureCardFactory factory = SignatureCardFactory.getInstance();
+    STARCOSCardEmul card = new STARCOSCardEmul(SS_PIN, Glob_PIN, pinState);
+    SignatureCard signatureCard = factory.createSignatureCard(card,
+        new CardTerminalEmul(card));
+    assertTrue(signatureCard instanceof PINMgmtSignatureCard);
+    return signatureCard;
+  }
+
   @Test
   public void testGetInfoboxIdentityLinkEmpty() throws SignatureCardException,
       InterruptedException, CardNotSupportedException {
@@ -82,7 +84,7 @@ public class STARCOSCardTest extends CardTest {
     appl.clearInfobox();
 
     byte[] idlink = signatureCard.getInfobox("IdentityLink",
-        new TestPINProvider(pin), null);
+        new SMCCTestPINProvider(pin), null);
     assertNull(idlink);
 
   }
@@ -98,10 +100,10 @@ public class STARCOSCardTest extends CardTest {
     STARCOSApplInfobox appl = (STARCOSApplInfobox) card.getApplication(STARCOSAppl.AID_Infobox);
     appl.setInfoboxHeader((byte) 0xFF);
 
-    signatureCard.getInfobox("IdentityLink", new TestPINProvider(pin), null);
+    signatureCard.getInfobox("IdentityLink", new SMCCTestPINProvider(pin), null);
 
   }
- 
+
   @Test
   public void testGetCerts() throws SignatureCardException,
       InterruptedException, CardNotSupportedException {
@@ -145,7 +147,7 @@ public class STARCOSCardTest extends CardTest {
     signatureCard.getCertificate(KeyboxName.CERITIFIED_KEYPAIR);
 
   }
-  
+
   @Test
   public void testSignSichereSignatur() throws SignatureCardException,
       InterruptedException, CardNotSupportedException,
@@ -160,7 +162,7 @@ public class STARCOSCardTest extends CardTest {
 
     byte[] signature = signatureCard.createSignature(new ByteArrayInputStream("MOCCA"
         .getBytes("ASCII")),
-        KeyboxName.SECURE_SIGNATURE_KEYPAIR, new TestPINProvider(pin), null);
+        KeyboxName.SECURE_SIGNATURE_KEYPAIR, new SMCCTestPINProvider(pin), null);
 
     assertNotNull(signature);
 
@@ -180,12 +182,12 @@ public class STARCOSCardTest extends CardTest {
 
     byte[] signature = signatureCard.createSignature(new ByteArrayInputStream("MOCCA"
         .getBytes("ASCII")),
-        KeyboxName.CERITIFIED_KEYPAIR, new TestPINProvider(pin), null);
+        KeyboxName.CERITIFIED_KEYPAIR, new SMCCTestPINProvider(pin), null);
 
     assertNotNull(signature);
 
   }
-  
+
   @Test(expected = LockedException.class)
   public void testSignSichereSignaturInvalidPin() throws SignatureCardException,
       InterruptedException, CardNotSupportedException,
@@ -193,7 +195,7 @@ public class STARCOSCardTest extends CardTest {
 
     SignatureCard signatureCard = createSignatureCard();
 
-    TestPINProvider pinProvider = new TestPINProvider("000000".toCharArray());
+    SMCCTestPINProvider pinProvider = new SMCCTestPINProvider("000000".toCharArray());
 
     signatureCard.createSignature(new ByteArrayInputStream("MOCCA"
         .getBytes("ASCII")), KeyboxName.SECURE_SIGNATURE_KEYPAIR,
@@ -208,7 +210,7 @@ public class STARCOSCardTest extends CardTest {
 
     SignatureCard signatureCard = createSignatureCard();
 
-    TestPINProvider pinProvider = new TestPINProvider("1234".toCharArray());
+    SMCCTestPINProvider pinProvider = new SMCCTestPINProvider("1234".toCharArray());
 
     signatureCard.createSignature(new ByteArrayInputStream("MOCCA"
         .getBytes("ASCII")), KeyboxName.CERITIFIED_KEYPAIR,
@@ -221,12 +223,9 @@ public class STARCOSCardTest extends CardTest {
       InterruptedException, CardNotSupportedException,
       NoSuchAlgorithmException, IOException {
 
-    SignatureCard signatureCard = createSignatureCard();
-    CardEmul card = (CardEmul) signatureCard.getCard();
-    STARCOSApplSichereSignatur appl = (STARCOSApplSichereSignatur) card.getApplication(STARCOSApplSichereSignatur.AID_SichereSignatur);
-    appl.setPin(STARCOSApplSichereSignatur.KID_PIN_SS, null);
+    SignatureCard signatureCard = createSignatureCard(null, null, PIN.STATE_PIN_BLOCKED);
 
-    TestPINProvider pinProvider = new TestPINProvider("000000".toCharArray());
+    SMCCTestPINProvider pinProvider = new SMCCTestPINProvider("000000".toCharArray());
     assertTrue(pinProvider.getProvided() <= 0);
 
     signatureCard.createSignature(new ByteArrayInputStream("MOCCA"
@@ -240,68 +239,79 @@ public class STARCOSCardTest extends CardTest {
       InterruptedException, CardNotSupportedException,
       NoSuchAlgorithmException, IOException {
 
-    SignatureCard signatureCard = createSignatureCard();
-    CardEmul card = (CardEmul) signatureCard.getCard();
-    STARCOSCardChannelEmul channel = (STARCOSCardChannelEmul) card.getBasicChannel();
-    channel.setPin(STARCOSCardChannelEmul.KID_PIN_Glob, null);
-
-    TestPINProvider pinProvider = new TestPINProvider("0000".toCharArray());
+    SignatureCard signatureCard = createSignatureCard(null, null, PIN.STATE_PIN_BLOCKED);
+    
+    SMCCTestPINProvider pinProvider = new SMCCTestPINProvider("0000".toCharArray());
 
     signatureCard.createSignature(new ByteArrayInputStream("MOCCA"
         .getBytes("ASCII")), KeyboxName.CERITIFIED_KEYPAIR,
         pinProvider, null);
 
   }
-  
+
   @Test
   public void testChangePin() throws CardNotSupportedException,
       LockedException, NotActivatedException, CancelledException,
       PINFormatException, SignatureCardException, InterruptedException {
 
-    char[] defaultPin = "123456".toCharArray();
-
-    PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard();
-    CardEmul card = (CardEmul) signatureCard.getCard();
-    STARCOSCardChannelEmul channel = (STARCOSCardChannelEmul) card.getBasicChannel();
-    channel.setPin(STARCOSCardChannelEmul.KID_PIN_Glob, defaultPin);
-    STARCOSApplSichereSignatur appl = (STARCOSApplSichereSignatur) card.getApplication(STARCOSApplSichereSignatur.AID_SichereSignatur);
-    appl.setPin(STARCOSApplSichereSignatur.KID_PIN_SS, defaultPin);
+    // set all initial pins to DEFAULT_SS_PIN (123456)
+    PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard(
+            STARCOSCardEmul.DEFAULT_SS_PIN, STARCOSCardEmul.DEFAULT_SS_PIN, PIN.STATE_RESET);
     
     for (PINSpec pinSpec : signatureCard.getPINSpecs()) {
 
-      char[] pin = defaultPin;
+      char[] pin = "123456".toCharArray();
 
       for (int i = pinSpec.getMinLength(); i <= pinSpec.getMaxLength(); i++) {
-        signatureCard.verifyPIN(pinSpec, new TestPINProvider(pin));
+        signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(pin));
         char[] newPin = new char[i];
         Arrays.fill(newPin, '0');
         signatureCard
-            .changePIN(pinSpec, new TestChangePINProvider(pin, newPin));
-        signatureCard.verifyPIN(pinSpec, new TestPINProvider(newPin));
+            .changePIN(pinSpec, new ChangePINProvider(pin, newPin));
+        signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(newPin));
         pin = newPin;
       }
     }
   }
 
   @Test
-  public void testVerifyInvalidPin() throws CardNotSupportedException,
+  @Override
+  public void testActivatePin() throws CardNotSupportedException,
       LockedException, NotActivatedException, CancelledException,
       PINFormatException, SignatureCardException, InterruptedException {
 
-    char[] defaultPin = "123456".toCharArray();
+    PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard(
+            null, null, PIN.STATE_PIN_NOTACTIVE);
+
+    for (PINSpec pinSpec : signatureCard.getPINSpecs()) {
+
+      char[] pin = "1234567890".substring(0, pinSpec.getMinLength()).toCharArray();
+
+      boolean notActive = false;
+      try {
+        signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(pin));
+      } catch (NotActivatedException ex) {
+        notActive = true;
+      }
+      assertTrue(notActive);
+
+      signatureCard.activatePIN(pinSpec, new ChangePINProvider(null, pin));
+      signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(pin));
+    }
+  }
+
+  @Test
+  public void testVerifyInvalidPin() throws CardNotSupportedException,
+      LockedException, NotActivatedException, CancelledException,
+      PINFormatException, SignatureCardException, InterruptedException {
 
     PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard();
-    CardEmul card = (CardEmul) signatureCard.getCard();
-    STARCOSCardChannelEmul channel = (STARCOSCardChannelEmul) card.getBasicChannel();
-    channel.setPin(STARCOSCardChannelEmul.KID_PIN_Glob, defaultPin);
-    STARCOSApplSichereSignatur appl = (STARCOSApplSichereSignatur) card.getApplication(STARCOSApplSichereSignatur.AID_SichereSignatur);
-    appl.setPin(STARCOSApplSichereSignatur.KID_PIN_SS, defaultPin);
 
     for (PINSpec pinSpec : signatureCard.getPINSpecs()) {
 
       char[] invalidPin = "999999".toCharArray();
       int numInvalidTries = 2;
-      TestInvalidPINProvider invalidPinProvider = new TestInvalidPINProvider(invalidPin, numInvalidTries);
+      InvalidPINProvider invalidPinProvider = new InvalidPINProvider(invalidPin, numInvalidTries);
       try {
         signatureCard.verifyPIN(pinSpec, invalidPinProvider);
       } catch (CancelledException ex) {
@@ -315,21 +325,15 @@ public class STARCOSCardTest extends CardTest {
   public void testChangeInvalidPin() throws CardNotSupportedException,
       LockedException, NotActivatedException, CancelledException,
       PINFormatException, SignatureCardException, InterruptedException {
-    char[] defaultPin = "123456".toCharArray();
 
     PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard();
-    CardEmul card = (CardEmul) signatureCard.getCard();
-    STARCOSCardChannelEmul channel = (STARCOSCardChannelEmul) card.getBasicChannel();
-    channel.setPin(STARCOSCardChannelEmul.KID_PIN_Glob, defaultPin);
-    STARCOSApplSichereSignatur appl = (STARCOSApplSichereSignatur) card.getApplication(STARCOSApplSichereSignatur.AID_SichereSignatur);
-    appl.setPin(STARCOSApplSichereSignatur.KID_PIN_SS, defaultPin);
-
+    
     for (PINSpec pinSpec : signatureCard.getPINSpecs()) {
 
       char[] invalidPin = "999999".toCharArray();
       int numInvalidTries = 2;
-      TestInvalidChangePINProvider invalidPinProvider =
-              new TestInvalidChangePINProvider(invalidPin, defaultPin, numInvalidTries);
+      InvalidChangePINProvider invalidPinProvider =
+              new InvalidChangePINProvider(invalidPin, invalidPin, numInvalidTries);
 
       try {
         signatureCard.changePIN(pinSpec, invalidPinProvider);
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardChannelEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardChannelEmul.java
new file mode 100644
index 00000000..dc6836ae
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardChannelEmul.java
@@ -0,0 +1,46 @@
+/*
+ * 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.starcos;
+
+import at.gv.egiz.smcc.CardEmul;
+import at.gv.egiz.smcc.File;
+import at.gv.egiz.smcc.PIN;
+
+/**
+ *
+ * @author clemens
+ */
+public class STARCOSG3CardChannelEmul extends STARCOSCardChannelEmul {
+
+  public STARCOSG3CardChannelEmul(CardEmul cardEmul, byte[] Glob_PIN, int PIN_STATE) {
+    super(cardEmul, Glob_PIN, PIN_STATE);
+
+    // G3 version file
+    byte[] versionFileFID = new byte[]{(byte) 0x00, (byte) 0x32};
+    byte[] versionFile = new byte[]{
+      (byte) 0xa5, (byte) 0x0e, (byte) 0x53, (byte) 0x02, (byte) 0x01, (byte) 0x20, (byte) 0x54, (byte) 0x08,
+      (byte) 0x01, (byte) 0x01, (byte) 0x03, (byte) 0x01, (byte) 0x04, (byte) 0x01, (byte) 0x70, (byte) 0x01};
+    byte[] versionFileFCX = new byte[]{
+      (byte) 0x62, (byte) 0x1a, (byte) 0x80, (byte) 0x02, (byte) 0x00, (byte) 0x14, (byte) 0x82, (byte) 0x05,
+      (byte) 0x44, (byte) 0x41, (byte) 0x00, (byte) 0x14, (byte) 0x01, (byte) 0x83, (byte) 0x02, (byte) 0x00,
+      (byte) 0x32, (byte) 0x88, (byte) 0x01, (byte) 0xd8, (byte) 0x8a, (byte) 0x01, (byte) 0x05, (byte) 0xa1,
+      (byte) 0x03, (byte) 0x8b, (byte) 0x01, (byte) 0x03};
+
+    globalFiles.add(new File(versionFileFID, versionFile, versionFileFCX));
+
+  }
+ }
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardEmul.java
new file mode 100644
index 00000000..7583b3ad
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardEmul.java
@@ -0,0 +1,57 @@
+/*
+ * 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.starcos;
+
+import at.gv.egiz.smcc.CardEmul;
+import javax.smartcardio.ATR;
+
+import at.gv.egiz.smcc.PIN;
+
+@SuppressWarnings("restriction")
+public class STARCOSG3CardEmul extends CardEmul {
+
+  public static byte[] TRANSPORT_SS_PIN = new byte[] { (byte) 0x26, (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
+  public static byte[] TRANSPORT_Glob_PIN = new byte[] { (byte) 0x24, (byte) 0x12, (byte) 0x34, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
+
+  public static byte[] DEFAULT_SS_PIN = TRANSPORT_SS_PIN;
+  public static byte[] DEFAULT_Glob_PIN = new byte[] { (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
+
+  protected static ATR ATR = new ATR(new byte[] {
+      (byte) 0x3b, (byte) 0xbd, (byte) 0x18, (byte) 0x00, (byte) 0x81, (byte) 0x31, (byte) 0xfe, (byte) 0x45,
+      (byte) 0x80, (byte) 0x51, (byte) 0x02, (byte) 0x67, (byte) 0x05, (byte) 0x18, (byte) 0xb1, (byte) 0x02,
+      (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x81, (byte) 0x05, (byte) 0x31
+  });
+
+  public STARCOSG3CardEmul(byte[] SS_PIN, byte[] Glob_PIN, int PIN_STATE){
+    channel = new STARCOSG3CardChannelEmul(this, Glob_PIN, PIN_STATE);
+    applications.add(new STARCOSApplSichereSignatur((STARCOSCardChannelEmul) channel,
+            SS_PIN, PIN_STATE));
+    applications.add(new STARCOSApplInfobox((STARCOSCardChannelEmul) channel));
+    applications.add(new STARCOSApplGewoehnlicheSignatur((STARCOSCardChannelEmul) channel,
+            STARCOSApplGewoehnlicheSignatur.DST_G3));
+  }
+
+
+  public STARCOSG3CardEmul() {
+    this(DEFAULT_SS_PIN, DEFAULT_Glob_PIN, PIN.STATE_RESET);
+  }
+
+  @Override
+  public ATR getATR() {
+    return ATR;
+  }
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardTest.java
new file mode 100644
index 00000000..06744c82
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSG3CardTest.java
@@ -0,0 +1,119 @@
+/*
+* 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.starcos;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+
+import org.junit.Test;
+
+import at.gv.egiz.smcc.CancelledException;
+import at.gv.egiz.smcc.CardEmul;
+import at.gv.egiz.smcc.CardNotSupportedException;
+import at.gv.egiz.smcc.CardTerminalEmul;
+import at.gv.egiz.smcc.CardTest;
+import at.gv.egiz.smcc.pin.gui.ChangePINProvider;
+import at.gv.egiz.smcc.LockedException;
+import at.gv.egiz.smcc.NotActivatedException;
+import at.gv.egiz.smcc.PIN;
+import at.gv.egiz.smcc.PINFormatException;
+import at.gv.egiz.smcc.PINMgmtSignatureCard;
+import at.gv.egiz.smcc.PINSpec;
+import at.gv.egiz.smcc.SignatureCard;
+import at.gv.egiz.smcc.SignatureCardException;
+import at.gv.egiz.smcc.SignatureCardFactory;
+import at.gv.egiz.smcc.pin.gui.SMCCTestPINProvider;
+import org.junit.Ignore;
+
+public class STARCOSG3CardTest extends CardTest {
+
+  @Override
+  protected SignatureCard createSignatureCard()
+      throws CardNotSupportedException {
+    SignatureCardFactory factory = SignatureCardFactory.getInstance();
+    STARCOSG3CardEmul card = new STARCOSG3CardEmul();
+    SignatureCard signatureCard = factory.createSignatureCard(card,
+        new CardTerminalEmul(card));
+    assertTrue(signatureCard instanceof PINMgmtSignatureCard);
+    return signatureCard;
+  }
+
+  protected SignatureCard createSignatureCard(byte[] SS_PIN, byte[] Glob_PIN, int pinState)
+      throws CardNotSupportedException {
+    SignatureCardFactory factory = SignatureCardFactory.getInstance();
+    STARCOSG3CardEmul card = new STARCOSG3CardEmul(SS_PIN, Glob_PIN, pinState);
+    SignatureCard signatureCard = factory.createSignatureCard(card,
+        new CardTerminalEmul(card));
+    assertTrue(signatureCard instanceof PINMgmtSignatureCard);
+    return signatureCard;
+  }
+
+  @Test
+  public void testChangePin() throws CardNotSupportedException,
+      LockedException, NotActivatedException, CancelledException,
+      PINFormatException, SignatureCardException, InterruptedException {
+
+    PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard(
+            STARCOSG3CardEmul.DEFAULT_SS_PIN, STARCOSG3CardEmul.DEFAULT_SS_PIN, PIN.STATE_RESET);
+    
+    for (PINSpec pinSpec : signatureCard.getPINSpecs()) {
+
+      char[] pin = "123456".toCharArray();
+
+      for (int i = pinSpec.getMinLength(); i <= pinSpec.getMaxLength(); i++) {
+        signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(pin));
+        char[] newPin = new char[i];
+        Arrays.fill(newPin, '0');
+        signatureCard
+            .changePIN(pinSpec, new ChangePINProvider(pin, newPin));
+        signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(newPin));
+        pin = newPin;
+      }
+    }
+  }
+
+  @Test
+  @Override
+  public void testActivatePin() throws CardNotSupportedException,
+      LockedException, NotActivatedException, CancelledException,
+      PINFormatException, SignatureCardException, InterruptedException {
+
+    PINMgmtSignatureCard signatureCard = (PINMgmtSignatureCard) createSignatureCard(
+            STARCOSG3CardEmul.TRANSPORT_SS_PIN, STARCOSG3CardEmul.TRANSPORT_SS_PIN, PIN.STATE_PIN_NOTACTIVE);
+    
+    for (PINSpec pinSpec : signatureCard.getPINSpecs()) {
+
+      char[] pin = "123456789".substring(0, pinSpec.getMinLength()).toCharArray();
+      char[] transportPIN = "123456".toCharArray();
+
+      boolean notActive = false;
+      try {
+        signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(pin));
+      } catch (NotActivatedException ex) {
+        notActive = true;
+      }
+      assertTrue(notActive);
+
+      signatureCard.activatePIN(pinSpec, new ChangePINProvider(transportPIN, pin));
+      signatureCard.verifyPIN(pinSpec, new SMCCTestPINProvider(pin));
+    }
+  }
+
+  
+}
-- 
cgit v1.2.3