From 616e06910051528674165319a1d6d161dff5859c Mon Sep 17 00:00:00 2001
From: clemenso <clemenso@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4>
Date: Fri, 27 Mar 2009 17:33:11 +0000
Subject: 1.1-RC6 (pinpad, pinmgmt, secureviewer)

git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@323 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4
---
 smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java   | 130 +++++-----
 .../at/gv/egiz/smcc/AbstractSignatureCard.java     | 220 +++--------------
 .../src/main/java/at/gv/egiz/smcc/STARCOSCard.java | 234 +++++++++++-------
 smcc/src/main/java/at/gv/egiz/smcc/SWCard.java     |  49 +++-
 .../main/java/at/gv/egiz/smcc/SignatureCard.java   |  15 +-
 smcc/src/main/java/at/gv/egiz/smcc/ccid/CCID.java  |  77 ++++++
 .../java/at/gv/egiz/smcc/ccid/DefaultReader.java   | 264 ++++++++++++++++++++
 .../at/gv/egiz/smcc/ccid/GemplusGemPCPinpad.java   |  65 +++++
 .../java/at/gv/egiz/smcc/ccid/ReaderFactory.java   |  35 +++
 .../test/java/at/gv/egiz/smcc/ACOSCardTest.java    | 135 +++++++++++
 .../test/java/at/gv/egiz/smcc/STARCOSCardTest.java | 267 +++++++++++++++++++++
 11 files changed, 1150 insertions(+), 341 deletions(-)
 create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/ccid/CCID.java
 create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java
 create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/ccid/GemplusGemPCPinpad.java
 create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/ccid/ReaderFactory.java
 create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/ACOSCardTest.java
 create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.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 01b9155b..06e4a018 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java
@@ -28,6 +28,7 @@
 //
 package at.gv.egiz.smcc;
 
+import at.gv.egiz.smcc.ccid.CCID;
 import at.gv.egiz.smcc.util.SMCCHelper;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
