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