diff options
| author | clemenso <clemenso@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4> | 2009-03-18 22:27:28 +0000 | 
|---|---|---|
| committer | clemenso <clemenso@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4> | 2009-03-18 22:27:28 +0000 | 
| commit | 2a1df5e58e44f8d77f34eb80df74e8c0d27caceb (patch) | |
| tree | 5603a81674a1fe60373ba0a3ca37b03473eeb92a /smcc/src/main/java/at/gv | |
| parent | 2f49ed7ea3649a51a9457b99004c8cb0ca443432 (diff) | |
| download | mocca-2a1df5e58e44f8d77f34eb80df74e8c0d27caceb.tar.gz mocca-2a1df5e58e44f8d77f34eb80df74e8c0d27caceb.tar.bz2 mocca-2a1df5e58e44f8d77f34eb80df74e8c0d27caceb.zip | |
1.1-rc5 (pinProviderFactories, gui refactoring, signatureCard, secureViewer)
git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@322 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4
Diffstat (limited to 'smcc/src/main/java/at/gv')
10 files changed, 1097 insertions, 358 deletions
| diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ACOS04Card.java b/smcc/src/main/java/at/gv/egiz/smcc/ACOS04Card.java new file mode 100644 index 00000000..9fca6ab9 --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOS04Card.java @@ -0,0 +1,30 @@ +/* + * Copyright 2008 Federal Chancellery Austria and + * Graz University of Technology + *  + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *  + *     http://www.apache.org/licenses/LICENSE-2.0 + *  + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package at.gv.egiz.smcc; + +/** + * + * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at> + */ +public class ACOS04Card extends ACOSCard { + +  public ACOS04Card() { +    pinSpecs.remove(PINSPEC_INF); +  } + +} 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 c2c62fd8..01b9155b 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java @@ -29,9 +29,10 @@  package at.gv.egiz.smcc;  import at.gv.egiz.smcc.util.SMCCHelper; +import java.nio.ByteBuffer; +import java.nio.CharBuffer;  import java.nio.charset.Charset; -import javax.smartcardio.Card;  import javax.smartcardio.CardChannel;  import javax.smartcardio.CardException;  import javax.smartcardio.CommandAPDU; @@ -100,9 +101,9 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {        (byte) 0x01 // RSA // TODO: Not verified yet    }; -  private static final int PINSPEC_INF = 0; -  private static final int PINSPEC_DEC = 1; -  private static final int PINSPEC_SIG = 2; +  protected static final int PINSPEC_INF = 0; +  protected static final int PINSPEC_DEC = 1; +  protected static final int PINSPEC_SIG = 2;    public ACOSCard() {      super("at/gv/egiz/smcc/ACOSCard"); @@ -179,15 +180,12 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {          //new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("inf.pin.name"));          int retries = -1; -        String pin = null; +        char[] pin = null;          boolean pinRequiered = false;          do {            if (pinRequiered) {              pin = provider.providePIN(spec, retries); -            if (pin == null) { -              throw new CancelledException(); -            }            }            try {              getCard().beginExclusive(); @@ -234,20 +232,17 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {          //new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name"));          int retries = -1; -        String pin = null; +        char[] pin = null;          do {            pin = provider.providePIN(spec, retries); -          if (pin == null) { -            throw new CancelledException(); -          }            try {              getCard().beginExclusive();              // SELECT DF              selectFileFID(DF_SIG);              // VERIFY -            retries = verifyPIN(pin, KID_PIN_SIG); +            retries = verifyPIN(KID_PIN_SIG, pin);              if (retries != -1) {                throw new VerificationFailedException(retries);              } @@ -259,7 +254,7 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {              return psoComputDigitalSiganture();            } catch (SecurityStatusNotSatisfiedException e) { -            retries = verifyPIN(null, KID_PIN_SIG); +            retries = verifyPIN(KID_PIN_SIG);            } catch (VerificationFailedException e) {              retries = e.getRetries();            } finally { @@ -276,15 +271,12 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {          //new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("dec.pin.name"));          int retries = -1; -        String pin = null; -        boolean pinRequiered = false; +        char[] pin = null; +        boolean pinRequired = false;          do { -          if (pinRequiered) { +          if (pinRequired) {              pin = provider.providePIN(spec, retries); -            if (pin == null) { -              throw new CancelledException(); -            }            }            try {              getCard().beginExclusive(); @@ -292,7 +284,7 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {              // SELECT DF              selectFileFID(DF_DEC);              // VERIFY -            retries = verifyPIN(pin, KID_PIN_DEC); +            retries = verifyPIN(KID_PIN_DEC, pin);              if (retries != -1) {                throw new VerificationFailedException(retries);              } @@ -304,10 +296,10 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {            } catch (FileNotFoundException e) {              throw new NotActivatedException();            } catch (SecurityStatusNotSatisfiedException e) { -            pinRequiered = true; -            retries = verifyPIN(null, KID_PIN_DEC); +            pinRequired = true; +            retries = verifyPIN(KID_PIN_DEC);            } catch (VerificationFailedException e) { -            pinRequiered = true; +            pinRequired = true;              retries = e.getRetries();            } finally {              getCard().endExclusive(); @@ -328,48 +320,16 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {    } +  //////////////////////////////////////////////////////////////////////// +  // PROTECTED METHODS (assume exclusive card access) +  //////////////////////////////////////////////////////////////////////// +    protected ResponseAPDU selectFileFID(byte[] fid) throws CardException, SignatureCardException {      CardChannel channel = getCardChannel();      return transmit(channel, new CommandAPDU(0x00, 0xA4, 0x00,          0x00, fid, 256));    } -  @Override -  protected int verifyPIN(String pin, byte kid) throws LockedException, NotActivatedException, SignatureCardException { - -    CardChannel channel = getCardChannel(); - -    ResponseAPDU resp; -    try { -      if (pin != null) { -        resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, kid, encodePINBlock(pin)), false); -      } else { -        //TODO this is not supported -        resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, kid), false); -      } -    } catch (CardException ex) { -      log.error("smart card communication failed: " + ex.getMessage()); -      throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex); -    } - -    //6A 00 (falshe P1/P2) nicht in contextAID -    //69 85 (nutzungsbedingungen nicht erfüllt) in DF_Sig und nicht sigpin - -    if (resp.getSW() == 0x63c0) { -      throw new LockedException("PIN locked."); -    } else if (resp.getSW1() == 0x63 && resp.getSW2() >> 4 == 0xc) { -      // return number of possible retries -      return resp.getSW2() & 0x0f; -    } else if (resp.getSW() == 0x6983) { -      throw new NotActivatedException(); -    } else if (resp.getSW() == 0x9000) { -      return -1; -    } else { -      throw new SignatureCardException("Failed to verify pin: SW=" -          + Integer.toHexString(resp.getSW()) + "."); -    } -  } -      private void mseSetDST(int p1, int p2, byte[] dst) throws CardException, SignatureCardException {      CardChannel channel = getCardChannel();      ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x22, p1, @@ -426,92 +386,294 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {      }    } -  @Override -  public String toString() { -    return "a-sign premium"; -  } -    /** -   * ASCII encoded pin, padded with 0x00 -   * @param pin -   * @return a 8 byte pin block  +   * +   * @param kid +   * @return -1     */ -  private byte[] encodePINBlock(String pin) { -    byte[] asciiPIN = pin.getBytes(Charset.forName("ASCII")); -    byte[] encodedPIN = new byte[8]; -    System.arraycopy(asciiPIN, 0, encodedPIN, 0, Math.min(asciiPIN.length, -        encodedPIN.length)); -//    System.out.println("ASCII encoded PIN block: " + SMCCHelper.toString(encodedPIN)); -    return encodedPIN; +  @Override +  protected int verifyPIN(byte kid) { +    log.debug("VERIFY PIN without PIN BLOCK not supported by ACOS"); +    return -1;    }    @Override -  public void activatePIN(PINSpec pinSpec, String pin) throws SignatureCardException { -    throw new SignatureCardException("PIN activation not supported by this card"); +  protected int verifyPIN(byte kid, char[] pin) +          throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException { +    try { +      byte[] sw; +      if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) { +        log.debug("verify PIN on IFD"); +        sw = transmitControlCommand( +                ifdCtrlCmds.get(FEATURE_VERIFY_PIN_DIRECT), +                getPINVerifyStructure(kid)); +//        int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff; +      } else { +        byte[] pinBlock = encodePINBlock(pin); +        CardChannel channel = getCardChannel(); +        ResponseAPDU resp = transmit(channel, +                new CommandAPDU(0x00, 0x20, 0x00, kid, pinBlock), false); +        sw = new byte[2]; +        sw[0] = (byte) resp.getSW1(); +        sw[1] = (byte) resp.getSW2(); +      } + +      //6A 00 (falshe P1/P2) nicht in contextAID +      //69 85 (nutzungsbedingungen nicht erfüllt) in DF_Sig und nicht sigpin + +      if (sw[0] == (byte) 0x90 && sw[1] == (byte) 0x00) { +        return -1; +      } else if (sw[0] == (byte) 0x63 && sw[1] == (byte) 0xc0) { +        throw new LockedException("[63:c0]"); +      } else if (sw[0] == (byte) 0x63 && (sw[1] & 0xf0) >> 4 == 0xc) { +        return sw[1] & 0x0f; +      } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x83) { +        //Authentisierungsmethode gesperrt +        throw new NotActivatedException("[69:83]"); +//      } 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 (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) { +        throw new CancelledException("[64:01]"); +      } +      log.error("Failed to verify pin: SW=" +              + SMCCHelper.toString(sw)); +      throw new SignatureCardException(SMCCHelper.toString(sw)); + +    } catch (CardException ex) { +      log.error("smart card communication failed: " + ex.getMessage()); +      throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex); +    }    }    /**     * SCARD_E_NOT_TRANSACTED inf/dec PIN not active (pcsc crash) -   * @param pinSpec -   * @param oldPIN -   * @param newPIN +   * @param kid +   * @param oldPin +   * @param newPin +   * @return     * @throws at.gv.egiz.smcc.LockedException -   * @throws at.gv.egiz.smcc.VerificationFailedException     * @throws at.gv.egiz.smcc.NotActivatedException     * @throws at.gv.egiz.smcc.SignatureCardException     */    @Override -  public void changePIN(PINSpec pinSpec, String oldPIN, String newPIN) -          throws LockedException, VerificationFailedException, NotActivatedException, SignatureCardException { -    Card icc = getCard(); +  protected int changePIN(byte kid, char[] oldPin, char[] newPin) +          throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException {      try { -      icc.beginExclusive(); -      CardChannel channel = icc.getBasicChannel(); - -      if (pinSpec.getContextAID() != null) { -        ResponseAPDU responseAPDU = transmit(channel, -                new CommandAPDU(0x00, 0xa4, 0x04, 0x0c, pinSpec.getContextAID())); -        if (responseAPDU.getSW() != 0x9000) { -          icc.endExclusive(); -          String msg = "Select AID " + SMCCHelper.toString(pinSpec.getContextAID()) + -                  ": SW=" + Integer.toHexString(responseAPDU.getSW()); -          log.error(msg); -          throw new SignatureCardException(msg); -        } -      } - -      byte[] cmd = new byte[16]; -      System.arraycopy(encodePINBlock(oldPIN), 0, cmd, 0, 8); -      System.arraycopy(encodePINBlock(newPIN), 0, cmd, 8, 8); +       byte[] sw; +      if (ifdSupportsFeature(FEATURE_MODIFY_PIN_DIRECT)) { +        log.debug("modify PIN on IFD"); +        sw = transmitControlCommand( +                ifdCtrlCmds.get(FEATURE_MODIFY_PIN_DIRECT), +                getPINModifyStructure(kid)); +//        int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff; +      } else { +        byte[] cmd = new byte[16]; +        System.arraycopy(encodePINBlock(oldPin), 0, cmd, 0, 8); +        System.arraycopy(encodePINBlock(newPin), 0, cmd, 8, 8); -      ResponseAPDU responseAPDU = transmit(channel, -              new CommandAPDU(0x00, 0x24, 0x00, pinSpec.getKID(), cmd), false); +        CardChannel channel = getCardChannel(); -      icc.endExclusive(); +        ResponseAPDU resp = transmit(channel, +                new CommandAPDU(0x00, 0x24, 0x00, kid, cmd), false); -      log.debug("change pin returned SW=" + Integer.toHexString(responseAPDU.getSW())); +        sw = new byte[2]; +        sw[0] = (byte) resp.getSW1(); +        sw[1] = (byte) resp.getSW2(); +      } -      if (responseAPDU.getSW() == 0x63c0) { -        log.error(pinSpec.getLocalizedName() + " locked"); -        throw new LockedException(); -      } else if (responseAPDU.getSW1() == 0x63 && responseAPDU.getSW2() >> 4 == 0xc) { -        int retries = responseAPDU.getSW2() & 0x0f; -        log.error("wrong " + pinSpec.getLocalizedName() + ", " + retries + " retries"); -        throw new VerificationFailedException(retries); -      } else if (responseAPDU.getSW() == 0x6983) { +      // activates pin (newPIN) if not active +      if (sw[0] == (byte) 0x90 && sw[1] == (byte) 0x00) { +        return -1; +      } else if (sw[0] == (byte) 0x63 && sw[1] == (byte) 0xc0) { +        throw new LockedException("[63:c0]"); +      } else if (sw[0] == (byte) 0x63 && (sw[1] & 0xf0) >> 4 == 0xc) { +        return sw[1] & 0x0f; +      } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x83) { +        //Authentisierungsmethode gesperrt          // sig-pin only (card not transacted for inf/dec pin) -        log.error(pinSpec.getLocalizedName() + " not activated"); -        throw new NotActivatedException(); -      } else if (responseAPDU.getSW() != 0x9000) { -        String msg = "Failed to change " + pinSpec.getLocalizedName() + -                ": SW=" + Integer.toHexString(responseAPDU.getSW()); -        log.error(msg); -        throw new SignatureCardException(msg); +        throw new NotActivatedException("[69:83]"); +      } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x00) { +        throw new TimeoutException("[64:00]"); +      } else if (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) { +        throw new CancelledException("[64:01]");        } +      log.error("Failed to change pin: SW=" +              + SMCCHelper.toString(sw)); +      throw new SignatureCardException(SMCCHelper.toString(sw)); +      } catch (CardException ex) { -      log.error("Failed to change " + pinSpec.getLocalizedName() + -              ": " + ex.getMessage()); -      throw new SignatureCardException(ex.getMessage(), ex); +      log.error("smart card communication failed: " + ex.getMessage()); +      throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex);      }    } + +  /** +   * throws SignatureCardException (PIN activation not supported by ACOS) +   * @throws at.gv.egiz.smcc.SignatureCardException +   */ +  @Override +  public void activatePIN(byte kid, char[] pin) +          throws SignatureCardException { +    log.error("ACTIVATE PIN not supported by ACOS"); +    throw new SignatureCardException("PIN activation not supported by this card"); +  } + +  /** +   * ASCII encoded pin, padded with 0x00 +   * @param pin +   * @return a 8 byte pin block +   */ +  @Override +  protected byte[] encodePINBlock(char[] pin) { +//    byte[] asciiPIN = new String(pin).getBytes(Charset.forName("ASCII")); +    CharBuffer chars = CharBuffer.wrap(pin); +    ByteBuffer bytes = Charset.forName("ASCII").encode(chars); +    byte[] asciiPIN = bytes.array(); +    byte[] encodedPIN = new byte[8]; +    System.arraycopy(asciiPIN, 0, encodedPIN, 0, Math.min(asciiPIN.length, +        encodedPIN.length)); +//    System.out.println("ASCII encoded PIN block: " + SMCCHelper.toString(encodedPIN)); +    return encodedPIN; +  } +   +  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 +                                              // ^------------ 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 +                                              //     ^-------- 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 bNumberMessage = (byte) 0x00;      // No message +      byte wLangIdL = (byte) 0x0C;            // - English? +      byte wLangIdH = (byte) 0x04;            // \ +      byte bMsgIndex = (byte) 0x00;           // Default Msg + +      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 +      }; + +      int offset = 0; +      byte[] pinVerifyStructure = new byte[offset + 19 + apdu.length]; +      pinVerifyStructure[offset++] = bTimeOut; +      pinVerifyStructure[offset++] = bTimeOut2; +      pinVerifyStructure[offset++] = bmFormatString; +      pinVerifyStructure[offset++] = bmPINBlockString; +      pinVerifyStructure[offset++] = bmPINLengthFormat; +      pinVerifyStructure[offset++] = wPINMaxExtraDigitL; +      pinVerifyStructure[offset++] = wPINMaxExtraDigitH; +      pinVerifyStructure[offset++] = bEntryValidationCondition; +      pinVerifyStructure[offset++] = bNumberMessage; +      pinVerifyStructure[offset++] = wLangIdL; +      pinVerifyStructure[offset++] = wLangIdH; +      pinVerifyStructure[offset++] = bMsgIndex; + +      pinVerifyStructure[offset++] = 0x00; +      pinVerifyStructure[offset++] = 0x00; +      pinVerifyStructure[offset++] = 0x00; + +      pinVerifyStructure[offset++] = (byte) apdu.length; +      pinVerifyStructure[offset++] = 0x00; +      pinVerifyStructure[offset++] = 0x00; +      pinVerifyStructure[offset++] = 0x00; +      System.arraycopy(apdu, 0, pinVerifyStructure, offset, apdu.length); + +      return pinVerifyStructure; +  } +   +  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 +                                              // ^------------ 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 +                                              //     ^-------- System bit units is bit +                                              //       ^^^^--- PIN length is at the 4th position bit +      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[] 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                // ... +      }; + +      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); + +      return pinModifyStructure; +  } + +  @Override +  public String toString() { +    return "a-sign premium"; +  }  } 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 39952bb9..6587aaf9 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java @@ -33,12 +33,12 @@ 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; @@ -54,6 +54,14 @@ 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; @@ -106,11 +114,14 @@ public abstract class AbstractSignatureCard implements SignatureCard {     */    protected byte[] selectFileAID(byte[] dfName) throws CardException, SignatureCardException {      CardChannel channel = getCardChannel(); -    ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x04, -        0x00, dfName, 256)); +    ResponseAPDU resp = transmit(channel, +            new CommandAPDU(0x00, 0xA4, 0x04, 0x00, dfName, 256)); +//            new CommandAPDU(0x00, 0xa4, 0x04, 0x0c, dfName));      if (resp.getSW() != 0x9000) { -      throw new SignatureCardException("Failed to select application AID=" -          + toString(dfName) + ": SW=" + Integer.toHexString(resp.getSW()) + "."); +      String msg = "Failed to select application AID=" + SMCCHelper.toString(dfName) + +              ": SW=" + Integer.toHexString(resp.getSW()); +      log.error(msg); +      throw new SignatureCardException(msg);      } else {        return resp.getBytes();      } @@ -119,10 +130,63 @@ public abstract class AbstractSignatureCard implements SignatureCard {    protected abstract ResponseAPDU selectFileFID(byte[] fid) throws CardException,        SignatureCardException; -  protected abstract int verifyPIN(String pin, byte kid)  +  /** +   * VERIFY APDU without PIN BLOCK +   * Not supported by ACOS cards (and GemPC Pinpad?) +   * @param kid +   * @return the number of possible tries until card is blocked or -1 if unknown +   * (ACOS does not support this VERIFY APDU type) +   * @throws at.gv.egiz.smcc.LockedException +   * @throws at.gv.egiz.smcc.NotActivatedException +   * @throws at.gv.egiz.smcc.SignatureCardException +   */ +  protected abstract int verifyPIN(byte kid)            throws LockedException, NotActivatedException, SignatureCardException; -   +  /** +   * VERIFY APDU with PIN BLOCK +   * If IFD supports VERIFY_PIN on pinpad, parameter pin may be empty. +   * @param kid +   * @param pin to be encoded in the PIN BLOCK +   * @return -1 if VERIFY PIN was successful, or the number of possible retries +   * @throws at.gv.egiz.smcc.LockedException +   * @throws at.gv.egiz.smcc.NotActivatedException +   * @throws at.gv.egiz.smcc.SignatureCardException +   */ +  protected abstract int verifyPIN(byte kid, char[] pin) +          throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException; + +  /** +   * CHANGE(?) APDU +   * If IFD supports VERIFY_PIN on pinpad, parameter pin may be empty. +   * @param kid +   * @param pin +   * @throws at.gv.egiz.smcc.SignatureCardException if activation fails +   */ +  protected abstract void activatePIN(byte kid, char[] pin) +          throws CancelledException, TimeoutException, SignatureCardException; + +  /** +   * CHANGE(?) APDU +   * If IFD supports VERIFY_PIN on pinpad, parameter pin may be empty. +   * @param kid +   * @param pin +   * @return -1 if CHANGE PIN was successful, or the number of possible retries +   * @throws at.gv.egiz.smcc.SignatureCardException if change fails +   */ +  protected abstract int changePIN(byte kid, char[] oldPin, char[] newPin) +          throws CancelledException, TimeoutException, SignatureCardException; + +  /** +   * encode the pin as needed in VERIFY/CHANGE APDUs +   * @param pin +   * @return +   * @throws at.gv.egiz.smcc.SignatureCardException if the provided pin does +   * not meet the restrictions imposed by the encoding (not the pinSpec!), +   * such as maximum Length +   */ +  protected abstract byte[] encodePINBlock(char[] pin) throws SignatureCardException; +    protected byte[] readRecord(int recordNumber) throws SignatureCardException, CardException {      return readRecord(getCardChannel(), recordNumber);    } @@ -295,7 +359,7 @@ public abstract class AbstractSignatureCard implements SignatureCard {     * @throws SignatureCardException     * @throws CardException      */ -  protected byte[] readTLVFile(byte[] aid, byte[] ef, String pin, byte kid, int maxLength) +  protected byte[] readTLVFile(byte[] aid, byte[] ef, char[] pin, byte kid, int maxLength)        throws SignatureCardException, InterruptedException, CardException { @@ -318,7 +382,7 @@ public abstract class AbstractSignatureCard implements SignatureCard {      // VERIFY      if (pin != null) { -      int retries = verifyPIN(pin, kid); +      int retries = verifyPIN(kid, pin);        if (retries != -1) {          throw new VerificationFailedException(retries);        } @@ -388,6 +452,7 @@ public abstract class AbstractSignatureCard implements SignatureCard {        ifs_ = 0xFF & atr.getBytes()[6];        log.trace("Setting IFS (information field size) to " + ifs_);      } +    ifdCtrlCmds = queryIFDFeatures();    }    @Override @@ -446,39 +511,266 @@ public abstract class AbstractSignatureCard implements SignatureCard {    }    @Override -  public int verifyPIN(PINSpec pinSpec, String pin) throws LockedException, NotActivatedException, SignatureCardException { - -    Card icc = getCard(); +  public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider) +          throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException, InterruptedException {      try { -      icc.beginExclusive(); -      CardChannel channel = icc.getBasicChannel(); +      getCard().beginExclusive();        if (pinSpec.getContextAID() != null) { -        ResponseAPDU responseAPDU = transmit(channel, -                new CommandAPDU(0x00, 0xa4, 0x04, 0x0c, pinSpec.getContextAID())); -        if (responseAPDU.getSW() != 0x9000) { -          icc.endExclusive(); -          String msg = "Failed to verify PIN " + -                  SMCCHelper.toString(new byte[]{pinSpec.getKID()}) + -                  ": Failed to verify AID " + -                  SMCCHelper.toString(pinSpec.getContextAID()) + -                  ": " + SMCCHelper.toString(responseAPDU.getBytes()); -          log.error(msg); -          throw new SignatureCardException(msg); -        } +        selectFileAID(pinSpec.getContextAID());        } -      return verifyPIN(pin, pinSpec.getKID()); + +      int retries = verifyPIN(pinSpec.getKID()); +      do { +        char[] pin = pinProvider.providePIN(pinSpec, retries); +        retries = verifyPIN(pinSpec.getKID(), pin); +      } while (retries > 0); +      //return on -1, 0 never reached: verifyPIN throws LockedEx      } catch (CardException ex) { -      log.error("failed to verify pinspec: " + ex.getMessage(), ex); +      log.error("failed to verify " + pinSpec.getLocalizedName() + +              ": " + ex.getMessage(), ex);        throw new SignatureCardException(ex);      } finally {        try { -        icc.endExclusive(); +        getCard().endExclusive(); +      } catch (CardException ex) { +        log.trace("failed to end exclusive card access: " + ex.getMessage()); +      } +    } +  } + +  @Override +  public void activatePIN(PINSpec pinSpec, PINProvider pinProvider) +          throws CancelledException, SignatureCardException, CancelledException, TimeoutException, InterruptedException { +   try { +      getCard().beginExclusive(); + +      if (pinSpec.getContextAID() != null) { +        selectFileAID(pinSpec.getContextAID()); +      } +      char[] pin = pinProvider.providePIN(pinSpec, -1); +      activatePIN(pinSpec.getKID(), pin); +       +    } catch (CardException ex) { +      log.error("Failed to activate " + pinSpec.getLocalizedName() + +              ": " + ex.getMessage()); +      throw new SignatureCardException(ex.getMessage(), ex); +    } finally { +      try { +        getCard().endExclusive();        } catch (CardException ex) {          log.trace("failed to end exclusive card access: " + ex.getMessage());        } +    } +  } + +  /** +   * activates pin (newPIN) if not active +   * @param pinSpec +   * @param oldPIN +   * @param newPIN +   * @throws at.gv.egiz.smcc.LockedException +   * @throws at.gv.egiz.smcc.VerificationFailedException +   * @throws at.gv.egiz.smcc.NotActivatedException +   * @throws at.gv.egiz.smcc.SignatureCardException +   */ +  @Override +  public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider) +          throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException, InterruptedException { +    try { +      getCard().beginExclusive(); + +      if (pinSpec.getContextAID() != null) { +        selectFileAID(pinSpec.getContextAID()); +      } + +      int retries = verifyPIN(pinSpec.getKID()); +      do { +        char[] newPin = pinProvider.providePIN(pinSpec, retries); +        char[] oldPin = pinProvider.provideOldPIN(pinSpec, retries); +        retries = changePIN(pinSpec.getKID(), oldPin, newPin); +      } while (retries > 0); +      //return on -1, 0 never reached: verifyPIN throws LockedEx +    } catch (CardException ex) { +      log.error("Failed to change " + pinSpec.getLocalizedName() + +              ": " + ex.getMessage()); +      throw new SignatureCardException(ex.getMessage(), ex); +    } finally { +      try { +        getCard().endExclusive(); +      } catch (CardException ex) { +        log.trace("failed to end exclusive card access: " + ex.getMessage()); +      }      }    } + +  @Override +  public void unblockPIN(PINSpec pinSpec, PINProvider pinProvider) +          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/ChangePINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.java new file mode 100644 index 00000000..d0622aa4 --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/ChangePINProvider.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; + +import at.gv.egiz.smcc.*; + +/** + * + * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at> + */ +public interface ChangePINProvider extends PINProvider { + +  /** +   * +   * @param spec +   * @param retries +   * @return null if no old value for this pin +   * @throws at.gv.egiz.smcc.CancelledException if cancelled by user +   * @throws java.lang.InterruptedException +   */ +  public char[] provideOldPIN(PINSpec spec, int retries) +          throws CancelledException, InterruptedException; + +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java index e0104618..8fa80dcb 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/PINProvider.java @@ -28,8 +28,30 @@  //  package at.gv.egiz.smcc; +/** + * The number of retries is not fixed and there is no way (?) to obtain this value. + * A PINProvider should therefore maintain an internal retry counter or flag + * to decide whether or not to warn the user (num retries passed in providePIN). + * + * Therefore PINProvider objects should not be reused. + * + * (ACOS: reload counter: between 0 and 15, where 15 meens deactivated) + * + * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at> + */  public interface PINProvider { -   -  public String providePIN(PINSpec spec, int retries) throws InterruptedException; + +  /** +   * +   * @param spec +   * @param retries num of remaining retries or -1 if unknown +   * (a positive value does <em>not</em> necessarily signify that there was +   * already an unsuccessful PIN verification) +   * @return pin != null +   * @throws at.gv.egiz.smcc.CancelledException +   * @throws java.lang.InterruptedException +   */ +  public char[] providePIN(PINSpec spec, int retries) +          throws CancelledException, InterruptedException;  } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java index 3c5f38a2..91245c50 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java @@ -30,7 +30,6 @@ package at.gv.egiz.smcc;  import at.gv.egiz.smcc.util.SMCCHelper;  import java.util.Arrays; -import javax.smartcardio.Card;  import javax.smartcardio.CardChannel;  import javax.smartcardio.CardException;  import javax.smartcardio.CommandAPDU; @@ -223,15 +222,12 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard          //new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name"));          int retries = -1; -        String pin = null; +        char[] pin = null;          boolean pinRequiered = false;          do {            if (pinRequiered) {              pin = provider.providePIN(spec, retries); -            if (pin == null) { -              throw new CancelledException(); -            }            }            try {              getCard().beginExclusive(); @@ -240,7 +236,7 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard              throw new NotActivatedException();            } catch (SecurityStatusNotSatisfiedException e) {              pinRequiered = true; -            retries = verifyPIN(null, KID_PIN_CARD); +            retries = verifyPIN(KID_PIN_CARD);            } catch (VerificationFailedException e) {              pinRequiered = true;              retries = e.getRetries(); @@ -316,20 +312,17 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard          //new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name"));          int retries = -1; -        String pin = null; +        char[] pin = null;          do {            try {              getCard().beginExclusive();              selectFileAID(AID_DF_SS); -            retries = verifyPIN(null, KID_PIN_SS); +            retries = verifyPIN(KID_PIN_SS); //, null);            } finally {              getCard().endExclusive();            }            pin = provider.providePIN(spec, retries); -          if (pin == null) { -            throw new CancelledException(); -          }            try {              getCard().beginExclusive();              return createSignature(hash, AID_DF_SS, pin, KID_PIN_SS, DST_SS); @@ -349,15 +342,12 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard          //new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name"));          int retries = -1; -        String pin = null; +        char[] pin = null;          boolean pinRequiered = false;          do {            if (pinRequiered) {              pin = provider.providePIN(spec, retries); -            if (pin == null) { -              throw new CancelledException(); -            }            }            try {              getCard().beginExclusive(); @@ -366,7 +356,7 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard              throw new NotActivatedException();            } catch (SecurityStatusNotSatisfiedException e) {              pinRequiered = true; -            retries = verifyPIN(null, KID_PIN_CARD); +            retries = verifyPIN(KID_PIN_CARD);            } catch (VerificationFailedException e) {              pinRequiered = true;              retries = e.getRetries(); @@ -389,13 +379,18 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard    } + +  //////////////////////////////////////////////////////////////////////// +  // PROTECTED METHODS (assume exclusive card access) +  //////////////////////////////////////////////////////////////////////// +    protected ResponseAPDU selectFileFID(byte[] fid) throws CardException, SignatureCardException {      CardChannel channel = getCardChannel();      return transmit(channel, new CommandAPDU(0x00, 0xA4, 0x02,          0x04, fid, 256));    } -  private byte[] createSignature(byte[] hash, byte[] aid, String pin, byte kid, +  private byte[] createSignature(byte[] hash, byte[] aid, char[] pin, byte kid,        byte[] dst) throws CardException, SignatureCardException {      // SELECT MF @@ -403,7 +398,7 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard      // SELECT DF      selectFileAID(aid);      // VERIFY -    int retries = verifyPIN(pin, kid); +    int retries = verifyPIN(kid, pin);      if (retries != -1) {        throw new VerificationFailedException(retries);      } @@ -417,7 +412,6 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard    } -      private void selectMF() throws CardException, SignatureCardException {      CardChannel channel = getCardChannel();      ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x00, @@ -467,58 +461,85 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard      }    } -  /** -   * VERIFY PIN -   * <p> -   * If <code>pin</code> is <code>null</code> only the PIN status is checked and -   * returned. -   * </p> -   *  -   * @param pin -   *          the PIN (may be <code>null</code>) -   * @param kid -   *          the KID of the PIN to be verified -   *  -   * @return -1 if VERIFY PIN was successful, or the number of possible retries  -   * -   * @throws LockedException -   *            if the pin is locked -   * @throws NotActivatedException -   *           if the card application has not been activated -   * @throws SignatureCardException -   *           if VERIFY PIN fails for some other reason (card communication error) -   */    @Override -  public int verifyPIN(String pin, byte kid) throws LockedException, NotActivatedException, SignatureCardException { +  protected int verifyPIN(byte kid, char[] pin) +          throws LockedException, NotActivatedException, SignatureCardException {      try { -      CardChannel channel = getCardChannel(); - -      ResponseAPDU resp; -      if (pin == null) { -        resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, kid)); +      byte[] sw; +      if (ifdSupportsFeature(FEATURE_VERIFY_PIN_DIRECT)) { +        log.debug("verify PIN on IFD"); +        sw = transmitControlCommand( +                ifdCtrlCmds.get(FEATURE_VERIFY_PIN_DIRECT), +                getPINVerifyStructure(kid)); +//        int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff;        } else { -        // BCD encode PIN and marshal PIN block          byte[] pinBlock = encodePINBlock(pin); -        resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, kid, pinBlock), false); +        CardChannel channel = getCardChannel(); +        ResponseAPDU resp = transmit(channel, +                new CommandAPDU(0x00, 0x20, 0x00, kid, pinBlock), false); +        sw = new byte[2]; +        sw[0] = (byte) resp.getSW1(); +        sw[1] = (byte) resp.getSW2(); +      } +      if (sw[0] == (byte) 0x90 && sw[1] == (byte) 0x00) { +        return -1; +      } else if (sw[0] == (byte) 0x63 && sw[1] == (byte) 0xc0) { +        throw new LockedException("[63:c0]"); +      } else if (sw[0] == (byte) 0x63 && (sw[1] & 0xf0) >> 4 == 0xc) { +        return sw[1] & 0x0f; +      } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x83) { +        //Authentisierungsmethode gesperrt +        throw new LockedException("[69:83]"); +      } 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 (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) { +        throw new CancelledException("[64:01]");        } +      log.error("Failed to verify pin: SW=" +              + SMCCHelper.toString(sw)); +      throw new SignatureCardException(SMCCHelper.toString(sw)); +       +    } catch (CardException ex) { +      log.error("smart card communication failed: " + ex.getMessage()); +      throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex); +    } +  } -      if (resp.getSW() == 0x63c0) { -        throw new LockedException("PIN locked."); -      } else if (resp.getSW1() == 0x63 && resp.getSW2() >> 4 == 0xc) { -        // return number of possible retries +  @Override +  protected int verifyPIN(byte kid) +          throws LockedException, NotActivatedException, SignatureCardException { +    try { +      CardChannel channel = getCardChannel(); +      ResponseAPDU resp = transmit(channel, +              new CommandAPDU(0x00, 0x20, 0x00, kid), false); + +      if (resp.getSW() == 0x9000) { +        return -1; +      } else if (resp.getSW() == 0x63c0) { +        throw new LockedException("[63:c0]"); +      } else if (resp.getSW1() == 0x63 && (resp.getSW2() & 0xf0) >> 4 == 0xc) {          return resp.getSW2() & 0x0f;        } else if (resp.getSW() == 0x6983) { -        throw new LockedException(); +        //Authentisierungsmethode gesperrt +        throw new LockedException("[69:83]");        } else if (resp.getSW() == 0x6984) { -        // PIN LCS = "Initialized" (-> not activated) -        throw new NotActivatedException(); -      } else if (resp.getSW() == 0x9000) { -        return -1; // success -      } else { -        throw new SignatureCardException("Failed to verify pin: SW=" -            + Integer.toHexString(resp.getSW())); +        //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]");        } +      log.error("Failed to verify pin: SW=" +              + Integer.toHexString(resp.getSW())); +      throw new SignatureCardException("[" + Integer.toHexString(resp.getSW()) + "]"); +      } catch (CardException ex) {        log.error("smart card communication failed: " + ex.getMessage());        throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex); @@ -526,24 +547,95 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard    }    @Override -  public void reset() throws SignatureCardException { +  protected int changePIN(byte kid, char[] oldPin, char[] newPin) +          throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException {      try { -      super.reset(); -      log.debug("select MF (e-card workaround)"); -      CardChannel channel = getCardChannel(); -      ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x00, 0x0C)); -      if (resp.getSW() != 0x9000) { -        throw new SignatureCardException("Failed to select MF after RESET: SW=" + Integer.toHexString(resp.getSW()) + "."); +      byte[] sw; +      if (ifdSupportsFeature(FEATURE_MODIFY_PIN_DIRECT)) { +        log.debug("modify PIN on IFD"); +        sw = transmitControlCommand( +                ifdCtrlCmds.get(FEATURE_MODIFY_PIN_DIRECT), +                getPINModifyStructure(kid)); +//        int sw = (resp[resp.length-2] & 0xff) << 8 | resp[resp.length-1] & 0xff; +      } else { +        byte[] cmd = new byte[16]; +        System.arraycopy(encodePINBlock(oldPin), 0, cmd, 0, 8); +        System.arraycopy(encodePINBlock(newPin), 0, cmd, 8, 8); + +        CardChannel channel = getCardChannel(); + +        ResponseAPDU resp = transmit(channel, +                new CommandAPDU(0x00, 0x24, 0x00, kid, cmd), false); + +        sw = new byte[2]; +        sw[0] = (byte) resp.getSW1(); +        sw[1] = (byte) resp.getSW2(); +      } + +      // activates pin (newPIN) if not active +      if (sw[0] == (byte) 0x90 && sw[1] == (byte) 0x00) { +        return -1; +      } else if (sw[0] == (byte) 0x63 && sw[1] == (byte) 0xc0) { +        throw new LockedException("[63:c0]"); +      } else if (sw[0] == (byte) 0x63 && (sw[1] & 0xf0) >> 4 == 0xc) { +        return sw[1] & 0x0f; +      } else if (sw[0] == (byte) 0x69 && sw[1] == (byte) 0x83) { +        //Authentisierungsmethode gesperrt +        throw new LockedException("[69:83]"); +//      } 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 (sw[0] == (byte) 0x64 && sw[1] == (byte) 0x01) { +        throw new CancelledException("[64:01]");        } +      log.error("Failed to change pin: SW=" +              + SMCCHelper.toString(sw)); +      throw new SignatureCardException(SMCCHelper.toString(sw));      } catch (CardException ex) { -      log.error("Failed to select MF after RESET: " + ex.getMessage(), ex); -      throw new SignatureCardException("Failed to select MF after RESET"); +      log.error("smart card communication failed: " + ex.getMessage()); +      throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex);      }    } +  @Override +  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); + +      log.trace("activate pin returned SW=" + Integer.toHexString(resp.getSW())); -  public String toString() { -    return "e-card"; +      if (resp.getSW1() == 0x9000) { +        return; +      } else if (resp.getSW() == 0x6983) { +        //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) { +        throw new TimeoutException("[64:00]"); +      } else if (resp.getSW() == 0x6401) { +        throw new CancelledException("[64:01]"); +      } +      log.error("Failed to activate pin: SW=" + +              Integer.toHexString(resp.getSW())); +      throw new SignatureCardException("[" + Integer.toHexString(resp.getSW()) + "]"); + +    } catch (CardException ex) { +      log.error("smart card communication failed: " + ex.getMessage()); +      throw new SignatureCardException("smart card communication failed: " + ex.getMessage(), ex); +    }    }    /** @@ -552,17 +644,20 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard     * @return a 8 byte pin block consisting of length byte (0x2X),     * the BCD encoded pin and a 0xFF padding     */ -  private byte[] encodePINBlock(String pin) { -    char[] pinChars = pin.toCharArray(); -    int numDigits = pinChars.length; +  @Override +  protected byte[] encodePINBlock(char[] pin) throws SignatureCardException { +    if (pin == null || pin.length > 12) { +      throw new SignatureCardException("invalid pin: " + pin); +    } +    int numDigits = pin.length;      int numBytes = (int) Math.ceil(numDigits/2.0);      byte[] pinBlock = new byte[8];      pinBlock[0] = (byte) (0x20 | numDigits);      for (int i = 0; i < numBytes; i++) { -      int p1 = 16*Character.digit(pinChars[i*2], 16); -      int p2 = (i*2+1 < numDigits) ? Character.digit(pinChars[i*2+1], 16) : 0xf; +      int p1 = 16*Character.digit(pin[i*2], 16); +      int p2 = (i*2+1 < numDigits) ? Character.digit(pin[i*2+1], 16) : 0xf;        pinBlock[i+1] = (byte) (p1 + p2);      }      Arrays.fill(pinBlock, numBytes + 1, pinBlock.length, (byte) 0xff); @@ -570,111 +665,151 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard      return pinBlock;    } +   +  private byte[] getPINVerifyStructure(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 wPINMaxExtraDigitL = (byte) 0x04;  // Max=4 digits +      byte wPINMaxExtraDigitH = (byte) 0x04;  // Min=4 digits +      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 bMsgIndex = (byte) 0x00;           // Default Msg + +      byte[] apdu = new byte[] { +        (byte) 0x00, (byte) 0x20, (byte) 0x00, kid, (byte) 0x08,  // CLA INS P1 P2 LC +        (byte) 0x20, (byte) 0xff, (byte) 0xff, (byte) 0xff,               // Data +        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff                // ... +      }; + +      int offset = 0; +      byte[] pinVerifyStructure = new byte[offset + 19 + apdu.length]; +      pinVerifyStructure[offset++] = bTimeOut; +      pinVerifyStructure[offset++] = bTimeOut2; +      pinVerifyStructure[offset++] = bmFormatString; +      pinVerifyStructure[offset++] = bmPINBlockString; +      pinVerifyStructure[offset++] = bmPINLengthFormat; +      pinVerifyStructure[offset++] = wPINMaxExtraDigitL; +      pinVerifyStructure[offset++] = wPINMaxExtraDigitH; +      pinVerifyStructure[offset++] = bEntryValidationCondition; +      pinVerifyStructure[offset++] = bNumberMessage; +      pinVerifyStructure[offset++] = wLangIdL; +      pinVerifyStructure[offset++] = wLangIdH; +      pinVerifyStructure[offset++] = bMsgIndex; +       +      pinVerifyStructure[offset++] = 0x00; +      pinVerifyStructure[offset++] = 0x00; +      pinVerifyStructure[offset++] = 0x00; +       +      pinVerifyStructure[offset++] = (byte) apdu.length; +      pinVerifyStructure[offset++] = 0x00; +      pinVerifyStructure[offset++] = 0x00; +      pinVerifyStructure[offset++] = 0x00; +      System.arraycopy(apdu, 0, pinVerifyStructure, offset, apdu.length); -  @Override -  public void activatePIN(PINSpec pinSpec, String pin) -          throws SignatureCardException { -    Card icc = getCard(); -    try { -      icc.beginExclusive(); -      CardChannel channel = icc.getBasicChannel(); - -      if (pinSpec.getContextAID() != null) { -        ResponseAPDU responseAPDU = transmit(channel, -                new CommandAPDU(0x00, 0xa4, 0x04, 0x0c, pinSpec.getContextAID())); -        if (responseAPDU.getSW() != 0x9000) { -          icc.endExclusive(); -          String msg = "Select AID " + SMCCHelper.toString(pinSpec.getContextAID()) + -                  ": SW=" + Integer.toHexString(responseAPDU.getSW()); -          log.error(msg); -          throw new SignatureCardException(msg); -        } -      } - -      ResponseAPDU responseAPDU = transmit(channel, -              new CommandAPDU(0x00, 0x24, 0x01, pinSpec.getKID(), encodePINBlock(pin)), -              false); - -      icc.endExclusive(); - -      log.debug("activate pin returned SW=" + Integer.toHexString(responseAPDU.getSW())); +      return pinVerifyStructure; +  } -       if (responseAPDU.getSW() != 0x9000) { -        String msg = "Failed to activate " + pinSpec.getLocalizedName() + -                ": SW=" + Integer.toHexString(responseAPDU.getSW()); -        log.error(msg); -        throw new SignatureCardException(msg); -      } -    } catch (CardException ex) { -      log.error("Failed to activate " + pinSpec.getLocalizedName() + -              ": " + ex.getMessage()); -      throw new SignatureCardException(ex.getMessage(), ex); -    } +  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[] 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                // ... +      }; + +      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;    } -  /** -   * activates pin (newPIN) if not active -   * @param pinSpec -   * @param oldPIN -   * @param newPIN -   * @throws at.gv.egiz.smcc.LockedException -   * @throws at.gv.egiz.smcc.VerificationFailedException -   * @throws at.gv.egiz.smcc.NotActivatedException -   * @throws at.gv.egiz.smcc.SignatureCardException -   */    @Override -  public void changePIN(PINSpec pinSpec, String oldPIN, String newPIN) -          throws LockedException, VerificationFailedException, NotActivatedException, SignatureCardException { -    Card icc = getCard(); +  public void reset() throws SignatureCardException {      try { -      icc.beginExclusive(); -      CardChannel channel = icc.getBasicChannel(); - -      if (pinSpec.getContextAID() != null) { -        ResponseAPDU responseAPDU = transmit(channel, -                new CommandAPDU(0x00, 0xa4, 0x04, 0x0c, pinSpec.getContextAID())); -        if (responseAPDU.getSW() != 0x9000) { -          icc.endExclusive(); -          String msg = "Select AID " + SMCCHelper.toString(pinSpec.getContextAID()) + -                  ": SW=" + Integer.toHexString(responseAPDU.getSW()); -          log.error(msg); -          throw new SignatureCardException(msg); -        } -      } - -      byte[] cmd = new byte[16]; -      System.arraycopy(encodePINBlock(oldPIN), 0, cmd, 0, 8); -      System.arraycopy(encodePINBlock(newPIN), 0, cmd, 8, 8); - -      ResponseAPDU responseAPDU = transmit(channel, -              new CommandAPDU(0x00, 0x24, 0x00, pinSpec.getKID(), cmd), false); - -      icc.endExclusive(); - -      log.debug("change pin returned SW=" + Integer.toHexString(responseAPDU.getSW())); - -      // activates pin (newPIN) if not active -      if (responseAPDU.getSW() == 0x63c0) { -        log.error(pinSpec.getLocalizedName() + " locked"); -        throw new LockedException(); -      } else if (responseAPDU.getSW1() == 0x63 && responseAPDU.getSW2() >> 4 == 0xc) { -        int retries = responseAPDU.getSW2() & 0x0f; -        log.error("wrong " + pinSpec.getLocalizedName() + ", " + retries + " retries"); -        throw new VerificationFailedException(retries); -      } else if (responseAPDU.getSW() == 0x6983) { -        log.error(pinSpec.getLocalizedName() + " locked"); -        throw new LockedException(); -      } else if (responseAPDU.getSW() != 0x9000) { -        String msg = "Failed to change " + pinSpec.getLocalizedName() + -                ": SW=" + Integer.toHexString(responseAPDU.getSW()); -        log.error(msg); -        throw new SignatureCardException(msg); +      super.reset(); +      log.debug("select MF (e-card workaround)"); +      CardChannel channel = getCardChannel(); +      ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x00, 0x0C)); +      if (resp.getSW() != 0x9000) { +        throw new SignatureCardException("Failed to select MF after RESET: SW=" + Integer.toHexString(resp.getSW()) + ".");        }      } catch (CardException ex) { -      log.error("Failed to change " + pinSpec.getLocalizedName() + -              ": " + ex.getMessage()); -      throw new SignatureCardException(ex.getMessage(), ex); +      log.error("Failed to select MF after RESET: " + ex.getMessage(), ex); +      throw new SignatureCardException("Failed to select MF after RESET");      }    } +  public String toString() { +    return "e-card"; +  }  } 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 d7763be0..293b9c71 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java @@ -77,11 +77,11 @@ public class SWCard implements SignatureCard {    private KeyStore certifiedKeyStore; -  private String certifiedKeyStorePassword; +  private char[] certifiedKeyStorePassword;    private KeyStore secureKeyStore; -  private String secureKeyStorePassword; +  private char[] secureKeyStorePassword;    private Certificate certifiedCertificate; @@ -195,7 +195,7 @@ public class SWCard implements SignatureCard {    } -  private String loadKeyStorePassword(String passwordFileName) throws SignatureCardException { +  private char[] loadKeyStorePassword(String passwordFileName) throws SignatureCardException {      String fileName = getFileName(passwordFileName);      FileInputStream keyStorePasswordFile; @@ -212,7 +212,7 @@ public class SWCard implements SignatureCard {        for (int l; (l = reader.read(b)) != -1;) {          sb.append(b, 0, l);        } -      return sb.toString(); +      return sb.toString().toCharArray();      } catch (IOException e) {        throw new SignatureCardException("Failed to read file '" + passwordFileName + "'.");      } @@ -237,7 +237,7 @@ public class SWCard implements SignatureCard {    } -  private String getPassword(KeyboxName keyboxName) throws SignatureCardException { +  private char[] getPassword(KeyboxName keyboxName) throws SignatureCardException {      if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) {        if (certifiedKeyStorePassword == null) { @@ -311,7 +311,7 @@ public class SWCard implements SignatureCard {    public byte[] createSignature(byte[] hash, KeyboxName keyboxName, PINProvider provider) throws SignatureCardException, InterruptedException {      // KeyStore password -    String password = getPassword(keyboxName); +    char[] password = getPassword(keyboxName);      if (password == null) { @@ -325,7 +325,7 @@ public class SWCard implements SignatureCard {      } -    KeyStore keyStore = getKeyStore(keyboxName, password.toCharArray()); +    KeyStore keyStore = getKeyStore(keyboxName, password);      PrivateKey privateKey = null; @@ -338,7 +338,7 @@ public class SWCard implements SignatureCard {            Key key = null;            while (key == null) {              try { -              key = keyStore.getKey(alias, password.toCharArray()); +              key = keyStore.getKey(alias, password);              } catch (UnrecoverableKeyException e) {                log.info("Failed to get Key from KeyStore. Wrong password?", e);              } @@ -399,15 +399,27 @@ public class SWCard implements SignatureCard {    }    @Override -  public int verifyPIN(PINSpec pinSpec, String pin) throws LockedException, NotActivatedException, SignatureCardException { -    return -1; +  public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider) +          throws LockedException, NotActivatedException, SignatureCardException {    }    @Override -  public void changePIN(PINSpec pinSpec, String oldPIN, String newPIN) throws LockedException, VerificationFailedException, NotActivatedException, SignatureCardException { +  public void activatePIN(PINSpec pinSpec, PINProvider pinProvider) throws SignatureCardException { +    throw new UnsupportedOperationException("Not supported yet.");    }    @Override -  public void activatePIN(PINSpec pinSpec, String pin) throws SignatureCardException { +  public void unblockPIN(PINSpec pinSpec, PINProvider pukProvider) throws CancelledException, SignatureCardException, InterruptedException { +    throw new UnsupportedOperationException("Not supported yet."); +  } + +  @Override +  public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider) throws LockedException, NotActivatedException, CancelledException, SignatureCardException, InterruptedException { +    throw new UnsupportedOperationException("Not supported yet."); +  } + +  @Override +  public boolean ifdSupportsFeature(byte feature) { +    return false;    }  } 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 3c2273b9..2097e6d3 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java @@ -36,6 +36,14 @@ 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( @@ -123,29 +131,29 @@ public interface SignatureCard {     */    public List<PINSpec> getPINSpecs(); -  /** -   * -   * @param pinSpec descriptor which pin to verify -   * @param pin may be null to test the PIN status -   * @return the number of remaining retries or -1 -   * @throws at.gv.egiz.smcc.LockedException -   * @throws at.gv.egiz.smcc.NotActivatedException -   * @throws at.gv.egiz.smcc.SignatureCardException -   */ -  public int verifyPIN(PINSpec pinSpec, String pin) -          throws LockedException, NotActivatedException, SignatureCardException; +  public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider) +          throws LockedException, NotActivatedException, CancelledException, SignatureCardException, InterruptedException; -  public void changePIN(PINSpec pinSpec, String oldPIN, String newPIN) -          throws LockedException, VerificationFailedException, NotActivatedException, SignatureCardException; +  public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider) +          throws LockedException, NotActivatedException, CancelledException, SignatureCardException, InterruptedException; -  public void activatePIN(PINSpec pinSpec, String pin) -          throws SignatureCardException; +  public void activatePIN(PINSpec pinSpec, PINProvider pinProvider) +          throws CancelledException, SignatureCardException, InterruptedException; + +  public void unblockPIN(PINSpec pinSpec, PINProvider pukProvider) +          throws CancelledException, SignatureCardException, InterruptedException; + +  /** +   * TODO +   * @return +   */ +  public boolean ifdSupportsFeature(byte feature);    /**     * Sets the local for evtl. required callbacks (e.g. PINSpec)     * @param locale must not be null;     */    public void setLocale(Locale locale); -   -   + +  } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java index ab66e9a1..5146c275 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java @@ -196,7 +196,7 @@ public class SignatureCardFactory {              (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00          },          "at.gv.egiz.smcc.ACOSCard")); -     +    }    /** diff --git a/smcc/src/main/java/at/gv/egiz/smcc/TimeoutException.java b/smcc/src/main/java/at/gv/egiz/smcc/TimeoutException.java new file mode 100644 index 00000000..d14a4c15 --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/TimeoutException.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; + +public class TimeoutException extends SignatureCardException { + +  private static final long serialVersionUID = 1L; + +  public TimeoutException() { +    super(); +  } + +  public TimeoutException(String message, Throwable cause) { +    super(message, cause); +  } + +  public TimeoutException(String message) { +    super(message); +  } + +  public TimeoutException(Throwable cause) { +    super(cause); +  } + +} | 
