diff options
Diffstat (limited to 'smcc')
5 files changed, 402 insertions, 1 deletions
| diff --git a/smcc/src/main/java/at/gv/egiz/smcc/LIEZertifikatCard.java b/smcc/src/main/java/at/gv/egiz/smcc/LIEZertifikatCard.java new file mode 100644 index 00000000..f8ba8643 --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/LIEZertifikatCard.java @@ -0,0 +1,356 @@ +/* +* 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.pin.gui.PINGUI; +import at.gv.egiz.smcc.util.ISO7816Utils; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.smcc.util.SMCCHelper; +import javax.smartcardio.Card; +import javax.smartcardio.CardTerminal; + +public class LIEZertifikatCard extends AbstractSignatureCard implements SignatureCard { +   +  /** +   * Logging facility. +   */ +  private final Logger log = LoggerFactory.getLogger(LIEZertifikatCard.class); + +  public static final byte[] MF = new byte[] { (byte) 0x3F, (byte) 0x00 }; + +  // DF.CIA +  public static final byte[] AID_SIG = new byte[] { +    (byte) 0xA0, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x63, +    (byte) 0x50, (byte) 0x4B, (byte) 0x43, (byte) 0x53, (byte) 0x2D, +    (byte) 0x31, (byte) 0x35 }; + +  public static final byte[] EF_QCERT = new byte[] { (byte) 0x0c, (byte) 0x02}; + +  public static final byte[] CRT_AT = new byte[] { +    // key 0x81??? (EF.PrKD defines 0x84 and 0x85) +    (byte) 0x84, (byte) 0x01, (byte) 0x81, +    //RSA Authentication +    (byte) 0x89, (byte) 0x02, (byte) 0x23, (byte) 0x13 +  }; + +  public static final byte[] PKCS1_PADDING = 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, (byte) 0x14 }; + + +  public static final byte KID = (byte) 0x82; + +  //TODO should be part of PinInfo +  public static final int STORED_LENGTH = 8; + +  protected PinInfo pinInfo = new PinInfo(4, 8, "[0-9]", +          "at/gv/egiz/smcc/LIEZertifikatCard", "pin", KID, AID_SIG, 3); +  protected String name = "LIEZertifikat"; + +  @Override +  public void init(Card card, CardTerminal cardTerminal) { +    super.init(card, cardTerminal); +    log.debug("initializing {} for ATR {}", name, toString(card.getATR().getBytes())); +  } + +  @Override +  public String toString() { +    return name; +  } + +  @Override +  @Exclusive +  public byte[] getCertificate(KeyboxName keyboxName, PINGUI pinGUI) +      throws SignatureCardException { + +    if (keyboxName != KeyboxName.SECURE_SIGNATURE_KEYPAIR) { +      throw new IllegalArgumentException("Keybox " + keyboxName +          + " not supported"); +    } + +    try { +      CardChannel channel = getCardChannel(); +      // SELECT DF.CIA +      execSELECT_AID(channel, AID_SIG); +      // SELECT CERT +      execSELECT_EF(channel, EF_QCERT); + +      // READ BINARY +      byte[] certificate = ISO7816Utils.readTransparentFileTLV(channel, -1, (byte) 0x30); +      if (certificate == null) { +        throw new NotActivatedException(); +      } +      return certificate; +       +    } catch (FileNotFoundException e) { +      throw new NotActivatedException(); +    } catch (CardException e) { +      log.info("Failed to get certificate.", e); +      throw new SignatureCardException(e); +    } + +  } + +  @Override +  @Exclusive +  public byte[] getInfobox(String infobox, PINGUI provider, String domainId) +      throws SignatureCardException, InterruptedException { +       +    throw new IllegalArgumentException("Infobox '" + infobox +        + "' not supported."); +  } + +  @Override +  @Exclusive +  public byte[] createSignature(InputStream input, KeyboxName keyboxName, +      PINGUI provider, String alg) throws SignatureCardException, InterruptedException, IOException { +     +    if (KeyboxName.SECURE_SIGNATURE_KEYPAIR != keyboxName) { +      throw new SignatureCardException("Card does not support key " + keyboxName + "."); +    } +    if (!"http://www.w3.org/2000/09/xmldsig#rsa-sha1".equals(alg)) { +      throw new SignatureCardException("Card does not support algorithm " + alg + "."); +    } + +     +    MessageDigest md; +    try { +      md = MessageDigest.getInstance("SHA-1"); +    } catch (NoSuchAlgorithmException e) { +      log.error("Failed to get MessageDigest.", e); +      throw new SignatureCardException(e); +    } +    // calculate message digest +    byte[] digest = new byte[md.getDigestLength()]; +    for (int l; (l = input.read(digest)) != -1;) { +      md.update(digest, 0, l); +    } +    digest = md.digest(); + +    ByteArrayOutputStream data = new ByteArrayOutputStream(); +     +    try { +      // oid +      data.write(PKCS1_PADDING); +      // hash +      data.write(digest); +    } catch (IOException e) { +      throw new SignatureCardException(e); +    } +     +    try { +       +      CardChannel channel = getCardChannel(); + +      // SELECT AID +      execSELECT_AID(channel, AID_SIG); +      // VERIFY +      verifyPINLoop(channel, pinInfo, provider); +      // MANAGE SECURITY ENVIRONMENT : SET SE +      execMSE_SET(channel, CRT_AT); +      // PERFORM SECURITY OPERATION : COMPUTE DIGITAL SIGNATURE +      return execINTERNAL_AUTHENTICATE(channel, data.toByteArray()); + +    } catch (CardException e) { +      log.warn("Failed to execute command.", e); +      throw new SignatureCardException("Failed to access card.", e); +    } + +  } + +  protected void verifyPINLoop(CardChannel channel, PinInfo spec, +      PINGUI provider) throws LockedException, NotActivatedException, +      SignatureCardException, InterruptedException, CardException { +     +    int retries = -1; //verifyPIN(channel, spec, null, -1); +    do { +      retries = verifyPIN(channel, spec, provider, retries); +    } while (retries > 0); +  } + +  protected int verifyPIN(CardChannel channel, PinInfo pinSpec, +      PINGUI provider, int retries) throws SignatureCardException, +      LockedException, NotActivatedException, InterruptedException, +      CardException { +     +    VerifyAPDUSpec apduSpec = new VerifyAPDUSpec( +        new byte[] { +            (byte) 0x00, (byte) 0x20, (byte) 0x00, pinSpec.getKID()}, +        0, VerifyAPDUSpec.PIN_FORMAT_ASCII, STORED_LENGTH); +     +    ResponseAPDU resp = reader.verify(channel, apduSpec, provider, pinSpec, retries); +     +    if (resp.getSW() == 0x9000) { +      return -1; +    } +    if (resp.getSW() >> 4 == 0x63c) { +      return 0x0f & resp.getSW(); +    } +     +    switch (resp.getSW()) { +    case 0x6983: +      // authentication method blocked +      throw new LockedException(); +    case 0x6984: +      // reference data not usable +      throw new NotActivatedException(); +    case 0x6985: +      // conditions of use not satisfied +      throw new NotActivatedException(); +   +    default: +      String msg = "VERIFY failed. SW=" + Integer.toHexString(resp.getSW());  +      log.info(msg); +      throw new SignatureCardException(msg); +    } +     +  } +   +  protected byte[] execSELECT_AID(CardChannel channel, byte[] aid) +      throws SignatureCardException, CardException { + +    // add Ne, otherwise 67:00 +    ResponseAPDU resp = channel.transmit( +        new CommandAPDU(0x00, 0xA4, 0x04, 0x00, aid, 256)); +     +    if (resp.getSW() == 0x6A82) { +      String msg = "File or application not found AID=" +          + SMCCHelper.toString(aid) + " SW=" +          + Integer.toHexString(resp.getSW()) + "."; +      log.info(msg); +      throw new FileNotFoundException(msg); +    } else if (resp.getSW() != 0x9000) { +      String msg = "Failed to select application FID=" +          + SMCCHelper.toString(aid) + " SW=" +          + Integer.toHexString(resp.getSW()) + "."; +      log.error(msg); +      throw new SignatureCardException(msg); +    } else { +      return resp.getBytes(); +    } +     +  } + +  protected byte[] execSELECT_MF(CardChannel channel) +  throws SignatureCardException, CardException { + +    // don't add Ne, causes 67:00 +    ResponseAPDU resp = channel.transmit( +        new CommandAPDU(0x00, 0xA4, 0x00, 0x0c, MF)); +     +    if (resp.getSW() == 0x6A82) { +      String msg = "File or application not found FID=" +          + SMCCHelper.toString(MF) + " SW=" +          + Integer.toHexString(resp.getSW()) + "."; +      log.info(msg); +      throw new FileNotFoundException(msg); +    } else if (resp.getSW() != 0x9000) { +      String msg = "Failed to select FID=" +          + SMCCHelper.toString(MF) + " SW=" +          + Integer.toHexString(resp.getSW()) + "."; +      log.error(msg); +      throw new SignatureCardException(msg); +    } else { +      return resp.getBytes(); +    } + +  } +   +   +  protected byte[] execSELECT_EF(CardChannel channel, byte[] fid) +  throws SignatureCardException, CardException { + +    ResponseAPDU resp = channel.transmit( +        new CommandAPDU(0x00, 0xA4, 0x02, 0x00, fid, 256)); + +    if (resp.getSW() == 0x6A82) { +      String msg = "File or application not found FID=" +          + SMCCHelper.toString(fid) + " SW=" +          + Integer.toHexString(resp.getSW()) + "."; +      log.info(msg); +      throw new FileNotFoundException(msg); +    } else if (resp.getSW() != 0x9000) { +      String msg = "Failed to select FID=" +          + SMCCHelper.toString(fid) + " SW=" +          + Integer.toHexString(resp.getSW()) + "."; +      log.error(msg); +      throw new SignatureCardException(msg); +    } else { +      return resp.getBytes(); +    } + +  } + + +  protected void execMSE_SET(CardChannel channel, byte[] at) +      throws CardException, SignatureCardException { + +    // don't add Ne, causes 67:00 +    ResponseAPDU resp = channel.transmit( +        new CommandAPDU(0x00, 0x22, 0x41, 0xa4, at)); +    if (resp.getSW() != 0x9000) { +      throw new SignatureCardException("MSE:SET failed: SW=" +          + Integer.toHexString(resp.getSW())); +    } +  } + +  protected void execMSE_RESTORE(CardChannel channel, byte seid) +      throws CardException, SignatureCardException { +    ResponseAPDU resp = channel.transmit( +        new CommandAPDU(0x00, 0x22, 0xf3, seid)); +    if (resp.getSW() != 0x9000) { +      throw new SignatureCardException("MSE:RESTORE failed: SW=" +          + Integer.toHexString(resp.getSW())); +    } +  } + +  protected byte[] execINTERNAL_AUTHENTICATE(CardChannel channel, byte[] AI) +      throws CardException, SignatureCardException { +    ResponseAPDU resp; +    resp = channel.transmit( +        new CommandAPDU(0x00, 0x88, 0x00, 0x00, AI, 256)); +    if (resp.getSW() == 0x6982) { +      throw new SecurityStatusNotSatisfiedException(); +    } else if (resp.getSW() == 0x6983) { +      throw new LockedException(); +    } else if (resp.getSW() != 0x9000) { +      throw new SignatureCardException( +          "INTERNAL AUTHENTICATE failed: SW=" +              + Integer.toHexString(resp.getSW())); +    } else { +      return resp.getData(); +    } +  } + +} 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 3f3893c5..a6056de5 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java @@ -424,6 +424,27 @@ public class SignatureCardFactory {                  (byte) 0xff},          "at.gv.egiz.smcc.SuisseIDCard")); +    supportedCards.add(new SupportedCard( +        // FL-Post card +        // [3b:bb:18:00:c0:10:31:fe:45:80:67:04:12: b0:03:03:00:00:81:05:3c] +        new byte[] { (byte) 0x3b, (byte) 0xbb, (byte) 0x18, +                (byte) 0x00, (byte) 0xc0, (byte) 0x10, (byte) 0x31, +                (byte) 0xfe, (byte) 0x45, (byte) 0x80, (byte) 0x67, +                (byte) 0x04, (byte) 0x12, (byte) 0xb0, (byte) 0x03, +                (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x81, +                (byte) 0x05, (byte) 0x3c}, +        // mask +        new byte[] { +                (byte) 0xff, (byte) 0xff, (byte) 0xff, +                (byte) 0xff, (byte) 0xff, (byte) 0xff, +                (byte) 0xff, (byte) 0xff, (byte) 0xff, +                (byte) 0xff, (byte) 0xff, (byte) 0xff, +                (byte) 0xff, (byte) 0xff, (byte) 0xff, +                (byte) 0xff, (byte) 0xff, (byte) 0xff, +                (byte) 0xff, (byte) 0xff, (byte) 0xff}, +        "at.gv.egiz.smcc.LIEZertifikatCard")); + +        }    /** diff --git a/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java b/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java index 3584af53..7bb466ff 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java @@ -115,6 +115,9 @@ public class PinpadCardReader extends DefaultCardReader {          log.trace("Setting custom wPINMaxExtraDigitH (0x01) for {}.", name);          wPINMaxExtraDigitMin = 0x01;        } +      //TODO Kobil KAAN Advanced seems to have an issue, +      //cf. http://www.buergerkarte.at/mvnforum/mvnforum/viewthread?thread=255 +      //CHANGE REFERENCE DATA failed. SW=6a80 on activate STARCOS card      }    } diff --git a/smcc/src/main/resources/at/gv/egiz/smcc/LIEZertifikatCard.properties b/smcc/src/main/resources/at/gv/egiz/smcc/LIEZertifikatCard.properties new file mode 100644 index 00000000..9b7b6993 --- /dev/null +++ b/smcc/src/main/resources/at/gv/egiz/smcc/LIEZertifikatCard.properties @@ -0,0 +1,20 @@ +# 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. + +# To change this template, choose Tools | Templates +# and open the template in the editor. + +pin.name=User PIN +pin.length=4-8
\ No newline at end of file diff --git a/smcc/src/test/java/at/gv/egiz/smcc/test/AbstractCardTestBase.java b/smcc/src/test/java/at/gv/egiz/smcc/test/AbstractCardTestBase.java index 90105b2b..96dc230a 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/test/AbstractCardTestBase.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/test/AbstractCardTestBase.java @@ -31,6 +31,7 @@ import at.gv.egiz.smcc.CardNotSupportedException;  import at.gv.egiz.smcc.CardTerminalEmul;  import at.gv.egiz.smcc.SignatureCard;  import at.gv.egiz.smcc.SignatureCardFactory; +import iaik.security.provider.IAIK;  public abstract class AbstractCardTestBase { @@ -44,7 +45,7 @@ public abstract class AbstractCardTestBase {    @BeforeClass    public static void setupClass() { -//    IAIK.addAsJDK14Provider(); +    IAIK.addAsJDK14Provider();    }    @Before | 