@@ -41,7 +42,7 @@ import javax.smartcardio.ResponseAPDU;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
-public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
+public class ACOSCard extends AbstractSignatureCard {
 
   private static Log log = LogFactory.getLog(ACOSCard.class);
 
@@ -180,22 +181,23 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
         //new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("inf.pin.name"));
         
         int retries = -1;
-        char[] pin = null;
-        boolean pinRequiered = false;
+        boolean pinRequired = false;
 
         do {
-          if (pinRequiered) {
-            pin = provider.providePIN(spec, retries);
-          }
           try {
             getCard().beginExclusive();
-            return readTLVFile(AID_DEC, EF_INFOBOX, pin, KID_PIN_INF, EF_INFOBOX_MAX_SIZE);
+            if (pinRequired) {
+              char[] pin = provider.providePIN(spec, retries);
+              return readTLVFile(AID_DEC, EF_INFOBOX, pin, spec.getKID(), EF_INFOBOX_MAX_SIZE);
+            } else {
+              return readTLVFile(AID_DEC, EF_INFOBOX, EF_INFOBOX_MAX_SIZE);
+            }
           } catch (FileNotFoundException e) {
             throw new NotActivatedException();
           } catch (SecurityStatusNotSatisfiedException e) {
-            pinRequiered = true;
+            pinRequired = true;
           } catch (VerificationFailedException e) {
-            pinRequiered = true;
+            pinRequired = true;
             retries = e.getRetries();
           } finally {
             getCard().endExclusive();
@@ -402,10 +404,10 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
           throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException {
     try {
       byte[] sw;
-      if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) {
+      if (reader.hasFeature(CCID.FEATURE_VERIFY_PIN_DIRECT)) {
         log.debug("verify PIN on IFD");
-        sw = transmitControlCommand(
-                ifdCtrlCmds.get(FEATURE_VERIFY_PIN_DIRECT),
+        sw = reader.transmitControlCommand(
+                CCID.FEATURE_VERIFY_PIN_DIRECT,
                 getPINVerifyStructure(kid));
 //        int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff;
       } else {
@@ -466,10 +468,10 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
           throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException {
     try {
        byte[] sw;
-      if (ifdSupportsFeature(FEATURE_MODIFY_PIN_DIRECT)) {
+      if (reader.hasFeature(CCID.FEATURE_MODIFY_PIN_DIRECT)) {
         log.debug("modify PIN on IFD");
-        sw = transmitControlCommand(
-                ifdCtrlCmds.get(FEATURE_MODIFY_PIN_DIRECT),
+        sw = reader.transmitControlCommand(
+                CCID.FEATURE_MODIFY_PIN_DIRECT,
                 getPINModifyStructure(kid));
 //        int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff;
       } else {
@@ -543,34 +545,37 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
   }
   
   private byte[] getPINVerifyStructure(byte kid) {
-
-      byte bTimeOut = (byte) 00;            // Default time out
-      byte bTimeOut2 = (byte) 00;           // Default time out
-      byte bmFormatString = (byte) 0x82;      // 1 0001 0 01
+      
+      byte bTimeOut = reader.getbTimeOut();   
+      byte bTimeOut2 = reader.getbTimeOut2(); 
+      byte bmFormatString = (byte) 0x82;      // 1 0000 0 10
                                               // ^------------ System unit = byte
                                               //   ^^^^------- PIN position in the frame = 1 byte
                                               //        ^----- PIN justification left
-                                              //          ^^-- BCD format
-                                              // 1 0000 0 10
                                               //          ^^-- ASCII format
-      byte bmPINBlockString = (byte) 0x08;    // 0100 0111
-                                              // ^^^^--------- PIN length size: 4 bits
-                                              //      ^^^^---- Length PIN = 7 bytes
-      byte bmPINLengthFormat = (byte) 0x04;   // 000 0 0100
+      byte bmPINBlockString = (byte) 0x08;    // 0000 1000
+                                              // ^^^^--------- PIN length size: 0 bits
+                                              //      ^^^^---- Length PIN = 8 bytes
+      byte bmPINLengthFormat = (byte) 0x00;   // 000 0 0000
                                               //     ^-------- System bit units is bit
-                                              //       ^^^^--- PIN length is at the 4th position bit
-      byte wPINMaxExtraDigitL = (byte) 0x04;  // Max=4 digits
-      byte wPINMaxExtraDigitH = (byte) 0x04;  // Min=4 digits
-      byte bEntryValidationCondition = 0x02;  // Max size reach or Validation key pressed
+                                              //       ^^^^--- no PIN length
+      byte wPINMaxExtraDigitL =
+              (reader.getwPINMaxExtraDigitL() < (byte) 0x08) ?
+                reader.getwPINMaxExtraDigitL() : (byte) 0x08;
+      byte wPINMaxExtraDigitH =               
+              (reader.getwPINMaxExtraDigitH() > (byte) 0x00) ?
+                reader.getwPINMaxExtraDigitH() : (byte) 0x00;
+      byte bEntryValidationCondition = 
+              reader.getbEntryValidationCondition();
       byte bNumberMessage = (byte) 0x00;      // No message
-      byte wLangIdL = (byte) 0x0C;            // - English?
-      byte wLangIdH = (byte) 0x04;            // \
-      byte bMsgIndex = (byte) 0x00;           // Default Msg
+      byte wLangIdL = (byte) 0x0C;            
+      byte wLangIdH = (byte) 0x04;            
+      byte bMsgIndex = (byte) 0x00;           
 
       byte[] apdu = new byte[] {
-        (byte) 0x00, (byte) 0x20, (byte) 0x00, kid, (byte) 0x08,  // CLA INS P1 P2 LC
-        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,               // Data
-        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00                // Data
+        (byte) 0x00, (byte) 0x20, (byte) 0x00, kid, (byte) 0x08, 
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,      
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00       
       };
 
       int offset = 0;
@@ -603,40 +608,43 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
   
   public byte[] getPINModifyStructure(byte kid) {
 
-      byte bTimeOut = (byte) 00;            // Default time out
-      byte bTimeOut2 = (byte) 00;           // Default time out
-      byte bmFormatString = (byte) 0x82;      // 1 0001 0 01
+      byte bTimeOut = reader.getbTimeOut();
+      byte bTimeOut2 = reader.getbTimeOut2();
+      byte bmFormatString = (byte) 0x82;      // 1 0000 0 10
                                               // ^------------ System unit = byte
                                               //   ^^^^------- PIN position in the frame = 1 byte
                                               //        ^----- PIN justification left
-                                              //          ^^-- BCD format
-                                              // 1 0000 0 10
                                               //          ^^-- ASCII format
-      byte bmPINBlockString = (byte) 0x08;    // 0100 0111
-                                              // ^^^^--------- PIN length size: 4 bits
-                                              //      ^^^^---- Length PIN = 7 bytes
-      byte bmPINLengthFormat = (byte) 0x00;   // 000 0 0100
+      byte bmPINBlockString = (byte) 0x08;    // 0000 1000
+                                              // ^^^^--------- PIN length size: 0 bits
+                                              //      ^^^^---- Length PIN = 8 bytes
+      byte bmPINLengthFormat = (byte) 0x00;   // 000 0 0000
                                               //     ^-------- System bit units is bit
-                                              //       ^^^^--- PIN length is at the 4th position bit
+                                              //       ^^^^--- no PIN length 
       byte bInsertionOffsetOld = (byte) 0x00; // insertion position offset in bytes
-      byte bInsertionOffsetNew = (byte) 0x00; // insertion position offset in bytes
-      byte wPINMaxExtraDigitL = (byte) 0x04;  // Min=4 digits
-      byte wPINMaxExtraDigitH = (byte) 0x04;  // Max=12 digits
-      byte bConfirmPIN = (byte) 0x00;         // ??? need for confirm pin
-      byte bEntryValidationCondition = 0x02;  // Max size reach or Validation key pressed
-      byte bNumberMessage = (byte) 0x00;      // No message
-      byte wLangIdL = (byte) 0x0C;            // - English?
-      byte wLangIdH = (byte) 0x04;            // \
-      byte bMsgIndex1 = (byte) 0x00;           // Default Msg
-      byte bMsgIndex2 = (byte) 0x00;           // Default Msg
-      byte bMsgIndex3 = (byte) 0x00;           // Default Msg
+      byte bInsertionOffsetNew = (byte) 0x08; 
+      byte wPINMaxExtraDigitL =
+              (reader.getwPINMaxExtraDigitL() < (byte) 0x08) ?
+                reader.getwPINMaxExtraDigitL() : (byte) 0x08;
+      byte wPINMaxExtraDigitH =
+              (reader.getwPINMaxExtraDigitH() > (byte) 0x00) ?
+                reader.getwPINMaxExtraDigitH() : (byte) 0x00;
+      byte bConfirmPIN = (byte) 0x03;
+      byte bEntryValidationCondition =
+              reader.getbEntryValidationCondition();
+      byte bNumberMessage = (byte) 0x03;      
+      byte wLangIdL = (byte) 0x0C;            
+      byte wLangIdH = (byte) 0x04;            
+      byte bMsgIndex1 = (byte) 0x00;           
+      byte bMsgIndex2 = (byte) 0x01;           
+      byte bMsgIndex3 = (byte) 0x02;           
 
       byte[] apdu = new byte[] {
-        (byte) 0x00, (byte) 0x24, (byte) 0x00, kid, (byte) 0x10,  // CLA INS P1 P2 LC
-        (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff,               // Data
-        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,                // ...
-        (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff,               // Data
-        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff                // ...
+        (byte) 0x00, (byte) 0x24, (byte) 0x00, kid, (byte) 0x10,  
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,       
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,       
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,       
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00        
       };
 
       int offset = 0;
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java
index 6587aaf9..47c27369 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java
@@ -28,6 +28,9 @@
 //
 package at.gv.egiz.smcc;
 
+import at.gv.egiz.smcc.ccid.CCID;
+import at.gv.egiz.smcc.ccid.DefaultReader;
+import at.gv.egiz.smcc.ccid.ReaderFactory;
 import at.gv.egiz.smcc.util.SMCCHelper;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -39,6 +42,8 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.ResourceBundle;
 
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import javax.smartcardio.ATR;
 import javax.smartcardio.Card;
 import javax.smartcardio.CardChannel;
@@ -54,14 +59,6 @@ public abstract class AbstractSignatureCard implements SignatureCard {
 
   private static Log log = LogFactory.getLog(AbstractSignatureCard.class);
 
-  static final short GET_FEATURE_REQUEST = 3400;
-  
-  private static int getCtrlCode(short function) {
-    return 0x310000 | ((0xFFFF & function) << 2);
-  }
-
-  protected Map<Byte, Long> ifdCtrlCmds;
-
   protected List<PINSpec> pinSpecs = new ArrayList<PINSpec>();
 
   private ResourceBundle i18n;
@@ -76,7 +73,8 @@ public abstract class AbstractSignatureCard implements SignatureCard {
   /**
    * The card terminal that connects the {@link #card_}.  
    */
-  private CardTerminal cardTerminal;
+//  private CardTerminal cardTerminal;
+  protected CCID reader;
 
   protected AbstractSignatureCard(String resourceBundleName) {
     this.resourceBundleName = resourceBundleName;
@@ -341,16 +339,34 @@ public abstract class AbstractSignatureCard implements SignatureCard {
    */
   protected byte[] readTLVFile(byte[] aid, byte[] ef, int maxLength)
       throws SignatureCardException, InterruptedException, CardException {
-    return readTLVFile(aid, ef, null, (byte) 0, maxLength);
+    // SELECT FILE (AID)
+    selectFileAID(aid);
+
+    // SELECT FILE (EF)
+    ResponseAPDU resp = selectFileFID(ef);
+    if (resp.getSW() == 0x6a82) {
+      // EF not found
+      throw new FileNotFoundException("EF " + toString(ef) + " not found.");
+    } else if (resp.getSW() != 0x9000) {
+      throw new SignatureCardException("SELECT FILE with "
+          + "FID="
+          + toString(ef)
+          + " failed ("
+          + "SW="
+          + Integer.toHexString(resp.getSW()) + ").");
+    }
+
+    return readBinaryTLV(maxLength, (byte) 0x30);
+//    return readTLVFile(aid, ef, null, (byte) 0, maxLength);
   }
 
   /**
-   * Read the content of a TLV file wich may require a PIN.
+   * Read the content of a TLV file wich requires a PIN.
    * 
    * @param aid the application ID (AID)
    * @param ef the elementary file (EF)
    * @param kid the key ID (KID) of the corresponding PIN
-   * @param provider the PINProvider
+   * @param pin the pin or null if VERIFY on pinpad
    * @param spec the PINSpec
    * @param maxLength the maximum length of the file
    * 
@@ -381,12 +397,10 @@ public abstract class AbstractSignatureCard implements SignatureCard {
     }
 
     // VERIFY
-    if (pin != null) {
       int retries = verifyPIN(kid, pin);
       if (retries != -1) {
         throw new VerificationFailedException(retries);
       }
-    }
    
     return readBinaryTLV(maxLength, (byte) 0x30);
       
@@ -443,16 +457,16 @@ public abstract class AbstractSignatureCard implements SignatureCard {
   }
 
   
+  @Override
   public void init(Card card, CardTerminal cardTerminal) {
-    card_ = card;
-    this.cardTerminal = cardTerminal;
+    this.card_ = card;
+    this.reader = ReaderFactory.getReader(card, cardTerminal);
     ATR atr = card.getATR();
     byte[] atrBytes = atr.getBytes();
     if (atrBytes.length >= 6) {
       ifs_ = 0xFF & atr.getBytes()[6];
       log.trace("Setting IFS (information field size) to " + ifs_);
     }
-    ifdCtrlCmds = queryIFDFeatures();
   }
   
   @Override
@@ -464,6 +478,11 @@ public abstract class AbstractSignatureCard implements SignatureCard {
     return card_.getBasicChannel();
   }
 
+  @Override
+  public CCID getReader() {
+    return reader;
+  }
+
   @Override
   public void setLocale(Locale locale) {
     if (locale == null) {
@@ -497,9 +516,7 @@ public abstract class AbstractSignatureCard implements SignatureCard {
       log.debug("Disconnect and reset smart card.");
       card_.disconnect(true);
       log.debug("Reconnect smart card.");
-      if (cardTerminal != null) {
-        card_ = cardTerminal.connect("*");
-      }
+      card_ = reader.connect();
     } catch (CardException e) {
       throw new SignatureCardException("Failed to reset card.", e);
     }
@@ -520,6 +537,7 @@ public abstract class AbstractSignatureCard implements SignatureCard {
         selectFileAID(pinSpec.getContextAID());
       }
 
+      // -1 if ok or unknown
       int retries = verifyPIN(pinSpec.getKID());
       do {
         char[] pin = pinProvider.providePIN(pinSpec, retries);
@@ -611,166 +629,4 @@ public abstract class AbstractSignatureCard implements SignatureCard {
           throws CancelledException, SignatureCardException, InterruptedException {
     throw new SignatureCardException("Unblock not supported yet");
   }
-
-  /////////////////////////////////////////////////////////////////////////////
-  // IFD related code
-  /////////////////////////////////////////////////////////////////////////////
-
-  /**
-   * TODO implement VERIFY_PIN_START/FINISH (feature 0x01/0x02)
-   * @return
-   */
-  @Override
-  public boolean ifdSupportsFeature(byte feature) {
-    if (ifdCtrlCmds != null) {
-      return ifdCtrlCmds.containsKey(feature);
-    }
-    return false;
-  }
-
-  protected Map<Byte, Long> queryIFDFeatures() {
-
-    if (card_ == null) {
-      throw new NullPointerException("Need connected smart card to query IFD features");
-    }
-
-    Map<Byte, Long> ifdFeatures = new HashMap<Byte, Long>();
-
-    try {
-      if (log.isTraceEnabled()) {
-        log.trace("GET_FEATURE_REQUEST CtrlCode " + Integer.toHexString(getCtrlCode(GET_FEATURE_REQUEST)));
-      }
-      byte[] resp = card_.transmitControlCommand(getCtrlCode(GET_FEATURE_REQUEST), new byte[]{});
-
-      if (log.isTraceEnabled()) {
-        log.trace("GET_FEATURE_REQUEST Response " + SMCCHelper.toString(resp));
-      }
-
-      for (int i = 0; i + 5 < resp.length; i += 6) {
-        Byte feature = new Byte(resp[i]);
-        Long ctrlCode = new Long(
-          ((0xFF & resp[i + 2]) << 24) |
-          ((0xFF & resp[i + 3]) << 16) |
-          ((0xFF & resp[i + 4]) << 8) |
-           (0xFF & resp[i + 5]));
-        if (log.isInfoEnabled()) {
-          log.info("IFD supports feature " + Integer.toHexString(feature.byteValue()) +
-                  ": " + Long.toHexString(ctrlCode.longValue()));
-        }
-        ifdFeatures.put(feature, ctrlCode);
-      }
-
-    } catch (CardException ex) {
-      log.debug("Failed to query IFD features: " + ex.getMessage());
-      log.trace(ex);
-      log.info("IFD does not support PINPad");
-      return null;
-    }
-    return ifdFeatures;
-  }
-
-
-  protected byte ifdGetKeyPressed() throws CardException {
-    if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) {
-
-      Long controlCode = (Long) ifdCtrlCmds.get(new Byte((byte) 0x05));
-
-      byte key = 0x00;
-      while (key == 0x00) {
-
-        byte[] resp = card_.transmitControlCommand(controlCode.intValue(), new byte[] {});
-
-        if (resp != null && resp.length > 0) {
-          key = resp[0];
-        }
-      }
-
-      System.out.println("Key: " + key);
-
-    }
-
-    return 0x00;
-  }
-
-  protected byte[] ifdVerifyPINFinish() throws CardException {
-    if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) {
-
-      Long controlCode = (Long) ifdCtrlCmds.get(new Byte((byte) 0x02));
-
-      byte[] resp = card_.transmitControlCommand(controlCode.intValue(), new byte[] {});
-
-      System.out.println("CommandResp: " + toString(resp));
-
-      return resp;
-
-    }
-
-    return null;
-  }
-
-
-  /**
-   * assumes ifdSupportsVerifyPIN() == true
-   * @param pinVerifyStructure
-   * @return
-   * @throws javax.smartcardio.CardException
-   */
-//  protected byte[] ifdVerifyPIN(byte[] pinVerifyStructure) throws CardException {
-//
-////      Long ctrlCode = (Long) ifdFeatures.get(FEATURE_IFD_PIN_PROPERTIES);
-////      if (ctrlCode != null) {
-////        if (log.isTraceEnabled()) {
-////          log.trace("PIN_PROPERTIES CtrlCode " + Integer.toHexString(ctrlCode.intValue()));
-////        }
-////        byte[] resp = card_.transmitControlCommand(ctrlCode.intValue(), new byte[] {});
-////
-////        if (log.isTraceEnabled()) {
-////          log.trace("PIN_PROPERTIES Response " + SMCCHelper.toString(resp));
-////        }
-////      }
-//
-//
-//      Long ctrlCode = (Long) ifdFeatures.get(FEATURE_VERIFY_PIN_DIRECT);
-//      if (ctrlCode == null) {
-//        throw new NullPointerException("no CtrlCode for FEATURE_VERIFY_PIN_DIRECT");
-//      }
-//
-//      if (log.isTraceEnabled()) {
-//        log.trace("VERIFY_PIN_DIRECT CtrlCode " + Integer.toHexString(ctrlCode.intValue()) +
-//                ", PIN_VERIFY_STRUCTURE " + SMCCHelper.toString(pinVerifyStructure));
-//      }
-//      byte[] resp = card_.transmitControlCommand(ctrlCode.intValue(), pinVerifyStructure);
-//
-//      if (log.isTraceEnabled()) {
-//        log.trace("VERIFY_PIN_DIRECT Response " + SMCCHelper.toString(resp));
-//      }
-//      return resp;
-//  }
-
-//  protected Long getControlCode(Byte feature) {
-//    if (ifdFeatures != null) {
-//      return ifdFeatures.get(feature);
-//    }
-//    return null;
-//  }
-
-  protected byte[] transmitControlCommand(Long ctrlCode, byte[] ctrlCommand)
-          throws CardException {
-//    Long ctrlCode = (Long) ifdFeatures.get(feature);
-    if (ctrlCode == null) {
-      throw new NullPointerException("ControlCode " +
-              Integer.toHexString(ctrlCode.intValue()) + " not supported");
-    }
-    if (log.isTraceEnabled()) {
-      log.trace("CtrlCommand (" + Integer.toHexString(ctrlCode.intValue()) +
-              ")  " + SMCCHelper.toString(ctrlCommand));
-    }
-    byte[] resp = card_.transmitControlCommand(ctrlCode.intValue(), ctrlCommand);
-
-    if (log.isTraceEnabled()) {
-      log.trace("CtrlCommand Response " + SMCCHelper.toString(resp));
-    }
-    return resp;
-  }
-
 }
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
index 91245c50..bc6a2316 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
@@ -28,6 +28,7 @@
 //
 package at.gv.egiz.smcc;
 
+import at.gv.egiz.smcc.ccid.DefaultReader;
 import at.gv.egiz.smcc.util.SMCCHelper;
 import java.util.Arrays;
 import javax.smartcardio.CardChannel;
@@ -38,7 +39,7 @@ import javax.smartcardio.ResponseAPDU;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
-public class STARCOSCard extends AbstractSignatureCard implements SignatureCard {
+public class STARCOSCard extends AbstractSignatureCard {
 
   /**
    * Logging facility.
@@ -153,8 +154,8 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
 
   public static final byte KID_PIN_CARD = (byte) 0x01;
 
-  private static final int PINSPEC_CARD = 0;
-  private static final int PINSPEC_SS = 1;
+  public static final int PINSPEC_CARD = 0;
+  public static final int PINSPEC_SS = 1;
 
   /**
    * Creates an new instance.
@@ -217,28 +218,29 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
   
     try {
       if ("IdentityLink".equals(infobox)) {
- 
+
         PINSpec spec = pinSpecs.get(PINSPEC_CARD);
         //new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name"));
-        
+
         int retries = -1;
-        char[] pin = null;
-        boolean pinRequiered = false;
+        boolean pinRequired = false;
 
         do {
-          if (pinRequiered) {
-            pin = provider.providePIN(spec, retries);
-          }
           try {
             getCard().beginExclusive();
-            return readTLVFile(AID_INFOBOX, EF_INFOBOX, pin, KID_PIN_CARD, 2000);
+            if (pinRequired) {
+              char[] pin = provider.providePIN(spec, retries);
+              return readTLVFile(AID_INFOBOX, EF_INFOBOX, pin, spec.getKID(), 2000);
+            } else {
+              return readTLVFile(AID_INFOBOX, EF_INFOBOX, 2000);
+            }
           } catch (FileNotFoundException e) {
             throw new NotActivatedException();
           } catch (SecurityStatusNotSatisfiedException e) {
-            pinRequiered = true;
+            pinRequired = true;
             retries = verifyPIN(KID_PIN_CARD);
           } catch (VerificationFailedException e) {
-            pinRequiered = true;
+            pinRequired = true;
             retries = e.getRetries();
           } finally {
             getCard().endExclusive();
@@ -246,54 +248,43 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
         } while (retries != 0);
 
         throw new LockedException();
-
         
       } else if ("EHIC".equals(infobox)) {
-        
         try {
           getCard().beginExclusive();
           return readTLVFile(AID_SV_PERSONENDATEN, FID_EHIC, 126);
         } finally {
           getCard().endExclusive();
         }
-        
       } else if ("Grunddaten".equals(infobox)) {
-        
         try {
           getCard().beginExclusive();
           return readTLVFile(AID_SV_PERSONENDATEN, FID_GRUNDDATEN, 550);
         } finally {
           getCard().endExclusive();
         }
-        
       } else if ("SV-Personenbindung".equals(infobox)) {
-        
         try {
           getCard().beginExclusive();
           return readTLVFile(AID_SV_PERSONENDATEN, FID_SV_PERSONENBINDUNG, 500);
         } finally {
           getCard().endExclusive();
         }
-        
       } else if ("Status".equals(infobox)) {
-        
         try {
           getCard().beginExclusive();
           return readRecords(AID_SV_PERSONENDATEN, FID_STATUS, 1, 5);
         } finally {
           getCard().endExclusive();
         }
-        
       } else {
         throw new IllegalArgumentException("Infobox '" + infobox
             + "' not supported.");
       }
-      
     } catch (CardException e) {
       log.warn(e);
       throw new SignatureCardException("Failed to access card.", e);
     }
-  
   }
 
   @Override
@@ -466,10 +457,10 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
           throws LockedException, NotActivatedException, SignatureCardException {
     try {
       byte[] sw;
-      if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) {
+      if (reader.hasFeature(DefaultReader.FEATURE_VERIFY_PIN_DIRECT)) {
         log.debug("verify PIN on IFD");
-        sw = transmitControlCommand(
-                ifdCtrlCmds.get(FEATURE_VERIFY_PIN_DIRECT),
+        sw = reader.transmitControlCommand(
+                DefaultReader.FEATURE_VERIFY_PIN_DIRECT,
                 getPINVerifyStructure(kid));
 //        int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff;
       } else {
@@ -551,10 +542,10 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
           throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException {
     try {
       byte[] sw;
-      if (ifdSupportsFeature(FEATURE_MODIFY_PIN_DIRECT)) {
+      if (reader.hasFeature(DefaultReader.FEATURE_MODIFY_PIN_DIRECT)) {
         log.debug("modify PIN on IFD");
-        sw = transmitControlCommand(
-                ifdCtrlCmds.get(FEATURE_MODIFY_PIN_DIRECT),
+        sw = reader.transmitControlCommand(
+                DefaultReader.FEATURE_MODIFY_PIN_DIRECT,
                 getPINModifyStructure(kid));
 //        int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff;
       } else {
@@ -606,31 +597,43 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
   protected void activatePIN(byte kid, char[] pin)
           throws CancelledException, TimeoutException, SignatureCardException {
     try {
-      CardChannel channel = getCardChannel();
-      ResponseAPDU resp = transmit(channel,
-              new CommandAPDU(0x00, 0x24, 0x01, kid, encodePINBlock(pin)), false);
+      byte[] sw;
+      if (reader.hasFeature(DefaultReader.FEATURE_MODIFY_PIN_DIRECT)) {
+        log.debug("activate PIN on IFD");
+        sw = reader.transmitControlCommand(
+                DefaultReader.FEATURE_MODIFY_PIN_DIRECT,
+                getActivatePINModifyStructure(kid));
+//        int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff;
+      } else {
+        CardChannel channel = getCardChannel();
+        ResponseAPDU resp = transmit(channel,
+                new CommandAPDU(0x00, 0x24, 0x01, kid, encodePINBlock(pin)), false);
 
-      log.trace("activate pin returned SW=" + Integer.toHexString(resp.getSW()));
+        sw = new byte[2];
+        sw[0] = (byte) resp.getSW1();
+        sw[1] = (byte) resp.getSW2();
+        log.trace("activate pin returned SW=" + Integer.toHexString(resp.getSW()));
+      }
 
-      if (resp.getSW1() == 0x9000) {
+      if (sw[0] == (byte) 0x90 && sw[1] == (byte) 0x00) {
         return;
-      } else if (resp.getSW() == 0x6983) {
+      } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x83) {
         //Authentisierungsmethode gesperrt
         throw new LockedException("[69:83]");
-      } else if (resp.getSW() == 0x6984) {
-        //referenzierte Daten sind reversibel gesperrt (invalidated)
-        throw new NotActivatedException("[69:84]");
-      } else if (resp.getSW() == 0x6985) {
-        //Benutzungsbedingungen nicht erfüllt
-        throw new NotActivatedException("[69:85]");
-      } else if (resp.getSW() == 0x6400) {
+//      } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x84) {
+//        //referenzierte Daten sind reversibel gesperrt (invalidated)
+//        throw new NotActivatedException("[69:84]");
+//      } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x85) {
+//        //Benutzungsbedingungen nicht erfüllt
+//        throw new NotActivatedException("[69:85]");
+      } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x00) {
         throw new TimeoutException("[64:00]");
-      } else if (resp.getSW() == 0x6401) {
+      } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) {
         throw new CancelledException("[64:01]");
       }
-      log.error("Failed to activate pin: SW=" +
-              Integer.toHexString(resp.getSW()));
-      throw new SignatureCardException("[" + Integer.toHexString(resp.getSW()) + "]");
+      log.error("Failed to activate pin: SW="
+              + SMCCHelper.toString(sw));
+      throw new SignatureCardException(SMCCHelper.toString(sw));
 
     } catch (CardException ex) {
       log.error("smart card communication failed: " + ex.getMessage());
@@ -667,9 +670,8 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
   }
   
   private byte[] getPINVerifyStructure(byte kid) {
-      
-      byte bTimeOut = (byte) 00;            // Default time out
-      byte bTimeOut2 = (byte) 00;           // Default time out
+      byte bTimeOut = reader.getbTimeOut(); 
+      byte bTimeOut2 = reader.getbTimeOut2(); // time out after first entry
       byte bmFormatString = (byte) 0x89;      // 1 0001 0 01 
                                               // ^------------ System unit = byte
                                               //   ^^^^------- PIN position in the frame = 1 byte
@@ -681,9 +683,14 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
       byte bmPINLengthFormat = (byte) 0x04;   // 000 0 0100
                                               //     ^-------- System bit units is bit
                                               //       ^^^^--- PIN length is at the 4th position bit
-      byte wPINMaxExtraDigitL = (byte) 0x04;  // Max=4 digits
-      byte wPINMaxExtraDigitH = (byte) 0x04;  // Min=4 digits
-      byte bEntryValidationCondition = 0x02;  // Max size reach or Validation key pressed
+      byte wPINMaxExtraDigitL =               // Max=12 digits (Gemplus support max 8)
+              (reader.getwPINMaxExtraDigitL() < (byte) 0x12) ?
+                reader.getwPINMaxExtraDigitL() : (byte) 0x12;
+      byte wPINMaxExtraDigitH =               // Min=4/6 digits TODO card/ss pin (min: 4/6)
+              (reader.getwPINMaxExtraDigitH() > (byte) 0x04) ?
+                reader.getwPINMaxExtraDigitH() : (byte) 0x04;
+      byte bEntryValidationCondition = 
+              reader.getbEntryValidationCondition();  
       byte bNumberMessage = (byte) 0x00;      // No message
       byte wLangIdL = (byte) 0x0C;            // - English?
       byte wLangIdH = (byte) 0x04;            // \
@@ -725,38 +732,99 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
 
   private byte[] getPINModifyStructure(byte kid) {
 
-      byte bTimeOut = (byte) 00;            // Default time out
-      byte bTimeOut2 = (byte) 00;           // Default time out
-      byte bmFormatString = (byte) 0x89;      // 1 0001 0 01
-                                              // ^------------ System unit = byte
-                                              //   ^^^^------- PIN position in the frame = 1 byte
-                                              //        ^----- PIN justification left
-                                              //          ^^-- BCD format
-      byte bmPINBlockString = (byte) 0x47;    // 0100 0111
-                                              // ^^^^--------- PIN length size: 4 bits
-                                              //      ^^^^---- Length PIN = 7 bytes
-      byte bmPINLengthFormat = (byte) 0x04;   // 000 0 0100
-                                              //     ^-------- System bit units is bit
-                                              //       ^^^^--- PIN length is at the 4th position bit
-      byte bInsertionOffsetOld = (byte) 0x01; // insertion position offset in bytes
-      byte bInsertionOffsetNew = (byte) 0x08; // insertion position offset in bytes
-      byte wPINMaxExtraDigitL = (byte) 0x04;  // Min=4 digits
-      byte wPINMaxExtraDigitH = (byte) 0x04;  // Max=12 digits
-      byte bConfirmPIN = (byte) 0x00;         // ??? need for confirm pin
-      byte bEntryValidationCondition = 0x02;  // Max size reach or Validation key pressed
-      byte bNumberMessage = (byte) 0x00;      // No message
-      byte wLangIdL = (byte) 0x0C;            // - English?
-      byte wLangIdH = (byte) 0x04;            // \
-      byte bMsgIndex1 = (byte) 0x00;           // Default Msg
-      byte bMsgIndex2 = (byte) 0x00;           // Default Msg
-      byte bMsgIndex3 = (byte) 0x00;           // Default Msg
+      byte bTimeOut = reader.getbTimeOut();   // s.o.
+      byte bTimeOut2 = reader.getbTimeOut2(); // s.o.
+      byte bmFormatString = (byte) 0x89;      // s.o.
+      byte bmPINBlockString = (byte) 0x47;    // s.o.
+      byte bmPINLengthFormat = (byte) 0x04;   // s.o.
+      byte bInsertionOffsetOld = (byte) 0x00; // insertion position offset in bytes
+      byte bInsertionOffsetNew = (byte) 0x08; // (add 1 from bmFormatString b3)
+      byte wPINMaxExtraDigitL = 
+              (reader.getwPINMaxExtraDigitL() < (byte) 0x12) ?
+                reader.getwPINMaxExtraDigitL() : (byte) 0x12;
+      byte wPINMaxExtraDigitH =               // Min=4/6 digits TODO card/ss pin (min: 4/6)
+              (reader.getwPINMaxExtraDigitH() > (byte) 0x04) ?
+                reader.getwPINMaxExtraDigitH() : (byte) 0x04;
+      byte bConfirmPIN = (byte) 0x03;         // current pin entry + confirmation
+      byte bEntryValidationCondition =
+              reader.getbEntryValidationCondition();
+      byte bNumberMessage = (byte) 0x03;      // 3 messages
+      byte wLangIdL = (byte) 0x0C;            
+      byte wLangIdH = (byte) 0x04;            
+      byte bMsgIndex1 = (byte) 0x00;          // insertion
+      byte bMsgIndex2 = (byte) 0x01;          // modification
+      byte bMsgIndex3 = (byte) 0x02;          // confirmation
 
       byte[] apdu = new byte[] {
-        (byte) 0x00, (byte) 0x24, (byte) 0x00, kid, (byte) 0x10,  // CLA INS P1 P2 LC
-        (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff,               // Data
-        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,                // ...
-        (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff,               // Data
-        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff                // ...
+        (byte) 0x00, (byte) 0x24, (byte) 0x00, kid, (byte) 0x10, 
+        (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff,      
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,      
+        (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff,      
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff       
+      };
+
+      int offset = 0;
+      byte[] pinModifyStructure = new byte[offset + 24 + apdu.length];
+      pinModifyStructure[offset++] = bTimeOut;
+      pinModifyStructure[offset++] = bTimeOut2;
+      pinModifyStructure[offset++] = bmFormatString;
+      pinModifyStructure[offset++] = bmPINBlockString;
+      pinModifyStructure[offset++] = bmPINLengthFormat;
+      pinModifyStructure[offset++] = bInsertionOffsetOld;
+      pinModifyStructure[offset++] = bInsertionOffsetNew;
+      pinModifyStructure[offset++] = wPINMaxExtraDigitL;
+      pinModifyStructure[offset++] = wPINMaxExtraDigitH;
+      pinModifyStructure[offset++] = bConfirmPIN;
+      pinModifyStructure[offset++] = bEntryValidationCondition;
+      pinModifyStructure[offset++] = bNumberMessage;
+      pinModifyStructure[offset++] = wLangIdL;
+      pinModifyStructure[offset++] = wLangIdH;
+      pinModifyStructure[offset++] = bMsgIndex1;
+      pinModifyStructure[offset++] = bMsgIndex2;
+      pinModifyStructure[offset++] = bMsgIndex3;
+
+      pinModifyStructure[offset++] = 0x00;
+      pinModifyStructure[offset++] = 0x00;
+      pinModifyStructure[offset++] = 0x00;
+
+      pinModifyStructure[offset++] = (byte) apdu.length;
+      pinModifyStructure[offset++] = 0x00;
+      pinModifyStructure[offset++] = 0x00;
+      pinModifyStructure[offset++] = 0x00;
+      System.arraycopy(apdu, 0, pinModifyStructure, offset, apdu.length);
+
+//      log.debug("PIN MODIFY " + SMCCHelper.toString(pinModifyStructure));
+      return pinModifyStructure;
+  }
+  private byte[] getActivatePINModifyStructure(byte kid) {
+
+      byte bTimeOut = reader.getbTimeOut();   
+      byte bTimeOut2 = reader.getbTimeOut2(); 
+      byte bmFormatString = (byte) 0x89;      
+      byte bmPINBlockString = (byte) 0x47;    
+      byte bmPINLengthFormat = (byte) 0x04;   
+      byte bInsertionOffsetOld = (byte) 0x00; // ignored
+      byte bInsertionOffsetNew = (byte) 0x00; 
+      byte wPINMaxExtraDigitL =
+              (reader.getwPINMaxExtraDigitL() < (byte) 0x12) ?
+                reader.getwPINMaxExtraDigitL() : (byte) 0x12;
+      byte wPINMaxExtraDigitH =               // Min=4/6 digits TODO card/ss pin (min: 4/6)
+              (reader.getwPINMaxExtraDigitH() > (byte) 0x04) ?
+                reader.getwPINMaxExtraDigitH() : (byte) 0x04;
+      byte bConfirmPIN = (byte) 0x01;         // confirm, no current pin entry
+      byte bEntryValidationCondition =
+              reader.getbEntryValidationCondition();
+      byte bNumberMessage = (byte) 0x02;      // 2 messages
+      byte wLangIdL = (byte) 0x0c;
+      byte wLangIdH = (byte) 0x04;
+      byte bMsgIndex1 = (byte) 0x01;          // modification prompt
+      byte bMsgIndex2 = (byte) 0x02;          // confirmation prompt
+      byte bMsgIndex3 = (byte) 0x00;           
+
+      byte[] apdu = new byte[] {
+        (byte) 0x00, (byte) 0x24, (byte) 0x01, kid, (byte) 0x08,
+        (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff
       };
 
       int offset = 0;
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java
index 293b9c71..253ac7a0 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java
@@ -17,6 +17,7 @@
 
 package at.gv.egiz.smcc;
 
+import at.gv.egiz.smcc.ccid.CCID;
 import java.io.ByteArrayOutputStream;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -44,6 +45,7 @@ import java.util.Locale;
 
 import java.util.Map;
 import javax.smartcardio.Card;
+import javax.smartcardio.CardException;
 import javax.smartcardio.CardTerminal;
 
 import org.apache.commons.logging.Log;
@@ -419,7 +421,50 @@ public class SWCard implements SignatureCard {
   }
 
   @Override
-  public boolean ifdSupportsFeature(byte feature) {
-    return false;
+  public CCID getReader() {
+    return new CCID() {
+
+      @Override
+      public boolean hasFeature(Byte feature) {
+        return false;
+      }
+
+      @Override
+      public byte[] transmitControlCommand(Byte feature, byte[] ctrlCommand)
+              throws SignatureCardException {
+        throw new SignatureCardException(CCID.FEATURES[feature.intValue()] +
+                " not supported");
+      }
+
+      @Override
+      public byte getbTimeOut() {
+        return 0;
+      }
+
+      @Override
+      public byte getbTimeOut2() {
+        return 0;
+      }
+
+      @Override
+      public byte getwPINMaxExtraDigitL() {
+        return 0x12;
+      }
+
+      @Override
+      public byte getwPINMaxExtraDigitH() {
+        return 0x00;
+      }
+
+      @Override
+      public byte getbEntryValidationCondition() {
+        return 0x02;
+      }
+
+      @Override
+      public Card connect() {
+        return null;
+      }
+    };
   }
 }
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java
index 2097e6d3..ad530ad5 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java
@@ -28,6 +28,7 @@
 //
 package at.gv.egiz.smcc;
 
+import at.gv.egiz.smcc.ccid.CCID;
 import java.util.List;
 import java.util.Locale;
 
@@ -36,14 +37,6 @@ import javax.smartcardio.CardTerminal;
 
 public interface SignatureCard {
 
-  /**
-   * IFD FEATURES
-   */
-  static final Byte FEATURE_VERIFY_PIN_DIRECT = new Byte((byte) 0x06);
-  static final Byte FEATURE_MODIFY_PIN_DIRECT = new Byte((byte) 0x07);
-  static final Byte FEATURE_MCT_READER_DIRECT = new Byte((byte) 0x08);
-  static final Byte FEATURE_IFD_PIN_PROPERTIES = new Byte((byte) 0x0a);
-
   public static class KeyboxName {
 
     public static KeyboxName SECURE_SIGNATURE_KEYPAIR = new KeyboxName(
@@ -143,11 +136,7 @@ public interface SignatureCard {
   public void unblockPIN(PINSpec pinSpec, PINProvider pukProvider)
           throws CancelledException, SignatureCardException, InterruptedException;
 
-  /**
-   * TODO
-   * @return
-   */
-  public boolean ifdSupportsFeature(byte feature);
+  public CCID getReader();
 
   /**
    * Sets the local for evtl. required callbacks (e.g. PINSpec)
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ccid/CCID.java b/smcc/src/main/java/at/gv/egiz/smcc/ccid/CCID.java
new file mode 100644
index 00000000..2c56ce98
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ccid/CCID.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package at.gv.egiz.smcc.ccid;
+
+import at.gv.egiz.smcc.*;
+import javax.smartcardio.Card;
+import javax.smartcardio.CardException;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public interface CCID {
+
+
+  String[] FEATURES = new String[]{"NO_FEATURE",
+    "FEATURE_VERIFY_PIN_START",
+    "FEATURE_VERIFY_PIN_FINISH",
+    "FEATURE_MODIFY_PIN_START",
+    "FEATURE_MODIFY_PIN_FINISH",
+    "FEATURE_GET_KEY_PRESSED",
+    "FEATURE_VERIFY_PIN_DIRECT",
+    "FEATURE_MODIFY_PIN_DIRECT",
+    "FEATURE_MCT_READER_DIRECT",
+    "FEATURE_MCT_UNIVERSAL",
+    "FEATURE_IFD_PIN_PROPERTIES",
+    "FEATURE_ABORT",
+    "FEATURE_SET_SPE_MESSAGE",
+    "FEATURE_VERIFY_PIN_DIRECT_APP_ID",
+    "FEATURE_MODIFY_PIN_DIRECT_APP_ID",
+    "FEATURE_WRITE_DISPLAY",
+    "FEATURE_GET_KEY",
+    "FEATURE_IFD_DISPLAY_PROPERTIES"};
+  
+  Byte FEATURE_IFD_PIN_PROPERTIES = new Byte((byte) 10);
+  Byte FEATURE_MCT_READER_DIRECT = new Byte((byte) 8);
+  Byte FEATURE_MODIFY_PIN_DIRECT = new Byte((byte) 7);
+  Byte FEATURE_VERIFY_PIN_DIRECT = new Byte((byte) 6);
+  
+  Card connect() throws CardException;
+
+  boolean hasFeature(Byte feature);
+
+  /**
+   *
+   * @param feature the corresponding control code will be transmitted
+   * @param ctrlCommand
+   * @return
+   * @throws at.gv.egiz.smcc.SignatureCardException if feature is not supported
+   * or card communication fails
+   */
+  byte[] transmitControlCommand(Byte feature, byte[] ctrlCommand) throws SignatureCardException;
+
+  /**
+   * allow subclasses to override default (deal with reader bugs)
+   * @return
+   */
+  byte getbTimeOut();
+  byte getbTimeOut2();
+  byte getwPINMaxExtraDigitL();
+  byte getwPINMaxExtraDigitH();
+  byte getbEntryValidationCondition();
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java b/smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java
new file mode 100644
index 00000000..2cc77dc9
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package at.gv.egiz.smcc.ccid;
+
+import at.gv.egiz.smcc.*;
+import at.gv.egiz.smcc.util.SMCCHelper;
+import java.util.HashMap;
+import java.util.Map;
+import javax.smartcardio.Card;
+import javax.smartcardio.CardException;
+import javax.smartcardio.CardTerminal;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class DefaultReader implements CCID {
+
+  protected final static Log log = LogFactory.getLog(DefaultReader.class);
+
+  private static int CTL_CODE(int code) {
+    return 0x42000000 + code;
+  }
+
+  int IOCTL_GET_FEATURE_REQUEST = CTL_CODE(3400);
+
+
+  protected Card icc;
+  protected CardTerminal ct;
+
+  /**
+   * supported features and respective control codes
+   */
+  protected Map<Byte, Integer> features;
+
+  public DefaultReader(Card icc, CardTerminal ct) {
+    if (icc == null || ct == null) {
+      throw new NullPointerException("no card or card terminal provided");
+    }
+    this.icc = icc;
+    this.ct = ct;
+    features = queryFeatures(); 
+  }
+
+  public Card connect() throws CardException { //SignatureCardException {
+//      try {
+    icc = ct.connect("*");
+    return icc;
+//      } catch (CardException ex) {
+//        log.error(ex.getMessage(), ex);
+//        throw new SignatureCardException("Failed to connect to card: " + ex.getMessage());
+//      }
+  }
+
+  Map<Byte, Integer> queryFeatures() {
+    Map<Byte, Integer> features = new HashMap<Byte, Integer>();
+
+    if (icc == null) {
+      log.warn("invalid card handle, cannot query ifd features");
+    } else {
+      try {
+        if (log.isTraceEnabled()) {
+          log.trace("GET_FEATURE_REQUEST " +
+                  Integer.toHexString(IOCTL_GET_FEATURE_REQUEST) +
+                  " on " + ct.getName());
+        }
+        byte[] resp = icc.transmitControlCommand(IOCTL_GET_FEATURE_REQUEST,
+                new byte[]{});
+
+        if (log.isTraceEnabled()) {
+          log.trace("Response TLV " + SMCCHelper.toString(resp));
+        }
+        // tag
+        // length in bytes (always 4)
+        // control code value for supported feature (in big endian)
+        for (int i = 0; i < resp.length; i += 6) {
+          Byte feature = new Byte(resp[i]);
+          int ioctlBigEndian = (resp[i + 2] << 24) |
+                  (resp[i + 3] << 16) | (resp[i + 4] << 8) | resp[i + 5];
+          Integer ioctl = new Integer(ioctlBigEndian);
+          if (log.isInfoEnabled()) {
+            log.info("CCID supports " + FEATURES[feature.intValue()] +
+                    ": " + Integer.toHexString(ioctl.intValue()));
+          }
+          features.put(feature, ioctl);
+        }
+      } catch (CardException ex) {
+        log.debug("Failed to query CCID features: " + ex.getMessage());
+        log.trace(ex);
+        log.info("CCID does not support PINPad");
+      }
+    }
+    return features;
+  }
+
+  @Override
+  public boolean hasFeature(Byte feature) {
+    if (features != null) {
+      return features.containsKey(feature);
+    }
+    return false;
+  }
+
+//  public Integer getIOCTL(Byte feature) {
+//    if (features != null) {
+//      return features.get(feature);
+//    }
+//    return null;
+//  }
+
+  @Override
+  public byte[] transmitControlCommand(Byte feature, byte[] ctrlCommand)
+          throws SignatureCardException {
+    try {
+      if (!features.containsKey(feature)) {
+        throw new SignatureCardException(FEATURES[feature.intValue()] + " not supported");
+      }
+      int ioctl = features.get(feature);
+      if (log.isTraceEnabled()) {
+        log.trace("CtrlCommand (" + Integer.toHexString(ioctl) +
+                ")  " + SMCCHelper.toString(ctrlCommand));
+      }
+      byte[] resp = icc.transmitControlCommand(ioctl, ctrlCommand);
+      if (log.isTraceEnabled()) {
+        log.trace("CtrlCommand Response " + SMCCHelper.toString(resp));
+      }
+      return resp;
+    } catch (CardException ex) {
+      log.error(ex.getMessage());
+      throw new SignatureCardException("Failed to transmit CtrlCommand for " +
+              FEATURES[feature.intValue()]);
+    }
+  }
+
+
+  @Override
+  public byte getbTimeOut() {
+    return (byte) 0x3c;    // (max 1min on ReinerSCT),
+                           // 0x00=default, 0x1e = 30sec
+  }
+
+  @Override
+  public byte getbTimeOut2() {
+    return (byte) 0x00;    // default
+  }
+
+  @Override
+  public byte getwPINMaxExtraDigitL() {
+    return (byte) 0x12;
+  }
+
+  @Override
+  public byte getwPINMaxExtraDigitH() {
+    return (byte) 0x00;
+  }
+
+  @Override
+  public byte getbEntryValidationCondition() {
+    return (byte) 0x02;    // validation key pressed
+  }
+
+
+  //  protected byte ifdGetKeyPressed() throws CardException {
+//    if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) {
+//
+//      Long controlCode = (Long) IFD_IOCTL.get(new Byte((byte) 0x05));
+//
+//      byte key = 0x00;
+//      while (key == 0x00) {
+//
+//        byte[] resp = card_.transmitControlCommand(controlCode.intValue(), new byte[] {});
+//
+//        if (resp != null && resp.length > 0) {
+//          key = resp[0];
+//        }
+//      }
+//
+//      System.out.println("Key: " + key);
+//
+//    }
+//
+//    return 0x00;
+//  }
+//
+//  protected byte[] ifdVerifyPINFinish() throws CardException {
+//    if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) {
+//
+//      Long controlCode = (Long) IFD_IOCTL.get(new Byte((byte) 0x02));
+//
+//      byte[] resp = card_.transmitControlCommand(controlCode.intValue(), new byte[] {});
+//
+//      System.out.println("CommandResp: " + toString(resp));
+//
+//      return resp;
+//
+//    }
+//
+//    return null;
+//  }
+
+
+  /**
+   * assumes ifdSupportsVerifyPIN() == true
+   * @param pinVerifyStructure
+   * @return
+   * @throws javax.smartcardio.CardException
+   */
+//  protected byte[] ifdVerifyPIN(byte[] pinVerifyStructure) throws CardException {
+//
+////      Long ctrlCode = (Long) ifdFeatures.get(FEATURE_IFD_PIN_PROPERTIES);
+////      if (ctrlCode != null) {
+////        if (log.isTraceEnabled()) {
+////          log.trace("PIN_PROPERTIES CtrlCode " + Integer.toHexString(ctrlCode.intValue()));
+////        }
+////        byte[] resp = card_.transmitControlCommand(ctrlCode.intValue(), new byte[] {});
+////
+////        if (log.isTraceEnabled()) {
+////          log.trace("PIN_PROPERTIES Response " + SMCCHelper.toString(resp));
+////        }
+////      }
+//
+//
+//      Long ctrlCode = (Long) ifdFeatures.get(FEATURE_VERIFY_PIN_DIRECT);
+//      if (ctrlCode == null) {
+//        throw new NullPointerException("no CtrlCode for FEATURE_VERIFY_PIN_DIRECT");
+//      }
+//
+//      if (log.isTraceEnabled()) {
+//        log.trace("VERIFY_PIN_DIRECT CtrlCode " + Integer.toHexString(ctrlCode.intValue()) +
+//                ", PIN_VERIFY_STRUCTURE " + SMCCHelper.toString(pinVerifyStructure));
+//      }
+//      byte[] resp = card_.transmitControlCommand(ctrlCode.intValue(), pinVerifyStructure);
+//
+//      if (log.isTraceEnabled()) {
+//        log.trace("VERIFY_PIN_DIRECT Response " + SMCCHelper.toString(resp));
+//      }
+//      return resp;
+//  }
+
+//  protected Long getControlCode(Byte feature) {
+//    if (ifdFeatures != null) {
+//      return ifdFeatures.get(feature);
+//    }
+//    return null;
+//  }
+
+  
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ccid/GemplusGemPCPinpad.java b/smcc/src/main/java/at/gv/egiz/smcc/ccid/GemplusGemPCPinpad.java
new file mode 100644
index 00000000..903b11fc
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ccid/GemplusGemPCPinpad.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package at.gv.egiz.smcc.ccid;
+
+import javax.smartcardio.Card;
+import javax.smartcardio.CardTerminal;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class GemplusGemPCPinpad extends DefaultReader {
+
+  protected final static Log log = LogFactory.getLog(GemplusGemPCPinpad.class);
+
+  public GemplusGemPCPinpad(Card icc, CardTerminal ct) {
+    super(icc, ct);
+    log.info("Initializing Gemplus GemPC Pinpad reader");
+    log.info("Gemplus GemPC Pinpad allows PINs to have 4-8 digits");
+
+  }
+
+  @Override
+  public byte getbTimeOut() {
+    return (byte) 0x3c;    // 0x00 default = 15sec
+                           // max 40sec (?)
+  }
+
+  @Override
+  public byte getbTimeOut2() {
+    return (byte) 0x00;    // 0x00 default = 15sec
+  }
+
+  @Override
+  public byte getwPINMaxExtraDigitL() {
+    return (byte) 0x08; 
+  }
+
+  @Override
+  public byte getwPINMaxExtraDigitH() {
+    return (byte) 0x04;
+  }
+
+  @Override
+  public byte getbEntryValidationCondition() {
+    return (byte) 0x02;    // validation key pressed
+  }
+
+}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ccid/ReaderFactory.java b/smcc/src/main/java/at/gv/egiz/smcc/ccid/ReaderFactory.java
new file mode 100644
index 00000000..2cfcef19
--- /dev/null
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ccid/ReaderFactory.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package at.gv.egiz.smcc.ccid;
+
+import javax.smartcardio.Card;
+import javax.smartcardio.CardTerminal;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class ReaderFactory {
+
+  public static CCID getReader(Card icc, CardTerminal ct) {
+    if ("Gemplus GemPC Pinpad 00 00".equals(ct.getName())) {
+      return new GemplusGemPCPinpad(icc, ct);
+    }
+    return new DefaultReader(icc, ct);
+  }
+}
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/ACOSCardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/ACOSCardTest.java
new file mode 100644
index 00000000..5839d14a
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/ACOSCardTest.java
@@ -0,0 +1,135 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package at.gv.egiz.smcc;
+
+import at.gv.egiz.smcc.SignatureCard.KeyboxName;
+import at.gv.egiz.smcc.util.SMCCHelper;
+import java.util.List;
+import java.util.Locale;
+import javax.smartcardio.ResponseAPDU;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author clemens
+ */
+@Ignore
+public class ACOSCardTest {
+
+  static ACOSCard card;
+  static PINSpec infPin, decPin, sigPin;
+
+    public ACOSCardTest() {
+    }
+
+  @BeforeClass
+  public static void setUpClass() throws Exception {
+    SMCCHelper smccHelper = new SMCCHelper();
+      switch (smccHelper.getResultCode()) {
+        case SMCCHelper.CARD_FOUND:
+          SignatureCard sigCard = smccHelper.getSignatureCard(Locale.GERMAN);
+          if (sigCard instanceof ACOSCard) {
+            System.out.println("ACOS card found");
+            card = (ACOSCard) sigCard;
+            List<PINSpec> pinSpecs = card.getPINSpecs();
+            infPin = pinSpecs.get(ACOSCard.PINSPEC_INF);
+            decPin = pinSpecs.get(ACOSCard.PINSPEC_DEC);
+            sigPin = pinSpecs.get(ACOSCard.PINSPEC_SIG);
+          } else {
+            throw new Exception("not STARCOS card: " + sigCard.toString());
+          }
+          break;
+        default:
+          throw new Exception("no card found");
+      }
+  }
+
+  @AfterClass
+  public static void tearDownClass() throws Exception {
+  }
+
+    @Before
+    public void setUp() {
+    }
+
+    @After
+    public void tearDown() {
+    }
+
+
+
+  /**
+   * Test of verifyPIN method, of class STARCOSCard.
+   */
+  @Test
+  @Ignore
+  public void testVerifyPIN_pinpad() throws Exception {
+    System.out.println("verifyPIN (pinpad)");
+    assertNotNull(card);
+
+    card.verifyPIN(decPin, new PINProvider() {
+
+      @Override
+      public char[] providePIN(PINSpec spec, int retries) {
+        return null;
+      }
+    });
+  }
+
+  /**
+   * Test of verifyPIN method, of class STARCOSCard.
+   */
+  @Test
+  @Ignore
+  public void testVerifyPIN_internal() throws Exception {
+    System.out.println("verifyPIN (internal)");
+    assertNotNull(card);
+
+    card.reset();
+
+    card.getCard().beginExclusive();
+
+    // 0x6700 without sending an APDU prior to send CtrlCmd
+    System.out.println("WARNING: this command will fail if no card " +
+            "communication took place prior to sending the CtrlCommand");
+    int retries = card.verifyPIN(decPin.getKID(), null); //"1397".toCharArray());
+
+    System.out.println("VERIFY PIN returned " + retries);
+    card.getCard().endExclusive();
+  }
+
+  /**
+   * Test of changePIN method, of class STARCOSCard.
+   */
+  @Test
+  @Ignore
+  public void testChangePIN() throws Exception {
+    System.out.println("changePIN");
+    assertNotNull(card);
+
+    card.reset();
+    int retries = card.changePIN(decPin.getKID(), null, null);
+
+    System.out.println("CHANGE PIN returned " + retries);
+  }
+
+  /**
+   * Test of reset method, of class STARCOSCard.
+   */
+  @Test
+  public void testReset() throws Exception {
+    System.out.println("reset");
+    assertNotNull(card);
+    card.reset();
+  }
+
+}
\ No newline at end of file
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java
new file mode 100644
index 00000000..9be8db00
--- /dev/null
+++ b/smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java
@@ -0,0 +1,267 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package at.gv.egiz.smcc;
+
+import at.gv.egiz.smcc.SignatureCard.KeyboxName;
+import at.gv.egiz.smcc.util.SMCCHelper;
+import java.util.List;
+import java.util.Locale;
+import javax.smartcardio.ResponseAPDU;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author clemens
+ */
+@Ignore
+public class STARCOSCardTest {
+
+  static STARCOSCard card;
+  static PINSpec cardPin, ssPin;
+
+    public STARCOSCardTest() {
+    }
+
+  @BeforeClass
+  public static void setUpClass() throws Exception {
+    SMCCHelper smccHelper = new SMCCHelper();
+      switch (smccHelper.getResultCode()) {
+        case SMCCHelper.CARD_FOUND:
+          SignatureCard sigCard = smccHelper.getSignatureCard(Locale.GERMAN);
+          if (sigCard instanceof STARCOSCard) {
+            System.out.println("STARCOS card found");
+            card = (STARCOSCard) sigCard;
+            List<PINSpec> pinSpecs = card.getPINSpecs();
+            cardPin = pinSpecs.get(STARCOSCard.PINSPEC_CARD);
+            ssPin = pinSpecs.get(STARCOSCard.PINSPEC_SS);
+
+          } else {
+            throw new Exception("not STARCOS card: " + sigCard.toString());
+          }
+          break;
+        default:
+          throw new Exception("no card found");
+      }
+  }
+
+  @AfterClass
+  public static void tearDownClass() throws Exception {
+  }
+
+    @Before
+    public void setUp() {
+    }
+
+    @After
+    public void tearDown() {
+    }
+
+  /**
+   * Test of getCertificate method, of class STARCOSCard.
+   */
+  @Test
+  @Ignore
+  public void testGetCertificate() throws Exception {
+    System.out.println("getCertificate");
+    KeyboxName keyboxName = null;
+    STARCOSCard instance = new STARCOSCard();
+    byte[] expResult = null;
+    byte[] result = instance.getCertificate(keyboxName);
+    assertEquals(expResult, result);
+    // TODO review the generated test code and remove the default call to fail.
+    fail("The test case is a prototype.");
+  }
+
+  /**
+   * Test of getInfobox method, of class STARCOSCard.
+   */
+  @Test
+  @Ignore
+  public void testGetInfobox() throws Exception {
+    System.out.println("getInfobox");
+    String infobox = "";
+    PINProvider provider = null;
+    String domainId = "";
+    STARCOSCard instance = new STARCOSCard();
+    byte[] expResult = null;
+    byte[] result = instance.getInfobox(infobox, provider, domainId);
+    assertEquals(expResult, result);
+    // TODO review the generated test code and remove the default call to fail.
+    fail("The test case is a prototype.");
+  }
+
+  /**
+   * Test of createSignature method, of class STARCOSCard.
+   */
+  @Test
+  @Ignore
+  public void testCreateSignature() throws Exception {
+    System.out.println("createSignature");
+    byte[] hash = null;
+    KeyboxName keyboxName = null;
+    PINProvider provider = null;
+    STARCOSCard instance = new STARCOSCard();
+    byte[] expResult = null;
+    byte[] result = instance.createSignature(hash, keyboxName, provider);
+    assertEquals(expResult, result);
+    // TODO review the generated test code and remove the default call to fail.
+    fail("The test case is a prototype.");
+  }
+
+  /**
+   * Test of selectFileFID method, of class STARCOSCard.
+   */
+  @Test
+  @Ignore
+  public void testSelectFileFID() throws Exception {
+    System.out.println("selectFileFID");
+    byte[] fid = null;
+    STARCOSCard instance = new STARCOSCard();
+    ResponseAPDU expResult = null;
+    ResponseAPDU result = instance.selectFileFID(fid);
+    assertEquals(expResult, result);
+    // TODO review the generated test code and remove the default call to fail.
+    fail("The test case is a prototype.");
+  }
+
+  /**
+   * Test of verifyPIN method, of class STARCOSCard.
+   */
+  @Test
+  @Ignore
+  public void testVerifyPIN_pinpad() throws Exception {
+    System.out.println("verifyPIN (pinpad)");
+    assertNotNull(card);
+
+    card.verifyPIN(cardPin, new PINProvider() {
+
+      @Override
+      public char[] providePIN(PINSpec spec, int retries) {
+        return null;
+      }
+    });
+  }
+
+  /**
+   * Test of verifyPIN method, of class STARCOSCard.
+   */
+  @Test
+  @Ignore
+  public void testVerifyPIN_internal() throws Exception {
+    System.out.println("verifyPIN (internal)");
+    assertNotNull(card);
+
+    card.reset();
+
+    card.getCard().beginExclusive();
+
+    // 0x6700 without sending an APDU prior to send CtrlCmd
+    System.out.println("WARNING: this command will fail if no card " +
+            "communication took place prior to sending the CtrlCommand");
+    int retries = card.verifyPIN(cardPin.getKID(), null); //"1397".toCharArray());
+
+    System.out.println("VERIFY PIN returned " + retries);
+    card.getCard().endExclusive();
+  }
+
+  /**
+   * Test of verifyPIN method, of class STARCOSCard.
+   */
+  @Test
+  @Ignore
+  public void testVerifyPIN_byte() throws Exception {
+    System.out.println("verifyPIN");
+    byte kid = 0;
+    STARCOSCard instance = new STARCOSCard();
+    int expResult = 0;
+    int result = instance.verifyPIN(kid);
+    assertEquals(expResult, result);
+    // TODO review the generated test code and remove the default call to fail.
+    fail("The test case is a prototype.");
+  }
+
+  /**
+   * Test of changePIN method, of class STARCOSCard.
+   */
+  @Test
+  @Ignore
+  public void testChangePIN() throws Exception {
+    System.out.println("changePIN");
+    assertNotNull(card);
+
+    card.reset();
+    int retries = card.changePIN(cardPin.getKID(), null, null);
+
+    System.out.println("CHANGE PIN returned " + retries);
+  }
+
+  /**
+   * Test of activatePIN method, of class STARCOSCard.
+   */
+  @Test
+  @Ignore
+  public void testActivatePIN() throws Exception {
+    System.out.println("activatePIN");
+    assertNotNull(card);
+
+    card.reset();
+    card.activatePIN(cardPin, new PINProvider() {
+
+      @Override
+      public char[] providePIN(PINSpec spec, int retries) throws CancelledException, InterruptedException {
+        return null;
+      }
+    });
+  }
+
+  /**
+   * Test of encodePINBlock method, of class STARCOSCard.
+   */
+  @Test
+  @Ignore
+  public void testEncodePINBlock() throws Exception {
+    System.out.println("encodePINBlock");
+    char[] pin = null;
+    STARCOSCard instance = new STARCOSCard();
+    byte[] expResult = null;
+    byte[] result = instance.encodePINBlock(pin);
+    assertEquals(expResult, result);
+    // TODO review the generated test code and remove the default call to fail.
+    fail("The test case is a prototype.");
+  }
+
+  /**
+   * Test of reset method, of class STARCOSCard.
+   */
+  @Test
+  public void testReset() throws Exception {
+    System.out.println("reset");
+    assertNotNull(card);
+    card.reset();
+  }
+
+  /**
+   * Test of toString method, of class STARCOSCard.
+   */
+  @Test
+  @Ignore
+  public void testToString() {
+    System.out.println("toString");
+    STARCOSCard instance = new STARCOSCard();
+    String expResult = "";
+    String result = instance.toString();
+    assertEquals(expResult, result);
+    // TODO review the generated test code and remove the default call to fail.
+    fail("The test case is a prototype.");
+  }
+
+}
\ No newline at end of file
-- 
cgit v1.2.3