From 32d17447a258188b2d534bcb0bf65a659ba7b7d0 Mon Sep 17 00:00:00 2001 From: mcentner Date: Fri, 29 Aug 2008 12:11:34 +0000 Subject: Initial import. git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@1 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4 --- .../src/main/java/at/gv/egiz/smcc/STARCOSCard.java | 341 +++++++++++++++++++++ 1 file changed, 341 insertions(+) create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java (limited to 'smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java') diff --git a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java new file mode 100644 index 00000000..79e2663e --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java @@ -0,0 +1,341 @@ +//Copyright (C) 2002 IAIK +//http://jce.iaik.at +// +//Copyright (C) 2003 Stiftung Secure Information and +// Communication Technologies SIC +//http://www.sic.st +// +//All rights reserved. +// +//This source is provided for inspection purposes and recompilation only, +//unless specified differently in a contract with IAIK. This source has to +//be kept in strict confidence and must not be disclosed to any third party +//under any circumstances. Redistribution in source and binary forms, with +//or without modification, are permitted in any case! +// +//THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +//ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +//SUCH DAMAGE. +// +// +package at.gv.egiz.smcc; + +import java.math.BigInteger; +import java.util.Arrays; + +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; + +public class STARCOSCard extends AbstractSignatureCard implements SignatureCard { + + public static final byte[] MF = new byte[] { (byte) 0x3F, (byte) 0x00 }; + + public static final byte[] AID_INFOBOX = new byte[] { (byte) 0xd0, + (byte) 0x40, (byte) 0x00, (byte) 0x00, (byte) 0x17, (byte) 0x00, + (byte) 0x18, (byte) 0x01 }; + + public static final byte[] EF_INFOBOX = new byte[] { (byte) 0xef, (byte) 0x01 }; + + public static final byte[] AID_SVSIG_CERT = new byte[] { (byte) 0xd0, + (byte) 0x40, (byte) 0x00, (byte) 0x00, (byte) 0x17, (byte) 0x00, + (byte) 0x10, (byte) 0x01 }; + + public static final byte[] EF_SVSIG_CERT_CA = new byte[] { (byte) 0x2f, + (byte) 0x01 }; + + public static final byte[] EF_SVSIG_CERT = new byte[] { (byte) 0x2f, + (byte) 0x02 }; + + // Sichere Signatur (SS) + + public static final byte[] AID_DF_SS = new byte[] { (byte) 0xd0, (byte) 0x40, + (byte) 0x00, (byte) 0x00, (byte) 0x17, (byte) 0x00, (byte) 0x12, + (byte) 0x01 }; + + public static final byte[] EF_C_X509_CH_DS = new byte[] { (byte) 0xc0, + (byte) 0x00 }; + + public static final byte[] EF_C_X509_CA_CS_DS = new byte[] { (byte) 0xc6, + (byte) 0x08 }; + + public static final byte[] DST_SS = new byte[] { (byte) 0x84, (byte) 0x03, // tag + // , + // length + // ( + // key + // desc + // . + // ) + (byte) 0x80, (byte) 0x02, (byte) 0x00, // local, key ID, key version + (byte) 0x89, (byte) 0x03, // tag, length (algorithm ID) + (byte) 0x13, (byte) 0x35, (byte) 0x10 // ECDSA + }; + + public static final byte KID_PIN_SS = (byte) 0x81; + + // Gew�hnliche Signatur (GS) + + public static final byte[] AID_DF_GS = new byte[] { (byte) 0xd0, (byte) 0x40, + (byte) 0x00, (byte) 0x00, (byte) 0x17, (byte) 0x00, (byte) 0x13, + (byte) 0x01 }; + + public static final byte[] EF_C_X509_CH_AUT = new byte[] { (byte) 0x2f, + (byte) 0x01 }; + + public static final byte[] EF_C_X509_CA_CS = new byte[] { (byte) 0x2f, + (byte) 0x02 }; + + public static final byte[] DST_GS = new byte[] { (byte) 0x84, (byte) 0x03, // tag + // , + // length + // ( + // key + // desc + // . + // ) + (byte) 0x80, (byte) 0x02, (byte) 0x00, // local, key ID, key version + (byte) 0x89, (byte) 0x01, // tag, length (algorithm ID) + (byte) 0x14 // ECDSA + }; + + public static final byte KID_PIN_CARD = (byte) 0x01; + + public STARCOSCard() { + super("at/gv/egiz/smcc/STARCOSCard"); + } + + public byte[] getCertificate(KeyboxName keyboxName) + throws SignatureCardException { + + if (keyboxName == KeyboxName.SECURE_SIGNATURE_KEYPAIR) { + return readTLVFile(AID_DF_SS, EF_C_X509_CH_DS, 2000); + } else if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) { + return readTLVFile(AID_DF_GS, EF_C_X509_CH_AUT, 2000); + } else { + throw new IllegalArgumentException("Keybox " + keyboxName + + " not supported."); + } + + } + + byte[] selectFileAID(byte[] fid) throws CardException, SignatureCardException { + CardChannel channel = getCardChannel(); + ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x04, + 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(); + } + } + + void selectMF() throws CardException, SignatureCardException { + CardChannel channel = getCardChannel(); + ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x00, + 0x0C)); + if (resp.getSW() != 0x9000) { + throw new SignatureCardException("Failed to select MF: SW=" + + Integer.toHexString(resp.getSW()) + "."); + } + } + + byte[] selectFileFID(byte[] fid) throws CardException, SignatureCardException { + CardChannel channel = getCardChannel(); + ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x02, + 0x04, fid, 256)); + if (resp.getSW() == 0x6a82) { + throw new SignatureCardException("Failed to select file (FID=" + + toString(fid) + "): SW=" + Integer.toHexString(resp.getSW()) + "."); + } else { + return resp.getBytes(); + } + } + + void mseSetDST(byte[] dst) throws CardException, SignatureCardException { + CardChannel channel = getCardChannel(); + ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x22, 0x41, + 0xB6, dst)); + if (resp.getSW() != 0x9000) { + throw new SignatureCardException("MSE:SET DST failed: SW=" + + Integer.toHexString(resp.getSW())); + } + } + + 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 + System.arraycopy(hash, 0, data, 2, hash.length); + + CardChannel channel = getCardChannel(); + ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x2A, 0x90, + 0xA0, data)); + if (resp.getSW() != 0x9000) { + throw new SignatureCardException("PSO:HASH failed: SW=" + + Integer.toHexString(resp.getSW())); + } + } + + byte[] psoComputDigitalSiganture() throws CardException, + SignatureCardException { + CardChannel channel = getCardChannel(); + ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x2A, 0x9E, + 0x9A, 256)); + if (resp.getSW() != 0x9000) { + throw new SignatureCardException( + "PSO: COMPUTE DIGITAL SIGNATRE failed: SW=" + + Integer.toHexString(resp.getSW())); + } else { + return resp.getData(); + } + } + + int verifyPIN(PINProvider pinProvider, PINSpec spec, byte kid, int kfpc) + throws CardException, SignatureCardException { + + CardChannel channel = getCardChannel(); + + // get number of possible retries + ResponseAPDU resp = transmit(channel, + new CommandAPDU(0x00, 0x20, 0x00, kid)); + int retries; + if (resp.getSW1() == 0x63 && resp.getSW2() >> 4 == 0xc) { + retries = resp.getSW2() & 0x0f; + } else if (resp.getSW() == 0x6984) { + // PIN LCS = "Initilized" (not activated) + throw new SignatureCardException(spec.getLocalizedName() + " not set."); + } else { + throw new SignatureCardException("Failed to get PIN retries: SW=" + + Integer.toHexString(resp.getSW())); + } + + // get PIN + String pin = pinProvider.providePIN(spec, retries); + if (pin == null) { + // User canceled operation + // throw new CancelledException("User canceld PIN entry"); + return -2; + } + // PIN length in bytes + int len = (int) Math.ceil(pin.length() / 2); + + // BCD encode PIN and marshal PIN block + byte[] pinBytes = new BigInteger(pin, 16).toByteArray(); + byte[] pinBlock = new byte[8]; + if (len < pinBytes.length) { + System.arraycopy(pinBytes, pinBytes.length - len, pinBlock, 1, len); + } else { + System.arraycopy(pinBytes, 0, pinBlock, len - pinBytes.length + 1, + pinBytes.length); + } + pinBlock[0] = (byte) (0x20 + len * 2); + Arrays.fill(pinBlock, len + 1, 8, (byte) 0xff); + + resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, kid, pinBlock)); + if (resp.getSW1() == 0x63 && resp.getSW2() >> 4 == 0xc) { + return resp.getSW2() & 0x0f; + } else if (resp.getSW() != 0x9000) { + throw new SignatureCardException("Failed to verify pin: SW=" + + Integer.toHexString(resp.getSW())); + } else { + return -1; + } + + } + + public byte[] createSignature(byte[] hash, KeyboxName keyboxName, + PINProvider provider) throws SignatureCardException { + + if (hash.length != 20) { + 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 { + + // SELECT MF + selectMF(); + // SELECT DF + selectFileAID(aid); + // VERIFY + int retr = -1; // unknown + while (true) { + retr = verifyPIN(provider, spec, kid, retr); + if (retr < -1) { + return null; + } else if (retr < 0) { + break; + } + } + // MSE: SET DST + mseSetDST(dst); + // PSO: HASH + psoHash(hash); + // PSO: COMPUTE DIGITAL SIGNATURE + byte[] rs = psoComputDigitalSiganture(); + return rs; + + } catch (CardException e) { + throw new SignatureCardException("Failed to create signature.", e); + } + + } + + public byte[] getInfobox(String infobox, PINProvider provider, String domainId) + throws SignatureCardException { + + if ("IdentityLink".equals(infobox)) { + + PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name")); + try { + byte[] res = readTLVFilePIN(AID_INFOBOX, EF_INFOBOX, KID_PIN_CARD, + provider, spec, 2000); + return res; + } catch (Exception e) { + throw new SignatureCardException(e); + } + } else { + throw new IllegalArgumentException("Infobox '" + infobox + + "' not supported."); + } + + } + + public String toString() { + return "eCard"; + } + + + +} -- cgit v1.2.3