diff options
Diffstat (limited to 'smcc/src/main')
5 files changed, 648 insertions, 375 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 2baff834..6d96599c 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java @@ -30,7 +30,6 @@ package at.gv.egiz.smcc;  import java.nio.charset.Charset; -import javax.smartcardio.Card;  import javax.smartcardio.CardChannel;  import javax.smartcardio.CardException;  import javax.smartcardio.CommandAPDU; @@ -110,41 +109,47 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {    public byte[] getCertificate(KeyboxName keyboxName)        throws SignatureCardException, InterruptedException { -    byte[] aid; -    byte[] efc; -    int maxsize; -    if (keyboxName == KeyboxName.SECURE_SIGNATURE_KEYPAIR) { -      aid = AID_SIG; -      efc = EF_C_CH_DS; -      maxsize = EF_C_CH_DS_MAX_SIZE; -    } else if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) { -      aid = AID_DEC; -      efc = EF_C_CH_EKEY; -      maxsize = EF_C_CH_EKEY_MAX_SIZE; -    } else { -      throw new IllegalArgumentException("Keybox " + keyboxName -          + " not supported."); -    } - -    log.debug("Get certificate for keybox '" + keyboxName.getKeyboxName() + "'" + -        " (AID=" + toString(aid) + " EF=" + toString(efc) + ")."); -          try { -      Card card = getCardChannel().getCard(); -      try { -        card.beginExclusive(); -        return readTLVFile(aid, efc, maxsize + 15000); -      } catch (FileNotFoundException e) { -        // if certificate is not present,  -        // the citizen card application has not been activated -        throw new NotActivatedException(); -      } finally { -        card.endExclusive(); +       +      if (keyboxName == KeyboxName.SECURE_SIGNATURE_KEYPAIR) { +         +        try { +          getCard().beginExclusive(); +          byte[] certificate = readTLVFile(AID_SIG, EF_C_CH_DS, EF_C_CH_DS_MAX_SIZE); +          if (certificate == null) { +            throw new NotActivatedException(); +          } +          return certificate; +        } catch (FileNotFoundException e) { +          throw new NotActivatedException(); +        } finally { +          getCard().endExclusive(); +        } +         +      } else if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) { +         +        try { +          getCard().beginExclusive(); +          byte[] certificate = readTLVFile(AID_DEC, EF_C_CH_EKEY, EF_C_CH_EKEY_MAX_SIZE); +          if (certificate == null) { +            throw new NotActivatedException(); +          } +          return certificate; +        } catch (FileNotFoundException e) { +          throw new NotActivatedException(); +        } finally { +          getCard().endExclusive(); +        } +         +      } else { +        throw new IllegalArgumentException("Keybox " + keyboxName +            + " not supported.");        } +      } catch (CardException e) { -      throw new SignatureCardException("Failed to get exclusive card access."); +      log.warn(e); +      throw new SignatureCardException("Failed to access card.", e);      } -    } @@ -155,30 +160,47 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {    public byte[] getInfobox(String infobox, PINProvider provider, String domainId)        throws SignatureCardException, InterruptedException { -    if ("IdentityLink".equals(infobox)) { -   -      PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("inf.pin.name")); -       -      try { -        Card card = getCardChannel().getCard(); -        try { -          card.beginExclusive(); -          return readTLVFilePIN(AID_DEC, EF_INFOBOX, KID_PIN_INF, provider, -              spec, EF_INFOBOX_MAX_SIZE); -        } catch (FileNotFoundException e) { -          // if certificate is not present,  -          // the citizen card application has not been activated -          throw new NotActivatedException(); -        } finally { -          card.endExclusive(); -        } -      } catch (CardException e) { -        throw new SignatureCardException("Failed to get exclusive card access."); +    try { +      if ("IdentityLink".equals(infobox)) { +  +        PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("inf.pin.name")); +         +        int retries = -1; +        String pin = null; +        boolean pinRequiered = false; + +        do { +          if (pinRequiered) { +            pin = provider.providePIN(spec, retries); +            if (pin == null) { +              throw new CancelledException(); +            } +          } +          try { +            getCard().beginExclusive(); +            return readTLVFile(AID_DEC, EF_INFOBOX, pin, KID_PIN_INF, EF_INFOBOX_MAX_SIZE); +          } catch (FileNotFoundException e) { +            throw new NotActivatedException(); +          } catch (SecurityStatusNotSatisfiedException e) { +            pinRequiered = true; +          } catch (VerificationFailedException e) { +            pinRequiered = true; +            retries = e.getRetries(); +          } finally { +            getCard().endExclusive(); +          } +        } while (retries != 0); + +        throw new LockedException(); + +      } else { +        throw new IllegalArgumentException("Infobox '" + infobox +            + "' not supported.");        } -   -    } else { -      throw new IllegalArgumentException("Infobox '" + infobox -          + "' not supported."); + +    } catch (CardException e) { +      log.warn(e); +      throw new SignatureCardException("Failed to access card.", e);      }    } @@ -192,68 +214,103 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {      }      try { -      Card card = getCardChannel().getCard(); -      try { -        card.beginExclusive(); -         -        if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) { - -          // SELECT DF -          selectFileFID(DF_SIG); -          // VERIFY -          verifyPIN(provider, new PINSpec(6, 10, "[0-9]", getResourceBundle() -              .getString("sig.pin.name")), KID_PIN_SIG); -          // MSE: SET DST -          mseSetDST(0x81, 0xb6, DST_SIG); -          // PSO: HASH -          psoHash(hash); -          // PSO: COMPUTE DIGITAL SIGNATURE -          return psoComputDigitalSiganture(); -        } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) { - -          // SELECT DF -          selectFileFID(DF_DEC); -          // VERIFY -          verifyPIN(provider, new PINSpec(4, 4, "[0-9]", getResourceBundle() -              .getString("dec.pin.name")), KID_PIN_DEC); -          // MSE: SET DST -          mseSetDST(0x41, 0xa4, DST_DEC); -          // INTERNAL AUTHENTICATE -          return internalAuthenticate(hash); - -           -          // 00 88 10 00 23 30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14 54 26 F0 EA  AF EA F0 4E D4 A1 AD BF 66 D4 A5 9B 45 6F AF 79 00 -          // 00 88 10 00 23 30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14 DF 8C AB 8F E2 AD AC 7B 5A AF BE E9 44 5E 95 99 FA AF 2F 48 00 -           -        } else { -          throw new IllegalArgumentException("KeyboxName '" + keyboxName -              + "' not supported."); -        } +      if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) { + +        PINSpec spec = new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name")); +         +        int retries = -1; +        String 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); +            if (retries != -1) { +              throw new VerificationFailedException(retries); +            } +            // MSE: SET DST +            mseSetDST(0x81, 0xb6, DST_SIG); +            // PSO: HASH +            psoHash(hash); +            // PSO: COMPUTE DIGITAL SIGNATURE +            return psoComputDigitalSiganture(); + +          } catch (SecurityStatusNotSatisfiedException e) { +            retries = verifyPIN(null, KID_PIN_SIG); +          } catch (VerificationFailedException e) { +            retries = e.getRetries(); +          } finally { +            getCard().endExclusive(); +          } +        } while (retries != 0); + +        throw new LockedException(); +         +     +      } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) { -      } catch (FileNotFoundException e) { -        // if certificate is not present,  -        // the citizen card application has not been activated -        throw new NotActivatedException(); -      } finally { -        card.endExclusive(); +        PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("dec.pin.name")); + +        int retries = -1; +        String pin = null; +        boolean pinRequiered = false; + +        do { +          if (pinRequiered) { +            pin = provider.providePIN(spec, retries); +            if (pin == null) { +              throw new CancelledException(); +            } +          } +          try { +            getCard().beginExclusive(); +             +            // SELECT DF +            selectFileFID(DF_DEC); +            // VERIFY +            retries = verifyPIN(pin, KID_PIN_DEC); +            if (retries != -1) { +              throw new VerificationFailedException(retries); +            } +            // MSE: SET DST +            mseSetDST(0x41, 0xa4, DST_DEC); +            // INTERNAL AUTHENTICATE +            return internalAuthenticate(hash); +             +          } catch (FileNotFoundException e) { +            throw new NotActivatedException(); +          } catch (SecurityStatusNotSatisfiedException e) { +            pinRequiered = true; +            retries = verifyPIN(null, KID_PIN_DEC); +          } catch (VerificationFailedException e) { +            pinRequiered = true; +            retries = e.getRetries(); +          } finally { +            getCard().endExclusive(); +          } +        } while (retries != 0); + +        throw new LockedException(); + +      } else { +        throw new IllegalArgumentException("KeyboxName '" + keyboxName +            + "' not supported.");        } +            } catch (CardException e) { -      throw new SignatureCardException("Failed to get exclusive card access."); -    } - -  } - -  protected byte[] selectFileAID(byte[] fid) throws CardException, SignatureCardException { -    CardChannel channel = getCardChannel(); -    ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x04, -        0x00, fid, 256)); -    if (resp.getSW() != 0x9000) { -      throw new SignatureCardException("Failed to select file (AID=" -          + toString(fid) + "): SW=" + Integer.toHexString(resp.getSW()) + "."); -    } else { -      return resp.getBytes(); -    } +      log.warn(e); +      throw new SignatureCardException("Failed to access card.", e); +    }  +          }    protected ResponseAPDU selectFileFID(byte[] fid) throws CardException, SignatureCardException { @@ -262,6 +319,7 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {          0x00, fid, 256));    } +  @Override    protected int verifyPIN(String pin, byte kid) throws CardException, SignatureCardException {      CardChannel channel = getCardChannel(); @@ -290,35 +348,7 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {    } -  /** -   *  -   * @param pinProvider -   * @param spec -   *          the PIN spec to be given to the pinProvider -   * @param kid -   *          the KID (key identifier) of the PIN to be verified -   * @throws CancelledException -   *           if the user canceld the operation -   * @throws javax.smartcardio.CardException -   * @throws at.gv.egiz.smcc.SignatureCardException -   */ -  @Override -  protected void verifyPIN(PINProvider pinProvider, PINSpec spec, byte kid) -      throws CardException, CancelledException, SignatureCardException, InterruptedException { - -    int retries = -1; -    do { -      String pin = pinProvider.providePIN(spec, retries); -      if (pin == null) { -        // user canceled operation -        throw new CancelledException("User canceled operation"); -      }  -      retries = verifyPIN(pin, kid); -    } while (retries > 0); -       -  } -     -  void mseSetDST(int p1, int p2, byte[] dst) throws CardException, SignatureCardException { +  private void mseSetDST(int p1, int p2, byte[] dst) throws CardException, SignatureCardException {      CardChannel channel = getCardChannel();      ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x22, p1,          p2, dst)); @@ -328,7 +358,7 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {      }    } -  void psoHash(byte[] hash) throws CardException, SignatureCardException { +  private void psoHash(byte[] hash) throws CardException, SignatureCardException {      CardChannel channel = getCardChannel();      ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x2A, 0x90,          0x81, hash)); @@ -338,7 +368,7 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {      }    } -  byte[] psoComputDigitalSiganture() throws CardException, +  private byte[] psoComputDigitalSiganture() throws CardException,        SignatureCardException {      CardChannel channel = getCardChannel();      ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x2A, 0x9E, @@ -352,7 +382,7 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {      }    } -  byte[] internalAuthenticate(byte[] hash) throws CardException, SignatureCardException { +  private byte[] internalAuthenticate(byte[] hash) throws CardException, SignatureCardException {      byte[] digestInfo = new byte[] {          (byte) 0x30, (byte) 0x21, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x05, (byte) 0x2B, (byte) 0x0E,           (byte) 0x03, (byte) 0x02, (byte) 0x1A, (byte) 0x05, (byte) 0x00, (byte) 0x04 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 e34c4899..633cc90d 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java @@ -28,6 +28,8 @@  //  package at.gv.egiz.smcc; +import java.io.ByteArrayOutputStream; +import java.io.IOException;  import java.nio.ByteBuffer;  import java.util.Locale;  import java.util.ResourceBundle; @@ -79,45 +81,56 @@ public abstract class AbstractSignatureCard implements SignatureCard {      return sb.toString();    } -  protected abstract byte[] selectFileAID(byte[] fid) throws CardException, -      SignatureCardException; - -  protected abstract ResponseAPDU selectFileFID(byte[] fid) throws CardException, -      SignatureCardException; -    /** -   * VERIFY PIN +   * Select an application using AID as DF name according to ISO/IEC 7816-4 +   * section 8.2.2.2.     *  -   * <p> -   * Implementations of this method should call -   * {@link PINProvider#providePIN(PINSpec, int)} to retrieve the PIN entered by -   * the user and VERIFY PIN on the smart card until the PIN has been -   * successfully verified. -   * </p> +   * @param dfName +   *          AID of the application to be selected     *  -   * @param pinProvider -   *          the PINProvider -   * @param spec -   *          the PINSpec -   * @param kid -   *          the key ID (KID) of the PIN to verify +   * @return the response data of the response APDU if SW=0x9000     *      * @throws CardException -   *           if smart card communication fails -   *  -   * @throws CancelledException -   *           if the PINProvider indicated that the user canceled the PIN entry -   * @throws NotActivatedException -   *           if the card application has not been activated -   * @throws LockedException -   *           if the card application is locked +   *           if card communication fails     *      * @throws SignatureCardException -   *           if VERIFY PIN fails +   *           if application selection fails (e.g. an application with the +   *           given AID is not present on the card)     */ -  protected abstract void verifyPIN(PINProvider pinProvider, PINSpec spec, -      byte kid) throws CardException, SignatureCardException, InterruptedException; +  protected byte[] selectFileAID(byte[] dfName) throws CardException, SignatureCardException { +    CardChannel channel = getCardChannel(); +    ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x04, +        0x00, dfName, 256)); +    if (resp.getSW() != 0x9000) { +      throw new SignatureCardException("Failed to select application AID=" +          + toString(dfName) + ": SW=" + Integer.toHexString(resp.getSW()) + "."); +    } else { +      return resp.getBytes(); +    } +  } + +  protected abstract ResponseAPDU selectFileFID(byte[] fid) throws CardException, +      SignatureCardException; +  protected abstract int verifyPIN(String pin, byte kid) throws CardException, SignatureCardException; + +   +  protected byte[] readRecord(int recordNumber) throws SignatureCardException, CardException { +    return readRecord(getCardChannel(), recordNumber); +  } + +  protected byte[] readRecord(CardChannel channel, int recordNumber) throws SignatureCardException, CardException { +     +    ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xB2, +        recordNumber, 0x04, 256)); +    if (resp.getSW() == 0x9000) { +      return resp.getData(); +    } else { +      throw new SignatureCardException("Failed to read records. SW=" + Integer.toHexString(resp.getSW())); +    } +      +  } +      protected byte[] readBinary(CardChannel channel, int offset, int len)        throws CardException, SignatureCardException { @@ -125,6 +138,8 @@ public abstract class AbstractSignatureCard implements SignatureCard {          0x7F & (offset >> 8), offset & 0xFF, len));      if (resp.getSW() == 0x9000) {        return resp.getData(); +    } else if (resp.getSW() == 0x6982) { +      throw new SecurityStatusNotSatisfiedException();      } else {        throw new SignatureCardException("Failed to read bytes (" + offset + "+"            + len + "): SW=" + Integer.toHexString(resp.getSW())); @@ -188,43 +203,10 @@ public abstract class AbstractSignatureCard implements SignatureCard {    } -  /** -   * Read the content of a TLV file. -   *  -   * @param aid the application ID (AID) -   * @param ef the elementary file (EF) -   * @param maxLength the maximum length of the file -   *  -   * @return the content of the file -   *  -   * @throws SignatureCardException -   */ -  protected byte[] readTLVFile(byte[] aid, byte[] ef, int maxLength) -      throws SignatureCardException, InterruptedException { -    return readTLVFilePIN(aid, ef, (byte) 0, null, null, maxLength); -  } - -   -  /** -   * Read the content of a TLV file wich may require a PIN. -   *  -   * @param aid the application ID (AID) -   * @param ef the elementary file (EF) -   * @param kid the key ID (KID) of the corresponding PIN -   * @param provider the PINProvider -   * @param spec the PINSpec -   * @param maxLength the maximum length of the file -   *  -   * @return the content of the file -   *  -   * @throws SignatureCardException -   */ -  protected byte[] readTLVFilePIN(byte[] aid, byte[] ef, byte kid, -      PINProvider provider, PINSpec spec, int maxLength) -      throws SignatureCardException, InterruptedException { - +  protected byte[] readRecords(byte[] aid, byte[] ef, int start, int end) throws SignatureCardException, InterruptedException { +          try { - +              // SELECT FILE (AID)        byte[] rb = selectFileAID(aid);        if (rb[rb.length - 2] != (byte) 0x90 || rb[rb.length - 1] != (byte) 0x00) { @@ -256,38 +238,90 @@ public abstract class AbstractSignatureCard implements SignatureCard {              + Integer.toHexString(resp.getSW()) + ").");        } - -      // try to READ BINARY -      byte[] b = new byte[1]; -      int sw = readBinary(0, 1, b); -      if (provider != null && sw == 0x6982) { - -        // VERIFY -        verifyPIN(provider, spec, kid); -         -      } else if (sw == 0x9000) { -        // not expected type -        if (b[0] != 0x30) { -          throw new NotActivatedException(); -        } -      } else { -        throw new SignatureCardException("READ BINARY failed (SW=" -            + Integer.toHexString(sw) + ")."); +      ByteArrayOutputStream bytes = new ByteArrayOutputStream(); +       +      for (int i = start; i <= end; i++) { +        bytes.write(readRecord(i));        } - -      // READ BINARY -      byte[] data = readBinaryTLV(maxLength, (byte) 0x30); - -      return data; - +       +      return bytes.toByteArray(); +            } catch (CardException e) {        throw new SignatureCardException("Failed to acces card.", e); +    } catch (IOException e) { +      throw new SignatureCardException("Failed to read records.", e);      } - +     +  } +   +  /** +   * Read the content of a TLV file. +   *  +   * @param aid the application ID (AID) +   * @param ef the elementary file (EF) +   * @param maxLength the maximum length of the file +   *  +   * @return the content of the file +   *  +   * @throws SignatureCardException +   * @throws CardException  +   */ +  protected byte[] readTLVFile(byte[] aid, byte[] ef, int maxLength) +      throws SignatureCardException, InterruptedException, CardException { +    return readTLVFile(aid, ef, null, (byte) 0, maxLength);    }    /** +   * Read the content of a TLV file wich may require a PIN. +   *  +   * @param aid the application ID (AID) +   * @param ef the elementary file (EF) +   * @param kid the key ID (KID) of the corresponding PIN +   * @param provider the PINProvider +   * @param spec the PINSpec +   * @param maxLength the maximum length of the file +   *  +   * @return the content of the file +   *  +   * @throws SignatureCardException +   * @throws CardException  +   */ +  protected byte[] readTLVFile(byte[] aid, byte[] ef, String pin, byte kid, int maxLength) +      throws SignatureCardException, InterruptedException, CardException { + + +    // SELECT FILE (AID) +    selectFileAID(aid); + +    // SELECT FILE (EF) +    ResponseAPDU resp = selectFileFID(ef); +    if (resp.getSW() == 0x6a82) { +      // EF not found +      throw new FileNotFoundException("EF " + toString(ef) + " not found."); +    } else if (resp.getSW() != 0x9000) { +      throw new SignatureCardException("SELECT FILE with " +          + "FID=" +          + toString(ef) +          + " failed (" +          + "SW=" +          + Integer.toHexString(resp.getSW()) + ")."); +    } + +    // VERIFY +    if (pin != null) { +      int retries = verifyPIN(pin, kid); +      if (retries != -1) { +        throw new VerificationFailedException(retries); +      } +    } +     +    return readBinaryTLV(maxLength, (byte) 0x30); +       +     +  } +   +  /**     * Transmit the given command APDU using the given card channel.     *      * @param channel 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 d6d02475..2a6e90bf 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java @@ -31,7 +31,6 @@ package at.gv.egiz.smcc;  import java.math.BigInteger;  import java.util.Arrays; -import javax.smartcardio.Card;  import javax.smartcardio.CardChannel;  import javax.smartcardio.CardException;  import javax.smartcardio.CommandAPDU; @@ -49,6 +48,42 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard    public static final byte[] MF = new byte[] { (byte) 0x3F, (byte) 0x00 }; +  /** +   * Application ID <em>SV-Personendaten</em>. +   */ +  public static final byte[] AID_SV_PERSONENDATEN = new byte[] {  +    (byte) 0xD0, (byte) 0x40, (byte) 0x00, (byte) 0x00,  +    (byte) 0x17, (byte) 0x01, (byte) 0x01, (byte) 0x01 +  }; +   +  /** +   * File ID <em>Grunddaten</em> ({@link #AID_SV_PERSONENDATEN}). +   */ +  public static final byte[] FID_GRUNDDATEN = new byte[] { +    (byte) 0xEF, (byte) 0x01 +  }; + +  /** +   * File ID <em>EHIC</em> ({@link #AID_SV_PERSONENDATEN}). +   */ +  public static final byte[] FID_EHIC = new byte[] { +    (byte) 0xEF, (byte) 0x02 +  }; +   +  /** +   * File ID <em>Status</em> ({@link #AID_SV_PERSONENDATEN}). +   */ +  public static final byte[] FID_SV_PERSONENBINDUNG = new byte[] { +    (byte) 0xEF, (byte) 0x03 +  }; + +  /** +   * File ID <em>Status</em> ({@link #AID_SV_PERSONENDATEN}). +   */ +  public static final byte[] FID_STATUS = new byte[] { +    (byte) 0xEF, (byte) 0x04 +  }; +    public static final byte[] AID_INFOBOX = new byte[] { (byte) 0xd0,        (byte) 0x40, (byte) 0x00, (byte) 0x00, (byte) 0x17, (byte) 0x00,        (byte) 0x18, (byte) 0x01 }; @@ -126,85 +161,134 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard      super("at/gv/egiz/smcc/STARCOSCard");    } -  /* (non-Javadoc) -   * @see at.gv.egiz.smcc.SignatureCard#getCertificate(at.gv.egiz.smcc.SignatureCard.KeyboxName) -   */    @Override    public byte[] getCertificate(KeyboxName keyboxName)        throws SignatureCardException, InterruptedException { -    byte[] aid; -    byte[] efc; -    if (keyboxName == KeyboxName.SECURE_SIGNATURE_KEYPAIR) { -      aid = AID_DF_SS; -      efc = EF_C_X509_CH_DS; -    } else if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) { -      aid = AID_DF_GS; -      efc = EF_C_X509_CH_AUT; -    } else { -      throw new IllegalArgumentException("Keybox " + keyboxName -          + " not supported."); -    } +    try { +       +      if (keyboxName == KeyboxName.SECURE_SIGNATURE_KEYPAIR) { +         +        try { +          getCard().beginExclusive(); +          return readTLVFile(AID_DF_SS, EF_C_X509_CH_DS, 2000); +        } catch (FileNotFoundException e) { +          throw new NotActivatedException(); +        } finally { +          getCard().endExclusive(); +        } +         +      } else if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) { -    log.debug("Get certificate for keybox '" + keyboxName.getKeyboxName() + "'" + -        " (AID=" + toString(aid) + " EF=" + toString(efc) + ")."); +        try { +          getCard().beginExclusive(); +          return readTLVFile(AID_DF_GS, EF_C_X509_CH_AUT, 2000); +        } catch (FileNotFoundException e) { +          throw new NotActivatedException(); +        } finally { +          getCard().endExclusive(); +        } -    try { -      Card card = getCardChannel().getCard(); -      try { -        card.beginExclusive(); -        return readTLVFile(aid, efc, 2000); -      } catch (FileNotFoundException e) { -        // if certificate is not present,  -        // the citizen card application has not been activated -        throw new NotActivatedException(); -      } finally { -        card.endExclusive(); +      } else { +        throw new IllegalArgumentException("Keybox " + keyboxName +            + " not supported.");        } +            } catch (CardException e) { -      throw new SignatureCardException("Failed to get exclusive card access."); +      log.warn(e); +      throw new SignatureCardException("Failed to access card.", e);      } -     -  } -  /* (non-Javadoc) -   * @see at.gv.egiz.smcc.SignatureCard#getInfobox(java.lang.String, at.gv.egiz.smcc.PINProvider, java.lang.String) -   */ +  } +      @Override    public byte[] getInfobox(String infobox, PINProvider provider, String domainId)        throws SignatureCardException, InterruptedException { -    if ("IdentityLink".equals(infobox)) { -   -      PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name")); -       -      try { -        Card card = getCardChannel().getCard(); +    try { +      if ("IdentityLink".equals(infobox)) { +  +        PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name")); +         +        int retries = -1; +        String pin = null; +        boolean pinRequiered = false; + +        do { +          if (pinRequiered) { +            pin = provider.providePIN(spec, retries); +            if (pin == null) { +              throw new CancelledException(); +            } +          } +          try { +            getCard().beginExclusive(); +            return readTLVFile(AID_INFOBOX, EF_INFOBOX, pin, KID_PIN_CARD, 2000); +          } catch (FileNotFoundException e) { +            throw new NotActivatedException(); +          } catch (SecurityStatusNotSatisfiedException e) { +            pinRequiered = true; +            retries = verifyPIN(null, KID_PIN_CARD); +          } catch (VerificationFailedException e) { +            pinRequiered = true; +            retries = e.getRetries(); +          } finally { +            getCard().endExclusive(); +          } +        } while (retries != 0); + +        throw new LockedException(); + +         +      } else if ("EHIC".equals(infobox)) { +                  try { -          card.beginExclusive(); -          return readTLVFilePIN(AID_INFOBOX, EF_INFOBOX, KID_PIN_CARD, -              provider, spec, 2000); -        } catch (FileNotFoundException e) { -          // if certificate is not present,  -          // the citizen card application has not been activated -          throw new NotActivatedException(); +          getCard().beginExclusive(); +          return readTLVFile(AID_SV_PERSONENDATEN, FID_EHIC, 126);          } finally { -          card.endExclusive(); +          getCard().endExclusive();          } -      } catch (CardException e) { -        throw new SignatureCardException("Failed to get exclusive card access."); +         +      } else if ("Grunddaten".equals(infobox)) { +         +        try { +          getCard().beginExclusive(); +          return readTLVFile(AID_SV_PERSONENDATEN, FID_GRUNDDATEN, 550); +        } finally { +          getCard().endExclusive(); +        } +         +      } else if ("SV-Personenbindung".equals(infobox)) { +         +        try { +          getCard().beginExclusive(); +          return readTLVFile(AID_SV_PERSONENDATEN, FID_SV_PERSONENBINDUNG, 500); +        } finally { +          getCard().endExclusive(); +        } +         +      } else if ("Status".equals(infobox)) { +         +        try { +          getCard().beginExclusive(); +          return readRecords(AID_SV_PERSONENDATEN, FID_STATUS, 1, 5); +        } finally { +          getCard().endExclusive(); +        } +         +      } else { +        throw new IllegalArgumentException("Infobox '" + infobox +            + "' not supported.");        } -    } else { -      throw new IllegalArgumentException("Infobox '" + infobox -          + "' not supported."); +    } catch (CardException e) { +      log.warn(e); +      throw new SignatureCardException("Failed to access card.", e);      }    } -  /* (non-Javadoc) -   * @see at.gv.egiz.smcc.SignatureCard#createSignature(byte[], at.gv.egiz.smcc.SignatureCard.KeyboxName, at.gv.egiz.smcc.PINProvider) -   */ +  @Override    public byte[] createSignature(byte[] hash, KeyboxName keyboxName,        PINProvider provider) throws SignatureCardException, InterruptedException { @@ -212,72 +296,115 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard        throw new IllegalArgumentException("Hash value must be of length 20.");      } -    byte[] aid; -    byte kid; -    byte[] dst; -    PINSpec spec; -    if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) { -      aid = AID_DF_SS; -      kid = KID_PIN_SS; -      dst = DST_SS; -      spec = new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name")); -   -    } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) { -      aid = AID_DF_GS; -      kid = KID_PIN_CARD; -      dst = DST_GS; -      spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name")); -   -    } else { -      throw new IllegalArgumentException("KeyboxName '" + keyboxName -          + "' not supported."); -    } -        try { -      Card card = getCardChannel().getCard(); -      try { -        card.beginExclusive(); - -        // SELECT MF -        selectMF(); -        // SELECT DF -        selectFileAID(aid); -        // VERIFY -        verifyPIN(provider, spec, kid); -        // MSE: SET DST -        mseSetDST(dst); -        // PSO: HASH -        psoHash(hash); -        // PSO: COMPUTE DIGITAL SIGNATURE -        return psoComputDigitalSiganture(); - - -      } catch (FileNotFoundException e) { -        // if certificate is not present,  -        // the citizen card application has not been activated -        throw new NotActivatedException(); -      } finally { -        card.endExclusive(); +       +      if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) { + +        PINSpec spec = new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name")); +         +        int retries = -1; +        String pin = null; + +        do { +          try { +            getCard().beginExclusive(); +            selectFileAID(AID_DF_SS); +            retries = verifyPIN(null, KID_PIN_SS); +          } 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); +          } catch (VerificationFailedException e) { +            retries = e.getRetries(); +          } finally { +            getCard().endExclusive(); +          } +        } while (retries != 0); + +        throw new LockedException(); + +  +      } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) { + +        PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name")); +  +        int retries = -1; +        String pin = null; +        boolean pinRequiered = false; + +        do { +          if (pinRequiered) { +            pin = provider.providePIN(spec, retries); +            if (pin == null) { +              throw new CancelledException(); +            } +          } +          try { +            getCard().beginExclusive(); +            return createSignature(hash, AID_DF_GS, pin, KID_PIN_CARD, DST_GS); +          } catch (FileNotFoundException e) { +            throw new NotActivatedException(); +          } catch (SecurityStatusNotSatisfiedException e) { +            pinRequiered = true; +            retries = verifyPIN(null, KID_PIN_CARD); +          } catch (VerificationFailedException e) { +            pinRequiered = true; +            retries = e.getRetries(); +          } finally { +            getCard().endExclusive(); +          } +        } while (retries != 0); + +        throw new LockedException(); +         +      } else { +        throw new IllegalArgumentException("KeyboxName '" + keyboxName +            + "' not supported.");        } +      } catch (CardException e) { -      throw new SignatureCardException("Failed to get exclusive card access."); +      log.warn(e); +      throw new SignatureCardException("Failed to access card.", e);      }    } -  protected byte[] selectFileAID(byte[] fid) throws CardException, SignatureCardException { +  protected ResponseAPDU selectFileFID(byte[] fid) throws CardException, SignatureCardException {      CardChannel channel = getCardChannel(); -    ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x04, +    return transmit(channel, new CommandAPDU(0x00, 0xA4, 0x02,          0x04, fid, 256)); -    if (resp.getSW() != 0x9000) { -      throw new SignatureCardException("Failed to select file (AID=" -          + toString(fid) + "): SW=" + Integer.toHexString(resp.getSW()) + "."); -    } else { -      return resp.getBytes(); +  } + +  private byte[] createSignature(byte[] hash, byte[] aid, String pin, byte kid, +      byte[] dst) throws CardException, SignatureCardException { +     +    // SELECT MF +    selectMF(); +    // SELECT DF +    selectFileAID(aid); +    // VERIFY +    int retries = verifyPIN(pin, kid); +    if (retries != -1) { +      throw new VerificationFailedException(retries);      } +    // MSE: SET DST +    mseSetDST(dst); +    // PSO: HASH +    psoHash(hash); +    // PSO: COMPUTE DIGITAL SIGNATURE +    return psoComputDigitalSiganture(); + +        } -  void selectMF() throws CardException, SignatureCardException { +   +  private void selectMF() throws CardException, SignatureCardException {      CardChannel channel = getCardChannel();      ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x00,          0x0C)); @@ -287,13 +414,7 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard      }    } -  protected ResponseAPDU selectFileFID(byte[] fid) throws CardException, SignatureCardException { -    CardChannel channel = getCardChannel(); -    return transmit(channel, new CommandAPDU(0x00, 0xA4, 0x02, -        0x04, fid, 256)); -  } - -  void mseSetDST(byte[] dst) throws CardException, SignatureCardException { +  private void mseSetDST(byte[] dst) throws CardException, SignatureCardException {      CardChannel channel = getCardChannel();      ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x22, 0x41,          0xB6, dst)); @@ -303,7 +424,7 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard      }    } -  void psoHash(byte[] hash) throws CardException, SignatureCardException { +  private void psoHash(byte[] hash) throws CardException, SignatureCardException {      byte[] data = new byte[hash.length + 2];      data[0] = (byte) 0x90; // tag      data[1] = (byte) (hash.length); // length @@ -318,7 +439,7 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard      }    } -  byte[] psoComputDigitalSiganture() throws CardException, +  private byte[] psoComputDigitalSiganture() throws CardException,        SignatureCardException {      CardChannel channel = getCardChannel();      ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x2A, 0x9E, @@ -353,7 +474,8 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard     * @throws SignatureCardException     *           if VERIFY PIN fails     */ -  private int verifyPIN(String pin, byte kid) throws CardException, SignatureCardException { +  @Override +  protected int verifyPIN(String pin, byte kid) throws CardException, SignatureCardException {      CardChannel channel = getCardChannel(); @@ -385,6 +507,8 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard      } 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 LockedException();      } else if (resp.getSW() == 0x6984) {        // PIN LCS = "Initialized" (-> not activated)        throw new NotActivatedException("PIN not set."); @@ -397,26 +521,8 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard    } -  /* (non-Javadoc) -   * @see at.gv.egiz.smcc.AbstractSignatureCard#verifyPIN(at.gv.egiz.smcc.PINProvider, at.gv.egiz.smcc.PINSpec, byte, int) -   */ -  protected void verifyPIN(PINProvider pinProvider, PINSpec spec, byte kid) -      throws CardException, SignatureCardException, InterruptedException { - -    int retries = verifyPIN(null, kid); -    do { -      String pin = pinProvider.providePIN(spec, retries); -      if (pin == null) { -        // user canceled operation -        throw new CancelledException("User canceld operation."); -      } -      retries = verifyPIN(pin, kid); -    } while (retries > 0); - -  } -    public String toString() { -    return "eCard"; +    return "e-card";    } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SecurityStatusNotSatisfiedException.java b/smcc/src/main/java/at/gv/egiz/smcc/SecurityStatusNotSatisfiedException.java new file mode 100644 index 00000000..bf0af76c --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/SecurityStatusNotSatisfiedException.java @@ -0,0 +1,38 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +*     http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egiz.smcc; + +public class SecurityStatusNotSatisfiedException extends SignatureCardException { + +  private static final long serialVersionUID = 1L; + +  public SecurityStatusNotSatisfiedException() { +  } + +  public SecurityStatusNotSatisfiedException(String message, Throwable cause) { +    super(message, cause); +  } + +  public SecurityStatusNotSatisfiedException(String message) { +    super(message); +  } + +  public SecurityStatusNotSatisfiedException(Throwable cause) { +    super(cause); +  } +   +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/VerificationFailedException.java b/smcc/src/main/java/at/gv/egiz/smcc/VerificationFailedException.java new file mode 100644 index 00000000..fa066ff9 --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/VerificationFailedException.java @@ -0,0 +1,65 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +*     http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egiz.smcc; + +public class VerificationFailedException extends SignatureCardException { + +  private static final long serialVersionUID = 1L; + +  public static final int UNKNOWN = -1; +   +  private int retries = UNKNOWN; +   +  public VerificationFailedException() { +  } + +  public VerificationFailedException(String message, Throwable cause) { +    super(message, cause); +  } + +  public VerificationFailedException(String message) { +    super(message); +  } + +  public VerificationFailedException(Throwable cause) { +    super(cause); +  } + +  public VerificationFailedException(int retries) { +    this.retries = retries; +  } + +  public VerificationFailedException(int retries, String message, Throwable cause) { +    super(message, cause); +    this.retries = retries; +  } + +  public VerificationFailedException(int retries, String message) { +    super(message); +    this.retries = retries; +  } + +  public VerificationFailedException(int retries, Throwable cause) { +    super(cause); +    this.retries = retries; +  } + +  public int getRetries() { +    return retries; +  } +   +} | 
