summaryrefslogtreecommitdiff
path: root/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
diff options
context:
space:
mode:
authormcentner <mcentner@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4>2008-10-30 10:33:29 +0000
committermcentner <mcentner@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4>2008-10-30 10:33:29 +0000
commitc2ae3db1bc6dcb8ba3eb3461c05e293917c004ca (patch)
tree78151b3f5364daac73dc305f536fae2aa2998521 /smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
parent687e55f5dbc25855c42757e3024a3c87126803e7 (diff)
downloadmocca-c2ae3db1bc6dcb8ba3eb3461c05e293917c004ca.tar.gz
mocca-c2ae3db1bc6dcb8ba3eb3461c05e293917c004ca.tar.bz2
mocca-c2ae3db1bc6dcb8ba3eb3461c05e293917c004ca.zip
Updated SMCC to use exclusive access and to throw exceptions upon locked or not activated cards. Improved locale support in the security layer request and response processing. Fixed issue in STAL which prevented the use of RSA-SHA1 signatures. Added additional parameters to the applet test pages.
git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@128 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4
Diffstat (limited to 'smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java')
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java339
1 files changed, 210 insertions, 129 deletions
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 79e2663e..99acbc0f 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java
@@ -31,12 +31,21 @@ 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;
import javax.smartcardio.ResponseAPDU;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
public class STARCOSCard extends AbstractSignatureCard implements SignatureCard {
+
+ /**
+ * Logging facility.
+ */
+ private static Log log = LogFactory.getLog(STARCOSCard.class);
public static final byte[] MF = new byte[] { (byte) 0x3F, (byte) 0x00 };
@@ -83,7 +92,7 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
public static final byte KID_PIN_SS = (byte) 0x81;
- // Gew�hnliche Signatur (GS)
+ // 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,
@@ -104,31 +113,157 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
// .
// )
(byte) 0x80, (byte) 0x02, (byte) 0x00, // local, key ID, key version
- (byte) 0x89, (byte) 0x01, // tag, length (algorithm ID)
- (byte) 0x14 // ECDSA
+ (byte) 0x89, (byte) 0x03, // tag, length (algorithm ID)
+ (byte) 0x13, (byte) 0x35, (byte) 0x10 // ECDSA
};
public static final byte KID_PIN_CARD = (byte) 0x01;
+ /**
+ * Creates an new instance.
+ */
public STARCOSCard() {
super("at/gv/egiz/smcc/STARCOSCard");
}
+ /* (non-Javadoc)
+ * @see at.gv.egiz.smcc.SignatureCard#getCertificate(at.gv.egiz.smcc.SignatureCard.KeyboxName)
+ */
public byte[] getCertificate(KeyboxName keyboxName)
throws SignatureCardException {
+ byte[] aid;
+ byte[] efc;
if (keyboxName == KeyboxName.SECURE_SIGNATURE_KEYPAIR) {
- return readTLVFile(AID_DF_SS, EF_C_X509_CH_DS, 2000);
+ aid = AID_DF_SS;
+ efc = EF_C_X509_CH_DS;
} else if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) {
- return readTLVFile(AID_DF_GS, EF_C_X509_CH_AUT, 2000);
+ aid = AID_DF_GS;
+ efc = EF_C_X509_CH_AUT;
} 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, 2000);
+ } 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.");
+ }
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egiz.smcc.SignatureCard#getInfobox(java.lang.String, at.gv.egiz.smcc.PINProvider, java.lang.String)
+ */
+ 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 {
+ Card card = getCardChannel().getCard();
+ 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();
+ } finally {
+ card.endExclusive();
+ }
+ } catch (CardException e) {
+ throw new SignatureCardException("Failed to get exclusive card access.");
+ }
+
+ } else {
+ throw new IllegalArgumentException("Infobox '" + infobox
+ + "' not supported.");
+ }
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egiz.smcc.SignatureCard#createSignature(byte[], at.gv.egiz.smcc.SignatureCard.KeyboxName, at.gv.egiz.smcc.PINProvider)
+ */
+ 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 {
+ 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();
+ }
+ } catch (CardException e) {
+ throw new SignatureCardException("Failed to get exclusive card access.");
+ }
+
}
- byte[] selectFileAID(byte[] fid) throws CardException, SignatureCardException {
+ protected byte[] selectFileAID(byte[] fid) throws CardException, SignatureCardException {
CardChannel channel = getCardChannel();
ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x04,
0x04, fid, 256));
@@ -150,16 +285,10 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
}
}
- byte[] selectFileFID(byte[] fid) throws CardException, SignatureCardException {
+ protected ResponseAPDU selectFileFID(byte[] fid) throws CardException, SignatureCardException {
CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x02,
+ return 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 {
@@ -201,134 +330,86 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard
}
}
- int verifyPIN(PINProvider pinProvider, PINSpec spec, byte kid, int kfpc)
- throws CardException, SignatureCardException {
-
+ /**
+ * 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 CardException
+ * if communication with the smart card fails.
+ * @throws NotActivatedException
+ * if the card application has not been activated
+ * @throws SignatureCardException
+ * if VERIFY PIN fails
+ */
+ private int verifyPIN(String pin, byte kid) 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);
+ ResponseAPDU resp;
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);
+ resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, kid));
} else {
- System.arraycopy(pinBytes, 0, pinBlock, len - pinBytes.length + 1,
- pinBytes.length);
+ // 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), false);
+
}
- 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) {
+ 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() != 0x9000) {
+ } else if (resp.getSW() == 0x6984) {
+ // PIN LCS = "Initialized" (-> not activated)
+ throw new NotActivatedException("PIN not set.");
+ } else if (resp.getSW() == 0x9000) {
+ return -1; // success
+ } else {
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);
- }
-
+
}
+
+ /* (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 {
- 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);
+ int retries = verifyPIN(null, kid);
+ do {
+ String pin = pinProvider.providePIN(spec, retries);
+ if (pin == null) {
+ // user canceled operation
+ throw new CancelledException("User canceld operation.");
}
- } else {
- throw new IllegalArgumentException("Infobox '" + infobox
- + "' not supported.");
- }
+ retries = verifyPIN(pin, kid);
+ } while (retries > 0);
}