summaryrefslogtreecommitdiff
path: root/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.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/ACOSCard.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/ACOSCard.java')
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java348
1 files changed, 208 insertions, 140 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 abe086ee..9e56701f 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java
@@ -30,12 +30,18 @@ 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;
import javax.smartcardio.ResponseAPDU;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
+
+ private static Log log = LogFactory.getLog(ACOSCard.class);
public static final byte[] AID_DEC = new byte[] { (byte) 0xA0, (byte) 0x00,
(byte) 0x00, (byte) 0x01, (byte) 0x18, (byte) 0x45, (byte) 0x4E };
@@ -97,7 +103,145 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
super("at/gv/egiz/smcc/ACOSCard");
}
- byte[] selectFileAID(byte[] fid) throws CardException, SignatureCardException {
+ /* (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;
+ 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();
+ }
+ } 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("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.");
+ }
+
+ } else {
+ throw new IllegalArgumentException("Infobox '" + infobox
+ + "' not supported.");
+ }
+
+ }
+
+ 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.");
+ }
+
+ 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.");
+ }
+
+ } 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.");
+ }
+
+ }
+
+ protected byte[] selectFileAID(byte[] fid) throws CardException, SignatureCardException {
CardChannel channel = getCardChannel();
ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x04,
0x00, fid, 256));
@@ -109,18 +253,40 @@ public class ACOSCard 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, 0x00,
+ return transmit(channel, new CommandAPDU(0x00, 0xA4, 0x00,
0x00, fid, 256));
- if (resp.getSW() == 0x6a82) {
- throw new SignatureCardException("Failed to select file (FID="
- + toString(fid) + "): SW=" + Integer.toHexString(resp.getSW()) + ")");
+ }
+
+ protected int verifyPIN(String pin, byte kid) throws CardException, SignatureCardException {
+
+ CardChannel channel = getCardChannel();
+
+ byte[] asciiPIN = pin.getBytes(Charset.forName("ASCII"));
+ byte[] encodedPIN = new byte[8];
+ System.arraycopy(asciiPIN, 0, encodedPIN, 0, Math.min(asciiPIN.length,
+ encodedPIN.length));
+
+ ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00,
+ kid, encodedPIN), false);
+
+ 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 {
- return resp.getBytes();
+ throw new SignatureCardException("Failed to verify pin: SW="
+ + Integer.toHexString(resp.getSW()) + ".");
}
- }
+ }
+
/**
*
* @param pinProvider
@@ -128,56 +294,30 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
* the PIN spec to be given to the pinProvider
* @param kid
* the KID (key identifier) of the PIN to be verified
- * @param kfpc
- * acutal value of the KFCP (key fault presentation counter) or less
- * than 0 if actual value is unknown
- *
- * @return -1 if the PIN has been verifyed successfully, or else the new value
- * of the KFCP (key fault presentation counter)
- *
* @throws CancelledException
* if the user canceld the operation
* @throws javax.smartcardio.CardException
* @throws at.gv.egiz.smcc.SignatureCardException
*/
- int verifyPIN(PINProvider pinProvider, PINSpec spec, byte kid, int kfpc)
+ protected void verifyPIN(PINProvider pinProvider, PINSpec spec, byte kid)
throws CardException, CancelledException, SignatureCardException {
- CardChannel channel = getCardChannel();
-
- // get PIN
- String pin = pinProvider.providePIN(spec, kfpc);
- if (pin == null) {
- // User canceld operation
- // throw new CancelledException("User canceld PIN entry");
- return -2;
- }
-
- byte[] asciiPIN = pin.getBytes(Charset.forName("ASCII"));
- byte[] encodedPIN = new byte[8];
- System.arraycopy(asciiPIN, 0, encodedPIN, 0, Math.min(asciiPIN.length,
- encodedPIN.length));
-
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00,
- kid, encodedPIN));
- if (resp.getSW1() == (byte) 0x63 && resp.getSW2() >> 4 == (byte) 0xc) {
- return resp.getSW2() & (byte) 0x0f;
- } else if (resp.getSW() == 0x6983) {
- // PIN blocked
- throw new SignatureCardException(spec.getLocalizedName() + " blocked.");
- } else if (resp.getSW() != 0x9000) {
- throw new SignatureCardException("Failed to verify pin: SW="
- + Integer.toHexString(resp.getSW()) + ".");
- } else {
- return -1;
- }
-
+ 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(byte[] dst) throws CardException, SignatureCardException {
+
+ void mseSetDST(int p1, int p2, byte[] dst) throws CardException, SignatureCardException {
CardChannel channel = getCardChannel();
- ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x22, 0x81,
- 0xB6, dst));
+ ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x22, p1,
+ p2, dst));
if (resp.getSW() != 0x9000) {
throw new SignatureCardException("MSE:SET DST failed: SW="
+ Integer.toHexString(resp.getSW()));
@@ -207,102 +347,30 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard {
return resp.getData();
}
}
-
- public byte[] getCertificate(KeyboxName keyboxName)
- throws SignatureCardException {
-
- if (keyboxName == KeyboxName.SECURE_SIGNATURE_KEYPAIR) {
- return readTLVFile(AID_SIG, EF_C_CH_DS, EF_C_CH_DS_MAX_SIZE);
- } else if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) {
- return readTLVFile(AID_DEC, EF_C_CH_EKEY, EF_C_CH_EKEY_MAX_SIZE);
- } else {
- throw new IllegalArgumentException("Keybox " + keyboxName
- + " not supported.");
- }
-
- }
-
- 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(
- "inf.pin.name"));
- try {
- byte[] res = readTLVFilePIN(AID_DEC, EF_INFOBOX, KID_PIN_INF, provider,
- spec, EF_INFOBOX_MAX_SIZE);
- return res;
- } catch (Exception e) {
- throw new SecurityException(e);
- }
-
+
+ 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
+ };
+
+ byte[] data = new byte[digestInfo.length + hash.length + 1];
+
+ System.arraycopy(digestInfo, 0, data, 0, digestInfo.length);
+ data[digestInfo.length] = (byte) hash.length;
+ System.arraycopy(hash, 0, data, digestInfo.length + 1, hash.length);
+
+ CardChannel channel = getCardChannel();
+
+ ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x88, 0x10, 0x00, data, 256));
+ if (resp.getSW() != 0x9000) {
+ throw new SignatureCardException("INTERNAL AUTHENTICATE failed: SW=" + Integer.toHexString(resp.getSW()));
} else {
- throw new IllegalArgumentException("Infobox '" + infobox
- + "' not supported.");
+ return resp.getData();
}
-
}
public String toString() {
return "a-sign premium";
}
-
- 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[] fid;
- byte kid;
- byte[] dst;
- PINSpec spec;
- if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) {
- fid = DF_SIG;
- kid = KID_PIN_SIG;
- dst = DST_SIG;
- spec = new PINSpec(6, 10, "[0-9]", getResourceBundle().getString(
- "sig.pin.name"));
-
- } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) {
- fid = DF_DEC;
- kid = KID_PIN_DEC;
- dst = DST_DEC;
- spec = new PINSpec(6, 10, "[0-9]", getResourceBundle().getString(
- "dec.pin.name"));
-
- } else {
- throw new IllegalArgumentException("KeyboxName '" + keyboxName
- + "' not supported.");
- }
-
- try {
-
- // SELECT DF
- selectFileFID(fid);
- // VERIFY
- int kfpc = -1;
- while (true) {
- kfpc = verifyPIN(provider, spec, kid, kfpc);
- if (kfpc < -1) {
- return null;
- } else if (kfpc < 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);
- }
- }
}