diff options
Diffstat (limited to 'smcc')
12 files changed, 605 insertions, 98 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 06e4a018..d064b821 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java @@ -401,15 +401,16 @@ public class ACOSCard extends AbstractSignatureCard {    @Override    protected int verifyPIN(byte kid, char[] pin) -          throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException { +          throws LockedException, NotActivatedException, CancelledException, TimeoutException, PINFormatException, PINOperationAbortedException, SignatureCardException {      try {        byte[] sw;        if (reader.hasFeature(CCID.FEATURE_VERIFY_PIN_DIRECT)) { -        log.debug("verify PIN on IFD"); -        sw = reader.transmitControlCommand( -                CCID.FEATURE_VERIFY_PIN_DIRECT, -                getPINVerifyStructure(kid)); +        log.debug("verify pin on cardreader"); +        sw = reader.verifyPinDirect(getPINVerifyStructure(kid));  //        int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff; +      } else if (reader.hasFeature(CCID.FEATURE_VERIFY_PIN_START)) { +        log.debug("verify pin on cardreader"); +        sw = reader.verifyPin(getPINVerifyStructure(kid));        } else {          byte[] pinBlock = encodePINBlock(pin);          CardChannel channel = getCardChannel(); @@ -442,6 +443,8 @@ public class ACOSCard extends AbstractSignatureCard {          throw new TimeoutException("[64:00]");        } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) {          throw new CancelledException("[64:01]"); +      } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x03) { +        throw new PINFormatException("[64:03]");        }        log.error("Failed to verify pin: SW="                + SMCCHelper.toString(sw)); @@ -465,15 +468,15 @@ public class ACOSCard extends AbstractSignatureCard {     */    @Override    protected int changePIN(byte kid, char[] oldPin, char[] newPin) -          throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException { +          throws LockedException, NotActivatedException, CancelledException, PINFormatException, PINConfirmationException, TimeoutException, PINOperationAbortedException, SignatureCardException {      try {         byte[] sw;        if (reader.hasFeature(CCID.FEATURE_MODIFY_PIN_DIRECT)) { -        log.debug("modify PIN on IFD"); -        sw = reader.transmitControlCommand( -                CCID.FEATURE_MODIFY_PIN_DIRECT, -                getPINModifyStructure(kid)); -//        int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff; +        log.debug("modify pin on cardreader"); +        sw = reader.modifyPinDirect(getPINModifyStructure(kid)); +      } else if (reader.hasFeature(CCID.FEATURE_MODIFY_PIN_START)) { +        log.debug("modify pin on cardreader"); +        sw = reader.modifyPin(getPINModifyStructure(kid));        } else {          byte[] cmd = new byte[16];          System.arraycopy(encodePINBlock(oldPin), 0, cmd, 0, 8); @@ -504,6 +507,13 @@ public class ACOSCard extends AbstractSignatureCard {          throw new TimeoutException("[64:00]");        } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) {          throw new CancelledException("[64:01]"); +      } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x02) { +        throw new PINConfirmationException("[64:02]"); +      } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x03) { +        throw new PINFormatException("[64:03]"); +      } else if (sw[0] == (byte) 0x6a && sw[1] == (byte) 0x80) { +        log.info("invalid parameter, assume wrong pin size"); +        throw new PINFormatException("[6a:80]");        }        log.error("Failed to change pin: SW="                + SMCCHelper.toString(sw)); @@ -559,7 +569,7 @@ public class ACOSCard extends AbstractSignatureCard {        byte bmPINLengthFormat = (byte) 0x00;   // 000 0 0000                                                //     ^-------- System bit units is bit                                                //       ^^^^--- no PIN length -      byte wPINMaxExtraDigitL = +      byte wPINMaxExtraDigitL = //TODO compare ints, not bytes                (reader.getwPINMaxExtraDigitL() < (byte) 0x08) ?                  reader.getwPINMaxExtraDigitL() : (byte) 0x08;        byte wPINMaxExtraDigitH =                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 47c27369..7dd3ee78 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java @@ -29,21 +29,16 @@  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;  import java.nio.ByteBuffer;  import java.util.ArrayList; -import java.util.HashMap;  import java.util.List;  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; @@ -152,8 +147,8 @@ public abstract class AbstractSignatureCard implements SignatureCard {     * @throws at.gv.egiz.smcc.SignatureCardException     */    protected abstract int verifyPIN(byte kid, char[] pin) -          throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException; - +          throws LockedException, NotActivatedException, CancelledException, PINFormatException, TimeoutException, PINOperationAbortedException, SignatureCardException; +      /**     * CHANGE(?) APDU     * If IFD supports VERIFY_PIN on pinpad, parameter pin may be empty. @@ -162,7 +157,7 @@ public abstract class AbstractSignatureCard implements SignatureCard {     * @throws at.gv.egiz.smcc.SignatureCardException if activation fails     */    protected abstract void activatePIN(byte kid, char[] pin) -          throws CancelledException, TimeoutException, SignatureCardException; +          throws CancelledException, PINFormatException, PINConfirmationException, TimeoutException, PINOperationAbortedException, SignatureCardException;    /**     * CHANGE(?) APDU @@ -173,7 +168,7 @@ public abstract class AbstractSignatureCard implements SignatureCard {     * @throws at.gv.egiz.smcc.SignatureCardException if change fails     */    protected abstract int changePIN(byte kid, char[] oldPin, char[] newPin) -          throws CancelledException, TimeoutException, SignatureCardException; +          throws LockedException, NotActivatedException, CancelledException, PINFormatException, PINConfirmationException, TimeoutException, PINOperationAbortedException, SignatureCardException;    /**     * encode the pin as needed in VERIFY/CHANGE APDUs @@ -595,7 +590,8 @@ public abstract class AbstractSignatureCard implements SignatureCard {     */    @Override    public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider) -          throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException, InterruptedException { +          throws LockedException, NotActivatedException, CancelledException, +          TimeoutException, SignatureCardException, InterruptedException {      try {        getCard().beginExclusive(); diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java b/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java new file mode 100644 index 00000000..115e6d5f --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/PINConfirmationException.java @@ -0,0 +1,43 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +*     http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egiz.smcc; + +/** + * TODO check whether card readers distinguish specific reason (pin too short?) + * and add getters/setters + * + * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at> + */ +public class PINConfirmationException extends SignatureCardException { + +  public PINConfirmationException() { +    super(); +  } + +  public PINConfirmationException(String message, Throwable cause) { +    super(message, cause); +  } + +  public PINConfirmationException(String message) { +    super(message); +  } + +  public PINConfirmationException(Throwable cause) { +    super(cause); +  } + +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java b/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java new file mode 100644 index 00000000..28a13fdb --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/PINFormatException.java @@ -0,0 +1,43 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +*     http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egiz.smcc; + +/** + * TODO check whether card readers distinguish specific reason (pin too short?) + * and add getters/setters + * + * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at> + */ +public class PINFormatException extends SignatureCardException { + +  public PINFormatException() { +    super(); +  } + +  public PINFormatException(String message, Throwable cause) { +    super(message, cause); +  } + +  public PINFormatException(String message) { +    super(message); +  } + +  public PINFormatException(Throwable cause) { +    super(cause); +  } + +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINOperationAbortedException.java b/smcc/src/main/java/at/gv/egiz/smcc/PINOperationAbortedException.java new file mode 100644 index 00000000..7337f59e --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/PINOperationAbortedException.java @@ -0,0 +1,43 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +*     http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egiz.smcc; + +/** + * TODO check whether card readers distinguish specific reason (pin too short?) + * and add getters/setters + * + * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at> + */ +public class PINOperationAbortedException extends SignatureCardException { + +  public PINOperationAbortedException() { +    super(); +  } + +  public PINOperationAbortedException(String message, Throwable cause) { +    super(message, cause); +  } + +  public PINOperationAbortedException(String message) { +    super(message); +  } + +  public PINOperationAbortedException(Throwable cause) { +    super(cause); +  } + +} 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 bc6a2316..b9c68b06 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java @@ -28,7 +28,7 @@  //  package at.gv.egiz.smcc; -import at.gv.egiz.smcc.ccid.DefaultReader; +import at.gv.egiz.smcc.ccid.CCID;  import at.gv.egiz.smcc.util.SMCCHelper;  import java.util.Arrays;  import javax.smartcardio.CardChannel; @@ -319,6 +319,8 @@ public class STARCOSCard extends AbstractSignatureCard {              return createSignature(hash, AID_DF_SS, pin, KID_PIN_SS, DST_SS);            } catch (VerificationFailedException e) {              retries = e.getRetries(); +          } catch (PINFormatException e) { +            log.debug("wrong pin size entered, retry");            } finally {              getCard().endExclusive();            } @@ -454,15 +456,16 @@ public class STARCOSCard extends AbstractSignatureCard {    @Override    protected int verifyPIN(byte kid, char[] pin) -          throws LockedException, NotActivatedException, SignatureCardException { +          throws LockedException, NotActivatedException, TimeoutException, CancelledException, PINFormatException, PINOperationAbortedException, SignatureCardException {      try {        byte[] sw; -      if (reader.hasFeature(DefaultReader.FEATURE_VERIFY_PIN_DIRECT)) { -        log.debug("verify PIN on IFD"); -        sw = reader.transmitControlCommand( -                DefaultReader.FEATURE_VERIFY_PIN_DIRECT, -                getPINVerifyStructure(kid)); +      if (reader.hasFeature(CCID.FEATURE_VERIFY_PIN_DIRECT)) { +        log.debug("verify pin on cardreader"); +        sw = reader.verifyPinDirect(getPINVerifyStructure(kid));  //        int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff; +      } else if (reader.hasFeature(CCID.FEATURE_VERIFY_PIN_START)) { +        log.debug("verify pin on cardreader"); +        sw = reader.verifyPin(getPINVerifyStructure(kid));        } else {          byte[] pinBlock = encodePINBlock(pin);          CardChannel channel = getCardChannel(); @@ -492,6 +495,8 @@ public class STARCOSCard extends AbstractSignatureCard {          throw new TimeoutException("[64:00]");        } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) {          throw new CancelledException("[64:01]"); +      } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x03) { +        throw new PINFormatException("[64:03]");        }        log.error("Failed to verify pin: SW="                + SMCCHelper.toString(sw)); @@ -539,15 +544,15 @@ public class STARCOSCard extends AbstractSignatureCard {    @Override    protected int changePIN(byte kid, char[] oldPin, char[] newPin) -          throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException { +          throws LockedException, CancelledException, PINFormatException, PINConfirmationException, TimeoutException, PINOperationAbortedException, SignatureCardException {      try {        byte[] sw; -      if (reader.hasFeature(DefaultReader.FEATURE_MODIFY_PIN_DIRECT)) { -        log.debug("modify PIN on IFD"); -        sw = reader.transmitControlCommand( -                DefaultReader.FEATURE_MODIFY_PIN_DIRECT, -                getPINModifyStructure(kid)); -//        int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff; +      if (reader.hasFeature(CCID.FEATURE_MODIFY_PIN_DIRECT)) { +        log.debug("modify pin on cardreader"); +        sw = reader.modifyPinDirect(getPINModifyStructure(kid)); +      } else if (reader.hasFeature(CCID.FEATURE_MODIFY_PIN_START)) { +        log.debug("modify pin on cardreader"); +        sw = reader.modifyPin(getPINModifyStructure(kid));        } else {          byte[] cmd = new byte[16];          System.arraycopy(encodePINBlock(oldPin), 0, cmd, 0, 8); @@ -583,6 +588,13 @@ public class STARCOSCard extends AbstractSignatureCard {          throw new TimeoutException("[64:00]");        } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) {          throw new CancelledException("[64:01]"); +      } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x02) { +        throw new PINConfirmationException("[64:02]"); +      } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x03) { +        throw new PINFormatException("[64:03]"); +      } else if (sw[0] == (byte) 0x6a && sw[1] == (byte) 0x80) { +        log.info("invalid parameter, assume wrong pin size"); +        throw new PINFormatException("[6a:80]");        }        log.error("Failed to change pin: SW="                + SMCCHelper.toString(sw)); @@ -595,15 +607,15 @@ public class STARCOSCard extends AbstractSignatureCard {    @Override    protected void activatePIN(byte kid, char[] pin) -          throws CancelledException, TimeoutException, SignatureCardException { +          throws CancelledException, PINFormatException, PINConfirmationException, TimeoutException, PINOperationAbortedException, SignatureCardException {      try {        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; +      if (reader.hasFeature(CCID.FEATURE_MODIFY_PIN_DIRECT)) { +        log.debug("activate pin on cardreader"); +        sw = reader.modifyPinDirect(getActivatePINModifyStructure(kid)); +      } else if (reader.hasFeature(CCID.FEATURE_MODIFY_PIN_START)) { +        log.debug("activate pin on cardreader"); +        sw = reader.modifyPin(getActivatePINModifyStructure(kid));        } else {          CardChannel channel = getCardChannel();          ResponseAPDU resp = transmit(channel, @@ -630,6 +642,10 @@ public class STARCOSCard extends AbstractSignatureCard {          throw new TimeoutException("[64:00]");        } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) {          throw new CancelledException("[64:01]"); +      } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x02) { +        throw new PINConfirmationException("[64:02]"); +      } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x03) { +        throw new PINFormatException("[64:03]");        }        log.error("Failed to activate pin: SW="                + SMCCHelper.toString(sw)); @@ -683,6 +699,7 @@ public class STARCOSCard extends AbstractSignatureCard {        byte bmPINLengthFormat = (byte) 0x04;   // 000 0 0100                                                //     ^-------- System bit units is bit                                                //       ^^^^--- PIN length is at the 4th position bit +      //TODO compare ints, not bytes        byte wPINMaxExtraDigitL =               // Max=12 digits (Gemplus support max 8)                (reader.getwPINMaxExtraDigitL() < (byte) 0x12) ?                  reader.getwPINMaxExtraDigitL() : (byte) 0x12; 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 253ac7a0..2ed1fe64 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java @@ -430,13 +430,6 @@ public class SWCard implements SignatureCard {        }        @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;        } @@ -465,6 +458,31 @@ public class SWCard implements SignatureCard {        public Card connect() {          return null;        } + +      @Override +      public String getName() { +        return "Software CardReader"; +      } + +      @Override +      public byte[] verifyPin(byte[] PIN_VERIFY) throws CardException { +        throw new UnsupportedOperationException("Not supported yet."); +      } + +      @Override +      public byte[] verifyPinDirect(byte[] PIN_VERIFY) throws CardException { +        throw new UnsupportedOperationException("Not supported yet."); +      } + +      @Override +      public byte[] modifyPin(byte[] PIN_MODIFY) throws CardException { +        throw new UnsupportedOperationException("Not supported yet."); +      } + +      @Override +      public byte[] modifyPinDirect(byte[] PIN_MODIFY) throws CardException { +        throw new UnsupportedOperationException("Not supported yet."); +      }      };    }  } 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 ad530ad5..c06074f2 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java @@ -128,7 +128,7 @@ public interface SignatureCard {            throws LockedException, NotActivatedException, CancelledException, SignatureCardException, InterruptedException;    public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider) -          throws LockedException, NotActivatedException, CancelledException, SignatureCardException, InterruptedException; +          throws LockedException, NotActivatedException, CancelledException, PINFormatException, SignatureCardException, InterruptedException;    public void activatePIN(PINSpec pinSpec, PINProvider pinProvider)            throws CancelledException, SignatureCardException, InterruptedException; 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 index 2c56ce98..56ebaffe 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ccid/CCID.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ccid/CCID.java @@ -45,17 +45,48 @@ public interface CCID {      "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); -   + +  Byte FEATURE_VERIFY_PIN_START = new Byte((byte) 0x01); +  Byte FEATURE_VERIFY_PIN_FINISH = new Byte((byte) 0x02); +  Byte FEATURE_MODIFY_PIN_START = new Byte((byte) 0x03); +  Byte FEATURE_MODIFY_PIN_FINISH = new Byte((byte) 0x04); +  Byte FEATURE_GET_KEY_PRESSED = new Byte((byte) 0x05); +  Byte FEATURE_VERIFY_PIN_DIRECT = new Byte((byte) 0x06); +  Byte FEATURE_MODIFY_PIN_DIRECT = new Byte((byte) 0x07); +  Byte FEATURE_MCT_READER_DIRECT = new Byte((byte) 0x08); +  Byte FEATURE_MCT_UNIVERSAL = new Byte((byte) 0x09); +  Byte FEATURE_IFD_PIN_PROPERTIES = new Byte((byte) 0x0a); +  //TODO continue list + +  String getName(); +    Card connect() throws CardException;    boolean hasFeature(Byte feature);    /** +   * not supported by OMNIKEY CardMan 3621 with ACOS card +   * @param PIN_VERIFY +   * @return +   * @throws at.gv.egiz.smcc.PINOperationAbortedException +   * @throws javax.smartcardio.CardException +   */ +  byte[] verifyPin(byte[] PIN_VERIFY) throws PINOperationAbortedException, CardException; +   +  byte[] verifyPinDirect(byte[] PIN_VERIFY) throws CardException; + +  /** +   * not supported by OMNIKEY CardMan 3621 with ACOS card +   * @param PIN_MODIFY +   * @return +   * @throws at.gv.egiz.smcc.PINOperationAbortedException +   * @throws javax.smartcardio.CardException +   */ +  byte[] modifyPin(byte[] PIN_MODIFY) throws PINOperationAbortedException, CardException; + +  byte[] modifyPinDirect(byte[] PIN_MODIFY) throws CardException; + +  /**     *     * @param feature the corresponding control code will be transmitted     * @param ctrlCommand @@ -63,7 +94,7 @@ public interface CCID {     * @throws at.gv.egiz.smcc.SignatureCardException if feature is not supported     * or card communication fails     */ -  byte[] transmitControlCommand(Byte feature, byte[] ctrlCommand) throws SignatureCardException; +//  byte[] transmitControlCommand(Byte feature, byte[] ctrlCommand) throws SignatureCardException;    /**     * allow subclasses to override default (deal with reader bugs) 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 index 2cc77dc9..9b1787a0 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ccid/DefaultReader.java @@ -20,6 +20,8 @@ import at.gv.egiz.smcc.*;  import at.gv.egiz.smcc.util.SMCCHelper;  import java.util.HashMap;  import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger;  import javax.smartcardio.Card;  import javax.smartcardio.CardException;  import javax.smartcardio.CardTerminal; @@ -35,12 +37,17 @@ public class DefaultReader implements CCID {    protected final static Log log = LogFactory.getLog(DefaultReader.class);    private static int CTL_CODE(int code) { -    return 0x42000000 + code; +    String os_name = System.getProperty("os.name").toLowerCase(); +    if (os_name.indexOf("windows") > -1) { +      // cf. WinIOCTL.h +      return (0x31 << 16 | (code) << 2); +    } +    // cf. reader.h +    return 0x42000000 + (code);    }    int IOCTL_GET_FEATURE_REQUEST = CTL_CODE(3400); -    protected Card icc;    protected CardTerminal ct; @@ -58,14 +65,19 @@ public class DefaultReader implements CCID {      features = queryFeatures();     } -  public Card connect() throws CardException { //SignatureCardException { -//      try { +  /** +   * +   * @return the card terminals name +   */ +  @Override +  public String getName() { +    return ct.getName(); +  } + +  @Override +  public Card connect() throws CardException {       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() { @@ -81,7 +93,7 @@ public class DefaultReader implements CCID {                    " on " + ct.getName());          }          byte[] resp = icc.transmitControlCommand(IOCTL_GET_FEATURE_REQUEST, -                new byte[]{}); +                new byte[0]);          if (log.isTraceEnabled()) {            log.trace("Response TLV " + SMCCHelper.toString(resp)); @@ -91,8 +103,10 @@ public class DefaultReader implements CCID {          // 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]; +          int ioctlBigEndian = ((0xff & resp[i + 2]) << 24) | +                  ((0xff & resp[i + 3]) << 16) | +                  ((0xff & resp[i + 4]) << 8) | +                  (0xff & resp[i + 5]);            Integer ioctl = new Integer(ioctlBigEndian);            if (log.isInfoEnabled()) {              log.info("CCID supports " + FEATURES[feature.intValue()] + @@ -117,37 +131,29 @@ public class DefaultReader implements CCID {      return false;    } -//  public Integer getIOCTL(Byte feature) { -//    if (features != null) { -//      return features.get(feature); +//  protected byte[] transmitControlCommand(Byte feature, byte[] ctrlCommand) +//          throws CardException { +//    try { +//      if (!features.containsKey(feature)) { +//        throw new CardException(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()]);  //    } -//    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() { @@ -162,7 +168,7 @@ public class DefaultReader implements CCID {    @Override    public byte getwPINMaxExtraDigitL() { -    return (byte) 0x12; +    return (byte) 0x12;     // signed int    }    @Override @@ -175,6 +181,265 @@ public class DefaultReader implements CCID {      return (byte) 0x02;    // validation key pressed    } +  void verifyPinStart(byte[] PIN_VERIFY) throws CardException { +    if (!features.containsKey(FEATURE_VERIFY_PIN_START)) { +      throw new CardException("FEATURE_VERIFY_PIN_START not supported"); +    } +    int ioctl = features.get(FEATURE_VERIFY_PIN_START); +    if (log.isTraceEnabled()) { +      log.trace("VERIFY_PIN_START (" + Integer.toHexString(ioctl) + +              ")  " + SMCCHelper.toString(PIN_VERIFY)); +    } +    byte[] resp = icc.transmitControlCommand(ioctl, PIN_VERIFY); +    if (resp != null && resp.length > 0) { +      if (resp[0] == (byte) 0x57) { +        log.error("Invalid parameter in PIN_VERIFY structure"); +        throw new CardException("ERROR_INVALID_PARAMETER"); +      } else { +        log.error("unexpected response to VERIFY_PIN_START: " + +                SMCCHelper.toString(resp)); +        throw new CardException("unexpected response to VERIFY_PIN_START: " + +                SMCCHelper.toString(resp)); +      } +    } +  } + +  byte[] verifyPinFinish() throws CardException { +    if (!features.containsKey(FEATURE_VERIFY_PIN_FINISH)) { +      throw new CardException("FEATURE_VERIFY_FINISH_FINISH not supported"); +    } +    int ioctl = features.get(FEATURE_VERIFY_PIN_FINISH); +    if (log.isTraceEnabled()) { +      log.trace("VERIFY_PIN_FINISH (" + Integer.toHexString(ioctl) + ")"); +    } +    byte[] resp = icc.transmitControlCommand(ioctl, new byte[0]); +    if (resp != null && resp.length == 2) { +      if (log.isTraceEnabled()) { +        log.trace("response " + SMCCHelper.toString(resp)); +      } +      return resp; +    } +    log.error("unexpected response to VERIFY_PIN_FINISH: " + +            SMCCHelper.toString(resp)); +    throw new CardException("unexpected response to VERIFY_PIN_FINISH: " + +            SMCCHelper.toString(resp)); +  } + +  void modifyPinStart(byte[] PIN_MODIFY) throws CardException { +    if (!features.containsKey(FEATURE_MODIFY_PIN_START)) { +      throw new CardException("FEATURE_MODIFY_PIN_START not supported"); +    } +    int ioctl = features.get(FEATURE_MODIFY_PIN_START); +    if (log.isTraceEnabled()) { +      log.trace("MODFIY_PIN_START (" + Integer.toHexString(ioctl) + +              ")  " + SMCCHelper.toString(PIN_MODIFY)); +    } +    byte[] resp = icc.transmitControlCommand(ioctl, PIN_MODIFY); +    if (resp != null && resp.length > 0) { +      if (resp[0] == (byte) 0x57) { +        log.error("Invalid parameter in PIN_MODIFY structure"); +        throw new CardException("ERROR_INVALID_PARAMETER"); +      } else { +        log.error("unexpected response to MODIFY_PIN_START: " + +                SMCCHelper.toString(resp)); +        throw new CardException("unexpected response to MODIFY_PIN_START: " + +                SMCCHelper.toString(resp)); +      } +    } +  } + +  byte[] modifyPinFinish() throws CardException { +    if (!features.containsKey(FEATURE_MODIFY_PIN_FINISH)) { +      throw new CardException("FEATURE_MODIFY_FINISH_FINISH not supported"); +    } +    int ioctl = features.get(FEATURE_MODIFY_PIN_FINISH); +    if (log.isTraceEnabled()) { +      log.trace("MODIFY_PIN_FINISH (" + Integer.toHexString(ioctl) + ")"); +    } +    byte[] resp = icc.transmitControlCommand(ioctl, new byte[0]); +    if (resp != null && resp.length == 2) { +      if (log.isTraceEnabled()) { +        log.trace("response " + SMCCHelper.toString(resp)); +      } +      return resp; +    } +    log.error("unexpected response to MODIFY_PIN_FINISH: " + +            SMCCHelper.toString(resp)); +    throw new CardException("unexpected response to MODIFY_PIN_FINISH: " + +            SMCCHelper.toString(resp)); +  } + + +  byte getKeyPressed() throws CardException { +    if (!features.containsKey(FEATURE_GET_KEY_PRESSED)) { +      throw new CardException("FEATURE_GET_KEY_PRESSED not supported"); +    } +    int ioctl = features.get(FEATURE_GET_KEY_PRESSED); +//    if (log.isTraceEnabled()) { +//      log.trace("GET_KEY_PRESSED (" + Integer.toHexString(ioctl) + ")"); +//    } +    byte[] resp = icc.transmitControlCommand(ioctl, new byte[0]); +    if (resp != null && resp.length == 1) { +//      if (log.isTraceEnabled()) { +//        log.trace("response " + SMCCHelper.toString(resp)); +//      } +      return resp[0]; +    } +    log.error("unexpected response to GET_KEY_PRESSED: " + +            SMCCHelper.toString(resp)); +    throw new CardException("unexpected response to GET_KEY_PRESSED: " + +            SMCCHelper.toString(resp)); +  } + + + +  @Override +  public byte[] verifyPinDirect(byte[] PIN_VERIFY) throws CardException { +    if (!features.containsKey(FEATURE_VERIFY_PIN_DIRECT)) { +      throw new CardException("FEATURE_VERIFY_PIN_DIRECT not supported"); +    } +    int ioctl = features.get(FEATURE_VERIFY_PIN_DIRECT); +    if (log.isTraceEnabled()) { +      log.trace("VERIFY_PIN_DIRECT (" + Integer.toHexString(ioctl) + +              ")  " + SMCCHelper.toString(PIN_VERIFY)); +    } +    byte[] resp = icc.transmitControlCommand(ioctl, PIN_VERIFY); +    if (log.isTraceEnabled()) { +      log.trace("response " + SMCCHelper.toString(resp)); +    } +    return resp; +  } + +  @Override +  public byte[] verifyPin(byte[] PIN_VERIFY) throws PINOperationAbortedException, CardException { +    verifyPinStart(PIN_VERIFY); +    byte resp; +    do { +      resp = getKeyPressed(); +      if (resp == (byte) 0x00) { +        synchronized(this) { +          try { +            wait(200); +          } catch (InterruptedException ex) { +            log.error("interrupted in VERIFY_PIN"); +          } +        } +      } else if (resp == (byte) 0x0d) { +        log.trace("user confirmed"); +        break; +      } else if (resp == (byte) 0x2b) { +        log.trace("user entered valid key (0-9)"); +      } else if (resp == (byte) 0x1b) { +        log.info("user cancelled VERIFY_PIN via cancel button"); +        return verifyPinFinish(); +//        return new byte[] { (byte) 0x64, (byte) 0x01 }; +      } else if (resp == (byte) 0x08) { +        log.trace("user pressed correction/backspace button"); +      } else if (resp == (byte) 0x0e) { +        log.trace("timeout occured"); +        return verifyPinFinish(); // return 0x64 0x00 +      } else if (resp == (byte) 0x40) { +        log.trace("PIN_Operation_Aborted"); +        throw new PINOperationAbortedException("PIN_Operation_Aborted"); +      } else if (resp == (byte) 0x0a) { +        log.trace("all keys cleared"); +      } else { +        log.error("unexpected response to GET_KEY_PRESSED: " + +            Integer.toHexString(resp)); +        throw new CardException("unexpected response to GET_KEY_PRESSED: " + +            Integer.toHexString(resp)); +      } +    } while (true); //resp != (byte) 0x0d); + +    return verifyPinFinish(); +  } + +  @Override +  public byte[] modifyPin(byte[] PIN_MODIFY) throws PINOperationAbortedException, CardException { +    modifyPinStart(PIN_MODIFY); +    log.debug(PIN_MODIFY[9] + " pin confirmations expected"); + +    byte resp; +    short pinConfirmations = 0; +    do { +      resp = getKeyPressed(); +      if (resp == (byte) 0x00) { +        synchronized(this) { +          try { +            wait(200); +          } catch (InterruptedException ex) { +            log.error("interrupted in MODIFY_PIN"); +          } +        } +      } else if (resp == (byte) 0x0d) { +        log.trace("user confirmed"); +        pinConfirmations++; +        continue; +      } else if (resp == (byte) 0x2b) { +        log.trace("user entered valid key (0-9)"); +      } else if (resp == (byte) 0x1b) { +        log.info("user cancelled MODIFY_PIN via cancel button"); +//        return verifyPinFinish(); +        return new byte[] { (byte) 0x64, (byte) 0x01 }; +      } else if (resp == (byte) 0x08) { +        log.trace("user pressed correction/backspace button"); +      } else if (resp == (byte) 0x0e) { +        log.trace("timeout occured"); +        return new byte[] { (byte) 0x64, (byte) 0x00 }; +//        return verifyPinFinish(); // return 0x64 0x00 +      } else if (resp == (byte) 0x40) { +        log.trace("PIN_Operation_Aborted"); +        throw new PINOperationAbortedException("PIN_Operation_Aborted"); +      } else if (resp == (byte) 0x0a) { +        log.trace("all keys cleared"); +      } else { +        log.error("unexpected response to GET_KEY_PRESSED: " + +            Integer.toHexString(resp)); +        throw new CardException("unexpected response to GET_KEY_PRESSED: " + +            Integer.toHexString(resp)); +      } +    } while (pinConfirmations < PIN_MODIFY[9]);  + +    return modifyPinFinish(); +  } + +  /** +   * NOT SUPPORTED FOR ACOS ON OMNIKEY CardMan 3621 +   *  +   * @param PIN_MODIFY +   * @return +   * @throws javax.smartcardio.CardException +   */ +  @Override +  public byte[] modifyPinDirect(byte[] PIN_MODIFY) throws CardException { +    if (!features.containsKey(FEATURE_MODIFY_PIN_DIRECT)) { +      throw new CardException("FEATURE_MODIFY_PIN_DIRECT not supported"); +    } +    int ioctl = features.get(FEATURE_MODIFY_PIN_DIRECT); +    if (log.isTraceEnabled()) { +      log.trace("MODIFY_PIN_DIRECT (" + Integer.toHexString(ioctl) + +              ")  " + SMCCHelper.toString(PIN_MODIFY)); +    } +    byte[] resp = icc.transmitControlCommand(ioctl, PIN_MODIFY); +    if (log.isTraceEnabled()) { +      log.trace("response " + SMCCHelper.toString(resp)); +    } +    return resp; +  } + + +//[TRACE] SmartCardIO - terminal 'PC/SC terminal OMNIKEY CardMan 3621 0' card inserted : PC/SC card in OMNIKEY CardMan 3621 0, protocol T=1, state OK +//[TRACE] DefaultReader - GET_FEATURE_REQUEST 313520 on OMNIKEY CardMan 3621 0 +//[TRACE] DefaultReader - Response TLV [01:04:00:31:30:00:02:04:00:31:2f:d4:03:04:00:31:30:04:04:04:00:31:2f:dc:05:04:00:31:2f:e0:0a:04 +//00:31:30:08] +//[INFO] DefaultReader - CCID supports FEATURE_VERIFY_PIN_START: 313000 +//[INFO] DefaultReader - CCID supports FEATURE_VERIFY_PIN_FINISH: ffffffd4 +//[INFO] DefaultReader - CCID supports FEATURE_MODIFY_PIN_START: 313004 +//[INFO] DefaultReader - CCID supports FEATURE_MODIFY_PIN_FINISH: ffffffdc +//[INFO] DefaultReader - CCID supports FEATURE_GET_KEY_PRESSED: ffffffe0 +//[INFO] DefaultReader - CCID supports FEATURE_IFD_PIN_PROPERTIES: 313008 +//[TRACE] AbstractSignatureCard - Setting IFS (information field size) to 254 +    //  protected byte ifdGetKeyPressed() throws CardException {  //    if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) { diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ccid/OMNIKEYCardMan3621.java b/smcc/src/main/java/at/gv/egiz/smcc/ccid/OMNIKEYCardMan3621.java new file mode 100644 index 00000000..35dd4f99 --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/ccid/OMNIKEYCardMan3621.java @@ -0,0 +1,39 @@ +/* + * Copyright 2008 Federal Chancellery Austria and + * Graz University of Technology + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package at.gv.egiz.smcc.ccid; + +import javax.smartcardio.Card; +import javax.smartcardio.CardTerminal; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Fails with ACOS cards (Problem might be 'short' VERIFY which is not supported by ACOS) + * TODO + * + * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at> + */ +public class OMNIKEYCardMan3621 extends DefaultReader { + +  protected static final Log log = LogFactory.getLog(OMNIKEYCardMan3621.class); +   +  public OMNIKEYCardMan3621(Card icc, CardTerminal ct) { +    super(icc, ct); +    log.warn("This card reader does not support ACOS cards."); +    log.debug("TODO: fall back to software pin entry"); +  } +} 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 index 2cfcef19..07c16c3e 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ccid/ReaderFactory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ccid/ReaderFactory.java @@ -29,6 +29,8 @@ 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); +    } else if ("OmniKey CardMan 3621 00 00".equals(ct.getName())) { +      return new OMNIKEYCardMan3621(icc, ct);      }      return new DefaultReader(icc, ct);    } | 
